Commit 21c79146 authored by Swapnil Jakhade's avatar Swapnil Jakhade Committed by Kishon Vijay Abraham I

phy: cadence-torrent: Refactor code for reusability

Add a separate function to set different power state values.
Use uniform polling timeout value. Also check return values
of functions for proper error handling.
Signed-off-by: default avatarSwapnil Jakhade <sjakhade@cadence.com>
Signed-off-by: default avatarYuti Amonkar <yamonkar@cadence.com>
Signed-off-by: default avatarKishon Vijay Abraham I <kishon@ti.com>
parent f61b3aed
...@@ -22,7 +22,7 @@ ...@@ -22,7 +22,7 @@
#define MAX_NUM_LANES 4 #define MAX_NUM_LANES 4
#define DEFAULT_MAX_BIT_RATE 8100 /* in Mbps */ #define DEFAULT_MAX_BIT_RATE 8100 /* in Mbps */
#define POLL_TIMEOUT_US 2000 #define POLL_TIMEOUT_US 5000
#define LANE_MASK 0x7 #define LANE_MASK 0x7
/* /*
...@@ -39,6 +39,7 @@ ...@@ -39,6 +39,7 @@
#define PHY_POWER_STATE_LN_1 0x0008 #define PHY_POWER_STATE_LN_1 0x0008
#define PHY_POWER_STATE_LN_2 0x0010 #define PHY_POWER_STATE_LN_2 0x0010
#define PHY_POWER_STATE_LN_3 0x0018 #define PHY_POWER_STATE_LN_3 0x0018
#define PMA_XCVR_POWER_STATE_REQ_LN_MASK 0x3FU
#define PHY_PMA_XCVR_POWER_STATE_ACK 0x30 #define PHY_PMA_XCVR_POWER_STATE_ACK 0x30
#define PHY_PMA_CMN_READY 0x34 #define PHY_PMA_CMN_READY 0x34
#define PHY_PMA_XCVR_TX_VMARGIN 0x38 #define PHY_PMA_XCVR_TX_VMARGIN 0x38
...@@ -109,10 +110,17 @@ struct cdns_torrent_phy { ...@@ -109,10 +110,17 @@ struct cdns_torrent_phy {
struct device *dev; struct device *dev;
}; };
enum phy_powerstate {
POWERSTATE_A0 = 0,
/* Powerstate A1 is unused */
POWERSTATE_A2 = 2,
POWERSTATE_A3 = 3,
};
static int cdns_torrent_dp_init(struct phy *phy); static int cdns_torrent_dp_init(struct phy *phy);
static void cdns_torrent_dp_run(struct cdns_torrent_phy *cdns_phy); static int cdns_torrent_dp_run(struct cdns_torrent_phy *cdns_phy);
static static
void 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);
static static
void cdns_torrent_dp_pma_cmn_cfg_25mhz(struct cdns_torrent_phy *cdns_phy); void cdns_torrent_dp_pma_cmn_cfg_25mhz(struct cdns_torrent_phy *cdns_phy);
...@@ -158,9 +166,46 @@ static u32 cdns_torrent_dp_read(struct cdns_torrent_phy *cdns_phy, u32 offset) ...@@ -158,9 +166,46 @@ 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)
/* 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)
{
u32 pwr_state = cdns_torrent_dp_read(cdns_phy,
PHY_PMA_XCVR_POWER_STATE_REQ);
u32 pll_clk_en = cdns_torrent_dp_read(cdns_phy,
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(cdns_phy,
PHY_PMA_XCVR_POWER_STATE_REQ, pwr_state);
cdns_torrent_dp_write(cdns_phy, PHY_PMA_XCVR_PLLCLK_EN, pll_clk_en);
}
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;
int ret;
struct cdns_torrent_phy *cdns_phy = phy_get_drvdata(phy); struct cdns_torrent_phy *cdns_phy = phy_get_drvdata(phy);
...@@ -173,40 +218,7 @@ static int cdns_torrent_dp_init(struct phy *phy) ...@@ -173,40 +218,7 @@ static int cdns_torrent_dp_init(struct phy *phy)
* Set lines power state to A0 * Set lines power state to A0
* Set lines pll clk enable to 0 * Set lines pll clk enable to 0
*/ */
cdns_torrent_dp_set_a0_pll(cdns_phy, cdns_phy->num_lanes);
cdns_dp_phy_write_field(cdns_phy, PHY_PMA_XCVR_POWER_STATE_REQ,
PHY_POWER_STATE_LN_0, 6, 0x0000);
if (cdns_phy->num_lanes >= 2) {
cdns_dp_phy_write_field(cdns_phy,
PHY_PMA_XCVR_POWER_STATE_REQ,
PHY_POWER_STATE_LN_1, 6, 0x0000);
if (cdns_phy->num_lanes == 4) {
cdns_dp_phy_write_field(cdns_phy,
PHY_PMA_XCVR_POWER_STATE_REQ,
PHY_POWER_STATE_LN_2, 6, 0);
cdns_dp_phy_write_field(cdns_phy,
PHY_PMA_XCVR_POWER_STATE_REQ,
PHY_POWER_STATE_LN_3, 6, 0);
}
}
cdns_dp_phy_write_field(cdns_phy, PHY_PMA_XCVR_PLLCLK_EN,
0, 1, 0x0000);
if (cdns_phy->num_lanes >= 2) {
cdns_dp_phy_write_field(cdns_phy, PHY_PMA_XCVR_PLLCLK_EN,
1, 1, 0x0000);
if (cdns_phy->num_lanes == 4) {
cdns_dp_phy_write_field(cdns_phy,
PHY_PMA_XCVR_PLLCLK_EN,
2, 1, 0x0000);
cdns_dp_phy_write_field(cdns_phy,
PHY_PMA_XCVR_PLLCLK_EN,
3, 1, 0x0000);
}
}
/* /*
* release phy_l0*_reset_n and pma_tx_elec_idle_ln_* based on * release phy_l0*_reset_n and pma_tx_elec_idle_ln_* based on
...@@ -225,23 +237,31 @@ static int cdns_torrent_dp_init(struct phy *phy) ...@@ -225,23 +237,31 @@ static int cdns_torrent_dp_init(struct phy *phy)
/* take out of reset */ /* take out of reset */
cdns_dp_phy_write_field(cdns_phy, PHY_RESET, 8, 1, 1); cdns_dp_phy_write_field(cdns_phy, PHY_RESET, 8, 1, 1);
cdns_torrent_dp_wait_pma_cmn_ready(cdns_phy); ret = cdns_torrent_dp_wait_pma_cmn_ready(cdns_phy);
cdns_torrent_dp_run(cdns_phy); if (ret)
return ret;
return 0; ret = cdns_torrent_dp_run(cdns_phy);
return ret;
} }
static static
void 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)
{ {
unsigned int reg; unsigned int reg;
int ret; int ret;
ret = cdns_torrent_dp_read_poll_timeout(cdns_phy, PHY_PMA_CMN_READY, ret = cdns_torrent_dp_read_poll_timeout(cdns_phy, PHY_PMA_CMN_READY,
reg, reg & 1, 0, 500); reg, reg & 1, 0,
if (ret == -ETIMEDOUT) POLL_TIMEOUT_US);
if (ret == -ETIMEDOUT) {
dev_err(cdns_phy->dev, dev_err(cdns_phy->dev,
"timeout waiting for PMA common ready\n"); "timeout waiting for PMA common ready\n");
return -ETIMEDOUT;
}
return 0;
} }
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)
...@@ -397,12 +417,73 @@ static void cdns_torrent_dp_pma_lane_cfg(struct cdns_torrent_phy *cdns_phy, ...@@ -397,12 +417,73 @@ static void cdns_torrent_dp_pma_lane_cfg(struct cdns_torrent_phy *cdns_phy,
(XCVR_DIAG_HSCLK_SEL | lane_bits), 0x0000); (XCVR_DIAG_HSCLK_SEL | lane_bits), 0x0000);
} }
static void cdns_torrent_dp_run(struct cdns_torrent_phy *cdns_phy) static int cdns_torrent_dp_set_power_state(struct cdns_torrent_phy *cdns_phy,
u32 num_lanes,
enum phy_powerstate powerstate)
{
/* Register value for power state for a single byte. */
u32 value_part;
u32 value;
u32 mask;
u32 read_val;
u32 ret;
switch (powerstate) {
case (POWERSTATE_A0):
value_part = 0x01U;
break;
case (POWERSTATE_A2):
value_part = 0x04U;
break;
default:
/* Powerstate A3 */
value_part = 0x08U;
break;
}
/* Select values of registers and mask, depending on enabled
* lane count.
*/
switch (num_lanes) {
/* lane 0 */
case (1):
value = value_part;
mask = 0x0000003FU;
break;
/* lanes 0-1 */
case (2):
value = (value_part
| (value_part << 8));
mask = 0x00003F3FU;
break;
/* lanes 0-3, all */
default:
value = (value_part
| (value_part << 8)
| (value_part << 16)
| (value_part << 24));
mask = 0x3F3F3F3FU;
break;
}
/* Set power state A<n>. */
cdns_torrent_dp_write(cdns_phy, PHY_PMA_XCVR_POWER_STATE_REQ, value);
/* Wait, until PHY acknowledges power state completion. */
ret = cdns_torrent_dp_read_poll_timeout(cdns_phy,
PHY_PMA_XCVR_POWER_STATE_ACK,
read_val,
(read_val & mask) == value, 0,
POLL_TIMEOUT_US);
cdns_torrent_dp_write(cdns_phy,
PHY_PMA_XCVR_POWER_STATE_REQ, 0x00000000);
ndelay(100);
return ret;
}
static int cdns_torrent_dp_run(struct cdns_torrent_phy *cdns_phy)
{ {
unsigned int read_val; unsigned int read_val;
u32 write_val1 = 0;
u32 write_val2 = 0;
u32 mask = 0;
int ret; int ret;
/* /*
...@@ -413,60 +494,23 @@ static void cdns_torrent_dp_run(struct cdns_torrent_phy *cdns_phy) ...@@ -413,60 +494,23 @@ static void cdns_torrent_dp_run(struct cdns_torrent_phy *cdns_phy)
PHY_PMA_XCVR_PLLCLK_EN_ACK, PHY_PMA_XCVR_PLLCLK_EN_ACK,
read_val, read_val & 1, 0, read_val, read_val & 1, 0,
POLL_TIMEOUT_US); POLL_TIMEOUT_US);
if (ret == -ETIMEDOUT) if (ret == -ETIMEDOUT) {
dev_err(cdns_phy->dev, dev_err(cdns_phy->dev,
"timeout waiting for link PLL clock enable ack\n"); "timeout waiting for link PLL clock enable ack\n");
return ret;
ndelay(100);
switch (cdns_phy->num_lanes) {
case 1: /* lane 0 */
write_val1 = 0x00000004;
write_val2 = 0x00000001;
mask = 0x0000003f;
break;
case 2: /* lane 0-1 */
write_val1 = 0x00000404;
write_val2 = 0x00000101;
mask = 0x00003f3f;
break;
case 4: /* lane 0-3 */
write_val1 = 0x04040404;
write_val2 = 0x01010101;
mask = 0x3f3f3f3f;
break;
} }
cdns_torrent_dp_write(cdns_phy,
PHY_PMA_XCVR_POWER_STATE_REQ, write_val1);
ret = cdns_torrent_dp_read_poll_timeout(cdns_phy,
PHY_PMA_XCVR_POWER_STATE_ACK,
read_val,
(read_val & mask) == write_val1,
0, POLL_TIMEOUT_US);
if (ret == -ETIMEDOUT)
dev_err(cdns_phy->dev,
"timeout waiting for link power state ack\n");
cdns_torrent_dp_write(cdns_phy, PHY_PMA_XCVR_POWER_STATE_REQ, 0);
ndelay(100); ndelay(100);
cdns_torrent_dp_write(cdns_phy, ret = cdns_torrent_dp_set_power_state(cdns_phy, cdns_phy->num_lanes,
PHY_PMA_XCVR_POWER_STATE_REQ, write_val2); POWERSTATE_A2);
if (ret)
return ret;
ret = cdns_torrent_dp_read_poll_timeout(cdns_phy, ret = cdns_torrent_dp_set_power_state(cdns_phy, cdns_phy->num_lanes,
PHY_PMA_XCVR_POWER_STATE_ACK, POWERSTATE_A0);
read_val,
(read_val & mask) == write_val2,
0, POLL_TIMEOUT_US);
if (ret == -ETIMEDOUT)
dev_err(cdns_phy->dev,
"timeout waiting for link power state ack\n");
cdns_torrent_dp_write(cdns_phy, PHY_PMA_XCVR_POWER_STATE_REQ, 0); return ret;
ndelay(100);
} }
static void cdns_dp_phy_write_field(struct cdns_torrent_phy *cdns_phy, static void cdns_dp_phy_write_field(struct cdns_torrent_phy *cdns_phy,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment