diff mbox

[U-Boot,v2,10/12] arm, spl, at91: add at91sam9260 and at91sam9g45 spl support

Message ID 1414656906-16632-11-git-send-email-hs@denx.de
State Superseded
Headers show

Commit Message

Heiko Schocher Oct. 30, 2014, 8:15 a.m. UTC
add support for using spl code on at91sam9260 and at91sam9g45
based boards.

Signed-off-by: Heiko Schocher <hs@denx.de>
---

Changes in v2: None

 arch/arm/cpu/arm926ejs/at91/at91sam9260_devices.c  |  22 +++
 arch/arm/cpu/arm926ejs/at91/clock.c                |  60 +++++++
 arch/arm/cpu/armv7/at91/clock.c                    |  27 +++
 arch/arm/cpu/at91-common/Makefile                  |   1 +
 arch/arm/cpu/at91-common/sdram.c                   |  77 +++++++++
 arch/arm/cpu/at91-common/spl.c                     | 185 +++++++++++++++------
 arch/arm/include/asm/arch-at91/at91_common.h       |   4 +
 arch/arm/include/asm/arch-at91/at91_pmc.h          |   5 +-
 arch/arm/include/asm/arch-at91/at91sam9260.h       |   1 +
 .../arm/include/asm/arch-at91/at91sam9260_matrix.h |   5 +
 arch/arm/include/asm/arch-at91/at91sam9_sdramc.h   |  22 ++-
 11 files changed, 359 insertions(+), 50 deletions(-)
 create mode 100644 arch/arm/cpu/at91-common/sdram.c

Comments

Bo Shen Oct. 30, 2014, 10:17 a.m. UTC | #1
Hi Heiko,

