From: Danylo Vodopianov <dvo-...@napatech.com> - Initialize IGAM module and check for its presence. - Enable system PLL using IGAM and check for PLL lock status. - Reset and configure TS PLL and check for lock status. - Force HIF soft reset and de-assert platform reset. - Enable RAB1 and RAB2 and perform RAB initialization and flush. - Check system PLL readiness using PHY_TILE and handle PLL lock status.
Signed-off-by: Danylo Vodopianov <dvo-...@napatech.com> --- .../net/ntnic/nthw/core/include/nthw_hif.h | 1 + .../net/ntnic/nthw/core/include/nthw_igam.h | 3 + .../nthw/core/include/nthw_pcm_nt400dxx.h | 4 + .../ntnic/nthw/core/include/nthw_phy_tile.h | 8 + .../nt400dxx/reset/nthw_fpga_rst_nt400dxx.c | 211 ++++++++++++++++++ drivers/net/ntnic/nthw/core/nthw_hif.c | 10 + drivers/net/ntnic/nthw/core/nthw_igam.c | 31 +++ .../net/ntnic/nthw/core/nthw_pcm_nt400dxx.c | 24 ++ drivers/net/ntnic/nthw/core/nthw_phy_tile.c | 61 +++++ drivers/net/ntnic/nthw/nthw_drv.h | 2 + 10 files changed, 355 insertions(+) diff --git a/drivers/net/ntnic/nthw/core/include/nthw_hif.h b/drivers/net/ntnic/nthw/core/include/nthw_hif.h index deb9ed04e8..7d5e1f1310 100644 --- a/drivers/net/ntnic/nthw/core/include/nthw_hif.h +++ b/drivers/net/ntnic/nthw/core/include/nthw_hif.h @@ -135,6 +135,7 @@ void nthw_hif_delete(nthw_hif_t *p); int nthw_hif_init(nthw_hif_t *p, nthw_fpga_t *p_fpga, int n_instance); int nthw_hif_trigger_sample_time(nthw_hif_t *p); +int nthw_hif_force_soft_reset(nthw_hif_t *p); int nthw_hif_stat_req_enable(nthw_hif_t *p); int nthw_hif_stat_req_disable(nthw_hif_t *p); diff --git a/drivers/net/ntnic/nthw/core/include/nthw_igam.h b/drivers/net/ntnic/nthw/core/include/nthw_igam.h index e78637a331..fed462cd34 100644 --- a/drivers/net/ntnic/nthw/core/include/nthw_igam.h +++ b/drivers/net/ntnic/nthw/core/include/nthw_igam.h @@ -33,5 +33,8 @@ typedef struct nt_igam nthw_igam; nthw_igam_t *nthw_igam_new(void); int nthw_igam_init(nthw_igam_t *p, nthw_fpga_t *p_fpga, int mn_igam_instance); +uint32_t nthw_igam_read(nthw_igam_t *p, uint32_t address); +void nthw_igam_write(nthw_igam_t *p, uint32_t address, uint32_t data); +void nthw_igam_set_ctrl_forward_rst(nthw_igam_t *p, uint32_t value); #endif /* __NTHW_IGAM_H__ */ diff --git a/drivers/net/ntnic/nthw/core/include/nthw_pcm_nt400dxx.h b/drivers/net/ntnic/nthw/core/include/nthw_pcm_nt400dxx.h index 23865f466b..47d2670cf5 100644 --- a/drivers/net/ntnic/nthw/core/include/nthw_pcm_nt400dxx.h +++ b/drivers/net/ntnic/nthw/core/include/nthw_pcm_nt400dxx.h @@ -32,5 +32,9 @@ typedef struct nthw_pcm_nt400_dxx nthw_pcm_nt400_dxx; nthw_pcm_nt400dxx_t *nthw_pcm_nt400dxx_new(void); int nthw_pcm_nt400dxx_init(nthw_pcm_nt400dxx_t *p, nthw_fpga_t *p_fpga, int n_instance); +void nthw_pcm_nt400dxx_set_ts_pll_recal(nthw_pcm_nt400dxx_t *p, uint32_t val); +bool nthw_pcm_nt400dxx_get_ts_pll_locked_stat(nthw_pcm_nt400dxx_t *p); +bool nthw_pcm_nt400dxx_get_ts_pll_locked_latch(nthw_pcm_nt400dxx_t *p); +void nthw_pcm_nt400dxx_set_ts_pll_locked_latch(nthw_pcm_nt400dxx_t *p, uint32_t val); #endif /* __NTHW_PCM_NT400DXX_H__ */ diff --git a/drivers/net/ntnic/nthw/core/include/nthw_phy_tile.h b/drivers/net/ntnic/nthw/core/include/nthw_phy_tile.h index ba044a5091..c4ec100c23 100644 --- a/drivers/net/ntnic/nthw/core/include/nthw_phy_tile.h +++ b/drivers/net/ntnic/nthw/core/include/nthw_phy_tile.h @@ -142,7 +142,15 @@ void nthw_phy_tile_write_xcvr(nthw_phy_tile_t *p, uint8_t intf_no, uint8_t lane, uint32_t data); uint32_t nthw_phy_tile_get_port_status_reset_ack(nthw_phy_tile_t *p, uint8_t intf_no); uint32_t nthw_phy_tile_get_port_status_tx_lanes_stable(nthw_phy_tile_t *p, uint8_t intf_no); +void nthw_phy_tile_set_sys_pll_set_rdy(nthw_phy_tile_t *p, uint32_t value); +uint32_t nthw_phy_tile_get_sys_pll_get_rdy(nthw_phy_tile_t *p); +uint32_t nthw_phy_tile_get_sys_pll_system_pll_lock(nthw_phy_tile_t *p); +void nthw_phy_tile_set_sys_pll_en_ref_clk_fgt(nthw_phy_tile_t *p, uint32_t value); +uint32_t nthw_phy_tile_get_sys_pll_ref_clk_fgt_enabled(nthw_phy_tile_t *p); +void nthw_phy_tile_set_sys_pll_forward_rst(nthw_phy_tile_t *p, uint32_t value); +void nthw_phy_tile_set_sys_pll_force_rst(nthw_phy_tile_t *p, uint32_t value); uint8_t nthw_phy_tile_get_no_intfs(nthw_phy_tile_t *p); void nthw_phy_tile_set_port_config_rst(nthw_phy_tile_t *p, uint8_t intf_no, uint32_t value); +bool nthw_phy_tile_use_phy_tile_pll_check(nthw_phy_tile_t *p); #endif /* __NTHW_PHY_TILE_H__ */ diff --git a/drivers/net/ntnic/nthw/core/nt400dxx/reset/nthw_fpga_rst_nt400dxx.c b/drivers/net/ntnic/nthw/core/nt400dxx/reset/nthw_fpga_rst_nt400dxx.c index 95394b9c8f..b93b0a829a 100644 --- a/drivers/net/ntnic/nthw/core/nt400dxx/reset/nthw_fpga_rst_nt400dxx.c +++ b/drivers/net/ntnic/nthw/core/nt400dxx/reset/nthw_fpga_rst_nt400dxx.c @@ -184,9 +184,13 @@ static int nthw_fpga_rst_nt400dxx_reset(struct fpga_info_s *p_fpga_info) { const char *const p_adapter_id_str = p_fpga_info->mp_adapter_id_str; nthw_fpga_t *p_fpga = NULL; + int res = -1; p_fpga = p_fpga_info->mp_fpga; + nthw_pcm_nt400dxx_t *p_pcm = p_fpga_info->mp_nthw_agx.p_pcm; + nthw_prm_nt400dxx_t *p_prm = p_fpga_info->mp_nthw_agx.p_prm; + assert(p_fpga_info); NT_LOG(DBG, NTHW, "%s: %s: BEGIN", p_adapter_id_str, __PRETTY_FUNCTION__); @@ -199,9 +203,216 @@ static int nthw_fpga_rst_nt400dxx_reset(struct fpga_info_s *p_fpga_info) return -1; } + nthw_phy_tile_t *p_phy_tile = p_fpga_info->mp_nthw_agx.p_phy_tile; + nthw_igam_t *p_igam = nthw_igam_new(); nthw_igam_init(p_igam, p_fpga, 0); + if (p_igam) { + if (!nthw_phy_tile_use_phy_tile_pll_check(p_fpga_info->mp_nthw_agx.p_phy_tile)) { + NT_LOG(DBG, NTHW, "%s: IGAM module present.", p_adapter_id_str); + uint32_t data; + + p_fpga_info->mp_nthw_agx.p_igam = p_igam; + + /* + * (E) When the reference clock for the F-tile system PLL is started (and + * stable) it must be enabled using the Intel Global Avalon Memory-Mapped + * Mailbox (IGAM) module. + */ + + nthw_igam_write(p_igam, 0xffff8, 0x90000000); + + /* (F) Check that the system PLL is ready. */ + for (int i = 1000; i >= 0; i--) { + nt_os_wait_usec(1000); + data = nthw_igam_read(p_igam, 0xffff4); + + if (data == 0x80000000 || data == 0xA0000000) { + NT_LOG(INF, + NTHW, + "%s: All enabled system PLLs are locked. Response: %#08x", + p_adapter_id_str, + data); + break; + } + + if (i == 0) { + NT_LOG(ERR, + NTHW, + "%s: Timeout waiting for all system PLLs to lock. Response: %#08x", + p_adapter_id_str, + data); + return -1; + } + } + + } else { + nthw_igam_set_ctrl_forward_rst(p_igam, + 0); /* Ensure that the Avalon bus is not */ + /* reset at every driver re-load. */ + nt_os_wait_usec(1000000); + NT_LOG(DBG, NTHW, "%s: IGAM module not used.", p_adapter_id_str); + } + + } else { + NT_LOG(DBG, NTHW, "%s: No IGAM module present.", p_adapter_id_str); + } + + /* + * (G) Reset TS PLL and select Time-of-Day clock (tod_fpga_clk). Source is either + * from ZL clock device or SiTime tunable XO. NOTE that the PLL must be held in + * RESET during clock switchover. + */ + + if (p_fpga_info->mp_nthw_agx.tcxo_present && p_fpga_info->mp_nthw_agx.tcxo_capable) { + nthw_pcm_nt400dxx_set_ts_pll_recal(p_pcm, 1); + nt_os_wait_usec(1000); + nthw_pcm_nt400dxx_set_ts_pll_recal(p_pcm, 0); + nt_os_wait_usec(1000); + } + + /* (I) Wait for TS PLL locked. */ + for (int i = 1000; i >= 0; i--) { + nt_os_wait_usec(1000); + + if (nthw_pcm_nt400dxx_get_ts_pll_locked_stat(p_pcm)) + break; + + if (i == 0) { + NT_LOG(ERR, + NTHW, + "%s: %s: Time out waiting for TS PLL locked", + p_adapter_id_str, + __func__); + return -1; + } + } + + /* NT_RAB0_REG.PCM_NT400D1X.STAT.TS_PLL_LOCKED==1 */ + + /* (J) Set latched TS PLL locked. */ + nthw_pcm_nt400dxx_set_ts_pll_locked_latch(p_pcm, 1); + /* NT_RAB0_REG.PCM_NT400D1X.LATCH.TS_PLL_LOCKED=1 */ + + /* (K) Ensure TS latched status bit is still set. */ + if (!nthw_pcm_nt400dxx_get_ts_pll_locked_stat(p_pcm)) { + NT_LOG(ERR, + NTHW, + "%s: %s: TS latched status bit toggled", + p_adapter_id_str, + __func__); + return -1; + } + + /* NT_RAB0_REG.PCM_NT400D1X.LATCH.TS_PLL_LOCKED==1 */ + + /* + * At this point all system clocks and TS clocks are running. + * Last thing to do before proceeding to product reset is to + * de-assert the platform reset and enable the RAB buses. + */ + + /* (K1) Force HIF soft reset. */ + nthw_hif_t *p_nthw_hif = nthw_hif_new(); + res = nthw_hif_init(p_nthw_hif, p_fpga, 0); + + if (res == 0) + NT_LOG(DBG, NTHW, "%s: Hif module found", p_fpga_info->mp_adapter_id_str); + + nt_os_wait_usec(1000); + nthw_hif_force_soft_reset(p_nthw_hif); + nt_os_wait_usec(1000); + nthw_hif_delete(p_nthw_hif); + + /* (L) De-assert platform reset. */ + nthw_prm_nt400dxx_platform_rst(p_prm, 0); + + /* + * (M) Enable RAB1 and RAB2. + * NT_BAR_REG.RAC.RAB_INIT.RAB=0 + */ + NT_LOG_DBGX(DBG, NTHW, "%s: RAB Init", p_adapter_id_str); + nthw_rac_rab_init(p_fpga_info->mp_nthw_rac, 0); + nthw_rac_rab_setup(p_fpga_info->mp_nthw_rac); + + NT_LOG_DBGX(DBG, NTHW, "%s: RAB Flush", p_adapter_id_str); + nthw_rac_rab_flush(p_fpga_info->mp_nthw_rac); + + /* + * FPGAs with newer PHY_TILE versions must use PhyTile to check that system PLL is ready. + * It has been added here after consultations with ORA since the test must be performed + * after de-assertion of platform reset. + */ + + if (nthw_phy_tile_use_phy_tile_pll_check(p_phy_tile)) { + /* Ensure that the Avalon bus is not reset at every driver re-load. */ + nthw_phy_tile_set_sys_pll_forward_rst(p_phy_tile, 0); + + nthw_phy_tile_set_sys_pll_set_rdy(p_phy_tile, 0x07); + NT_LOG_DBGX(DBG, NTHW, "%s: setSysPllSetRdy.", p_adapter_id_str); + + /* (F) Check that the system PLL is ready. */ + for (int i = 1000; i >= 0; i--) { + nt_os_wait_usec(1000); + + if (nthw_phy_tile_get_sys_pll_get_rdy(p_phy_tile) && + nthw_phy_tile_get_sys_pll_system_pll_lock(p_phy_tile)) { + break; + } + + if (i == 500) { + nthw_phy_tile_set_sys_pll_force_rst(p_phy_tile, 1); + nt_os_wait_usec(1000); + nthw_phy_tile_set_sys_pll_force_rst(p_phy_tile, 0); + NT_LOG_DBGX(DBG, + NTHW, + "%s: setSysPllForceRst due to system PLL not ready.", + p_adapter_id_str); + } + + if (i == 0) { + NT_LOG_DBGX(DBG, + NTHW, + "%s: Timeout waiting for all system PLLs to lock", + p_adapter_id_str); + return -1; + } + } + + nt_os_wait_usec(100000);/* 100 ms */ + + uint32_t fgt_enable = 0x0d; /* FGT 0, 2 & 3 */ + nthw_phy_tile_set_sys_pll_en_ref_clk_fgt(p_phy_tile, fgt_enable); + + for (int i = 1000; i >= 0; i--) { + nt_os_wait_usec(1000); + + if (nthw_phy_tile_get_sys_pll_ref_clk_fgt_enabled(p_phy_tile) == + fgt_enable) { + break; + } + + if (i == 500) { + nthw_phy_tile_set_sys_pll_force_rst(p_phy_tile, 1); + nt_os_wait_usec(1000); + nthw_phy_tile_set_sys_pll_force_rst(p_phy_tile, 0); + NT_LOG_DBGX(DBG, + NTHW, + "%s: setSysPllForceRst due to FGTs not ready.", + p_adapter_id_str); + } + + if (i == 0) { + NT_LOG_DBGX(DBG, + NTHW, + "%s: Timeout waiting for FGTs to lock", + p_adapter_id_str); + return -1; + } + } + } + return 0; } diff --git a/drivers/net/ntnic/nthw/core/nthw_hif.c b/drivers/net/ntnic/nthw/core/nthw_hif.c index 92a2348bbb..630262a7fc 100644 --- a/drivers/net/ntnic/nthw/core/nthw_hif.c +++ b/drivers/net/ntnic/nthw/core/nthw_hif.c @@ -202,6 +202,16 @@ int nthw_hif_init(nthw_hif_t *p, nthw_fpga_t *p_fpga, int n_instance) return 0; } +int nthw_hif_force_soft_reset(nthw_hif_t *p) +{ + if (p->mp_fld_ctrl_fsr) { + nthw_field_update_register(p->mp_fld_ctrl_fsr); + nthw_field_set_flush(p->mp_fld_ctrl_fsr); + } + + return 0; +} + int nthw_hif_trigger_sample_time(nthw_hif_t *p) { nthw_field_set_val_flush32(p->mp_fld_sample_time, 0xfee1dead); diff --git a/drivers/net/ntnic/nthw/core/nthw_igam.c b/drivers/net/ntnic/nthw/core/nthw_igam.c index 5dc7e36c7b..385282298a 100644 --- a/drivers/net/ntnic/nthw/core/nthw_igam.c +++ b/drivers/net/ntnic/nthw/core/nthw_igam.c @@ -60,3 +60,34 @@ int nthw_igam_init(nthw_igam_t *p, nthw_fpga_t *p_fpga, int mn_igam_instance) return 0; } + +uint32_t nthw_igam_read(nthw_igam_t *p, uint32_t address) +{ + nthw_register_update(p->mp_reg_base); + nthw_field_set_val32(p->mp_fld_base_cmd, 0); + nthw_field_set_val_flush32(p->mp_fld_base_ptr, address); + + while (nthw_field_get_updated(p->mp_fld_base_busy) == 1) + nt_os_wait_usec(100); + + return nthw_field_get_updated(p->mp_fld_data_data); +} + +void nthw_igam_write(nthw_igam_t *p, uint32_t address, uint32_t data) +{ + nthw_field_set_val_flush32(p->mp_fld_data_data, data); + nthw_register_update(p->mp_reg_base); + nthw_field_set_val32(p->mp_fld_base_ptr, address); + nthw_field_set_val_flush32(p->mp_fld_base_cmd, 1); + + while (nthw_field_get_updated(p->mp_fld_base_busy) == 1) + nt_os_wait_usec(100); +} + +void nthw_igam_set_ctrl_forward_rst(nthw_igam_t *p, uint32_t value) +{ + if (p->mp_fld_ctrl_forward_rst) { + nthw_field_get_updated(p->mp_fld_ctrl_forward_rst); + nthw_field_set_val_flush32(p->mp_fld_ctrl_forward_rst, value); + } +} diff --git a/drivers/net/ntnic/nthw/core/nthw_pcm_nt400dxx.c b/drivers/net/ntnic/nthw/core/nthw_pcm_nt400dxx.c index f32a277e86..e7be634a83 100644 --- a/drivers/net/ntnic/nthw/core/nthw_pcm_nt400dxx.c +++ b/drivers/net/ntnic/nthw/core/nthw_pcm_nt400dxx.c @@ -54,3 +54,27 @@ int nthw_pcm_nt400dxx_init(nthw_pcm_nt400dxx_t *p, nthw_fpga_t *p_fpga, int n_in return 0; } + +void nthw_pcm_nt400dxx_set_ts_pll_recal(nthw_pcm_nt400dxx_t *p, uint32_t val) +{ + if (p->mp_fld_ctrl_ts_pll_recal) { + nthw_field_update_register(p->mp_fld_ctrl_ts_pll_recal); + nthw_field_set_val_flush32(p->mp_fld_ctrl_ts_pll_recal, val); + } +} + +bool nthw_pcm_nt400dxx_get_ts_pll_locked_stat(nthw_pcm_nt400dxx_t *p) +{ + return nthw_field_get_updated(p->mp_fld_stat_ts_pll_locked) != 0; +} + +bool nthw_pcm_nt400dxx_get_ts_pll_locked_latch(nthw_pcm_nt400dxx_t *p) +{ + return nthw_field_get_updated(p->mp_fld_latch_ts_pll_locked) != 0; +} + +void nthw_pcm_nt400dxx_set_ts_pll_locked_latch(nthw_pcm_nt400dxx_t *p, uint32_t val) +{ + nthw_field_update_register(p->mp_fld_latch_ts_pll_locked); + nthw_field_set_val_flush32(p->mp_fld_latch_ts_pll_locked, val); +} diff --git a/drivers/net/ntnic/nthw/core/nthw_phy_tile.c b/drivers/net/ntnic/nthw/core/nthw_phy_tile.c index f78d8263f5..0dc2784034 100644 --- a/drivers/net/ntnic/nthw/core/nthw_phy_tile.c +++ b/drivers/net/ntnic/nthw/core/nthw_phy_tile.c @@ -642,6 +642,11 @@ int nthw_phy_tile_init(nthw_phy_tile_t *p, nthw_fpga_t *p_fpga, int mn_phy_tile_ return 0; } +bool nthw_phy_tile_use_phy_tile_pll_check(nthw_phy_tile_t *p) +{ + return nthw_module_is_version_newer(p->m_mod_phy_tile, 0, 8); +} + uint8_t nthw_phy_tile_get_no_intfs(nthw_phy_tile_t *p) { switch (p->mac_pcs_mode) { @@ -1172,6 +1177,62 @@ uint32_t nthw_phy_tile_get_port_status_tx_lanes_stable(nthw_phy_tile_t *p, uint8 return 1; } +void nthw_phy_tile_set_sys_pll_set_rdy(nthw_phy_tile_t *p, uint32_t value) +{ + if (p->mp_fld_sys_pll_set_rdy) { + nthw_field_get_updated(p->mp_fld_sys_pll_set_rdy); + nthw_field_set_val_flush32(p->mp_fld_sys_pll_set_rdy, value); + } +} + +uint32_t nthw_phy_tile_get_sys_pll_get_rdy(nthw_phy_tile_t *p) +{ + if (p->mp_fld_sys_pll_get_rdy) + return nthw_field_get_updated(p->mp_fld_sys_pll_get_rdy); + + return 0; +} + +uint32_t nthw_phy_tile_get_sys_pll_system_pll_lock(nthw_phy_tile_t *p) +{ + if (p->mp_fld_sys_pll_system_pll_lock) + return nthw_field_get_updated(p->mp_fld_sys_pll_system_pll_lock); + + return 0; +} + +void nthw_phy_tile_set_sys_pll_en_ref_clk_fgt(nthw_phy_tile_t *p, uint32_t value) +{ + if (p->mp_fld_sys_pll_en_ref_clk_fgt) { + nthw_field_get_updated(p->mp_fld_sys_pll_en_ref_clk_fgt); + nthw_field_set_val_flush32(p->mp_fld_sys_pll_en_ref_clk_fgt, value); + } +} + +uint32_t nthw_phy_tile_get_sys_pll_ref_clk_fgt_enabled(nthw_phy_tile_t *p) +{ + if (p->mp_fld_sys_pll_ref_clk_fgt_enabled) + return nthw_field_get_updated(p->mp_fld_sys_pll_ref_clk_fgt_enabled); + + return 0; +} + +void nthw_phy_tile_set_sys_pll_forward_rst(nthw_phy_tile_t *p, uint32_t value) +{ + if (p->mp_fld_sys_pll_forward_rst) { + nthw_field_get_updated(p->mp_fld_sys_pll_forward_rst); + nthw_field_set_val_flush32(p->mp_fld_sys_pll_forward_rst, value); + } +} + +void nthw_phy_tile_set_sys_pll_force_rst(nthw_phy_tile_t *p, uint32_t value) +{ + if (p->mp_fld_sys_pll_force_rst) { + nthw_field_get_updated(p->mp_fld_sys_pll_force_rst); + nthw_field_set_val_flush32(p->mp_fld_sys_pll_force_rst, value); + } +} + void nthw_phy_tile_set_port_config_rst(nthw_phy_tile_t *p, uint8_t intf_no, uint32_t value) { if (p->mp_fld_port_config_reset[intf_no]) { diff --git a/drivers/net/ntnic/nthw/nthw_drv.h b/drivers/net/ntnic/nthw/nthw_drv.h index 574dd663ea..e1a00c5ea5 100644 --- a/drivers/net/ntnic/nthw/nthw_drv.h +++ b/drivers/net/ntnic/nthw/nthw_drv.h @@ -17,6 +17,7 @@ #include "nthw_phy_tile.h" #include "nthw_prm_nt400dxx.h" #include "nthw_pcm_nt400dxx.h" +#include "nthw_igam.h" /* * Structs for controlling Agilex based NT400DXX adapter @@ -31,6 +32,7 @@ typedef struct nthw_agx_s { nthw_si5156_t *p_si5156; nthw_prm_nt400dxx_t *p_prm; nthw_pcm_nt400dxx_t *p_pcm; + nthw_igam_t *p_igam; nthw_phy_tile_t *p_phy_tile; nthw_rpf_t *p_rpf; bool tcxo_present; -- 2.45.0