13e0a4e85SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
20b56e9a7SVivek Gautam /*
30b56e9a7SVivek Gautam * Broadcom SATA3 AHCI Controller PHY Driver
40b56e9a7SVivek Gautam *
50b56e9a7SVivek Gautam * Copyright (C) 2016 Broadcom
60b56e9a7SVivek Gautam */
70b56e9a7SVivek Gautam
80b56e9a7SVivek Gautam #include <linux/delay.h>
90b56e9a7SVivek Gautam #include <linux/device.h>
100b56e9a7SVivek Gautam #include <linux/init.h>
110b56e9a7SVivek Gautam #include <linux/interrupt.h>
120b56e9a7SVivek Gautam #include <linux/io.h>
130b56e9a7SVivek Gautam #include <linux/kernel.h>
140b56e9a7SVivek Gautam #include <linux/module.h>
150b56e9a7SVivek Gautam #include <linux/of.h>
160b56e9a7SVivek Gautam #include <linux/phy/phy.h>
170b56e9a7SVivek Gautam #include <linux/platform_device.h>
180b56e9a7SVivek Gautam
190b56e9a7SVivek Gautam #define SATA_PCB_BANK_OFFSET 0x23c
200b56e9a7SVivek Gautam #define SATA_PCB_REG_OFFSET(ofs) ((ofs) * 4)
210b56e9a7SVivek Gautam
220b56e9a7SVivek Gautam #define MAX_PORTS 2
230b56e9a7SVivek Gautam
240b56e9a7SVivek Gautam /* Register offset between PHYs in PCB space */
250b56e9a7SVivek Gautam #define SATA_PCB_REG_28NM_SPACE_SIZE 0x1000
260b56e9a7SVivek Gautam
270b56e9a7SVivek Gautam /* The older SATA PHY registers duplicated per port registers within the map,
280b56e9a7SVivek Gautam * rather than having a separate map per port.
290b56e9a7SVivek Gautam */
300b56e9a7SVivek Gautam #define SATA_PCB_REG_40NM_SPACE_SIZE 0x10
310b56e9a7SVivek Gautam
320b56e9a7SVivek Gautam /* Register offset between PHYs in PHY control space */
330b56e9a7SVivek Gautam #define SATA_PHY_CTRL_REG_28NM_SPACE_SIZE 0x8
340b56e9a7SVivek Gautam
350b56e9a7SVivek Gautam enum brcm_sata_phy_version {
3697844253SFlorian Fainelli BRCM_SATA_PHY_STB_16NM,
370b56e9a7SVivek Gautam BRCM_SATA_PHY_STB_28NM,
380b56e9a7SVivek Gautam BRCM_SATA_PHY_STB_40NM,
390b56e9a7SVivek Gautam BRCM_SATA_PHY_IPROC_NS2,
400b56e9a7SVivek Gautam BRCM_SATA_PHY_IPROC_NSP,
4180886f7cSSrinath Mannam BRCM_SATA_PHY_IPROC_SR,
427b69fa1cSFlorian Fainelli BRCM_SATA_PHY_DSL_28NM,
430b56e9a7SVivek Gautam };
440b56e9a7SVivek Gautam
45af174c49SFlorian Fainelli enum brcm_sata_phy_rxaeq_mode {
46af174c49SFlorian Fainelli RXAEQ_MODE_OFF = 0,
47af174c49SFlorian Fainelli RXAEQ_MODE_AUTO,
48af174c49SFlorian Fainelli RXAEQ_MODE_MANUAL,
49af174c49SFlorian Fainelli };
50af174c49SFlorian Fainelli
rxaeq_to_val(const char * m)51af174c49SFlorian Fainelli static enum brcm_sata_phy_rxaeq_mode rxaeq_to_val(const char *m)
52af174c49SFlorian Fainelli {
53af174c49SFlorian Fainelli if (!strcmp(m, "auto"))
54af174c49SFlorian Fainelli return RXAEQ_MODE_AUTO;
55af174c49SFlorian Fainelli else if (!strcmp(m, "manual"))
56af174c49SFlorian Fainelli return RXAEQ_MODE_MANUAL;
57af174c49SFlorian Fainelli else
58af174c49SFlorian Fainelli return RXAEQ_MODE_OFF;
59af174c49SFlorian Fainelli }
60af174c49SFlorian Fainelli
610b56e9a7SVivek Gautam struct brcm_sata_port {
620b56e9a7SVivek Gautam int portnum;
630b56e9a7SVivek Gautam struct phy *phy;
640b56e9a7SVivek Gautam struct brcm_sata_phy *phy_priv;
650b56e9a7SVivek Gautam bool ssc_en;
66af174c49SFlorian Fainelli enum brcm_sata_phy_rxaeq_mode rxaeq_mode;
67af174c49SFlorian Fainelli u32 rxaeq_val;
68839034d8SFlorian Fainelli u32 tx_amplitude_val;
690b56e9a7SVivek Gautam };
700b56e9a7SVivek Gautam
710b56e9a7SVivek Gautam struct brcm_sata_phy {
720b56e9a7SVivek Gautam struct device *dev;
730b56e9a7SVivek Gautam void __iomem *phy_base;
740b56e9a7SVivek Gautam void __iomem *ctrl_base;
750b56e9a7SVivek Gautam enum brcm_sata_phy_version version;
760b56e9a7SVivek Gautam
770b56e9a7SVivek Gautam struct brcm_sata_port phys[MAX_PORTS];
780b56e9a7SVivek Gautam };
790b56e9a7SVivek Gautam
800b56e9a7SVivek Gautam enum sata_phy_regs {
810b56e9a7SVivek Gautam BLOCK0_REG_BANK = 0x000,
820b56e9a7SVivek Gautam BLOCK0_XGXSSTATUS = 0x81,
830b56e9a7SVivek Gautam BLOCK0_XGXSSTATUS_PLL_LOCK = BIT(12),
840b56e9a7SVivek Gautam BLOCK0_SPARE = 0x8d,
850b56e9a7SVivek Gautam BLOCK0_SPARE_OOB_CLK_SEL_MASK = 0x3,
860b56e9a7SVivek Gautam BLOCK0_SPARE_OOB_CLK_SEL_REFBY2 = 0x1,
870b56e9a7SVivek Gautam
88839034d8SFlorian Fainelli BLOCK1_REG_BANK = 0x10,
89839034d8SFlorian Fainelli BLOCK1_TEST_TX = 0x83,
90839034d8SFlorian Fainelli BLOCK1_TEST_TX_AMP_SHIFT = 12,
91839034d8SFlorian Fainelli
920b56e9a7SVivek Gautam PLL_REG_BANK_0 = 0x050,
930b56e9a7SVivek Gautam PLL_REG_BANK_0_PLLCONTROL_0 = 0x81,
940b56e9a7SVivek Gautam PLLCONTROL_0_FREQ_DET_RESTART = BIT(13),
950b56e9a7SVivek Gautam PLLCONTROL_0_FREQ_MONITOR = BIT(12),
960b56e9a7SVivek Gautam PLLCONTROL_0_SEQ_START = BIT(15),
977b69fa1cSFlorian Fainelli PLL_CAP_CHARGE_TIME = 0x83,
987b69fa1cSFlorian Fainelli PLL_VCO_CAL_THRESH = 0x84,
990b56e9a7SVivek Gautam PLL_CAP_CONTROL = 0x85,
1007b69fa1cSFlorian Fainelli PLL_FREQ_DET_TIME = 0x86,
1010b56e9a7SVivek Gautam PLL_ACTRL2 = 0x8b,
1020b56e9a7SVivek Gautam PLL_ACTRL2_SELDIV_MASK = 0x1f,
1030b56e9a7SVivek Gautam PLL_ACTRL2_SELDIV_SHIFT = 9,
10480886f7cSSrinath Mannam PLL_ACTRL6 = 0x86,
1050b56e9a7SVivek Gautam
1060b56e9a7SVivek Gautam PLL1_REG_BANK = 0x060,
1070b56e9a7SVivek Gautam PLL1_ACTRL2 = 0x82,
1080b56e9a7SVivek Gautam PLL1_ACTRL3 = 0x83,
1090b56e9a7SVivek Gautam PLL1_ACTRL4 = 0x84,
1107b69fa1cSFlorian Fainelli PLL1_ACTRL5 = 0x85,
1117b69fa1cSFlorian Fainelli PLL1_ACTRL6 = 0x86,
1127b69fa1cSFlorian Fainelli PLL1_ACTRL7 = 0x87,
11397844253SFlorian Fainelli PLL1_ACTRL8 = 0x88,
1140b56e9a7SVivek Gautam
11580886f7cSSrinath Mannam TX_REG_BANK = 0x070,
11680886f7cSSrinath Mannam TX_ACTRL0 = 0x80,
11780886f7cSSrinath Mannam TX_ACTRL0_TXPOL_FLIP = BIT(6),
11897844253SFlorian Fainelli TX_ACTRL5 = 0x85,
11997844253SFlorian Fainelli TX_ACTRL5_SSC_EN = BIT(11),
12080886f7cSSrinath Mannam
121af174c49SFlorian Fainelli AEQRX_REG_BANK_0 = 0xd0,
122af174c49SFlorian Fainelli AEQ_CONTROL1 = 0x81,
123af174c49SFlorian Fainelli AEQ_CONTROL1_ENABLE = BIT(2),
124af174c49SFlorian Fainelli AEQ_CONTROL1_FREEZE = BIT(3),
125af174c49SFlorian Fainelli AEQ_FRC_EQ = 0x83,
126af174c49SFlorian Fainelli AEQ_FRC_EQ_FORCE = BIT(0),
127af174c49SFlorian Fainelli AEQ_FRC_EQ_FORCE_VAL = BIT(1),
12897844253SFlorian Fainelli AEQ_RFZ_FRC_VAL = BIT(8),
129af174c49SFlorian Fainelli AEQRX_REG_BANK_1 = 0xe0,
1307b69fa1cSFlorian Fainelli AEQRX_SLCAL0_CTRL0 = 0x82,
1317b69fa1cSFlorian Fainelli AEQRX_SLCAL1_CTRL0 = 0x86,
132af174c49SFlorian Fainelli
1330b56e9a7SVivek Gautam OOB_REG_BANK = 0x150,
1340b56e9a7SVivek Gautam OOB1_REG_BANK = 0x160,
1350b56e9a7SVivek Gautam OOB_CTRL1 = 0x80,
1360b56e9a7SVivek Gautam OOB_CTRL1_BURST_MAX_MASK = 0xf,
1370b56e9a7SVivek Gautam OOB_CTRL1_BURST_MAX_SHIFT = 12,
1380b56e9a7SVivek Gautam OOB_CTRL1_BURST_MIN_MASK = 0xf,
1390b56e9a7SVivek Gautam OOB_CTRL1_BURST_MIN_SHIFT = 8,
1400b56e9a7SVivek Gautam OOB_CTRL1_WAKE_IDLE_MAX_MASK = 0xf,
1410b56e9a7SVivek Gautam OOB_CTRL1_WAKE_IDLE_MAX_SHIFT = 4,
1420b56e9a7SVivek Gautam OOB_CTRL1_WAKE_IDLE_MIN_MASK = 0xf,
1430b56e9a7SVivek Gautam OOB_CTRL1_WAKE_IDLE_MIN_SHIFT = 0,
1440b56e9a7SVivek Gautam OOB_CTRL2 = 0x81,
1450b56e9a7SVivek Gautam OOB_CTRL2_SEL_ENA_SHIFT = 15,
1460b56e9a7SVivek Gautam OOB_CTRL2_SEL_ENA_RC_SHIFT = 14,
1470b56e9a7SVivek Gautam OOB_CTRL2_RESET_IDLE_MAX_MASK = 0x3f,
1480b56e9a7SVivek Gautam OOB_CTRL2_RESET_IDLE_MAX_SHIFT = 8,
1490b56e9a7SVivek Gautam OOB_CTRL2_BURST_CNT_MASK = 0x3,
1500b56e9a7SVivek Gautam OOB_CTRL2_BURST_CNT_SHIFT = 6,
1510b56e9a7SVivek Gautam OOB_CTRL2_RESET_IDLE_MIN_MASK = 0x3f,
1520b56e9a7SVivek Gautam OOB_CTRL2_RESET_IDLE_MIN_SHIFT = 0,
1530b56e9a7SVivek Gautam
1540b56e9a7SVivek Gautam TXPMD_REG_BANK = 0x1a0,
1550b56e9a7SVivek Gautam TXPMD_CONTROL1 = 0x81,
1560b56e9a7SVivek Gautam TXPMD_CONTROL1_TX_SSC_EN_FRC = BIT(0),
1570b56e9a7SVivek Gautam TXPMD_CONTROL1_TX_SSC_EN_FRC_VAL = BIT(1),
1580b56e9a7SVivek Gautam TXPMD_TX_FREQ_CTRL_CONTROL1 = 0x82,
1590b56e9a7SVivek Gautam TXPMD_TX_FREQ_CTRL_CONTROL2 = 0x83,
1600b56e9a7SVivek Gautam TXPMD_TX_FREQ_CTRL_CONTROL2_FMIN_MASK = 0x3ff,
1610b56e9a7SVivek Gautam TXPMD_TX_FREQ_CTRL_CONTROL3 = 0x84,
1620b56e9a7SVivek Gautam TXPMD_TX_FREQ_CTRL_CONTROL3_FMAX_MASK = 0x3ff,
1633e507769SFlorian Fainelli
1643e507769SFlorian Fainelli RXPMD_REG_BANK = 0x1c0,
16597844253SFlorian Fainelli RXPMD_RX_CDR_CONTROL1 = 0x81,
16697844253SFlorian Fainelli RXPMD_RX_PPM_VAL_MASK = 0x1ff,
16797844253SFlorian Fainelli RXPMD_RXPMD_EN_FRC = BIT(12),
16897844253SFlorian Fainelli RXPMD_RXPMD_EN_FRC_VAL = BIT(13),
16997844253SFlorian Fainelli RXPMD_RX_CDR_CDR_PROP_BW = 0x82,
17097844253SFlorian Fainelli RXPMD_G_CDR_PROP_BW_MASK = 0x7,
17197844253SFlorian Fainelli RXPMD_G1_CDR_PROP_BW_SHIFT = 0,
17297844253SFlorian Fainelli RXPMD_G2_CDR_PROP_BW_SHIFT = 3,
17397844253SFlorian Fainelli RXPMD_G3_CDR_PROB_BW_SHIFT = 6,
17497844253SFlorian Fainelli RXPMD_RX_CDR_CDR_ACQ_INTEG_BW = 0x83,
17597844253SFlorian Fainelli RXPMD_G_CDR_ACQ_INT_BW_MASK = 0x7,
17697844253SFlorian Fainelli RXPMD_G1_CDR_ACQ_INT_BW_SHIFT = 0,
17797844253SFlorian Fainelli RXPMD_G2_CDR_ACQ_INT_BW_SHIFT = 3,
17897844253SFlorian Fainelli RXPMD_G3_CDR_ACQ_INT_BW_SHIFT = 6,
17997844253SFlorian Fainelli RXPMD_RX_CDR_CDR_LOCK_INTEG_BW = 0x84,
18097844253SFlorian Fainelli RXPMD_G_CDR_LOCK_INT_BW_MASK = 0x7,
18197844253SFlorian Fainelli RXPMD_G1_CDR_LOCK_INT_BW_SHIFT = 0,
18297844253SFlorian Fainelli RXPMD_G2_CDR_LOCK_INT_BW_SHIFT = 3,
18397844253SFlorian Fainelli RXPMD_G3_CDR_LOCK_INT_BW_SHIFT = 6,
1843e507769SFlorian Fainelli RXPMD_RX_FREQ_MON_CONTROL1 = 0x87,
18597844253SFlorian Fainelli RXPMD_MON_CORRECT_EN = BIT(8),
18697844253SFlorian Fainelli RXPMD_MON_MARGIN_VAL_MASK = 0xff,
1870b56e9a7SVivek Gautam };
1880b56e9a7SVivek Gautam
1890b56e9a7SVivek Gautam enum sata_phy_ctrl_regs {
1900b56e9a7SVivek Gautam PHY_CTRL_1 = 0x0,
1910b56e9a7SVivek Gautam PHY_CTRL_1_RESET = BIT(0),
1920b56e9a7SVivek Gautam };
1930b56e9a7SVivek Gautam
brcm_sata_ctrl_base(struct brcm_sata_port * port)1940b56e9a7SVivek Gautam static inline void __iomem *brcm_sata_ctrl_base(struct brcm_sata_port *port)
1950b56e9a7SVivek Gautam {
1960b56e9a7SVivek Gautam struct brcm_sata_phy *priv = port->phy_priv;
1970b56e9a7SVivek Gautam u32 size = 0;
1980b56e9a7SVivek Gautam
1990b56e9a7SVivek Gautam switch (priv->version) {
2000b56e9a7SVivek Gautam case BRCM_SATA_PHY_IPROC_NS2:
2010b56e9a7SVivek Gautam size = SATA_PHY_CTRL_REG_28NM_SPACE_SIZE;
2020b56e9a7SVivek Gautam break;
2030b56e9a7SVivek Gautam default:
2040b56e9a7SVivek Gautam dev_err(priv->dev, "invalid phy version\n");
2050b56e9a7SVivek Gautam break;
2060b56e9a7SVivek Gautam }
2070b56e9a7SVivek Gautam
2080b56e9a7SVivek Gautam return priv->ctrl_base + (port->portnum * size);
2090b56e9a7SVivek Gautam }
2100b56e9a7SVivek Gautam
brcm_sata_phy_wr(struct brcm_sata_port * port,u32 bank,u32 ofs,u32 msk,u32 value)2110ed41b33SFlorian Fainelli static void brcm_sata_phy_wr(struct brcm_sata_port *port, u32 bank,
2120b56e9a7SVivek Gautam u32 ofs, u32 msk, u32 value)
2130b56e9a7SVivek Gautam {
2140ed41b33SFlorian Fainelli struct brcm_sata_phy *priv = port->phy_priv;
2150ed41b33SFlorian Fainelli void __iomem *pcb_base = priv->phy_base;
2160b56e9a7SVivek Gautam u32 tmp;
2170b56e9a7SVivek Gautam
2180ed41b33SFlorian Fainelli if (priv->version == BRCM_SATA_PHY_STB_40NM)
2190ed41b33SFlorian Fainelli bank += (port->portnum * SATA_PCB_REG_40NM_SPACE_SIZE);
2200ed41b33SFlorian Fainelli else
2210ed41b33SFlorian Fainelli pcb_base += (port->portnum * SATA_PCB_REG_28NM_SPACE_SIZE);
2220ed41b33SFlorian Fainelli
2230b56e9a7SVivek Gautam writel(bank, pcb_base + SATA_PCB_BANK_OFFSET);
2240b56e9a7SVivek Gautam tmp = readl(pcb_base + SATA_PCB_REG_OFFSET(ofs));
2250b56e9a7SVivek Gautam tmp = (tmp & msk) | value;
2260b56e9a7SVivek Gautam writel(tmp, pcb_base + SATA_PCB_REG_OFFSET(ofs));
2270b56e9a7SVivek Gautam }
2280b56e9a7SVivek Gautam
brcm_sata_phy_rd(struct brcm_sata_port * port,u32 bank,u32 ofs)2290ed41b33SFlorian Fainelli static u32 brcm_sata_phy_rd(struct brcm_sata_port *port, u32 bank, u32 ofs)
2300b56e9a7SVivek Gautam {
2310ed41b33SFlorian Fainelli struct brcm_sata_phy *priv = port->phy_priv;
2320ed41b33SFlorian Fainelli void __iomem *pcb_base = priv->phy_base;
2330ed41b33SFlorian Fainelli
2340ed41b33SFlorian Fainelli if (priv->version == BRCM_SATA_PHY_STB_40NM)
2350ed41b33SFlorian Fainelli bank += (port->portnum * SATA_PCB_REG_40NM_SPACE_SIZE);
2360ed41b33SFlorian Fainelli else
2370ed41b33SFlorian Fainelli pcb_base += (port->portnum * SATA_PCB_REG_28NM_SPACE_SIZE);
2380ed41b33SFlorian Fainelli
2390b56e9a7SVivek Gautam writel(bank, pcb_base + SATA_PCB_BANK_OFFSET);
2400b56e9a7SVivek Gautam return readl(pcb_base + SATA_PCB_REG_OFFSET(ofs));
2410b56e9a7SVivek Gautam }
2420b56e9a7SVivek Gautam
2430b56e9a7SVivek Gautam /* These defaults were characterized by H/W group */
2440b56e9a7SVivek Gautam #define STB_FMIN_VAL_DEFAULT 0x3df
2450b56e9a7SVivek Gautam #define STB_FMAX_VAL_DEFAULT 0x3df
2460b56e9a7SVivek Gautam #define STB_FMAX_VAL_SSC 0x83
2470b56e9a7SVivek Gautam
brcm_stb_sata_ssc_init(struct brcm_sata_port * port)2486ec248feSFlorian Fainelli static void brcm_stb_sata_ssc_init(struct brcm_sata_port *port)
2490b56e9a7SVivek Gautam {
2500b56e9a7SVivek Gautam struct brcm_sata_phy *priv = port->phy_priv;
2510b56e9a7SVivek Gautam u32 tmp;
2520b56e9a7SVivek Gautam
2530b56e9a7SVivek Gautam /* override the TX spread spectrum setting */
2540b56e9a7SVivek Gautam tmp = TXPMD_CONTROL1_TX_SSC_EN_FRC_VAL | TXPMD_CONTROL1_TX_SSC_EN_FRC;
2550ed41b33SFlorian Fainelli brcm_sata_phy_wr(port, TXPMD_REG_BANK, TXPMD_CONTROL1, ~tmp, tmp);
2560b56e9a7SVivek Gautam
2570b56e9a7SVivek Gautam /* set fixed min freq */
2580ed41b33SFlorian Fainelli brcm_sata_phy_wr(port, TXPMD_REG_BANK, TXPMD_TX_FREQ_CTRL_CONTROL2,
2590b56e9a7SVivek Gautam ~TXPMD_TX_FREQ_CTRL_CONTROL2_FMIN_MASK,
2600b56e9a7SVivek Gautam STB_FMIN_VAL_DEFAULT);
2610b56e9a7SVivek Gautam
2620b56e9a7SVivek Gautam /* set fixed max freq depending on SSC config */
2630b56e9a7SVivek Gautam if (port->ssc_en) {
2640b56e9a7SVivek Gautam dev_info(priv->dev, "enabling SSC on port%d\n", port->portnum);
2650b56e9a7SVivek Gautam tmp = STB_FMAX_VAL_SSC;
2660b56e9a7SVivek Gautam } else {
2670b56e9a7SVivek Gautam tmp = STB_FMAX_VAL_DEFAULT;
2680b56e9a7SVivek Gautam }
2690b56e9a7SVivek Gautam
2700ed41b33SFlorian Fainelli brcm_sata_phy_wr(port, TXPMD_REG_BANK, TXPMD_TX_FREQ_CTRL_CONTROL3,
2710b56e9a7SVivek Gautam ~TXPMD_TX_FREQ_CTRL_CONTROL3_FMAX_MASK, tmp);
2726ec248feSFlorian Fainelli }
2736ec248feSFlorian Fainelli
274af174c49SFlorian Fainelli #define AEQ_FRC_EQ_VAL_SHIFT 2
275af174c49SFlorian Fainelli #define AEQ_FRC_EQ_VAL_MASK 0x3f
276af174c49SFlorian Fainelli
brcm_stb_sata_rxaeq_init(struct brcm_sata_port * port)277af174c49SFlorian Fainelli static int brcm_stb_sata_rxaeq_init(struct brcm_sata_port *port)
278af174c49SFlorian Fainelli {
279af174c49SFlorian Fainelli u32 tmp = 0, reg = 0;
280af174c49SFlorian Fainelli
281af174c49SFlorian Fainelli switch (port->rxaeq_mode) {
282af174c49SFlorian Fainelli case RXAEQ_MODE_OFF:
283af174c49SFlorian Fainelli return 0;
284af174c49SFlorian Fainelli
285af174c49SFlorian Fainelli case RXAEQ_MODE_AUTO:
286af174c49SFlorian Fainelli reg = AEQ_CONTROL1;
287af174c49SFlorian Fainelli tmp = AEQ_CONTROL1_ENABLE | AEQ_CONTROL1_FREEZE;
288af174c49SFlorian Fainelli break;
289af174c49SFlorian Fainelli
290af174c49SFlorian Fainelli case RXAEQ_MODE_MANUAL:
291af174c49SFlorian Fainelli reg = AEQ_FRC_EQ;
292af174c49SFlorian Fainelli tmp = AEQ_FRC_EQ_FORCE | AEQ_FRC_EQ_FORCE_VAL;
293af174c49SFlorian Fainelli if (port->rxaeq_val > AEQ_FRC_EQ_VAL_MASK)
294af174c49SFlorian Fainelli return -EINVAL;
295af174c49SFlorian Fainelli tmp |= port->rxaeq_val << AEQ_FRC_EQ_VAL_SHIFT;
296af174c49SFlorian Fainelli break;
297af174c49SFlorian Fainelli }
298af174c49SFlorian Fainelli
2990ed41b33SFlorian Fainelli brcm_sata_phy_wr(port, AEQRX_REG_BANK_0, reg, ~tmp, tmp);
3000ed41b33SFlorian Fainelli brcm_sata_phy_wr(port, AEQRX_REG_BANK_1, reg, ~tmp, tmp);
301af174c49SFlorian Fainelli
302af174c49SFlorian Fainelli return 0;
303af174c49SFlorian Fainelli }
304af174c49SFlorian Fainelli
brcm_stb_sata_init(struct brcm_sata_port * port)3056ec248feSFlorian Fainelli static int brcm_stb_sata_init(struct brcm_sata_port *port)
3066ec248feSFlorian Fainelli {
3076ec248feSFlorian Fainelli brcm_stb_sata_ssc_init(port);
3080b56e9a7SVivek Gautam
309af174c49SFlorian Fainelli return brcm_stb_sata_rxaeq_init(port);
3100b56e9a7SVivek Gautam }
3110b56e9a7SVivek Gautam
brcm_stb_sata_16nm_ssc_init(struct brcm_sata_port * port)31297844253SFlorian Fainelli static int brcm_stb_sata_16nm_ssc_init(struct brcm_sata_port *port)
31397844253SFlorian Fainelli {
31497844253SFlorian Fainelli u32 tmp, value;
31597844253SFlorian Fainelli
31697844253SFlorian Fainelli /* Reduce CP tail current to 1/16th of its default value */
3170ed41b33SFlorian Fainelli brcm_sata_phy_wr(port, PLL1_REG_BANK, PLL1_ACTRL6, 0, 0x141);
31897844253SFlorian Fainelli
31997844253SFlorian Fainelli /* Turn off CP tail current boost */
3200ed41b33SFlorian Fainelli brcm_sata_phy_wr(port, PLL1_REG_BANK, PLL1_ACTRL8, 0, 0xc006);
32197844253SFlorian Fainelli
32297844253SFlorian Fainelli /* Set a specific AEQ equalizer value */
32397844253SFlorian Fainelli tmp = AEQ_FRC_EQ_FORCE_VAL | AEQ_FRC_EQ_FORCE;
3240ed41b33SFlorian Fainelli brcm_sata_phy_wr(port, AEQRX_REG_BANK_0, AEQ_FRC_EQ,
32597844253SFlorian Fainelli ~(tmp | AEQ_RFZ_FRC_VAL |
32697844253SFlorian Fainelli AEQ_FRC_EQ_VAL_MASK << AEQ_FRC_EQ_VAL_SHIFT),
32797844253SFlorian Fainelli tmp | 32 << AEQ_FRC_EQ_VAL_SHIFT);
32897844253SFlorian Fainelli
32997844253SFlorian Fainelli /* Set RX PPM val center frequency */
33097844253SFlorian Fainelli if (port->ssc_en)
33197844253SFlorian Fainelli value = 0x52;
33297844253SFlorian Fainelli else
33397844253SFlorian Fainelli value = 0;
3340ed41b33SFlorian Fainelli brcm_sata_phy_wr(port, RXPMD_REG_BANK, RXPMD_RX_CDR_CONTROL1,
33597844253SFlorian Fainelli ~RXPMD_RX_PPM_VAL_MASK, value);
33697844253SFlorian Fainelli
33797844253SFlorian Fainelli /* Set proportional loop bandwith Gen1/2/3 */
33897844253SFlorian Fainelli tmp = RXPMD_G_CDR_PROP_BW_MASK << RXPMD_G1_CDR_PROP_BW_SHIFT |
33997844253SFlorian Fainelli RXPMD_G_CDR_PROP_BW_MASK << RXPMD_G2_CDR_PROP_BW_SHIFT |
34097844253SFlorian Fainelli RXPMD_G_CDR_PROP_BW_MASK << RXPMD_G3_CDR_PROB_BW_SHIFT;
34197844253SFlorian Fainelli if (port->ssc_en)
34297844253SFlorian Fainelli value = 2 << RXPMD_G1_CDR_PROP_BW_SHIFT |
34397844253SFlorian Fainelli 2 << RXPMD_G2_CDR_PROP_BW_SHIFT |
34497844253SFlorian Fainelli 2 << RXPMD_G3_CDR_PROB_BW_SHIFT;
34597844253SFlorian Fainelli else
34697844253SFlorian Fainelli value = 1 << RXPMD_G1_CDR_PROP_BW_SHIFT |
34797844253SFlorian Fainelli 1 << RXPMD_G2_CDR_PROP_BW_SHIFT |
34897844253SFlorian Fainelli 1 << RXPMD_G3_CDR_PROB_BW_SHIFT;
3490ed41b33SFlorian Fainelli brcm_sata_phy_wr(port, RXPMD_REG_BANK, RXPMD_RX_CDR_CDR_PROP_BW, ~tmp,
35097844253SFlorian Fainelli value);
35197844253SFlorian Fainelli
35297844253SFlorian Fainelli /* Set CDR integral loop acquisition bandwidth for Gen1/2/3 */
35397844253SFlorian Fainelli tmp = RXPMD_G_CDR_ACQ_INT_BW_MASK << RXPMD_G1_CDR_ACQ_INT_BW_SHIFT |
35497844253SFlorian Fainelli RXPMD_G_CDR_ACQ_INT_BW_MASK << RXPMD_G2_CDR_ACQ_INT_BW_SHIFT |
35597844253SFlorian Fainelli RXPMD_G_CDR_ACQ_INT_BW_MASK << RXPMD_G3_CDR_ACQ_INT_BW_SHIFT;
35697844253SFlorian Fainelli if (port->ssc_en)
35797844253SFlorian Fainelli value = 1 << RXPMD_G1_CDR_ACQ_INT_BW_SHIFT |
35897844253SFlorian Fainelli 1 << RXPMD_G2_CDR_ACQ_INT_BW_SHIFT |
35997844253SFlorian Fainelli 1 << RXPMD_G3_CDR_ACQ_INT_BW_SHIFT;
36097844253SFlorian Fainelli else
36197844253SFlorian Fainelli value = 0;
3620ed41b33SFlorian Fainelli brcm_sata_phy_wr(port, RXPMD_REG_BANK, RXPMD_RX_CDR_CDR_ACQ_INTEG_BW,
36397844253SFlorian Fainelli ~tmp, value);
36497844253SFlorian Fainelli
36597844253SFlorian Fainelli /* Set CDR integral loop locking bandwidth to 1 for Gen 1/2/3 */
36697844253SFlorian Fainelli tmp = RXPMD_G_CDR_LOCK_INT_BW_MASK << RXPMD_G1_CDR_LOCK_INT_BW_SHIFT |
36797844253SFlorian Fainelli RXPMD_G_CDR_LOCK_INT_BW_MASK << RXPMD_G2_CDR_LOCK_INT_BW_SHIFT |
36897844253SFlorian Fainelli RXPMD_G_CDR_LOCK_INT_BW_MASK << RXPMD_G3_CDR_LOCK_INT_BW_SHIFT;
36997844253SFlorian Fainelli if (port->ssc_en)
37097844253SFlorian Fainelli value = 1 << RXPMD_G1_CDR_LOCK_INT_BW_SHIFT |
37197844253SFlorian Fainelli 1 << RXPMD_G2_CDR_LOCK_INT_BW_SHIFT |
37297844253SFlorian Fainelli 1 << RXPMD_G3_CDR_LOCK_INT_BW_SHIFT;
37397844253SFlorian Fainelli else
37497844253SFlorian Fainelli value = 0;
3750ed41b33SFlorian Fainelli brcm_sata_phy_wr(port, RXPMD_REG_BANK, RXPMD_RX_CDR_CDR_LOCK_INTEG_BW,
37697844253SFlorian Fainelli ~tmp, value);
37797844253SFlorian Fainelli
37897844253SFlorian Fainelli /* Set no guard band and clamp CDR */
37997844253SFlorian Fainelli tmp = RXPMD_MON_CORRECT_EN | RXPMD_MON_MARGIN_VAL_MASK;
38097844253SFlorian Fainelli if (port->ssc_en)
38197844253SFlorian Fainelli value = 0x51;
38297844253SFlorian Fainelli else
38397844253SFlorian Fainelli value = 0;
3840ed41b33SFlorian Fainelli brcm_sata_phy_wr(port, RXPMD_REG_BANK, RXPMD_RX_FREQ_MON_CONTROL1,
38597844253SFlorian Fainelli ~tmp, RXPMD_MON_CORRECT_EN | value);
38697844253SFlorian Fainelli
387839034d8SFlorian Fainelli tmp = GENMASK(15, 12);
388839034d8SFlorian Fainelli switch (port->tx_amplitude_val) {
389839034d8SFlorian Fainelli case 400:
390839034d8SFlorian Fainelli value = BIT(12) | BIT(13);
391839034d8SFlorian Fainelli break;
392839034d8SFlorian Fainelli case 500:
393839034d8SFlorian Fainelli value = BIT(13);
394839034d8SFlorian Fainelli break;
395839034d8SFlorian Fainelli case 600:
396839034d8SFlorian Fainelli value = BIT(12);
397839034d8SFlorian Fainelli break;
398839034d8SFlorian Fainelli case 800:
399839034d8SFlorian Fainelli value = 0;
400839034d8SFlorian Fainelli break;
401839034d8SFlorian Fainelli default:
402839034d8SFlorian Fainelli value = tmp;
403839034d8SFlorian Fainelli break;
404839034d8SFlorian Fainelli }
405839034d8SFlorian Fainelli
406839034d8SFlorian Fainelli if (value != tmp)
407839034d8SFlorian Fainelli brcm_sata_phy_wr(port, BLOCK1_REG_BANK, BLOCK1_TEST_TX, ~tmp,
408839034d8SFlorian Fainelli value);
409839034d8SFlorian Fainelli
41097844253SFlorian Fainelli /* Turn on/off SSC */
4110ed41b33SFlorian Fainelli brcm_sata_phy_wr(port, TX_REG_BANK, TX_ACTRL5, ~TX_ACTRL5_SSC_EN,
41297844253SFlorian Fainelli port->ssc_en ? TX_ACTRL5_SSC_EN : 0);
41397844253SFlorian Fainelli
41497844253SFlorian Fainelli return 0;
41597844253SFlorian Fainelli }
41697844253SFlorian Fainelli
brcm_stb_sata_16nm_init(struct brcm_sata_port * port)41797844253SFlorian Fainelli static int brcm_stb_sata_16nm_init(struct brcm_sata_port *port)
41897844253SFlorian Fainelli {
41997844253SFlorian Fainelli return brcm_stb_sata_16nm_ssc_init(port);
42097844253SFlorian Fainelli }
42197844253SFlorian Fainelli
4220b56e9a7SVivek Gautam /* NS2 SATA PLL1 defaults were characterized by H/W group */
4230b56e9a7SVivek Gautam #define NS2_PLL1_ACTRL2_MAGIC 0x1df8
4240b56e9a7SVivek Gautam #define NS2_PLL1_ACTRL3_MAGIC 0x2b00
4250b56e9a7SVivek Gautam #define NS2_PLL1_ACTRL4_MAGIC 0x8824
4260b56e9a7SVivek Gautam
brcm_ns2_sata_init(struct brcm_sata_port * port)4270b56e9a7SVivek Gautam static int brcm_ns2_sata_init(struct brcm_sata_port *port)
4280b56e9a7SVivek Gautam {
4290b56e9a7SVivek Gautam int try;
4300b56e9a7SVivek Gautam unsigned int val;
4310b56e9a7SVivek Gautam void __iomem *ctrl_base = brcm_sata_ctrl_base(port);
4320b56e9a7SVivek Gautam struct device *dev = port->phy_priv->dev;
4330b56e9a7SVivek Gautam
4340b56e9a7SVivek Gautam /* Configure OOB control */
4350b56e9a7SVivek Gautam val = 0x0;
4360b56e9a7SVivek Gautam val |= (0xc << OOB_CTRL1_BURST_MAX_SHIFT);
4370b56e9a7SVivek Gautam val |= (0x4 << OOB_CTRL1_BURST_MIN_SHIFT);
4380b56e9a7SVivek Gautam val |= (0x9 << OOB_CTRL1_WAKE_IDLE_MAX_SHIFT);
4390b56e9a7SVivek Gautam val |= (0x3 << OOB_CTRL1_WAKE_IDLE_MIN_SHIFT);
4400ed41b33SFlorian Fainelli brcm_sata_phy_wr(port, OOB_REG_BANK, OOB_CTRL1, 0x0, val);
4410b56e9a7SVivek Gautam val = 0x0;
4420b56e9a7SVivek Gautam val |= (0x1b << OOB_CTRL2_RESET_IDLE_MAX_SHIFT);
4430b56e9a7SVivek Gautam val |= (0x2 << OOB_CTRL2_BURST_CNT_SHIFT);
4440b56e9a7SVivek Gautam val |= (0x9 << OOB_CTRL2_RESET_IDLE_MIN_SHIFT);
4450ed41b33SFlorian Fainelli brcm_sata_phy_wr(port, OOB_REG_BANK, OOB_CTRL2, 0x0, val);
4460b56e9a7SVivek Gautam
4470b56e9a7SVivek Gautam /* Configure PHY PLL register bank 1 */
4480b56e9a7SVivek Gautam val = NS2_PLL1_ACTRL2_MAGIC;
4490ed41b33SFlorian Fainelli brcm_sata_phy_wr(port, PLL1_REG_BANK, PLL1_ACTRL2, 0x0, val);
4500b56e9a7SVivek Gautam val = NS2_PLL1_ACTRL3_MAGIC;
4510ed41b33SFlorian Fainelli brcm_sata_phy_wr(port, PLL1_REG_BANK, PLL1_ACTRL3, 0x0, val);
4520b56e9a7SVivek Gautam val = NS2_PLL1_ACTRL4_MAGIC;
4530ed41b33SFlorian Fainelli brcm_sata_phy_wr(port, PLL1_REG_BANK, PLL1_ACTRL4, 0x0, val);
4540b56e9a7SVivek Gautam
4550b56e9a7SVivek Gautam /* Configure PHY BLOCK0 register bank */
4560b56e9a7SVivek Gautam /* Set oob_clk_sel to refclk/2 */
4570ed41b33SFlorian Fainelli brcm_sata_phy_wr(port, BLOCK0_REG_BANK, BLOCK0_SPARE,
4580b56e9a7SVivek Gautam ~BLOCK0_SPARE_OOB_CLK_SEL_MASK,
4590b56e9a7SVivek Gautam BLOCK0_SPARE_OOB_CLK_SEL_REFBY2);
4600b56e9a7SVivek Gautam
4610b56e9a7SVivek Gautam /* Strobe PHY reset using PHY control register */
4620b56e9a7SVivek Gautam writel(PHY_CTRL_1_RESET, ctrl_base + PHY_CTRL_1);
4630b56e9a7SVivek Gautam mdelay(1);
4640b56e9a7SVivek Gautam writel(0x0, ctrl_base + PHY_CTRL_1);
4650b56e9a7SVivek Gautam mdelay(1);
4660b56e9a7SVivek Gautam
4670b56e9a7SVivek Gautam /* Wait for PHY PLL lock by polling pll_lock bit */
4680b56e9a7SVivek Gautam try = 50;
4690b56e9a7SVivek Gautam while (try) {
4700ed41b33SFlorian Fainelli val = brcm_sata_phy_rd(port, BLOCK0_REG_BANK,
4710b56e9a7SVivek Gautam BLOCK0_XGXSSTATUS);
4720b56e9a7SVivek Gautam if (val & BLOCK0_XGXSSTATUS_PLL_LOCK)
4730b56e9a7SVivek Gautam break;
4740b56e9a7SVivek Gautam msleep(20);
4750b56e9a7SVivek Gautam try--;
4760b56e9a7SVivek Gautam }
4770b56e9a7SVivek Gautam if (!try) {
4780b56e9a7SVivek Gautam /* PLL did not lock; give up */
4790b56e9a7SVivek Gautam dev_err(dev, "port%d PLL did not lock\n", port->portnum);
4800b56e9a7SVivek Gautam return -ETIMEDOUT;
4810b56e9a7SVivek Gautam }
4820b56e9a7SVivek Gautam
4830b56e9a7SVivek Gautam dev_dbg(dev, "port%d initialized\n", port->portnum);
4840b56e9a7SVivek Gautam
4850b56e9a7SVivek Gautam return 0;
4860b56e9a7SVivek Gautam }
4870b56e9a7SVivek Gautam
brcm_nsp_sata_init(struct brcm_sata_port * port)4880b56e9a7SVivek Gautam static int brcm_nsp_sata_init(struct brcm_sata_port *port)
4890b56e9a7SVivek Gautam {
4900b56e9a7SVivek Gautam struct device *dev = port->phy_priv->dev;
4910b56e9a7SVivek Gautam unsigned int oob_bank;
4920b56e9a7SVivek Gautam unsigned int val, try;
4930b56e9a7SVivek Gautam
4940b56e9a7SVivek Gautam /* Configure OOB control */
4950b56e9a7SVivek Gautam if (port->portnum == 0)
4960b56e9a7SVivek Gautam oob_bank = OOB_REG_BANK;
4970b56e9a7SVivek Gautam else if (port->portnum == 1)
4980b56e9a7SVivek Gautam oob_bank = OOB1_REG_BANK;
4990b56e9a7SVivek Gautam else
5000b56e9a7SVivek Gautam return -EINVAL;
5010b56e9a7SVivek Gautam
5020b56e9a7SVivek Gautam val = 0x0;
5030b56e9a7SVivek Gautam val |= (0x0f << OOB_CTRL1_BURST_MAX_SHIFT);
5040b56e9a7SVivek Gautam val |= (0x06 << OOB_CTRL1_BURST_MIN_SHIFT);
5050b56e9a7SVivek Gautam val |= (0x0f << OOB_CTRL1_WAKE_IDLE_MAX_SHIFT);
5060b56e9a7SVivek Gautam val |= (0x06 << OOB_CTRL1_WAKE_IDLE_MIN_SHIFT);
5070ed41b33SFlorian Fainelli brcm_sata_phy_wr(port, oob_bank, OOB_CTRL1, 0x0, val);
5080b56e9a7SVivek Gautam
5090b56e9a7SVivek Gautam val = 0x0;
5100b56e9a7SVivek Gautam val |= (0x2e << OOB_CTRL2_RESET_IDLE_MAX_SHIFT);
5110b56e9a7SVivek Gautam val |= (0x02 << OOB_CTRL2_BURST_CNT_SHIFT);
5120b56e9a7SVivek Gautam val |= (0x16 << OOB_CTRL2_RESET_IDLE_MIN_SHIFT);
5130ed41b33SFlorian Fainelli brcm_sata_phy_wr(port, oob_bank, OOB_CTRL2, 0x0, val);
5140b56e9a7SVivek Gautam
5150b56e9a7SVivek Gautam
5160ed41b33SFlorian Fainelli brcm_sata_phy_wr(port, PLL_REG_BANK_0, PLL_ACTRL2,
5170b56e9a7SVivek Gautam ~(PLL_ACTRL2_SELDIV_MASK << PLL_ACTRL2_SELDIV_SHIFT),
5180b56e9a7SVivek Gautam 0x0c << PLL_ACTRL2_SELDIV_SHIFT);
5190b56e9a7SVivek Gautam
5200ed41b33SFlorian Fainelli brcm_sata_phy_wr(port, PLL_REG_BANK_0, PLL_CAP_CONTROL,
5210b56e9a7SVivek Gautam 0xff0, 0x4f0);
5220b56e9a7SVivek Gautam
5230b56e9a7SVivek Gautam val = PLLCONTROL_0_FREQ_DET_RESTART | PLLCONTROL_0_FREQ_MONITOR;
5240ed41b33SFlorian Fainelli brcm_sata_phy_wr(port, PLL_REG_BANK_0, PLL_REG_BANK_0_PLLCONTROL_0,
5250b56e9a7SVivek Gautam ~val, val);
5260b56e9a7SVivek Gautam val = PLLCONTROL_0_SEQ_START;
5270ed41b33SFlorian Fainelli brcm_sata_phy_wr(port, PLL_REG_BANK_0, PLL_REG_BANK_0_PLLCONTROL_0,
5280b56e9a7SVivek Gautam ~val, 0);
5290b56e9a7SVivek Gautam mdelay(10);
5300ed41b33SFlorian Fainelli brcm_sata_phy_wr(port, PLL_REG_BANK_0, PLL_REG_BANK_0_PLLCONTROL_0,
5310b56e9a7SVivek Gautam ~val, val);
5320b56e9a7SVivek Gautam
5330b56e9a7SVivek Gautam /* Wait for pll_seq_done bit */
5340b56e9a7SVivek Gautam try = 50;
535d9c51f4cSDan Carpenter while (--try) {
5360ed41b33SFlorian Fainelli val = brcm_sata_phy_rd(port, BLOCK0_REG_BANK,
5370b56e9a7SVivek Gautam BLOCK0_XGXSSTATUS);
5380b56e9a7SVivek Gautam if (val & BLOCK0_XGXSSTATUS_PLL_LOCK)
5390b56e9a7SVivek Gautam break;
5400b56e9a7SVivek Gautam msleep(20);
5410b56e9a7SVivek Gautam }
5420b56e9a7SVivek Gautam if (!try) {
5430b56e9a7SVivek Gautam /* PLL did not lock; give up */
5440b56e9a7SVivek Gautam dev_err(dev, "port%d PLL did not lock\n", port->portnum);
5450b56e9a7SVivek Gautam return -ETIMEDOUT;
5460b56e9a7SVivek Gautam }
5470b56e9a7SVivek Gautam
5480b56e9a7SVivek Gautam dev_dbg(dev, "port%d initialized\n", port->portnum);
5490b56e9a7SVivek Gautam
5500b56e9a7SVivek Gautam return 0;
5510b56e9a7SVivek Gautam }
5520b56e9a7SVivek Gautam
55380886f7cSSrinath Mannam /* SR PHY PLL0 registers */
55480886f7cSSrinath Mannam #define SR_PLL0_ACTRL6_MAGIC 0xa
55580886f7cSSrinath Mannam
55680886f7cSSrinath Mannam /* SR PHY PLL1 registers */
55780886f7cSSrinath Mannam #define SR_PLL1_ACTRL2_MAGIC 0x32
55880886f7cSSrinath Mannam #define SR_PLL1_ACTRL3_MAGIC 0x2
55980886f7cSSrinath Mannam #define SR_PLL1_ACTRL4_MAGIC 0x3e8
56080886f7cSSrinath Mannam
brcm_sr_sata_init(struct brcm_sata_port * port)56180886f7cSSrinath Mannam static int brcm_sr_sata_init(struct brcm_sata_port *port)
56280886f7cSSrinath Mannam {
56380886f7cSSrinath Mannam struct device *dev = port->phy_priv->dev;
56480886f7cSSrinath Mannam unsigned int val, try;
56580886f7cSSrinath Mannam
56680886f7cSSrinath Mannam /* Configure PHY PLL register bank 1 */
56780886f7cSSrinath Mannam val = SR_PLL1_ACTRL2_MAGIC;
5680ed41b33SFlorian Fainelli brcm_sata_phy_wr(port, PLL1_REG_BANK, PLL1_ACTRL2, 0x0, val);
56980886f7cSSrinath Mannam val = SR_PLL1_ACTRL3_MAGIC;
5700ed41b33SFlorian Fainelli brcm_sata_phy_wr(port, PLL1_REG_BANK, PLL1_ACTRL3, 0x0, val);
57180886f7cSSrinath Mannam val = SR_PLL1_ACTRL4_MAGIC;
5720ed41b33SFlorian Fainelli brcm_sata_phy_wr(port, PLL1_REG_BANK, PLL1_ACTRL4, 0x0, val);
57380886f7cSSrinath Mannam
57480886f7cSSrinath Mannam /* Configure PHY PLL register bank 0 */
57580886f7cSSrinath Mannam val = SR_PLL0_ACTRL6_MAGIC;
5760ed41b33SFlorian Fainelli brcm_sata_phy_wr(port, PLL_REG_BANK_0, PLL_ACTRL6, 0x0, val);
57780886f7cSSrinath Mannam
57880886f7cSSrinath Mannam /* Wait for PHY PLL lock by polling pll_lock bit */
57980886f7cSSrinath Mannam try = 50;
58080886f7cSSrinath Mannam do {
5810ed41b33SFlorian Fainelli val = brcm_sata_phy_rd(port, BLOCK0_REG_BANK,
58280886f7cSSrinath Mannam BLOCK0_XGXSSTATUS);
58380886f7cSSrinath Mannam if (val & BLOCK0_XGXSSTATUS_PLL_LOCK)
58480886f7cSSrinath Mannam break;
58580886f7cSSrinath Mannam msleep(20);
58680886f7cSSrinath Mannam try--;
58780886f7cSSrinath Mannam } while (try);
58880886f7cSSrinath Mannam
58980886f7cSSrinath Mannam if ((val & BLOCK0_XGXSSTATUS_PLL_LOCK) == 0) {
59080886f7cSSrinath Mannam /* PLL did not lock; give up */
59180886f7cSSrinath Mannam dev_err(dev, "port%d PLL did not lock\n", port->portnum);
59280886f7cSSrinath Mannam return -ETIMEDOUT;
59380886f7cSSrinath Mannam }
59480886f7cSSrinath Mannam
59580886f7cSSrinath Mannam /* Invert Tx polarity */
5960ed41b33SFlorian Fainelli brcm_sata_phy_wr(port, TX_REG_BANK, TX_ACTRL0,
59780886f7cSSrinath Mannam ~TX_ACTRL0_TXPOL_FLIP, TX_ACTRL0_TXPOL_FLIP);
59880886f7cSSrinath Mannam
59980886f7cSSrinath Mannam /* Configure OOB control to handle 100MHz reference clock */
60080886f7cSSrinath Mannam val = ((0xc << OOB_CTRL1_BURST_MAX_SHIFT) |
60180886f7cSSrinath Mannam (0x4 << OOB_CTRL1_BURST_MIN_SHIFT) |
60280886f7cSSrinath Mannam (0x8 << OOB_CTRL1_WAKE_IDLE_MAX_SHIFT) |
60380886f7cSSrinath Mannam (0x3 << OOB_CTRL1_WAKE_IDLE_MIN_SHIFT));
6040ed41b33SFlorian Fainelli brcm_sata_phy_wr(port, OOB_REG_BANK, OOB_CTRL1, 0x0, val);
60580886f7cSSrinath Mannam val = ((0x1b << OOB_CTRL2_RESET_IDLE_MAX_SHIFT) |
60680886f7cSSrinath Mannam (0x2 << OOB_CTRL2_BURST_CNT_SHIFT) |
60780886f7cSSrinath Mannam (0x9 << OOB_CTRL2_RESET_IDLE_MIN_SHIFT));
6080ed41b33SFlorian Fainelli brcm_sata_phy_wr(port, OOB_REG_BANK, OOB_CTRL2, 0x0, val);
60980886f7cSSrinath Mannam
61080886f7cSSrinath Mannam return 0;
61180886f7cSSrinath Mannam }
61280886f7cSSrinath Mannam
brcm_dsl_sata_init(struct brcm_sata_port * port)6137b69fa1cSFlorian Fainelli static int brcm_dsl_sata_init(struct brcm_sata_port *port)
6147b69fa1cSFlorian Fainelli {
6157b69fa1cSFlorian Fainelli struct device *dev = port->phy_priv->dev;
6167b69fa1cSFlorian Fainelli unsigned int try;
6177b69fa1cSFlorian Fainelli u32 tmp;
6187b69fa1cSFlorian Fainelli
6190ed41b33SFlorian Fainelli brcm_sata_phy_wr(port, PLL1_REG_BANK, PLL1_ACTRL7, 0, 0x873);
6207b69fa1cSFlorian Fainelli
6210ed41b33SFlorian Fainelli brcm_sata_phy_wr(port, PLL1_REG_BANK, PLL1_ACTRL6, 0, 0xc000);
6227b69fa1cSFlorian Fainelli
6230ed41b33SFlorian Fainelli brcm_sata_phy_wr(port, PLL_REG_BANK_0, PLL_REG_BANK_0_PLLCONTROL_0,
6247b69fa1cSFlorian Fainelli 0, 0x3089);
6257b69fa1cSFlorian Fainelli usleep_range(1000, 2000);
6267b69fa1cSFlorian Fainelli
6270ed41b33SFlorian Fainelli brcm_sata_phy_wr(port, PLL_REG_BANK_0, PLL_REG_BANK_0_PLLCONTROL_0,
6287b69fa1cSFlorian Fainelli 0, 0x3088);
6297b69fa1cSFlorian Fainelli usleep_range(1000, 2000);
6307b69fa1cSFlorian Fainelli
6310ed41b33SFlorian Fainelli brcm_sata_phy_wr(port, AEQRX_REG_BANK_1, AEQRX_SLCAL0_CTRL0,
6327b69fa1cSFlorian Fainelli 0, 0x3000);
6337b69fa1cSFlorian Fainelli
6340ed41b33SFlorian Fainelli brcm_sata_phy_wr(port, AEQRX_REG_BANK_1, AEQRX_SLCAL1_CTRL0,
6357b69fa1cSFlorian Fainelli 0, 0x3000);
6367b69fa1cSFlorian Fainelli usleep_range(1000, 2000);
6377b69fa1cSFlorian Fainelli
6380ed41b33SFlorian Fainelli brcm_sata_phy_wr(port, PLL_REG_BANK_0, PLL_CAP_CHARGE_TIME, 0, 0x32);
6397b69fa1cSFlorian Fainelli
6400ed41b33SFlorian Fainelli brcm_sata_phy_wr(port, PLL_REG_BANK_0, PLL_VCO_CAL_THRESH, 0, 0xa);
6417b69fa1cSFlorian Fainelli
6420ed41b33SFlorian Fainelli brcm_sata_phy_wr(port, PLL_REG_BANK_0, PLL_FREQ_DET_TIME, 0, 0x64);
6437b69fa1cSFlorian Fainelli usleep_range(1000, 2000);
6447b69fa1cSFlorian Fainelli
6457b69fa1cSFlorian Fainelli /* Acquire PLL lock */
6467b69fa1cSFlorian Fainelli try = 50;
6477b69fa1cSFlorian Fainelli while (try) {
6480ed41b33SFlorian Fainelli tmp = brcm_sata_phy_rd(port, BLOCK0_REG_BANK,
6497b69fa1cSFlorian Fainelli BLOCK0_XGXSSTATUS);
6507b69fa1cSFlorian Fainelli if (tmp & BLOCK0_XGXSSTATUS_PLL_LOCK)
6517b69fa1cSFlorian Fainelli break;
6527b69fa1cSFlorian Fainelli msleep(20);
6537b69fa1cSFlorian Fainelli try--;
65425e3ee59SYang Li }
6557b69fa1cSFlorian Fainelli
6567b69fa1cSFlorian Fainelli if (!try) {
6577b69fa1cSFlorian Fainelli /* PLL did not lock; give up */
6587b69fa1cSFlorian Fainelli dev_err(dev, "port%d PLL did not lock\n", port->portnum);
6597b69fa1cSFlorian Fainelli return -ETIMEDOUT;
6607b69fa1cSFlorian Fainelli }
6617b69fa1cSFlorian Fainelli
6627b69fa1cSFlorian Fainelli dev_dbg(dev, "port%d initialized\n", port->portnum);
6637b69fa1cSFlorian Fainelli
6647b69fa1cSFlorian Fainelli return 0;
6657b69fa1cSFlorian Fainelli }
6667b69fa1cSFlorian Fainelli
brcm_sata_phy_init(struct phy * phy)6670b56e9a7SVivek Gautam static int brcm_sata_phy_init(struct phy *phy)
6680b56e9a7SVivek Gautam {
6690b56e9a7SVivek Gautam int rc;
6700b56e9a7SVivek Gautam struct brcm_sata_port *port = phy_get_drvdata(phy);
6710b56e9a7SVivek Gautam
6720b56e9a7SVivek Gautam switch (port->phy_priv->version) {
67397844253SFlorian Fainelli case BRCM_SATA_PHY_STB_16NM:
67497844253SFlorian Fainelli rc = brcm_stb_sata_16nm_init(port);
67597844253SFlorian Fainelli break;
6760b56e9a7SVivek Gautam case BRCM_SATA_PHY_STB_28NM:
6770b56e9a7SVivek Gautam case BRCM_SATA_PHY_STB_40NM:
6780b56e9a7SVivek Gautam rc = brcm_stb_sata_init(port);
6790b56e9a7SVivek Gautam break;
6800b56e9a7SVivek Gautam case BRCM_SATA_PHY_IPROC_NS2:
6810b56e9a7SVivek Gautam rc = brcm_ns2_sata_init(port);
6820b56e9a7SVivek Gautam break;
6830b56e9a7SVivek Gautam case BRCM_SATA_PHY_IPROC_NSP:
6840b56e9a7SVivek Gautam rc = brcm_nsp_sata_init(port);
6850b56e9a7SVivek Gautam break;
68680886f7cSSrinath Mannam case BRCM_SATA_PHY_IPROC_SR:
68780886f7cSSrinath Mannam rc = brcm_sr_sata_init(port);
68880886f7cSSrinath Mannam break;
6897b69fa1cSFlorian Fainelli case BRCM_SATA_PHY_DSL_28NM:
6907b69fa1cSFlorian Fainelli rc = brcm_dsl_sata_init(port);
6917b69fa1cSFlorian Fainelli break;
6920b56e9a7SVivek Gautam default:
6930b56e9a7SVivek Gautam rc = -ENODEV;
6940b56e9a7SVivek Gautam }
6950b56e9a7SVivek Gautam
6960b56e9a7SVivek Gautam return rc;
6970b56e9a7SVivek Gautam }
6980b56e9a7SVivek Gautam
brcm_stb_sata_calibrate(struct brcm_sata_port * port)6993e507769SFlorian Fainelli static void brcm_stb_sata_calibrate(struct brcm_sata_port *port)
7003e507769SFlorian Fainelli {
7013e507769SFlorian Fainelli u32 tmp = BIT(8);
7023e507769SFlorian Fainelli
7030ed41b33SFlorian Fainelli brcm_sata_phy_wr(port, RXPMD_REG_BANK, RXPMD_RX_FREQ_MON_CONTROL1,
7043e507769SFlorian Fainelli ~tmp, tmp);
7053e507769SFlorian Fainelli }
7063e507769SFlorian Fainelli
brcm_sata_phy_calibrate(struct phy * phy)7073e507769SFlorian Fainelli static int brcm_sata_phy_calibrate(struct phy *phy)
7083e507769SFlorian Fainelli {
7093e507769SFlorian Fainelli struct brcm_sata_port *port = phy_get_drvdata(phy);
7103e507769SFlorian Fainelli int rc = -EOPNOTSUPP;
7113e507769SFlorian Fainelli
7123e507769SFlorian Fainelli switch (port->phy_priv->version) {
7133e507769SFlorian Fainelli case BRCM_SATA_PHY_STB_28NM:
7143e507769SFlorian Fainelli case BRCM_SATA_PHY_STB_40NM:
7153e507769SFlorian Fainelli brcm_stb_sata_calibrate(port);
7163e507769SFlorian Fainelli rc = 0;
7173e507769SFlorian Fainelli break;
7183e507769SFlorian Fainelli default:
7193e507769SFlorian Fainelli break;
72001353bbeSFengguang Wu }
7213e507769SFlorian Fainelli
7223e507769SFlorian Fainelli return rc;
7233e507769SFlorian Fainelli }
7243e507769SFlorian Fainelli
7250b56e9a7SVivek Gautam static const struct phy_ops phy_ops = {
7260b56e9a7SVivek Gautam .init = brcm_sata_phy_init,
7273e507769SFlorian Fainelli .calibrate = brcm_sata_phy_calibrate,
7280b56e9a7SVivek Gautam .owner = THIS_MODULE,
7290b56e9a7SVivek Gautam };
7300b56e9a7SVivek Gautam
7310b56e9a7SVivek Gautam static const struct of_device_id brcm_sata_phy_of_match[] = {
73297844253SFlorian Fainelli { .compatible = "brcm,bcm7216-sata-phy",
73397844253SFlorian Fainelli .data = (void *)BRCM_SATA_PHY_STB_16NM },
7340b56e9a7SVivek Gautam { .compatible = "brcm,bcm7445-sata-phy",
7350b56e9a7SVivek Gautam .data = (void *)BRCM_SATA_PHY_STB_28NM },
7360b56e9a7SVivek Gautam { .compatible = "brcm,bcm7425-sata-phy",
7370b56e9a7SVivek Gautam .data = (void *)BRCM_SATA_PHY_STB_40NM },
7380b56e9a7SVivek Gautam { .compatible = "brcm,iproc-ns2-sata-phy",
7390b56e9a7SVivek Gautam .data = (void *)BRCM_SATA_PHY_IPROC_NS2 },
7400b56e9a7SVivek Gautam { .compatible = "brcm,iproc-nsp-sata-phy",
7410b56e9a7SVivek Gautam .data = (void *)BRCM_SATA_PHY_IPROC_NSP },
74280886f7cSSrinath Mannam { .compatible = "brcm,iproc-sr-sata-phy",
74380886f7cSSrinath Mannam .data = (void *)BRCM_SATA_PHY_IPROC_SR },
7447b69fa1cSFlorian Fainelli { .compatible = "brcm,bcm63138-sata-phy",
7457b69fa1cSFlorian Fainelli .data = (void *)BRCM_SATA_PHY_DSL_28NM },
7460b56e9a7SVivek Gautam {},
7470b56e9a7SVivek Gautam };
7480b56e9a7SVivek Gautam MODULE_DEVICE_TABLE(of, brcm_sata_phy_of_match);
7490b56e9a7SVivek Gautam
brcm_sata_phy_probe(struct platform_device * pdev)7500b56e9a7SVivek Gautam static int brcm_sata_phy_probe(struct platform_device *pdev)
7510b56e9a7SVivek Gautam {
752af174c49SFlorian Fainelli const char *rxaeq_mode;
7530b56e9a7SVivek Gautam struct device *dev = &pdev->dev;
7540b56e9a7SVivek Gautam struct device_node *dn = dev->of_node, *child;
7550b56e9a7SVivek Gautam const struct of_device_id *of_id;
7560b56e9a7SVivek Gautam struct brcm_sata_phy *priv;
7570b56e9a7SVivek Gautam struct phy_provider *provider;
7580b56e9a7SVivek Gautam int ret, count = 0;
7590b56e9a7SVivek Gautam
7600b56e9a7SVivek Gautam if (of_get_child_count(dn) == 0)
7610b56e9a7SVivek Gautam return -ENODEV;
7620b56e9a7SVivek Gautam
7630b56e9a7SVivek Gautam priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
7640b56e9a7SVivek Gautam if (!priv)
7650b56e9a7SVivek Gautam return -ENOMEM;
7660b56e9a7SVivek Gautam dev_set_drvdata(dev, priv);
7670b56e9a7SVivek Gautam priv->dev = dev;
7680b56e9a7SVivek Gautam
769f669bc8bSChunfeng Yun priv->phy_base = devm_platform_ioremap_resource_byname(pdev, "phy");
7700b56e9a7SVivek Gautam if (IS_ERR(priv->phy_base))
7710b56e9a7SVivek Gautam return PTR_ERR(priv->phy_base);
7720b56e9a7SVivek Gautam
7730b56e9a7SVivek Gautam of_id = of_match_node(brcm_sata_phy_of_match, dn);
7740b56e9a7SVivek Gautam if (of_id)
775*d35c12b7SKrzysztof Kozlowski priv->version = (uintptr_t)of_id->data;
7760b56e9a7SVivek Gautam else
7770b56e9a7SVivek Gautam priv->version = BRCM_SATA_PHY_STB_28NM;
7780b56e9a7SVivek Gautam
7790b56e9a7SVivek Gautam if (priv->version == BRCM_SATA_PHY_IPROC_NS2) {
780f669bc8bSChunfeng Yun priv->ctrl_base = devm_platform_ioremap_resource_byname(pdev, "phy-ctrl");
7810b56e9a7SVivek Gautam if (IS_ERR(priv->ctrl_base))
7820b56e9a7SVivek Gautam return PTR_ERR(priv->ctrl_base);
7830b56e9a7SVivek Gautam }
7840b56e9a7SVivek Gautam
7850b56e9a7SVivek Gautam for_each_available_child_of_node(dn, child) {
7860b56e9a7SVivek Gautam unsigned int id;
7870b56e9a7SVivek Gautam struct brcm_sata_port *port;
7880b56e9a7SVivek Gautam
7890b56e9a7SVivek Gautam if (of_property_read_u32(child, "reg", &id)) {
790ac9ba7dcSRob Herring dev_err(dev, "missing reg property in node %pOFn\n",
791ac9ba7dcSRob Herring child);
7920b56e9a7SVivek Gautam ret = -EINVAL;
7930b56e9a7SVivek Gautam goto put_child;
7940b56e9a7SVivek Gautam }
7950b56e9a7SVivek Gautam
7960b56e9a7SVivek Gautam if (id >= MAX_PORTS) {
7970b56e9a7SVivek Gautam dev_err(dev, "invalid reg: %u\n", id);
7980b56e9a7SVivek Gautam ret = -EINVAL;
7990b56e9a7SVivek Gautam goto put_child;
8000b56e9a7SVivek Gautam }
8010b56e9a7SVivek Gautam if (priv->phys[id].phy) {
8020b56e9a7SVivek Gautam dev_err(dev, "already registered port %u\n", id);
8030b56e9a7SVivek Gautam ret = -EINVAL;
8040b56e9a7SVivek Gautam goto put_child;
8050b56e9a7SVivek Gautam }
8060b56e9a7SVivek Gautam
8070b56e9a7SVivek Gautam port = &priv->phys[id];
8080b56e9a7SVivek Gautam port->portnum = id;
8090b56e9a7SVivek Gautam port->phy_priv = priv;
8100b56e9a7SVivek Gautam port->phy = devm_phy_create(dev, child, &phy_ops);
811af174c49SFlorian Fainelli port->rxaeq_mode = RXAEQ_MODE_OFF;
812af174c49SFlorian Fainelli if (!of_property_read_string(child, "brcm,rxaeq-mode",
813af174c49SFlorian Fainelli &rxaeq_mode))
814af174c49SFlorian Fainelli port->rxaeq_mode = rxaeq_to_val(rxaeq_mode);
815af174c49SFlorian Fainelli if (port->rxaeq_mode == RXAEQ_MODE_MANUAL)
816af174c49SFlorian Fainelli of_property_read_u32(child, "brcm,rxaeq-value",
817af174c49SFlorian Fainelli &port->rxaeq_val);
818839034d8SFlorian Fainelli
819839034d8SFlorian Fainelli of_property_read_u32(child, "brcm,tx-amplitude-millivolt",
820839034d8SFlorian Fainelli &port->tx_amplitude_val);
821839034d8SFlorian Fainelli
8220b56e9a7SVivek Gautam port->ssc_en = of_property_read_bool(child, "brcm,enable-ssc");
8230b56e9a7SVivek Gautam if (IS_ERR(port->phy)) {
8240b56e9a7SVivek Gautam dev_err(dev, "failed to create PHY\n");
8250b56e9a7SVivek Gautam ret = PTR_ERR(port->phy);
8260b56e9a7SVivek Gautam goto put_child;
8270b56e9a7SVivek Gautam }
8280b56e9a7SVivek Gautam
8290b56e9a7SVivek Gautam phy_set_drvdata(port->phy, port);
8300b56e9a7SVivek Gautam count++;
8310b56e9a7SVivek Gautam }
8320b56e9a7SVivek Gautam
8330b56e9a7SVivek Gautam provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
8340b56e9a7SVivek Gautam if (IS_ERR(provider)) {
8350b56e9a7SVivek Gautam dev_err(dev, "could not register PHY provider\n");
8360b56e9a7SVivek Gautam return PTR_ERR(provider);
8370b56e9a7SVivek Gautam }
8380b56e9a7SVivek Gautam
8390b56e9a7SVivek Gautam dev_info(dev, "registered %d port(s)\n", count);
8400b56e9a7SVivek Gautam
8410b56e9a7SVivek Gautam return 0;
8420b56e9a7SVivek Gautam put_child:
8430b56e9a7SVivek Gautam of_node_put(child);
8440b56e9a7SVivek Gautam return ret;
8450b56e9a7SVivek Gautam }
8460b56e9a7SVivek Gautam
8470b56e9a7SVivek Gautam static struct platform_driver brcm_sata_phy_driver = {
8480b56e9a7SVivek Gautam .probe = brcm_sata_phy_probe,
8490b56e9a7SVivek Gautam .driver = {
8500b56e9a7SVivek Gautam .of_match_table = brcm_sata_phy_of_match,
8510b56e9a7SVivek Gautam .name = "brcm-sata-phy",
8520b56e9a7SVivek Gautam }
8530b56e9a7SVivek Gautam };
8540b56e9a7SVivek Gautam module_platform_driver(brcm_sata_phy_driver);
8550b56e9a7SVivek Gautam
8560b56e9a7SVivek Gautam MODULE_DESCRIPTION("Broadcom SATA PHY driver");
8570b56e9a7SVivek Gautam MODULE_LICENSE("GPL");
8580b56e9a7SVivek Gautam MODULE_AUTHOR("Marc Carino");
8590b56e9a7SVivek Gautam MODULE_AUTHOR("Brian Norris");
8600b56e9a7SVivek Gautam MODULE_ALIAS("platform:phy-brcm-sata");
861