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
20static 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
87__weak void matrix_init(void)
88{
89	/* This only be used for sama5d4 soc now */
90}
91
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 */
98void s_init(void)
99{
100}
101
102void 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(CFG_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