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