xref: /openbmc/linux/drivers/phy/broadcom/phy-brcm-sata.c (revision c900529f3d9161bfde5cca0754f83b4d3c3e0220)
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