[PATCH 14/19] arch/MPC5xxx: add MPC5125 SoC support
Juergen Borleis
jbe at pengutronix.de
Tue Oct 7 07:22:13 PDT 2014
The MPC5125 shares most of the internals with the MPC52000 but differs in
many details. It also differs from the the MPC5121/MPC5123, so the latter
SoCs are not supported yet.
Signed-off-by: Juergen Borleis <jbe at pengutronix.de>
---
arch/ppc/include/asm/processor.h | 11 +
arch/ppc/lib/Makefile | 2 +-
arch/ppc/lib/nor-bbu.c | 141 ++++++++++
arch/ppc/mach-mpc5xxx/cpu-mpc5125.c | 174 ++++++++++++
arch/ppc/mach-mpc5xxx/include/mach/bbu.h | 18 ++
arch/ppc/mach-mpc5xxx/include/mach/clocks.h | 9 +
arch/ppc/mach-mpc5xxx/include/mach/mpc512x.h | 321 +++++++++++++++++++++++
arch/ppc/mach-mpc5xxx/include/mach/mpc512x_fec.h | 46 ++++
arch/ppc/mach-mpc5xxx/include/mach/mpc5xxx.h | 6 +-
arch/ppc/mach-mpc5xxx/iomux-mpc5125.c | 39 +++
arch/ppc/mach-mpc5xxx/lpc-mpc5125.c | 73 ++++++
arch/ppc/mach-mpc5xxx/sdram-mpc5125.c | 269 +++++++++++++++++++
arch/ppc/mach-mpc5xxx/speed-mpc5125.c | 209 +++++++++++++++
arch/ppc/mach-mpc5xxx/start.S | 99 ++++++-
arch/ppc/mach-mpc5xxx/sys-mpc5125.c | 136 ++++++++++
15 files changed, 1549 insertions(+), 4 deletions(-)
create mode 100644 arch/ppc/lib/nor-bbu.c
create mode 100644 arch/ppc/mach-mpc5xxx/cpu-mpc5125.c
create mode 100644 arch/ppc/mach-mpc5xxx/include/mach/bbu.h
create mode 100644 arch/ppc/mach-mpc5xxx/include/mach/mpc512x.h
create mode 100644 arch/ppc/mach-mpc5xxx/include/mach/mpc512x_fec.h
create mode 100644 arch/ppc/mach-mpc5xxx/iomux-mpc5125.c
create mode 100644 arch/ppc/mach-mpc5xxx/lpc-mpc5125.c
create mode 100644 arch/ppc/mach-mpc5xxx/sdram-mpc5125.c
create mode 100644 arch/ppc/mach-mpc5xxx/speed-mpc5125.c
create mode 100644 arch/ppc/mach-mpc5xxx/sys-mpc5125.c
diff --git a/arch/ppc/include/asm/processor.h b/arch/ppc/include/asm/processor.h
index e8a9c14..4d5a10f 100644
--- a/arch/ppc/include/asm/processor.h
+++ b/arch/ppc/include/asm/processor.h
@@ -236,6 +236,16 @@
#define HID1_ASTME (1<<13) /* Address bus streaming mode */
#define HID1_ABE (1<<12) /* Address broadcast enable */
#define HID1_MBDD (1<<6) /* optimized sync instruction */
+#define SPRN_HID2 0x3F3
+#define HID2_LET (1 << 27)
+#define HID2_HBE (1 << 18)
+#define HID2_IWLCK_000 (0x0 << 13) /* no ways locked */
+#define HID2_IWLCK_001 (0x1 << 13) /* way 0 locked */
+#define HID2_IWLCK_010 (0x2 << 13) /* way 0 through way 1 locked */
+#define HID2_IWLCK_011 (0x3 << 13) /* way 0 through way 2 locked */
+#define HID2_IWLCK_100 (0x4 << 13) /* way 0 through way 3 locked */
+#define HID2_IWLCK_101 (0x5 << 13) /* way 0 through way 4 locked */
+#define HID2_IWLCK_110 (0x6 << 13) /* way 0 through way 5 locked */
#define SPRN_IABR 0x3F2 /* Instruction Address Breakpoint Register */
#ifndef CONFIG_BOOKE
#define SPRN_IAC1 0x3F4 /* Instruction Address Compare 1 */
@@ -509,6 +519,7 @@
#define HASH2 SPRN_HASH2 /* Secondary Hash Address Register */
#define HID0 SPRN_HID0 /* Hardware Implementation Register 0 */
#define HID1 SPRN_HID1 /* Hardware Implementation Register 1 */
+#define HID2 SPRN_HID2 /* Hardware Implementation Register 2 */
#define IABR SPRN_IABR /* Instruction Address Breakpoint Register */
#define IAC1 SPRN_IAC1 /* Instruction Address Register 1 */
#define IAC2 SPRN_IAC2 /* Instruction Address Register 2 */
diff --git a/arch/ppc/lib/Makefile b/arch/ppc/lib/Makefile
index ba2f078..99d6225 100644
--- a/arch/ppc/lib/Makefile
+++ b/arch/ppc/lib/Makefile
@@ -9,4 +9,4 @@ obj-$(CONFIG_CMD_BOOTM) += ppclinux.o
obj-$(CONFIG_MODULES) += module.o
obj-y += crtsavres.o
obj-y += reloc.o
-
+obj-$(CONFIG_BAREBOX_UPDATE) += nor-bbu.o
diff --git a/arch/ppc/lib/nor-bbu.c b/arch/ppc/lib/nor-bbu.c
new file mode 100644
index 0000000..3bdd214
--- /dev/null
+++ b/arch/ppc/lib/nor-bbu.c
@@ -0,0 +1,141 @@
+/*
+ * nor-bbu.c - PowerPC generic functions to store barebox into a NOR flash
+ * Copyright (C) 2014 Juergen Borleis, Pengutronix
+ *
+ * Based on imx-bbu-internal.c
+ * Copyright (c) 2012 Sascha Hauer <s.hauer at pengutronix.de>, Pengutronix
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <common.h>
+#include <malloc.h>
+#include <bbu.h>
+#include <mach/bbu.h>
+#include <fs.h>
+#include <linux/stat.h>
+#include <fcntl.h>
+
+#define BBU_FLAG_ERASE (1 << 0)
+
+/* Actually write an image to NOR target device */
+static int ppc_bbu_write_device(struct bbu_handler *handler,
+ struct bbu_data *data, void *buf, int image_len)
+{
+ int fd, ret;
+
+ fd = open(data->devicefile, O_RDWR | O_CREAT);
+ if (fd < 0)
+ return fd;
+
+ if (handler->flags & BBU_FLAG_ERASE) {
+ debug("%s: unprotecting %s from 0 to 0x%08x\n", __func__,
+ data->devicefile, image_len);
+ ret = protect(fd, image_len, 0, 0);
+ if (ret && ret != -ENOSYS) {
+ printf("unprotecting %s failed with %s\n",
+ data->devicefile, strerror(-ret));
+ goto err_close;
+ }
+
+ debug("%s: erasing %s from 0 to 0x%08x\n", __func__,
+ data->devicefile, image_len);
+ ret = erase(fd, image_len, 0);
+ if (ret) {
+ printf("erasing %s failed with %s\n", data->devicefile,
+ strerror(-ret));
+ goto err_close;
+ }
+ }
+
+ ret = write(fd, buf, image_len);
+ if (ret < 0)
+ goto err_close;
+
+ if (handler->flags & BBU_FLAG_ERASE) {
+ debug("%s: protecting %s from 0 to 0x%08x\n", __func__,
+ data->devicefile, image_len);
+ ret = protect(fd, image_len, 0, 1);
+ if (ret && ret != -ENOSYS) {
+ printf("protecting %s failed with %s\n",
+ data->devicefile, strerror(-ret));
+ }
+ }
+
+ ret = 0;
+
+err_close:
+ close(fd);
+
+ return ret;
+}
+
+static int ppc_bbu_check_prereq(struct bbu_data *data)
+{
+ struct stat s;
+ int ret;
+
+ /*
+ * Check if the given image is a valid one
+ * FIXME: currently we have no real chance to detect if the image
+ * we got is a valid image.
+ */
+
+ ret = stat(data->devicefile, &s);
+ if (ret != 0) {
+ printf("Cannot stat '%s'. Failed with %s\n", data->devicefile,
+ strerror(-ret));
+ return ret;
+ }
+
+ if (data->len > s.st_size) {
+ printf("'%s' too large for '%s'\n", data->imagefile,
+ data->devicefile);
+ return -EINVAL;
+ }
+
+ ret = bbu_confirm(data);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+/* write a regular barebox image into an externally connected NOR flash */
+static int ppc_bbu_nor_update(struct bbu_handler *handler, struct bbu_data *data)
+{
+ int ret;
+
+ ret = ppc_bbu_check_prereq(data);
+ if (ret)
+ return ret;
+
+ return ppc_bbu_write_device(handler, data, data->image, data->len);
+}
+
+int ppc_bbu_nor_register_handler(const char *name, const char *devicefile,
+ unsigned long flags)
+{
+ struct bbu_handler *bbu;
+ int ret;
+
+ bbu = xzalloc(sizeof(*bbu));
+ bbu->devicefile = devicefile;
+ bbu->name = name;
+ bbu->flags = flags | BBU_FLAG_ERASE;
+ bbu->handler = ppc_bbu_nor_update;
+
+ ret = bbu_register_handler(bbu);
+ if (ret)
+ free(bbu);
+
+ return ret;
+}
diff --git a/arch/ppc/mach-mpc5xxx/cpu-mpc5125.c b/arch/ppc/mach-mpc5xxx/cpu-mpc5125.c
new file mode 100644
index 0000000..512e2a5
--- /dev/null
+++ b/arch/ppc/mach-mpc5xxx/cpu-mpc5125.c
@@ -0,0 +1,174 @@
+/*
+ * Copyright (C) 2014 Juergen Borleis, Pengutronix
+ *
+ * This code bases partially on:
+ * (C) Copyright 2007-2010 DENX Software Engineering
+ * Copyright (C) 2004-2006 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <common.h>
+#include <init.h>
+#include <types.h>
+#include <driver.h>
+#include <reset_source.h>
+#include <asm/processor.h>
+#include <mach/mpc5xxx.h>
+#include <asm/io.h>
+
+/* Reset Module */
+struct resetc {
+ u32 rcwl;
+ u32 rcwh;
+ u8 res0[8];
+ u32 rsr;
+ u32 rmr;
+ u32 rpr;
+ u32 rcr;
+ u32 rcer;
+};
+
+/* RSR - Reset Status Register */
+#define MPC512X_RSR_SWSR (1 << 13) /* software soft reset */
+#define MPC512X_RSR_SWHR (1 << 12) /* software hard reset */
+#define MPC512X_RSR_JHRS (1 << 9) /* jtag hreset */
+#define MPC512X_RSR_JSRS (1 << 8) /* jtag sreset status */
+#define MPC512X_RSR_CSHR (1 << 4) /* checkstop reset status */
+#define MPC512X_RSR_SWRS (1 << 3) /* software watchdog reset status */
+#define MPC512X_RSR_BMRS (1 << 2) /* bus monitop reset status */
+#define MPC512X_RSR_SRS (1 << 1) /* soft reset status */
+#define MPC512X_RSR_HRS (1 << 0) /* hard reset status */
+
+/* RMR - Reset Mode Register */
+#define MPC512X_RMR_CSRE (1 << 0) /* checkstop reset enable */
+
+/* RCR - Reset Control Register */
+#define MPC512X_RCR_SWHR (1 << 1) /* software hard reset */
+#define MPC512X_RCR_SWSR (1 << 0) /* software soft reset */
+
+/* RCER - Reset Control Enable Register */
+#define MPC512X_RCER_CRE (1 << 0) /* software hard reset */
+
+static struct resetc * const resetc = (struct resetc *)MPC512X_RESET;
+
+/* called from assembler in start.S */
+int cpu_init(void)
+{
+ /* do it very early, because its required for any delay() */
+ mpc5125_enable_time_base_counter();
+
+ /* RMR - Reset Mode Register - enable checkstop reset */
+ out_be32(&resetc->rmr, MPC512X_RMR_CSRE);
+
+ /* system performance tweaking */
+#ifdef CONFIG_SYS_ACR_PIPE_DEP
+ /* Arbiter pipeline depth */
+ out_be32(&im->arbiter.acr,
+ (im->arbiter.acr & ~ACR_PIPE_DEP) |
+ (CONFIG_SYS_ACR_PIPE_DEP << ACR_PIPE_DEP_SHIFT)
+ );
+#endif
+
+#ifdef CONFIG_SYS_ACR_RPTCNT
+ /* Arbiter repeat count */
+ out_be32(im->arbiter.acr,
+ (im->arbiter.acr & ~(ACR_RPTCNT)) |
+ (CONFIG_SYS_ACR_RPTCNT << ACR_RPTCNT_SHIFT)
+ );
+#endif
+
+#if 0
+ /* Set IPS-CSB divider: IPS = 1/2 CSB */
+ ips_div = in_be32(&im->clk.scfr[0]);
+ ips_div &= ~(SCFR1_IPS_DIV_MASK);
+ ips_div |= SCFR1_IPS_DIV << SCFR1_IPS_DIV_SHIFT;
+ out_be32(&im->clk.scfr[0], ips_div);
+#endif
+#ifdef SCFR1_LPC_DIV
+ clrsetbits_be32(&im->clk.scfr[0], SCFR1_LPC_DIV_MASK,
+ SCFR1_LPC_DIV << SCFR1_LPC_DIV_SHIFT);
+#endif
+ return 0;
+}
+
+void __noreturn reset_cpu(unsigned long addr)
+{
+ unsigned msr;
+
+ /* Interrupts and MMU off */
+ __asm__ __volatile__ ("mfmsr %0":"=r" (msr):);
+
+ msr &= ~( MSR_EE | MSR_IR | MSR_DR);
+ __asm__ __volatile__ ("mtmsr %0"::"r" (msr));
+
+ /* Enable Reset Control Reg - "RSTE" is the magic word that let us go */
+ out_be32(&resetc->rpr, 0x52535445);
+
+ /* Verify Reset Control Reg is enabled */
+ while (!(in_be32(&resetc->rcer) & MPC512X_RCER_CRE))
+ ;
+
+ udelay(200);
+
+ /* Perform reset */
+ out_be32(&resetc->rcr, MPC512X_RCR_SWHR);
+
+ while(1)
+ ;
+}
+
+/*
+ * the watchdog is always active after reset. To control it we can
+ * write to its 'control register' - but only once. So, after disabling it
+ * there is no way to re-enable it without a hard reset.
+ * If the user don't want to use the watchdog feature, disable it here
+ * forever. If the user wants to use it, start to pet it by registering
+ * the corresponding driver.
+ * The default timeout value after reset is about 130 seconds.
+ * This gives us the time to handle the watchdog at a reasonable
+ * point of initialization time.
+ */
+static int mpc5125_handle_watchdog(void)
+{
+ if (IS_ENABLED(CONFIG_WATCHDOG_MPC5125))
+ add_generic_device("mpc5125wd", 0, NULL, MPC512X_WDT,
+ 0x10, IORESOURCE_MEM, NULL);
+ else
+ out_be32((void *)(MPC512X_WDT + 4), 0); /* disable it */
+
+ return 0;
+}
+device_initcall(mpc5125_handle_watchdog);
+
+/* detect the reset source after the framework is up and running */
+static int mpc5125_keep_reset_cause(void)
+{
+ u32 reg;
+
+ reg = in_be32(&resetc->rsr);
+ if (IS_ENABLED(CONFIG_RESET_SOURCE)) {
+ if (reg & MPC512X_RSR_HRS)
+ reset_source_set(RESET_POR);
+ else if (reg & MPC512X_RSR_SRS)
+ reset_source_set(RESET_RST);
+ else if (reg & MPC512X_RSR_SWRS)
+ reset_source_set(RESET_WDG);
+ else if (reg & (MPC512X_RSR_JSRS | MPC512X_RSR_JHRS))
+ reset_source_set(RESET_JTAG);
+ else
+ reset_source_set(RESET_UKWN);
+ }
+ out_be32(&resetc->rsr, reg);
+
+ return 0;
+}
+device_initcall(mpc5125_keep_reset_cause);
diff --git a/arch/ppc/mach-mpc5xxx/include/mach/bbu.h b/arch/ppc/mach-mpc5xxx/include/mach/bbu.h
new file mode 100644
index 0000000..6727d42
--- /dev/null
+++ b/arch/ppc/mach-mpc5xxx/include/mach/bbu.h
@@ -0,0 +1,18 @@
+#ifndef __MACH_BBU_H
+#define __MACH_BBU_H
+
+#ifdef CONFIG_BAREBOX_UPDATE
+
+int ppc_bbu_nor_register_handler(const char *name, const char *devicefile,
+ unsigned long flags);
+
+#else /* CONFIG_BAREBOX_UPDATE */
+
+static inline int ppc_bbu_nor_register_handler(const char *name,
+ const char *devicefile, unsigned long flags)
+{
+ return -ENOSYS;
+}
+#endif
+
+#endif /* __MACH_BBU_H */
diff --git a/arch/ppc/mach-mpc5xxx/include/mach/clocks.h b/arch/ppc/mach-mpc5xxx/include/mach/clocks.h
index 717a85b..87fdbc6 100644
--- a/arch/ppc/mach-mpc5xxx/include/mach/clocks.h
+++ b/arch/ppc/mach-mpc5xxx/include/mach/clocks.h
@@ -4,6 +4,7 @@
/* common clocks */
unsigned long get_cpu_clock(void);
unsigned long get_timebase_clock(void);
+void mpc5xxx_enable_psc_clock(unsigned idx);
#if defined(CONFIG_MGT5100) || defined(CONFIG_MPC5200)
unsigned long get_bus_clock(void);
@@ -11,4 +12,12 @@ unsigned long get_ipb_clock(void);
unsigned long get_pci_clock(void);
#endif
+#ifdef CONFIG_SOC_MPC5125
+unsigned long get_ips_clock(void);
+unsigned long get_psc_clock(unsigned);
+void mpc5125_enable_psc_fifo_clock(void);
+void mpc5xxx_enable_fec_clock(unsigned idx);
+unsigned long mpc5125_get_psc_clock(unsigned idx);
+#endif
+
#endif /* __ASM_ARCH_CLOCKS_H */
diff --git a/arch/ppc/mach-mpc5xxx/include/mach/mpc512x.h b/arch/ppc/mach-mpc5xxx/include/mach/mpc512x.h
new file mode 100644
index 0000000..ed60f2a
--- /dev/null
+++ b/arch/ppc/mach-mpc5xxx/include/mach/mpc512x.h
@@ -0,0 +1,321 @@
+/*
+ * Copyright (C) 2014 Juergen Borleis, Pengutronix
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __MPC512X_H__
+#define __MPC512X_H__
+
+#include <asm/types.h>
+#include <sizes.h>
+
+/* reset default */
+#define DEFAULT_MBAR 0xff400000
+
+/*
+ * Memory map after reset:
+ *
+ * 0x00000000 - 0x007fffff LPB-ROM (when BMS = 0)
+ * 0x10000000 - 0x13ffffff system main memory area
+ * 0x30000000 - 0x3001ffff SRAM
+ * 0x40000000 - 0x400fffff NFC
+ * 0xff400000 - 0xff4fffff MBAR + IO area
+ *
+ * Memory map after _start in start.S run:
+ *
+ * 0x00000000 ... 0x7fffffff system main memory area
+ * 0xf0000000 ... 0xf00fffff MBAR + IO area (1 MiB)
+ * 0xf0500000 ... 0xff53ffff SRAM (256 kiB)
+ * 0xf0600000 ... 0xff6fffff NFC (1 MiB)
+ * 0xfe000000 ... 0xffffffff ROM (32 MiB)
+ */
+
+#define CFG_MBAR 0xf0000000
+#define CFG_ROM_LOC 0xfe000000
+#define CFG_ROM_SZ SZ_8M
+#define CFG_SRAM_LOC 0xf0500000
+# define MPC5XXX_SRAM CFG_SRAM_LOC
+#define CFG_SRAM_SZ SZ_32K
+# define MPC5XXX_SRAM_SIZE CFG_SRAM_SZ
+#define CFG_NFC_LOC 0xf0600000
+
+#define DEFAULT_DRAM_BASE 0x00000000
+
+/* base address is IMMBAR */
+#define MPC512X_RESET (CFG_MBAR + 0x00E00)
+#define MPC512X_CLKM (CFG_MBAR + 0x00f00)
+#define MPC512X_WDT (CFG_MBAR + 0x00900)
+#define MPC512X_FEC1 (CFG_MBAR + 0x02800)
+#define MPC512X_FEC2 (CFG_MBAR + 0x04800)
+#define MPC512X_DRAMC (CFG_MBAR + 0x09000)
+#define MPC512X_IOC (CFG_MBAR + 0x0A000)
+#define MPC512X_LPC (CFG_MBAR + 0x10000)
+#define MPC512X_PSC0 (CFG_MBAR + 0x11000)
+#define MPC512X_PSC1 (CFG_MBAR + 0x11100)
+#define MPC512X_PSC2 (CFG_MBAR + 0x11200)
+#define MPC512X_PSC3 (CFG_MBAR + 0x11300)
+#define MPC512X_PSC4 (CFG_MBAR + 0x11400)
+#define MPC512X_PSC5 (CFG_MBAR + 0x11500)
+#define MPC512X_PSC6 (CFG_MBAR + 0x11600)
+#define MPC512X_PSC7 (CFG_MBAR + 0x11700)
+#define MPC512X_PSC8 (CFG_MBAR + 0x11800)
+#define MPC512X_PSC9 (CFG_MBAR + 0x11900)
+#define MPC512X_FIFOC (CFG_MBAR + 0x11f00)
+
+/* System reset offset (PowerPC standard) */
+#define EXC_OFF_SYS_RESET 0x0100
+#define _START_OFFSET EXC_OFF_SYS_RESET
+
+/* some register offsets from the "Local Access Register Memory Map" */
+#define LPBAW_OFFSET 0x20
+#define LPCS0AW_OFFSET 0x24
+#define SRAMBAR_OFFSET 0xc4
+#define NFSCBAR_OFFSET 0xc8
+#define SWCRR_OFFSET 0x0904
+#define CS_CR_OFFSET 0x20
+
+#ifndef CFG_HID0_INIT
+# define CFG_HID0_INIT HID0_ICE | HID0_ICFI
+#endif
+#ifndef CFG_HID0_FINAL
+# define CFG_HID0_FINAL HID0_ICE
+#endif
+#ifndef CFG_SYS_HID2
+# define CFG_SYS_HID2 HID2_HBE
+#endif
+
+#ifndef __ASSEMBLY__
+
+void mpc5125_setup_access_window(unsigned cs, unsigned start, unsigned size);
+void mpc5125_setup_ram_memory_window(unsigned base, unsigned size);
+unsigned mpc5xxx_get_sdram_size(void);
+void mpc5125_enable_time_base_counter(void);
+
+void mpc5125_setup_ram_memory_window(unsigned base, unsigned size);
+
+enum mpc5125_pinmux_id {
+ io_control_mem = 0,
+ io_control_lpc_clk = 4,
+ io_control_lpc_oe,
+ io_control_lpc_rw,
+ io_control_lpc_cs0,
+ io_control_lpc_ack,
+ io_control_lpc_ax03 = 9,
+ io_control_emb_ax02,
+ io_control_emb_ax01,
+ io_control_emb_ax00 = 12,
+ io_control_emb_ad31 = 13,
+ io_control_emb_ad30,
+ io_control_emb_ad29,
+ io_control_emb_ad28,
+ io_control_emb_ad27,
+ io_control_emb_ad26,
+ io_control_emb_ad25,
+ io_control_emb_ad24,
+ io_control_emb_ad23,
+ io_control_emb_ad22,
+ io_control_emb_ad21,
+ io_control_emb_ad20,
+ io_control_emb_ad19,
+ io_control_emb_ad18,
+ io_control_emb_ad17,
+ io_control_emb_ad16,
+ io_control_emb_ad15,
+ io_control_emb_ad14,
+ io_control_emb_ad13,
+ io_control_emb_ad12,
+ io_control_emb_ad11,
+ io_control_emb_ad10 = 34,
+ io_control_emb_ad9,
+ io_control_emb_ad8,
+ io_control_emb_ad7,
+ io_control_emb_ad6,
+ io_control_emb_ad5,
+ io_control_emb_ad4,
+ io_control_emb_ad3,
+ io_control_emb_ad2,
+ io_control_emb_ad1,
+ io_control_emb_ad0 = 44,
+ io_control_nfc_ce0 = 45,
+ io_control_nfc_rb,
+ io_control_dui_clk,
+ io_control_dui_de,
+ io_control_dui_hsync = 49,
+ io_control_dui_vsync,
+ io_control_dui_ld0 = 51,
+ io_control_dui_ld1,
+ io_control_dui_ld2,
+ io_control_dui_ld3,
+ io_control_dui_ld4,
+ io_control_dui_ld5,
+ io_control_dui_ld6,
+ io_control_dui_ld7,
+ io_control_dui_ld8,
+ io_control_dui_ld9,
+ io_control_dui_ld10,
+ io_control_dui_ld11,
+ io_control_dui_ld12,
+ io_control_dui_ld13,
+ io_control_dui_ld14,
+ io_control_dui_ld15,
+ io_control_dui_ld16,
+ io_control_dui_ld17,
+ io_control_dui_ld18,
+ io_control_dui_ld19,
+ io_control_dui_ld20,
+ io_control_dui_ld21,
+ io_control_dui_ld22,
+ io_control_dui_ld23 = 74,
+ io_control_i2c2_scl = 75,
+ io_control_i2c2_sda = 76,
+ io_control_can1_tx = 77,
+ io_control_can2_tx = 78,
+ io_control_i2c1_scl = 79,
+ io_control_i2c1_sda = 80,
+/* No pin control register for can1_rx and can2_rx */
+ io_control_fec1_txd2 = 81,
+ io_control_fec1_txd3,
+ io_control_fec1_rxd2,
+ io_control_fec1_rxd3,
+ io_control_fec1_crs,
+ io_control_fec1_txerr,
+ io_control_fec1_rxd1,
+ io_control_fec1_txd1,
+ io_control_fec1_mdc,
+ io_control_fec1_rxerr,
+ io_control_fec1_mdio,
+ io_control_fec1_rxd0,
+ io_control_fec1_txd0,
+ io_control_fec1_txclk,
+ io_control_fec1_rxclk,
+ io_control_fec1_rxdv,
+ io_control_fec1_txen,
+ io_control_fec1_col,
+ io_control_usb1_data0 = 99,
+ io_control_usb1_data1,
+ io_control_usb1_data2,
+ io_control_usb1_data3,
+ io_control_usb1_data4,
+ io_control_usb1_data5,
+ io_control_usb1_data6,
+ io_control_usb1_data7,
+ io_control_usb1_stop,
+ io_control_usb1_clk,
+ io_control_usb1_next,
+ io_control_usb1_dir,
+ io_control_sdhc1_clk = 111,
+ io_control_sdhc1_cmd,
+ io_control_sdhc1_d0,
+ io_control_sdhc1_d1,
+ io_control_sdhc1_d2,
+ io_control_sdhc1_d3,
+ io_control_psc_mclk_in,
+ io_control_psc0_0 = 118,
+ io_control_psc0_1,
+ io_control_psc0_2,
+ io_control_psc0_3,
+ io_control_psc0_4,
+ io_control_psc1_0,
+ io_control_psc1_1,
+ io_control_psc1_2,
+ io_control_psc1_3,
+ io_control_psc1_4,
+ io_control_j1850_tx,
+ io_control_j1850_rx,
+};
+
+#define MPC5125_ALTF_0 (0x0 << 5)
+#define MPC5125_ALTF_1 (0x1 << 5)
+#define MPC5125_ALTF_2 (0x2 << 5)
+#define MPC5125_ALTF_3 (0x3 << 5)
+#define MPC5125_PULL_UP (1 << 4)
+#define MPC5125_PULL_DOWN (0 << 4)
+#define MPC5125_PUD_ENA (1 << 3)
+#define MPC5125_ST_ENA (1 << 2)
+
+/*
+ * from the MPC5125 revision 4 (09/2011) datasheet
+ * Slew rate definition for general IOs:
+ * - configuration 0: 140/183 ns
+ * - configuration 1: 19/24 ns
+ * - configuration 2: 9.8/12 ns
+ * - configuration 3: 1.4/1.6 ns
+ */
+#define MPC5125_SLEW_RATE(x) ((x) & 0x03)
+
+void mpc5125_mux_pin(enum mpc5125_pinmux_id idx, unsigned char mux);
+
+/* SDRAM commands */
+#define DRAM_CMD_NOP 0x01380000
+#define DRAM_CMD_PCHG_ALL 0x01100400
+#define DRAM_CMD_EM2 0x01020000
+#define DRAM_CMD_EM3 0x01030000
+#define DRAM_CMD_EN_DLL 0x01010000
+#define DRAM_CMD_RFSH 0x01080000
+
+#define DDR_COMMAND_CMD_REQ (1 << 24)
+#define DDR_COMMAND_CMD_MSR (0 << 16)
+#define DDR_COMMAND_CMD_EMR1 (1 << 16)
+#define DDR_COMMAND_CMD_EMR2 (2 << 16)
+#define DDR_COMMAND_CMD_EMR3 (3 << 16)
+#define DDR_COMMAND_RST_DLL (1 << 8)
+
+struct sdram_prio {
+ unsigned prioman_config1;
+ unsigned prioman_config2;
+ unsigned hiprio_config;
+ unsigned lut_table0_main_upper;
+ unsigned lut_table0_main_lower;
+ unsigned lut_table1_main_upper;
+ unsigned lut_table1_main_lower;
+ unsigned lut_table2_main_upper;
+ unsigned lut_table2_main_lower;
+ unsigned lut_table3_main_upper;
+ unsigned lut_table3_main_lower;
+ unsigned lut_table4_main_upper;
+ unsigned lut_table4_main_lower;
+ unsigned lut_table0_alt_upper;
+ unsigned lut_table0_alt_lower;
+ unsigned lut_table1_alt_upper;
+ unsigned lut_table1_alt_lower;
+ unsigned lut_table2_alt_upper;
+ unsigned lut_table2_alt_lower;
+ unsigned lut_table3_alt_upper;
+ unsigned lut_table3_alt_lower;
+ unsigned lut_table4_alt_upper;
+ unsigned lut_table4_alt_lower;
+};
+
+struct sdram_conf {
+ struct sdram_prio prio;
+ unsigned mux_ddr;
+ unsigned sys_cfg;
+ unsigned tim_cfg0, tim_cfg1, tim_cfg2;
+ unsigned size;
+ const unsigned *cmds;
+};
+
+void mpc5125_init_sdram(const struct sdram_conf *init_sequence);
+
+struct lpc_config {
+ unsigned cs_ale_timing;
+ unsigned cs_burst;
+ unsigned cs_dead_cyle;
+ unsigned cs_hold_cycle;
+};
+
+void mpc5125_configure_lpc(const struct lpc_config *c);
+void mpc5125_setup_cs(unsigned, unsigned, unsigned, unsigned);
+
+#endif /* __ASSEMBLY__ */
+
+#endif /* __MPC512X_H__ */
diff --git a/arch/ppc/mach-mpc5xxx/include/mach/mpc512x_fec.h b/arch/ppc/mach-mpc5xxx/include/mach/mpc512x_fec.h
new file mode 100644
index 0000000..ddac8e5
--- /dev/null
+++ b/arch/ppc/mach-mpc5xxx/include/mach/mpc512x_fec.h
@@ -0,0 +1,46 @@
+#include <linux/types.h>
+
+/* FEC */
+struct fec {
+ u32 fec_id; /* FEC_ID register */
+ u32 ievent; /* Interrupt event register */
+ u32 imask; /* Interrupt mask register */
+ u32 reserved_01;
+ u32 r_des_active; /* Receive ring updated flag */
+ u32 x_des_active; /* Transmit ring updated flag */
+ u32 reserved_02[3];
+ u32 ecntrl; /* Ethernet control register */
+ u32 reserved_03[6];
+ u32 mii_data; /* MII data register */
+ u32 mii_speed; /* MII speed register */
+ u32 reserved_04[7];
+ u32 mib_control; /* MIB control/status register */
+ u32 reserved_05[7];
+ u32 r_cntrl; /* Receive control register */
+ u32 r_hash; /* Receive hash */
+ u32 reserved_06[14];
+ u32 x_cntrl; /* Transmit control register */
+ u32 reserved_07[7];
+ u32 paddr1; /* Physical address low */
+ u32 paddr2; /* Physical address high + type field */
+ u32 op_pause; /* Opcode + pause duration */
+ u32 reserved_08[10];
+ u32 iaddr1; /* Upper 32 bits of individual hash table */
+ u32 iaddr2; /* Lower 32 bits of individual hash table */
+ u32 gaddr1; /* Upper 32 bits of group hash table */
+ u32 gaddr2; /* Lower 32 bits of group hash table */
+ u32 reserved_09[7];
+ u32 x_wmrk; /* Transmit FIFO watermark */
+ u32 reserved_10;
+ u32 r_bound; /* End of RAM */
+ u32 r_fstart; /* Receive FIFO start address */
+ u32 reserved_11[11];
+ u32 r_des_start; /* Beginning of receive descriptor ring */
+ u32 x_des_start; /* Pointer to beginning of transmit descriptor ring */
+ u32 r_buff_size; /* Receive buffer size */
+ u32 reserved_12[26];
+ u32 dma_control; /* DMA control for IP bus, AMBA IF + DMA revision */
+ u32 reserved_13[2];
+ u32 mib[128]; /* MIB Block Counters */
+ u32 fifo[256]; /* used by FEC, can only be accessed by DMA */
+};
diff --git a/arch/ppc/mach-mpc5xxx/include/mach/mpc5xxx.h b/arch/ppc/mach-mpc5xxx/include/mach/mpc5xxx.h
index 2455484..f5f0a75 100644
--- a/arch/ppc/mach-mpc5xxx/include/mach/mpc5xxx.h
+++ b/arch/ppc/mach-mpc5xxx/include/mach/mpc5xxx.h
@@ -1,8 +1,10 @@
-#ifndef __ASMPPC_MPC5XXX_H
-#define __ASMPPC_MPC5XXX_H
+#ifndef __MACH_MPC5XXX_H
+#define __MACH_MPC5XXX_H
#if defined(CONFIG_MPC5200) || defined(CONFIG_MGT5100)
# include <mach/mpc5200.h>
#else
# error "Undefined Core CPU"
#endif
+
+#endif /* __MACH_MPC5XXX_H */
diff --git a/arch/ppc/mach-mpc5xxx/iomux-mpc5125.c b/arch/ppc/mach-mpc5xxx/iomux-mpc5125.c
new file mode 100644
index 0000000..a52010e
--- /dev/null
+++ b/arch/ppc/mach-mpc5xxx/iomux-mpc5125.c
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2014 Juergen Borleis, Pengutronix
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <common.h>
+#include <init.h>
+#include <asm/io.h>
+#include <mach/mpc5xxx.h>
+
+static u8 * const ioc = (u8 * )MPC512X_IOC;
+
+void mpc5125_mux_pin(enum mpc5125_pinmux_id idx, unsigned char mux)
+{
+ out_8(&ioc[idx], mux);
+}
+
+#define IOC_GB_OBE (1 << 0)
+
+static int mpc5125_mux_init(void)
+{
+ /*
+ * Note: all default muxed pins/features which are outputs are
+ * *tristated* after reset. Enable them right now
+ */
+ out_8(&ioc[1], IOC_GB_OBE);
+
+ return 0;
+}
+coredevice_initcall(mpc5125_mux_init);
diff --git a/arch/ppc/mach-mpc5xxx/lpc-mpc5125.c b/arch/ppc/mach-mpc5xxx/lpc-mpc5125.c
new file mode 100644
index 0000000..0e602d5
--- /dev/null
+++ b/arch/ppc/mach-mpc5xxx/lpc-mpc5125.c
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2014 Juergen Borleis, Pengutronix
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <common.h>
+#include <types.h>
+#include <mach/mpc5xxx.h>
+#include <asm/io.h>
+
+/* LPC */
+struct lpc {
+ u32 cs_cfg[8]; /* Chip Select N Configuration Registers
+ No dedicated entry for CS Boot as == CS0 */
+ u32 cs_cr; /* Chip Select Control Register */
+ u32 cs_sr; /* Chip Select Status Register */
+ u32 cs_bcr; /* Chip Select Burst Control Register */
+ u32 cs_dccr; /* Chip Select Deadcycle Control Register */
+ u32 cs_hccr; /* Chip Select Holdcycle Control Register */
+ u32 altr; /* Address Latch Timing Register */
+ u8 res0[0xc8];
+ u32 sclpc_psr; /* SCLPC Packet Size Register */
+ u32 sclpc_sar; /* SCLPC Start Address Register */
+ u32 sclpc_cr; /* SCLPC Control Register */
+ u32 sclpc_er; /* SCLPC Enable Register */
+ u32 sclpc_nar; /* SCLPC NextAddress Register */
+ u32 sclpc_sr; /* SCLPC Status Register */
+ u32 sclpc_bdr; /* SCLPC Bytes Done Register */
+ u32 emb_scr; /* EMB Share Counter Register */
+ u32 emb_pcr; /* EMB Pause Control Register */
+ u8 res1[0x1c];
+ u32 lpc_fdwr; /* LPC RX/TX FIFO Data Word Register */
+ u32 lpc_fsr; /* LPC RX/TX FIFO Status Register */
+ u32 lpc_cr; /* LPC RX/TX FIFO Control Register */
+ u32 lpc_ar; /* LPC RX/TX FIFO Alarm Register */
+};
+
+static struct lpc * const lpc = (struct lpc *)MPC512X_LPC;
+
+void mpc5125_setup_access_window(unsigned cs, unsigned start, unsigned size);
+
+/* setup one CS line at the LPC bus */
+void mpc5125_setup_cs(unsigned cs, unsigned start, unsigned size, unsigned cfg)
+{
+ /* access window first */
+ mpc5125_setup_access_window(cs, start, size);
+
+ /* access method and timing */
+ out_be32(&lpc->cs_cfg[cs], cfg);
+}
+
+void mpc5125_configure_lpc(const struct lpc_config *c)
+{
+ /* enable the LPC feature */
+ setbits_be32(&lpc->cs_cr, 0x01000000);
+
+ if (c == NULL)
+ return; /* keep the defaults */
+
+ out_be32(&lpc->altr, c->cs_ale_timing);
+ out_be32(&lpc->cs_bcr, c->cs_burst);
+ out_be32(&lpc->cs_dccr, c->cs_dead_cyle);
+ out_be32(&lpc->cs_hccr, c->cs_hold_cycle);
+}
diff --git a/arch/ppc/mach-mpc5xxx/sdram-mpc5125.c b/arch/ppc/mach-mpc5xxx/sdram-mpc5125.c
new file mode 100644
index 0000000..9fc3723
--- /dev/null
+++ b/arch/ppc/mach-mpc5xxx/sdram-mpc5125.c
@@ -0,0 +1,269 @@
+/*
+ * Copyright (C) 2014 Juergen Borleis, Pengutronix
+ *
+ * This code bases partially on:
+ * (C) Copyright 2007-2009 DENX Software Engineering
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <common.h>
+#include <types.h>
+#include <mach/mpc5xxx.h>
+#include <asm/io.h>
+
+/* register description of the MPC5125 memory controller */
+struct mddrc {
+ u32 ddr_sys_config;
+ u32 ddr_time_config0;
+ u32 ddr_time_config1;
+ u32 ddr_time_config2;
+ u32 ddr_command;
+ u32 ddr_compact_command;
+ u32 self_refresh_cmd_0;
+ u32 self_refresh_cmd_1;
+ u32 self_refresh_cmd_2;
+ u32 self_refresh_cmd_3;
+ u32 self_refresh_cmd_4;
+ u32 self_refresh_cmd_5;
+ u32 self_refresh_cmd_6;
+ u32 self_refresh_cmd_7;
+ u32 dqs_config_offset_count;
+ u32 dqs_config_offset_time;
+ u32 DQS_delay_status;
+ u32 res0[0xF];
+ u32 prioman_config1;
+ u32 prioman_config2;
+ u32 hiprio_config;
+ u32 lut_table0_main_upper;
+ u32 lut_table1_main_upper;
+ u32 lut_table2_main_upper;
+ u32 lut_table3_main_upper;
+ u32 lut_table4_main_upper;
+ u32 lut_table0_main_lower;
+ u32 lut_table1_main_lower;
+ u32 lut_table2_main_lower;
+ u32 lut_table3_main_lower;
+ u32 lut_table4_main_lower;
+ u32 lut_table0_alt_upper;
+ u32 lut_table1_alt_upper;
+ u32 lut_table2_alt_upper;
+ u32 lut_table3_alt_upper;
+ u32 lut_table4_alt_upper;
+ u32 lut_table0_alt_lower;
+ u32 lut_table1_alt_lower;
+ u32 lut_table2_alt_lower;
+ u32 lut_table3_alt_lower;
+ u32 lut_table4_alt_lower;
+ u32 performance_monitor_config;
+ u32 event_time_counter;
+ u32 event_time_preset;
+ u32 performance_monitor1_address_low;
+ u32 performance_monitor2_address_low;
+ u32 performance_monitor1_address_hi;
+ u32 performance_monitor2_address_hi;
+ u32 res1[2];
+ u32 performance_monitor1_read_counter;
+ u32 performance_monitor2_read_counter;
+ u32 performance_monitor1_write_counter;
+ u32 performance_monitor2_write_counter;
+ u32 granted_ack_counter0;
+ u32 granted_ack_counter1;
+ u32 granted_ack_counter2;
+ u32 granted_ack_counter3;
+ u32 granted_ack_counter4;
+ u32 cumulative_wait_counter0;
+ u32 cumulative_wait_counter1;
+ u32 cumulative_wait_counter2;
+ u32 cumulative_wait_counter3;
+ u32 cumulative_wait_counter4;
+ u32 summed_priority_counter0;
+ u32 summed_priority_counter1;
+ u32 summed_priority_counter2;
+ u32 summed_priority_counter3;
+ u32 summed_priority_counter4;
+};
+
+/* MDDRC SYS CFG and Timing CFG0 Registers */
+#define MDDRC_SYS_CFG_EN 0xF0000000
+#define MDDRC_SYS_CFG_CKE_MASK 0x40000000
+#define MDDRC_SYS_CFG_CMD_MASK 0x10000000
+#define MDDRC_REFRESH_ZERO_MASK 0x0000FFFF
+
+#define DRAM_DSC_CMD_MODE (1 << 28)
+#define DRAM_DSC_CLK_ON (1 << 29)
+#define DRAM_DSC_CKE (1 << 30)
+#define DRAM_DSC_RST_B (1 << 31)
+
+static struct mddrc * const dramc = (struct mddrc *)MPC512X_DRAMC;
+
+static const unsigned char page_addr[16] = {
+ 10, 11, 11, 12, 12, 13, 13, 14, 14, 24, 24, 25, 25, 26, 17, 28,
+};
+
+static const unsigned char bank_addr[16] = {
+ 2, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 3, 3, 3,
+};
+
+static const unsigned char row_addr[8] = {
+ 16, 16, 16, 16, 16, 16, 15, 14,
+};
+
+/* note: don't call when already running from SDRAM */
+static unsigned detect_real_memory_size(unsigned slice_count, unsigned full_count)
+{
+ void *p;
+ unsigned u, cnt;
+
+ for (u = full_count - 1; u >= slice_count; u--) {
+ p = (void *)((1 << u) + DEFAULT_DRAM_BASE);
+ out_8(p, u);
+ }
+
+ cnt = in_8((void*)DEFAULT_DRAM_BASE);
+ return 1 << cnt;
+}
+
+/*static*/ const void *fix_main_address(const void *init_sequence)
+{
+ unsigned linked_address = (unsigned)init_sequence;
+ unsigned real_address;
+
+ /* FIXME use get_runtime_offset() instead */
+ real_address = linked_address - CONFIG_TEXT_BASE;
+ real_address += CFG_ROM_LOC;
+
+ return (const void *)real_address;
+}
+
+/*
+ * Note: this function depends on the possibility to map up to
+ * the full 2 GiB memory area (e.g. special mapping must exist)
+ */
+/*static*/ unsigned mpc5125_detect_sdram_size(void)
+{
+ size_t pagei, banki, rowi;
+ unsigned addr_cnt, slice_count, reg;
+ const unsigned char *p;
+
+ reg = in_be32(&dramc->ddr_sys_config);
+ pagei = banki = (reg >> 21) & 0xf;
+ rowi = (reg >> 25) & 0x7;
+
+ p = fix_main_address(&page_addr[pagei]);
+ addr_cnt = *p;
+ p = fix_main_address(&bank_addr[banki]);
+ addr_cnt += *p;
+ slice_count = addr_cnt;
+ p = fix_main_address(&row_addr[rowi]);
+ addr_cnt += *p;
+
+ /* enable up to the full possible SDRAM access window for size detection */
+ mpc5125_setup_ram_memory_window(DEFAULT_DRAM_BASE, 1 << addr_cnt);
+ return detect_real_memory_size(slice_count, addr_cnt);
+}
+
+/*static */void setup_priority_manager(const struct sdram_conf *init_sequence)
+{
+ out_be32(&dramc->prioman_config1, init_sequence->prio.prioman_config1);
+ out_be32(&dramc->prioman_config2, init_sequence->prio.prioman_config2);
+ out_be32(&dramc->hiprio_config, init_sequence->prio.hiprio_config);
+ out_be32(&dramc->lut_table0_main_upper, init_sequence->prio.lut_table0_main_upper);
+ out_be32(&dramc->lut_table0_main_lower, init_sequence->prio.lut_table0_main_lower);
+ out_be32(&dramc->lut_table1_main_upper, init_sequence->prio.lut_table1_main_upper);
+ out_be32(&dramc->lut_table1_main_lower, init_sequence->prio.lut_table1_main_lower);
+ out_be32(&dramc->lut_table2_main_upper, init_sequence->prio.lut_table2_main_upper);
+ out_be32(&dramc->lut_table2_main_lower, init_sequence->prio.lut_table2_main_lower);
+ out_be32(&dramc->lut_table3_main_upper, init_sequence->prio.lut_table3_main_upper);
+ out_be32(&dramc->lut_table3_main_lower, init_sequence->prio.lut_table3_main_lower);
+ out_be32(&dramc->lut_table4_main_upper, init_sequence->prio.lut_table4_main_upper);
+ out_be32(&dramc->lut_table4_main_lower, init_sequence->prio.lut_table4_main_lower);
+ out_be32(&dramc->lut_table0_alt_upper, init_sequence->prio.lut_table0_alt_upper);
+ out_be32(&dramc->lut_table0_alt_lower, init_sequence->prio.lut_table0_alt_lower);
+ out_be32(&dramc->lut_table1_alt_upper, init_sequence->prio.lut_table1_alt_upper);
+ out_be32(&dramc->lut_table1_alt_lower, init_sequence->prio.lut_table1_alt_lower);
+ out_be32(&dramc->lut_table2_alt_upper, init_sequence->prio.lut_table2_alt_upper);
+ out_be32(&dramc->lut_table2_alt_lower, init_sequence->prio.lut_table2_alt_lower);
+ out_be32(&dramc->lut_table3_alt_upper, init_sequence->prio.lut_table3_alt_upper);
+ out_be32(&dramc->lut_table3_alt_lower, init_sequence->prio.lut_table3_alt_lower);
+ out_be32(&dramc->lut_table4_alt_upper, init_sequence->prio.lut_table4_alt_upper);
+ out_be32(&dramc->lut_table4_alt_lower, init_sequence->prio.lut_table4_alt_lower);
+}
+
+/* depends on an enabled core internal timer ('TBEN' in 'SPCR') */
+void mpc5125_low_level_delay(unsigned ticks)
+{
+ uint64_t timeval = get_ticks();
+
+ while ((get_ticks() - timeval) < ticks)
+ ;
+}
+
+#define TICKS_PER_US 50
+
+/*static */void startup_dram(const struct sdram_conf *init_sequence)
+{
+ unsigned reg = init_sequence->sys_cfg & ~DRAM_DSC_CKE;
+
+ /*
+ * the "enable" combination: DRAM controller out of reset,
+ * clock enabled, command mode -- BUT leave CKE low for now
+ */
+ reg |= DRAM_DSC_RST_B | DRAM_DSC_CLK_ON | DRAM_DSC_CMD_MODE;
+ out_be32(&dramc->ddr_sys_config, reg);
+
+ /* maintain 500 microseconds of stable power and clock */
+ mpc5125_low_level_delay(500 * TICKS_PER_US);
+
+ /* apply a NOP, it shouldn't harm */
+ out_be32(&dramc->ddr_command, DRAM_CMD_NOP);
+
+ /* now assert CKE (high) */
+ reg |= DRAM_DSC_CKE;
+ out_be32(&dramc->ddr_sys_config, reg);
+}
+
+void mpc5125_init_sdram(const struct sdram_conf *init_sequence)
+{
+ unsigned msize;
+ const unsigned *cmds;
+ size_t u;
+
+ init_sequence = fix_main_address(init_sequence);
+
+ mpc5125_mux_pin(io_control_mem, init_sequence->mux_ddr);
+ startup_dram(init_sequence);
+ setup_priority_manager(init_sequence);
+
+ /* start to setup the external memory */
+ out_be32(&dramc->ddr_time_config0, init_sequence->tim_cfg0 &
+ MDDRC_REFRESH_ZERO_MASK);
+ out_be32(&dramc->ddr_time_config1, init_sequence->tim_cfg1);
+ out_be32(&dramc->ddr_time_config2, init_sequence->tim_cfg2);
+
+ cmds = fix_main_address(&init_sequence->cmds[0]);
+
+ /* Initialize memory with supplied init sequence */
+ for (u = 0; u < init_sequence->size; u++)
+ out_be32(&dramc->ddr_command, cmds[u]);
+
+ /* Start DDRC with final settings */
+ out_be32(&dramc->ddr_time_config0, init_sequence->tim_cfg0);
+ out_be32(&dramc->ddr_sys_config, init_sequence->sys_cfg);
+
+ /* Allow for the DLL to startup before accessing data */
+ mpc5125_low_level_delay(1000 * TICKS_PER_US);
+
+ msize = mpc5125_detect_sdram_size();
+
+ /* size and move the memory to its final destination */
+ mpc5125_setup_ram_memory_window(DEFAULT_DRAM_BASE, msize);
+}
diff --git a/arch/ppc/mach-mpc5xxx/speed-mpc5125.c b/arch/ppc/mach-mpc5xxx/speed-mpc5125.c
new file mode 100644
index 0000000..66d0e88
--- /dev/null
+++ b/arch/ppc/mach-mpc5xxx/speed-mpc5125.c
@@ -0,0 +1,209 @@
+/*
+ * Copyright (C) 2014 Juergen Borleis, Pengutronix
+ *
+ * This code bases partially on:
+ * (C) Copyright 2000-2009
+ * Wolfgang Denk, DENX Software Engineering, wd at denx.de.
+ * Copyright (C) 2004-2006 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <common.h>
+#include <init.h>
+#include <types.h>
+#include <asm/io.h>
+#include <mach/mpc512x.h>
+
+/* Clock Module register description */
+struct clkm {
+ u32 spmr; /* System PLL Mode Register */
+ u32 sccr[2]; /* System Clock Control Registers */
+ u32 scfr[2]; /* System Clock Frequency Registers */
+ u8 res0[4];
+ u32 bcr; /* Bread Crumb Register */
+ u32 pscccr[12]; /* PSC0-11 Clock Control Registers */
+ u32 spccr; /* SPDIF Clock Control Register */
+ u32 cccr; /* CFM Clock Control Register */
+ u32 dccr; /* DIU Clock Control Register */
+ u32 msccr[4]; /* MSCAN1-4 Clock Control Registers */
+};
+
+#define SPMR_SPMF 0x0F000000
+#define SPMR_SPMF_SHIFT 24
+#define SPMR_CPMF 0x000F0000
+#define SPMR_CPMF_SHIFT 16
+
+#define SCFR1_IPS_DIV_MASK 0x03800000
+#define SCFR1_IPS_DIV_SHIFT 23
+
+#define SCFR2_SYS_DIV 0xFC000000
+#define SCFR2_SYS_DIV_SHIFT 26
+
+#define SCCR_EN_CLK_FEC1 (1 << 13)
+#define SCCR_EN_CLK_FEC2 (1 << 9)
+
+#define PSCCCR_MCLK_DIV_SHIFT 17
+#define PSCCCR_MCLK_DIV_MASK (0xfffe << PSCCCR_MCLK_DIV_SHIFT)
+#define PSCCCR_MCLK_EN (1 << 16)
+#define PSCCCR_MCLK_0_SRC_SHIFT 14
+#define PSCCCR_MCLK_0_SRC_MASK (3 << PSCCCR_MCLK_0_SRC_SHIFT)
+
+static struct clkm * const clkm = (struct clkm *)MPC512X_CLKM;
+
+unsigned long get_timebase_clock(void)
+{
+ return CONFIG_SYS_MPC512X_CLKIN;
+}
+
+static const unsigned char spmf_mult[] = {
+ 68, 1, 12, 16,
+ 20, 24, 28, 32,
+ 36, 40, 44, 48,
+ 52, 56, 60, 64
+};
+
+unsigned long get_pll_clk(void)
+{
+ unsigned reg;
+ size_t spmf;
+
+ reg = in_be32(&clkm->spmr);
+ spmf = (reg & SPMR_SPMF) >> SPMR_SPMF_SHIFT;
+ return get_timebase_clock() * spmf_mult[spmf];
+}
+
+static const unsigned char sys_dividors[][2] = {
+ {2, 1}, {5, 2}, {3, 1}, {7, 2}, {4, 1},
+ {9, 2}, {5, 1}, {7, 1}, {6, 1}, {8, 1},
+ {9, 1}, {11, 1}, {10, 1}, {12, 1}, {13, 1},
+ {15, 1}, {14, 1}, {16, 1}, {17, 1}, {19, 1},
+ {18, 1}, {20, 1}, {21, 1}, {23, 1}, {22, 1},
+ {24, 1}, {25, 1}, {27, 1}, {26, 1}, {28, 1},
+ {29, 1}, {31, 1}, {30, 1}, {32, 1}, {33, 1}
+};
+
+unsigned long get_sys_clk(void)
+{
+ unsigned reg;
+ size_t sys_div;
+
+ reg = in_be32(&clkm->scfr[1]);
+ sys_div = (reg & SCFR2_SYS_DIV) >> SCFR2_SYS_DIV_SHIFT;
+ return (get_pll_clk() * sys_dividors[sys_div][1]) / sys_dividors[sys_div][0];
+}
+
+static const unsigned char cpmf_mult[][2] = {
+ {0, 1}, {0, 1}, /* 0 and 1 are not valid */
+ {1, 1}, {3, 2},
+ {2, 1}, {5, 2},
+ {3, 1}, {7, 2},
+ {0, 1}, {0, 1}, /* and all above 7 are not valid too */
+ {0, 1}, {0, 1},
+ {0, 1}, {0, 1},
+ {0, 1}, {0, 1}
+};
+
+unsigned long get_cpu_clk(void)
+{
+ unsigned reg;
+ size_t cpmf;
+
+ reg = in_be32(&clkm->spmr);
+ cpmf = (reg & SPMR_CPMF) >> SPMR_CPMF_SHIFT;
+ return ((get_sys_clk() / 2) * cpmf_mult[cpmf][0]) / cpmf_mult[cpmf][1];
+}
+
+unsigned long get_ips_clock(void)
+{
+ unsigned reg;
+ unsigned long ips_div;
+
+ reg = in_be32(&clkm->scfr[0]);
+ ips_div = (reg & SCFR1_IPS_DIV_MASK) >> SCFR1_IPS_DIV_SHIFT;
+ if (ips_div == 0) {
+ /* in case we cannot get a sane IPS divisor, fail gracefully */
+ pr_debug("IPS clock: invalid divider setting!\n");
+ return 0;
+ }
+
+ return get_sys_clk() / 2 / ips_div;
+}
+
+unsigned long get_psc_clock(unsigned idx)
+{
+ unsigned reg, clk;
+ unsigned long psc_div;
+
+ reg = in_be32(&clkm->pscccr[idx]);
+ if (!(reg & PSCCCR_MCLK_EN))
+ return 0;
+
+ psc_div = (reg & PSCCCR_MCLK_DIV_MASK) >> PSCCCR_MCLK_DIV_SHIFT;
+ if (psc_div == 0) {
+ /* in case we cannot get a sane IPS divisor, fail gracefully */
+ pr_debug("PSC clock: invalid divider setting!\n");
+ return 0;
+ }
+
+ switch (reg & PSCCCR_MCLK_0_SRC_MASK) {
+ case 0x0000:
+ clk = get_ips_clock();
+ case 0x4000:
+ clk = get_timebase_clock();
+ default:
+ pr_debug("PSC clock: unknown source configured: %u\n",
+ reg & PSCCCR_MCLK_0_SRC_MASK);
+ return 0;
+ }
+
+ return clk / (psc_div + 1);
+}
+
+void mpc5125_enable_psc_fifo_clock(void)
+{
+ setbits_be32(&clkm->sccr[0], 0x8000);
+}
+
+void mpc5xxx_enable_psc_clock(unsigned idx)
+{
+ /*
+ * configure the clock for this unit, it
+ * should run at full sysclock speed (brute force...)
+ */
+ out_be32(&clkm->pscccr[idx], PSCCCR_MCLK_EN);
+ /* its now save to enable the clock */
+ setbits_be32(&clkm->sccr[0], 1 << (27 - idx));
+}
+
+void mpc5xxx_enable_fec_clock(unsigned idx)
+{
+ switch (idx) {
+ case 0:
+ setbits_be32(&clkm->sccr[0], SCCR_EN_CLK_FEC1);
+ break;
+ case 1:
+ setbits_be32(&clkm->sccr[0], SCCR_EN_CLK_FEC2);
+ break;
+ default:
+ pr_debug("Enabling clock: unknown FEC index: %u\n", idx);
+ }
+}
+
+static int mpc5125_clks(void)
+{
+ printf("PLL %lu MHz, CPU %lu MHz, Sys %lu MHz, IPS %lu MHz\n",
+ get_pll_clk() / 1000000, get_cpu_clk() / 1000000,
+ get_sys_clk() / 1000000, get_ips_clock() / 1000000);
+
+ return 0;
+}
+postconsole_initcall(mpc5125_clks);
diff --git a/arch/ppc/mach-mpc5xxx/start.S b/arch/ppc/mach-mpc5xxx/start.S
index 810a5bb..aadaa3f 100644
--- a/arch/ppc/mach-mpc5xxx/start.S
+++ b/arch/ppc/mach-mpc5xxx/start.S
@@ -28,6 +28,7 @@
#include <asm/cache.h>
#include <asm/mmu.h>
+#include <mach/mpc5xxx.h>
/* We don't want the MMU yet.
*/
@@ -88,7 +89,9 @@ setup_mbar:
lis r3, CFG_MBAR at h
ori r3, r3, CFG_MBAR at l
mtspr MBAR, r3
+#ifndef CONFIG_ARCH_MPC5125 /* MPC5200 only */
rlwinm r3, r3, 16, 16, 31
+#endif
stw r3, 0(r4)
/* Initialise the MPC5xxx processor core */
@@ -98,7 +101,81 @@ setup_mbar:
/* initialize some things that are hard to access from C */
/*--------------------------------------------------------------*/
+#ifdef CONFIG_ARCH_MPC5125
+ lis r3, CFG_MBAR at h
+ ori r3, r3, CFG_MBAR at l
+
+ /* enable the LPC based ROM access in the upper address space */
+ lis r0, CFG_ROM_LOC at h
+ ori r0, r0, (CFG_ROM_LOC + CFG_ROM_SZ - 1)@h
+ stw r0, LPCS0AW_OFFSET(r3)
+
+ /* just sync the hardware according to the manual */
+ lwz r1, LPCS0AW_OFFSET(r3)
+ isync
+
+ /*
+ * in order to make the CS0 (instead of the BOOTCS) work,
+ * we must set the LPC master bit first
+ */
+ lis r1, MPC512X_IOC at h
+ ori r1, r1, MPC512X_IOC at l
+ lwz r0, CS_CR_OFFSET(r1)
+ oris r0, r0, 0x01000000 at h
+ stw r0, CS_CR_OFFSET(r1)
+ isync
+
+ /*
+ * when we still run from lower address space, its now time to jump to
+ * the just enabled upper address space. We need this step in order
+ * to move the lower ROM window out of the way.
+ * (but only, if we not run from RAM)
+ */
+ bl 1f
+1: mflr r0
+ lis r1, CFG_ROM_LOC at h
+ cmplw r0, r1
+ bgt final_destination /* skip if already in upper address space */
+ /*
+ * to detect if we already running from RAM we just check if the
+ * BootCS setting is equal to the CS0 setting.
+ */
+ lwz r2, LPBAW_OFFSET(r3)
+ lwz r1, LPCS0AW_OFFSET(r3)
+ cmplw r1, r2
+ beq final_destination /* stay in RAM */
+ /*
+ * Jump into the upper flash memory area
+ * destination = address of 'final_destination' - TEXT_BASE + CFG_ROM_LOC at h
+ */
+ lis r0, (final_destination - TEXT_BASE + CFG_ROM_LOC)@h
+ ori r0, r0, (final_destination - TEXT_BASE + CFG_ROM_LOC)@l
+ mtlr r0
+ blr
+
+final_destination:
+ /*
+ * we are now running from the upper address space from flash or
+ * from lower address space inside RAM.
+ * Its save now to move away the flash memory access in the lower
+ * address space. To do so sync both BOOTCS and CS0 settings.
+ * For the 'inside RAM' case this should not harm.
+ */
+ lwz r1, LPCS0AW_OFFSET(r3)
+ stw r1, LPBAW_OFFSET(r3)
+ /* move NFC out of the way */
+ lis r0, CFG_NFC_LOC at h
+ stw r0, NFSCBAR_OFFSET(r3)
+
+ /* move the on-chip SRAM out of the way */
+ lis r0, CFG_SRAM_LOC at h
+ stw r0, SRAMBAR_OFFSET(r3)
+
+ /* just sync the hardware according to the manual */
+ lwz r1, SRAMBAR_OFFSET(r3)
+ isync
+#endif
/* set up stack in on-chip SRAM */
lis r1, (MPC5XXX_SRAM + MPC5XXX_SRAM_SIZE)@h
ori r1, r1, (MPC5XXX_SRAM + MPC5XXX_SRAM_SIZE)@l
@@ -116,11 +193,24 @@ setup_mbar:
/* r3: IMMR */
bl cpu_init /* run low-level CPU init code (in Flash)*/
+#ifdef CONFIG_ARCH_MPC5125
+ bl 1f
+1: mflr r0
+ lis r9, CFG_ROM_LOC at h
+ cmplw r0, r9
+ blt skip_dram_init /* skip if the RAM is already up and running */
mr r3, r21
+#endif
/* r3: BOOTFLAG */
bl initdram /* initialize sdram */
/* r3: End of RAM */
+#ifdef CONFIG_ARCH_MPC5125
+skip_dram_init:
+ bl mpc5xxx_get_sdram_size
+ subi r3,r3,1
+ /* r3: End of RAM */
+#endif
b _continue_init
/*
* Vector Table
@@ -501,7 +591,14 @@ init_5xxx_core:
ori r3, r3, CFG_HID0_FINAL at l
SYNC
mtspr HID0, r3
+#ifdef CONFIG_ARCH_MPC5125
+ lis r3, CFG_SYS_HID2 at h
+ ori r3, r3, CFG_SYS_HID2 at l
+ SYNC
+ mtspr HID2, r3
+ sync
+#else
/* clear all BAT's */
/*--------------------------------------------------------------*/
@@ -570,7 +667,7 @@ init_5xxx_core:
/* Done! */
/*--------------------------------------------------------------*/
-
+#endif
blr
/* Cache functions.
diff --git a/arch/ppc/mach-mpc5xxx/sys-mpc5125.c b/arch/ppc/mach-mpc5xxx/sys-mpc5125.c
new file mode 100644
index 0000000..c537669
--- /dev/null
+++ b/arch/ppc/mach-mpc5xxx/sys-mpc5125.c
@@ -0,0 +1,136 @@
+/*
+ * Copyright (C) 2014 Juergen Borleis, Pengutronix
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <common.h>
+#include <init.h>
+#include <types.h>
+#include <asm/io.h>
+#include <mach/mpc5xxx.h>
+
+struct law {
+ u32 bar; /* Base Addr Register */
+ u32 ar; /* Attributes Register */
+};
+
+/* System configuration registers for MPC5125 */
+struct sysconf {
+ u32 immrbar;
+ u8 res0[0x1c];
+ u32 lpbaw;
+ u32 lpcsaw[8];
+ u8 res1[0x5c];
+ struct law ddrlaw;
+ u8 res3[0x1c];
+ u32 srambar;
+ u32 nfcbar;
+ u8 res4[0x34];
+ u32 spridr;
+ u32 spcr;
+};
+
+#define MPC512X_SYSCONF_LPCSAW_START(x) (x & 0xffff0000)
+#define MPC512X_SYSCONF_LPCSAW_STOP(x) ((x) >> 16)
+
+#define MPC512X_SPCR_TBEN 0x00400000 /* E300 core time base unit enable */
+
+#define MPC512X_SVR_PART(x) (((x) >> 16) & 0xFFFF) /* Part ID */
+#define MPC512X_SVR_REV(x) (((x) >> 0) & 0xFFFF) /* Revision ID */
+
+/* the MPC512x comes in two revisions. Note: these SoCs are not supported yet */
+#define MPC512x_PART_ID 0x8018
+# define MPC512X_5121E 0x0020
+# define MPC512X_5123 0x0030
+
+/* the MPC5125 comes in one revisions */
+#define MPC5125_PART_ID 0x8019
+# define MPC512X_SPR_5125 0x0010
+
+static struct sysconf * const sysconf = (struct sysconf *)CFG_MBAR;
+
+/*
+ * According to MPC5121e RM, configuring local access windows should
+ * be followed by a dummy read of the config register that was
+ * modified last and an isync.
+ */
+static void sync_law(void *addr)
+{
+ in_be32(addr);
+}
+
+void mpc5125_setup_access_window(unsigned cs, unsigned start, unsigned size)
+{
+ unsigned long long u = start;
+
+ u += size;
+ if (u > 0x100000000) {
+ pr_err("Size for LPC chipselect %d exceeds address space. Limited!\n", cs);
+ size = 0x100000000 - start;
+ }
+
+ out_be32(&sysconf->lpcsaw[cs],
+ MPC512X_SYSCONF_LPCSAW_START(start) |
+ MPC512X_SYSCONF_LPCSAW_STOP(start + size - 1));
+ sync_law(&sysconf->lpcsaw[cs]);
+}
+
+void mpc5125_setup_ram_memory_window(unsigned base, unsigned size)
+{
+ out_be32(&sysconf->ddrlaw.bar, base & 0xFFFFF000);
+ out_be32(&sysconf->ddrlaw.ar, __ilog2(size) - 1);
+ sync_law(&sysconf->ddrlaw.ar);
+}
+
+unsigned mpc5xxx_get_sdram_size(void)
+{
+ return 1 << (in_be32(&sysconf->ddrlaw.ar) + 1);
+}
+
+void mpc5125_enable_time_base_counter(void)
+{
+ setbits_be32(&sysconf->spcr, MPC512X_SPCR_TBEN);
+}
+
+static int mpc5125_check_cpu(void)
+{
+ unsigned svr;
+ unsigned pid, rid;
+
+ svr = in_be32(&sysconf->spridr);
+ pid = MPC512X_SVR_PART(svr);
+ rid = MPC512X_SVR_REV(svr);
+
+ puts("SoC type: ");
+ switch (pid) {
+ case MPC512x_PART_ID:
+ switch (rid) {
+ case MPC512X_5121E:
+ puts("MPC5121e\n");
+ break;
+ case MPC512X_5123:
+ puts ("MPC5123\n");
+ break;
+ default:
+ printf("Unknown MPC512x variant: %x\n", rid);
+ }
+ break;
+ case MPC5125_PART_ID:
+ puts("MPC5125\n");
+ break;
+ default:
+ printf("Unknown MPC51xx part/variant: %x/%x\n", pid, rid);
+ }
+
+ return 0;
+}
+postconsole_initcall(mpc5125_check_cpu);
--
2.1.0
More information about the barebox
mailing list