summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--hw/npu2-hw-procedures.c128
-rw-r--r--include/npu2-regs.h6
-rw-r--r--include/npu2.h4
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);
+ 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 */
OpenPOWER on IntegriCloud