1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Copyright (C) 2013 Atmel Corporation
4  *		      Bo Shen <voice.shen@atmel.com>
5  */
6 
7 #include <common.h>
8 #include <hang.h>
9 #include <init.h>
10 #include <log.h>
11 #include <asm/io.h>
12 #include <asm/arch/at91_common.h>
13 #include <asm/arch/at91_pit.h>
14 #include <asm/arch/at91_pmc.h>
15 #include <asm/arch/at91_rstc.h>
16 #include <asm/arch/at91_wdt.h>
17 #include <asm/arch/clk.h>
18 #include <spl.h>
19 
switch_to_main_crystal_osc(void)20 static void switch_to_main_crystal_osc(void)
21 {
22 	struct at91_pmc *pmc = (struct at91_pmc *)ATMEL_BASE_PMC;
23 	u32 tmp;
24 
25 	tmp = readl(&pmc->mor);
26 	tmp &= ~AT91_PMC_MOR_OSCOUNT(0xff);
27 	tmp &= ~AT91_PMC_MOR_KEY(0xff);
28 	tmp |= AT91_PMC_MOR_MOSCEN;
29 	tmp |= AT91_PMC_MOR_OSCOUNT(8);
30 	tmp |= AT91_PMC_MOR_KEY(0x37);
31 	writel(tmp, &pmc->mor);
32 	while (!(readl(&pmc->sr) & AT91_PMC_IXR_MOSCS))
33 		;
34 
35 #if defined(CONFIG_SAMA5D2)
36 	/* Enable a measurement of the external oscillator */
37 	tmp = readl(&pmc->mcfr);
38 	tmp |= AT91_PMC_MCFR_CCSS_XTAL_OSC;
39 	tmp |= AT91_PMC_MCFR_RCMEAS;
40 	writel(tmp, &pmc->mcfr);
41 
42 	while (!(readl(&pmc->mcfr) & AT91_PMC_MCFR_MAINRDY))
43 		;
44 
45 	if (!(readl(&pmc->mcfr) & AT91_PMC_MCFR_MAINF_MASK))
46 		hang();
47 #endif
48 
49 	tmp = readl(&pmc->mor);
50 /*
51  * some boards have an external oscillator with driving.
52  * in this case we need to disable the internal SoC driving (bypass mode)
53  */
54 #if defined(CONFIG_SPL_AT91_MCK_BYPASS)
55 	tmp |= AT91_PMC_MOR_OSCBYPASS;
56 #else
57 	tmp &= ~AT91_PMC_MOR_OSCBYPASS;
58 #endif
59 	tmp &= ~AT91_PMC_MOR_KEY(0xff);
60 	tmp |= AT91_PMC_MOR_KEY(0x37);
61 	writel(tmp, &pmc->mor);
62 
63 	tmp = readl(&pmc->mor);
64 	tmp |= AT91_PMC_MOR_MOSCSEL;
65 	tmp &= ~AT91_PMC_MOR_KEY(0xff);
66 	tmp |= AT91_PMC_MOR_KEY(0x37);
67 	writel(tmp, &pmc->mor);
68 
69 	while (!(readl(&pmc->sr) & AT91_PMC_IXR_MOSCSELS))
70 		;
71 
72 #if !defined(CONFIG_SAMA5D2)
73 	/* Wait until MAINRDY field is set to make sure main clock is stable */
74 	while (!(readl(&pmc->mcfr) & AT91_PMC_MAINRDY))
75 		;
76 #endif
77 
78 #if !defined(CONFIG_SAMA5D4) && !defined(CONFIG_SAMA5D2)
79 	tmp = readl(&pmc->mor);
80 	tmp &= ~AT91_PMC_MOR_MOSCRCEN;
81 	tmp &= ~AT91_PMC_MOR_KEY(0xff);
82 	tmp |= AT91_PMC_MOR_KEY(0x37);
83 	writel(tmp, &pmc->mor);
84 #endif
85 }
86 
matrix_init(void)87 __weak void matrix_init(void)
88 {
89 	/* This only be used for sama5d4 soc now */
90 }
91 
redirect_int_from_saic_to_aic(void)92 __weak void redirect_int_from_saic_to_aic(void)
93 {
94 	/* This only be used for sama5d4 soc now */
95 }
96 
97 /* empty stub to satisfy current lowlevel_init, can be removed any time */
s_init(void)98 void s_init(void)
99 {
100 }
101 
board_init_f(ulong dummy)102 void board_init_f(ulong dummy)
103 {
104 	int ret;
105 
106 	if (IS_ENABLED(CONFIG_OF_CONTROL)) {
107 		ret = spl_early_init();
108 		if (ret) {
109 			debug("spl_early_init() failed: %d\n", ret);
110 			hang();
111 		}
112 	}
113 	switch_to_main_crystal_osc();
114 
115 #ifdef CONFIG_SAMA5D2
116 	configure_2nd_sram_as_l2_cache();
117 #endif
118 
119 #if !defined(CONFIG_WDT_AT91)
120 	/* disable watchdog */
121 	at91_disable_wdt();
122 #endif
123 
124 	/* PMC configuration */
125 	at91_pmc_init();
126 
127 	at91_clock_init(CONFIG_SYS_AT91_MAIN_CLOCK);
128 
129 	matrix_init();
130 
131 	redirect_int_from_saic_to_aic();
132 
133 	timer_init();
134 
135 	board_early_init_f();
136 
137 	mem_init();
138 
139 	ret = spl_init();
140 	if (ret) {
141 		debug("spl_init() failed: %d\n", ret);
142 		hang();
143 	}
144 
145 	preloader_console_init();
146 
147 }
148