]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - arch/arm/cpu/armv7/omap-common/pipe3-phy.c
Merge branch 'karo-tx-uboot' into kc-merge
[karo-tx-uboot.git] / arch / arm / cpu / armv7 / omap-common / pipe3-phy.c
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 <asm/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