blob: aa54ebc43efb1d991b20506d0b581702deb50739 [file] [log] [blame]
Ionela Voinescub3f666b2015-01-18 22:37:11 +00001/*
2 * This file is part of the coreboot project.
3 *
4 * Copyright (C) 2014 Imagination Technologies
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License as
8 * published by the Free Software Foundation; version 2 of
9 * the License.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
Ionela Voinescub3f666b2015-01-18 22:37:11 +000015 */
16
Kyösti Mälkki13f66502019-03-03 08:01:05 +020017#include <device/mmio.h>
Ionela Voinescu1d4c3052015-06-07 23:22:34 +010018#include <assert.h>
19#include <delay.h>
Ionela Voinescub3f666b2015-01-18 22:37:11 +000020#include <soc/clocks.h>
21#include <timer.h>
Ionela Voinescub3f666b2015-01-18 22:37:11 +000022
23/* Definitions for PLL enable */
24#define PISTACHIO_CLOCK_SWITCH 0xB8144200
25
26#define SYS_EXTERN_PLL_BYPASS_MASK 0x00002000
27#define SYS_PLL_CTRL4_ADDR 0xB8144048
28#define SYS_INTERNAL_PLL_BYPASS_MASK 0x10000000
29#define SYS_PLL_PD_CTRL_ADDR 0xB8144044
Ionela Voinescu11364472015-07-15 12:42:01 +010030#define SYS_PLL_PD_CTRL_PD_MASK 0x00000039
31#define SYS_PLL_DACPD_ADDR 0xB8144044
32#define SYS_PLL_DACPD_MASK 0x00000002
33#define SYS_PLL_DSMPD_ADDR 0xB8144044
34#define SYS_PLL_DSMPD_MASK 0x00000004
Ionela Voinescub3f666b2015-01-18 22:37:11 +000035
36#define MIPS_EXTERN_PLL_BYPASS_MASK 0x00000002
37#define MIPS_PLL_CTRL2_ADDR 0xB8144008
38#define MIPS_INTERNAL_PLL_BYPASS_MASK 0x10000000
39#define MIPS_PLL_PD_CTRL_ADDR 0xB8144004
Ionela Voinescu11364472015-07-15 12:42:01 +010040#define MIPS_PLL_PD_CTRL_PD_MASK 0x0D000000
41#define MIPS_PLL_DSMPD_ADDR 0xB8144004
42#define MIPS_PLL_DSMPD_MASK 0x02000000
Ionela Voinescub3f666b2015-01-18 22:37:11 +000043
44/* Definitions for PLL dividers */
45#define SYS_PLL_POSTDIV_ADDR 0xB8144040
46#define SYS_PLL_POSTDIV1_MASK 0x07000000
47#define SYS_PLL_POSTDIV1_SHIFT 24
48#define SYS_PLL_POSTDIV2_MASK 0x38000000
49#define SYS_PLL_POSTDIV2_SHIFT 27
50#define SYS_PLL_STATUS_ADDR 0xB8144038
51#define SYS_PLL_STATUS_LOCK_MASK 0x00000001
52
Ionela Voinescu90d12352015-07-15 12:10:05 +010053#define SYS_PLL_REFDIV_ADDR 0xB814403C
54#define SYS_PLL_REFDIV_MASK 0x0000003F
55#define SYS_PLL_REFDIV_SHIFT 0
56#define SYS_PLL_FEEDBACK_ADDR 0xB814403C
57#define SYS_PLL_FEEDBACK_MASK 0x0003FFC0
58#define SYS_PLL_FEEDBACK_SHIFT 6
59
Ionela Voinescub3f666b2015-01-18 22:37:11 +000060#define MIPS_PLL_POSTDIV_ADDR 0xB8144004
61#define MIPS_PLL_POSTDIV1_MASK 0x001C0000
62#define MIPS_PLL_POSTDIV1_SHIFT 18
63#define MIPS_PLL_POSTDIV2_MASK 0x00E00000
64#define MIPS_PLL_POSTDIV2_SHIFT 21
65#define MIPS_PLL_STATUS_ADDR 0xB8144000
66#define MIPS_PLL_STATUS_LOCK_MASK 0x00000001
67
68#define MIPS_REFDIV_ADDR 0xB8144004
69#define MIPS_REFDIV_MASK 0x0000003F
70#define MIPS_REFDIV_SHIFT 0
71#define MIPS_FEEDBACK_ADDR 0xB8144004
72#define MIPS_FEEDBACK_MASK 0x0003FFC0
73#define MIPS_FEEDBACK_SHIFT 6
74
75/* Definitions for system clock setup */
76#define SYSCLKINTERNAL_CTRL_ADDR 0xB8144244
77#define SYSCLKINTERNAL_MASK 0X00000007
78
Ionela Voinescu8b1f23e2015-01-26 13:15:12 +000079/* Definitions for MIPS clock setup */
80#define MIPSCLKINTERNAL_CTRL_ADDR 0xB8144204
81#define MIPSCLKINTERNAL_MASK 0x00000003
82#define MIPSCLKOUT_CTRL_ADDR 0xB8144208
83#define MIPSCLKOUT_MASK 0x000000FF
84
Ionela Voinescu4f3d4002015-11-01 19:55:48 +000085/* Peripheral Clock gate reg */
86#define MIPS_CLOCK_GATE_ADDR 0xB8144900
87#define RPU_CLOCK_GATE_ADDR 0xB8144904
88#define MIPS_CLOCK_GATE_ALL_ON 0x3fff
89#define RPU_CLOCK_GATE_ALL_OFF 0x0
90
Ionela Voinescub3f666b2015-01-18 22:37:11 +000091/* Definitions for USB clock setup */
92#define USBPHYCLKOUT_CTRL_ADDR 0xB814422C
93#define USBPHYCLKOUT_MASK 0X0000003F
94#define USBPHYCONTROL1_ADDR 0xB8149004
95#define USBPHYCONTROL1_FSEL_SHIFT 2
96#define USBPHYCONTROL1_FSEL_MASK 0x1C
97#define USBPHYSTRAPCTRL_ADDR 0xB8149010
98#define USBPHYSTRAPCTRL_REFCLKSEL_SHIFT 4
99#define USBPHYSTRAPCTRL_REFCLKSEL_MASK 0x30
100#define USBPHYSTATUS_ADDR 0xB8149014
101#define USBPHYSTATUS_RX_PHY_CLK_MASK 0x200
102#define USBPHYSTATUS_RX_UTMI_CLK_MASK 0x100
103#define USBPHYSTATUS_VBUS_FAULT_MASK 0x80
104
105/* Definitions for UART0/1 setup */
106#define UART0CLKINTERNAL_CTRL_ADDR 0xB8144234
107#define UART0CLKINTERNAL_MASK 0x00000007
108#define UART0CLKOUT_CTRL_ADDR 0xB8144238
109#define UART0CLKOUT_MASK 0x000003FF
110#define UART1CLKINTERNAL_CTRL_ADDR 0xB814423C
111#define UART1CLKINTERNAL_MASK 0x00000007
112#define UART1CLKOUT_CTRL_ADDR 0xB8144240
113#define UART1CLKOUT_MASK 0x000003FF
114
Ionela Voinescu38063b02015-03-05 13:09:57 +0000115/* Definitions for I2C setup */
Ionela Voinescu88357542015-09-15 13:56:30 +0100116#define I2CCLKDIV1_CTRL_ADDR(i) (0xB8144800 + 0x013C + (2*(i)*4))
Ionela Voinescu38063b02015-03-05 13:09:57 +0000117#define I2CCLKDIV1_MASK 0x0000007F
Ionela Voinescu88357542015-09-15 13:56:30 +0100118#define I2CCLKOUT_CTRL_ADDR(i) (0xB8144800 + 0x0140 + (2*(i)*4))
Ionela Voinescu38063b02015-03-05 13:09:57 +0000119#define I2CCLKOUT_MASK 0x0000007F
Ionela Voinescufdce6802015-02-17 18:28:34 +0000120
Ionela Voinescu8b1f23e2015-01-26 13:15:12 +0000121/* Definitions for ROM clock setup */
Ionela Voinescua7023902015-02-02 14:34:24 +0000122#define ROMCLKOUT_CTRL_ADDR 0xB814490C
Ionela Voinescu8b1f23e2015-01-26 13:15:12 +0000123#define ROMCLKOUT_MASK 0x0000007F
124
125/* Definitions for ETH clock setup */
126#define ENETCLKMUX_MASK 0x00004000
127#define ENETCLKDIV_CTRL_ADDR 0xB8144230
128#define ENETCLKDIV_MASK 0x0000003F
129
Ionela Voinescub3f666b2015-01-18 22:37:11 +0000130/* Definitions for timeout values */
131#define PLL_TIMEOUT_VALUE_US 20000
132#define USB_TIMEOUT_VALUE_US 200000
133#define SYS_CLK_LOCK_DELAY 3
134
135struct pll_parameters {
136 u32 external_bypass_mask;
137 u32 ctrl_addr;
138 u32 internal_bypass_mask;
139 u32 power_down_ctrl_addr;
140 u32 power_down_ctrl_mask;
Ionela Voinescu11364472015-07-15 12:42:01 +0100141 u32 dacpd_addr;
142 u32 dacpd_mask;
143 u32 dsmpd_addr;
144 u32 dsmpd_mask;
Ionela Voinescub3f666b2015-01-18 22:37:11 +0000145 u32 postdiv_addr;
146 u32 postdiv1_shift;
147 u32 postdiv1_mask;
148 u32 postdiv2_shift;
149 u32 postdiv2_mask;
150 u32 status_addr;
151 u32 status_lock_mask;
152 u32 refdivider;
153 u32 refdiv_addr;
154 u32 refdiv_shift;
155 u32 refdiv_mask;
156 u32 feedback;
157 u32 feedback_addr;
158 u32 feedback_shift;
159 u32 feedback_mask;
160};
161
162enum plls {
163 SYS_PLL = 0,
164 MIPS_PLL = 1
165};
166
167static struct pll_parameters pll_params[] = {
168 [SYS_PLL] = {
169 .external_bypass_mask = SYS_EXTERN_PLL_BYPASS_MASK,
170 .ctrl_addr = SYS_PLL_CTRL4_ADDR,
171 .internal_bypass_mask = SYS_INTERNAL_PLL_BYPASS_MASK,
172 .power_down_ctrl_addr = SYS_PLL_PD_CTRL_ADDR,
173 .power_down_ctrl_mask = SYS_PLL_PD_CTRL_PD_MASK,
Ionela Voinescu11364472015-07-15 12:42:01 +0100174 /* Noise cancellation */
175 .dacpd_addr = SYS_PLL_DACPD_ADDR,
176 .dacpd_mask = SYS_PLL_DACPD_MASK,
177 .dsmpd_addr = SYS_PLL_DSMPD_ADDR,
178 /* 0 - Integer mode
179 * SYS_PLL_DSMPD_MASK - Fractional mode
180 */
181 .dsmpd_mask = 0,
Ionela Voinescub3f666b2015-01-18 22:37:11 +0000182 .postdiv_addr = SYS_PLL_POSTDIV_ADDR,
183 .postdiv1_shift = SYS_PLL_POSTDIV1_SHIFT,
184 .postdiv1_mask = SYS_PLL_POSTDIV1_MASK,
185 .postdiv2_shift = SYS_PLL_POSTDIV2_SHIFT,
186 .postdiv2_mask = SYS_PLL_POSTDIV2_MASK,
187 .status_addr = SYS_PLL_STATUS_ADDR,
188 .status_lock_mask = SYS_PLL_STATUS_LOCK_MASK,
189 .refdivider = 0, /* Not defined yet */
Ionela Voinescu90d12352015-07-15 12:10:05 +0100190 .refdiv_addr = SYS_PLL_REFDIV_ADDR,
191 .refdiv_shift = SYS_PLL_REFDIV_SHIFT,
192 .refdiv_mask = SYS_PLL_REFDIV_MASK,
193 .feedback = 0, /* Not defined yet */
194 .feedback_addr = SYS_PLL_FEEDBACK_ADDR,
195 .feedback_shift = SYS_PLL_FEEDBACK_SHIFT,
196 .feedback_mask = SYS_PLL_FEEDBACK_MASK
Ionela Voinescub3f666b2015-01-18 22:37:11 +0000197 },
198
199 [MIPS_PLL] = {
200 .external_bypass_mask = MIPS_EXTERN_PLL_BYPASS_MASK,
201 .ctrl_addr = MIPS_PLL_CTRL2_ADDR,
202 .internal_bypass_mask = MIPS_INTERNAL_PLL_BYPASS_MASK,
203 .power_down_ctrl_addr = MIPS_PLL_PD_CTRL_ADDR,
204 .power_down_ctrl_mask = MIPS_PLL_PD_CTRL_PD_MASK,
Ionela Voinescu11364472015-07-15 12:42:01 +0100205 .dacpd_addr = 0,
206 .dacpd_mask = 0,
207 .dsmpd_addr = MIPS_PLL_DSMPD_ADDR,
208 .dsmpd_mask = MIPS_PLL_DSMPD_MASK,
Ionela Voinescub3f666b2015-01-18 22:37:11 +0000209 .postdiv_addr = MIPS_PLL_POSTDIV_ADDR,
210 .postdiv1_shift = MIPS_PLL_POSTDIV1_SHIFT,
211 .postdiv1_mask = MIPS_PLL_POSTDIV1_MASK,
212 .postdiv2_shift = MIPS_PLL_POSTDIV2_SHIFT,
213 .postdiv2_mask = MIPS_PLL_POSTDIV2_MASK,
214 .status_addr = MIPS_PLL_STATUS_ADDR,
215 .status_lock_mask = MIPS_PLL_STATUS_LOCK_MASK,
216 .refdivider = 0, /* Not defined yet */
217 .refdiv_addr = MIPS_REFDIV_ADDR,
218 .refdiv_shift = MIPS_REFDIV_SHIFT,
219 .refdiv_mask = MIPS_REFDIV_MASK,
220 .feedback = 0, /* Not defined yet */
221 .feedback_addr = MIPS_FEEDBACK_ADDR,
222 .feedback_shift = MIPS_FEEDBACK_SHIFT,
223 .feedback_mask = MIPS_FEEDBACK_MASK
224 }
225};
226
227static int pll_setup(struct pll_parameters *param, u8 divider1, u8 divider2)
228{
229 u32 reg;
230 struct stopwatch sw;
231
232 /* Check input parameters */
Ionela Voinescu41d1ca82015-01-26 17:15:59 +0000233 assert(!((divider1 << param->postdiv1_shift) &
234 ~(param->postdiv1_mask)));
235 assert(!((divider2 << param->postdiv2_shift) &
236 ~(param->postdiv2_mask)));
Ionela Voinescub3f666b2015-01-18 22:37:11 +0000237
238 /* Temporary bypass PLL (select XTAL as clock input) */
Kyösti Mälkkia9506db2019-03-20 20:30:02 +0200239 reg = read32_x(PISTACHIO_CLOCK_SWITCH);
Ionela Voinescub3f666b2015-01-18 22:37:11 +0000240 reg &= ~(param->external_bypass_mask);
Kyösti Mälkkia9506db2019-03-20 20:30:02 +0200241 write32_x(PISTACHIO_CLOCK_SWITCH, reg);
Ionela Voinescub3f666b2015-01-18 22:37:11 +0000242
243 /* Un-bypass PLL's internal bypass */
Kyösti Mälkkia9506db2019-03-20 20:30:02 +0200244 reg = read32_x(param->ctrl_addr);
Ionela Voinescub3f666b2015-01-18 22:37:11 +0000245 reg &= ~(param->internal_bypass_mask);
Kyösti Mälkkia9506db2019-03-20 20:30:02 +0200246 write32_x(param->ctrl_addr, reg);
Ionela Voinescub3f666b2015-01-18 22:37:11 +0000247
248 /* Disable power down */
Kyösti Mälkkia9506db2019-03-20 20:30:02 +0200249 reg = read32_x(param->power_down_ctrl_addr);
Ionela Voinescub3f666b2015-01-18 22:37:11 +0000250 reg &= ~(param->power_down_ctrl_mask);
Kyösti Mälkkia9506db2019-03-20 20:30:02 +0200251 write32_x(param->power_down_ctrl_addr, reg);
Ionela Voinescub3f666b2015-01-18 22:37:11 +0000252
Ionela Voinescu11364472015-07-15 12:42:01 +0100253 /* Noise cancellation */
254 if (param->dacpd_addr) {
Kyösti Mälkkia9506db2019-03-20 20:30:02 +0200255 reg = read32_x(param->dacpd_addr);
Ionela Voinescu11364472015-07-15 12:42:01 +0100256 reg &= ~(param->dacpd_mask);
Kyösti Mälkkia9506db2019-03-20 20:30:02 +0200257 write32_x(param->dacpd_addr, reg);
Ionela Voinescu11364472015-07-15 12:42:01 +0100258 }
259
260 /* Functional mode */
261 if (param->dsmpd_addr) {
Kyösti Mälkkia9506db2019-03-20 20:30:02 +0200262 reg = read32_x(param->dsmpd_addr);
Ionela Voinescu11364472015-07-15 12:42:01 +0100263 reg &= ~(param->dsmpd_mask);
Kyösti Mälkkia9506db2019-03-20 20:30:02 +0200264 write32_x(param->dsmpd_addr, reg);
Ionela Voinescu11364472015-07-15 12:42:01 +0100265 }
266
Ionela Voinescub3f666b2015-01-18 22:37:11 +0000267 if (param->feedback_addr) {
Ionela Voinescu41d1ca82015-01-26 17:15:59 +0000268 assert(!((param->feedback << param->feedback_shift) &
269 ~(param->feedback_mask)));
Kyösti Mälkkia9506db2019-03-20 20:30:02 +0200270 reg = read32_x(param->feedback_addr);
Ionela Voinescub3f666b2015-01-18 22:37:11 +0000271 reg &= ~(param->feedback_mask);
272 reg |= (param->feedback << param->feedback_shift) &
273 param->feedback_mask;
Kyösti Mälkkia9506db2019-03-20 20:30:02 +0200274 write32_x(param->feedback_addr, reg);
Ionela Voinescub3f666b2015-01-18 22:37:11 +0000275 }
276
277 if (param->refdiv_addr) {
Ionela Voinescu41d1ca82015-01-26 17:15:59 +0000278 assert(!((param->refdivider << param->refdiv_shift) &
279 ~(param->refdiv_mask)));
Kyösti Mälkkia9506db2019-03-20 20:30:02 +0200280 reg = read32_x(param->refdiv_addr);
Ionela Voinescub3f666b2015-01-18 22:37:11 +0000281 reg &= ~(param->refdiv_mask);
282 reg |= (param->refdivider << param->refdiv_shift) &
283 param->refdiv_mask;
Kyösti Mälkkia9506db2019-03-20 20:30:02 +0200284 write32_x(param->refdiv_addr, reg);
Ionela Voinescub3f666b2015-01-18 22:37:11 +0000285 }
286
287 /* Read postdivider register value */
Kyösti Mälkkia9506db2019-03-20 20:30:02 +0200288 reg = read32_x(param->postdiv_addr);
Ionela Voinescub3f666b2015-01-18 22:37:11 +0000289 /* Set divider 1 */
290 reg &= ~(param->postdiv1_mask);
291 reg |= (divider1 << param->postdiv1_shift) &
292 param->postdiv1_mask;
293 /* Set divider 2 */
294 reg &= ~(param->postdiv2_mask);
295 reg |= (divider2 << param->postdiv2_shift) &
296 param->postdiv2_mask;
297 /* Write back to register */
Kyösti Mälkkia9506db2019-03-20 20:30:02 +0200298 write32_x(param->postdiv_addr, reg);
Ionela Voinescub3f666b2015-01-18 22:37:11 +0000299
300 /* Waiting for PLL to lock*/
301 stopwatch_init_usecs_expire(&sw, PLL_TIMEOUT_VALUE_US);
Kyösti Mälkkia9506db2019-03-20 20:30:02 +0200302 while (!(read32_x(param->status_addr) & param->status_lock_mask)) {
Ionela Voinescub3f666b2015-01-18 22:37:11 +0000303 if (stopwatch_expired(&sw))
304 return PLL_TIMEOUT;
305 }
306
307 /* Start using PLL */
Kyösti Mälkkia9506db2019-03-20 20:30:02 +0200308 reg = read32_x(PISTACHIO_CLOCK_SWITCH);
Ionela Voinescub3f666b2015-01-18 22:37:11 +0000309 reg |= param->external_bypass_mask;
Kyösti Mälkkia9506db2019-03-20 20:30:02 +0200310 write32_x(PISTACHIO_CLOCK_SWITCH, reg);
Ionela Voinescub3f666b2015-01-18 22:37:11 +0000311
312 return CLOCKS_OK;
313}
314
Ionela Voinescu90d12352015-07-15 12:10:05 +0100315int sys_pll_setup(u8 divider1, u8 divider2, u8 refdivider, u32 feedback)
Ionela Voinescub3f666b2015-01-18 22:37:11 +0000316{
Ionela Voinescu90d12352015-07-15 12:10:05 +0100317 pll_params[SYS_PLL].refdivider = refdivider;
318 pll_params[SYS_PLL].feedback = feedback;
Ionela Voinescub3f666b2015-01-18 22:37:11 +0000319 return pll_setup(&(pll_params[SYS_PLL]), divider1, divider2);
320}
321
322int mips_pll_setup(u8 divider1, u8 divider2, u8 refdivider, u32 feedback)
323{
324 pll_params[MIPS_PLL].refdivider = refdivider;
325 pll_params[MIPS_PLL].feedback = feedback;
326 return pll_setup(&(pll_params[MIPS_PLL]), divider1, divider2);
327}
328
329/*
330 * uart1_clk_setup: sets up clocks for UART1
331 * divider1: 3-bit divider value
332 * divider2: 10-bit divider value
333 */
334void uart1_clk_setup(u8 divider1, u16 divider2)
335{
336 u32 reg;
337
338 /* Check input parameters */
339 assert(!(divider1 & ~(UART1CLKINTERNAL_MASK)));
340 assert(!(divider2 & ~(UART1CLKOUT_MASK)));
341
342 /* Set divider 1 */
Kyösti Mälkkia9506db2019-03-20 20:30:02 +0200343 reg = read32_x(UART1CLKINTERNAL_CTRL_ADDR);
Ionela Voinescub3f666b2015-01-18 22:37:11 +0000344 reg &= ~UART1CLKINTERNAL_MASK;
345 reg |= divider1 & UART1CLKINTERNAL_MASK;
Kyösti Mälkkia9506db2019-03-20 20:30:02 +0200346 write32_x(UART1CLKINTERNAL_CTRL_ADDR, reg);
Ionela Voinescub3f666b2015-01-18 22:37:11 +0000347
348 /* Set divider 2 */
Kyösti Mälkkia9506db2019-03-20 20:30:02 +0200349 reg = read32_x(UART1CLKOUT_CTRL_ADDR);
Ionela Voinescub3f666b2015-01-18 22:37:11 +0000350 reg &= ~UART1CLKOUT_MASK;
351 reg |= divider2 & UART1CLKOUT_MASK;
Kyösti Mälkkia9506db2019-03-20 20:30:02 +0200352 write32_x(UART1CLKOUT_CTRL_ADDR, reg);
Ionela Voinescub3f666b2015-01-18 22:37:11 +0000353}
354
Ionela Voinescufdce6802015-02-17 18:28:34 +0000355/*
Ionela Voinescu38063b02015-03-05 13:09:57 +0000356 * i2c_clk_setup: sets up clocks for I2C
Ionela Voinescufdce6802015-02-17 18:28:34 +0000357 * divider1: 7-bit divider value
358 * divider2: 7-bit divider value
359 */
Ionela Voinescu38063b02015-03-05 13:09:57 +0000360void i2c_clk_setup(u8 divider1, u16 divider2, u8 interface)
Ionela Voinescufdce6802015-02-17 18:28:34 +0000361{
362 u32 reg;
363
364 /* Check input parameters */
Ionela Voinescu38063b02015-03-05 13:09:57 +0000365 assert(!(divider1 & ~(I2CCLKDIV1_MASK)));
366 assert(!(divider2 & ~(I2CCLKOUT_MASK)));
367 assert(interface < 4);
Ionela Voinescufdce6802015-02-17 18:28:34 +0000368 /* Set divider 1 */
Kyösti Mälkkia9506db2019-03-20 20:30:02 +0200369 reg = read32_x(I2CCLKDIV1_CTRL_ADDR(interface));
Ionela Voinescu38063b02015-03-05 13:09:57 +0000370 reg &= ~I2CCLKDIV1_MASK;
371 reg |= divider1 & I2CCLKDIV1_MASK;
Kyösti Mälkkia9506db2019-03-20 20:30:02 +0200372 write32_x(I2CCLKDIV1_CTRL_ADDR(interface), reg);
Ionela Voinescufdce6802015-02-17 18:28:34 +0000373
374 /* Set divider 2 */
Kyösti Mälkkia9506db2019-03-20 20:30:02 +0200375 reg = read32_x(I2CCLKOUT_CTRL_ADDR(interface));
Ionela Voinescu38063b02015-03-05 13:09:57 +0000376 reg &= ~I2CCLKOUT_MASK;
377 reg |= divider2 & I2CCLKOUT_MASK;
Kyösti Mälkkia9506db2019-03-20 20:30:02 +0200378 write32_x(I2CCLKOUT_CTRL_ADDR(interface), reg);
Ionela Voinescufdce6802015-02-17 18:28:34 +0000379}
380
Ionela Voinescub3f666b2015-01-18 22:37:11 +0000381/* system_clk_setup: sets up the system (peripheral) clock */
382void system_clk_setup(u8 divider)
383{
384 u32 reg;
385
386 /* Check input parameters */
387 assert(!(divider & ~(SYSCLKINTERNAL_MASK)));
388
389 /* Set system clock divider */
Kyösti Mälkkia9506db2019-03-20 20:30:02 +0200390 reg = read32_x(SYSCLKINTERNAL_CTRL_ADDR);
Ionela Voinescub3f666b2015-01-18 22:37:11 +0000391 reg &= ~SYSCLKINTERNAL_MASK;
392 reg |= divider & SYSCLKINTERNAL_MASK;
Kyösti Mälkkia9506db2019-03-20 20:30:02 +0200393 write32_x(SYSCLKINTERNAL_CTRL_ADDR, reg);
Ionela Voinescub3f666b2015-01-18 22:37:11 +0000394
395 /* Small delay to cover a maximum lock time of 1500 cycles */
396 udelay(SYS_CLK_LOCK_DELAY);
397}
398
Ionela Voinescu8b1f23e2015-01-26 13:15:12 +0000399void mips_clk_setup(u8 divider1, u8 divider2)
400{
401 u32 reg;
402
403 /* Check input parameters */
404 assert(!(divider1 & ~(MIPSCLKINTERNAL_MASK)));
405 assert(!(divider2 & ~(MIPSCLKOUT_MASK)));
406
407 /* Set divider 1 */
Kyösti Mälkkia9506db2019-03-20 20:30:02 +0200408 reg = read32_x(MIPSCLKINTERNAL_CTRL_ADDR);
Ionela Voinescu8b1f23e2015-01-26 13:15:12 +0000409 reg &= ~MIPSCLKINTERNAL_MASK;
410 reg |= divider1 & MIPSCLKINTERNAL_MASK;
Kyösti Mälkkia9506db2019-03-20 20:30:02 +0200411 write32_x(MIPSCLKINTERNAL_CTRL_ADDR, reg);
Ionela Voinescu8b1f23e2015-01-26 13:15:12 +0000412
413 /* Set divider 2 */
Kyösti Mälkkia9506db2019-03-20 20:30:02 +0200414 reg = read32_x(MIPSCLKOUT_CTRL_ADDR);
Ionela Voinescu8b1f23e2015-01-26 13:15:12 +0000415 reg &= ~MIPSCLKOUT_MASK;
416 reg |= divider2 & MIPSCLKOUT_MASK;
Kyösti Mälkkia9506db2019-03-20 20:30:02 +0200417 write32_x(MIPSCLKOUT_CTRL_ADDR, reg);
Ionela Voinescu8b1f23e2015-01-26 13:15:12 +0000418}
419
Ionela Voinescub3f666b2015-01-18 22:37:11 +0000420/* usb_clk_setup: sets up USB clock */
421int usb_clk_setup(u8 divider, u8 refclksel, u8 fsel)
422{
423 u32 reg;
424 struct stopwatch sw;
425
426 /* Check input parameters */
427 assert(!(divider & ~(USBPHYCLKOUT_MASK)));
Ionela Voinescu41d1ca82015-01-26 17:15:59 +0000428 assert(!((refclksel << USBPHYSTRAPCTRL_REFCLKSEL_SHIFT) &
429 ~(USBPHYSTRAPCTRL_REFCLKSEL_MASK)));
430 assert(!((fsel << USBPHYCONTROL1_FSEL_SHIFT) &
431 ~(USBPHYCONTROL1_FSEL_MASK)));
Ionela Voinescub3f666b2015-01-18 22:37:11 +0000432
433 /* Set USB divider */
Kyösti Mälkkia9506db2019-03-20 20:30:02 +0200434 reg = read32_x(USBPHYCLKOUT_CTRL_ADDR);
Ionela Voinescub3f666b2015-01-18 22:37:11 +0000435 reg &= ~USBPHYCLKOUT_MASK;
436 reg |= divider & USBPHYCLKOUT_MASK;
Kyösti Mälkkia9506db2019-03-20 20:30:02 +0200437 write32_x(USBPHYCLKOUT_CTRL_ADDR, reg);
Ionela Voinescub3f666b2015-01-18 22:37:11 +0000438
439 /* Set REFCLKSEL */
Kyösti Mälkkia9506db2019-03-20 20:30:02 +0200440 reg = read32_x(USBPHYSTRAPCTRL_ADDR);
Ionela Voinescub3f666b2015-01-18 22:37:11 +0000441 reg &= ~USBPHYSTRAPCTRL_REFCLKSEL_MASK;
442 reg |= (refclksel << USBPHYSTRAPCTRL_REFCLKSEL_SHIFT) &
443 USBPHYSTRAPCTRL_REFCLKSEL_MASK;
Kyösti Mälkkia9506db2019-03-20 20:30:02 +0200444 write32_x(USBPHYSTRAPCTRL_ADDR, reg);
Ionela Voinescub3f666b2015-01-18 22:37:11 +0000445
446 /* Set FSEL */
Kyösti Mälkkia9506db2019-03-20 20:30:02 +0200447 reg = read32_x(USBPHYCONTROL1_ADDR);
Ionela Voinescub3f666b2015-01-18 22:37:11 +0000448 reg &= ~USBPHYCONTROL1_FSEL_MASK;
449 reg |= (fsel << USBPHYCONTROL1_FSEL_SHIFT) &
450 USBPHYCONTROL1_FSEL_MASK;
Kyösti Mälkkia9506db2019-03-20 20:30:02 +0200451 write32_x(USBPHYCONTROL1_ADDR, reg);
Ionela Voinescub3f666b2015-01-18 22:37:11 +0000452
453 /* Waiting for USB clock status */
454 stopwatch_init_usecs_expire(&sw, USB_TIMEOUT_VALUE_US);
455 while (1) {
Kyösti Mälkkia9506db2019-03-20 20:30:02 +0200456 reg = read32_x(USBPHYSTATUS_ADDR);
Ionela Voinescub3f666b2015-01-18 22:37:11 +0000457 if (reg & USBPHYSTATUS_VBUS_FAULT_MASK)
458 return USB_VBUS_FAULT;
459 if (stopwatch_expired(&sw))
460 return USB_TIMEOUT;
Ionela Voinescu41d1ca82015-01-26 17:15:59 +0000461 /* Check if USB is set up properly */
462 if ((reg & USBPHYSTATUS_RX_PHY_CLK_MASK) &&
463 (reg & USBPHYSTATUS_RX_UTMI_CLK_MASK))
464 break;
Ionela Voinescub3f666b2015-01-18 22:37:11 +0000465 }
466
467 return CLOCKS_OK;
468}
Ionela Voinescu8b1f23e2015-01-26 13:15:12 +0000469
470void rom_clk_setup(u8 divider)
471{
472 u32 reg;
473
474 /* Check input parameter */
475 assert(!(divider & ~(ROMCLKOUT_MASK)));
476
477 /* Set ROM divider */
Kyösti Mälkkia9506db2019-03-20 20:30:02 +0200478 reg = read32_x(ROMCLKOUT_CTRL_ADDR);
Ionela Voinescu8b1f23e2015-01-26 13:15:12 +0000479 reg &= ~ROMCLKOUT_MASK;
480 reg |= divider & ROMCLKOUT_MASK;
Kyösti Mälkkia9506db2019-03-20 20:30:02 +0200481 write32_x(ROMCLKOUT_CTRL_ADDR, reg);
Ionela Voinescu8b1f23e2015-01-26 13:15:12 +0000482}
483
484void eth_clk_setup(u8 mux, u8 divider)
485{
486
487 u32 reg;
488
489 /* Check input parameters */
490 assert(!(divider & ~(ENETCLKDIV_MASK)));
491 /* This can be either 0 or 1, selecting between
492 * ENET and system clock as clocksource */
493 assert(!(mux & ~(0x1)));
494
495 /* Set ETH divider */
Kyösti Mälkkia9506db2019-03-20 20:30:02 +0200496 reg = read32_x(ENETCLKDIV_CTRL_ADDR);
Ionela Voinescu8b1f23e2015-01-26 13:15:12 +0000497 reg &= ~ENETCLKDIV_MASK;
498 reg |= divider & ENETCLKDIV_MASK;
Kyösti Mälkkia9506db2019-03-20 20:30:02 +0200499 write32_x(ENETCLKDIV_CTRL_ADDR, reg);
Ionela Voinescu8b1f23e2015-01-26 13:15:12 +0000500
501 /* Select source */
502 if (mux) {
Kyösti Mälkkia9506db2019-03-20 20:30:02 +0200503 reg = read32_x(PISTACHIO_CLOCK_SWITCH);
Ionela Voinescu8b1f23e2015-01-26 13:15:12 +0000504 reg |= ENETCLKMUX_MASK;
Kyösti Mälkkia9506db2019-03-20 20:30:02 +0200505 write32_x(PISTACHIO_CLOCK_SWITCH, reg);
Ionela Voinescu8b1f23e2015-01-26 13:15:12 +0000506 }
507}
Ionela Voinescu4f3d4002015-11-01 19:55:48 +0000508
509void setup_clk_gate_defaults(void)
510{
Kyösti Mälkkia9506db2019-03-20 20:30:02 +0200511 write32_x(MIPS_CLOCK_GATE_ADDR, MIPS_CLOCK_GATE_ALL_ON);
512 write32_x(RPU_CLOCK_GATE_ADDR, RPU_CLOCK_GATE_ALL_OFF);
Ionela Voinescu4f3d4002015-11-01 19:55:48 +0000513}