summaryrefslogtreecommitdiff
path: root/arch/arm/cpu/at91-common
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/cpu/at91-common')
-rw-r--r--arch/arm/cpu/at91-common/Makefile12
-rw-r--r--arch/arm/cpu/at91-common/mpddrc.c124
-rw-r--r--arch/arm/cpu/at91-common/phy.c57
-rw-r--r--arch/arm/cpu/at91-common/spl.c90
-rw-r--r--arch/arm/cpu/at91-common/u-boot-spl.lds50
5 files changed, 333 insertions, 0 deletions
diff --git a/arch/arm/cpu/at91-common/Makefile b/arch/arm/cpu/at91-common/Makefile
new file mode 100644
index 0000000..5b97838
--- /dev/null
+++ b/arch/arm/cpu/at91-common/Makefile
@@ -0,0 +1,12 @@
+#
+# (C) Copyright 2000-2008
+# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+#
+# (C) Copyright 2013 Atmel Corporation
+# Bo Shen <voice.shen@atmel.com>
+#
+# SPDX-License-Identifier: GPL-2.0+
+#
+
+obj-$(CONFIG_AT91_WANTS_COMMON_PHY) += phy.o
+obj-$(CONFIG_SPL_BUILD) += mpddrc.o spl.o
diff --git a/arch/arm/cpu/at91-common/mpddrc.c b/arch/arm/cpu/at91-common/mpddrc.c
new file mode 100644
index 0000000..8136396
--- /dev/null
+++ b/arch/arm/cpu/at91-common/mpddrc.c
@@ -0,0 +1,124 @@
+/*
+ * Copyright (C) 2013 Atmel Corporation
+ * Bo Shen <voice.shen@atmel.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <asm/arch/atmel_mpddrc.h>
+
+static inline void atmel_mpddr_op(int mode, u32 ram_address)
+{
+ struct atmel_mpddr *mpddr = (struct atmel_mpddr *)ATMEL_BASE_MPDDRC;
+
+ writel(mode, &mpddr->mr);
+ writel(0, ram_address);
+}
+
+int ddr2_init(const unsigned int ram_address,
+ const struct atmel_mpddr *mpddr_value)
+{
+ struct atmel_mpddr *mpddr = (struct atmel_mpddr *)ATMEL_BASE_MPDDRC;
+ u32 ba_off, cr;
+
+ /* Compute bank offset according to NC in configuration register */
+ ba_off = (mpddr_value->cr & ATMEL_MPDDRC_CR_NC_MASK) + 9;
+ if (!(mpddr_value->cr & ATMEL_MPDDRC_CR_DECOD_INTERLEAVED))
+ ba_off += ((mpddr->cr & ATMEL_MPDDRC_CR_NR_MASK) >> 2) + 11;
+
+ ba_off += (mpddr_value->md & ATMEL_MPDDRC_MD_DBW_MASK) ? 1 : 2;
+
+ /* Program the memory device type into the memory device register */
+ writel(mpddr_value->md, &mpddr->md);
+
+ /* Program the configuration register */
+ writel(mpddr_value->cr, &mpddr->cr);
+
+ /* Program the timing register */
+ writel(mpddr_value->tpr0, &mpddr->tpr0);
+ writel(mpddr_value->tpr1, &mpddr->tpr1);
+ writel(mpddr_value->tpr2, &mpddr->tpr2);
+
+ /* Issue a NOP command */
+ atmel_mpddr_op(ATMEL_MPDDRC_MR_MODE_NOP_CMD, ram_address);
+
+ /* A 200 us is provided to precede any signal toggle */
+ udelay(200);
+
+ /* Issue a NOP command */
+ atmel_mpddr_op(ATMEL_MPDDRC_MR_MODE_NOP_CMD, ram_address);
+
+ /* Issue an all banks precharge command */
+ atmel_mpddr_op(ATMEL_MPDDRC_MR_MODE_PRCGALL_CMD, ram_address);
+
+ /* Issue an extended mode register set(EMRS2) to choose operation */
+ atmel_mpddr_op(ATMEL_MPDDRC_MR_MODE_EXT_LMR_CMD,
+ ram_address + (0x2 << ba_off));
+
+ /* Issue an extended mode register set(EMRS3) to set EMSR to 0 */
+ atmel_mpddr_op(ATMEL_MPDDRC_MR_MODE_EXT_LMR_CMD,
+ ram_address + (0x3 << ba_off));
+
+ /*
+ * Issue an extended mode register set(EMRS1) to enable DLL and
+ * program D.I.C (output driver impedance control)
+ */
+ atmel_mpddr_op(ATMEL_MPDDRC_MR_MODE_EXT_LMR_CMD,
+ ram_address + (0x1 << ba_off));
+
+ /* Enable DLL reset */
+ cr = readl(&mpddr->cr);
+ writel(cr | ATMEL_MPDDRC_CR_DLL_RESET_ENABLED, &mpddr->cr);
+
+ /* A mode register set(MRS) cycle is issued to reset DLL */
+ atmel_mpddr_op(ATMEL_MPDDRC_MR_MODE_LMR_CMD, ram_address);
+
+ /* Issue an all banks precharge command */
+ atmel_mpddr_op(ATMEL_MPDDRC_MR_MODE_PRCGALL_CMD, ram_address);
+
+ /* Two auto-refresh (CBR) cycles are provided */
+ atmel_mpddr_op(ATMEL_MPDDRC_MR_MODE_RFSH_CMD, ram_address);
+ atmel_mpddr_op(ATMEL_MPDDRC_MR_MODE_RFSH_CMD, ram_address);
+
+ /* Disable DLL reset */
+ cr = readl(&mpddr->cr);
+ writel(cr & (~ATMEL_MPDDRC_CR_DLL_RESET_ENABLED), &mpddr->cr);
+
+ /* A mode register set (MRS) cycle is issued to disable DLL reset */
+ atmel_mpddr_op(ATMEL_MPDDRC_MR_MODE_LMR_CMD, ram_address);
+
+ /* Set OCD calibration in default state */
+ cr = readl(&mpddr->cr);
+ writel(cr | ATMEL_MPDDRC_CR_OCD_DEFAULT, &mpddr->cr);
+
+ /*
+ * An extended mode register set (EMRS1) cycle is issued
+ * to OCD default value
+ */
+ atmel_mpddr_op(ATMEL_MPDDRC_MR_MODE_EXT_LMR_CMD,
+ ram_address + (0x1 << ba_off));
+
+ /* OCD calibration mode exit */
+ cr = readl(&mpddr->cr);
+ writel(cr & (~ATMEL_MPDDRC_CR_OCD_DEFAULT), &mpddr->cr);
+
+ /*
+ * An extended mode register set (EMRS1) cycle is issued
+ * to enable OCD exit
+ */
+ atmel_mpddr_op(ATMEL_MPDDRC_MR_MODE_EXT_LMR_CMD,
+ ram_address + (0x1 << ba_off));
+
+ /* A nornal mode command is provided */
+ atmel_mpddr_op(ATMEL_MPDDRC_MR_MODE_NORMAL_CMD, ram_address);
+
+ /* Perform a write access to any DDR2-SDRAM address */
+ writel(0, ram_address);
+
+ /* Write the refresh rate */
+ writel(mpddr_value->rtr, &mpddr->rtr);
+
+ return 0;
+}
diff --git a/arch/arm/cpu/at91-common/phy.c b/arch/arm/cpu/at91-common/phy.c
new file mode 100644
index 0000000..3b6c60c
--- /dev/null
+++ b/arch/arm/cpu/at91-common/phy.c
@@ -0,0 +1,57 @@
+/*
+ * (C) Copyright 2007-2008
+ * Stelian Pop <stelian@popies.net>
+ * Lead Tech Design <www.leadtechdesign.com>
+ *
+ * (C) Copyright 2012
+ * Markus Hubig <mhubig@imko.de>
+ * IMKO GmbH <www.imko.de>
+ *
+ * Copyright (C) 2013 DENX Software Engineering, hs@denx.de
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <asm/sizes.h>
+#include <asm/arch/at91_pmc.h>
+#include <asm/arch/at91_rstc.h>
+#include <watchdog.h>
+
+void at91_phy_reset(void)
+{
+ unsigned long erstl;
+ unsigned long start = get_timer(0);
+ unsigned long const timeout = 1000; /* 1000ms */
+ at91_rstc_t *rstc = (at91_rstc_t *)ATMEL_BASE_RSTC;
+
+ erstl = readl(&rstc->mr) & AT91_RSTC_MR_ERSTL_MASK;
+
+ /*
+ * Need to reset PHY -> 500ms reset
+ * Reset PHY by pulling the NRST line for 500ms to low. To do so
+ * disable user reset for low level on NRST pin and poll the NRST
+ * level in reset status register.
+ */
+ writel(AT91_RSTC_KEY | AT91_RSTC_MR_ERSTL(0x0D) |
+ AT91_RSTC_MR_URSTEN, &rstc->mr);
+
+ writel(AT91_RSTC_KEY | AT91_RSTC_CR_EXTRST, &rstc->cr);
+
+ /* Wait for end of hardware reset */
+ while (!(readl(&rstc->sr) & AT91_RSTC_SR_NRSTL)) {
+ /* avoid shutdown by watchdog */
+ WATCHDOG_RESET();
+ mdelay(10);
+
+ /* timeout for not getting stuck in an endless loop */
+ if (get_timer(start) >= timeout) {
+ puts("*** ERROR: Timeout waiting for PHY reset!\n");
+ break;
+ }
+ };
+
+ /* Restore NRST value */
+ writel(AT91_RSTC_KEY | erstl | AT91_RSTC_MR_URSTEN, &rstc->mr);
+}
diff --git a/arch/arm/cpu/at91-common/spl.c b/arch/arm/cpu/at91-common/spl.c
new file mode 100644
index 0000000..37c0cc4
--- /dev/null
+++ b/arch/arm/cpu/at91-common/spl.c
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2013 Atmel Corporation
+ * Bo Shen <voice.shen@atmel.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/at91_wdt.h>
+#include <asm/arch/clk.h>
+#include <spl.h>
+
+static void at91_disable_wdt(void)
+{
+ struct at91_wdt *wdt = (struct at91_wdt *)ATMEL_BASE_WDT;
+
+ writel(AT91_WDT_MR_WDDIS, &wdt->mr);
+}
+
+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))
+ ;
+}
+
+
+u32 spl_boot_device(void)
+{
+#ifdef CONFIG_SYS_USE_MMC
+ return BOOT_DEVICE_MMC1;
+#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_FAT;
+ break;
+#endif
+ case BOOT_DEVICE_NONE:
+ default:
+ hang();
+ }
+}
+
+void s_init(void)
+{
+ /* disable watchdog */
+ at91_disable_wdt();
+
+ /* PMC configuration */
+ at91_pmc_init();
+
+ at91_clock_init(CONFIG_SYS_AT91_MAIN_CLOCK);
+
+ timer_init();
+
+ board_early_init_f();
+
+ preloader_console_init();
+
+ mem_init();
+}
diff --git a/arch/arm/cpu/at91-common/u-boot-spl.lds b/arch/arm/cpu/at91-common/u-boot-spl.lds
new file mode 100644
index 0000000..038335d
--- /dev/null
+++ b/arch/arm/cpu/at91-common/u-boot-spl.lds
@@ -0,0 +1,50 @@
+/*
+ * (C) Copyright 2002
+ * Gary Jennejohn, DENX Software Engineering, <garyj@denx.de>
+ *
+ * (C) Copyright 2010
+ * Texas Instruments, <www.ti.com>
+ * Aneesh V <aneesh@ti.com>
+ *
+ * (C) 2013 Atmel Corporation
+ * Bo Shen <voice.shen@atmel.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+MEMORY { .sram : ORIGIN = CONFIG_SPL_TEXT_BASE, \
+ LENGTH = CONFIG_SPL_MAX_SIZE }
+MEMORY { .sdram : ORIGIN = CONFIG_SPL_BSS_START_ADDR, \
+ LENGTH = CONFIG_SPL_BSS_MAX_SIZE }
+
+OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
+OUTPUT_ARCH(arm)
+ENTRY(_start)
+SECTIONS
+{
+ .text :
+ {
+ __start = .;
+ arch/arm/cpu/armv7/start.o (.text*)
+ *(.text*)
+ } >.sram
+
+ . = ALIGN(4);
+ .rodata : { *(SORT_BY_ALIGNMENT(.rodata*)) } >.sram
+
+ . = ALIGN(4);
+ .data : { *(SORT_BY_ALIGNMENT(.data*)) } >.sram
+
+ . = ALIGN(4);
+ __image_copy_end = .;
+ _end = .;
+
+ .bss :
+ {
+ . = ALIGN(4);
+ __bss_start = .;
+ *(.bss*)
+ . = ALIGN(4);
+ __bss_end = .;
+ } >.sdram
+}