blob: a30c4f6c075f2ad1e13093b111b2463af047a7c0 [file] [log] [blame]
Tom Rini83d290c2018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
Heiko Schocher5abc00d2014-10-31 08:31:04 +01002/*
3 * Copyright (C) 2013 Atmel Corporation
4 * Bo Shen <voice.shen@atmel.com>
Heiko Schocher5abc00d2014-10-31 08:31:04 +01005 */
6
7#include <common.h>
Simon Glassdb41d652019-12-28 10:45:07 -07008#include <hang.h>
Simon Glass691d7192020-05-10 11:40:02 -06009#include <init.h>
Simon Glassf7ae49f2020-05-10 11:40:05 -060010#include <log.h>
Heiko Schocher5abc00d2014-10-31 08:31:04 +010011#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
Heiko Schocher5abc00d2014-10-31 08:31:04 +010020static 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
Wenyou Yang3ceb5112017-09-13 14:58:48 +080035#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
Heiko Schocher5abc00d2014-10-31 08:31:04 +010049 tmp = readl(&pmc->mor);
Eugen Hristev0be07872019-05-24 09:38:10 +030050/*
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
Heiko Schocher5abc00d2014-10-31 08:31:04 +010057 tmp &= ~AT91_PMC_MOR_OSCBYPASS;
Eugen Hristev0be07872019-05-24 09:38:10 +030058#endif
Heiko Schocher5abc00d2014-10-31 08:31:04 +010059 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
Wenyou Yang3ceb5112017-09-13 14:58:48 +080072#if !defined(CONFIG_SAMA5D2)
Heiko Schocher5abc00d2014-10-31 08:31:04 +010073 /* Wait until MAINRDY field is set to make sure main clock is stable */
74 while (!(readl(&pmc->mcfr) & AT91_PMC_MAINRDY))
75 ;
Wenyou Yang3ceb5112017-09-13 14:58:48 +080076#endif
Heiko Schocher5abc00d2014-10-31 08:31:04 +010077
Wenyou Yang3ceb5112017-09-13 14:58:48 +080078#if !defined(CONFIG_SAMA5D4) && !defined(CONFIG_SAMA5D2)
Heiko Schocher5abc00d2014-10-31 08:31:04 +010079 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);
Bo Shen0246b7c2014-12-15 13:24:32 +080084#endif
Heiko Schocher5abc00d2014-10-31 08:31:04 +010085}
86
Bo Shen433be902014-12-15 13:24:30 +080087__weak void matrix_init(void)
88{
89 /* This only be used for sama5d4 soc now */
90}
91
Bo Shen4514b5f2014-12-15 13:24:31 +080092__weak void redirect_int_from_saic_to_aic(void)
93{
94 /* This only be used for sama5d4 soc now */
95}
96
Tom Rinie755d542015-02-10 19:07:22 -050097/* empty stub to satisfy current lowlevel_init, can be removed any time */
Heiko Schocher5abc00d2014-10-31 08:31:04 +010098void s_init(void)
99{
Tom Rinie755d542015-02-10 19:07:22 -0500100}
101
102void board_init_f(ulong dummy)
103{
Wenyou Yang730a7b42017-03-24 11:34:04 +0800104 int ret;
105
Greg Gallagher786f35b2021-01-21 11:55:36 -0500106 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 }
Heiko Schocher5abc00d2014-10-31 08:31:04 +0100113 switch_to_main_crystal_osc();
114
Samuel Mescofff7cf2912016-02-16 09:45:06 +0100115#ifdef CONFIG_SAMA5D2
116 configure_2nd_sram_as_l2_cache();
117#endif
118
Prasanthi Chellakumar1473f6a2018-10-09 11:46:40 -0700119#if !defined(CONFIG_WDT_AT91)
Heiko Schocher5abc00d2014-10-31 08:31:04 +0100120 /* disable watchdog */
121 at91_disable_wdt();
Tom Rinif58e9462018-05-10 07:15:52 -0400122#endif
Heiko Schocher5abc00d2014-10-31 08:31:04 +0100123
124 /* PMC configuration */
125 at91_pmc_init();
126
Tom Rini65cc0e22022-11-16 13:10:41 -0500127 at91_clock_init(CFG_SYS_AT91_MAIN_CLOCK);
Heiko Schocher5abc00d2014-10-31 08:31:04 +0100128
Bo Shen433be902014-12-15 13:24:30 +0800129 matrix_init();
130
Bo Shen4514b5f2014-12-15 13:24:31 +0800131 redirect_int_from_saic_to_aic();
132
Heiko Schocher5abc00d2014-10-31 08:31:04 +0100133 timer_init();
134
135 board_early_init_f();
136
Wenyou Yang5bede732017-03-24 11:34:05 +0800137 mem_init();
138
Wenyou Yang730a7b42017-03-24 11:34:04 +0800139 ret = spl_init();
140 if (ret) {
141 debug("spl_init() failed: %d\n", ret);
142 hang();
143 }
144
Heiko Schocher5abc00d2014-10-31 08:31:04 +0100145 preloader_console_init();
146
Heiko Schocher5abc00d2014-10-31 08:31:04 +0100147}