#include "aq_hw_utils.h"
#include "aq_ring.h"
#include "aq_nic.h"
+#include "aq_ptp.h"
#include "hw_atl/hw_atl_b0.h"
#include "hw_atl/hw_atl_utils.h"
#include "hw_atl/hw_atl_llh.h"
static int hw_atl2_act_rslvr_table_set(struct aq_hw_s *self, u8 location,
u32 tag, u32 mask, u32 action);
+static void hw_atl2_enable_ptp(struct aq_hw_s *self,
+ unsigned int param, int enable);
+static int hw_atl2_hw_tx_ptp_ring_init(struct aq_hw_s *self,
+ struct aq_ring_s *aq_ring);
+static int hw_atl2_hw_rx_ptp_ring_init(struct aq_hw_s *self,
+ struct aq_ring_s *aq_ring);
+static void aq_get_ptp_ts(struct aq_hw_s *self, u64 *stamp);
+static int hw_atl2_adj_clock_freq(struct aq_hw_s *self, s32 ppb);
+
#define DEFAULT_BOARD_BASIC_CAPABILITIES \
.is_64_dma = true, \
.op64bit = true, \
static int hw_atl2_hw_reset(struct aq_hw_s *self)
{
struct hw_atl2_priv *priv = self->priv;
+ s8 clk_sel;
int err;
int i;
priv->l3l4_filters[i].l4_index = -1;
}
+ clk_sel = READ_ONCE(self->clk_select);
+ if (clk_sel != -1)
+ hw_atl2_enable_ptp(self,
+ clk_sel,
+ aq_utils_obj_test(&self->flags, AQ_HW_PTP_AVAILABLE) ?
+ 1 : 0);
+
self->aq_fw_ops->set_state(self, MPI_RESET);
err = aq_hw_err_from_flags(self);
struct aq_ring_s *aq_ring,
struct aq_ring_param_s *aq_ring_param)
{
- return hw_atl_b0_hw_ring_rx_init(self, aq_ring, aq_ring_param);
+ int res = hw_atl_b0_hw_ring_rx_init(self, aq_ring, aq_ring_param);
+
+ if (!res && aq_ptp_ring(aq_ring->aq_nic, aq_ring))
+ res = hw_atl2_hw_rx_ptp_ring_init(self, aq_ring);
+
+ return res;
}
static int hw_atl2_hw_ring_tx_init(struct aq_hw_s *self,
struct aq_ring_s *aq_ring,
struct aq_ring_param_s *aq_ring_param)
{
- return hw_atl_b0_hw_ring_tx_init(self, aq_ring, aq_ring_param);
+ int res = hw_atl_b0_hw_ring_tx_init(self, aq_ring, aq_ring_param);
+
+ if (!res && aq_ptp_ring(aq_ring->aq_nic, aq_ring))
+ res = hw_atl2_hw_tx_ptp_ring_init(self, aq_ring);
+
+ return res;
}
#define IS_FILTER_ENABLED(_F_) ((packet_filter & (_F_)) ? 1U : 0U)
return &self->curr_stats;
}
+static void hw_atl2_enable_ptp(struct aq_hw_s *self,
+ unsigned int param, int enable)
+{
+ s8 sel = (s8)param;
+
+ WRITE_ONCE(self->clk_select, sel);
+ /* enable tsg counter */
+ hw_atl2_tsg_clock_reset(self, sel);
+ hw_atl2_tsg_clock_en(self, !sel, enable);
+ hw_atl2_tsg_clock_en(self, sel, enable);
+
+ if (enable)
+ hw_atl2_adj_clock_freq(self, 0);
+
+ hw_atl2_tpb_tps_highest_priority_tc_enable_set(self, enable);
+}
+
+static void aq_get_ptp_ts(struct aq_hw_s *self, u64 *stamp)
+{
+ s8 clk_sel = READ_ONCE(self->clk_select);
+
+ if (clk_sel < 0) {
+ if (stamp)
+ *stamp = 0;
+ return;
+ }
+ if (stamp)
+ *stamp = hw_atl2_tsg_clock_read(self, clk_sel);
+}
+
+static u64 hw_atl2_hw_ring_tx_ptp_get_ts(struct aq_ring_s *ring)
+{
+ struct hw_atl2_txts_s *txts;
+ u32 ctrl;
+
+ txts = (struct hw_atl2_txts_s *)&ring->dx_ring[ring->sw_head *
+ HW_ATL2_TXD_SIZE];
+ /* DD + TS_VALID */
+ ctrl = le32_to_cpu(READ_ONCE(txts->ctrl));
+ if ((ctrl & HW_ATL2_TXTS_DD) && (ctrl & HW_ATL2_TXTS_TS_VALID)) {
+ dma_rmb();
+ return le64_to_cpu(txts->ts);
+ }
+
+ return 0;
+}
+
+static u16 hw_atl2_hw_rx_extract_ts(struct aq_hw_s *self, u8 *p,
+ unsigned int len, u64 *timestamp)
+{
+ unsigned int offset = HW_ATL2_RX_TS_SIZE;
+ __le64 ts;
+ u8 *ptr;
+
+ if (len <= offset || !timestamp)
+ return 0;
+
+ ptr = p + (len - offset);
+ memcpy(&ts, ptr, sizeof(ts));
+ *timestamp = le64_to_cpu(ts);
+
+ return HW_ATL2_RX_TS_SIZE;
+}
+
+static int hw_atl2_adj_sys_clock(struct aq_hw_s *self, s64 delta)
+{
+ s8 clk_sel = READ_ONCE(self->clk_select);
+
+ if (clk_sel < 0)
+ return -ENODEV;
+ if (delta >= 0)
+ hw_atl2_tsg_clock_add(self, clk_sel, (u64)delta);
+ else
+ hw_atl2_tsg_clock_sub(self, clk_sel, (u64)(-delta));
+
+ return 0;
+}
+
+static int hw_atl2_adj_clock_freq(struct aq_hw_s *self, s32 ppb)
+{
+ u32 freq = AQ2_HW_PTP_COUNTER_HZ;
+ u64 divisor = 0, base_ns;
+ u32 nsi_frac = 0, nsi;
+ u32 nsi_rem;
+ s8 clk_sel;
+
+ base_ns = div_u64((u64)((s64)ppb + NSEC_PER_SEC) * NSEC_PER_SEC, freq);
+ nsi = (u32)div_u64_rem(base_ns, NSEC_PER_SEC, &nsi_rem);
+ if (nsi_rem != 0) {
+ divisor = div_u64(mul_u32_u32(NSEC_PER_SEC, NSEC_PER_SEC),
+ nsi_rem);
+ nsi_frac = (u32)div64_u64(AQ_FRAC_PER_NS * NSEC_PER_SEC,
+ divisor);
+ }
+
+ clk_sel = READ_ONCE(self->clk_select);
+ if (clk_sel < 0)
+ return -ENODEV;
+ hw_atl2_tsg_clock_increment_set(self, clk_sel, nsi, nsi_frac);
+
+ return 0;
+}
+
+static int hw_atl2_hw_tx_ptp_ring_init(struct aq_hw_s *self,
+ struct aq_ring_s *aq_ring)
+{
+ hw_atl2_tdm_tx_desc_timestamp_writeback_en_set(self, true,
+ aq_ring->idx);
+ hw_atl2_tdm_tx_desc_timestamp_en_set(self, true, aq_ring->idx);
+ hw_atl2_tdm_tx_desc_avb_en_set(self, true, aq_ring->idx);
+
+ return aq_hw_err_from_flags(self);
+}
+
+static int hw_atl2_hw_rx_ptp_ring_init(struct aq_hw_s *self,
+ struct aq_ring_s *aq_ring)
+{
+ s8 clk_sel = READ_ONCE(self->clk_select);
+
+ hw_atl2_rpf_rx_desc_timestamp_req_set(self,
+ clk_sel == ATL_TSG_CLOCK_SEL_1 ? 2 : 1,
+ aq_ring->idx);
+ return aq_hw_err_from_flags(self);
+}
+
+static u32 hw_atl2_hw_get_clk_sel(struct aq_hw_s *self)
+{
+ return READ_ONCE(self->clk_select);
+}
+
+static int hw_atl2_gpio_pulse(struct aq_hw_s *self, u32 index, u32 clk_sel,
+ u64 start, u32 period, u32 hightime)
+{
+ u32 mode;
+
+ if (index != 1 && index != 3)
+ return -EINVAL;
+
+ if (start == 0)
+ mode = HW_ATL2_GPIO_PIN_SPEC_MODE_GPIO;
+ else if (clk_sel == ATL_TSG_CLOCK_SEL_0)
+ mode = HW_ATL2_GPIO_PIN_SPEC_MODE_TSG0_EVENT_OUTPUT;
+ else
+ mode = HW_ATL2_GPIO_PIN_SPEC_MODE_TSG1_EVENT_OUTPUT;
+
+ hw_atl2_gpio_special_mode_set(self, mode, index);
+ hw_atl2_tsg_ptp_gpio_gen_pulse(self, clk_sel, start, period, hightime);
+
+ return 0;
+}
+
static bool hw_atl2_rxf_l3_is_equal(struct hw_atl2_l3_filter *f1,
struct hw_atl2_l3_filter *f2)
{
.hw_set_offload = hw_atl_b0_hw_offload_set,
.hw_set_loopback = hw_atl_b0_set_loopback,
.hw_set_fc = hw_atl_b0_set_fc,
+
+ .hw_ring_hwts_rx_fill = NULL,
+ .hw_ring_hwts_rx_receive = NULL,
+
+ .hw_get_ptp_ts = aq_get_ptp_ts,
+ .hw_adj_clock_freq = hw_atl2_adj_clock_freq,
+ .hw_adj_sys_clock = hw_atl2_adj_sys_clock,
+ .hw_gpio_pulse = hw_atl2_gpio_pulse,
+
+ .enable_ptp = hw_atl2_enable_ptp,
+ .hw_ring_tx_ptp_get_ts = hw_atl2_hw_ring_tx_ptp_get_ts,
+ .rx_extract_ts = hw_atl2_hw_rx_extract_ts,
+ .hw_tx_ptp_ring_init = hw_atl2_hw_tx_ptp_ring_init,
+ .hw_rx_ptp_ring_init = hw_atl2_hw_rx_ptp_ring_init,
+ .hw_get_clk_sel = hw_atl2_hw_get_clk_sel,
+ .extract_hwts = NULL,
+ .hw_extts_gpio_enable = NULL,
};