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