diff options
author | Swapnil Jakhade | 2021-07-28 16:54:47 +0200 |
---|---|---|
committer | Vinod Koul | 2021-08-17 15:42:43 +0530 |
commit | 5b16a790f18d234187f31eab0a222bd53cb12b9e (patch) | |
tree | 2dbc8732905e65d6d9d9b60ac8269f9f6bcb2a9a /drivers/phy | |
parent | e956d4fceba3aeb1cc088d043048b1d2157427b0 (diff) |
phy: cadence-torrent: Reorder few functions to remove function declarations
Reorder some functions to avoid function declarations.
No functional change.
Signed-off-by: Swapnil Jakhade <sjakhade@cadence.com>
Link: https://lore.kernel.org/r/20210728145454.15945-3-sjakhade@cadence.com
Signed-off-by: Vinod Koul <vkoul@kernel.org>
Diffstat (limited to 'drivers/phy')
-rw-r--r-- | drivers/phy/cadence/phy-cadence-torrent.c | 1207 |
1 files changed, 588 insertions, 619 deletions
diff --git a/drivers/phy/cadence/phy-cadence-torrent.c b/drivers/phy/cadence/phy-cadence-torrent.c index ff647669f1a3..4b2d6d3eace9 100644 --- a/drivers/phy/cadence/phy-cadence-torrent.c +++ b/drivers/phy/cadence/phy-cadence-torrent.c @@ -333,57 +333,6 @@ struct cdns_torrent_derived_refclk { #define to_cdns_torrent_derived_refclk(_hw) \ container_of(_hw, struct cdns_torrent_derived_refclk, hw) -static int cdns_torrent_phy_init(struct phy *phy); -static int cdns_torrent_dp_init(struct phy *phy); -static int cdns_torrent_dp_run(struct cdns_torrent_phy *cdns_phy, - u32 num_lanes); -static -int cdns_torrent_dp_wait_pma_cmn_ready(struct cdns_torrent_phy *cdns_phy); -static void cdns_torrent_dp_pma_cfg(struct cdns_torrent_phy *cdns_phy, - struct cdns_torrent_inst *inst); -static -void cdns_torrent_dp_pma_cmn_cfg_19_2mhz(struct cdns_torrent_phy *cdns_phy); -static -void cdns_torrent_dp_pma_cmn_vco_cfg_19_2mhz(struct cdns_torrent_phy *cdns_phy, - u32 rate, bool ssc); -static -void cdns_torrent_dp_pma_cmn_cfg_25mhz(struct cdns_torrent_phy *cdns_phy); -static -void cdns_torrent_dp_pma_cmn_vco_cfg_25mhz(struct cdns_torrent_phy *cdns_phy, - u32 rate, bool ssc); -static void cdns_torrent_dp_pma_lane_cfg(struct cdns_torrent_phy *cdns_phy, - unsigned int lane); -static void cdns_torrent_dp_pma_cmn_rate(struct cdns_torrent_phy *cdns_phy, - u32 rate, u32 num_lanes); -static int cdns_torrent_dp_configure(struct phy *phy, - union phy_configure_opts *opts); -static int cdns_torrent_dp_set_power_state(struct cdns_torrent_phy *cdns_phy, - u32 num_lanes, - enum phy_powerstate powerstate); -static int cdns_torrent_phy_on(struct phy *phy); -static int cdns_torrent_phy_off(struct phy *phy); - -static const struct phy_ops cdns_torrent_phy_ops = { - .init = cdns_torrent_phy_init, - .configure = cdns_torrent_dp_configure, - .power_on = cdns_torrent_phy_on, - .power_off = cdns_torrent_phy_off, - .owner = THIS_MODULE, -}; - -static int cdns_torrent_noop_phy_on(struct phy *phy) -{ - /* Give 5ms to 10ms delay for the PIPE clock to be stable */ - usleep_range(5000, 10000); - - return 0; -} - -static const struct phy_ops noop_ops = { - .power_on = cdns_torrent_noop_phy_on, - .owner = THIS_MODULE, -}; - struct cdns_reg_pairs { u32 val; u32 off; @@ -615,477 +564,6 @@ static const struct coefficients vltg_coeff[4][4] = { } }; -/* - * Enable or disable PLL for selected lanes. - */ -static int cdns_torrent_dp_set_pll_en(struct cdns_torrent_phy *cdns_phy, - struct phy_configure_opts_dp *dp, - bool enable) -{ - u32 rd_val; - u32 ret; - struct regmap *regmap = cdns_phy->regmap_dptx_phy_reg; - - /* - * Used to determine, which bits to check for or enable in - * PHY_PMA_XCVR_PLLCLK_EN register. - */ - u32 pll_bits; - /* Used to enable or disable lanes. */ - u32 pll_val; - - /* Select values of registers and mask, depending on enabled lane - * count. - */ - switch (dp->lanes) { - /* lane 0 */ - case (1): - pll_bits = 0x00000001; - break; - /* lanes 0-1 */ - case (2): - pll_bits = 0x00000003; - break; - /* lanes 0-3, all */ - default: - pll_bits = 0x0000000F; - break; - } - - if (enable) - pll_val = pll_bits; - else - pll_val = 0x00000000; - - cdns_torrent_dp_write(regmap, PHY_PMA_XCVR_PLLCLK_EN, pll_val); - - /* Wait for acknowledgment from PHY. */ - ret = regmap_read_poll_timeout(regmap, - PHY_PMA_XCVR_PLLCLK_EN_ACK, - rd_val, - (rd_val & pll_bits) == pll_val, - 0, POLL_TIMEOUT_US); - ndelay(100); - return ret; -} - -/* - * Perform register operations related to setting link rate, once powerstate is - * set and PLL disable request was processed. - */ -static int cdns_torrent_dp_configure_rate(struct cdns_torrent_phy *cdns_phy, - struct phy_configure_opts_dp *dp) -{ - u32 ret; - u32 read_val; - - /* Disable the cmn_pll0_en before re-programming the new data rate. */ - regmap_field_write(cdns_phy->phy_pma_pll_raw_ctrl, 0x0); - - /* - * Wait for PLL ready de-assertion. - * For PLL0 - PHY_PMA_CMN_CTRL2[2] == 1 - */ - ret = regmap_field_read_poll_timeout(cdns_phy->phy_pma_cmn_ctrl_2, - read_val, - ((read_val >> 2) & 0x01) != 0, - 0, POLL_TIMEOUT_US); - if (ret) - return ret; - ndelay(200); - - /* DP Rate Change - VCO Output settings. */ - if (cdns_phy->ref_clk_rate == REF_CLK_19_2MHZ) { - /* PMA common configuration 19.2MHz */ - cdns_torrent_dp_pma_cmn_vco_cfg_19_2mhz(cdns_phy, dp->link_rate, - dp->ssc); - cdns_torrent_dp_pma_cmn_cfg_19_2mhz(cdns_phy); - } else if (cdns_phy->ref_clk_rate == REF_CLK_25MHZ) { - /* PMA common configuration 25MHz */ - cdns_torrent_dp_pma_cmn_vco_cfg_25mhz(cdns_phy, dp->link_rate, - dp->ssc); - cdns_torrent_dp_pma_cmn_cfg_25mhz(cdns_phy); - } - cdns_torrent_dp_pma_cmn_rate(cdns_phy, dp->link_rate, dp->lanes); - - /* Enable the cmn_pll0_en. */ - regmap_field_write(cdns_phy->phy_pma_pll_raw_ctrl, 0x3); - - /* - * Wait for PLL ready assertion. - * For PLL0 - PHY_PMA_CMN_CTRL2[0] == 1 - */ - ret = regmap_field_read_poll_timeout(cdns_phy->phy_pma_cmn_ctrl_2, - read_val, - (read_val & 0x01) != 0, - 0, POLL_TIMEOUT_US); - return ret; -} - -/* - * Verify, that parameters to configure PHY with are correct. - */ -static int cdns_torrent_dp_verify_config(struct cdns_torrent_inst *inst, - struct phy_configure_opts_dp *dp) -{ - u8 i; - - /* If changing link rate was required, verify it's supported. */ - if (dp->set_rate) { - switch (dp->link_rate) { - case 1620: - case 2160: - case 2430: - case 2700: - case 3240: - case 4320: - case 5400: - case 8100: - /* valid bit rate */ - break; - default: - return -EINVAL; - } - } - - /* Verify lane count. */ - switch (dp->lanes) { - case 1: - case 2: - case 4: - /* valid lane count. */ - break; - default: - return -EINVAL; - } - - /* Check against actual number of PHY's lanes. */ - if (dp->lanes > inst->num_lanes) - return -EINVAL; - - /* - * If changing voltages is required, check swing and pre-emphasis - * levels, per-lane. - */ - if (dp->set_voltages) { - /* Lane count verified previously. */ - for (i = 0; i < dp->lanes; i++) { - if (dp->voltage[i] > 3 || dp->pre[i] > 3) - return -EINVAL; - - /* Sum of voltage swing and pre-emphasis levels cannot - * exceed 3. - */ - if (dp->voltage[i] + dp->pre[i] > 3) - return -EINVAL; - } - } - - return 0; -} - -/* Set power state A0 and PLL clock enable to 0 on enabled lanes. */ -static void cdns_torrent_dp_set_a0_pll(struct cdns_torrent_phy *cdns_phy, - u32 num_lanes) -{ - struct regmap *regmap = cdns_phy->regmap_dptx_phy_reg; - u32 pwr_state = cdns_torrent_dp_read(regmap, - PHY_PMA_XCVR_POWER_STATE_REQ); - u32 pll_clk_en = cdns_torrent_dp_read(regmap, - PHY_PMA_XCVR_PLLCLK_EN); - - /* Lane 0 is always enabled. */ - pwr_state &= ~(PMA_XCVR_POWER_STATE_REQ_LN_MASK << - PHY_POWER_STATE_LN_0); - pll_clk_en &= ~0x01U; - - if (num_lanes > 1) { - /* lane 1 */ - pwr_state &= ~(PMA_XCVR_POWER_STATE_REQ_LN_MASK << - PHY_POWER_STATE_LN_1); - pll_clk_en &= ~(0x01U << 1); - } - - if (num_lanes > 2) { - /* lanes 2 and 3 */ - pwr_state &= ~(PMA_XCVR_POWER_STATE_REQ_LN_MASK << - PHY_POWER_STATE_LN_2); - pwr_state &= ~(PMA_XCVR_POWER_STATE_REQ_LN_MASK << - PHY_POWER_STATE_LN_3); - pll_clk_en &= ~(0x01U << 2); - pll_clk_en &= ~(0x01U << 3); - } - - cdns_torrent_dp_write(regmap, PHY_PMA_XCVR_POWER_STATE_REQ, pwr_state); - cdns_torrent_dp_write(regmap, PHY_PMA_XCVR_PLLCLK_EN, pll_clk_en); -} - -/* Configure lane count as required. */ -static int cdns_torrent_dp_set_lanes(struct cdns_torrent_phy *cdns_phy, - struct phy_configure_opts_dp *dp) -{ - u32 value; - u32 ret; - struct regmap *regmap = cdns_phy->regmap_dptx_phy_reg; - u8 lane_mask = (1 << dp->lanes) - 1; - - value = cdns_torrent_dp_read(regmap, PHY_RESET); - /* clear pma_tx_elec_idle_ln_* bits. */ - value &= ~PMA_TX_ELEC_IDLE_MASK; - /* Assert pma_tx_elec_idle_ln_* for disabled lanes. */ - value |= ((~lane_mask) << PMA_TX_ELEC_IDLE_SHIFT) & - PMA_TX_ELEC_IDLE_MASK; - cdns_torrent_dp_write(regmap, PHY_RESET, value); - - /* reset the link by asserting phy_l00_reset_n low */ - cdns_torrent_dp_write(regmap, PHY_RESET, - value & (~PHY_L00_RESET_N_MASK)); - - /* - * Assert lane reset on unused lanes and lane 0 so they remain in reset - * and powered down when re-enabling the link - */ - value = (value & 0x0000FFF0) | (0x0000000E & lane_mask); - cdns_torrent_dp_write(regmap, PHY_RESET, value); - - cdns_torrent_dp_set_a0_pll(cdns_phy, dp->lanes); - - /* release phy_l0*_reset_n based on used laneCount */ - value = (value & 0x0000FFF0) | (0x0000000F & lane_mask); - cdns_torrent_dp_write(regmap, PHY_RESET, value); - - /* Wait, until PHY gets ready after releasing PHY reset signal. */ - ret = cdns_torrent_dp_wait_pma_cmn_ready(cdns_phy); - if (ret) - return ret; - - ndelay(100); - - /* release pma_xcvr_pllclk_en_ln_*, only for the master lane */ - cdns_torrent_dp_write(regmap, PHY_PMA_XCVR_PLLCLK_EN, 0x0001); - - ret = cdns_torrent_dp_run(cdns_phy, dp->lanes); - - return ret; -} - -/* Configure link rate as required. */ -static int cdns_torrent_dp_set_rate(struct cdns_torrent_phy *cdns_phy, - struct phy_configure_opts_dp *dp) -{ - u32 ret; - - ret = cdns_torrent_dp_set_power_state(cdns_phy, dp->lanes, - POWERSTATE_A3); - if (ret) - return ret; - ret = cdns_torrent_dp_set_pll_en(cdns_phy, dp, false); - if (ret) - return ret; - ndelay(200); - - ret = cdns_torrent_dp_configure_rate(cdns_phy, dp); - if (ret) - return ret; - ndelay(200); - - ret = cdns_torrent_dp_set_pll_en(cdns_phy, dp, true); - if (ret) - return ret; - ret = cdns_torrent_dp_set_power_state(cdns_phy, dp->lanes, - POWERSTATE_A2); - if (ret) - return ret; - ret = cdns_torrent_dp_set_power_state(cdns_phy, dp->lanes, - POWERSTATE_A0); - if (ret) - return ret; - ndelay(900); - - return ret; -} - -/* Configure voltage swing and pre-emphasis for all enabled lanes. */ -static void cdns_torrent_dp_set_voltages(struct cdns_torrent_phy *cdns_phy, - struct phy_configure_opts_dp *dp) -{ - u8 lane; - u16 val; - - for (lane = 0; lane < dp->lanes; lane++) { - val = cdns_torrent_phy_read(cdns_phy->regmap_tx_lane_cdb[lane], - TX_DIAG_ACYA); - /* - * Write 1 to register bit TX_DIAG_ACYA[0] to freeze the - * current state of the analog TX driver. - */ - val |= TX_DIAG_ACYA_HBDC_MASK; - cdns_torrent_phy_write(cdns_phy->regmap_tx_lane_cdb[lane], - TX_DIAG_ACYA, val); - - cdns_torrent_phy_write(cdns_phy->regmap_tx_lane_cdb[lane], - TX_TXCC_CTRL, 0x08A4); - val = vltg_coeff[dp->voltage[lane]][dp->pre[lane]].diag_tx_drv; - cdns_torrent_phy_write(cdns_phy->regmap_tx_lane_cdb[lane], - DRV_DIAG_TX_DRV, val); - val = vltg_coeff[dp->voltage[lane]][dp->pre[lane]].mgnfs_mult; - cdns_torrent_phy_write(cdns_phy->regmap_tx_lane_cdb[lane], - TX_TXCC_MGNFS_MULT_000, - val); - val = vltg_coeff[dp->voltage[lane]][dp->pre[lane]].cpost_mult; - cdns_torrent_phy_write(cdns_phy->regmap_tx_lane_cdb[lane], - TX_TXCC_CPOST_MULT_00, - val); - - val = cdns_torrent_phy_read(cdns_phy->regmap_tx_lane_cdb[lane], - TX_DIAG_ACYA); - /* - * Write 0 to register bit TX_DIAG_ACYA[0] to allow the state of - * analog TX driver to reflect the new programmed one. - */ - val &= ~TX_DIAG_ACYA_HBDC_MASK; - cdns_torrent_phy_write(cdns_phy->regmap_tx_lane_cdb[lane], - TX_DIAG_ACYA, val); - } -}; - -static int cdns_torrent_dp_configure(struct phy *phy, - union phy_configure_opts *opts) -{ - struct cdns_torrent_inst *inst = phy_get_drvdata(phy); - struct cdns_torrent_phy *cdns_phy = dev_get_drvdata(phy->dev.parent); - int ret; - - ret = cdns_torrent_dp_verify_config(inst, &opts->dp); - if (ret) { - dev_err(&phy->dev, "invalid params for phy configure\n"); - return ret; - } - - if (opts->dp.set_lanes) { - ret = cdns_torrent_dp_set_lanes(cdns_phy, &opts->dp); - if (ret) { - dev_err(&phy->dev, "cdns_torrent_dp_set_lanes failed\n"); - return ret; - } - } - - if (opts->dp.set_rate) { - ret = cdns_torrent_dp_set_rate(cdns_phy, &opts->dp); - if (ret) { - dev_err(&phy->dev, "cdns_torrent_dp_set_rate failed\n"); - return ret; - } - } - - if (opts->dp.set_voltages) - cdns_torrent_dp_set_voltages(cdns_phy, &opts->dp); - - return ret; -} - -static int cdns_torrent_dp_init(struct phy *phy) -{ - unsigned char lane_bits; - int ret; - struct cdns_torrent_inst *inst = phy_get_drvdata(phy); - struct cdns_torrent_phy *cdns_phy = dev_get_drvdata(phy->dev.parent); - struct regmap *regmap = cdns_phy->regmap_dptx_phy_reg; - - switch (cdns_phy->ref_clk_rate) { - case REF_CLK_19_2MHZ: - case REF_CLK_25MHZ: - /* Valid Ref Clock Rate */ - break; - default: - dev_err(cdns_phy->dev, "Unsupported Ref Clock Rate\n"); - return -EINVAL; - } - - cdns_torrent_dp_write(regmap, PHY_AUX_CTRL, 0x0003); /* enable AUX */ - - /* PHY PMA registers configuration function */ - cdns_torrent_dp_pma_cfg(cdns_phy, inst); - - /* - * Set lines power state to A0 - * Set lines pll clk enable to 0 - */ - cdns_torrent_dp_set_a0_pll(cdns_phy, inst->num_lanes); - - /* - * release phy_l0*_reset_n and pma_tx_elec_idle_ln_* based on - * used lanes - */ - lane_bits = (1 << inst->num_lanes) - 1; - cdns_torrent_dp_write(regmap, PHY_RESET, - ((0xF & ~lane_bits) << 4) | (0xF & lane_bits)); - - /* release pma_xcvr_pllclk_en_ln_*, only for the master lane */ - cdns_torrent_dp_write(regmap, PHY_PMA_XCVR_PLLCLK_EN, 0x0001); - - /* PHY PMA registers configuration functions */ - /* Initialize PHY with max supported link rate, without SSC. */ - if (cdns_phy->ref_clk_rate == REF_CLK_19_2MHZ) - cdns_torrent_dp_pma_cmn_vco_cfg_19_2mhz(cdns_phy, - cdns_phy->max_bit_rate, - false); - else if (cdns_phy->ref_clk_rate == REF_CLK_25MHZ) - cdns_torrent_dp_pma_cmn_vco_cfg_25mhz(cdns_phy, - cdns_phy->max_bit_rate, - false); - cdns_torrent_dp_pma_cmn_rate(cdns_phy, cdns_phy->max_bit_rate, - inst->num_lanes); - - /* take out of reset */ - regmap_field_write(cdns_phy->phy_reset_ctrl, 0x1); - - cdns_torrent_phy_on(phy); - - ret = cdns_torrent_dp_wait_pma_cmn_ready(cdns_phy); - if (ret) - return ret; - - ret = cdns_torrent_dp_run(cdns_phy, inst->num_lanes); - - return ret; -} - -static -int cdns_torrent_dp_wait_pma_cmn_ready(struct cdns_torrent_phy *cdns_phy) -{ - unsigned int reg; - int ret; - struct regmap *regmap = cdns_phy->regmap_dptx_phy_reg; - - ret = regmap_read_poll_timeout(regmap, PHY_PMA_CMN_READY, reg, - reg & 1, 0, POLL_TIMEOUT_US); - if (ret == -ETIMEDOUT) { - dev_err(cdns_phy->dev, - "timeout waiting for PMA common ready\n"); - return -ETIMEDOUT; - } - - return 0; -} - -static void cdns_torrent_dp_pma_cfg(struct cdns_torrent_phy *cdns_phy, - struct cdns_torrent_inst *inst) -{ - unsigned int i; - - if (cdns_phy->ref_clk_rate == REF_CLK_19_2MHZ) - /* PMA common configuration 19.2MHz */ - cdns_torrent_dp_pma_cmn_cfg_19_2mhz(cdns_phy); - else if (cdns_phy->ref_clk_rate == REF_CLK_25MHZ) - /* PMA common configuration 25MHz */ - cdns_torrent_dp_pma_cmn_cfg_25mhz(cdns_phy); - - /* PMA lane configuration to deal with multi-link operation */ - for (i = 0; i < inst->num_lanes; i++) - cdns_torrent_dp_pma_lane_cfg(cdns_phy, i); -} - static void cdns_torrent_dp_pma_cmn_cfg_19_2mhz(struct cdns_torrent_phy *cdns_phy) { @@ -1478,53 +956,6 @@ void cdns_torrent_dp_pma_cmn_vco_cfg_25mhz(struct cdns_torrent_phy *cdns_phy, cdns_torrent_phy_write(regmap, CMN_PLL1_LOCK_PLLCNT_START, 0x00C7); } -static void cdns_torrent_dp_pma_cmn_rate(struct cdns_torrent_phy *cdns_phy, - u32 rate, u32 num_lanes) -{ - unsigned int clk_sel_val = 0; - unsigned int hsclk_div_val = 0; - unsigned int i; - - /* 16'h0000 for single DP link configuration */ - regmap_field_write(cdns_phy->phy_pll_cfg, 0x0); - - switch (rate) { - case 1620: - clk_sel_val = 0x0f01; - hsclk_div_val = 2; - break; - case 2160: - case 2430: - case 2700: - clk_sel_val = 0x0701; - hsclk_div_val = 1; - break; - case 3240: - clk_sel_val = 0x0b00; - hsclk_div_val = 2; - break; - case 4320: - case 5400: - clk_sel_val = 0x0301; - hsclk_div_val = 0; - break; - case 8100: - clk_sel_val = 0x0200; - hsclk_div_val = 0; - break; - } - - cdns_torrent_phy_write(cdns_phy->regmap_common_cdb, - CMN_PDIAG_PLL0_CLK_SEL_M0, clk_sel_val); - cdns_torrent_phy_write(cdns_phy->regmap_common_cdb, - CMN_PDIAG_PLL1_CLK_SEL_M0, clk_sel_val); - - /* PMA lane configuration to deal with multi-link operation */ - for (i = 0; i < num_lanes; i++) - cdns_torrent_phy_write(cdns_phy->regmap_tx_lane_cdb[i], - XCVR_DIAG_HSCLK_DIV, hsclk_div_val); -} - static void cdns_torrent_dp_pma_lane_cfg(struct cdns_torrent_phy *cdns_phy, unsigned int lane) { @@ -1568,6 +999,77 @@ static void cdns_torrent_dp_pma_lane_cfg(struct cdns_torrent_phy *cdns_phy, XCVR_DIAG_HSCLK_SEL, 0x0000); } +static void cdns_torrent_dp_pma_cfg(struct cdns_torrent_phy *cdns_phy, + struct cdns_torrent_inst *inst) +{ + unsigned int i; + + if (cdns_phy->ref_clk_rate == REF_CLK_19_2MHZ) + /* PMA common configuration 19.2MHz */ + cdns_torrent_dp_pma_cmn_cfg_19_2mhz(cdns_phy); + else if (cdns_phy->ref_clk_rate == REF_CLK_25MHZ) + /* PMA common configuration 25MHz */ + cdns_torrent_dp_pma_cmn_cfg_25mhz(cdns_phy); + + /* PMA lane configuration to deal with multi-link operation */ + for (i = 0; i < inst->num_lanes; i++) + cdns_torrent_dp_pma_lane_cfg(cdns_phy, i); +} + +/* + * Enable or disable PLL for selected lanes. + */ +static int cdns_torrent_dp_set_pll_en(struct cdns_torrent_phy *cdns_phy, + struct phy_configure_opts_dp *dp, + bool enable) +{ + u32 rd_val; + u32 ret; + struct regmap *regmap = cdns_phy->regmap_dptx_phy_reg; + + /* + * Used to determine, which bits to check for or enable in + * PHY_PMA_XCVR_PLLCLK_EN register. + */ + u32 pll_bits; + /* Used to enable or disable lanes. */ + u32 pll_val; + + /* Select values of registers and mask, depending on enabled lane + * count. + */ + switch (dp->lanes) { + /* lane 0 */ + case (1): + pll_bits = 0x00000001; + break; + /* lanes 0-1 */ + case (2): + pll_bits = 0x00000003; + break; + /* lanes 0-3, all */ + default: + pll_bits = 0x0000000F; + break; + } + + if (enable) + pll_val = pll_bits; + else + pll_val = 0x00000000; + + cdns_torrent_dp_write(regmap, PHY_PMA_XCVR_PLLCLK_EN, pll_val); + + /* Wait for acknowledgment from PHY. */ + ret = regmap_read_poll_timeout(regmap, + PHY_PMA_XCVR_PLLCLK_EN_ACK, + rd_val, + (rd_val & pll_bits) == pll_val, + 0, POLL_TIMEOUT_US); + ndelay(100); + return ret; +} + static int cdns_torrent_dp_set_power_state(struct cdns_torrent_phy *cdns_phy, u32 num_lanes, enum phy_powerstate powerstate) @@ -1662,6 +1164,502 @@ static int cdns_torrent_dp_run(struct cdns_torrent_phy *cdns_phy, u32 num_lanes) return ret; } +static int cdns_torrent_dp_wait_pma_cmn_ready(struct cdns_torrent_phy *cdns_phy) +{ + unsigned int reg; + int ret; + struct regmap *regmap = cdns_phy->regmap_dptx_phy_reg; + + ret = regmap_read_poll_timeout(regmap, PHY_PMA_CMN_READY, reg, + reg & 1, 0, POLL_TIMEOUT_US); + if (ret == -ETIMEDOUT) { + dev_err(cdns_phy->dev, + "timeout waiting for PMA common ready\n"); + return -ETIMEDOUT; + } + + return 0; +} + +static void cdns_torrent_dp_pma_cmn_rate(struct cdns_torrent_phy *cdns_phy, + u32 rate, u32 num_lanes) +{ + unsigned int clk_sel_val = 0; + unsigned int hsclk_div_val = 0; + unsigned int i; + + /* 16'h0000 for single DP link configuration */ + regmap_field_write(cdns_phy->phy_pll_cfg, 0x0); + + switch (rate) { + case 1620: + clk_sel_val = 0x0f01; + hsclk_div_val = 2; + break; + case 2160: + case 2430: + case 2700: + clk_sel_val = 0x0701; + hsclk_div_val = 1; + break; + case 3240: + clk_sel_val = 0x0b00; + hsclk_div_val = 2; + break; + case 4320: + case 5400: + clk_sel_val = 0x0301; + hsclk_div_val = 0; + break; + case 8100: + clk_sel_val = 0x0200; + hsclk_div_val = 0; + break; + } + + cdns_torrent_phy_write(cdns_phy->regmap_common_cdb, + CMN_PDIAG_PLL0_CLK_SEL_M0, clk_sel_val); + cdns_torrent_phy_write(cdns_phy->regmap_common_cdb, + CMN_PDIAG_PLL1_CLK_SEL_M0, clk_sel_val); + + /* PMA lane configuration to deal with multi-link operation */ + for (i = 0; i < num_lanes; i++) + cdns_torrent_phy_write(cdns_phy->regmap_tx_lane_cdb[i], + XCVR_DIAG_HSCLK_DIV, hsclk_div_val); +} + +/* + * Perform register operations related to setting link rate, once powerstate is + * set and PLL disable request was processed. + */ +static int cdns_torrent_dp_configure_rate(struct cdns_torrent_phy *cdns_phy, + struct phy_configure_opts_dp *dp) +{ + u32 ret; + u32 read_val; + + /* Disable the cmn_pll0_en before re-programming the new data rate. */ + regmap_field_write(cdns_phy->phy_pma_pll_raw_ctrl, 0x0); + + /* + * Wait for PLL ready de-assertion. + * For PLL0 - PHY_PMA_CMN_CTRL2[2] == 1 + */ + ret = regmap_field_read_poll_timeout(cdns_phy->phy_pma_cmn_ctrl_2, + read_val, + ((read_val >> 2) & 0x01) != 0, + 0, POLL_TIMEOUT_US); + if (ret) + return ret; + ndelay(200); + + /* DP Rate Change - VCO Output settings. */ + if (cdns_phy->ref_clk_rate == REF_CLK_19_2MHZ) { + /* PMA common configuration 19.2MHz */ + cdns_torrent_dp_pma_cmn_vco_cfg_19_2mhz(cdns_phy, dp->link_rate, + dp->ssc); + cdns_torrent_dp_pma_cmn_cfg_19_2mhz(cdns_phy); + } else if (cdns_phy->ref_clk_rate == REF_CLK_25MHZ) { + /* PMA common configuration 25MHz */ + cdns_torrent_dp_pma_cmn_vco_cfg_25mhz(cdns_phy, dp->link_rate, + dp->ssc); + cdns_torrent_dp_pma_cmn_cfg_25mhz(cdns_phy); + } + cdns_torrent_dp_pma_cmn_rate(cdns_phy, dp->link_rate, dp->lanes); + + /* Enable the cmn_pll0_en. */ + regmap_field_write(cdns_phy->phy_pma_pll_raw_ctrl, 0x3); + + /* + * Wait for PLL ready assertion. + * For PLL0 - PHY_PMA_CMN_CTRL2[0] == 1 + */ + ret = regmap_field_read_poll_timeout(cdns_phy->phy_pma_cmn_ctrl_2, + read_val, + (read_val & 0x01) != 0, + 0, POLL_TIMEOUT_US); + return ret; +} + +/* + * Verify, that parameters to configure PHY with are correct. + */ +static int cdns_torrent_dp_verify_config(struct cdns_torrent_inst *inst, + struct phy_configure_opts_dp *dp) +{ + u8 i; + + /* If changing link rate was required, verify it's supported. */ + if (dp->set_rate) { + switch (dp->link_rate) { + case 1620: + case 2160: + case 2430: + case 2700: + case 3240: + case 4320: + case 5400: + case 8100: + /* valid bit rate */ + break; + default: + return -EINVAL; + } + } + + /* Verify lane count. */ + switch (dp->lanes) { + case 1: + case 2: + case 4: + /* valid lane count. */ + break; + default: + return -EINVAL; + } + + /* Check against actual number of PHY's lanes. */ + if (dp->lanes > inst->num_lanes) + return -EINVAL; + + /* + * If changing voltages is required, check swing and pre-emphasis + * levels, per-lane. + */ + if (dp->set_voltages) { + /* Lane count verified previously. */ + for (i = 0; i < dp->lanes; i++) { + if (dp->voltage[i] > 3 || dp->pre[i] > 3) + return -EINVAL; + + /* Sum of voltage swing and pre-emphasis levels cannot + * exceed 3. + */ + if (dp->voltage[i] + dp->pre[i] > 3) + return -EINVAL; + } + } + + return 0; +} + +/* Set power state A0 and PLL clock enable to 0 on enabled lanes. */ +static void cdns_torrent_dp_set_a0_pll(struct cdns_torrent_phy *cdns_phy, + u32 num_lanes) +{ + struct regmap *regmap = cdns_phy->regmap_dptx_phy_reg; + u32 pwr_state = cdns_torrent_dp_read(regmap, + PHY_PMA_XCVR_POWER_STATE_REQ); + u32 pll_clk_en = cdns_torrent_dp_read(regmap, + PHY_PMA_XCVR_PLLCLK_EN); + + /* Lane 0 is always enabled. */ + pwr_state &= ~(PMA_XCVR_POWER_STATE_REQ_LN_MASK << + PHY_POWER_STATE_LN_0); + pll_clk_en &= ~0x01U; + + if (num_lanes > 1) { + /* lane 1 */ + pwr_state &= ~(PMA_XCVR_POWER_STATE_REQ_LN_MASK << + PHY_POWER_STATE_LN_1); + pll_clk_en &= ~(0x01U << 1); + } + + if (num_lanes > 2) { + /* lanes 2 and 3 */ + pwr_state &= ~(PMA_XCVR_POWER_STATE_REQ_LN_MASK << + PHY_POWER_STATE_LN_2); + pwr_state &= ~(PMA_XCVR_POWER_STATE_REQ_LN_MASK << + PHY_POWER_STATE_LN_3); + pll_clk_en &= ~(0x01U << 2); + pll_clk_en &= ~(0x01U << 3); + } + + cdns_torrent_dp_write(regmap, PHY_PMA_XCVR_POWER_STATE_REQ, pwr_state); + cdns_torrent_dp_write(regmap, PHY_PMA_XCVR_PLLCLK_EN, pll_clk_en); +} + +/* Configure lane count as required. */ +static int cdns_torrent_dp_set_lanes(struct cdns_torrent_phy *cdns_phy, + struct phy_configure_opts_dp *dp) +{ + u32 value; + u32 ret; + struct regmap *regmap = cdns_phy->regmap_dptx_phy_reg; + u8 lane_mask = (1 << dp->lanes) - 1; + + value = cdns_torrent_dp_read(regmap, PHY_RESET); + /* clear pma_tx_elec_idle_ln_* bits. */ + value &= ~PMA_TX_ELEC_IDLE_MASK; + /* Assert pma_tx_elec_idle_ln_* for disabled lanes. */ + value |= ((~lane_mask) << PMA_TX_ELEC_IDLE_SHIFT) & + PMA_TX_ELEC_IDLE_MASK; + cdns_torrent_dp_write(regmap, PHY_RESET, value); + + /* reset the link by asserting phy_l00_reset_n low */ + cdns_torrent_dp_write(regmap, PHY_RESET, + value & (~PHY_L00_RESET_N_MASK)); + + /* + * Assert lane reset on unused lanes and lane 0 so they remain in reset + * and powered down when re-enabling the link + */ + value = (value & 0x0000FFF0) | (0x0000000E & lane_mask); + cdns_torrent_dp_write(regmap, PHY_RESET, value); + + cdns_torrent_dp_set_a0_pll(cdns_phy, dp->lanes); + + /* release phy_l0*_reset_n based on used laneCount */ + value = (value & 0x0000FFF0) | (0x0000000F & lane_mask); + cdns_torrent_dp_write(regmap, PHY_RESET, value); + + /* Wait, until PHY gets ready after releasing PHY reset signal. */ + ret = cdns_torrent_dp_wait_pma_cmn_ready(cdns_phy); + if (ret) + return ret; + + ndelay(100); + + /* release pma_xcvr_pllclk_en_ln_*, only for the master lane */ + cdns_torrent_dp_write(regmap, PHY_PMA_XCVR_PLLCLK_EN, 0x0001); + + ret = cdns_torrent_dp_run(cdns_phy, dp->lanes); + + return ret; +} + +/* Configure link rate as required. */ +static int cdns_torrent_dp_set_rate(struct cdns_torrent_phy *cdns_phy, + struct phy_configure_opts_dp *dp) +{ + u32 ret; + + ret = cdns_torrent_dp_set_power_state(cdns_phy, dp->lanes, + POWERSTATE_A3); + if (ret) + return ret; + ret = cdns_torrent_dp_set_pll_en(cdns_phy, dp, false); + if (ret) + return ret; + ndelay(200); + + ret = cdns_torrent_dp_configure_rate(cdns_phy, dp); + if (ret) + return ret; + ndelay(200); + + ret = cdns_torrent_dp_set_pll_en(cdns_phy, dp, true); + if (ret) + return ret; + ret = cdns_torrent_dp_set_power_state(cdns_phy, dp->lanes, + POWERSTATE_A2); + if (ret) + return ret; + ret = cdns_torrent_dp_set_power_state(cdns_phy, dp->lanes, + POWERSTATE_A0); + if (ret) + return ret; + ndelay(900); + + return ret; +} + +/* Configure voltage swing and pre-emphasis for all enabled lanes. */ +static void cdns_torrent_dp_set_voltages(struct cdns_torrent_phy *cdns_phy, + struct phy_configure_opts_dp *dp) +{ + u8 lane; + u16 val; + + for (lane = 0; lane < dp->lanes; lane++) { + val = cdns_torrent_phy_read(cdns_phy->regmap_tx_lane_cdb[lane], + TX_DIAG_ACYA); + /* + * Write 1 to register bit TX_DIAG_ACYA[0] to freeze the + * current state of the analog TX driver. + */ + val |= TX_DIAG_ACYA_HBDC_MASK; + cdns_torrent_phy_write(cdns_phy->regmap_tx_lane_cdb[lane], + TX_DIAG_ACYA, val); + + cdns_torrent_phy_write(cdns_phy->regmap_tx_lane_cdb[lane], + TX_TXCC_CTRL, 0x08A4); + val = vltg_coeff[dp->voltage[lane]][dp->pre[lane]].diag_tx_drv; + cdns_torrent_phy_write(cdns_phy->regmap_tx_lane_cdb[lane], + DRV_DIAG_TX_DRV, val); + val = vltg_coeff[dp->voltage[lane]][dp->pre[lane]].mgnfs_mult; + cdns_torrent_phy_write(cdns_phy->regmap_tx_lane_cdb[lane], + TX_TXCC_MGNFS_MULT_000, + val); + val = vltg_coeff[dp->voltage[lane]][dp->pre[lane]].cpost_mult; + cdns_torrent_phy_write(cdns_phy->regmap_tx_lane_cdb[lane], + TX_TXCC_CPOST_MULT_00, + val); + + val = cdns_torrent_phy_read(cdns_phy->regmap_tx_lane_cdb[lane], + TX_DIAG_ACYA); + /* + * Write 0 to register bit TX_DIAG_ACYA[0] to allow the state of + * analog TX driver to reflect the new programmed one. + */ + val &= ~TX_DIAG_ACYA_HBDC_MASK; + cdns_torrent_phy_write(cdns_phy->regmap_tx_lane_cdb[lane], + TX_DIAG_ACYA, val); + } +}; + +static int cdns_torrent_dp_configure(struct phy *phy, + union phy_configure_opts *opts) +{ + struct cdns_torrent_inst *inst = phy_get_drvdata(phy); + struct cdns_torrent_phy *cdns_phy = dev_get_drvdata(phy->dev.parent); + int ret; + + ret = cdns_torrent_dp_verify_config(inst, &opts->dp); + if (ret) { + dev_err(&phy->dev, "invalid params for phy configure\n"); + return ret; + } + + if (opts->dp.set_lanes) { + ret = cdns_torrent_dp_set_lanes(cdns_phy, &opts->dp); + if (ret) { + dev_err(&phy->dev, "cdns_torrent_dp_set_lanes failed\n"); + return ret; + } + } + + if (opts->dp.set_rate) { + ret = cdns_torrent_dp_set_rate(cdns_phy, &opts->dp); + if (ret) { + dev_err(&phy->dev, "cdns_torrent_dp_set_rate failed\n"); + return ret; + } + } + + if (opts->dp.set_voltages) + cdns_torrent_dp_set_voltages(cdns_phy, &opts->dp); + + return ret; +} + +static int cdns_torrent_phy_on(struct phy *phy) +{ + struct cdns_torrent_inst *inst = phy_get_drvdata(phy); + struct cdns_torrent_phy *cdns_phy = dev_get_drvdata(phy->dev.parent); + u32 read_val; + int ret; + + if (cdns_phy->nsubnodes == 1) { + /* Take the PHY lane group out of reset */ + reset_control_deassert(inst->lnk_rst); + + /* Take the PHY out of reset */ + ret = reset_control_deassert(cdns_phy->phy_rst); + if (ret) + return ret; + } + + /* + * Wait for cmn_ready assertion + * PHY_PMA_CMN_CTRL1[0] == 1 + */ + ret = regmap_field_read_poll_timeout(cdns_phy->phy_pma_cmn_ctrl_1, + read_val, read_val, 1000, + PLL_LOCK_TIMEOUT); + if (ret) { + dev_err(cdns_phy->dev, "Timeout waiting for CMN ready\n"); + return ret; + } + + mdelay(10); + + return 0; +} + +static int cdns_torrent_phy_off(struct phy *phy) +{ + struct cdns_torrent_inst *inst = phy_get_drvdata(phy); + struct cdns_torrent_phy *cdns_phy = dev_get_drvdata(phy->dev.parent); + int ret; + + if (cdns_phy->nsubnodes != 1) + return 0; + + ret = reset_control_assert(cdns_phy->phy_rst); + if (ret) + return ret; + + return reset_control_assert(inst->lnk_rst); +} + +static int cdns_torrent_dp_init(struct phy *phy) +{ + unsigned char lane_bits; + int ret; + struct cdns_torrent_inst *inst = phy_get_drvdata(phy); + struct cdns_torrent_phy *cdns_phy = dev_get_drvdata(phy->dev.parent); + struct regmap *regmap = cdns_phy->regmap_dptx_phy_reg; + + switch (cdns_phy->ref_clk_rate) { + case REF_CLK_19_2MHZ: + case REF_CLK_25MHZ: + /* Valid Ref Clock Rate */ + break; + default: + dev_err(cdns_phy->dev, "Unsupported Ref Clock Rate\n"); + return -EINVAL; + } + + cdns_torrent_dp_write(regmap, PHY_AUX_CTRL, 0x0003); /* enable AUX */ + + /* PHY PMA registers configuration function */ + cdns_torrent_dp_pma_cfg(cdns_phy, inst); + + /* + * Set lines power state to A0 + * Set lines pll clk enable to 0 + */ + cdns_torrent_dp_set_a0_pll(cdns_phy, inst->num_lanes); + + /* + * release phy_l0*_reset_n and pma_tx_elec_idle_ln_* based on + * used lanes + */ + lane_bits = (1 << inst->num_lanes) - 1; + cdns_torrent_dp_write(regmap, PHY_RESET, + ((0xF & ~lane_bits) << 4) | (0xF & lane_bits)); + + /* release pma_xcvr_pllclk_en_ln_*, only for the master lane */ + cdns_torrent_dp_write(regmap, PHY_PMA_XCVR_PLLCLK_EN, 0x0001); + + /* PHY PMA registers configuration functions */ + /* Initialize PHY with max supported link rate, without SSC. */ + if (cdns_phy->ref_clk_rate == REF_CLK_19_2MHZ) + cdns_torrent_dp_pma_cmn_vco_cfg_19_2mhz(cdns_phy, + cdns_phy->max_bit_rate, + false); + else if (cdns_phy->ref_clk_rate == REF_CLK_25MHZ) + cdns_torrent_dp_pma_cmn_vco_cfg_25mhz(cdns_phy, + cdns_phy->max_bit_rate, + false); + cdns_torrent_dp_pma_cmn_rate(cdns_phy, cdns_phy->max_bit_rate, + inst->num_lanes); + + /* take out of reset */ + regmap_field_write(cdns_phy->phy_reset_ctrl, 0x1); + + cdns_torrent_phy_on(phy); + + ret = cdns_torrent_dp_wait_pma_cmn_ready(cdns_phy); + if (ret) + return ret; + + ret = cdns_torrent_dp_run(cdns_phy, inst->num_lanes); + + return ret; +} + static int cdns_torrent_derived_refclk_enable(struct clk_hw *hw) { struct cdns_torrent_derived_refclk *derived_refclk = to_cdns_torrent_derived_refclk(hw); @@ -1764,56 +1762,6 @@ static int cdns_torrent_derived_refclk_register(struct cdns_torrent_phy *cdns_ph return 0; } -static int cdns_torrent_phy_on(struct phy *phy) -{ - struct cdns_torrent_inst *inst = phy_get_drvdata(phy); - struct cdns_torrent_phy *cdns_phy = dev_get_drvdata(phy->dev.parent); - u32 read_val; - int ret; - - if (cdns_phy->nsubnodes == 1) { - /* Take the PHY lane group out of reset */ - reset_control_deassert(inst->lnk_rst); - - /* Take the PHY out of reset */ - ret = reset_control_deassert(cdns_phy->phy_rst); - if (ret) - return ret; - } - - /* - * Wait for cmn_ready assertion - * PHY_PMA_CMN_CTRL1[0] == 1 - */ - ret = regmap_field_read_poll_timeout(cdns_phy->phy_pma_cmn_ctrl_1, - read_val, read_val, 1000, - PLL_LOCK_TIMEOUT); - if (ret) { - dev_err(cdns_phy->dev, "Timeout waiting for CMN ready\n"); - return ret; - } - - mdelay(10); - - return 0; -} - -static int cdns_torrent_phy_off(struct phy *phy) -{ - struct cdns_torrent_inst *inst = phy_get_drvdata(phy); - struct cdns_torrent_phy *cdns_phy = dev_get_drvdata(phy->dev.parent); - int ret; - - if (cdns_phy->nsubnodes != 1) - return 0; - - ret = reset_control_assert(cdns_phy->phy_rst); - if (ret) - return ret; - - return reset_control_assert(inst->lnk_rst); -} - static struct regmap *cdns_regmap_init(struct device *dev, void __iomem *base, u32 block_offset, u8 reg_offset_shift, @@ -2091,6 +2039,27 @@ static int cdns_torrent_phy_init(struct phy *phy) return 0; } +static const struct phy_ops cdns_torrent_phy_ops = { + .init = cdns_torrent_phy_init, + .configure = cdns_torrent_dp_configure, + .power_on = cdns_torrent_phy_on, + .power_off = cdns_torrent_phy_off, + .owner = THIS_MODULE, +}; + +static int cdns_torrent_noop_phy_on(struct phy *phy) +{ + /* Give 5ms to 10ms delay for the PIPE clock to be stable */ + usleep_range(5000, 10000); + + return 0; +} + +static const struct phy_ops noop_ops = { + .power_on = cdns_torrent_noop_phy_on, + .owner = THIS_MODULE, +}; + static int cdns_torrent_phy_configure_multilink(struct cdns_torrent_phy *cdns_phy) { |