diff options
-rw-r--r-- | hw/npu2-hw-procedures.c | 128 | ||||
-rw-r--r-- | include/npu2-regs.h | 6 | ||||
-rw-r--r-- | include/npu2.h | 4 |
3 files changed, 126 insertions, 12 deletions
diff --git a/hw/npu2-hw-procedures.c b/hw/npu2-hw-procedures.c index eb087bc1..69e788eb 100644 --- a/hw/npu2-hw-procedures.c +++ b/hw/npu2-hw-procedures.c @@ -60,6 +60,7 @@ struct npu2_phy_reg NPU2_PHY_TX_FIFO_INIT = {0x105, 53, 1}; struct npu2_phy_reg NPU2_PHY_TX_RXCAL = {0x103, 57, 1}; struct npu2_phy_reg NPU2_PHY_RX_INIT_DONE = {0x0ca, 48, 1}; struct npu2_phy_reg NPU2_PHY_RX_PR_EDGE_TRACK_CNTL = {0x092, 48, 2}; +struct npu2_phy_reg NPU2_PHY_RX_PR_BUMP_SL_1UI = {0x092, 57, 1}; struct npu2_phy_reg NPU2_PHY_RX_PR_FW_OFF = {0x08a, 56, 1}; struct npu2_phy_reg NPU2_PHY_RX_PR_FW_INERTIA_AMT = {0x08a, 57, 3}; struct npu2_phy_reg NPU2_PHY_RX_CFG_LTE_MC = {0x000, 60, 4}; @@ -68,6 +69,8 @@ struct npu2_phy_reg NPU2_PHY_RX_B_INTEG_COARSE_GAIN = {0x026, 48, 4}; struct npu2_phy_reg NPU2_PHY_RX_E_INTEG_COARSE_GAIN = {0x030, 48, 4}; /* These registers are per-PHY, not per lane */ +struct npu2_phy_reg NPU2_PHY_RX_SPEED_SELECT = {0x262, 51, 2}; +struct npu2_phy_reg NPU2_PHY_RX_AC_COUPLED = {0x262, 53, 1}; struct npu2_phy_reg NPU2_PHY_TX_ZCAL_SWO_EN = {0x3c9, 48, 1}; struct npu2_phy_reg NPU2_PHY_TX_ZCAL_REQ = {0x3c1, 49, 1}; struct npu2_phy_reg NPU2_PHY_TX_ZCAL_DONE = {0x3c1, 50, 1}; @@ -98,6 +101,7 @@ struct npu2_phy_reg NPU2_PHY_RX_CLKDIST_PDWN = {0x204, 48, 3}; struct npu2_phy_reg NPU2_PHY_RX_IREF_PDWN = {0x230, 54, 1}; struct npu2_phy_reg NPU2_PHY_TX_CLKDIST_PDWN = {0x305, 48, 3}; struct npu2_phy_reg NPU2_PHY_RX_CTL_DATASM_CLKDIST_PDWN = {0x2e0, 60, 1}; +struct npu2_phy_reg NPU2_PHY_TX_DRV_DATA_PATTERN_GCRMSG = {0x309, 50, 4}; #define NPU2_PHY_REG(scom_base, reg, lane) \ SETFIELD(PPC_BITMASK(27, 31), ((reg)->offset << 42) | scom_base, lane) @@ -378,6 +382,25 @@ static uint32_t phy_reset_complete(struct npu2_dev *ndev) { int lane; + if (ndev->type == NPU2_DEV_TYPE_OPENCAPI) { + phy_write(ndev, &NPU2_PHY_RX_AC_COUPLED, 1); + + switch (ndev->link_speed) { + case 20000000000: + prlog(PR_INFO, "OCAPI: Link speed set at 20Gb/s\n"); + phy_write(ndev, &NPU2_PHY_RX_SPEED_SELECT, 1); + break; + case 25000000000: + case 25781250000: + prlog(PR_INFO, "OCAPI: Link speed set at 25.xGb/s\n"); + phy_write(ndev, &NPU2_PHY_RX_SPEED_SELECT, 0); + break; + default: + prlog(PR_CRIT, "OCAPI: Invalid link speed!\n"); + assert(false); + } + } + FOR_EACH_LANE(ndev, lane) { phy_write_lane(ndev, &NPU2_PHY_RX_LANE_ANA_PDWN, lane, 0); phy_write_lane(ndev, &NPU2_PHY_RX_LANE_DIG_PDWN, lane, 0); @@ -640,18 +663,25 @@ static uint32_t phy_rx_dccal_complete(struct npu2_dev *ndev) static uint32_t phy_rx_clock_sel(struct npu2_dev *ndev) { - /* - * Change the RX clk mux control to be done by software instead of HW. This - * avoids glitches caused by changing the mux setting. - * - * Work around a known DL bug by doing these writes twice. - */ - npu2_write_mask_4b(ndev->npu, NPU2_NTL_DL_CLK_CTRL(ndev), 0x80000002, 0x80000003); - npu2_write_mask_4b(ndev->npu, NPU2_NTL_DL_CLK_CTRL(ndev), 0x80000002, 0x80000003); - - npu2_write_mask_4b(ndev->npu, NPU2_NTL_DL_CLK_CTRL(ndev), 0x80000000, 0x80000003); - npu2_write_mask_4b(ndev->npu, NPU2_NTL_DL_CLK_CTRL(ndev), 0x80000000, 0x80000003); - + if (ndev->type != NPU2_DEV_TYPE_OPENCAPI) { + /* + * Change the RX clk mux control to be done by + * software instead of HW. This avoids glitches caused + * by changing the mux setting. + * + * Work around a known DL bug by doing these writes + * twice. + */ + npu2_write_mask_4b(ndev->npu, NPU2_NTL_DL_CLK_CTRL(ndev), + 0x80000002, 0x80000003); + npu2_write_mask_4b(ndev->npu, NPU2_NTL_DL_CLK_CTRL(ndev), + 0x80000002, 0x80000003); + + npu2_write_mask_4b(ndev->npu, NPU2_NTL_DL_CLK_CTRL(ndev), + 0x80000000, 0x80000003); + npu2_write_mask_4b(ndev->npu, NPU2_NTL_DL_CLK_CTRL(ndev), + 0x80000000, 0x80000003); + } return PROCEDURE_NEXT; } @@ -887,3 +917,77 @@ void npu2_dev_procedure_reset(struct npu2_dev *dev) { npu2_clear_link_flag(dev, NPU2_DEV_DL_RESET); } + +static uint32_t run_procedure(struct npu2_dev *dev, uint16_t procedure_number) +{ + struct procedure *proc; + const char *name; + uint32_t result; + + assert(procedure_number <= ARRAY_SIZE(npu_procedures)); + proc = npu_procedures[procedure_number]; + assert(proc); + + name = proc->name; + NPU2DEVINF(dev, "Running procedure %s\n", name); + dev->procedure_status = PROCEDURE_INPROGRESS; + dev->procedure_number = procedure_number; + dev->procedure_step = 0; + dev->procedure_data = 0; + dev->procedure_tb = mftb(); + + result = get_procedure_status(dev); + while (!(result & PROCEDURE_COMPLETE)) { + time_wait_ms(1); + result = get_procedure_status(dev); + } + return result; +} + +void npu2_opencapi_bump_ui_lane(struct npu2_dev *dev) +{ + uint64_t reg; + uint64_t status_xscom; + int lane, bit = 7; + + switch (dev->index) { + case 2: + status_xscom = OB0_ODL0_TRAINING_STATUS; + break; + case 3: + status_xscom = OB0_ODL1_TRAINING_STATUS; + break; + case 4: + status_xscom = OB3_ODL1_TRAINING_STATUS; + break; + case 5: + status_xscom = OB3_ODL0_TRAINING_STATUS; + break; + default: + assert(false); + } + xscom_read(dev->npu->chip_id, status_xscom, ®); + reg = GETFIELD(OB_ODL_TRAINING_STATUS_STS_RX_PATTERN_B, reg); + + FOR_EACH_LANE(dev, lane) { + if (reg & (1 << bit--)) + continue; + prlog(PR_TRACE, "OCAPI: bumpui bumping lane %d\n", lane); + for (int i = 0; i < 4; i++) { + phy_write_lane(dev, &NPU2_PHY_RX_PR_BUMP_SL_1UI, lane, 1); + phy_write_lane(dev, &NPU2_PHY_RX_PR_BUMP_SL_1UI, lane, 0); + } + } +} + +void npu2_opencapi_phy_setup(struct npu2_dev *dev) +{ + run_procedure(dev, 4); /* procedure_phy_reset */ + run_procedure(dev, 5); /* procedure_phy_tx_zcal */ + run_procedure(dev, 6); /* procedure_phy_rx_dccal */ +} + +void npu2_opencapi_phy_prbs31(struct npu2_dev *dev) +{ + phy_write(dev, &NPU2_PHY_TX_DRV_DATA_PATTERN_GCRMSG, 0xD); +} diff --git a/include/npu2-regs.h b/include/npu2-regs.h index 08c4f92d..7ef5994f 100644 --- a/include/npu2-regs.h +++ b/include/npu2-regs.h @@ -668,4 +668,10 @@ void npu2_scom_write(uint64_t gcid, uint64_t scom_base, #define PU_IOE_PB_FP_CFG_FP1_FMR_DISABLE PPC_BIT(52) #define PU_IOE_PB_FP_CFG_FP1_PRS_DISABLE PPC_BIT(57) +#define OB0_ODL0_TRAINING_STATUS 0x901082E +#define OB0_ODL1_TRAINING_STATUS 0x901082F +#define OB3_ODL0_TRAINING_STATUS 0xC01082E +#define OB3_ODL1_TRAINING_STATUS 0xC01082F +#define OB_ODL_TRAINING_STATUS_STS_RX_PATTERN_B PPC_BITMASK(8, 15) + #endif /* __NPU2_REGS_H */ diff --git a/include/npu2.h b/include/npu2.h index c836e6e2..58edf701 100644 --- a/include/npu2.h +++ b/include/npu2.h @@ -201,10 +201,14 @@ int64_t npu2_dev_procedure(void *dev, struct pci_cfg_reg_filter *pcrf, uint32_t offset, uint32_t len, uint32_t *data, bool write); void npu2_dev_procedure_reset(struct npu2_dev *dev); + void npu2_set_link_flag(struct npu2_dev *ndev, uint8_t flag); void npu2_clear_link_flag(struct npu2_dev *ndev, uint8_t flag); uint32_t reset_ntl(struct npu2_dev *ndev); extern int nv_zcal_nominal; bool is_p9dd1(void); +void npu2_opencapi_phy_setup(struct npu2_dev *dev); +void npu2_opencapi_phy_prbs31(struct npu2_dev *dev); +void npu2_opencapi_bump_ui_lane(struct npu2_dev *dev); #endif /* __NPU2_H */ |