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