Merge tag 'u-boot-atmel-fixes-2020.07-a' of https://gitlab.denx.de/u-boot/custodians...
[oweals/u-boot.git] / arch / arm / mach-omap2 / pipe3-phy.c
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
57 static inline u32 omap_pipe3_readl(void __iomem *addr, unsigned offset)
58 {
59         return __raw_readl(addr + offset);
60 }
61
62 static inline void omap_pipe3_writel(void __iomem *addr, unsigned offset,
63                 u32 data)
64 {
65         __raw_writel(data, addr + offset);
66 }
67
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
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
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
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
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
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