On 10/30/2014 04:15 PM, Heiko Schocher wrote:
> diff --git a/arch/arm/include/asm/arch-at91/at91_pmc.h b/arch/arm/include/asm/arch-at91/at91_pmc.h
> index 27331ff..5f64583 100644
> --- a/arch/arm/include/asm/arch-at91/at91_pmc.h
> +++ b/arch/arm/include/asm/arch-at91/at91_pmc.h
> @@ -95,7 +95,7 @@ typedef struct at91_pmc {
>   #define AT91_PMC_MCKR_CSS_MAIN		0x00000001
>   #define AT91_PMC_MCKR_CSS_PLLA		0x00000002
>   #define AT91_PMC_MCKR_CSS_PLLB		0x00000003
> -#define AT91_PMC_MCKR_CSS_MASK		0x00000003
> +#define AT91_PMC_MCKR_CSS_MASK		0x00000007

Where this come from, CSS only two bits.

>   #ifdef CONFIG_SAMA5D3
>   #define AT91_PMC_MCKR_PRES_1		0x00000000
> @@ -114,7 +114,7 @@ typedef struct at91_pmc {
>   #define AT91_PMC_MCKR_PRES_16		0x00000010
>   #define AT91_PMC_MCKR_PRES_32		0x00000014
>   #define AT91_PMC_MCKR_PRES_64		0x00000018
> -#define AT91_PMC_MCKR_PRES_MASK		0x0000001C
> +#define AT91_PMC_MCKR_PRES_MASK		0x0000003C

Ditto

>   #endif

Best Regards,
Bo Shen
Heiko Schocher Oct. 30, 2014, 11:41 a.m. UTC | #2
Hello Bo,

Am 30.10.2014 11:17, schrieb Bo Shen:
> Hi Heiko,
>
> On 10/30/2014 04:15 PM, Heiko Schocher wrote:
>> diff --git a/arch/arm/include/asm/arch-at91/at91_pmc.h b/arch/arm/include/asm/arch-at91/at91_pmc.h
>> index 27331ff..5f64583 100644
>> --- a/arch/arm/include/asm/arch-at91/at91_pmc.h
>> +++ b/arch/arm/include/asm/arch-at91/at91_pmc.h
>> @@ -95,7 +95,7 @@ typedef struct at91_pmc {
>> #define AT91_PMC_MCKR_CSS_MAIN 0x00000001
>> #define AT91_PMC_MCKR_CSS_PLLA 0x00000002
>> #define AT91_PMC_MCKR_CSS_PLLB 0x00000003
>> -#define AT91_PMC_MCKR_CSS_MASK 0x00000003
>> +#define AT91_PMC_MCKR_CSS_MASK 0x00000007
>
> Where this come from, CSS only two bits.

Good question ... looked again into the doc, it is only two bits.

>
>> #ifdef CONFIG_SAMA5D3
>> #define AT91_PMC_MCKR_PRES_1 0x00000000
>> @@ -114,7 +114,7 @@ typedef struct at91_pmc {
>> #define AT91_PMC_MCKR_PRES_16 0x00000010
>> #define AT91_PMC_MCKR_PRES_32 0x00000014
>> #define AT91_PMC_MCKR_PRES_64 0x00000018
>> -#define AT91_PMC_MCKR_PRES_MASK 0x0000001C
>> +#define AT91_PMC_MCKR_PRES_MASK 0x0000003C
>
> Ditto

Hmm... no idea, why I changed this ... good catch!

Is the rest of the patch (and the patchserie OK) ?

Then I can send a v3 ...

bye,
Heiko
Bo Shen Oct. 31, 2014, 1:50 a.m. UTC | #3
Hi Heiko,

On 10/30/2014 04:15 PM, Heiko Schocher wrote:
> diff --git a/arch/arm/cpu/at91-common/spl.c b/arch/arm/cpu/at91-common/spl.c
> index 674a470..5c9a3ad 100644
> --- a/arch/arm/cpu/at91-common/spl.c
> +++ b/arch/arm/cpu/at91-common/spl.c

I am thinking, whether it be better to keep this file as two copy? This 
will remove #ifdef, although a little code duplication.

If this solution acceptable, some suggestion as following:
   - for armv5 (arm926ejs, now at91 series), named it spl_at91.c,
   - for armv7 (cortex-a5, now, sama5d3), named it spl_atmel.c?
(As for arm9 series, we have at91 prefix for SoC name, and for armv7 
SoC, we don't have at91 prefix, and it now changed to Atmel Smart)

> @@ -8,11 +8,18 @@
>   #include <common.h>
>   #include <asm/io.h>
>   #include <asm/arch/at91_common.h>
> +#if !defined(CONFIG_SAMA5D3)
> +#include <asm/arch/at91sam9_matrix.h>
> +#endif
> +#include <asm/arch/at91_pit.h>
>   #include <asm/arch/at91_pmc.h>
> +#include <asm/arch/at91_rstc.h>
>   #include <asm/arch/at91_wdt.h>
>   #include <asm/arch/clk.h>
>   #include <spl.h>
>
> +DECLARE_GLOBAL_DATA_PTR;
> +
>   static void at91_disable_wdt(void)
>   {
>   	struct at91_wdt *wdt = (struct at91_wdt *)ATMEL_BASE_WDT;
> @@ -20,6 +27,33 @@ static void at91_disable_wdt(void)
>   	writel(AT91_WDT_MR_WDDIS, &wdt->mr);
>   }
>
> +u32 spl_boot_device(void)
> +{
> +#ifdef CONFIG_SYS_USE_MMC
> +	return BOOT_DEVICE_MMC1;
> +#elif CONFIG_SYS_USE_NANDFLASH
> +	return BOOT_DEVICE_NAND;
> +#elif CONFIG_SYS_USE_SERIALFLASH
> +	return BOOT_DEVICE_SPI;
> +#endif
> +	return BOOT_DEVICE_NONE;
> +}
> +
> +u32 spl_boot_mode(void)
> +{
> +	switch (spl_boot_device()) {
> +#ifdef CONFIG_SYS_USE_MMC
> +	case BOOT_DEVICE_MMC1:
> +		return MMCSD_MODE_FS;
> +		break;
> +#endif
> +	case BOOT_DEVICE_NONE:
> +	default:
> +		hang();
> +	}
> +}
> +
> +#if defined(CONFIG_SAMA5D3)
>   static void switch_to_main_crystal_osc(void)
>   {
>   	struct at91_pmc *pmc = (struct at91_pmc *)ATMEL_BASE_PMC;
> @@ -57,77 +91,134 @@ static void switch_to_main_crystal_osc(void)
>   	writel(tmp, &pmc->mor);
>   }
>
> -void at91_plla_init(u32 pllar)
> +void s_init(void)
>   {
> -	struct at91_pmc *pmc = (struct at91_pmc *)ATMEL_BASE_PMC;
> +	switch_to_main_crystal_osc();
>
> -	writel(pllar, &pmc->pllar);
> -	while (!(readl(&pmc->sr) & (AT91_PMC_LOCKA | AT91_PMC_MCKRDY)))
> -		;
> -}
> +	/* disable watchdog */
> +	at91_disable_wdt();
>
> -void at91_mck_init(u32 mckr)
> -{
> -	struct at91_pmc *pmc = (struct at91_pmc *)ATMEL_BASE_PMC;
> -	u32 tmp;
> +	/* PMC configuration */
> +	at91_pmc_init();
>
> -	tmp = readl(&pmc->mckr);
> -	tmp &= ~(AT91_PMC_MCKR_PRES_MASK |
> -		 AT91_PMC_MCKR_MDIV_MASK |
> -		 AT91_PMC_MCKR_PLLADIV_2);
> -	tmp |= mckr & (AT91_PMC_MCKR_PRES_MASK |
> -		       AT91_PMC_MCKR_MDIV_MASK |
> -		       AT91_PMC_MCKR_PLLADIV_2);
> -	writel(tmp, &pmc->mckr);
> +	at91_clock_init(CONFIG_SYS_AT91_MAIN_CLOCK);
>
> -	while (!(readl(&pmc->sr) & AT91_PMC_MCKRDY))
> -		;
> -}
> +	timer_init();
>
> +	board_early_init_f();
>
> -u32 spl_boot_device(void)
> +	preloader_console_init();
> +
> +	mem_init();
> +}
> +#else
> +static void enable_ext_reset(void)
>   {
> -#ifdef CONFIG_SYS_USE_MMC
> -	return BOOT_DEVICE_MMC1;
> -#elif CONFIG_SYS_USE_NANDFLASH
> -	return BOOT_DEVICE_NAND;
> -#elif CONFIG_SYS_USE_SERIALFLASH
> -	return BOOT_DEVICE_SPI;
> -#endif
> -	return BOOT_DEVICE_NONE;
> +	struct at91_rstc *rstc = (struct at91_rstc *)ATMEL_BASE_RSTC;
> +
> +	writel(AT91_RSTC_KEY | AT91_RSTC_MR_URSTEN, &rstc->mr);
>   }
>
> -u32 spl_boot_mode(void)
> +#if defined(CONFIG_ATMEL_MATRIX_INIT)
> +static void matrix_init(void)
>   {
> -	switch (spl_boot_device()) {
> -#ifdef CONFIG_SYS_USE_MMC
> -	case BOOT_DEVICE_MMC1:
> -		return MMCSD_MODE_FS;
> -		break;
> +	struct at91_matrix *mat = (struct at91_matrix *)ATMEL_BASE_MATRIX;
> +
> +	writel((readl(&mat->scfg[3]) & (~AT91_MATRIX_SLOT_CYCLE))
> +			| AT91_MATRIX_SLOT_CYCLE_(0x40),
> +			&mat->scfg[3]);
> +}
>   #endif
> -	case BOOT_DEVICE_NONE:
> -	default:
> -		hang();
> +
> +void lowlevel_clock_init(void)
> +{
> +	struct at91_pmc *pmc = (struct at91_pmc *)ATMEL_BASE_PMC;
> +
> +	if (!(readl(&pmc->sr) & AT91_PMC_MOSCS)) {
> +		/* Enable Main Oscillator */
> +		writel(AT91_PMC_MOSCS | (0x40 << 8), &pmc->mor);
> +
> +		/* Wait until Main Oscillator is stable */
> +		while (!(readl(&pmc->sr) & AT91_PMC_MOSCS))
> +			;
>   	}
> +
> +	/* After stabilization, switch to Main Oscillator */
> +	if ((readl(&pmc->mckr) & AT91_PMC_CSS) == AT91_PMC_CSS_SLOW) {
> +		unsigned long tmp;
> +
> +		tmp = readl(&pmc->mckr);
> +		tmp &= ~AT91_PMC_CSS;
> +		tmp |= AT91_PMC_CSS_MAIN;
> +		writel(tmp, &pmc->mckr);
> +		while (!(readl(&pmc->sr) & AT91_PMC_MCKRDY))
> +			;
> +
> +		tmp &= ~AT91_PMC_PRES;
> +		tmp |= AT91_PMC_PRES_1;
> +		writel(tmp, &pmc->mckr);
> +		while (!(readl(&pmc->sr) & AT91_PMC_MCKRDY))
> +			;
> +	}
> +
> +	return;
>   }
>
> -void s_init(void)
> +void __weak at91_spl_board_init(void)
>   {
> -	switch_to_main_crystal_osc();
> +}
>
> -	/* disable watchdog */
> +void spl_board_init(void)
> +{
> +	struct at91_pmc *pmc = (struct at91_pmc *)ATMEL_BASE_PMC;
> +
> +	lowlevel_clock_init();
>   	at91_disable_wdt();
>
> -	/* PMC configuration */
> -	at91_pmc_init();
> +	/*
> +	 * At this stage the main oscillator is supposed to be enabled
> +	 * PCK = MCK = MOSC
> +	 */
> +	writel(0x00, &pmc->pllicpr);
>
> -	at91_clock_init(CONFIG_SYS_AT91_MAIN_CLOCK);
> +	/* Configure PLLA = MOSC * (PLL_MULA + 1) / PLL_DIVA */
> +	at91_plla_init(CONFIG_SYS_AT91_PLLA);
>
> -	timer_init();
> +	/* PCK = PLLA = 2 * MCK */
> +	at91_mck_init(CONFIG_SYS_MCKR);
>
> -	board_early_init_f();
> +	/* Switch MCK on PLLA output */
> +	at91_mck_init(CONFIG_SYS_MCKR_CSS);
> +
> +#if defined(CONFIG_SYS_AT91_PLLB)
> +	/* Configure PLLB */
> +	at91_pllb_init(CONFIG_SYS_AT91_PLLB);
> +#endif
> +
> +	/* Enable External Reset */
> +	enable_ext_reset();
>
> +#if defined(CONFIG_ATMEL_MATRIX_INIT)
> +	/* Initialize matrix */
> +	matrix_init();
> +#endif

Can this also be weak function? And put matrix_init() code to SoC/board 
related file.

> +	gd->arch.mck_rate_hz = CONFIG_SYS_MASTER_CLOCK;
> +	/*
> +	 * init timer long enough for using in spl.
> +	 */
> +	timer_init();
> +
> +	/* enable clocks for all PIOs */
> +	at91_periph_clk_enable(ATMEL_ID_PIOA);
> +	at91_periph_clk_enable(ATMEL_ID_PIOB);
> +	at91_periph_clk_enable(ATMEL_ID_PIOC);
> +	/* init console */
> +	at91_seriald_hw_init();
>   	preloader_console_init();
>
>   	mem_init();
> +
> +	at91_spl_board_init();
>   }
> +#endif

Best Regards,
Bo Shen
Bo Shen Oct. 31, 2014, 1:55 a.m. UTC | #4
Hi Heiko,

On 10/30/2014 07:41 PM, Heiko Schocher wrote:
> Hello Bo,
>
> Am 30.10.2014 11:17, schrieb Bo Shen:
>> Hi Heiko,
>>
>> On 10/30/2014 04:15 PM, Heiko Schocher wrote:
>>> diff --git a/arch/arm/include/asm/arch-at91/at91_pmc.h
>>> b/arch/arm/include/asm/arch-at91/at91_pmc.h
>>> index 27331ff..5f64583 100644
>>> --- a/arch/arm/include/asm/arch-at91/at91_pmc.h
>>> +++ b/arch/arm/include/asm/arch-at91/at91_pmc.h
>>> @@ -95,7 +95,7 @@ typedef struct at91_pmc {
>>> #define AT91_PMC_MCKR_CSS_MAIN 0x00000001
>>> #define AT91_PMC_MCKR_CSS_PLLA 0x00000002
>>> #define AT91_PMC_MCKR_CSS_PLLB 0x00000003
>>> -#define AT91_PMC_MCKR_CSS_MASK 0x00000003
>>> +#define AT91_PMC_MCKR_CSS_MASK 0x00000007
>>
>> Where this come from, CSS only two bits.
>
> Good question ... looked again into the doc, it is only two bits.
>
>>
>>> #ifdef CONFIG_SAMA5D3
>>> #define AT91_PMC_MCKR_PRES_1 0x00000000
>>> @@ -114,7 +114,7 @@ typedef struct at91_pmc {
>>> #define AT91_PMC_MCKR_PRES_16 0x00000010
>>> #define AT91_PMC_MCKR_PRES_32 0x00000014
>>> #define AT91_PMC_MCKR_PRES_64 0x00000018
>>> -#define AT91_PMC_MCKR_PRES_MASK 0x0000001C
>>> +#define AT91_PMC_MCKR_PRES_MASK 0x0000003C
>>
>> Ditto
>
> Hmm... no idea, why I changed this ... good catch!
>
> Is the rest of the patch (and the patchserie OK) ?

Except one suggestion and nitpick sent just now, the rest patch seems good.
For this whole series:
Reviewed-by: Bo Shen <voice.shen@atmel.com>

> Then I can send a v3 ...
>
> bye,
> Heiko

Best Regards,
Bo Shen
Heiko Schocher Oct. 31, 2014, 6:03 a.m. UTC | #5
Hello Bo,

Am 31.10.2014 02:50, schrieb Bo Shen:
> Hi Heiko,
>
> On 10/30/2014 04:15 PM, Heiko Schocher wrote:
>> diff --git a/arch/arm/cpu/at91-common/spl.c b/arch/arm/cpu/at91-common/spl.c
>> index 674a470..5c9a3ad 100644
>> --- a/arch/arm/cpu/at91-common/spl.c
>> +++ b/arch/arm/cpu/at91-common/spl.c
>
> I am thinking, whether it be better to keep this file as two copy? This will remove #ifdef, although a little code duplication.
>
> If this solution acceptable, some suggestion as following:
> - for armv5 (arm926ejs, now at91 series), named it spl_at91.c,
> - for armv7 (cortex-a5, now, sama5d3), named it spl_atmel.c?
> (As for arm9 series, we have at91 prefix for SoC name, and for armv7 SoC, we don't have at91 prefix, and it now changed to Atmel Smart)

Ok, I look into this.

[...]
>> @@ -57,77 +91,134 @@ static void switch_to_main_crystal_osc(void)
[...]
>> - /* disable watchdog */
>> +void spl_board_init(void)
>> +{
>> + struct at91_pmc *pmc = (struct at91_pmc *)ATMEL_BASE_PMC;
>> +
>> + lowlevel_clock_init();
>> at91_disable_wdt();
>>
>> - /* PMC configuration */
>> - at91_pmc_init();
>> + /*
>> + * At this stage the main oscillator is supposed to be enabled
>> + * PCK = MCK = MOSC
>> + */
>> + writel(0x00, &pmc->pllicpr);
>>
>> - at91_clock_init(CONFIG_SYS_AT91_MAIN_CLOCK);
>> + /* Configure PLLA = MOSC * (PLL_MULA + 1) / PLL_DIVA */
>> + at91_plla_init(CONFIG_SYS_AT91_PLLA);
>>
>> - timer_init();
>> + /* PCK = PLLA = 2 * MCK */
>> + at91_mck_init(CONFIG_SYS_MCKR);
>>
>> - board_early_init_f();
>> + /* Switch MCK on PLLA output */
>> + at91_mck_init(CONFIG_SYS_MCKR_CSS);
>> +
>> +#if defined(CONFIG_SYS_AT91_PLLB)
>> + /* Configure PLLB */
>> + at91_pllb_init(CONFIG_SYS_AT91_PLLB);
>> +#endif
>> +
>> + /* Enable External Reset */
>> + enable_ext_reset();
>>
>> +#if defined(CONFIG_ATMEL_MATRIX_INIT)
>> + /* Initialize matrix */
>> + matrix_init();
>> +#endif
>
> Can this also be weak function? And put matrix_init() code to SoC/board related file.

Changed.

Thanks!

bye,
Heiko
Wolfgang Denk Oct. 31, 2014, 6:08 a.m. UTC | #6
Dear Bo Shen,

In message <5452EAD4.7080903@atmel.com> you wrote:
> 
> I am thinking, whether it be better to keep this file as two copy? This 
> will remove #ifdef, although a little code duplication.

I agree that we should try and minimize #ifdef's, but code duplication
is even worse.


Best regards,

Wolfgang Denk
diff mbox

Patch

diff --git a/arch/arm/cpu/arm926ejs/at91/at91sam9260_devices.c b/arch/arm/cpu/arm926ejs/at91/at91sam9260_devices.c
index cae4abc..7a7fd7d 100644
--- a/arch/arm/cpu/arm926ejs/at91/at91sam9260_devices.c
+++ b/arch/arm/cpu/arm926ejs/at91/at91sam9260_devices.c
@@ -8,8 +8,10 @@ 
 
 #include <common.h>
 #include <asm/io.h>
+#include <asm/arch/at91sam9260_matrix.h>
 #include <asm/arch/at91_common.h>
 #include <asm/arch/at91_pmc.h>
+#include <asm/arch/at91sam9_sdramc.h>
 #include <asm/arch/gpio.h>
 
 /*
@@ -207,3 +209,23 @@  void at91_mci_hw_init(void)
 #endif
 }
 #endif
+
+void at91_sdram_hw_init(void)
+{
+	at91_set_a_periph(AT91_PIO_PORTC, 16, 0);
+	at91_set_a_periph(AT91_PIO_PORTC, 17, 0);
+	at91_set_a_periph(AT91_PIO_PORTC, 18, 0);
+	at91_set_a_periph(AT91_PIO_PORTC, 19, 0);
+	at91_set_a_periph(AT91_PIO_PORTC, 20, 0);
+	at91_set_a_periph(AT91_PIO_PORTC, 21, 0);
+	at91_set_a_periph(AT91_PIO_PORTC, 22, 0);
+	at91_set_a_periph(AT91_PIO_PORTC, 23, 0);
+	at91_set_a_periph(AT91_PIO_PORTC, 24, 0);
+	at91_set_a_periph(AT91_PIO_PORTC, 25, 0);
+	at91_set_a_periph(AT91_PIO_PORTC, 26, 0);
+	at91_set_a_periph(AT91_PIO_PORTC, 27, 0);
+	at91_set_a_periph(AT91_PIO_PORTC, 28, 0);
+	at91_set_a_periph(AT91_PIO_PORTC, 29, 0);
+	at91_set_a_periph(AT91_PIO_PORTC, 30, 0);
+	at91_set_a_periph(AT91_PIO_PORTC, 31, 0);
+}
diff --git a/arch/arm/cpu/arm926ejs/at91/clock.c b/arch/arm/cpu/arm926ejs/at91/clock.c
index 31315b5..f363982 100644
--- a/arch/arm/cpu/arm926ejs/at91/clock.c
+++ b/arch/arm/cpu/arm926ejs/at91/clock.c
@@ -187,3 +187,63 @@  int at91_clock_init(unsigned long main_clock)
 
 	return 0;
 }
+
+#if !defined(AT91_PLL_LOCK_TIMEOUT)
+#define AT91_PLL_LOCK_TIMEOUT	1000000
+#endif
+
+void at91_plla_init(u32 pllar)
+{
+	struct at91_pmc *pmc = (struct at91_pmc *)ATMEL_BASE_PMC;
+	int timeout = AT91_PLL_LOCK_TIMEOUT;
+
+	writel(pllar, &pmc->pllar);
+	while (!(readl(&pmc->sr) & (AT91_PMC_LOCKA | AT91_PMC_MCKRDY))) {
+		timeout--;
+		if (timeout == 0)
+			break;
+	}
+}
+void at91_pllb_init(u32 pllbr)
+{
+	struct at91_pmc *pmc = (struct at91_pmc *)ATMEL_BASE_PMC;
+	int timeout = AT91_PLL_LOCK_TIMEOUT;
+
+	writel(pllbr, &pmc->pllbr);
+	while (!(readl(&pmc->sr) & (AT91_PMC_LOCKB | AT91_PMC_MCKRDY))) {
+		timeout--;
+		if (timeout == 0)
+			break;
+	}
+}
+
+void at91_mck_init(u32 mckr)
+{
+	struct at91_pmc *pmc = (struct at91_pmc *)ATMEL_BASE_PMC;
+	int timeout = AT91_PLL_LOCK_TIMEOUT;
+	u32 tmp;
+
+	tmp = readl(&pmc->mckr);
+	tmp &= ~(AT91_PMC_MCKR_PRES_MASK |
+		 AT91_PMC_MCKR_MDIV_MASK |
+		 AT91_PMC_MCKR_PLLADIV_MASK |
+		 AT91_PMC_MCKR_CSS_MASK);
+	tmp |= mckr & (AT91_PMC_MCKR_PRES_MASK |
+		       AT91_PMC_MCKR_MDIV_MASK |
+		       AT91_PMC_MCKR_PLLADIV_MASK |
+		       AT91_PMC_MCKR_CSS_MASK);
+	writel(tmp, &pmc->mckr);
+
+	while (!(readl(&pmc->sr) & AT91_PMC_MCKRDY)) {
+		timeout--;
+		if (timeout == 0)
+			break;
+	}
+}
+
+void at91_periph_clk_enable(int id)
+{
+	struct at91_pmc *pmc = (struct at91_pmc *)ATMEL_BASE_PMC;
+
+	writel(1 << id, &pmc->pcer);
+}
diff --git a/arch/arm/cpu/armv7/at91/clock.c b/arch/arm/cpu/armv7/at91/clock.c
index 36ed4a6..363081a 100644
--- a/arch/arm/cpu/armv7/at91/clock.c
+++ b/arch/arm/cpu/armv7/at91/clock.c
@@ -111,6 +111,33 @@  int at91_clock_init(unsigned long main_clock)
 	return 0;
 }
 
+void at91_plla_init(u32 pllar)
+{
+	struct at91_pmc *pmc = (struct at91_pmc *)ATMEL_BASE_PMC;
+
+	writel(pllar, &pmc->pllar);
+	while (!(readl(&pmc->sr) & (AT91_PMC_LOCKA | AT91_PMC_MCKRDY)))
+		;
+}
+
+void at91_mck_init(u32 mckr)
+{
+	struct at91_pmc *pmc = (struct at91_pmc *)ATMEL_BASE_PMC;
+	u32 tmp;
+
+	tmp = readl(&pmc->mckr);
+	tmp &= ~(AT91_PMC_MCKR_PRES_MASK |
+		 AT91_PMC_MCKR_MDIV_MASK |
+		 AT91_PMC_MCKR_PLLADIV_2);
+	tmp |= mckr & (AT91_PMC_MCKR_PRES_MASK |
+		       AT91_PMC_MCKR_MDIV_MASK |
+		       AT91_PMC_MCKR_PLLADIV_2);
+	writel(tmp, &pmc->mckr);
+
+	while (!(readl(&pmc->sr) & AT91_PMC_MCKRDY))
+		;
+}
+
 void at91_periph_clk_enable(int id)
 {
 	struct at91_pmc *pmc = (struct at91_pmc *)ATMEL_BASE_PMC;
diff --git a/arch/arm/cpu/at91-common/Makefile b/arch/arm/cpu/at91-common/Makefile
index f62863a..5bdfb6a 100644
--- a/arch/arm/cpu/at91-common/Makefile
+++ b/arch/arm/cpu/at91-common/Makefile
@@ -10,6 +10,7 @@ 
 
 obj-$(CONFIG_AT91_WANTS_COMMON_PHY) += phy.o
 ifneq ($(CONFIG_SPL_BUILD),)
+obj-$(CONFIG_AT91SAM9G20) += sdram.o
 obj-$(CONFIG_AT91SAM9M10G45) += mpddrc.o
 obj-$(CONFIG_SAMA5D3) += mpddrc.o
 obj-y += spl.o
diff --git a/arch/arm/cpu/at91-common/sdram.c b/arch/arm/cpu/at91-common/sdram.c
new file mode 100644
index 0000000..5758b06
--- /dev/null
+++ b/arch/arm/cpu/at91-common/sdram.c
@@ -0,0 +1,77 @@ 
+/*
+ * (C) Copyright 2014
+ * Heiko Schocher, DENX Software Engineering, hs@denx.de.
+ *
+ * Based on:
+ * (C) Copyright 2007-2008
+ * Stelian Pop <stelian@popies.net>
+ * Lead Tech Design <www.leadtechdesign.com>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <asm/arch/at91_common.h>
+#include <asm/arch/at91_pmc.h>
+#include <asm/arch/at91sam9_sdramc.h>
+#include <asm/arch/gpio.h>
+
+int sdramc_initialize(unsigned int sdram_address, const struct sdramc_reg *p)
+{
+	struct sdramc_reg *reg = (struct sdramc_reg *)ATMEL_BASE_SDRAMC;
+	unsigned int i;
+
+	/* SDRAM feature must be in the configuration register */
+	writel(p->cr, &reg->cr);
+
+	/* The SDRAM memory type must be set in the Memory Device Register */
+	writel(p->mdr, &reg->mdr);
+
+	/*
+	 * The minimum pause of 200 us is provided to precede any single
+	 * toggle
+	 */
+	for (i = 0; i < 1000; i++)
+		;
+
+	/* A NOP command is issued to the SDRAM devices */
+	writel(AT91_SDRAMC_MODE_NOP, &reg->mr);
+	writel(0x00000000, sdram_address);
+
+	/* An All Banks Precharge command is issued to the SDRAM devices */
+	writel(AT91_SDRAMC_MODE_PRECHARGE, &reg->mr);
+	writel(0x00000000, sdram_address);
+
+	for (i = 0; i < 10000; i++)
+		;
+
+	/* Eight auto-refresh cycles are provided */
+	for (i = 0; i < 8; i++) {
+		writel(AT91_SDRAMC_MODE_REFRESH, &reg->mr);
+		writel(0x00000001 + i, sdram_address + 4 + 4 * i);
+	}
+
+	/*
+	 * A Mode Register set (MRS) cyscle is issued to program the
+	 * SDRAM parameters(TCSR, PASR, DS)
+	 */
+	writel(AT91_SDRAMC_MODE_LMR, &reg->mr);
+	writel(0xcafedede, sdram_address + 0x24);
+
+	/*
+	 * The application must go into Normal Mode, setting Mode
+	 * to 0 in the Mode Register and perform a write access at
+	 * any location in the SDRAM.
+	 */
+	writel(AT91_SDRAMC_MODE_NORMAL, &reg->mr);
+	writel(0x00000000, sdram_address);	/* Perform Normal mode */
+
+	/*
+	 * Write the refresh rate into the count field in the SDRAMC
+	 * Refresh Timer Rgister.
+	 */
+	writel(p->tr, &reg->tr);
+
+	return 0;
+}
diff --git a/arch/arm/cpu/at91-common/spl.c b/arch/arm/cpu/at91-common/spl.c
index 674a470..5c9a3ad 100644
--- a/arch/arm/cpu/at91-common/spl.c
+++ b/arch/arm/cpu/at91-common/spl.c
@@ -8,11 +8,18 @@ 
 #include <common.h>
 #include <asm/io.h>
 #include <asm/arch/at91_common.h>
+#if !defined(CONFIG_SAMA5D3)
+#include <asm/arch/at91sam9_matrix.h>
+#endif
+#include <asm/arch/at91_pit.h>
 #include <asm/arch/at91_pmc.h>
+#include <asm/arch/at91_rstc.h>
 #include <asm/arch/at91_wdt.h>
 #include <asm/arch/clk.h>
 #include <spl.h>
 
+DECLARE_GLOBAL_DATA_PTR;
+
 static void at91_disable_wdt(void)
 {
 	struct at91_wdt *wdt = (struct at91_wdt *)ATMEL_BASE_WDT;
@@ -20,6 +27,33 @@  static void at91_disable_wdt(void)
 	writel(AT91_WDT_MR_WDDIS, &wdt->mr);
 }
 
+u32 spl_boot_device(void)
+{
+#ifdef CONFIG_SYS_USE_MMC
+	return BOOT_DEVICE_MMC1;
+#elif CONFIG_SYS_USE_NANDFLASH
+	return BOOT_DEVICE_NAND;
+#elif CONFIG_SYS_USE_SERIALFLASH
+	return BOOT_DEVICE_SPI;
+#endif
+	return BOOT_DEVICE_NONE;
+}
+
+u32 spl_boot_mode(void)
+{
+	switch (spl_boot_device()) {
+#ifdef CONFIG_SYS_USE_MMC
+	case BOOT_DEVICE_MMC1:
+		return MMCSD_MODE_FS;
+		break;
+#endif
+	case BOOT_DEVICE_NONE:
+	default:
+		hang();
+	}
+}
+
+#if defined(CONFIG_SAMA5D3)
 static void switch_to_main_crystal_osc(void)
 {
 	struct at91_pmc *pmc = (struct at91_pmc *)ATMEL_BASE_PMC;
@@ -57,77 +91,134 @@  static void switch_to_main_crystal_osc(void)
 	writel(tmp, &pmc->mor);
 }
 
-void at91_plla_init(u32 pllar)
+void s_init(void)
 {
-	struct at91_pmc *pmc = (struct at91_pmc *)ATMEL_BASE_PMC;
+	switch_to_main_crystal_osc();
 
-	writel(pllar, &pmc->pllar);
-	while (!(readl(&pmc->sr) & (AT91_PMC_LOCKA | AT91_PMC_MCKRDY)))
-		;
-}
+	/* disable watchdog */
+	at91_disable_wdt();
 
-void at91_mck_init(u32 mckr)
-{
-	struct at91_pmc *pmc = (struct at91_pmc *)ATMEL_BASE_PMC;
-	u32 tmp;
+	/* PMC configuration */
+	at91_pmc_init();
 
-	tmp = readl(&pmc->mckr);
-	tmp &= ~(AT91_PMC_MCKR_PRES_MASK |
-		 AT91_PMC_MCKR_MDIV_MASK |
-		 AT91_PMC_MCKR_PLLADIV_2);
-	tmp |= mckr & (AT91_PMC_MCKR_PRES_MASK |
-		       AT91_PMC_MCKR_MDIV_MASK |
-		       AT91_PMC_MCKR_PLLADIV_2);
-	writel(tmp, &pmc->mckr);
+	at91_clock_init(CONFIG_SYS_AT91_MAIN_CLOCK);
 
-	while (!(readl(&pmc->sr) & AT91_PMC_MCKRDY))
-		;
-}
+	timer_init();
 
+	board_early_init_f();
 
-u32 spl_boot_device(void)
+	preloader_console_init();
+
+	mem_init();
+}
+#else
+static void enable_ext_reset(void)
 {
-#ifdef CONFIG_SYS_USE_MMC
-	return BOOT_DEVICE_MMC1;
-#elif CONFIG_SYS_USE_NANDFLASH
-	return BOOT_DEVICE_NAND;
-#elif CONFIG_SYS_USE_SERIALFLASH
-	return BOOT_DEVICE_SPI;
-#endif
-	return BOOT_DEVICE_NONE;
+	struct at91_rstc *rstc = (struct at91_rstc *)ATMEL_BASE_RSTC;
+
+	writel(AT91_RSTC_KEY | AT91_RSTC_MR_URSTEN, &rstc->mr);
 }
 
-u32 spl_boot_mode(void)
+#if defined(CONFIG_ATMEL_MATRIX_INIT)
+static void matrix_init(void)
 {
-	switch (spl_boot_device()) {
-#ifdef CONFIG_SYS_USE_MMC
-	case BOOT_DEVICE_MMC1:
-		return MMCSD_MODE_FS;
-		break;
+	struct at91_matrix *mat = (struct at91_matrix *)ATMEL_BASE_MATRIX;
+
+	writel((readl(&mat->scfg[3]) & (~AT91_MATRIX_SLOT_CYCLE))
+			| AT91_MATRIX_SLOT_CYCLE_(0x40),
+			&mat->scfg[3]);
+}
 #endif
-	case BOOT_DEVICE_NONE:
-	default:
-		hang();
+
+void lowlevel_clock_init(void)
+{
+	struct at91_pmc *pmc = (struct at91_pmc *)ATMEL_BASE_PMC;
+
+	if (!(readl(&pmc->sr) & AT91_PMC_MOSCS)) {
+		/* Enable Main Oscillator */
+		writel(AT91_PMC_MOSCS | (0x40 << 8), &pmc->mor);
+
+		/* Wait until Main Oscillator is stable */
+		while (!(readl(&pmc->sr) & AT91_PMC_MOSCS))
+			;
 	}
+
+	/* After stabilization, switch to Main Oscillator */
+	if ((readl(&pmc->mckr) & AT91_PMC_CSS) == AT91_PMC_CSS_SLOW) {
+		unsigned long tmp;
+
+		tmp = readl(&pmc->mckr);
+		tmp &= ~AT91_PMC_CSS;
+		tmp |= AT91_PMC_CSS_MAIN;
+		writel(tmp, &pmc->mckr);
+		while (!(readl(&pmc->sr) & AT91_PMC_MCKRDY))
+			;
+
+		tmp &= ~AT91_PMC_PRES;
+		tmp |= AT91_PMC_PRES_1;
+		writel(tmp, &pmc->mckr);
+		while (!(readl(&pmc->sr) & AT91_PMC_MCKRDY))
+			;
+	}
+
+	return;
 }
 
-void s_init(void)
+void __weak at91_spl_board_init(void)
 {
-	switch_to_main_crystal_osc();
+}
 
-	/* disable watchdog */
+void spl_board_init(void)
+{
+	struct at91_pmc *pmc = (struct at91_pmc *)ATMEL_BASE_PMC;
+
+	lowlevel_clock_init();
 	at91_disable_wdt();
 
-	/* PMC configuration */
-	at91_pmc_init();
+	/*
+	 * At this stage the main oscillator is supposed to be enabled
+	 * PCK = MCK = MOSC
+	 */
+	writel(0x00, &pmc->pllicpr);
 
-	at91_clock_init(CONFIG_SYS_AT91_MAIN_CLOCK);
+	/* Configure PLLA = MOSC * (PLL_MULA + 1) / PLL_DIVA */
+	at91_plla_init(CONFIG_SYS_AT91_PLLA);
 
-	timer_init();
+	/* PCK = PLLA = 2 * MCK */
+	at91_mck_init(CONFIG_SYS_MCKR);
 
-	board_early_init_f();
+	/* Switch MCK on PLLA output */
+	at91_mck_init(CONFIG_SYS_MCKR_CSS);
+
+#if defined(CONFIG_SYS_AT91_PLLB)
+	/* Configure PLLB */
+	at91_pllb_init(CONFIG_SYS_AT91_PLLB);
+#endif
+
+	/* Enable External Reset */
+	enable_ext_reset();
 
+#if defined(CONFIG_ATMEL_MATRIX_INIT)
+	/* Initialize matrix */
+	matrix_init();
+#endif
+
+	gd->arch.mck_rate_hz = CONFIG_SYS_MASTER_CLOCK;
+	/*
+	 * init timer long enough for using in spl.
+	 */
+	timer_init();
+
+	/* enable clocks for all PIOs */
+	at91_periph_clk_enable(ATMEL_ID_PIOA);
+	at91_periph_clk_enable(ATMEL_ID_PIOB);
+	at91_periph_clk_enable(ATMEL_ID_PIOC);
+	/* init console */
+	at91_seriald_hw_init();
 	preloader_console_init();
 
 	mem_init();
+
+	at91_spl_board_init();
 }
+#endif
diff --git a/arch/arm/include/asm/arch-at91/at91_common.h b/arch/arm/include/asm/arch-at91/at91_common.h
index 59e2f43..2d94090 100644
--- a/arch/arm/include/asm/arch-at91/at91_common.h
+++ b/arch/arm/include/asm/arch-at91/at91_common.h
@@ -23,9 +23,13 @@  void at91_udp_hw_init(void);
 void at91_uhp_hw_init(void);
 void at91_lcd_hw_init(void);
 void at91_plla_init(u32 pllar);
+void at91_pllb_init(u32 pllar);
 void at91_mck_init(u32 mckr);
 void at91_pmc_init(void);
 void mem_init(void);
 void at91_phy_reset(void);
+void at91_sdram_hw_init(void);
+void at91_mck_init(u32 mckr);
+void at91_spl_board_init(void);
 
 #endif /* AT91_COMMON_H */
diff --git a/arch/arm/include/asm/arch-at91/at91_pmc.h b/arch/arm/include/asm/arch-at91/at91_pmc.h
index 27331ff..5f64583 100644
--- a/arch/arm/include/asm/arch-at91/at91_pmc.h
+++ b/arch/arm/include/asm/arch-at91/at91_pmc.h
@@ -95,7 +95,7 @@  typedef struct at91_pmc {
 #define AT91_PMC_MCKR_CSS_MAIN		0x00000001
 #define AT91_PMC_MCKR_CSS_PLLA		0x00000002
 #define AT91_PMC_MCKR_CSS_PLLB		0x00000003
-#define AT91_PMC_MCKR_CSS_MASK		0x00000003
+#define AT91_PMC_MCKR_CSS_MASK		0x00000007
 
 #ifdef CONFIG_SAMA5D3
 #define AT91_PMC_MCKR_PRES_1		0x00000000
@@ -114,7 +114,7 @@  typedef struct at91_pmc {
 #define AT91_PMC_MCKR_PRES_16		0x00000010
 #define AT91_PMC_MCKR_PRES_32		0x00000014
 #define AT91_PMC_MCKR_PRES_64		0x00000018
-#define AT91_PMC_MCKR_PRES_MASK		0x0000001C
+#define AT91_PMC_MCKR_PRES_MASK		0x0000003C
 #endif
 
 #ifdef CONFIG_AT91RM9200
@@ -133,6 +133,7 @@  typedef struct at91_pmc {
 #define AT91_PMC_MCKR_MDIV_MASK		0x00000300
 #endif
 
+#define AT91_PMC_MCKR_PLLADIV_MASK	0x00003000
 #define AT91_PMC_MCKR_PLLADIV_1		0x00000000
 #define AT91_PMC_MCKR_PLLADIV_2		0x00001000
 
diff --git a/arch/arm/include/asm/arch-at91/at91sam9260.h b/arch/arm/include/asm/arch-at91/at91sam9260.h
index 2e902ee..1e613fa 100644
--- a/arch/arm/include/asm/arch-at91/at91sam9260.h
+++ b/arch/arm/include/asm/arch-at91/at91sam9260.h
@@ -95,6 +95,7 @@ 
 #define ATMEL_BASE_SDRAMC	0xffffea00
 #define ATMEL_BASE_SMC		0xffffec00
 #define ATMEL_BASE_MATRIX	0xffffee00
+#define ATMEL_BASE_CCFG         0xffffef14
 #define ATMEL_BASE_AIC		0xfffff000
 #define ATMEL_BASE_DBGU		0xfffff200
 #define ATMEL_BASE_PIOA		0xfffff400
diff --git a/arch/arm/include/asm/arch-at91/at91sam9260_matrix.h b/arch/arm/include/asm/arch-at91/at91sam9260_matrix.h
index 4755fa1..dc61f48 100644
--- a/arch/arm/include/asm/arch-at91/at91sam9260_matrix.h
+++ b/arch/arm/include/asm/arch-at91/at91sam9260_matrix.h
@@ -61,5 +61,10 @@  struct at91_matrix {
 #define AT91_MATRIX_DBPUC		(1 << 8)
 #define AT91_MATRIX_VDDIOMSEL_1_8V	(0 << 16)
 #define AT91_MATRIX_VDDIOMSEL_3_3V	(1 << 16)
+#define AT91_MATRIX_EBI_IOSR_SEL	(1 << 17)
+
+/* Maximum Number of Allowed Cycles for a Burst */
+#define AT91_MATRIX_SLOT_CYCLE		(0xff << 0)
+#define AT91_MATRIX_SLOT_CYCLE_(x)	(x << 0)
 
 #endif
diff --git a/arch/arm/include/asm/arch-at91/at91sam9_sdramc.h b/arch/arm/include/asm/arch-at91/at91sam9_sdramc.h
index 5c98cc7..3a076c6 100644
--- a/arch/arm/include/asm/arch-at91/at91sam9_sdramc.h
+++ b/arch/arm/include/asm/arch-at91/at91sam9_sdramc.h
@@ -25,6 +25,21 @@ 
 #define AT91_ASM_SDRAMC_CR	(ATMEL_BASE_SDRAMC + 0x08)
 #define AT91_ASM_SDRAMC_MDR	(ATMEL_BASE_SDRAMC + 0x24)
 
+#else
+struct sdramc_reg {
+	u32	mr;
+	u32	tr;
+	u32	cr;
+	u32	lpr;
+	u32	ier;
+	u32	idr;
+	u32	imr;
+	u32	isr;
+	u32	mdr;
+};
+
+int sdramc_initialize(unsigned int sdram_address,
+		      const struct sdramc_reg *p);
 #endif
 
 /* SDRAM Controller (SDRAMC) registers */
@@ -62,11 +77,17 @@ 
 #define			AT91_SDRAMC_DBW_32	(0 << 7)
 #define			AT91_SDRAMC_DBW_16	(1 << 7)
 #define		AT91_SDRAMC_TWR		(0xf <<  8)		/* Write Recovery Delay */
+#define		AT91_SDRAMC_TWR_VAL(x)	(x << 8)
 #define		AT91_SDRAMC_TRC		(0xf << 12)		/* Row Cycle Delay */
+#define			AT91_SDRAMC_TRC_VAL(x)	(x << 12)
 #define		AT91_SDRAMC_TRP		(0xf << 16)		/* Row Precharge Delay */
+#define		AT91_SDRAMC_TRP_VAL(x)	(x << 16)
 #define		AT91_SDRAMC_TRCD	(0xf << 20)		/* Row to Column Delay */
+#define			AT91_SDRAMC_TRCD_VAL(x)	(x << 20)
 #define		AT91_SDRAMC_TRAS	(0xf << 24)		/* Active to Precharge Delay */
+#define		AT91_SDRAMC_TRAS_VAL(x)	(x << 24)
 #define		AT91_SDRAMC_TXSR	(0xf << 28)		/* Exit Self Refresh to Active Delay */
+#define		AT91_SDRAMC_TXSR_VAL(x)	(x << 28)
 
 #define AT91_SDRAMC_LPR		(ATMEL_BASE_SDRAMC + 0x10)	/* SDRAM Controller Low Power Register */
 #define		AT91_SDRAMC_LPCB		(3 << 0)	/* Low-power Configurations */
@@ -93,5 +114,4 @@ 
 #define			AT91_SDRAMC_MD_SDRAM		0
 #define			AT91_SDRAMC_MD_LOW_POWER_SDRAM	1
 
-
 #endif