mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-08-23 09:19:51 +00:00
phy: cadence-torrent: Implement PHY configure APIs
Add support for PHY configuration APIs. These will mainly reconfigure link rate, number of lanes, voltage swing and pre-emphasis values. Signed-off-by: Swapnil Jakhade <sjakhade@cadence.com> Signed-off-by: Yuti Amonkar <yamonkar@cadence.com> Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>
This commit is contained in:
parent
e4b496a376
commit
572d659256
1 changed files with 431 additions and 5 deletions
|
@ -36,6 +36,9 @@
|
||||||
#define PHY_AUX_CONFIG 0x00
|
#define PHY_AUX_CONFIG 0x00
|
||||||
#define PHY_AUX_CTRL 0x04
|
#define PHY_AUX_CTRL 0x04
|
||||||
#define PHY_RESET 0x20
|
#define PHY_RESET 0x20
|
||||||
|
#define PMA_TX_ELEC_IDLE_MASK 0xF0U
|
||||||
|
#define PMA_TX_ELEC_IDLE_SHIFT 4
|
||||||
|
#define PHY_L00_RESET_N_MASK 0x01U
|
||||||
#define PHY_PMA_XCVR_PLLCLK_EN 0x24
|
#define PHY_PMA_XCVR_PLLCLK_EN 0x24
|
||||||
#define PHY_PMA_XCVR_PLLCLK_EN_ACK 0x28
|
#define PHY_PMA_XCVR_PLLCLK_EN_ACK 0x28
|
||||||
#define PHY_PMA_XCVR_POWER_STATE_REQ 0x2c
|
#define PHY_PMA_XCVR_POWER_STATE_REQ 0x2c
|
||||||
|
@ -119,6 +122,10 @@
|
||||||
#define CMN_PDIAG_PLL1_CP_IADJ_M0 0x00714
|
#define CMN_PDIAG_PLL1_CP_IADJ_M0 0x00714
|
||||||
#define CMN_PDIAG_PLL1_FILT_PADJ_M0 0x00718
|
#define CMN_PDIAG_PLL1_FILT_PADJ_M0 0x00718
|
||||||
|
|
||||||
|
#define TX_TXCC_CTRL 0x10100
|
||||||
|
#define TX_TXCC_CPOST_MULT_00 0x10130
|
||||||
|
#define TX_TXCC_MGNFS_MULT_000 0x10140
|
||||||
|
#define DRV_DIAG_TX_DRV 0x10318
|
||||||
#define XCVR_DIAG_PLLDRC_CTRL 0x10394
|
#define XCVR_DIAG_PLLDRC_CTRL 0x10394
|
||||||
#define XCVR_DIAG_HSCLK_SEL 0x10398
|
#define XCVR_DIAG_HSCLK_SEL 0x10398
|
||||||
#define XCVR_DIAG_HSCLK_DIV 0x1039c
|
#define XCVR_DIAG_HSCLK_DIV 0x1039c
|
||||||
|
@ -128,6 +135,8 @@
|
||||||
#define TX_PSC_A2 0x10408
|
#define TX_PSC_A2 0x10408
|
||||||
#define TX_PSC_A3 0x1040c
|
#define TX_PSC_A3 0x1040c
|
||||||
#define TX_RCVDET_ST_TMR 0x1048c
|
#define TX_RCVDET_ST_TMR 0x1048c
|
||||||
|
#define TX_DIAG_ACYA 0x1079c
|
||||||
|
#define TX_DIAG_ACYA_HBDC_MASK 0x0001U
|
||||||
#define RX_PSC_A0 0x20000
|
#define RX_PSC_A0 0x20000
|
||||||
#define RX_PSC_A1 0x20004
|
#define RX_PSC_A1 0x20004
|
||||||
#define RX_PSC_A2 0x20008
|
#define RX_PSC_A2 0x20008
|
||||||
|
@ -139,6 +148,9 @@
|
||||||
|
|
||||||
#define PHY_PLL_CFG 0x30038
|
#define PHY_PLL_CFG 0x30038
|
||||||
|
|
||||||
|
#define PHY_PMA_CMN_CTRL2 0x38004
|
||||||
|
#define PHY_PMA_PLL_RAW_CTRL 0x3800c
|
||||||
|
|
||||||
struct cdns_torrent_phy {
|
struct cdns_torrent_phy {
|
||||||
void __iomem *base; /* DPTX registers base */
|
void __iomem *base; /* DPTX registers base */
|
||||||
void __iomem *sd_base; /* SD0801 registers base */
|
void __iomem *sd_base; /* SD0801 registers base */
|
||||||
|
@ -158,7 +170,8 @@ enum phy_powerstate {
|
||||||
|
|
||||||
static int cdns_torrent_dp_init(struct phy *phy);
|
static int cdns_torrent_dp_init(struct phy *phy);
|
||||||
static int cdns_torrent_dp_exit(struct phy *phy);
|
static int cdns_torrent_dp_exit(struct phy *phy);
|
||||||
static int cdns_torrent_dp_run(struct cdns_torrent_phy *cdns_phy);
|
static int cdns_torrent_dp_run(struct cdns_torrent_phy *cdns_phy,
|
||||||
|
u32 num_lanes);
|
||||||
static
|
static
|
||||||
int cdns_torrent_dp_wait_pma_cmn_ready(struct cdns_torrent_phy *cdns_phy);
|
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);
|
static void cdns_torrent_dp_pma_cfg(struct cdns_torrent_phy *cdns_phy);
|
||||||
|
@ -182,9 +195,16 @@ static void cdns_dp_phy_write_field(struct cdns_torrent_phy *cdns_phy,
|
||||||
unsigned char num_bits,
|
unsigned char num_bits,
|
||||||
unsigned int val);
|
unsigned int val);
|
||||||
|
|
||||||
|
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 const struct phy_ops cdns_torrent_phy_ops = {
|
static const struct phy_ops cdns_torrent_phy_ops = {
|
||||||
.init = cdns_torrent_dp_init,
|
.init = cdns_torrent_dp_init,
|
||||||
.exit = cdns_torrent_dp_exit,
|
.exit = cdns_torrent_dp_exit,
|
||||||
|
.configure = cdns_torrent_dp_configure,
|
||||||
.owner = THIS_MODULE,
|
.owner = THIS_MODULE,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -196,6 +216,16 @@ static void cdns_torrent_phy_write(struct cdns_torrent_phy *cdns_phy,
|
||||||
writel(val, cdns_phy->sd_base + offset);
|
writel(val, cdns_phy->sd_base + offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static u32 cdns_torrent_phy_read(struct cdns_torrent_phy *cdns_phy, u32 offset)
|
||||||
|
{
|
||||||
|
return readl(cdns_phy->sd_base + offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define cdns_torrent_phy_read_poll_timeout(cdns_phy, offset, val, cond, \
|
||||||
|
delay_us, timeout_us) \
|
||||||
|
readl_poll_timeout((cdns_phy)->sd_base + (offset), \
|
||||||
|
val, cond, delay_us, timeout_us)
|
||||||
|
|
||||||
/* DPTX mmr access functions */
|
/* DPTX mmr access functions */
|
||||||
|
|
||||||
static void cdns_torrent_dp_write(struct cdns_torrent_phy *cdns_phy,
|
static void cdns_torrent_dp_write(struct cdns_torrent_phy *cdns_phy,
|
||||||
|
@ -214,6 +244,237 @@ static u32 cdns_torrent_dp_read(struct cdns_torrent_phy *cdns_phy, u32 offset)
|
||||||
readl_poll_timeout((cdns_phy)->base + (offset), \
|
readl_poll_timeout((cdns_phy)->base + (offset), \
|
||||||
val, cond, delay_us, timeout_us)
|
val, cond, delay_us, timeout_us)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Structure used to store values of PHY registers for voltage-related
|
||||||
|
* coefficients, for particular voltage swing and pre-emphasis level. Values
|
||||||
|
* are shared across all physical lanes.
|
||||||
|
*/
|
||||||
|
struct coefficients {
|
||||||
|
/* Value of DRV_DIAG_TX_DRV register to use */
|
||||||
|
u16 diag_tx_drv;
|
||||||
|
/* Value of TX_TXCC_MGNFS_MULT_000 register to use */
|
||||||
|
u16 mgnfs_mult;
|
||||||
|
/* Value of TX_TXCC_CPOST_MULT_00 register to use */
|
||||||
|
u16 cpost_mult;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Array consists of values of voltage-related registers for sd0801 PHY. A value
|
||||||
|
* of 0xFFFF is a placeholder for invalid combination, and will never be used.
|
||||||
|
*/
|
||||||
|
static const struct coefficients vltg_coeff[4][4] = {
|
||||||
|
/* voltage swing 0, pre-emphasis 0->3 */
|
||||||
|
{ {.diag_tx_drv = 0x0003, .mgnfs_mult = 0x002A,
|
||||||
|
.cpost_mult = 0x0000},
|
||||||
|
{.diag_tx_drv = 0x0003, .mgnfs_mult = 0x001F,
|
||||||
|
.cpost_mult = 0x0014},
|
||||||
|
{.diag_tx_drv = 0x0003, .mgnfs_mult = 0x0012,
|
||||||
|
.cpost_mult = 0x0020},
|
||||||
|
{.diag_tx_drv = 0x0003, .mgnfs_mult = 0x0000,
|
||||||
|
.cpost_mult = 0x002A}
|
||||||
|
},
|
||||||
|
|
||||||
|
/* voltage swing 1, pre-emphasis 0->3 */
|
||||||
|
{ {.diag_tx_drv = 0x0003, .mgnfs_mult = 0x001F,
|
||||||
|
.cpost_mult = 0x0000},
|
||||||
|
{.diag_tx_drv = 0x0003, .mgnfs_mult = 0x0013,
|
||||||
|
.cpost_mult = 0x0012},
|
||||||
|
{.diag_tx_drv = 0x0003, .mgnfs_mult = 0x0000,
|
||||||
|
.cpost_mult = 0x001F},
|
||||||
|
{.diag_tx_drv = 0xFFFF, .mgnfs_mult = 0xFFFF,
|
||||||
|
.cpost_mult = 0xFFFF}
|
||||||
|
},
|
||||||
|
|
||||||
|
/* voltage swing 2, pre-emphasis 0->3 */
|
||||||
|
{ {.diag_tx_drv = 0x0003, .mgnfs_mult = 0x0013,
|
||||||
|
.cpost_mult = 0x0000},
|
||||||
|
{.diag_tx_drv = 0x0003, .mgnfs_mult = 0x0000,
|
||||||
|
.cpost_mult = 0x0013},
|
||||||
|
{.diag_tx_drv = 0xFFFF, .mgnfs_mult = 0xFFFF,
|
||||||
|
.cpost_mult = 0xFFFF},
|
||||||
|
{.diag_tx_drv = 0xFFFF, .mgnfs_mult = 0xFFFF,
|
||||||
|
.cpost_mult = 0xFFFF}
|
||||||
|
},
|
||||||
|
|
||||||
|
/* voltage swing 3, pre-emphasis 0->3 */
|
||||||
|
{ {.diag_tx_drv = 0x0003, .mgnfs_mult = 0x0000,
|
||||||
|
.cpost_mult = 0x0000},
|
||||||
|
{.diag_tx_drv = 0xFFFF, .mgnfs_mult = 0xFFFF,
|
||||||
|
.cpost_mult = 0xFFFF},
|
||||||
|
{.diag_tx_drv = 0xFFFF, .mgnfs_mult = 0xFFFF,
|
||||||
|
.cpost_mult = 0xFFFF},
|
||||||
|
{.diag_tx_drv = 0xFFFF, .mgnfs_mult = 0xFFFF,
|
||||||
|
.cpost_mult = 0xFFFF}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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;
|
||||||
|
/*
|
||||||
|
* 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(cdns_phy, PHY_PMA_XCVR_PLLCLK_EN, pll_val);
|
||||||
|
|
||||||
|
/* Wait for acknowledgment from PHY. */
|
||||||
|
ret = cdns_torrent_dp_read_poll_timeout(cdns_phy,
|
||||||
|
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. */
|
||||||
|
cdns_torrent_phy_write(cdns_phy, PHY_PMA_PLL_RAW_CTRL, 0);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Wait for PLL ready de-assertion.
|
||||||
|
* For PLL0 - PHY_PMA_CMN_CTRL2[2] == 1
|
||||||
|
*/
|
||||||
|
ret = cdns_torrent_phy_read_poll_timeout(cdns_phy, PHY_PMA_CMN_CTRL2,
|
||||||
|
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. */
|
||||||
|
cdns_torrent_phy_write(cdns_phy, PHY_PMA_PLL_RAW_CTRL, 0x3);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Wait for PLL ready assertion.
|
||||||
|
* For PLL0 - PHY_PMA_CMN_CTRL2[0] == 1
|
||||||
|
*/
|
||||||
|
ret = cdns_torrent_phy_read_poll_timeout(cdns_phy, PHY_PMA_CMN_CTRL2,
|
||||||
|
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_phy *cdns_phy,
|
||||||
|
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 > cdns_phy->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. */
|
/* 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,
|
static void cdns_torrent_dp_set_a0_pll(struct cdns_torrent_phy *cdns_phy,
|
||||||
u32 num_lanes)
|
u32 num_lanes)
|
||||||
|
@ -250,6 +511,171 @@ static void cdns_torrent_dp_set_a0_pll(struct cdns_torrent_phy *cdns_phy,
|
||||||
cdns_torrent_dp_write(cdns_phy, PHY_PMA_XCVR_PLLCLK_EN, pll_clk_en);
|
cdns_torrent_dp_write(cdns_phy, 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;
|
||||||
|
u8 lane_mask = (1 << dp->lanes) - 1;
|
||||||
|
|
||||||
|
value = cdns_torrent_dp_read(cdns_phy, 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(cdns_phy, PHY_RESET, value);
|
||||||
|
|
||||||
|
/* reset the link by asserting phy_l00_reset_n low */
|
||||||
|
cdns_torrent_dp_write(cdns_phy, 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(cdns_phy, 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(cdns_phy, 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(cdns_phy, 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;
|
||||||
|
unsigned int lane_bits;
|
||||||
|
|
||||||
|
for (lane = 0; lane < dp->lanes; lane++) {
|
||||||
|
lane_bits = (lane & LANE_MASK) << 11;
|
||||||
|
|
||||||
|
val = cdns_torrent_phy_read(cdns_phy,
|
||||||
|
(TX_DIAG_ACYA | lane_bits));
|
||||||
|
/*
|
||||||
|
* 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,
|
||||||
|
(TX_DIAG_ACYA | lane_bits), val);
|
||||||
|
|
||||||
|
cdns_torrent_phy_write(cdns_phy,
|
||||||
|
(TX_TXCC_CTRL | lane_bits), 0x08A4);
|
||||||
|
val = vltg_coeff[dp->voltage[lane]][dp->pre[lane]].diag_tx_drv;
|
||||||
|
cdns_torrent_phy_write(cdns_phy,
|
||||||
|
(DRV_DIAG_TX_DRV | lane_bits), val);
|
||||||
|
val = vltg_coeff[dp->voltage[lane]][dp->pre[lane]].mgnfs_mult;
|
||||||
|
cdns_torrent_phy_write(cdns_phy,
|
||||||
|
(TX_TXCC_MGNFS_MULT_000 | lane_bits),
|
||||||
|
val);
|
||||||
|
val = vltg_coeff[dp->voltage[lane]][dp->pre[lane]].cpost_mult;
|
||||||
|
cdns_torrent_phy_write(cdns_phy,
|
||||||
|
(TX_TXCC_CPOST_MULT_00 | lane_bits),
|
||||||
|
val);
|
||||||
|
|
||||||
|
val = cdns_torrent_phy_read(cdns_phy,
|
||||||
|
(TX_DIAG_ACYA | lane_bits));
|
||||||
|
/*
|
||||||
|
* 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,
|
||||||
|
(TX_DIAG_ACYA | lane_bits), val);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
static int cdns_torrent_dp_configure(struct phy *phy,
|
||||||
|
union phy_configure_opts *opts)
|
||||||
|
{
|
||||||
|
struct cdns_torrent_phy *cdns_phy = phy_get_drvdata(phy);
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = cdns_torrent_dp_verify_config(cdns_phy, &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)
|
static int cdns_torrent_dp_init(struct phy *phy)
|
||||||
{
|
{
|
||||||
unsigned char lane_bits;
|
unsigned char lane_bits;
|
||||||
|
@ -321,7 +747,7 @@ static int cdns_torrent_dp_init(struct phy *phy)
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
ret = cdns_torrent_dp_run(cdns_phy);
|
ret = cdns_torrent_dp_run(cdns_phy, cdns_phy->num_lanes);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -898,7 +1324,7 @@ static int cdns_torrent_dp_set_power_state(struct cdns_torrent_phy *cdns_phy,
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int cdns_torrent_dp_run(struct cdns_torrent_phy *cdns_phy)
|
static int cdns_torrent_dp_run(struct cdns_torrent_phy *cdns_phy, u32 num_lanes)
|
||||||
{
|
{
|
||||||
unsigned int read_val;
|
unsigned int read_val;
|
||||||
int ret;
|
int ret;
|
||||||
|
@ -919,12 +1345,12 @@ static int cdns_torrent_dp_run(struct cdns_torrent_phy *cdns_phy)
|
||||||
|
|
||||||
ndelay(100);
|
ndelay(100);
|
||||||
|
|
||||||
ret = cdns_torrent_dp_set_power_state(cdns_phy, cdns_phy->num_lanes,
|
ret = cdns_torrent_dp_set_power_state(cdns_phy, num_lanes,
|
||||||
POWERSTATE_A2);
|
POWERSTATE_A2);
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
ret = cdns_torrent_dp_set_power_state(cdns_phy, cdns_phy->num_lanes,
|
ret = cdns_torrent_dp_set_power_state(cdns_phy, num_lanes,
|
||||||
POWERSTATE_A0);
|
POWERSTATE_A0);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
|
|
Loading…
Reference in a new issue