1/*
2 * BCM43XX Sonics SiliconBackplane ARM core routines
3 *
4 * Copyright (C) 2015, Broadcom Corporation. All Rights Reserved.
5 *
6 * Permission to use, copy, modify, and/or distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
13 * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
15 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
16 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 *
18 * $Id: hndarm.c 328955 2012-04-23 09:06:12Z $
19 */
20
21#include <typedefs.h>
22#include <bcmutils.h>
23#include <siutils.h>
24#include <hndsoc.h>
25#include <sbchipc.h>
26#include <bcmdevs.h>
27#include <hndpmu.h>
28#include <chipcommonb.h>
29#include <armca9_core.h>
30#include <ddr_core.h>
31
32#define PLL_SUP_4708	0x00000001
33#define PLL_SUP_4709	0x00000002
34#define PLL_SUP_47092	0x00000004
35#define PLL_SUP_47094	0x00000008
36#define PLL_SUP_NS_ALL	(PLL_SUP_4708 | PLL_SUP_4709 | PLL_SUP_47092 | PLL_SUP_47094)
37#define PLL_SUP_DDR2	0x00000001
38#define PLL_SUP_DDR3	0x00000002
39
40struct arm_pll {
41	uint32 clk;
42	uint32 reg_val;
43	uint32 flag;
44};
45
46struct ddr_clk {
47	uint32 clk;
48	uint32 pll_ctrl_1;
49	uint32 pll_ctrl_2;
50	uint32 type_flag;
51	uint32 flag;
52};
53
54static struct arm_pll arm_pll_table[] = {
55	{ 600,	0x1003001, PLL_SUP_NS_ALL},
56	{ 800,	0x1004001, PLL_SUP_NS_ALL},
57	{ 1000, 0x1005001, PLL_SUP_4709 | PLL_SUP_47092 | PLL_SUP_47094},
58	{ 1200, 0x1006001, PLL_SUP_47094},
59	{ 1400, 0x1007001, PLL_SUP_47094},
60	{0}
61};
62
63static struct ddr_clk ddr_clock_pll_table[] = {
64	{ 333, 0x17800000, 0x1e0f1219, PLL_SUP_DDR2 | PLL_SUP_DDR3, PLL_SUP_NS_ALL},
65	{ 389, 0x18c00000, 0x23121219, PLL_SUP_DDR2 | PLL_SUP_DDR3, PLL_SUP_NS_ALL},
66	{ 400, 0x18000000, 0x20101019, PLL_SUP_DDR2 | PLL_SUP_DDR3, PLL_SUP_NS_ALL},
67	{ 533, 0x18000000, 0x20100c19, PLL_SUP_DDR3, PLL_SUP_NS_ALL},
68	{ 666, 0x17800000, 0x1e0f0919, PLL_SUP_DDR3, PLL_SUP_4709 | PLL_SUP_47094},
69	{ 775, 0x17c00000, 0x20100819, PLL_SUP_DDR3, PLL_SUP_4709 | PLL_SUP_47094},
70	{ 800, 0x18000000, 0x20100819, PLL_SUP_DDR3, PLL_SUP_4709 | PLL_SUP_47094},
71	{0}
72};
73
74uint
75BCMINITFN(si_irq)(si_t *sih)
76{
77	return 0;
78}
79
80/*
81 * Initializes clocks and interrupts. SB and NVRAM access must be
82 * initialized prior to calling.
83 */
84void
85BCMATTACHFN(si_arm_init)(si_t *sih)
86{
87	return;
88}
89
90uint32
91BCMINITFN(si_cpu_clock)(si_t *sih)
92{
93	uint32 val;
94	osl_t *osh;
95	osh = si_osh(sih);
96
97	if (BCM4707_CHIP(CHIPID(sih->chip))) {
98		/* Return 100 MHz if we are in default value policy 2 */
99		val = (uint32)R_REG(osh, (uint32 *)IHOST_PROC_CLK_POLICY_FREQ);
100		if ((val & 0x7070707) == 0x2020202)
101			return 100000000;
102
103		val = (uint32)R_REG(osh, (uint32 *)IHOST_PROC_CLK_PLLARMA);
104		val = (val >> 8) & 0x2ff;
105		val = (val * 25 * 1000000) / 2;
106
107		return val;
108	}
109
110	return si_clock(sih);
111}
112
113uint32
114BCMINITFN(si_mem_clock)(si_t *sih)
115{
116	osl_t *osh;
117	uint idx;
118	chipcommonbregs_t *chipcb;
119	uint32 control1, control2, val;
120
121	osh = si_osh(sih);
122
123	if (BCM4707_CHIP(CHIPID(sih->chip))) {
124		chipcb = si_setcore(sih, NS_CCB_CORE_ID, 0);
125		if (chipcb) {
126			control1 = R_REG(osh, &chipcb->cru_lcpll_control1);
127			control2 = R_REG(osh, &chipcb->cru_lcpll_control2);
128			for (idx = 0; ddr_clock_pll_table[idx].clk != 0; idx++) {
129				if ((control1 == ddr_clock_pll_table[idx].pll_ctrl_1) &&
130				    (control2 == ddr_clock_pll_table[idx].pll_ctrl_2)) {
131					val = ddr_clock_pll_table[idx].clk;
132					return (val * 1000000);
133				}
134			}
135		}
136
137	}
138
139	return si_clock(sih);
140}
141
142bool
143BCMINITFN(si_arm_setclock)(si_t *sih, uint32 armclock, uint32 ddrclock, uint32 axiclock)
144{
145	osl_t *osh;
146	uint32 val;
147	bool ret = TRUE;
148	int idx;
149	int bootdev;
150	uint32 *ddrclk;
151	osh = si_osh(sih);
152
153	if (BCM4707_CHIP(CHIPID(sih->chip))) {
154		uint32 platform_flag = 0, ddr_flag = 0;
155		void *regs = (void *)si_setcore(sih, NS_DDR23_CORE_ID, 0);
156		if (regs) {
157			ddr_flag = ((si_core_sflags(sih, 0, 0) & DDR_TYPE_MASK)
158				== DDR_STAT_DDR3)? PLL_SUP_DDR3 : PLL_SUP_DDR2;
159		}
160
161		switch (sih->chippkg) {
162			case BCM4708_PKG_ID:
163				if (CHIPID(sih->chip) == BCM47094_CHIP_ID) {
164					platform_flag = PLL_SUP_47092;
165				} else {
166					platform_flag = PLL_SUP_4708;
167				}
168				break;
169			case BCM4709_PKG_ID:
170				if (CHIPID(sih->chip) == BCM47094_CHIP_ID) {
171					platform_flag = PLL_SUP_47094;
172				} else {
173					platform_flag = PLL_SUP_4709;
174				}
175				break;
176		}
177
178		/* Check CPU CLK table */
179		for (idx = 0; arm_pll_table[idx].clk != 0; idx++) {
180			if ((arm_pll_table[idx].flag & platform_flag) == 0)
181				arm_pll_table[idx].clk = 0;
182		}
183
184		/* Check DDR CLK table */
185		for (idx = 0; ddr_clock_pll_table[idx].clk != 0; idx++) {
186			if ((ddr_clock_pll_table[idx].type_flag & ddr_flag) == 0 ||
187			    (ddr_clock_pll_table[idx].flag & platform_flag) == 0) {
188				ddr_clock_pll_table[idx].clk = 0;
189				break;
190			}
191		}
192
193		/* Check DDR clock */
194		if (ddrclock && si_mem_clock(sih) != ddrclock) {
195			ddrclock /= 1000000;
196			for (idx = 0; ddr_clock_pll_table[idx].clk != 0; idx ++) {
197				if (ddrclock == ddr_clock_pll_table[idx].clk)
198					break;
199			}
200			if (ddr_clock_pll_table[idx].clk != 0) {
201				ddrclk = (uint32 *)(0x1000 + BISZ_OFFSET - 4);
202				*ddrclk = ddrclock;
203				bootdev = soc_boot_dev((void *)sih);
204				if (bootdev == SOC_BOOTDEV_NANDFLASH) {
205					__asm__ __volatile__("ldr\tpc,=0x1c000000\n\t");
206				} else if (bootdev == SOC_BOOTDEV_SFLASH) {
207					__asm__ __volatile__("ldr\tpc,=0x1e000000\n\t");
208				}
209			}
210		}
211
212		/* Set CPU clock */
213		armclock /= 1000000;
214
215		/* The password */
216		W_REG(osh, (uint32 *)IHOST_PROC_CLK_WR_ACCESS, 0xa5a501);
217
218		/* ndiv_int */
219		for (idx = 0; arm_pll_table[idx].clk != 0; idx++) {
220			if (armclock <= arm_pll_table[idx].clk)
221				break;
222		}
223		if (arm_pll_table[idx].clk == 0) {
224			ret = FALSE;
225			goto done;
226		}
227		val = arm_pll_table[idx].reg_val;
228		W_REG(osh, (uint32 *)IHOST_PROC_CLK_PLLARMA, val);
229
230		do {
231			val = (uint32)R_REG(osh, (uint32 *)IHOST_PROC_CLK_PLLARMA);
232			if (val & (1 << IHOST_PROC_CLK_PLLARMA__PLLARM_LOCK))
233				break;
234		} while (1);
235
236
237		val |= (1 << IHOST_PROC_CLK_PLLARMA__PLLARM_SOFT_POST_RESETB);
238		W_REG(osh, (uint32 *)IHOST_PROC_CLK_PLLARMA, val);
239
240		W_REG(osh, (uint32 *)IHOST_PROC_CLK_POLICY_FREQ, 0x87070707);
241		W_REG(osh, (uint32 *)IHOST_PROC_CLK_CORE0_CLKGATE, 0x00010303);
242		W_REG(osh, (uint32 *)IHOST_PROC_CLK_CORE1_CLKGATE, 0x00000303);
243		W_REG(osh, (uint32 *)IHOST_PROC_CLK_ARM_SWITCH_CLKGATE, 0x00010303);
244		W_REG(osh, (uint32 *)IHOST_PROC_CLK_ARM_PERIPH_CLKGATE, 0x00010303);
245		W_REG(osh, (uint32 *)IHOST_PROC_CLK_APB0_CLKGATE, 0x00010303);
246
247		val = (1 << IHOST_PROC_CLK_POLICY_CTL__GO) |
248		      (1 << IHOST_PROC_CLK_POLICY_CTL__GO_AC);
249		W_REG(osh, (uint32 *)IHOST_PROC_CLK_POLICY_CTL, val);
250
251		do {
252			val = R_REG(osh, (uint32 *)IHOST_PROC_CLK_POLICY_CTL);
253			if ((val & (1 << IHOST_PROC_CLK_POLICY_CTL__GO)) == 0)
254				break;
255		} while (1);
256	}
257done:
258	return (ret);
259}
260
261void si_mem_setclock(si_t *sih, uint32 ddrclock)
262{
263	osl_t *osh;
264	chipcommonbregs_t *chipcb;
265	uint32 val;
266	int idx;
267
268	for (idx = 0; ddr_clock_pll_table[idx].clk != 0; idx++) {
269		if (ddr_clock_pll_table[idx].clk == ddrclock)
270			break;
271	}
272	if (ddr_clock_pll_table[idx].clk == 0)
273		return;
274
275	osh = si_osh(sih);
276	chipcb = (chipcommonbregs_t *)si_setcore(sih, NS_CCB_CORE_ID, 0);
277	if (chipcb) {
278		val = 0xea68;
279		W_REG(osh, &chipcb->cru_clkset_key, val);
280		val = R_REG(osh, &chipcb->cru_lcpll_control1);
281		val &= ~0x0ff00000;
282		val |= (ddr_clock_pll_table[idx].pll_ctrl_1 & 0x0ff00000);
283		W_REG(osh, &chipcb->cru_lcpll_control1, val);
284
285		val = R_REG(osh, &chipcb->cru_lcpll_control2);
286		val &= ~0xffffff00;
287		val |= (ddr_clock_pll_table[idx].pll_ctrl_2 & 0xffffff00);
288		W_REG(osh, &chipcb->cru_lcpll_control2, val);
289		/* Enable change */
290		val = R_REG(osh, &chipcb->cru_lcpll_control0);
291		val |= 0x7;
292		W_REG(osh, &chipcb->cru_lcpll_control0, val);
293		val &= ~0x7;
294		W_REG(osh, &chipcb->cru_lcpll_control0, val);
295		val = 0;
296		W_REG(osh, &chipcb->cru_clkset_key, val);
297	}
298}
299
300/* Start chipc watchdog timer and wait till reset */
301void
302hnd_cpu_reset(si_t *sih)
303{
304	si_watchdog(sih, 1);
305	while (1);
306}
307
308void
309hnd_cpu_jumpto(void *addr)
310{
311	void (*jumpto)(void) = addr;
312
313	(jumpto)();
314}
315