xref: /rk3399_rockchip-uboot/arch/arm/mach-omap2/pipe3-phy.c (revision 2d221489df021393654805536be7effcb9d39702)
1*983e3700STom Rini /*
2*983e3700STom Rini  * TI PIPE3 PHY
3*983e3700STom Rini  *
4*983e3700STom Rini  * (C) Copyright 2013
5*983e3700STom Rini  * Texas Instruments, <www.ti.com>
6*983e3700STom Rini  *
7*983e3700STom Rini  * SPDX-License-Identifier:     GPL-2.0+
8*983e3700STom Rini  */
9*983e3700STom Rini 
10*983e3700STom Rini #include <common.h>
11*983e3700STom Rini #include <sata.h>
12*983e3700STom Rini #include <asm/arch/clock.h>
13*983e3700STom Rini #include <asm/arch/sys_proto.h>
14*983e3700STom Rini #include <asm/io.h>
15*983e3700STom Rini #include <linux/errno.h>
16*983e3700STom Rini #include "pipe3-phy.h"
17*983e3700STom Rini 
18*983e3700STom Rini /* PLLCTRL Registers */
19*983e3700STom Rini #define PLL_STATUS              0x00000004
20*983e3700STom Rini #define PLL_GO                  0x00000008
21*983e3700STom Rini #define PLL_CONFIGURATION1      0x0000000C
22*983e3700STom Rini #define PLL_CONFIGURATION2      0x00000010
23*983e3700STom Rini #define PLL_CONFIGURATION3      0x00000014
24*983e3700STom Rini #define PLL_CONFIGURATION4      0x00000020
25*983e3700STom Rini 
26*983e3700STom Rini #define PLL_REGM_MASK           0x001FFE00
27*983e3700STom Rini #define PLL_REGM_SHIFT          9
28*983e3700STom Rini #define PLL_REGM_F_MASK         0x0003FFFF
29*983e3700STom Rini #define PLL_REGM_F_SHIFT        0
30*983e3700STom Rini #define PLL_REGN_MASK           0x000001FE
31*983e3700STom Rini #define PLL_REGN_SHIFT          1
32*983e3700STom Rini #define PLL_SELFREQDCO_MASK     0x0000000E
33*983e3700STom Rini #define PLL_SELFREQDCO_SHIFT    1
34*983e3700STom Rini #define PLL_SD_MASK             0x0003FC00
35*983e3700STom Rini #define PLL_SD_SHIFT            10
36*983e3700STom Rini #define SET_PLL_GO              0x1
37*983e3700STom Rini #define PLL_TICOPWDN            BIT(16)
38*983e3700STom Rini #define PLL_LDOPWDN             BIT(15)
39*983e3700STom Rini #define PLL_LOCK                0x2
40*983e3700STom Rini #define PLL_IDLE                0x1
41*983e3700STom Rini 
42*983e3700STom Rini /* PHY POWER CONTROL Register */
43*983e3700STom Rini #define OMAP_CTRL_PIPE3_PHY_PWRCTL_CLK_CMD_MASK         0x003FC000
44*983e3700STom Rini #define OMAP_CTRL_PIPE3_PHY_PWRCTL_CLK_CMD_SHIFT        0xE
45*983e3700STom Rini 
46*983e3700STom Rini #define OMAP_CTRL_PIPE3_PHY_PWRCTL_CLK_FREQ_MASK        0xFFC00000
47*983e3700STom Rini #define OMAP_CTRL_PIPE3_PHY_PWRCTL_CLK_FREQ_SHIFT       0x16
48*983e3700STom Rini 
49*983e3700STom Rini #define OMAP_CTRL_PIPE3_PHY_TX_RX_POWERON       0x3
50*983e3700STom Rini #define OMAP_CTRL_PIPE3_PHY_TX_RX_POWEROFF      0x0
51*983e3700STom Rini 
52*983e3700STom Rini 
53*983e3700STom Rini #define PLL_IDLE_TIME   100     /* in milliseconds */
54*983e3700STom Rini #define PLL_LOCK_TIME   100     /* in milliseconds */
55*983e3700STom Rini 
omap_pipe3_readl(void __iomem * addr,unsigned offset)56*983e3700STom Rini static inline u32 omap_pipe3_readl(void __iomem *addr, unsigned offset)
57*983e3700STom Rini {
58*983e3700STom Rini 	return __raw_readl(addr + offset);
59*983e3700STom Rini }
60*983e3700STom Rini 
omap_pipe3_writel(void __iomem * addr,unsigned offset,u32 data)61*983e3700STom Rini static inline void omap_pipe3_writel(void __iomem *addr, unsigned offset,
62*983e3700STom Rini 		u32 data)
63*983e3700STom Rini {
64*983e3700STom Rini 	__raw_writel(data, addr + offset);
65*983e3700STom Rini }
66*983e3700STom Rini 
omap_pipe3_get_dpll_params(struct omap_pipe3 * pipe3)67*983e3700STom Rini static struct pipe3_dpll_params *omap_pipe3_get_dpll_params(struct omap_pipe3
68*983e3700STom Rini 									*pipe3)
69*983e3700STom Rini {
70*983e3700STom Rini 	u32 rate;
71*983e3700STom Rini 	struct pipe3_dpll_map *dpll_map = pipe3->dpll_map;
72*983e3700STom Rini 
73*983e3700STom Rini 	rate = get_sys_clk_freq();
74*983e3700STom Rini 
75*983e3700STom Rini 	for (; dpll_map->rate; dpll_map++) {
76*983e3700STom Rini 		if (rate == dpll_map->rate)
77*983e3700STom Rini 			return &dpll_map->params;
78*983e3700STom Rini 	}
79*983e3700STom Rini 
80*983e3700STom Rini 	printf("%s: No DPLL configuration for %u Hz SYS CLK\n",
81*983e3700STom Rini 	       __func__, rate);
82*983e3700STom Rini 	return NULL;
83*983e3700STom Rini }
84*983e3700STom Rini 
85*983e3700STom Rini 
omap_pipe3_wait_lock(struct omap_pipe3 * phy)86*983e3700STom Rini static int omap_pipe3_wait_lock(struct omap_pipe3 *phy)
87*983e3700STom Rini {
88*983e3700STom Rini 	u32 val;
89*983e3700STom Rini 	int timeout = PLL_LOCK_TIME;
90*983e3700STom Rini 
91*983e3700STom Rini 	do {
92*983e3700STom Rini 		mdelay(1);
93*983e3700STom Rini 		val = omap_pipe3_readl(phy->pll_ctrl_base, PLL_STATUS);
94*983e3700STom Rini 		if (val & PLL_LOCK)
95*983e3700STom Rini 			break;
96*983e3700STom Rini 	} while (--timeout);
97*983e3700STom Rini 
98*983e3700STom Rini 	if (!(val & PLL_LOCK)) {
99*983e3700STom Rini 		printf("%s: DPLL failed to lock\n", __func__);
100*983e3700STom Rini 		return -EBUSY;
101*983e3700STom Rini 	}
102*983e3700STom Rini 
103*983e3700STom Rini 	return 0;
104*983e3700STom Rini }
105*983e3700STom Rini 
omap_pipe3_dpll_program(struct omap_pipe3 * phy)106*983e3700STom Rini static int omap_pipe3_dpll_program(struct omap_pipe3 *phy)
107*983e3700STom Rini {
108*983e3700STom Rini 	u32                     val;
109*983e3700STom Rini 	struct pipe3_dpll_params *dpll_params;
110*983e3700STom Rini 
111*983e3700STom Rini 	dpll_params = omap_pipe3_get_dpll_params(phy);
112*983e3700STom Rini 	if (!dpll_params) {
113*983e3700STom Rini 		printf("%s: Invalid DPLL parameters\n", __func__);
114*983e3700STom Rini 		return -EINVAL;
115*983e3700STom Rini 	}
116*983e3700STom Rini 
117*983e3700STom Rini 	val = omap_pipe3_readl(phy->pll_ctrl_base, PLL_CONFIGURATION1);
118*983e3700STom Rini 	val &= ~PLL_REGN_MASK;
119*983e3700STom Rini 	val |= dpll_params->n << PLL_REGN_SHIFT;
120*983e3700STom Rini 	omap_pipe3_writel(phy->pll_ctrl_base, PLL_CONFIGURATION1, val);
121*983e3700STom Rini 
122*983e3700STom Rini 	val = omap_pipe3_readl(phy->pll_ctrl_base, PLL_CONFIGURATION2);
123*983e3700STom Rini 	val &= ~PLL_SELFREQDCO_MASK;
124*983e3700STom Rini 	val |= dpll_params->freq << PLL_SELFREQDCO_SHIFT;
125*983e3700STom Rini 	omap_pipe3_writel(phy->pll_ctrl_base, PLL_CONFIGURATION2, val);
126*983e3700STom Rini 
127*983e3700STom Rini 	val = omap_pipe3_readl(phy->pll_ctrl_base, PLL_CONFIGURATION1);
128*983e3700STom Rini 	val &= ~PLL_REGM_MASK;
129*983e3700STom Rini 	val |= dpll_params->m << PLL_REGM_SHIFT;
130*983e3700STom Rini 	omap_pipe3_writel(phy->pll_ctrl_base, PLL_CONFIGURATION1, val);
131*983e3700STom Rini 
132*983e3700STom Rini 	val = omap_pipe3_readl(phy->pll_ctrl_base, PLL_CONFIGURATION4);
133*983e3700STom Rini 	val &= ~PLL_REGM_F_MASK;
134*983e3700STom Rini 	val |= dpll_params->mf << PLL_REGM_F_SHIFT;
135*983e3700STom Rini 	omap_pipe3_writel(phy->pll_ctrl_base, PLL_CONFIGURATION4, val);
136*983e3700STom Rini 
137*983e3700STom Rini 	val = omap_pipe3_readl(phy->pll_ctrl_base, PLL_CONFIGURATION3);
138*983e3700STom Rini 	val &= ~PLL_SD_MASK;
139*983e3700STom Rini 	val |= dpll_params->sd << PLL_SD_SHIFT;
140*983e3700STom Rini 	omap_pipe3_writel(phy->pll_ctrl_base, PLL_CONFIGURATION3, val);
141*983e3700STom Rini 
142*983e3700STom Rini 	omap_pipe3_writel(phy->pll_ctrl_base, PLL_GO, SET_PLL_GO);
143*983e3700STom Rini 
144*983e3700STom Rini 	return omap_pipe3_wait_lock(phy);
145*983e3700STom Rini }
146*983e3700STom Rini 
omap_control_phy_power(struct omap_pipe3 * phy,int on)147*983e3700STom Rini static void omap_control_phy_power(struct omap_pipe3 *phy, int on)
148*983e3700STom Rini {
149*983e3700STom Rini 	u32 val, rate;
150*983e3700STom Rini 
151*983e3700STom Rini 	val = readl(phy->power_reg);
152*983e3700STom Rini 
153*983e3700STom Rini 	rate = get_sys_clk_freq();
154*983e3700STom Rini 	rate = rate/1000000;
155*983e3700STom Rini 
156*983e3700STom Rini 	if (on) {
157*983e3700STom Rini 		val &= ~(OMAP_CTRL_PIPE3_PHY_PWRCTL_CLK_CMD_MASK |
158*983e3700STom Rini 				OMAP_CTRL_PIPE3_PHY_PWRCTL_CLK_FREQ_MASK);
159*983e3700STom Rini 		val |= OMAP_CTRL_PIPE3_PHY_TX_RX_POWERON <<
160*983e3700STom Rini 			OMAP_CTRL_PIPE3_PHY_PWRCTL_CLK_CMD_SHIFT;
161*983e3700STom Rini 		val |= rate <<
162*983e3700STom Rini 			OMAP_CTRL_PIPE3_PHY_PWRCTL_CLK_FREQ_SHIFT;
163*983e3700STom Rini 	} else {
164*983e3700STom Rini 		val &= ~OMAP_CTRL_PIPE3_PHY_PWRCTL_CLK_CMD_MASK;
165*983e3700STom Rini 		val |= OMAP_CTRL_PIPE3_PHY_TX_RX_POWEROFF <<
166*983e3700STom Rini 			OMAP_CTRL_PIPE3_PHY_PWRCTL_CLK_CMD_SHIFT;
167*983e3700STom Rini 	}
168*983e3700STom Rini 
169*983e3700STom Rini 	writel(val, phy->power_reg);
170*983e3700STom Rini }
171*983e3700STom Rini 
phy_pipe3_power_on(struct omap_pipe3 * phy)172*983e3700STom Rini int phy_pipe3_power_on(struct omap_pipe3 *phy)
173*983e3700STom Rini {
174*983e3700STom Rini 	int ret;
175*983e3700STom Rini 	u32 val;
176*983e3700STom Rini 
177*983e3700STom Rini 	/* Program the DPLL only if not locked */
178*983e3700STom Rini 	val = omap_pipe3_readl(phy->pll_ctrl_base, PLL_STATUS);
179*983e3700STom Rini 	if (!(val & PLL_LOCK)) {
180*983e3700STom Rini 		ret = omap_pipe3_dpll_program(phy);
181*983e3700STom Rini 		if (ret)
182*983e3700STom Rini 			return ret;
183*983e3700STom Rini 	} else {
184*983e3700STom Rini 		/* else just bring it out of IDLE mode */
185*983e3700STom Rini 		val = omap_pipe3_readl(phy->pll_ctrl_base, PLL_CONFIGURATION2);
186*983e3700STom Rini 		if (val & PLL_IDLE) {
187*983e3700STom Rini 			val &= ~PLL_IDLE;
188*983e3700STom Rini 			omap_pipe3_writel(phy->pll_ctrl_base,
189*983e3700STom Rini 					  PLL_CONFIGURATION2, val);
190*983e3700STom Rini 			ret = omap_pipe3_wait_lock(phy);
191*983e3700STom Rini 			if (ret)
192*983e3700STom Rini 				return ret;
193*983e3700STom Rini 		}
194*983e3700STom Rini 	}
195*983e3700STom Rini 
196*983e3700STom Rini 	/* Power up the PHY */
197*983e3700STom Rini 	omap_control_phy_power(phy, 1);
198*983e3700STom Rini 
199*983e3700STom Rini 	return 0;
200*983e3700STom Rini }
201*983e3700STom Rini 
phy_pipe3_power_off(struct omap_pipe3 * phy)202*983e3700STom Rini int phy_pipe3_power_off(struct omap_pipe3 *phy)
203*983e3700STom Rini {
204*983e3700STom Rini 	u32 val;
205*983e3700STom Rini 	int timeout = PLL_IDLE_TIME;
206*983e3700STom Rini 
207*983e3700STom Rini 	/* Power down the PHY */
208*983e3700STom Rini 	omap_control_phy_power(phy, 0);
209*983e3700STom Rini 
210*983e3700STom Rini 	/* Put DPLL in IDLE mode */
211*983e3700STom Rini 	val = omap_pipe3_readl(phy->pll_ctrl_base, PLL_CONFIGURATION2);
212*983e3700STom Rini 	val |= PLL_IDLE;
213*983e3700STom Rini 	omap_pipe3_writel(phy->pll_ctrl_base, PLL_CONFIGURATION2, val);
214*983e3700STom Rini 
215*983e3700STom Rini 	/* wait for LDO and Oscillator to power down */
216*983e3700STom Rini 	do {
217*983e3700STom Rini 		mdelay(1);
218*983e3700STom Rini 		val = omap_pipe3_readl(phy->pll_ctrl_base, PLL_STATUS);
219*983e3700STom Rini 		if ((val & PLL_TICOPWDN) && (val & PLL_LDOPWDN))
220*983e3700STom Rini 			break;
221*983e3700STom Rini 	} while (--timeout);
222*983e3700STom Rini 
223*983e3700STom Rini 	if (!(val & PLL_TICOPWDN) || !(val & PLL_LDOPWDN)) {
224*983e3700STom Rini 		printf("%s: Failed to power down DPLL: PLL_STATUS 0x%x\n",
225*983e3700STom Rini 		       __func__, val);
226*983e3700STom Rini 		return -EBUSY;
227*983e3700STom Rini 	}
228*983e3700STom Rini 
229*983e3700STom Rini 	return 0;
230*983e3700STom Rini }
231*983e3700STom Rini 
232