openwrtv4/package/boot/uboot-lantiq/patches/0014-MIPS-add-support-for-Lantiq-XWAY-SoCs.patch
Mathias Kresin ecf10d3796 uboot-lantiq: vrx200 - lzma compress gphy firmware
The default bootloader partition of some devices is to small for an
u-boot with uncompressed gphy firmware(s).

Instead of increasing the bootloader partition size, in compare to the
stock firmware, compress the firmware. This would allow the bootloader
of at least the FritzBox 3370 as well as the bootloader of the
VGV7510KW22 to fit into the bootloader partition of the stock firmware.

Signed-off-by: Mathias Kresin <dev@kresin.me>
2016-05-27 15:50:17 +02:00

8705 lines
216 KiB
Diff

From 11553b0de8992ded6240d034bd49f561d17bea53 Mon Sep 17 00:00:00 2001
From: Daniel Schwierzeck <daniel.schwierzeck@gmail.com>
Date: Thu, 13 Jun 2013 01:18:02 +0200
Subject: MIPS: add support for Lantiq XWAY SoCs
Signed-off-by: Luka Perkov <luka@openwrt.org>
Signed-off-by: Daniel Schwierzeck <daniel.schwierzeck@gmail.com>
--- a/.gitignore
+++ b/.gitignore
@@ -49,6 +49,13 @@
/u-boot.sb
/u-boot.bd
/u-boot.geany
+/u-boot.bin.lzma
+/u-boot.bin.lzo
+/u-boot.ltq.lzma.norspl
+/u-boot.ltq.lzo.norspl
+/u-boot.ltq.norspl
+/u-boot.lzma.img
+/u-boot.lzo.img
#
# Generated files
--- a/Makefile
+++ b/Makefile
@@ -435,6 +435,12 @@ $(obj)u-boot.bin: $(obj)u-boot
$(OBJCOPY) ${OBJCFLAGS} -O binary $< $@
$(BOARD_SIZE_CHECK)
+$(obj)u-boot.bin.lzma: $(obj)u-boot.bin
+ cat $< | lzma -9 -f - > $@
+
+$(obj)u-boot.bin.lzo: $(obj)u-boot.bin
+ cat $< | lzop -9 -f - > $@
+
$(obj)u-boot.ldr: $(obj)u-boot
$(CREATE_LDR_ENV)
$(LDR) -T $(CONFIG_BFIN_CPU) -c $@ $< $(LDR_FLAGS)
@@ -454,13 +460,23 @@ ifndef CONFIG_SYS_UBOOT_START
CONFIG_SYS_UBOOT_START := 0
endif
-$(obj)u-boot.img: $(obj)u-boot.bin
- $(obj)tools/mkimage -A $(ARCH) -T firmware -C none \
+define GEN_UBOOT_IMAGE
+ $(obj)tools/mkimage -A $(ARCH) -T firmware -C $(1) \
-O u-boot -a $(CONFIG_SYS_TEXT_BASE) \
-e $(CONFIG_SYS_UBOOT_START) \
-n $(shell sed -n -e 's/.*U_BOOT_VERSION//p' $(VERSION_FILE) | \
sed -e 's/"[ ]*$$/ for $(BOARD) board"/') \
-d $< $@
+endef
+
+$(obj)u-boot.img: $(obj)u-boot.bin
+ $(call GEN_UBOOT_IMAGE,none)
+
+$(obj)u-boot.lzma.img: $(obj)u-boot.bin.lzma
+ $(call GEN_UBOOT_IMAGE,lzma)
+
+$(obj)u-boot.lzo.img: $(obj)u-boot.bin.lzo
+ $(call GEN_UBOOT_IMAGE,lzo)
$(obj)u-boot.imx: $(obj)u-boot.bin depend
$(MAKE) -C $(SRCTREE)/arch/arm/imx-common $(OBJTREE)/u-boot.imx
@@ -571,6 +587,27 @@ $(obj)u-boot-img-spl-at-end.bin: $(obj)s
conv=notrunc 2>/dev/null
cat $(obj)u-boot-pad.img $(obj)spl/u-boot-spl.bin > $@
+$(obj)u-boot.ltq.sfspl: $(obj)u-boot.img $(obj)spl/u-boot-spl.bin
+ $(obj)tools/ltq-boot-image -t sfspl -e $(CONFIG_SPL_TEXT_BASE) \
+ -s $(obj)spl/u-boot-spl.bin -u $< -o $@
+
+$(obj)u-boot.ltq.lzo.sfspl: $(obj)u-boot.lzo.img $(obj)spl/u-boot-spl.bin
+ $(obj)tools/ltq-boot-image -t sfspl -e $(CONFIG_SPL_TEXT_BASE) \
+ -s $(obj)spl/u-boot-spl.bin -u $< -o $@
+
+$(obj)u-boot.ltq.lzma.sfspl: $(obj)u-boot.lzma.img $(obj)spl/u-boot-spl.bin
+ $(obj)tools/ltq-boot-image -t sfspl -e $(CONFIG_SPL_TEXT_BASE) \
+ -s $(obj)spl/u-boot-spl.bin -u $< -o $@
+
+$(obj)u-boot.ltq.norspl: $(obj)u-boot.img $(obj)spl/u-boot-spl.bin
+ cat $(obj)spl/u-boot-spl.bin $< > $@
+
+$(obj)u-boot.ltq.lzo.norspl: $(obj)u-boot.lzo.img $(obj)spl/u-boot-spl.bin
+ cat $(obj)spl/u-boot-spl.bin $< > $@
+
+$(obj)u-boot.ltq.lzma.norspl: $(obj)u-boot.lzma.img $(obj)spl/u-boot-spl.bin
+ cat $(obj)spl/u-boot-spl.bin $< > $@
+
ifeq ($(CONFIG_SANDBOX),y)
GEN_UBOOT = \
cd $(LNDIR) && $(CC) $(SYMS) -T $(obj)u-boot.lds \
--- a/README
+++ b/README
@@ -468,6 +468,11 @@ The following options need to be configu
CONF_CM_CACHABLE_CUW
CONF_CM_CACHABLE_ACCELERATED
+ CONFIG_SYS_MIPS_CACHE_EXT_INIT
+
+ Enable this to use extended cache initialization for recent
+ MIPS CPU cores.
+
CONFIG_SYS_XWAY_EBU_BOOTCFG
Special option for Lantiq XWAY SoCs for booting from NOR flash.
--- a/arch/mips/config.mk
+++ b/arch/mips/config.mk
@@ -45,9 +45,13 @@ PLATFORM_CPPFLAGS += -DCONFIG_MIPS -D__M
# On the other hand, we want PIC in the U-Boot code to relocate it from ROM
# to RAM. $28 is always used as gp.
#
-PLATFORM_CPPFLAGS += -G 0 -mabicalls -fpic $(ENDIANNESS)
+PF_ABICALLS ?= -mabicalls
+PF_PIC ?= -fpic
+PF_PIE ?= -pie
+
+PLATFORM_CPPFLAGS += -G 0 $(PF_ABICALLS) $(PF_PIC) $(ENDIANNESS)
PLATFORM_CPPFLAGS += -msoft-float
PLATFORM_LDFLAGS += -G 0 -static -n -nostdlib $(ENDIANNESS)
PLATFORM_RELFLAGS += -ffunction-sections -fdata-sections
-LDFLAGS_FINAL += --gc-sections -pie
+LDFLAGS_FINAL += --gc-sections $(PF_PIE)
OBJCFLAGS += --remove-section=.dynsym
--- a/arch/mips/cpu/mips32/cache.S
+++ b/arch/mips/cpu/mips32/cache.S
@@ -29,7 +29,11 @@
*/
#define MIPS_MAX_CACHE_SIZE 0x10000
+#ifdef CONFIG_SYS_MIPS_CACHE_EXT_INIT
+#define INDEX_BASE 0x9fc00000
+#else
#define INDEX_BASE CKSEG0
+#endif
.macro cache_op op addr
.set push
@@ -65,7 +69,11 @@
*/
LEAF(mips_init_icache)
blez a1, 9f
+#ifdef CONFIG_SYS_MIPS_CACHE_EXT_INIT
+ mtc0 zero, CP0_ITAGLO
+#else
mtc0 zero, CP0_TAGLO
+#endif
/* clear tag to invalidate */
PTR_LI t0, INDEX_BASE
PTR_ADDU t1, t0, a1
@@ -90,7 +98,11 @@ LEAF(mips_init_icache)
*/
LEAF(mips_init_dcache)
blez a1, 9f
+#ifdef CONFIG_SYS_MIPS_CACHE_EXT_INIT
+ mtc0 zero, CP0_DTAGLO
+#else
mtc0 zero, CP0_TAGLO
+#endif
/* clear all tags */
PTR_LI t0, INDEX_BASE
PTR_ADDU t1, t0, a1
--- /dev/null
+++ b/arch/mips/cpu/mips32/danube/Makefile
@@ -0,0 +1,31 @@
+#
+# Copyright (C) 2000-2011 Wolfgang Denk, DENX Software Engineering, wd@denx.de
+#
+# SPDX-License-Identifier: GPL-2.0+
+#
+
+include $(TOPDIR)/config.mk
+
+LIB = $(obj)lib$(SOC).o
+
+COBJS-y += cgu.o chipid.o ebu.o mem.o pmu.o rcu.o
+SOBJS-y += cgu_init.o mem_init.o
+
+COBJS := $(COBJS-y)
+SOBJS := $(SOBJS-y)
+SRCS := $(SOBJS:.o=.S) $(COBJS:.o=.c)
+OBJS := $(addprefix $(obj),$(SOBJS) $(COBJS))
+
+all: $(LIB)
+
+$(LIB): $(obj).depend $(OBJS)
+ $(call cmd_link_o_target, $(OBJS))
+
+#########################################################################
+
+# defines $(obj).depend target
+include $(SRCTREE)/rules.mk
+
+sinclude $(obj).depend
+
+#########################################################################
--- /dev/null
+++ b/arch/mips/cpu/mips32/danube/cgu.c
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2007-2010 Lantiq Deutschland GmbH
+ * Copyright (C) 2011-2013 Daniel Schwierzeck, daniel.schwierzeck@gmail.com
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <asm/arch/soc.h>
+#include <asm/lantiq/clk.h>
+#include <asm/lantiq/io.h>
+
+#define LTQ_CGU_SYS_DDR_MASK 0x0003
+#define LTQ_CGU_SYS_DDR_SHIFT 0
+#define LTQ_CGU_SYS_CPU0_MASK 0x000C
+#define LTQ_CGU_SYS_CPU0_SHIFT 2
+#define LTQ_CGU_SYS_FPI_MASK 0x0040
+#define LTQ_CGU_SYS_FPI_SHIFT 6
+
+struct ltq_cgu_regs {
+ u32 rsvd0;
+ u32 pll0_cfg; /* PLL0 config */
+ u32 pll1_cfg; /* PLL1 config */
+ u32 pll2_cfg; /* PLL2 config */
+ u32 sys; /* System clock */
+ u32 update; /* CGU update control */
+ u32 if_clk; /* Interface clock */
+ u32 osc_con; /* Update OSC Control */
+ u32 smd; /* SDRAM Memory Control */
+ u32 rsvd1[3];
+ u32 pcm_cr; /* PCM control */
+ u32 pci_cr; /* PCI clock control */
+};
+
+static struct ltq_cgu_regs *ltq_cgu_regs =
+ (struct ltq_cgu_regs *) CKSEG1ADDR(LTQ_CGU_BASE);
+
+static inline u32 ltq_cgu_sys_readl(u32 mask, u32 shift)
+{
+ return (ltq_readl(&ltq_cgu_regs->sys) & mask) >> shift;
+}
+
+unsigned long ltq_get_io_region_clock(void)
+{
+ u32 ddr_sel;
+ unsigned long clk;
+
+ ddr_sel = ltq_cgu_sys_readl(LTQ_CGU_SYS_DDR_MASK,
+ LTQ_CGU_SYS_DDR_SHIFT);
+
+ switch (ddr_sel) {
+ case 0:
+ clk = CLOCK_166_MHZ;
+ break;
+ case 1:
+ clk = CLOCK_133_MHZ;
+ break;
+ case 2:
+ clk = CLOCK_111_MHZ;
+ break;
+ case 3:
+ clk = CLOCK_83_MHZ;
+ break;
+ default:
+ clk = 0;
+ break;
+ }
+
+ return clk;
+}
+
+unsigned long ltq_get_cpu_clock(void)
+{
+ u32 cpu0_sel;
+ unsigned long clk;
+
+ cpu0_sel = ltq_cgu_sys_readl(LTQ_CGU_SYS_CPU0_MASK,
+ LTQ_CGU_SYS_CPU0_SHIFT);
+
+ switch (cpu0_sel) {
+ /* Same as PLL0 output (333,33 MHz) */
+ case 0:
+ clk = CLOCK_333_MHZ;
+ break;
+ /* 1/1 fixed ratio to DDR clock */
+ case 1:
+ clk = ltq_get_io_region_clock();
+ break;
+ /* 1/2 fixed ratio to DDR clock */
+ case 2:
+ clk = ltq_get_io_region_clock() << 1;
+ break;
+ default:
+ clk = 0;
+ break;
+ }
+
+ return clk;
+}
+
+unsigned long ltq_get_bus_clock(void)
+{
+ u32 fpi_sel;
+ unsigned long clk;
+
+ fpi_sel = ltq_cgu_sys_readl(LTQ_CGU_SYS_FPI_MASK,
+ LTQ_CGU_SYS_FPI_SHIFT);
+
+ if (fpi_sel)
+ /* Half the DDR clock */
+ clk = ltq_get_io_region_clock() >> 1;
+ else
+ /* Same as DDR clock */
+ clk = ltq_get_io_region_clock();
+
+ return clk;
+}
--- /dev/null
+++ b/arch/mips/cpu/mips32/danube/cgu_init.S
@@ -0,0 +1,142 @@
+/*
+ * Copyright (C) 2007-2010 Lantiq Deutschland GmbH
+ * Copyright (C) 2011-2013 Daniel Schwierzeck, daniel.schwierzeck@gmail.com
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <config.h>
+#include <asm/asm.h>
+#include <asm/regdef.h>
+#include <asm/addrspace.h>
+#include <asm/arch/soc.h>
+
+/* RCU module register */
+#define LTQ_RCU_RST_REQ 0x0010
+#define LTQ_RCU_RST_STAT 0x0014
+#define LTQ_RCU_RST_REQ_VALUE 0x40000008
+#define LTQ_RCU_RST_STAT_XTAL_F 0x20000
+
+/* CGU module register */
+#define LTQ_CGU_PLL0_CFG 0x0004 /* PLL0 config */
+#define LTQ_CGU_PLL1_CFG 0x0008 /* PLL1 config */
+#define LTQ_CGU_PLL2_CFG 0x000C /* PLL2 config */
+#define LTQ_CGU_SYS 0x0010 /* System clock */
+
+/* Valid SYS.CPU0/1 values */
+#define LTQ_CGU_SYS_CPU0_SHIFT 2
+#define LTQ_CGU_SYS_CPU1_SHIFT 4
+#define LTQ_CGU_SYS_CPU_PLL0 0x0
+#define LTQ_CGU_SYS_CPU_DDR_EQUAL 0x1
+#define LTQ_CGU_SYS_CPU_DDR_TWICE 0x2
+
+/* Valid SYS.DDR values */
+#define LTQ_CGU_SYS_DDR_SHIFT 0
+#define LTQ_CGU_SYS_DDR_167_MHZ 0x0
+#define LTQ_CGU_SYS_DDR_133_MHZ 0x1
+#define LTQ_CGU_SYS_DDR_111_MHZ 0x2
+#define LTQ_CGU_SYS_DDR_83_MHZ 0x3
+
+/* Valid SYS.FPI values */
+#define LTQ_CGU_SYS_FPI_SHIFT 6
+#define LTQ_CGU_SYS_FPI_DDR_EQUAL 0x0
+#define LTQ_CGU_SYS_FPI_DDR_HALF 0x1
+
+/* Valid SYS.PPE values */
+#define LTQ_CGU_SYS_PPE_SHIFT 7
+#define LTQ_CGU_SYS_PPE_266_MHZ 0x0
+#define LTQ_CGU_SYS_PPE_240_MHZ 0x1
+#define LTQ_CGU_SYS_PPE_222_MHZ 0x2
+#define LTQ_CGU_SYS_PPE_133_MHZ 0x3
+
+#if (CONFIG_SYS_CLOCK_MODE == LTQ_CLK_CPU_333_DDR_167)
+#define LTQ_CGU_SYS_CPU_CONFIG LTQ_CGU_SYS_CPU_DDR_TWICE
+#define LTQ_CGU_SYS_DDR_CONFIG LTQ_CGU_SYS_DDR_167_MHZ
+#define LTQ_CGU_SYS_FPI_CONFIG LTQ_CGU_SYS_FPI_DDR_HALF
+#define LTQ_CGU_SYS_PPE_CONFIG LTQ_CGU_SYS_PPE_266_MHZ
+#elif (CONFIG_SYS_CLOCK_MODE == LTQ_CLK_CPU_111_DDR_111)
+#define LTQ_CGU_SYS_CPU_CONFIG LTQ_CGU_SYS_CPU_DDR_EQUAL
+#define LTQ_CGU_SYS_DDR_CONFIG LTQ_CGU_SYS_DDR_111_MHZ
+#define LTQ_CGU_SYS_FPI_CONFIG LTQ_CGU_SYS_FPI_DDR_HALF
+#define LTQ_CGU_SYS_PPE_CONFIG LTQ_CGU_SYS_PPE_133_MHZ
+#else
+#error "Invalid system clock configuration!"
+#endif
+
+/* Build register values */
+#define LTQ_CGU_SYS_VALUE ((LTQ_CGU_SYS_PPE_CONFIG << \
+ LTQ_CGU_SYS_PPE_SHIFT) | \
+ (LTQ_CGU_SYS_FPI_CONFIG << \
+ LTQ_CGU_SYS_FPI_SHIFT) | \
+ (LTQ_CGU_SYS_CPU_CONFIG << \
+ LTQ_CGU_SYS_CPU1_SHIFT) | \
+ (LTQ_CGU_SYS_CPU_CONFIG << \
+ LTQ_CGU_SYS_CPU0_SHIFT) | \
+ LTQ_CGU_SYS_DDR_CONFIG)
+
+/* Reset values for PLL registers for usage with 35.328 MHz crystal */
+#define PLL0_35MHZ_CONFIG 0x9D861059
+#define PLL1_35MHZ_CONFIG 0x1A260CD9
+#define PLL2_35MHZ_CONFIG 0x8000f1e5
+
+/* Reset values for PLL registers for usage with 36 MHz crystal */
+#define PLL0_36MHZ_CONFIG 0x1000125D
+#define PLL1_36MHZ_CONFIG 0x1B1E0C99
+#define PLL2_36MHZ_CONFIG 0x8002f2a1
+
+LEAF(ltq_cgu_init)
+ /* Load current CGU register value */
+ li t0, (LTQ_CGU_BASE | KSEG1)
+ lw t1, LTQ_CGU_SYS(t0)
+
+ /* Load target CGU register values */
+ li t3, LTQ_CGU_SYS_VALUE
+
+ /* Only update registers if values differ */
+ beq t1, t3, finished
+
+ /*
+ * Check whether the XTAL_F bit in RST_STAT register is set or not.
+ * This bit is latched in via pin strapping. If bit is set then
+ * clock source is a 36 MHz crystal. Otherwise a 35.328 MHz crystal.
+ */
+ li t1, (LTQ_RCU_BASE | KSEG1)
+ lw t2, LTQ_RCU_RST_STAT(t1)
+ and t2, t2, LTQ_RCU_RST_STAT_XTAL_F
+ beq t2, LTQ_RCU_RST_STAT_XTAL_F, boot_36mhz
+
+boot_35mhz:
+ /* Configure PLL for 35.328 MHz */
+ li t2, PLL0_35MHZ_CONFIG
+ sw t2, LTQ_CGU_PLL0_CFG(t0)
+ li t2, PLL1_35MHZ_CONFIG
+ sw t2, LTQ_CGU_PLL1_CFG(t0)
+ li t2, PLL2_35MHZ_CONFIG
+ sw t2, LTQ_CGU_PLL2_CFG(t0)
+
+ b do_reset
+
+boot_36mhz:
+ /* Configure PLL for 36 MHz */
+ li t2, PLL0_36MHZ_CONFIG
+ sw t2, LTQ_CGU_PLL0_CFG(t0)
+ li t2, PLL1_36MHZ_CONFIG
+ sw t2, LTQ_CGU_PLL1_CFG(t0)
+ li t2, PLL2_36MHZ_CONFIG
+ sw t2, LTQ_CGU_PLL2_CFG(t0)
+
+do_reset:
+ /* Store new clock config */
+ sw t3, LTQ_CGU_SYS(t0)
+
+ /* Perform software reset to activate new clock config */
+ li t2, LTQ_RCU_RST_REQ_VALUE
+ sw t2, LTQ_RCU_RST_REQ(t1)
+
+wait_reset:
+ b wait_reset
+
+finished:
+ jr ra
+
+ END(ltq_cgu_init)
--- /dev/null
+++ b/arch/mips/cpu/mips32/danube/chipid.c
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2011-2013 Daniel Schwierzeck, daniel.schwierzeck@gmail.com
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <asm/lantiq/io.h>
+#include <asm/lantiq/chipid.h>
+#include <asm/arch/soc.h>
+
+#define LTQ_CHIPID_VERSION_SHIFT 28
+#define LTQ_CHIPID_VERSION_MASK (0xF << LTQ_CHIPID_VERSION_SHIFT)
+#define LTQ_CHIPID_PNUM_SHIFT 12
+#define LTQ_CHIPID_PNUM_MASK (0xFFFF << LTQ_CHIPID_PNUM_SHIFT)
+
+struct ltq_chipid_regs {
+ u32 manid; /* Manufacturer identification */
+ u32 chipid; /* Chip identification */
+};
+
+static struct ltq_chipid_regs *ltq_chipid_regs =
+ (struct ltq_chipid_regs *) CKSEG1ADDR(LTQ_CHIPID_BASE);
+
+unsigned int ltq_chip_version_get(void)
+{
+ u32 chipid;
+
+ chipid = ltq_readl(&ltq_chipid_regs->chipid);
+
+ return (chipid & LTQ_CHIPID_VERSION_MASK) >> LTQ_CHIPID_VERSION_SHIFT;
+}
+
+unsigned int ltq_chip_partnum_get(void)
+{
+ u32 chipid;
+
+ chipid = ltq_readl(&ltq_chipid_regs->chipid);
+
+ return (chipid & LTQ_CHIPID_PNUM_MASK) >> LTQ_CHIPID_PNUM_SHIFT;
+}
+
+const char *ltq_chip_partnum_str(void)
+{
+ enum ltq_chip_partnum partnum = ltq_chip_partnum_get();
+
+ switch (partnum) {
+ case LTQ_SOC_DANUBE:
+ return "Danube";
+ case LTQ_SOC_DANUBE_S:
+ return "Danube-S";
+ case LTQ_SOC_TWINPASS:
+ return "Twinpass";
+ default:
+ printf("Unknown partnum: %x\n", partnum);
+ }
+
+ return "";
+}
--- /dev/null
+++ b/arch/mips/cpu/mips32/danube/config.mk
@@ -0,0 +1,25 @@
+#
+# Copyright (C) 2011-2013 Daniel Schwierzeck, daniel.schwierzeck@gmail.com
+#
+# SPDX-License-Identifier: GPL-2.0+
+#
+
+PF_CPPFLAGS_DANUBE := $(call cc-option,-mtune=24kec,)
+PLATFORM_CPPFLAGS += $(PF_CPPFLAGS_DANUBE)
+
+ifdef CONFIG_SPL_BUILD
+PF_ABICALLS := -mno-abicalls
+PF_PIC := -fno-pic
+PF_PIE :=
+USE_PRIVATE_LIBGCC := yes
+endif
+
+LIBS-y += $(CPUDIR)/lantiq-common/liblantiq-common.o
+
+ifndef CONFIG_SPL_BUILD
+ifdef CONFIG_SYS_BOOT_NORSPL
+ALL-y += $(obj)u-boot.ltq.norspl
+ALL-$(CONFIG_SPL_LZO_SUPPORT) += $(obj)u-boot.ltq.lzo.norspl
+ALL-$(CONFIG_SPL_LZMA_SUPPORT) += $(obj)u-boot.ltq.lzma.norspl
+endif
+endif
--- /dev/null
+++ b/arch/mips/cpu/mips32/danube/ebu.c
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2011-2013 Daniel Schwierzeck, daniel.schwierzeck@gmail.com
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <asm/arch/soc.h>
+#include <asm/lantiq/io.h>
+
+#define EBU_ADDRSEL_MASK(mask) ((mask & 0xf) << 4)
+#define EBU_ADDRSEL_REGEN (1 << 0)
+
+#define EBU_CON_WRDIS (1 << 31)
+#define EBU_CON_AGEN_DEMUX (0x0 << 24)
+#define EBU_CON_AGEN_MUX (0x2 << 24)
+#define EBU_CON_SETUP (1 << 22)
+#define EBU_CON_WAIT_DIS (0x0 << 20)
+#define EBU_CON_WAIT_ASYNC (0x1 << 20)
+#define EBU_CON_WAIT_SYNC (0x2 << 20)
+#define EBU_CON_WINV (1 << 19)
+#define EBU_CON_PW_8BIT (0x0 << 16)
+#define EBU_CON_PW_16BIT (0x1 << 16)
+#define EBU_CON_ALEC(cycles) ((cycles & 0x3) << 14)
+#define EBU_CON_BCGEN_CS (0x0 << 12)
+#define EBU_CON_BCGEN_INTEL (0x1 << 12)
+#define EBU_CON_BCGEN_MOTOROLA (0x2 << 12)
+#define EBU_CON_WAITWRC(cycles) ((cycles & 0x7) << 8)
+#define EBU_CON_WAITRDC(cycles) ((cycles & 0x3) << 6)
+#define EBU_CON_HOLDC(cycles) ((cycles & 0x3) << 4)
+#define EBU_CON_RECOVC(cycles) ((cycles & 0x3) << 2)
+#define EBU_CON_CMULT_1 0x0
+#define EBU_CON_CMULT_4 0x1
+#define EBU_CON_CMULT_8 0x2
+#define EBU_CON_CMULT_16 0x3
+
+#if defined(CONFIG_LTQ_SUPPORT_NOR_FLASH)
+#define ebu_region0_enable 1
+#else
+#define ebu_region0_enable 0
+#endif
+
+#if defined(CONFIG_LTQ_SUPPORT_NAND_FLASH)
+#define ebu_region1_enable 1
+#else
+#define ebu_region1_enable 0
+#endif
+
+struct ltq_ebu_regs {
+ u32 clc;
+ u32 rsvd0[3];
+ u32 con;
+ u32 rsvd1[3];
+ u32 addr_sel_0;
+ u32 addr_sel_1;
+ u32 rsvd2[14];
+ u32 con_0;
+ u32 con_1;
+};
+
+static struct ltq_ebu_regs *ltq_ebu_regs =
+ (struct ltq_ebu_regs *) CKSEG1ADDR(LTQ_EBU_BASE);
+
+void ltq_ebu_init(void)
+{
+ if (ebu_region0_enable) {
+ /*
+ * Map EBU region 0 to range 0x10000000-0x13ffffff and enable
+ * region control. This supports up to 32 MiB NOR flash in
+ * bank 0.
+ */
+ ltq_writel(&ltq_ebu_regs->addr_sel_0, LTQ_EBU_REGION0_BASE |
+ EBU_ADDRSEL_MASK(1) | EBU_ADDRSEL_REGEN);
+
+ ltq_writel(&ltq_ebu_regs->con_0, EBU_CON_AGEN_DEMUX |
+ EBU_CON_WAIT_DIS | EBU_CON_PW_16BIT |
+ EBU_CON_ALEC(3) | EBU_CON_BCGEN_INTEL |
+ EBU_CON_WAITWRC(7) | EBU_CON_WAITRDC(3) |
+ EBU_CON_HOLDC(3) | EBU_CON_RECOVC(3) |
+ EBU_CON_CMULT_16);
+ } else
+ ltq_clrbits(&ltq_ebu_regs->addr_sel_0, EBU_ADDRSEL_REGEN);
+
+ if (ebu_region1_enable) {
+ /*
+ * Map EBU region 1 to range 0x14000000-0x13ffffff and enable
+ * region control. This supports NAND flash in bank 1.
+ */
+ ltq_writel(&ltq_ebu_regs->addr_sel_1, LTQ_EBU_REGION1_BASE |
+ EBU_ADDRSEL_MASK(3) | EBU_ADDRSEL_REGEN);
+
+ ltq_writel(&ltq_ebu_regs->con_1, EBU_CON_AGEN_DEMUX |
+ EBU_CON_SETUP | EBU_CON_WAIT_DIS | EBU_CON_PW_8BIT |
+ EBU_CON_ALEC(3) | EBU_CON_BCGEN_INTEL |
+ EBU_CON_WAITWRC(2) | EBU_CON_WAITRDC(2) |
+ EBU_CON_HOLDC(1) | EBU_CON_RECOVC(1) |
+ EBU_CON_CMULT_4);
+ } else
+ ltq_clrbits(&ltq_ebu_regs->addr_sel_1, EBU_ADDRSEL_REGEN);
+}
+
+void *flash_swap_addr(unsigned long addr)
+{
+ return (void *)(addr ^ 2);
+}
--- /dev/null
+++ b/arch/mips/cpu/mips32/danube/mem.c
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2011-2013 Daniel Schwierzeck, daniel.schwierzeck@gmail.com
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <asm/arch/soc.h>
+#include <asm/lantiq/io.h>
+
+static void *ltq_mc_ddr_base = (void *) CKSEG1ADDR(LTQ_MC_DDR_BASE);
+
+static inline u32 ltq_mc_dc_read(u32 index)
+{
+ return ltq_readl(ltq_mc_ddr_base + LTQ_MC_DDR_DC_OFFSET(index));
+}
+
+phys_size_t initdram(int board_type)
+{
+ u32 col, row, dc04, dc19, dc20;
+
+ dc04 = ltq_mc_dc_read(4);
+ dc19 = ltq_mc_dc_read(19);
+ dc20 = ltq_mc_dc_read(20);
+
+ row = (dc04 & 0xF) - ((dc19 & 0x700) >> 8);
+ col = ((dc04 & 0xF00) >> 8) - (dc20 & 0x7);
+
+ return (1 << (row + col)) * 4 * 2;
+}
--- /dev/null
+++ b/arch/mips/cpu/mips32/danube/mem_init.S
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2007-2010 Lantiq Deutschland GmbH
+ * Copyright (C) 2011-2013 Daniel Schwierzeck, daniel.schwierzeck@gmail.com
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <config.h>
+#include <asm/asm.h>
+#include <asm/regdef.h>
+#include <asm/addrspace.h>
+#include <asm/arch/soc.h>
+
+/* Must be configured in BOARDDIR */
+#include <ddr_settings.h>
+
+#define LTQ_MC_GEN_ERRCAUSE 0x0010
+#define LTQ_MC_GEN_ERRADDR 0x0020
+#define LTQ_MC_GEN_CON 0x0060
+#define LTQ_MC_GEN_STAT 0x0070
+#define LTQ_MC_GEN_CON_SRAM_DDR_ENABLE 0x5
+#define LTQ_MC_GEN_STAT_DLCK_PWRON 0xC
+
+#define LTQ_MC_DDR_DC03_MC_START 0x100
+
+ /* Store given value in MC DDR CCRx register */
+ .macro dc_sw num, val
+ li t2, \val
+ sw t2, LTQ_MC_DDR_DC_OFFSET(\num)(t1)
+ .endm
+
+LEAF(ltq_mem_init)
+ /* Load MC General and MC DDR module base */
+ li t0, (LTQ_MC_GEN_BASE | KSEG1)
+ li t1, (LTQ_MC_DDR_BASE | KSEG1)
+
+ /* Clear access error log registers */
+ sw zero, LTQ_MC_GEN_ERRCAUSE(t0)
+ sw zero, LTQ_MC_GEN_ERRADDR(t0)
+
+ /* Enable DDR and SRAM module in memory controller */
+ li t2, LTQ_MC_GEN_CON_SRAM_DDR_ENABLE
+ sw t2, LTQ_MC_GEN_CON(t0)
+
+ /* Clear start bit of DDR memory controller */
+ sw zero, LTQ_MC_DDR_DC_OFFSET(3)(t1)
+
+ /* Init memory controller registers with values ddr_settings.h */
+ dc_sw 0, MC_DC00_VALUE
+ dc_sw 1, MC_DC01_VALUE
+ dc_sw 2, MC_DC02_VALUE
+ dc_sw 4, MC_DC04_VALUE
+ dc_sw 5, MC_DC05_VALUE
+ dc_sw 6, MC_DC06_VALUE
+ dc_sw 7, MC_DC07_VALUE
+ dc_sw 8, MC_DC08_VALUE
+ dc_sw 9, MC_DC09_VALUE
+
+ dc_sw 10, MC_DC10_VALUE
+ dc_sw 11, MC_DC11_VALUE
+ dc_sw 12, MC_DC12_VALUE
+ dc_sw 13, MC_DC13_VALUE
+ dc_sw 14, MC_DC14_VALUE
+ dc_sw 15, MC_DC15_VALUE
+ dc_sw 16, MC_DC16_VALUE
+ dc_sw 17, MC_DC17_VALUE
+ dc_sw 18, MC_DC18_VALUE
+ dc_sw 19, MC_DC19_VALUE
+
+ dc_sw 20, MC_DC20_VALUE
+ dc_sw 21, MC_DC21_VALUE
+ dc_sw 22, MC_DC22_VALUE
+ dc_sw 23, MC_DC23_VALUE
+ dc_sw 24, MC_DC24_VALUE
+ dc_sw 25, MC_DC25_VALUE
+ dc_sw 26, MC_DC26_VALUE
+ dc_sw 27, MC_DC27_VALUE
+ dc_sw 28, MC_DC28_VALUE
+ dc_sw 29, MC_DC29_VALUE
+
+ dc_sw 30, MC_DC30_VALUE
+ dc_sw 31, MC_DC31_VALUE
+ dc_sw 32, MC_DC32_VALUE
+ dc_sw 33, MC_DC33_VALUE
+ dc_sw 34, MC_DC34_VALUE
+ dc_sw 35, MC_DC35_VALUE
+ dc_sw 36, MC_DC36_VALUE
+ dc_sw 37, MC_DC37_VALUE
+ dc_sw 38, MC_DC38_VALUE
+ dc_sw 39, MC_DC39_VALUE
+
+ dc_sw 40, MC_DC40_VALUE
+ dc_sw 41, MC_DC41_VALUE
+ dc_sw 42, MC_DC42_VALUE
+ dc_sw 43, MC_DC43_VALUE
+ dc_sw 44, MC_DC44_VALUE
+ dc_sw 45, MC_DC45_VALUE
+ dc_sw 46, MC_DC46_VALUE
+
+ /* Set start bit of DDR memory controller */
+ li t2, LTQ_MC_DDR_DC03_MC_START
+ sw t2, LTQ_MC_DDR_DC_OFFSET(3)(t1)
+
+ /* Wait until DLL has locked and core is ready for data transfers */
+wait_ready:
+ lw t2, LTQ_MC_GEN_STAT(t0)
+ li t3, LTQ_MC_GEN_STAT_DLCK_PWRON
+ and t2, t3
+ bne t2, t3, wait_ready
+
+finished:
+ jr ra
+
+ END(ltq_mem_init)
--- /dev/null
+++ b/arch/mips/cpu/mips32/danube/pmu.c
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2011-2013 Daniel Schwierzeck, daniel.schwierzeck@gmail.com
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <asm/lantiq/io.h>
+#include <asm/lantiq/pm.h>
+#include <asm/arch/soc.h>
+
+#define LTQ_PMU_PWDCR_RESERVED 0xFD0C001C
+
+#define LTQ_PMU_PWDCR_TDM (1 << 25)
+#define LTQ_PMU_PWDCR_PPE_ENET0 (1 << 23)
+#define LTQ_PMU_PWDCR_PPE_ENET1 (1 << 22)
+#define LTQ_PMU_PWDCR_PPE_TC (1 << 21)
+#define LTQ_PMU_PWDCR_DEU (1 << 20)
+#define LTQ_PMU_PWDCR_UART1 (1 << 17)
+#define LTQ_PMU_PWDCR_SDIO (1 << 16)
+#define LTQ_PMU_PWDCR_AHB (1 << 15)
+#define LTQ_PMU_PWDCR_FPI0 (1 << 14)
+#define LTQ_PMU_PWDCR_PPE (1 << 13)
+#define LTQ_PMU_PWDCR_GPTC (1 << 12)
+#define LTQ_PMU_PWDCR_LEDC (1 << 11)
+#define LTQ_PMU_PWDCR_EBU (1 << 10)
+#define LTQ_PMU_PWDCR_DSL (1 << 9)
+#define LTQ_PMU_PWDCR_SPI (1 << 8)
+#define LTQ_PMU_PWDCR_UART0 (1 << 7)
+#define LTQ_PMU_PWDCR_USB (1 << 6)
+#define LTQ_PMU_PWDCR_DMA (1 << 5)
+#define LTQ_PMU_PWDCR_FPI1 (1 << 1)
+#define LTQ_PMU_PWDCR_USB_PHY (1 << 0)
+
+struct ltq_pmu_regs {
+ u32 rsvd0[7];
+ u32 pwdcr;
+ u32 sr;
+ u32 pwdcr1;
+ u32 sr1;
+};
+
+static struct ltq_pmu_regs *ltq_pmu_regs =
+ (struct ltq_pmu_regs *) CKSEG1ADDR(LTQ_PMU_BASE);
+
+u32 ltq_pm_map(enum ltq_pm_modules module)
+{
+ u32 val;
+
+ switch (module) {
+ case LTQ_PM_CORE:
+ val = LTQ_PMU_PWDCR_UART1 | LTQ_PMU_PWDCR_FPI0 |
+ LTQ_PMU_PWDCR_LEDC | LTQ_PMU_PWDCR_EBU;
+ break;
+ case LTQ_PM_DMA:
+ val = LTQ_PMU_PWDCR_DMA;
+ break;
+ case LTQ_PM_ETH:
+ val = LTQ_PMU_PWDCR_PPE_ENET0 | LTQ_PMU_PWDCR_PPE_TC |
+ LTQ_PMU_PWDCR_PPE;
+ break;
+ case LTQ_PM_SPI:
+ val = LTQ_PMU_PWDCR_SPI;
+ break;
+ default:
+ val = 0;
+ break;
+ }
+
+ return val;
+}
+
+int ltq_pm_enable(enum ltq_pm_modules module)
+{
+ const unsigned long timeout = 1000;
+ unsigned long timebase;
+ u32 sr, val;
+
+ val = ltq_pm_map(module);
+ if (unlikely(!val))
+ return 1;
+
+ ltq_clrbits(&ltq_pmu_regs->pwdcr, val);
+
+ timebase = get_timer(0);
+
+ do {
+ sr = ltq_readl(&ltq_pmu_regs->sr);
+ if (~sr & val)
+ return 0;
+ } while (get_timer(timebase) < timeout);
+
+ return 1;
+}
+
+int ltq_pm_disable(enum ltq_pm_modules module)
+{
+ u32 val;
+
+ val = ltq_pm_map(module);
+ if (unlikely(!val))
+ return 1;
+
+ ltq_setbits(&ltq_pmu_regs->pwdcr, val);
+
+ return 0;
+}
+
+void ltq_pmu_init(void)
+{
+ u32 set, clr;
+
+ clr = ltq_pm_map(LTQ_PM_CORE);
+ set = ~(LTQ_PMU_PWDCR_RESERVED | clr);
+
+ ltq_clrsetbits(&ltq_pmu_regs->pwdcr, clr, set);
+}
--- /dev/null
+++ b/arch/mips/cpu/mips32/danube/rcu.c
@@ -0,0 +1,125 @@
+/*
+ * Copyright (C) 2011-2013 Daniel Schwierzeck, daniel.schwierzeck@gmail.com
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <asm/lantiq/io.h>
+#include <asm/lantiq/reset.h>
+#include <asm/lantiq/cpu.h>
+#include <asm/arch/soc.h>
+
+#define LTQ_RCU_RD_SRST (1 << 30) /* Global SW Reset */
+#define LTQ_RCU_RD_MC (1 << 14) /* Memory Controller */
+#define LTQ_RCU_RD_PCI (1 << 13) /* PCI core */
+#define LTQ_RCU_RD_DFE_AFE (1 << 12) /* Voice DFE/AFE */
+#define LTQ_RCU_RD_DSL_AFE (1 << 11) /* DSL AFE */
+#define LTQ_RCU_RD_SDIO (1 << 10) /* SDIO core */
+#define LTQ_RCU_RD_DMA (1 << 9) /* DMA core */
+#define LTQ_RCU_RD_PPE (1 << 8) /* PPE core */
+#define LTQ_RCU_RD_ARC_DFE (1 << 7) /* ARC/DFE core */
+#define LTQ_RCU_RD_AHB (1 << 6) /* AHB bus */
+#define LTQ_RCU_RD_ENET_MAC1 (1 << 5) /* Ethernet MAC1 */
+#define LTQ_RCU_RD_USB (1 << 4) /* USB and Phy core */
+#define LTQ_RCU_RD_CPU1 (1 << 3) /* CPU1 subsystem */
+#define LTQ_RCU_RD_FPI (1 << 2) /* FPI bus */
+#define LTQ_RCU_RD_CPU0 (1 << 1) /* CPU0 subsystem */
+#define LTQ_RCU_RD_HRST (1 << 0) /* HW reset via HRST pin */
+
+#define LTQ_RCU_STAT_BOOT_SHIFT 18
+#define LTQ_RCU_STAT_BOOT_MASK (0x7 << LTQ_RCU_STAT_BOOT_SHIFT)
+
+struct ltq_rcu_regs {
+ u32 rsvd0[4];
+ u32 req; /* Reset request */
+ u32 stat; /* Reset status */
+ u32 usb_cfg; /* USB configure */
+ u32 rsvd1[2];
+ u32 pci_rdy; /* PCI boot ready */
+};
+
+static struct ltq_rcu_regs *ltq_rcu_regs =
+ (struct ltq_rcu_regs *) CKSEG1ADDR(LTQ_RCU_BASE);
+
+u32 ltq_reset_map(enum ltq_reset_modules module)
+{
+ u32 val;
+
+ switch (module) {
+ case LTQ_RESET_CORE:
+ case LTQ_RESET_SOFT:
+ val = LTQ_RCU_RD_SRST | LTQ_RCU_RD_CPU1;
+ break;
+ case LTQ_RESET_DMA:
+ val = LTQ_RCU_RD_DMA;
+ break;
+ case LTQ_RESET_ETH:
+ val = LTQ_RCU_RD_PPE;
+ break;
+ case LTQ_RESET_HARD:
+ val = LTQ_RCU_RD_HRST;
+ break;
+ default:
+ val = 0;
+ break;
+ }
+
+ return val;
+}
+
+int ltq_reset_activate(enum ltq_reset_modules module)
+{
+ u32 val;
+
+ val = ltq_reset_map(module);
+ if (unlikely(!val))
+ return 1;
+
+ ltq_setbits(&ltq_rcu_regs->req, val);
+
+ return 0;
+}
+
+int ltq_reset_deactivate(enum ltq_reset_modules module)
+{
+ u32 val;
+
+ val = ltq_reset_map(module);
+ if (unlikely(!val))
+ return 1;
+
+ ltq_clrbits(&ltq_rcu_regs->req, val);
+
+ return 0;
+}
+
+enum ltq_boot_select ltq_boot_select(void)
+{
+ u32 stat;
+ unsigned int bootstrap;
+
+ stat = ltq_readl(&ltq_rcu_regs->stat);
+ bootstrap = (stat & LTQ_RCU_STAT_BOOT_MASK) >> LTQ_RCU_STAT_BOOT_SHIFT;
+
+ switch (bootstrap) {
+ case 0:
+ return BOOT_NOR_NO_BOOTROM;
+ case 1:
+ return BOOT_NOR;
+ case 2:
+ return BOOT_MII0;
+ case 3:
+ return BOOT_PCI;
+ case 4:
+ return BOOT_UART;
+ case 5:
+ return BOOT_SPI;
+ case 6:
+ return BOOT_NAND;
+ case 7:
+ return BOOT_RMII0;
+ default:
+ return BOOT_UNKNOWN;
+ }
+}
--- /dev/null
+++ b/arch/mips/cpu/mips32/lantiq-common/Makefile
@@ -0,0 +1,34 @@
+#
+# Copyright (C) 2000-2011 Wolfgang Denk, DENX Software Engineering, wd@denx.de
+#
+# SPDX-License-Identifier: GPL-2.0+
+#
+
+include $(TOPDIR)/config.mk
+
+LIB = $(obj)liblantiq-common.o
+
+START = start.o
+COBJS-y = cpu.o pmu.o
+COBJS-$(CONFIG_SPL_BUILD) += spl.o
+SOBJS-y = lowlevel_init.o
+
+COBJS := $(COBJS-y)
+SOBJS := $(SOBJS-y)
+SRCS := $(START:.o=.S) $(SOBJS:.o=.S) $(COBJS:.o=.c)
+OBJS := $(addprefix $(obj),$(SOBJS) $(COBJS))
+START := $(addprefix $(obj),$(START))
+
+all: $(LIB)
+
+$(LIB): $(obj).depend $(OBJS)
+ $(call cmd_link_o_target, $(OBJS))
+
+#########################################################################
+
+# defines $(obj).depend target
+include $(SRCTREE)/rules.mk
+
+sinclude $(obj).depend
+
+#########################################################################
--- /dev/null
+++ b/arch/mips/cpu/mips32/lantiq-common/cpu.c
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2012-2013 Daniel Schwierzeck, daniel.schwierzeck@gmail.com
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <asm/lantiq/chipid.h>
+#include <asm/lantiq/clk.h>
+#include <asm/lantiq/reset.h>
+#include <asm/lantiq/cpu.h>
+
+static const char ltq_bootsel_strings[][16] = {
+ "NOR",
+ "NOR w/o BootROM",
+ "UART",
+ "UART w/o EEPROM",
+ "SPI",
+ "NAND",
+ "PCI",
+ "MII0",
+ "RMII0",
+ "RGMII1",
+ "unknown",
+};
+
+const char *ltq_boot_select_str(void)
+{ enum ltq_boot_select bootsel = ltq_boot_select();
+
+ if (bootsel > BOOT_UNKNOWN)
+ bootsel = BOOT_UNKNOWN;
+
+ return ltq_bootsel_strings[bootsel];
+}
+
+void ltq_chip_print_info(void)
+{
+ char buf[32];
+
+ printf("SoC: Lantiq %s v1.%u\n", ltq_chip_partnum_str(),
+ ltq_chip_version_get());
+ printf("CPU: %s MHz\n", strmhz(buf, ltq_get_cpu_clock()));
+ printf("IO: %s MHz\n", strmhz(buf, ltq_get_io_region_clock()));
+ printf("BUS: %s MHz\n", strmhz(buf, ltq_get_bus_clock()));
+ printf("BOOT: %s\n", ltq_boot_select_str());
+}
+
+int arch_cpu_init(void)
+{
+ ltq_pmu_init();
+ ltq_ebu_init();
+
+ return 0;
+}
+
+void _machine_restart(void)
+{
+ ltq_reset_activate(LTQ_RESET_CORE);
+}
--- /dev/null
+++ b/arch/mips/cpu/mips32/lantiq-common/lowlevel_init.S
@@ -0,0 +1,20 @@
+/*
+ * Copyright (C) 2011-2013 Daniel Schwierzeck, daniel.schwierzeck@gmail.com
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <asm/asm.h>
+#include <asm/regdef.h>
+
+NESTED(lowlevel_init, 0, ra)
+ move t8, ra
+
+ la t7, ltq_cgu_init
+ jalr t7
+
+ la t7, ltq_mem_init
+ jalr t7
+
+ jr t8
+ END(lowlevel_init)
--- /dev/null
+++ b/arch/mips/cpu/mips32/lantiq-common/pmu.c
@@ -0,0 +1,9 @@
+/*
+ * Copyright (C) 2011-2013 Daniel Schwierzeck, daniel.schwierzeck@gmail.com
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <asm/lantiq/pm.h>
+
--- /dev/null
+++ b/arch/mips/cpu/mips32/lantiq-common/spl.c
@@ -0,0 +1,403 @@
+/*
+ * Copyright (C) 2011-2013 Daniel Schwierzeck, daniel.schwierzeck@gmail.com
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <image.h>
+#include <version.h>
+#include <spi_flash.h>
+#include <linux/compiler.h>
+#include <lzma/LzmaDec.h>
+#include <linux/lzo.h>
+#include <asm/mipsregs.h>
+
+#if defined(CONFIG_LTQ_SPL_CONSOLE)
+#define spl_has_console 1
+
+#if defined(CONFIG_LTQ_SPL_DEBUG)
+#define spl_has_debug 1
+#else
+#define spl_has_debug 0
+#endif
+
+#else
+#define spl_has_console 0
+#define spl_has_debug 0
+#endif
+
+#define spl_debug(fmt, args...) \
+ do { \
+ if (spl_has_debug) \
+ printf(fmt, ##args); \
+ } while (0)
+
+#define spl_puts(msg) \
+ do { \
+ if (spl_has_console) \
+ puts(msg); \
+ } while (0)
+
+#if defined(CONFIG_LTQ_SUPPORT_SPL_SPI_FLASH) && defined(CONFIG_SYS_BOOT_SFSPL)
+#define spl_boot_spi_flash 1
+#else
+#define spl_boot_spi_flash 0
+#ifndef CONFIG_SPL_SPI_BUS
+#define CONFIG_SPL_SPI_BUS 0
+#endif
+#ifndef CONFIG_SPL_SPI_CS
+#define CONFIG_SPL_SPI_CS 0
+#endif
+#ifndef CONFIG_SPL_SPI_MAX_HZ
+#define CONFIG_SPL_SPI_MAX_HZ 0
+#endif
+#ifndef CONFIG_SPL_SPI_MODE
+#define CONFIG_SPL_SPI_MODE 0
+#endif
+#endif
+
+#if defined(CONFIG_LTQ_SUPPORT_SPL_NOR_FLASH) && defined(CONFIG_SYS_BOOT_NORSPL)
+#define spl_boot_nor_flash 1
+#else
+#define spl_boot_nor_flash 0
+#endif
+
+#define spl_sync() __asm__ __volatile__("sync");
+
+struct spl_image {
+ ulong data_addr;
+ ulong entry_addr;
+ ulong data_size;
+ ulong entry_size;
+ ulong data_crc;
+ u8 comp;
+};
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/* Emulated malloc area needed for LZMA allocator in BSS */
+static u8 *spl_mem_ptr __maybe_unused;
+static size_t spl_mem_size __maybe_unused;
+
+static int spl_is_comp_lzma(const struct spl_image *spl)
+{
+#if defined(CONFIG_LTQ_SPL_COMP_LZMA)
+ return spl->comp == IH_COMP_LZMA;
+#else
+ return 0;
+#endif
+}
+
+static int spl_is_comp_lzo(const struct spl_image *spl)
+{
+#if defined(CONFIG_LTQ_SPL_COMP_LZO)
+ return spl->comp == IH_COMP_LZO;
+#else
+ return 0;
+#endif
+}
+
+static int spl_is_compressed(const struct spl_image *spl)
+{
+ if (spl_is_comp_lzma(spl))
+ return 1;
+
+ if (spl_is_comp_lzo(spl))
+ return 1;
+
+ return 0;
+}
+
+static void spl_console_init(void)
+{
+ if (!spl_has_console)
+ return;
+
+ gd->flags |= GD_FLG_RELOC;
+ gd->baudrate = CONFIG_BAUDRATE;
+
+ serial_init();
+
+ gd->have_console = 1;
+
+ spl_puts("\nU-Boot SPL " PLAIN_VERSION " (" U_BOOT_DATE " - " \
+ U_BOOT_TIME ")\n");
+}
+
+static int spl_parse_image(const image_header_t *hdr, struct spl_image *spl)
+{
+ spl_puts("SPL: checking U-Boot image\n");
+
+ if (!image_check_magic(hdr)) {
+ spl_puts("SPL: invalid magic\n");
+ return -1;
+ }
+
+ if (!image_check_hcrc(hdr)) {
+ spl_puts("SPL: invalid header CRC\n");
+ return -1;
+ }
+
+ spl->data_addr += image_get_header_size();
+ spl->entry_addr = image_get_load(hdr);
+ spl->data_size = image_get_data_size(hdr);
+ spl->data_crc = image_get_dcrc(hdr);
+ spl->comp = image_get_comp(hdr);
+
+ spl_debug("SPL: data %08lx, size %lu, entry %08lx, comp %u\n",
+ spl->data_addr, spl->data_size, spl->entry_addr, spl->comp);
+
+ return 0;
+}
+
+static int spl_check_data(const struct spl_image *spl, ulong loadaddr)
+{
+ ulong dcrc = crc32(0, (unsigned char *)loadaddr, spl->data_size);
+
+ if (dcrc != spl->data_crc) {
+ spl_puts("SPL: invalid data CRC\n");
+ return 0;
+ }
+
+ return 1;
+}
+
+static void *spl_lzma_alloc(void *p, size_t size)
+{
+ u8 *ret;
+
+ if (size > spl_mem_size)
+ return NULL;
+
+ ret = spl_mem_ptr;
+ spl_mem_ptr += size;
+ spl_mem_size -= size;
+
+ return ret;
+}
+
+static void spl_lzma_free(void *p, void *addr)
+{
+}
+
+static int spl_copy_image(struct spl_image *spl)
+{
+ spl_puts("SPL: copying U-Boot to RAM\n");
+
+ memcpy((void *) spl->entry_addr, (const void *) spl->data_addr,
+ spl->data_size);
+
+ spl->entry_size = spl->data_size;
+
+ return 0;
+}
+
+static int spl_uncompress_lzma(struct spl_image *spl, unsigned long loadaddr)
+{
+ SRes res;
+ const Byte *prop = (const Byte *) loadaddr;
+ const Byte *src = (const Byte *) loadaddr + LZMA_PROPS_SIZE +
+ sizeof(uint64_t);
+ Byte *dest = (Byte *) spl->entry_addr;
+ SizeT dest_len = 0xFFFFFFFF;
+ SizeT src_len = spl->data_size - LZMA_PROPS_SIZE;
+ ELzmaStatus status = 0;
+ ISzAlloc alloc;
+
+ spl_puts("SPL: decompressing U-Boot with LZMA\n");
+
+ alloc.Alloc = spl_lzma_alloc;
+ alloc.Free = spl_lzma_free;
+ spl_mem_ptr = (u8 *) CONFIG_SPL_MALLOC_BASE;
+ spl_mem_size = CONFIG_SPL_MALLOC_MAX_SIZE;
+
+ res = LzmaDecode(dest, &dest_len, src, &src_len, prop, LZMA_PROPS_SIZE,
+ LZMA_FINISH_ANY, &status, &alloc);
+ if (res != SZ_OK)
+ return 1;
+
+ spl->entry_size = dest_len;
+
+ return 0;
+}
+
+static int spl_uncompress_lzo(struct spl_image *spl, unsigned long loadaddr)
+{
+ size_t len;
+ int ret;
+
+ spl_puts("SPL: decompressing U-Boot with LZO\n");
+
+ ret = lzop_decompress(
+ (const unsigned char*) loadaddr, spl->data_size,
+ (unsigned char *) spl->entry_addr, &len);
+
+ spl->entry_size = len;
+
+ return ret;
+}
+
+static int spl_uncompress(struct spl_image *spl, unsigned long loadaddr)
+{
+ int ret;
+
+ if (spl_is_comp_lzma(spl))
+ ret = spl_uncompress_lzma(spl, loadaddr);
+ else if (spl_is_comp_lzo(spl))
+ ret = spl_uncompress_lzo(spl, loadaddr);
+ else
+ ret = 1;
+
+ return ret;
+}
+
+static int spl_load_spi_flash(struct spl_image *spl)
+{
+ struct spi_flash sf = { 0 };
+ image_header_t hdr;
+ int ret;
+ unsigned long loadaddr;
+
+ /*
+ * Image format:
+ *
+ * - 12 byte non-volatile bootstrap header
+ * - SPL binary
+ * - 12 byte non-volatile bootstrap header
+ * - 64 byte U-Boot mkimage header
+ * - U-Boot binary
+ */
+ spl->data_addr = image_copy_end() - CONFIG_SPL_TEXT_BASE + 24;
+
+ spl_puts("SPL: probing SPI flash\n");
+
+ spi_init();
+ ret = spl_spi_flash_probe(&sf);
+ if (ret)
+ return ret;
+
+ spl_debug("SPL: reading image header at offset %lx\n", spl->data_addr);
+
+ ret = spi_flash_read(&sf, spl->data_addr, sizeof(hdr), &hdr);
+ if (ret)
+ return ret;
+
+ spl_debug("SPL: checking image header at offset %lx\n", spl->data_addr);
+
+ ret = spl_parse_image(&hdr, spl);
+ if (ret)
+ return ret;
+
+ if (spl_is_compressed(spl))
+ loadaddr = CONFIG_LOADADDR;
+ else
+ loadaddr = spl->entry_addr;
+
+ spl_puts("SPL: loading U-Boot to RAM\n");
+
+ ret = spi_flash_read(&sf, spl->data_addr, spl->data_size,
+ (void *) loadaddr);
+
+ if (!spl_check_data(spl, loadaddr))
+ return -1;
+
+ if (spl_is_compressed(spl))
+ ret = spl_uncompress(spl, loadaddr);
+
+ return ret;
+}
+
+static int spl_load_nor_flash(struct spl_image *spl)
+{
+ const image_header_t *hdr;
+ int ret;
+
+ /*
+ * Image format:
+ *
+ * - SPL binary
+ * - 64 byte U-Boot mkimage header
+ * - U-Boot binary
+ */
+ spl->data_addr = image_copy_end();
+ hdr = (const image_header_t *) image_copy_end();
+
+ spl_debug("SPL: checking image header at address %p\n", hdr);
+
+ ret = spl_parse_image(hdr, spl);
+ if (ret)
+ return ret;
+
+ if (spl_is_compressed(spl))
+ ret = spl_uncompress(spl, spl->data_addr);
+ else
+ ret = spl_copy_image(spl);
+
+ return ret;
+}
+
+static int spl_load(struct spl_image *spl)
+{
+ int ret;
+
+ if (spl_boot_spi_flash)
+ ret = spl_load_spi_flash(spl);
+ else if (spl_boot_nor_flash)
+ ret = spl_load_nor_flash(spl);
+ else
+ ret = 1;
+
+ return ret;
+}
+
+void __noreturn spl_lantiq_init(void)
+{
+ void (*uboot)(void) __noreturn;
+ struct spl_image spl;
+ gd_t gd_data;
+ int ret;
+
+ gd = &gd_data;
+ barrier();
+ memset((void *)gd, 0, sizeof(gd_t));
+
+ spl_console_init();
+
+ spl_debug("SPL: initializing\n");
+
+#if 0
+ spl_debug("CP0_CONFIG: %08x\n", read_c0_config());
+ spl_debug("CP0_CONFIG1: %08x\n", read_c0_config1());
+ spl_debug("CP0_CONFIG2: %08x\n", read_c0_config2());
+ spl_debug("CP0_CONFIG3: %08x\n", read_c0_config3());
+ spl_debug("CP0_CONFIG6: %08x\n", read_c0_config6());
+ spl_debug("CP0_CONFIG7: %08x\n", read_c0_config7());
+ spl_debug("CP0_STATUS: %08x\n", read_c0_status());
+ spl_debug("CP0_PRID: %08x\n", read_c0_prid());
+#endif
+
+ board_early_init_f();
+ timer_init();
+
+ memset(&spl, 0, sizeof(spl));
+
+ ret = spl_load(&spl);
+ if (ret)
+ goto hang;
+
+ spl_debug("SPL: U-Boot entry %08lx\n", spl.entry_addr);
+ spl_puts("SPL: jumping to U-Boot\n");
+
+ flush_cache(spl.entry_addr, spl.entry_size);
+ spl_sync();
+
+ uboot = (void *) spl.entry_addr;
+ uboot();
+
+hang:
+ spl_puts("SPL: cannot start U-Boot\n");
+
+ for (;;)
+ ;
+}
--- /dev/null
+++ b/arch/mips/cpu/mips32/lantiq-common/start.S
@@ -0,0 +1,143 @@
+/*
+ * Copyright (C) 2010 Lantiq Deutschland GmbH
+ * Copyright (C) 2011-2013 Daniel Schwierzeck, daniel.schwierzeck@gmail.com
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <config.h>
+#include <asm/regdef.h>
+#include <asm/mipsregs.h>
+
+#define S_PRIdCoID 16 /* Company ID (R) */
+#define M_PRIdCoID (0xff << S_PRIdCoID)
+#define S_PRIdImp 8 /* Implementation ID (R) */
+#define M_PRIdImp (0xff << S_PRIdImp)
+
+#define K_CacheAttrCWTnWA 0 /* Cacheable, write-thru, no write allocate */
+#define K_CacheAttrCWTWA 1 /* Cacheable, write-thru, write allocate */
+#define K_CacheAttrU 2 /* Uncached */
+#define K_CacheAttrC 3 /* Cacheable */
+#define K_CacheAttrCN 3 /* Cacheable, non-coherent */
+#define K_CacheAttrCCE 4 /* Cacheable, coherent, exclusive */
+#define K_CacheAttrCCS 5 /* Cacheable, coherent, shared */
+#define K_CacheAttrCCU 6 /* Cacheable, coherent, update */
+#define K_CacheAttrUA 7 /* Uncached accelerated */
+
+#define S_ConfigK23 28 /* Kseg2/3 coherency algorithm (FM MMU only) (R/W) */
+#define M_ConfigK23 (0x7 << S_ConfigK23)
+#define W_ConfigK23 3
+#define S_ConfigKU 25 /* Kuseg coherency algorithm (FM MMU only) (R/W) */
+#define M_ConfigKU (0x7 << S_ConfigKU)
+#define W_ConfigKU 3
+
+#define S_ConfigMM 18 /* Merge mode (implementation specific) */
+#define M_ConfigMM (0x1 << S_ConfigMM)
+
+#define S_StatusBEV 22 /* Enable Boot Exception Vectors (R/W) */
+#define M_StatusBEV (0x1 << S_StatusBEV)
+
+#define S_StatusFR 26 /* Enable 64-bit FPRs (R/W) */
+#define M_StatusFR (0x1 << S_StatusFR)
+
+#define S_ConfigK0 0 /* Kseg0 coherency algorithm (R/W) */
+#define M_ConfigK0 (0x7 << S_ConfigK0)
+
+#define CONFIG0_MIPS32_64_MSK 0x8000ffff
+#define STATUS_MIPS32_64_MSK 0xfffcffff
+
+#define STATUS_MIPS24K 0
+#define CONFIG0_MIPS24K ((K_CacheAttrCN << S_ConfigK23) |\
+ (K_CacheAttrCN << S_ConfigKU) |\
+ (M_ConfigMM))
+
+#define STATUS_MIPS34K 0
+#define CONFIG0_MIPS34K ((K_CacheAttrCN << S_ConfigK23) |\
+ (K_CacheAttrCN << S_ConfigKU) |\
+ (M_ConfigMM))
+
+#define STATUS_MIPS32_64 (M_StatusBEV | M_StatusFR)
+#define CONFIG0_MIPS32_64 (K_CacheAttrCN << S_ConfigK0)
+
+#ifdef CONFIG_SOC_XWAY_DANUBE
+#define CONFIG0_LANTIQ (CONFIG0_MIPS24K | CONFIG0_MIPS32_64)
+#define STATUS_LANTIQ (STATUS_MIPS24K | STATUS_MIPS32_64)
+#endif
+
+#ifdef CONFIG_SOC_XWAY_VRX200
+#define CONFIG0_LANTIQ (CONFIG0_MIPS34K | CONFIG0_MIPS32_64)
+#define STATUS_LANTIQ (STATUS_MIPS34K | STATUS_MIPS32_64)
+#endif
+
+
+ .set noreorder
+
+ .globl _start
+ .text
+_start:
+ /* Entry point */
+ b main
+ nop
+
+ /* Lantiq SoC Boot config word */
+ .org 0x10
+#ifdef CONFIG_SYS_XWAY_EBU_BOOTCFG
+ .word CONFIG_SYS_XWAY_EBU_BOOTCFG
+#else
+ .word 0
+#endif
+ .word 0
+
+ .align 4
+main:
+
+ /* Init Timer */
+ mtc0 zero, CP0_COUNT
+ mtc0 zero, CP0_COMPARE
+
+ /* Setup MIPS24K/MIPS34K specifics (implementation dependent fields) */
+ mfc0 t0, CP0_CONFIG
+ li t1, CONFIG0_MIPS32_64_MSK
+ and t0, t1
+ li t1, CONFIG0_LANTIQ
+ or t0, t1
+ mtc0 t0, CP0_CONFIG
+
+ mfc0 t0, CP0_STATUS
+ li t1, STATUS_MIPS32_64_MSK
+ and t0, t1
+ li t1, STATUS_LANTIQ
+ or t0, t1
+ mtc0 t0, CP0_STATUS
+
+ /* Initialize CGU */
+ la t9, ltq_cgu_init
+ jalr t9
+ nop
+
+ /* Initialize memory controller */
+ la t9, ltq_mem_init
+ jalr t9
+ nop
+
+ /* Initialize caches... */
+ la t9, mips_cache_reset
+ jalr t9
+ nop
+
+ /* Clear BSS */
+ la t1, __bss_start
+ la t2, __bss_end
+ sub t1, 4
+1:
+ addi t1, 4
+ bltl t1, t2, 1b
+ sw zero, 0(t1)
+
+ /* Setup stack pointer and force alignment on a 16 byte boundary */
+ li t0, (CONFIG_SPL_STACK_BASE & ~0xF)
+ la sp, 0(t0)
+
+ la t9, spl_lantiq_init
+ jr t9
+ nop
--- /dev/null
+++ b/arch/mips/cpu/mips32/lantiq-common/u-boot-spl.lds
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2011-2013 Daniel Schwierzeck, daniel.schwierzeck@gmail.com
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+MEMORY { .spl_mem : ORIGIN = CONFIG_SPL_TEXT_BASE, \
+ LENGTH = CONFIG_SPL_MAX_SIZE }
+MEMORY { .bss_mem : ORIGIN = CONFIG_SPL_BSS_BASE, \
+ LENGTH = CONFIG_SPL_BSS_MAX_SIZE }
+
+OUTPUT_FORMAT("elf32-tradbigmips", "elf32-tradbigmips", "elf32-tradlittlemips")
+OUTPUT_ARCH(mips)
+ENTRY(_start)
+SECTIONS
+{
+ . = ALIGN(4);
+ .text : {
+ *(.text*)
+ } > .spl_mem
+
+ . = ALIGN(4);
+ .rodata : {
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
+ } > .spl_mem
+
+ . = ALIGN(4);
+ .data : {
+ *(SORT_BY_ALIGNMENT(.data*))
+ *(SORT_BY_ALIGNMENT(.sdata*))
+ } > .spl_mem
+
+ . = ALIGN(4);
+ __image_copy_end = .;
+ uboot_end_data = .;
+
+ .bss : {
+ __bss_start = .;
+ *(.bss*)
+ *(.sbss*)
+ . = ALIGN(4);
+ __bss_end = .;
+ } > .bss_mem
+
+ . = ALIGN(4);
+ __end = .;
+ uboot_end = .;
+}
--- a/arch/mips/cpu/mips32/start.S
+++ b/arch/mips/cpu/mips32/start.S
@@ -105,7 +105,7 @@ reset:
mtc0 zero, CP0_COUNT
mtc0 zero, CP0_COMPARE
-#ifndef CONFIG_SKIP_LOWLEVEL_INIT
+#if !defined(CONFIG_SKIP_LOWLEVEL_INIT) || defined(CONFIG_SYS_DISABLE_CACHE)
/* CONFIG0 register */
li t0, CONF_CM_UNCACHED
mtc0 t0, CP0_CONFIG
--- /dev/null
+++ b/arch/mips/cpu/mips32/vrx200/Makefile
@@ -0,0 +1,32 @@
+#
+# Copyright (C) 2000-2011 Wolfgang Denk, DENX Software Engineering, wd@denx.de
+#
+# SPDX-License-Identifier: GPL-2.0+
+#
+
+include $(TOPDIR)/config.mk
+
+LIB = $(obj)lib$(SOC).o
+
+COBJS-y += cgu.o chipid.o dcdc.o ebu.o gphy.o mem.o pmu.o rcu.o
+SOBJS-y += cgu_init.o mem_init.o
+SOBJS-y += gphy_fw.o
+
+COBJS := $(COBJS-y)
+SOBJS := $(SOBJS-y)
+SRCS := $(SOBJS:.o=.S) $(COBJS:.o=.c)
+OBJS := $(addprefix $(obj),$(SOBJS) $(COBJS))
+
+all: $(LIB)
+
+$(LIB): $(obj).depend $(OBJS)
+ $(call cmd_link_o_target, $(OBJS))
+
+#########################################################################
+
+# defines $(obj).depend target
+include $(SRCTREE)/rules.mk
+
+sinclude $(obj).depend
+
+#########################################################################
--- /dev/null
+++ b/arch/mips/cpu/mips32/vrx200/cgu.c
@@ -0,0 +1,208 @@
+/*
+ * Copyright (C) 2010 Lantiq Deutschland GmbH
+ * Copyright (C) 2011-2013 Daniel Schwierzeck, daniel.schwierzeck@gmail.com
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <asm/arch/soc.h>
+#include <asm/arch/gphy.h>
+#include <asm/lantiq/clk.h>
+#include <asm/lantiq/io.h>
+
+#define LTQ_CGU_PLL1_PLLN_SHIFT 6
+#define LTQ_CGU_PLL1_PLLN_MASK (0x3F << LTQ_CGU_PLL1_PLLN_SHIFT)
+#define LTQ_CGU_PLL1_PLLM_SHIFT 2
+#define LTQ_CGU_PLL1_PLLM_MASK (0xF << LTQ_CGU_PLL1_PLLM_SHIFT)
+#define LTQ_CGU_PLL1_PLLL (1 << 1)
+#define LTQ_CGU_PLL1_PLL_EN 1
+
+#define LTQ_CGU_SYS_OCP_SHIFT 0
+#define LTQ_CGU_SYS_OCP_MASK (0x3 << LTQ_CGU_SYS_OCP_SHIFT)
+#define LTQ_CGU_SYS_CPU_SHIFT 4
+#define LTQ_CGU_SYS_CPU_MASK (0xF << LTQ_CGU_SYS_CPU_SHIFT)
+
+#define LTQ_CGU_UPDATE 1
+
+#define LTQ_CGU_IFCLK_GPHY_SEL_SHIFT 2
+#define LTQ_CGU_IFCLK_GPHY_SEL_MASK (0x7 << LTQ_CGU_IFCLK_GPHY_SEL_SHIFT)
+
+struct ltq_cgu_regs {
+ u32 rsvd0;
+ u32 pll0_cfg; /* PLL0 config */
+ u32 pll1_cfg; /* PLL1 config */
+ u32 sys; /* System clock */
+ u32 clk_fsr; /* Clock frequency select */
+ u32 clk_gsr; /* Clock gating status */
+ u32 clk_gcr0; /* Clock gating control 0 */
+ u32 clk_gcr1; /* Clock gating control 1 */
+ u32 update; /* CGU update control */
+ u32 if_clk; /* Interface clock */
+ u32 ddr; /* DDR memory control */
+ u32 ct1_sr; /* CT status 1 */
+ u32 ct_kval; /* CT K value */
+ u32 pcm_cr; /* PCM control */
+ u32 pci_cr; /* PCI clock control */
+ u32 rsvd1;
+ u32 gphy1_cfg; /* GPHY1 config */
+ u32 gphy0_cfg; /* GPHY0 config */
+ u32 rsvd2[6];
+ u32 pll2_cfg; /* PLL2 config */
+};
+
+static struct ltq_cgu_regs *ltq_cgu_regs =
+ (struct ltq_cgu_regs *) CKSEG1ADDR(LTQ_CGU_BASE);
+
+static inline u32 ltq_cgu_sys_readl(u32 mask, u32 shift)
+{
+ return (ltq_readl(&ltq_cgu_regs->sys) & mask) >> shift;
+}
+
+unsigned long ltq_get_io_region_clock(void)
+{
+ unsigned int ocp_sel;
+ unsigned long clk, cpu_clk;
+
+ cpu_clk = ltq_get_cpu_clock();
+
+ ocp_sel = ltq_cgu_sys_readl(LTQ_CGU_SYS_OCP_MASK,
+ LTQ_CGU_SYS_OCP_SHIFT);
+
+ switch (ocp_sel) {
+ case 0:
+ /* OCP ratio 1 */
+ clk = cpu_clk;
+ break;
+ case 2:
+ /* OCP ratio 2 */
+ clk = cpu_clk / 2;
+ break;
+ case 3:
+ /* OCP ratio 2.5 */
+ clk = (cpu_clk * 2) / 5;
+ break;
+ case 4:
+ /* OCP ratio 3 */
+ clk = cpu_clk / 3;
+ break;
+ default:
+ clk = 0;
+ break;
+ }
+
+ return clk;
+}
+
+unsigned long ltq_get_cpu_clock(void)
+{
+ unsigned int cpu_sel;
+ unsigned long clk;
+
+ cpu_sel = ltq_cgu_sys_readl(LTQ_CGU_SYS_CPU_MASK,
+ LTQ_CGU_SYS_CPU_SHIFT);
+
+ switch (cpu_sel) {
+ case 0:
+ clk = CLOCK_600_MHZ;
+ break;
+ case 1:
+ clk = CLOCK_500_MHZ;
+ break;
+ case 2:
+ clk = CLOCK_393_MHZ;
+ break;
+ case 3:
+ clk = CLOCK_333_MHZ;
+ break;
+ case 5:
+ case 6:
+ clk = CLOCK_197_MHZ;
+ break;
+ case 7:
+ clk = CLOCK_166_MHZ;
+ break;
+ case 4:
+ case 8:
+ case 9:
+ clk = CLOCK_125_MHZ;
+ break;
+ default:
+ clk = 0;
+ break;
+ }
+
+ return clk;
+}
+
+unsigned long ltq_get_bus_clock(void)
+{
+ return ltq_get_io_region_clock();
+}
+
+void ltq_cgu_gphy_clk_src(enum ltq_gphy_clk clk)
+{
+ ltq_clrbits(&ltq_cgu_regs->if_clk, LTQ_CGU_IFCLK_GPHY_SEL_MASK);
+ ltq_setbits(&ltq_cgu_regs->if_clk, clk << LTQ_CGU_IFCLK_GPHY_SEL_SHIFT);
+}
+
+static inline int ltq_cgu_pll1_locked(void)
+{
+ u32 pll1_cfg = ltq_readl(&ltq_cgu_regs->pll1_cfg);
+
+ return pll1_cfg & LTQ_CGU_PLL1_PLLL;
+}
+
+static inline void ltq_cgu_pll1_restart(unsigned m, unsigned n)
+{
+ u32 pll1_cfg;
+
+ ltq_clrbits(&ltq_cgu_regs->pll1_cfg, LTQ_CGU_PLL1_PLL_EN);
+ ltq_setbits(&ltq_cgu_regs->update, LTQ_CGU_UPDATE);
+
+ pll1_cfg = ltq_readl(&ltq_cgu_regs->pll1_cfg);
+ pll1_cfg &= ~(LTQ_CGU_PLL1_PLLN_MASK | LTQ_CGU_PLL1_PLLM_MASK);
+ pll1_cfg |= n << LTQ_CGU_PLL1_PLLN_SHIFT;
+ pll1_cfg |= m << LTQ_CGU_PLL1_PLLM_SHIFT;
+ pll1_cfg |= LTQ_CGU_PLL1_PLL_EN;
+ ltq_writel(&ltq_cgu_regs->pll1_cfg, pll1_cfg);
+ ltq_setbits(&ltq_cgu_regs->update, LTQ_CGU_UPDATE);
+
+ __udelay(1000);
+}
+
+/*
+ * From chapter 9 in errata sheet:
+ *
+ * Under certain condition, the PLL1 may failed to enter into lock
+ * status by hardware default N, M setting.
+ *
+ * Since system always starts from PLL0, the system software can run
+ * and re-program the PLL1 settings.
+ */
+static void ltq_cgu_pll1_init(void)
+{
+ unsigned i;
+ const unsigned pll1_m[] = { 1, 2, 3, 4 };
+ const unsigned pll1_n[] = { 21, 32, 43, 54 };
+
+ /* Check if PLL1 has locked with hardware default settings */
+ if (ltq_cgu_pll1_locked())
+ return;
+
+ for (i = 0; i < 4; i++) {
+ ltq_cgu_pll1_restart(pll1_m[i], pll1_n[i]);
+
+ if (ltq_cgu_pll1_locked())
+ goto done;
+ }
+
+done:
+ /* Restart with hardware default values M=5, N=64 */
+ ltq_cgu_pll1_restart(5, 64);
+}
+
+void ltq_pll_init(void)
+{
+ ltq_cgu_pll1_init();
+}
--- /dev/null
+++ b/arch/mips/cpu/mips32/vrx200/cgu_init.S
@@ -0,0 +1,119 @@
+/*
+ * Copyright (C) 2010 Lantiq Deutschland GmbH
+ * Copyright (C) 2011-2013 Daniel Schwierzeck, daniel.schwierzeck@gmail.com
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <config.h>
+#include <asm/asm.h>
+#include <asm/regdef.h>
+#include <asm/addrspace.h>
+#include <asm/arch/soc.h>
+
+/* RCU module register */
+#define LTQ_RCU_RST_REQ 0x0010 /* Reset request */
+#define LTQ_RCU_RST_REQ_VALUE ((1 << 14) | (1 << 1))
+
+/* CGU module register */
+#define LTQ_CGU_PLL0_CFG 0x0004 /* PLL0 config */
+#define LTQ_CGU_PLL1_CFG 0x0008 /* PLL1 config */
+#define LTQ_CGU_PLL2_CFG 0x0060 /* PLL2 config */
+#define LTQ_CGU_SYS 0x000C /* System clock */
+#define LTQ_CGU_CLK_FSR 0x0010 /* Clock frequency select */
+#define LTQ_CGU_UPDATE 0x0020 /* Clock update control */
+
+/* Valid SYS.CPU values */
+#define LTQ_CGU_SYS_CPU_SHIFT 4
+#define LTQ_CGU_SYS_CPU_600_MHZ 0x0
+#define LTQ_CGU_SYS_CPU_500_MHZ 0x1
+#define LTQ_CGU_SYS_CPU_393_MHZ 0x2
+#define LTQ_CGU_SYS_CPU_333_MHZ 0x3
+#define LTQ_CGU_SYS_CPU_197_MHZ 0x5
+#define LTQ_CGU_SYS_CPU_166_MHZ 0x7
+#define LTQ_CGU_SYS_CPU_125_MHZ 0x9
+
+/* Valid SYS.OCP values */
+#define LTQ_CGU_SYS_OCP_SHIFT 0
+#define LTQ_CGU_SYS_OCP_1 0x0
+#define LTQ_CGU_SYS_OCP_2 0x2
+#define LTQ_CGU_SYS_OCP_2_5 0x3
+#define LTQ_CGU_SYS_OCP_3 0x4
+
+/* Valid CLK_FSR.ETH values */
+#define LTQ_CGU_CLK_FSR_ETH_SHIFT 24
+#define LTQ_CGU_CLK_FSR_ETH_50_MHZ 0x0
+#define LTQ_CGU_CLK_FSR_ETH_25_MHZ 0x1
+#define LTQ_CGU_CLK_FSR_ETH_2_5_MHZ 0x2
+#define LTQ_CGU_CLK_FSR_ETH_125_MHZ 0x3
+
+/* Valid CLK_FSR.PPE values */
+#define LTQ_CGU_CLK_FSR_PPE_SHIFT 16
+#define LTQ_CGU_CLK_FSR_PPE_500_MHZ 0x0 /* Overclock frequency */
+#define LTQ_CGU_CLK_FSR_PPE_450_MHZ 0x1 /* High frequency */
+#define LTQ_CGU_CLK_FSR_PPE_400_MHZ 0x2 /* Low frequency */
+
+#if (CONFIG_SYS_CLOCK_MODE == LTQ_CLK_CPU_500_DDR_250)
+#define LTQ_CGU_SYS_CPU_CONFIG LTQ_CGU_SYS_CPU_500_MHZ
+#define LTQ_CGU_SYS_OCP_CONFIG LTQ_CGU_SYS_OCP_2
+#define LTQ_CGU_CLK_FSR_ETH_CONFIG LTQ_CGU_CLK_FSR_ETH_125_MHZ
+#define LTQ_CGU_CLK_FSR_PPE_CONFIG LTQ_CGU_CLK_FSR_PPE_450_MHZ
+#else
+#error "Invalid system clock configuration!"
+#endif
+
+/* Build register values */
+#define LTQ_CGU_SYS_VALUE ((LTQ_CGU_SYS_CPU_CONFIG << \
+ LTQ_CGU_SYS_CPU_SHIFT) | \
+ LTQ_CGU_SYS_OCP_CONFIG)
+
+#define LTQ_CGU_CLK_FSR_VALUE ((LTQ_CGU_CLK_FSR_ETH_CONFIG << \
+ LTQ_CGU_CLK_FSR_ETH_SHIFT) | \
+ (LTQ_CGU_CLK_FSR_PPE_CONFIG << \
+ LTQ_CGU_CLK_FSR_PPE_SHIFT))
+
+ .set noreorder
+
+LEAF(ltq_cgu_init)
+ /* Load current CGU register values */
+ li t0, (LTQ_CGU_BASE | KSEG1)
+ lw t1, LTQ_CGU_SYS(t0)
+ lw t2, LTQ_CGU_CLK_FSR(t0)
+
+ /* Load target CGU register values */
+ li t3, LTQ_CGU_SYS_VALUE
+ li t4, LTQ_CGU_CLK_FSR_VALUE
+
+ /* Only update registers if values differ */
+ bne t1, t3, update
+ nop
+ beq t2, t4, finished
+ nop
+
+update:
+ /* Store target register values */
+ sw t3, LTQ_CGU_SYS(t0)
+ sw t4, LTQ_CGU_CLK_FSR(t0)
+
+ /* Perform software reset to activate new clock config */
+#if 0
+ li t0, (LTQ_RCU_BASE | KSEG1)
+ lw t1, LTQ_RCU_RST_REQ(t0)
+ or t1, LTQ_RCU_RST_REQ_VALUE
+ sw t1, LTQ_RCU_RST_REQ(t0)
+#else
+ li t1, 1
+ sw t1, LTQ_CGU_UPDATE(t0)
+#endif
+
+#if 0
+wait_reset:
+ b wait_reset
+ nop
+#endif
+
+finished:
+ jr ra
+ nop
+
+ END(ltq_cgu_init)
--- /dev/null
+++ b/arch/mips/cpu/mips32/vrx200/chipid.c
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2011-2013 Daniel Schwierzeck, daniel.schwierzeck@gmail.com
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <asm/lantiq/io.h>
+#include <asm/lantiq/chipid.h>
+#include <asm/arch/soc.h>
+
+#define LTQ_CHIPID_VERSION_SHIFT 28
+#define LTQ_CHIPID_VERSION_MASK (0x7 << LTQ_CHIPID_VERSION_SHIFT)
+#define LTQ_CHIPID_PNUM_SHIFT 12
+#define LTQ_CHIPID_PNUM_MASK (0xFFFF << LTQ_CHIPID_PNUM_SHIFT)
+
+struct ltq_chipid_regs {
+ u32 manid; /* Manufacturer identification */
+ u32 chipid; /* Chip identification */
+};
+
+static struct ltq_chipid_regs *ltq_chipid_regs =
+ (struct ltq_chipid_regs *) CKSEG1ADDR(LTQ_CHIPID_BASE);
+
+unsigned int ltq_chip_version_get(void)
+{
+ u32 chipid;
+
+ chipid = ltq_readl(&ltq_chipid_regs->chipid);
+
+ return (chipid & LTQ_CHIPID_VERSION_MASK) >> LTQ_CHIPID_VERSION_SHIFT;
+}
+
+unsigned int ltq_chip_partnum_get(void)
+{
+ u32 chipid;
+
+ chipid = ltq_readl(&ltq_chipid_regs->chipid);
+
+ return (chipid & LTQ_CHIPID_PNUM_MASK) >> LTQ_CHIPID_PNUM_SHIFT;
+}
+
+const char *ltq_chip_partnum_str(void)
+{
+ enum ltq_chip_partnum partnum = ltq_chip_partnum_get();
+
+ switch (partnum) {
+ case LTQ_SOC_VRX268:
+ case LTQ_SOC_VRX268_2:
+ return "VRX268";
+ case LTQ_SOC_VRX288:
+ case LTQ_SOC_VRX288_2:
+ return "VRX288";
+ case LTQ_SOC_GRX288:
+ case LTQ_SOC_GRX288_2:
+ return "GRX288";
+ default:
+ printf("Unknown partnum: %x\n", partnum);
+ }
+
+ return "";
+}
--- /dev/null
+++ b/arch/mips/cpu/mips32/vrx200/config.mk
@@ -0,0 +1,30 @@
+#
+# Copyright (C) 2011-2013 Daniel Schwierzeck, daniel.schwierzeck@gmail.com
+#
+# SPDX-License-Identifier: GPL-2.0+
+#
+
+PF_CPPFLAGS_XRX := $(call cc-option,-mtune=34kc,)
+PLATFORM_CPPFLAGS += $(PF_CPPFLAGS_XRX)
+
+ifdef CONFIG_SPL_BUILD
+PF_ABICALLS := -mno-abicalls
+PF_PIC := -fno-pic
+PF_PIE :=
+USE_PRIVATE_LIBGCC := yes
+endif
+
+LIBS-y += $(CPUDIR)/lantiq-common/liblantiq-common.o
+
+ifndef CONFIG_SPL_BUILD
+ifdef CONFIG_SYS_BOOT_SFSPL
+ALL-y += $(obj)u-boot.ltq.sfspl
+ALL-$(CONFIG_SPL_LZO_SUPPORT) += $(obj)u-boot.ltq.lzo.sfspl
+ALL-$(CONFIG_SPL_LZMA_SUPPORT) += $(obj)u-boot.ltq.lzma.sfspl
+endif
+ifdef CONFIG_SYS_BOOT_NORSPL
+ALL-y += $(obj)u-boot.ltq.norspl
+ALL-$(CONFIG_SPL_LZO_SUPPORT) += $(obj)u-boot.ltq.lzo.norspl
+ALL-$(CONFIG_SPL_LZMA_SUPPORT) += $(obj)u-boot.ltq.lzma.norspl
+endif
+endif
--- /dev/null
+++ b/arch/mips/cpu/mips32/vrx200/dcdc.c
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2010 Lantiq Deutschland GmbH
+ * Copyright (C) 2011-2013 Daniel Schwierzeck, daniel.schwierzeck@gmail.com
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <asm/arch/soc.h>
+#include <asm/lantiq/io.h>
+
+#define LTQ_DCDC_CLK_SET0_CLK_SEL_P (1 << 6)
+#define LTQ_DCDC_CLK_SET1_SEL_DIV25 (1 << 5)
+#define LTQ_DCDC_CONF_TEST_DIG_PID_FREEZE (1 << 5)
+
+struct ltq_dcdc_regs {
+ u8 b0_coeh; /* Coefficient b0 */
+ u8 b0_coel; /* Coefficient b0 */
+ u8 b1_coeh; /* Coefficient b1 */
+ u8 b1_coel; /* Coefficient b1 */
+ u8 b2_coeh; /* Coefficient b2 */
+ u8 b2_coel; /* Coefficient b2 */
+ u8 clk_set0; /* Clock setup */
+ u8 clk_set1; /* Clock setup */
+ u8 pwm_confh; /* Configure PWM */
+ u8 pwm_confl; /* Configure PWM */
+ u8 bias_vreg0; /* Bias and regulator setup */
+ u8 bias_vreg1; /* Bias and regulator setup */
+ u8 adc_gen0; /* ADC and general control */
+ u8 adc_gen1; /* ADC and general control */
+ u8 adc_con0; /* ADC and general config */
+ u8 adc_con1; /* ADC and general config */
+ u8 conf_test_ana; /* not documented */
+ u8 conf_test_dig; /* not documented */
+ u8 dcdc_status; /* not documented */
+ u8 pid_status; /* not documented */
+ u8 duty_cycle; /* not documented */
+ u8 non_ov_delay; /* not documented */
+ u8 analog_gain; /* not documented */
+ u8 duty_cycle_max_sat; /* not documented */
+ u8 duty_cycle_min_sat; /* not documented */
+ u8 duty_cycle_max; /* not documented */
+ u8 duty_cycle_min; /* not documented */
+ u8 error_max; /* not documented */
+ u8 error_read; /* not documented */
+ u8 delay_deglitch; /* not documented */
+ u8 latch_control; /* not documented */
+ u8 rsvd[240];
+ u8 osc_conf; /* OSC general config */
+ u8 osc_stat; /* OSC general status */
+};
+
+static struct ltq_dcdc_regs *ltq_dcdc_regs =
+ (struct ltq_dcdc_regs *) CKSEG1ADDR(LTQ_DCDC_BASE);
+
+void ltq_dcdc_init(unsigned int dig_ref)
+{
+ u8 dig_ref_cur, val;
+
+ /* Set duty cycle max sat. to 70/90, enable PID freeze */
+ ltq_writeb(&ltq_dcdc_regs->duty_cycle_max_sat, 0x5A);
+ ltq_writeb(&ltq_dcdc_regs->duty_cycle_min_sat, 0x46);
+ val = ltq_readb(&ltq_dcdc_regs->conf_test_dig);
+ val |= LTQ_DCDC_CONF_TEST_DIG_PID_FREEZE;
+ ltq_writeb(&ltq_dcdc_regs->conf_test_dig, val);
+
+ /* Program new coefficients */
+ ltq_writeb(&ltq_dcdc_regs->b0_coeh, 0x00);
+ ltq_writeb(&ltq_dcdc_regs->b0_coel, 0x00);
+ ltq_writeb(&ltq_dcdc_regs->b1_coeh, 0xFF);
+ ltq_writeb(&ltq_dcdc_regs->b1_coel, 0xE6);
+ ltq_writeb(&ltq_dcdc_regs->b2_coeh, 0x00);
+ ltq_writeb(&ltq_dcdc_regs->b2_coel, 0x1B);
+ ltq_writeb(&ltq_dcdc_regs->non_ov_delay, 0x8B);
+
+ /* Set duty cycle max sat. to 60/108, disable PID freeze */
+ ltq_writeb(&ltq_dcdc_regs->duty_cycle_max_sat, 0x6C);
+ ltq_writeb(&ltq_dcdc_regs->duty_cycle_min_sat, 0x3C);
+ val = ltq_readb(&ltq_dcdc_regs->conf_test_dig);
+ val &= ~LTQ_DCDC_CONF_TEST_DIG_PID_FREEZE;
+ ltq_writeb(&ltq_dcdc_regs->conf_test_dig, val);
+
+ /* Init clock and DLL settings */
+ val = ltq_readb(&ltq_dcdc_regs->clk_set0);
+ val |= LTQ_DCDC_CLK_SET0_CLK_SEL_P;
+ ltq_writeb(&ltq_dcdc_regs->clk_set0, val);
+ val = ltq_readb(&ltq_dcdc_regs->clk_set1);
+ val |= LTQ_DCDC_CLK_SET1_SEL_DIV25;
+ ltq_writeb(&ltq_dcdc_regs->clk_set1, val);
+ ltq_writeb(&ltq_dcdc_regs->pwm_confh, 0xF9);
+
+ wmb();
+
+ /* Adapt value of digital reference of DCDC converter */
+ dig_ref_cur = ltq_readb(&ltq_dcdc_regs->bias_vreg1);
+
+ while (dig_ref_cur != dig_ref) {
+ if (dig_ref >= dig_ref_cur)
+ dig_ref_cur++;
+ else if (dig_ref < dig_ref_cur)
+ dig_ref_cur--;
+
+ ltq_writeb(&ltq_dcdc_regs->bias_vreg1, dig_ref_cur);
+ __udelay(1000);
+ }
+}
--- /dev/null
+++ b/arch/mips/cpu/mips32/vrx200/ebu.c
@@ -0,0 +1,126 @@
+/*
+ * Copyright (C) 2011-2013 Daniel Schwierzeck, daniel.schwierzeck@gmail.com
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <asm/arch/soc.h>
+#include <asm/lantiq/io.h>
+
+#define EBU_ADDRSEL_MASK(mask) ((mask & 0xf) << 4)
+#define EBU_ADDRSEL_REGEN (1 << 0)
+
+#define EBU_CON_WRDIS (1 << 31)
+#define EBU_CON_AGEN_DEMUX (0x0 << 24)
+#define EBU_CON_AGEN_MUX (0x2 << 24)
+#define EBU_CON_SETUP (1 << 22)
+#define EBU_CON_WAIT_DIS (0x0 << 20)
+#define EBU_CON_WAIT_ASYNC (0x1 << 20)
+#define EBU_CON_WAIT_SYNC (0x2 << 20)
+#define EBU_CON_WINV (1 << 19)
+#define EBU_CON_PW_8BIT (0x0 << 16)
+#define EBU_CON_PW_16BIT (0x1 << 16)
+#define EBU_CON_ALEC(cycles) ((cycles & 0x3) << 14)
+#define EBU_CON_BCGEN_CS (0x0 << 12)
+#define EBU_CON_BCGEN_INTEL (0x1 << 12)
+#define EBU_CON_BCGEN_MOTOROLA (0x2 << 12)
+#define EBU_CON_WAITWRC(cycles) ((cycles & 0x7) << 8)
+#define EBU_CON_WAITRDC(cycles) ((cycles & 0x3) << 6)
+#define EBU_CON_HOLDC(cycles) ((cycles & 0x3) << 4)
+#define EBU_CON_RECOVC(cycles) ((cycles & 0x3) << 2)
+#define EBU_CON_CMULT_1 0x0
+#define EBU_CON_CMULT_4 0x1
+#define EBU_CON_CMULT_8 0x2
+#define EBU_CON_CMULT_16 0x3
+
+#if defined(CONFIG_LTQ_SUPPORT_NOR_FLASH)
+#define ebu_region0_enable 1
+#else
+#define ebu_region0_enable 0
+#endif
+
+#if ((CONFIG_SYS_MAX_FLASH_BANKS == 2) && defined(CONFIG_LTQ_SUPPORT_NOR_FLASH) )
+#define ebu_region0_addrsel_mask 3
+#else
+#define ebu_region0_addrsel_mask 1
+#endif
+
+#if defined(CONFIG_LTQ_SUPPORT_NAND_FLASH) || ((CONFIG_SYS_MAX_FLASH_BANKS == 2) && defined(CONFIG_LTQ_SUPPORT_NOR_FLASH) )
+#define ebu_region1_enable 1
+#else
+#define ebu_region1_enable 0
+#endif
+
+struct ltq_ebu_regs {
+ u32 clc;
+ u32 rsvd0;
+ u32 id;
+ u32 rsvd1;
+ u32 con;
+ u32 rsvd2[3];
+ u32 addr_sel_0;
+ u32 addr_sel_1;
+ u32 addr_sel_2;
+ u32 addr_sel_3;
+ u32 rsvd3[12];
+ u32 con_0;
+ u32 con_1;
+ u32 con_2;
+ u32 con_3;
+};
+
+static struct ltq_ebu_regs *ltq_ebu_regs =
+ (struct ltq_ebu_regs *) CKSEG1ADDR(LTQ_EBU_BASE);
+
+void ltq_ebu_init(void)
+{
+ if (ebu_region0_enable) {
+ /*
+ * Map EBU region 0 to range 0x10000000-0x13ffffff and enable
+ * region control. This supports up to 32 MiB NOR flash in
+ * bank 0.
+ */
+ ltq_writel(&ltq_ebu_regs->addr_sel_0, LTQ_EBU_REGION0_BASE |
+ EBU_ADDRSEL_MASK(ebu_region0_addrsel_mask) | EBU_ADDRSEL_REGEN);
+
+ ltq_writel(&ltq_ebu_regs->con_0, EBU_CON_AGEN_DEMUX |
+ EBU_CON_WAIT_DIS | EBU_CON_PW_16BIT |
+ EBU_CON_ALEC(3) | EBU_CON_BCGEN_INTEL |
+ EBU_CON_WAITWRC(7) | EBU_CON_WAITRDC(3) |
+ EBU_CON_HOLDC(3) | EBU_CON_RECOVC(3) |
+ EBU_CON_CMULT_16);
+ } else
+ ltq_clrbits(&ltq_ebu_regs->addr_sel_0, EBU_ADDRSEL_REGEN);
+
+ if (ebu_region1_enable) {
+ /*
+ * Map EBU region 1 to range 0x14000000-0x13ffffff and enable
+ * region control. This supports NAND flash in bank 1. (and NOR flash in bank 2)
+ */
+ ltq_writel(&ltq_ebu_regs->addr_sel_1, LTQ_EBU_REGION1_BASE |
+ EBU_ADDRSEL_MASK(3) | EBU_ADDRSEL_REGEN);
+
+ if (ebu_region0_addrsel_mask == 1)
+ ltq_writel(&ltq_ebu_regs->con_1, EBU_CON_AGEN_DEMUX |
+ EBU_CON_SETUP | EBU_CON_WAIT_DIS | EBU_CON_PW_8BIT |
+ EBU_CON_ALEC(3) | EBU_CON_BCGEN_INTEL |
+ EBU_CON_WAITWRC(2) | EBU_CON_WAITRDC(2) |
+ EBU_CON_HOLDC(1) | EBU_CON_RECOVC(1) |
+ EBU_CON_CMULT_4);
+
+ if (ebu_region0_addrsel_mask == 3)
+ ltq_writel(&ltq_ebu_regs->con_1, EBU_CON_AGEN_DEMUX |
+ EBU_CON_WAIT_DIS | EBU_CON_PW_16BIT |
+ EBU_CON_ALEC(3) | EBU_CON_BCGEN_INTEL |
+ EBU_CON_WAITWRC(7) | EBU_CON_WAITRDC(3) |
+ EBU_CON_HOLDC(3) | EBU_CON_RECOVC(3) |
+ EBU_CON_CMULT_16);
+ } else
+ ltq_clrbits(&ltq_ebu_regs->addr_sel_1, EBU_ADDRSEL_REGEN);
+}
+
+void *flash_swap_addr(unsigned long addr)
+{
+ return (void *)(addr ^ 2);
+}
--- /dev/null
+++ b/arch/mips/cpu/mips32/vrx200/gphy.c
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2011-2013 Daniel Schwierzeck, daniel.schwierzeck@gmail.com
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <asm/lantiq/io.h>
+#include <asm/arch/soc.h>
+#include <asm/arch/gphy.h>
+#include <lzma/LzmaTypes.h>
+#include <lzma/LzmaDec.h>
+#include <lzma/LzmaTools.h>
+
+static inline void ltq_gphy_decompress(const void *fw_start, const void *fw_end,
+ ulong dst_addr)
+{
+ const ulong fw_len = (ulong) fw_end - (ulong) fw_start;
+ const ulong addr = CKSEG1ADDR(dst_addr);
+
+ debug("ltq_gphy_decompress: addr %08lx, fw_start %p, fw_end %p\n",
+ addr, fw_start, fw_end);
+
+ SizeT lzma_len = 65536;
+ int ret = lzmaBuffToBuffDecompress(
+ (unsigned char *)addr, &lzma_len,
+ (unsigned char *)fw_start, fw_len);
+}
+
+void ltq_gphy_phy11g_a1x_load(ulong addr)
+{
+ extern ulong __ltq_fw_phy11g_a1x_start;
+ extern ulong __ltq_fw_phy11g_a1x_end;
+
+ ltq_gphy_decompress(&__ltq_fw_phy11g_a1x_start,
+ &__ltq_fw_phy11g_a1x_end,
+ addr);
+}
+
+void ltq_gphy_phy11g_a2x_load(ulong addr)
+{
+ extern ulong __ltq_fw_phy11g_a2x_start;
+ extern ulong __ltq_fw_phy11g_a2x_end;
+
+ ltq_gphy_decompress(&__ltq_fw_phy11g_a2x_start,
+ &__ltq_fw_phy11g_a2x_end,
+ addr);
+}
+
+void ltq_gphy_phy22f_a1x_load(ulong addr)
+{
+ extern ulong __ltq_fw_phy22f_a1x_start;
+ extern ulong __ltq_fw_phy22f_a1x_end;
+
+ ltq_gphy_decompress(&__ltq_fw_phy22f_a1x_start,
+ &__ltq_fw_phy22f_a1x_end,
+ addr);
+}
+
+void ltq_gphy_phy22f_a2x_load(ulong addr)
+{
+ extern ulong __ltq_fw_phy22f_a2x_start;
+ extern ulong __ltq_fw_phy22f_a2x_end;
+
+ ltq_gphy_decompress(&__ltq_fw_phy22f_a2x_start,
+ &__ltq_fw_phy22f_a2x_end,
+ addr);
+}
--- /dev/null
+++ b/arch/mips/cpu/mips32/vrx200/gphy_fw.S
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2011-2013 Daniel Schwierzeck, daniel.schwierzeck@gmail.com
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <asm/asm.h>
+
+ .section .rodata.__ltq_fw_phy11g_a1x
+EXPORT(__ltq_fw_phy11g_a1x_start)
+ .incbin "fw_phy11g_a1x.blob"
+EXPORT(__ltq_fw_phy11g_a1x_end)
+
+ .section .rodata.__ltq_fw_phy11g_a2x
+EXPORT(__ltq_fw_phy11g_a2x_start)
+ .incbin "fw_phy11g_a2x.blob"
+EXPORT(__ltq_fw_phy11g_a2x_end)
+
+ .section .rodata.__ltq_fw_phy22f_a1x
+EXPORT(__ltq_fw_phy22f_a1x_start)
+ .incbin "fw_phy22f_a1x.blob"
+EXPORT(__ltq_fw_phy22f_a1x_end)
+
+ .section .rodata.__ltq_fw_phy22f_a2x
+EXPORT(__ltq_fw_phy22f_a2x_start)
+ .incbin "fw_phy22f_a2x.blob"
+EXPORT(__ltq_fw_phy22f_a2x_end)
--- /dev/null
+++ b/arch/mips/cpu/mips32/vrx200/mem.c
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2011-2013 Daniel Schwierzeck, daniel.schwierzeck@gmail.com
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <asm/arch/soc.h>
+#include <asm/lantiq/io.h>
+
+#define LTQ_CCR03_EIGHT_BANK_MODE (1 << 0)
+#define LTQ_CCR08_CS_MAP_SHIFT 24
+#define LTQ_CCR08_CS_MAP_MASK (0x3 << LTQ_CCR08_CS_MAP_SHIFT)
+#define LTQ_CCR11_COLUMN_SIZE_SHIFT 24
+#define LTQ_CCR11_COLUMN_SIZE_MASK (0x7 << LTQ_CCR11_COLUMN_SIZE_SHIFT)
+#define LTQ_CCR11_ADDR_PINS_MASK 0x7
+#define LTQ_CCR15_MAX_COL_REG_SHIFT 24
+#define LTQ_CCR15_MAX_COL_REG_MASK (0xF << LTQ_CCR15_MAX_COL_REG_SHIFT)
+#define LTQ_CCR16_MAX_ROW_REG_MASK 0xF
+
+static void *ltq_mc_ddr_base = (void *) CKSEG1ADDR(LTQ_MC_DDR_BASE);
+
+static inline u32 ltq_mc_ccr_read(u32 index)
+{
+ return ltq_readl(ltq_mc_ddr_base + LTQ_MC_DDR_CCR_OFFSET(index));
+}
+
+phys_size_t initdram(int board_type)
+{
+ u32 max_col_reg, max_row_reg, column_size, addr_pins;
+ u32 banks, cs_map;
+ phys_size_t size;
+
+ banks = (ltq_mc_ccr_read(3) & LTQ_CCR03_EIGHT_BANK_MODE) ? 8 : 4;
+
+ cs_map = (ltq_mc_ccr_read(8) & LTQ_CCR08_CS_MAP_MASK) >>
+ LTQ_CCR08_CS_MAP_SHIFT;
+
+ column_size = (ltq_mc_ccr_read(11) & LTQ_CCR11_COLUMN_SIZE_MASK) >>
+ LTQ_CCR11_COLUMN_SIZE_SHIFT;
+
+ addr_pins = ltq_mc_ccr_read(11) & LTQ_CCR11_ADDR_PINS_MASK;
+
+ max_col_reg = (ltq_mc_ccr_read(15) & LTQ_CCR15_MAX_COL_REG_MASK) >>
+ LTQ_CCR15_MAX_COL_REG_SHIFT;
+
+ max_row_reg = ltq_mc_ccr_read(16) & LTQ_CCR16_MAX_ROW_REG_MASK;
+
+ /*
+ * size (bytes) = 2 ^ rowsize * 2 ^ colsize * banks * chipselects
+ * * datawidth (bytes)
+ */
+ size = (2 << (max_col_reg - column_size - 1)) *
+ (2 << (max_row_reg - addr_pins - 1)) * banks * cs_map * 2;
+
+ return size;
+}
--- /dev/null
+++ b/arch/mips/cpu/mips32/vrx200/mem_init.S
@@ -0,0 +1,233 @@
+/*
+ * Copyright (C) 2010 Lantiq Deutschland GmbH
+ * Copyright (C) 2011-2013 Daniel Schwierzeck, daniel.schwierzeck@gmail.com
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <config.h>
+#include <asm/asm.h>
+#include <asm/regdef.h>
+#include <asm/addrspace.h>
+#include <asm/arch/soc.h>
+
+/* Must be configured in BOARDDIR */
+#include <ddr_settings.h>
+
+#define LTQ_MC_DDR_START (1 << 8)
+#define LTQ_MC_DDR_DLL_LOCK_IND 1
+
+#define CCS_ALWAYS_LAST 0x0430
+#define CCS_AHBM_CR_BURST_EN (1 << 2)
+#define CCS_FPIM_CR_BURST_EN (1 << 1)
+
+#define CCR03_EIGHT_BANK_MODE (1 << 0)
+
+ /* Store given value in MC DDR CCRx register */
+ .macro ccr_sw num, val
+ li t1, \val
+ sw t1, LTQ_MC_DDR_CCR_OFFSET(\num)(t0)
+ .endm
+
+LEAF(ltq_mem_init)
+ /* Load MC DDR module base */
+ li t0, (LTQ_MC_DDR_BASE | KSEG1)
+
+ /* Put memory controller in inactive mode */
+ sw zero, LTQ_MC_DDR_CCR_OFFSET(7)(t0)
+
+ /* Init MC DDR CCR registers with values from ddr_settings.h */
+ ccr_sw 0, MC_CCR00_VALUE
+ ccr_sw 1, MC_CCR01_VALUE
+ ccr_sw 2, MC_CCR02_VALUE
+ ccr_sw 3, MC_CCR03_VALUE
+ ccr_sw 4, MC_CCR04_VALUE
+ ccr_sw 5, MC_CCR05_VALUE
+ ccr_sw 6, MC_CCR06_VALUE
+ ccr_sw 7, MC_CCR07_VALUE
+ ccr_sw 8, MC_CCR08_VALUE
+ ccr_sw 9, MC_CCR09_VALUE
+
+ ccr_sw 10, MC_CCR10_VALUE
+ ccr_sw 11, MC_CCR11_VALUE
+ ccr_sw 12, MC_CCR12_VALUE
+ ccr_sw 13, MC_CCR13_VALUE
+ ccr_sw 14, MC_CCR14_VALUE
+ ccr_sw 15, MC_CCR15_VALUE
+ ccr_sw 16, MC_CCR16_VALUE
+ ccr_sw 17, MC_CCR17_VALUE
+ ccr_sw 18, MC_CCR18_VALUE
+ ccr_sw 19, MC_CCR19_VALUE
+
+ ccr_sw 20, MC_CCR20_VALUE
+ ccr_sw 21, MC_CCR21_VALUE
+ ccr_sw 22, MC_CCR22_VALUE
+ ccr_sw 23, MC_CCR23_VALUE
+ ccr_sw 24, MC_CCR24_VALUE
+ ccr_sw 25, MC_CCR25_VALUE
+ ccr_sw 26, MC_CCR26_VALUE
+ ccr_sw 27, MC_CCR27_VALUE
+ ccr_sw 28, MC_CCR28_VALUE
+ ccr_sw 29, MC_CCR29_VALUE
+
+ ccr_sw 30, MC_CCR30_VALUE
+ ccr_sw 31, MC_CCR31_VALUE
+ ccr_sw 32, MC_CCR32_VALUE
+ ccr_sw 33, MC_CCR33_VALUE
+ ccr_sw 34, MC_CCR34_VALUE
+ ccr_sw 35, MC_CCR35_VALUE
+ ccr_sw 36, MC_CCR36_VALUE
+ ccr_sw 37, MC_CCR37_VALUE
+ ccr_sw 38, MC_CCR38_VALUE
+ ccr_sw 39, MC_CCR39_VALUE
+
+ ccr_sw 40, MC_CCR40_VALUE
+ ccr_sw 41, MC_CCR41_VALUE
+ ccr_sw 42, MC_CCR42_VALUE
+ ccr_sw 43, MC_CCR43_VALUE
+ ccr_sw 44, MC_CCR44_VALUE
+ ccr_sw 45, MC_CCR45_VALUE
+ ccr_sw 46, MC_CCR46_VALUE
+
+ ccr_sw 52, MC_CCR52_VALUE
+ ccr_sw 53, MC_CCR53_VALUE
+ ccr_sw 54, MC_CCR54_VALUE
+ ccr_sw 55, MC_CCR55_VALUE
+ ccr_sw 56, MC_CCR56_VALUE
+ ccr_sw 57, MC_CCR57_VALUE
+ ccr_sw 58, MC_CCR58_VALUE
+ ccr_sw 59, MC_CCR59_VALUE
+
+ ccr_sw 60, MC_CCR60_VALUE
+ ccr_sw 61, MC_CCR61_VALUE
+
+ /* Disable bursts between FPI Master bus and XBAR bus */
+ li t4, (LTQ_MC_GLOBAL_BASE | KSEG1)
+ li t5, CCS_AHBM_CR_BURST_EN
+ sw t5, CCS_ALWAYS_LAST(t4)
+
+ /* Init abort condition for DRAM probe */
+ move t4, zero
+
+ /*
+ * Put memory controller in active mode and start initialitation
+ * sequence for connected DDR-SDRAM device
+ */
+mc_start:
+ lw t1, LTQ_MC_DDR_CCR_OFFSET(7)(t0)
+ li t2, LTQ_MC_DDR_START
+ or t1, t1, t2
+ sw t1, LTQ_MC_DDR_CCR_OFFSET(7)(t0)
+
+ /*
+ * Wait until DLL has locked and core is ready for data transfers.
+ * DLL lock indication is in register CCR47 and CCR48
+ */
+wait_ready:
+ li t1, LTQ_MC_DDR_DLL_LOCK_IND
+ lw t2, LTQ_MC_DDR_CCR_OFFSET(47)(t0)
+ and t2, t2, t1
+ bne t1, t2, wait_ready
+
+ lw t2, LTQ_MC_DDR_CCR_OFFSET(48)(t0)
+ and t2, t2, t1
+ bne t1, t2, wait_ready
+
+#ifdef CONFIG_SYS_DRAM_PROBE
+dram_probe:
+ /* Initialization is finished after the second MC start */
+ bnez t4, mc_finished
+
+ /*
+ * Preload register values for CCR03 and CCR11. Initial settings
+ * are 8-bank mode enabled, 14 use address row bits, 10 used
+ * column address bits.
+ */
+ li t1, CONFIG_SYS_SDRAM_BASE_UC
+ li t5, MC_CCR03_VALUE
+ li t6, MC_CCR11_VALUE
+ addi t4, t4, 1
+
+ /*
+ * Store test values to DRAM at offsets 0 and 2^13 (bit 2 in bank select
+ * address BA[3]) and read back the value at offset 0. If the resulting
+ * value is equal to 1 we can skip to the next test. Otherwise
+ * the 8-bank mode does not work with the current DRAM device,
+ * thus we need to clear the according bit in register CCR03.
+ */
+ li t2, 1
+ sw t2, 0x0(t1)
+ li t3, (1 << 13)
+ add t3, t3, t1
+ sw zero, 0(t3)
+ lw t3, 0(t1)
+ bnez t3, row_col_test
+
+ /* Clear CCR03.EIGHT_BANK_MODE */
+ li t3, ~CCR03_EIGHT_BANK_MODE
+ and t5, t5, t3
+
+row_col_test:
+ /*
+ * Store test values to DRAM at offsets 0, 2^27 (bit 13 of row address
+ * RA[14]) and 2^26 (bit 12 of RA[14]). The chosen test values
+ * represent the difference between max. row address bits (14) and used
+ * row address bits. Then the read back value at offset 0 indicates
+ * the useable row address bits with the current DRAM device. This
+ * value must be set in the CCR11 register.
+ */
+ sw zero, 0(t1)
+
+ li t2, 1
+ li t3, (1 << 27)
+ add t3, t3, t1
+ sw t2, 0(t3)
+
+ li t2, 2
+ li t3, (1 << 26)
+ add t3, t3, t1
+ sw t2, 0(t3)
+
+ /* Update CCR11.ADDR_PINS */
+ lw t3, 0(t1)
+ add t6, t6, t3
+
+ /*
+ * Store test values to DRAM at offsets 0, 2^10 (bit 9 of column address
+ * CA[10]) and 2^9 (bit 8 of CA[10]). The chosen test values represent
+ * the difference between max. column address bits (12) and used
+ * column address bits. Then the read back value at offset 0 indicates
+ * the useable column address bits with the current DRAM device. This
+ * value must be set in the CCR11 register.
+ */
+ sw zero, 0(t1)
+
+ li t2, 1
+ li t3, (1 << 10)
+ add t3, t3, t1
+ sw t2, 0(t3)
+
+ li t2, 2
+ li t3, (1 << 9)
+ add t3, t3, t1
+ sw t2, 0(t3)
+
+ /* Update CCR11.COLUMN_SIZE */
+ lw t3, 0(t1)
+ sll t3, t3, 24
+ add t6, t6, t3
+
+ /* Put memory controller in inactive mode */
+ sw zero, LTQ_MC_DDR_CCR_OFFSET(7)(t0)
+
+ /* Update CCR03 and CCR11 and restart memory controller initialiation */
+ sw t5, LTQ_MC_DDR_CCR_OFFSET(3)(t0)
+ sw t6, LTQ_MC_DDR_CCR_OFFSET(11)(t0)
+ b mc_start
+
+mc_finished:
+#endif /* CONFIG_SYS_DRAM_PROBE */
+
+ jr ra
+
+ END(ltq_mem_init)
--- /dev/null
+++ b/arch/mips/cpu/mips32/vrx200/pmu.c
@@ -0,0 +1,130 @@
+/*
+ * Copyright (C) 2011-2013 Daniel Schwierzeck, daniel.schwierzeck@gmail.com
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <asm/lantiq/io.h>
+#include <asm/lantiq/pm.h>
+#include <asm/arch/soc.h>
+
+#define LTQ_PMU_PWDCR_RESERVED ((1 << 13) | (1 << 4))
+
+#define LTQ_PMU_PWDCR_PCIELOC_EN (1 << 31)
+#define LTQ_PMU_PWDCR_GPHY (1 << 30)
+#define LTQ_PMU_PWDCR_PPE_TOP (1 << 29)
+#define LTQ_PMU_PWDCR_SWITCH (1 << 28)
+#define LTQ_PMU_PWDCR_USB1 (1 << 27)
+#define LTQ_PMU_PWDCR_USB1_PHY (1 << 26)
+#define LTQ_PMU_PWDCR_TDM (1 << 25)
+#define LTQ_PMU_PWDCR_PPE_DPLUS (1 << 24)
+#define LTQ_PMU_PWDCR_PPE_DPLUM (1 << 23)
+#define LTQ_PMU_PWDCR_PPE_EMA (1 << 22)
+#define LTQ_PMU_PWDCR_PPE_TC (1 << 21)
+#define LTQ_PMU_PWDCR_DEU (1 << 20)
+#define LTQ_PMU_PWDCR_PPE_SLL01 (1 << 19)
+#define LTQ_PMU_PWDCR_PPE_QSB (1 << 18)
+#define LTQ_PMU_PWDCR_UART1 (1 << 17)
+#define LTQ_PMU_PWDCR_SDIO (1 << 16)
+#define LTQ_PMU_PWDCR_AHBM (1 << 15)
+#define LTQ_PMU_PWDCR_FPIM (1 << 14)
+#define LTQ_PMU_PWDCR_GPTC (1 << 12)
+#define LTQ_PMU_PWDCR_LEDC (1 << 11)
+#define LTQ_PMU_PWDCR_EBU (1 << 10)
+#define LTQ_PMU_PWDCR_DSL (1 << 9)
+#define LTQ_PMU_PWDCR_SPI (1 << 8)
+#define LTQ_PMU_PWDCR_USIF (1 << 7)
+#define LTQ_PMU_PWDCR_USB0 (1 << 6)
+#define LTQ_PMU_PWDCR_DMA (1 << 5)
+#define LTQ_PMU_PWDCR_DFEV1 (1 << 3)
+#define LTQ_PMU_PWDCR_DFEV0 (1 << 2)
+#define LTQ_PMU_PWDCR_FPIS (1 << 1)
+#define LTQ_PMU_PWDCR_USB0_PHY (1 << 0)
+
+struct ltq_pmu_regs {
+ u32 rsvd0[7];
+ u32 pwdcr; /* Power down control */
+ u32 sr; /* Power down status */
+ u32 pwdcr1; /* Power down control 1 */
+ u32 sr1; /* Power down status 1 */
+};
+
+static struct ltq_pmu_regs *ltq_pmu_regs =
+ (struct ltq_pmu_regs *) CKSEG1ADDR(LTQ_PMU_BASE);
+
+u32 ltq_pm_map(enum ltq_pm_modules module)
+{
+ u32 val;
+
+ switch (module) {
+ case LTQ_PM_CORE:
+ val = LTQ_PMU_PWDCR_UART1 | LTQ_PMU_PWDCR_FPIM |
+ LTQ_PMU_PWDCR_LEDC | LTQ_PMU_PWDCR_EBU;
+ break;
+ case LTQ_PM_DMA:
+ val = LTQ_PMU_PWDCR_DMA;
+ break;
+ case LTQ_PM_ETH:
+ val = LTQ_PMU_PWDCR_GPHY | LTQ_PMU_PWDCR_PPE_TOP |
+ LTQ_PMU_PWDCR_SWITCH | LTQ_PMU_PWDCR_PPE_DPLUS |
+ LTQ_PMU_PWDCR_PPE_DPLUM | LTQ_PMU_PWDCR_PPE_EMA |
+ LTQ_PMU_PWDCR_PPE_TC | LTQ_PMU_PWDCR_PPE_SLL01 |
+ LTQ_PMU_PWDCR_PPE_QSB;
+ break;
+ case LTQ_PM_SPI:
+ val = LTQ_PMU_PWDCR_SPI;
+ break;
+ default:
+ val = 0;
+ break;
+ }
+
+ return val;
+}
+
+int ltq_pm_enable(enum ltq_pm_modules module)
+{
+ const unsigned long timeout = 1000;
+ unsigned long timebase;
+ u32 sr, val;
+
+ val = ltq_pm_map(module);
+ if (unlikely(!val))
+ return 1;
+
+ ltq_clrbits(&ltq_pmu_regs->pwdcr, val);
+
+ timebase = get_timer(0);
+
+ do {
+ sr = ltq_readl(&ltq_pmu_regs->sr);
+ if (~sr & val)
+ return 0;
+ } while (get_timer(timebase) < timeout);
+
+ return 1;
+}
+
+int ltq_pm_disable(enum ltq_pm_modules module)
+{
+ u32 val;
+
+ val = ltq_pm_map(module);
+ if (unlikely(!val))
+ return 1;
+
+ ltq_setbits(&ltq_pmu_regs->pwdcr, val);
+
+ return 0;
+}
+
+void ltq_pmu_init(void)
+{
+ u32 set, clr;
+
+ clr = ltq_pm_map(LTQ_PM_CORE);
+ set = ~(LTQ_PMU_PWDCR_RESERVED | clr);
+
+ ltq_clrsetbits(&ltq_pmu_regs->pwdcr, clr, set);
+}
--- /dev/null
+++ b/arch/mips/cpu/mips32/vrx200/rcu.c
@@ -0,0 +1,194 @@
+/*
+ * Copyright (C) 2011-2013 Daniel Schwierzeck, daniel.schwierzeck@gmail.com
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <asm/lantiq/io.h>
+#include <asm/lantiq/reset.h>
+#include <asm/lantiq/cpu.h>
+#include <asm/arch/soc.h>
+
+#define LTQ_RCU_RD_GPHY0 (1 << 31) /* GPHY0 */
+#define LTQ_RCU_RD_SRST (1 << 30) /* Global SW Reset */
+#define LTQ_RCU_RD_GPHY1 (1 << 29) /* GPHY1 */
+#define LTQ_RCU_RD_ENMIP2 (1 << 28) /* Enable NMI of PLL2 */
+#define LTQ_RCU_RD_REG25_PD (1 << 26) /* Power down 2.5V regulator */
+#define LTQ_RCU_RD_ENDINIT (1 << 25) /* FPI slave bus access */
+#define LTQ_RCU_RD_PPE_ATM_TC (1 << 23) /* PPE ATM TC */
+#define LTQ_RCU_RD_PCIE (1 << 22) /* PCI-E core */
+#define LTQ_RCU_RD_ETHSW (1 << 21) /* Ethernet switch */
+#define LTQ_RCU_RD_DSP_DEN (1 << 20) /* Enable DSP JTAG */
+#define LTQ_RCU_RD_TDM (1 << 19) /* TDM module interface */
+#define LTQ_RCU_RD_ENMIP1 (1 << 18) /* Enable NMI of PLL1 */
+#define LTQ_RCU_RD_SWBCK (1 << 17) /* Switch backward compat */
+#define LTQ_RCU_RD_HSNAND (1 << 16) /* HSNAND controller */
+#define LTQ_RCU_RD_ENMIP0 (1 << 15) /* Enable NMI of PLL0 */
+#define LTQ_RCU_RD_MC (1 << 14) /* Memory Controller */
+#define LTQ_RCU_RD_PCI (1 << 13) /* PCI core */
+#define LTQ_RCU_RD_PCIE_PHY (1 << 12) /* PCI-E Phy */
+#define LTQ_RCU_RD_DFE_CORE (1 << 11) /* DFE core */
+#define LTQ_RCU_RD_SDIO (1 << 10) /* SDIO core */
+#define LTQ_RCU_RD_DMA (1 << 9) /* DMA core */
+#define LTQ_RCU_RD_PPE (1 << 8) /* PPE core */
+#define LTQ_RCU_RD_DFE (1 << 7) /* DFE core */
+#define LTQ_RCU_RD_AHB (1 << 6) /* AHB bus */
+#define LTQ_RCU_RD_HRST_CFG (1 << 5) /* HW reset configuration */
+#define LTQ_RCU_RD_USB (1 << 4) /* USB and Phy core */
+#define LTQ_RCU_RD_PPE_DSP (1 << 3) /* PPE DSP interface */
+#define LTQ_RCU_RD_FPI (1 << 2) /* FPI bus */
+#define LTQ_RCU_RD_CPU (1 << 1) /* CPU subsystem */
+#define LTQ_RCU_RD_HRST (1 << 0) /* HW reset via HRST pin */
+
+#define LTQ_RCU_STAT_BOOT_SHIFT 17
+#define LTQ_RCU_STAT_BOOT_MASK (0xF << LTQ_RCU_STAT_BOOT_SHIFT)
+#define LTQ_RCU_STAT_BOOT_H (1 << 12)
+
+#define LTQ_RCU_GP_STRAP_CLOCKSOURCE (1 << 15)
+
+struct ltq_rcu_regs {
+ u32 rsvd0[4];
+ u32 req; /* Reset request */
+ u32 stat; /* Reset status */
+ u32 usb0_cfg; /* USB0 configure */
+ u32 gp_strap; /* GPIO strapping */
+ u32 gfs_add0; /* GPHY0 firmware base addr */
+ u32 stat2; /* SLIC and USB reset status */
+ u32 pci_rdy; /* PCI boot ready */
+ u32 ppe_conf; /* PPE ethernet config */
+ u32 pcie_phy_con; /* PCIE PHY config/status */
+ u32 usb1_cfg; /* USB1 configure */
+ u32 usb_ana_cfg1a; /* USB analog config 1a */
+ u32 usb_ana_cfg1b; /* USB analog config 1b */
+ u32 rsvd1;
+ u32 gf_mdio_add; /* GPHY0/1 MDIO address */
+ u32 req2; /* SLIC and USB reset request */
+ u32 ahb_endian; /* AHB bus endianess */
+ u32 rsvd2[4];
+ u32 gcc; /* General CPU config */
+ u32 rsvd3;
+ u32 gfs_add1; /* GPHY1 firmware base addr */
+};
+
+static struct ltq_rcu_regs *ltq_rcu_regs =
+ (struct ltq_rcu_regs *) CKSEG1ADDR(LTQ_RCU_BASE);
+
+u32 ltq_reset_map(enum ltq_reset_modules module)
+{
+ u32 val;
+
+ switch (module) {
+ case LTQ_RESET_CORE:
+ case LTQ_RESET_SOFT:
+ val = LTQ_RCU_RD_SRST | LTQ_RCU_RD_CPU | LTQ_RCU_RD_ENMIP2 |
+ LTQ_RCU_RD_GPHY1 | LTQ_RCU_RD_GPHY0;
+ break;
+ case LTQ_RESET_DMA:
+ val = LTQ_RCU_RD_DMA;
+ break;
+ case LTQ_RESET_ETH:
+ val = LTQ_RCU_RD_PPE | LTQ_RCU_RD_ETHSW;
+ break;
+ case LTQ_RESET_PHY:
+ val = LTQ_RCU_RD_GPHY1 | LTQ_RCU_RD_GPHY0;
+ break;
+ case LTQ_RESET_HARD:
+ val = LTQ_RCU_RD_HRST;
+ break;
+ default:
+ val = 0;
+ break;
+ }
+
+ return val;
+}
+
+int ltq_reset_activate(enum ltq_reset_modules module)
+{
+ u32 val;
+
+ val = ltq_reset_map(module);
+ if (unlikely(!val))
+ return 1;
+
+ ltq_setbits(&ltq_rcu_regs->req, val);
+
+ return 0;
+}
+
+int ltq_reset_deactivate(enum ltq_reset_modules module)
+{
+ u32 val;
+
+ val = ltq_reset_map(module);
+ if (unlikely(!val))
+ return 1;
+
+ ltq_clrbits(&ltq_rcu_regs->req, val);
+
+ return 0;
+}
+
+enum ltq_boot_select ltq_boot_select(void)
+{
+ u32 stat;
+ unsigned int bootstrap;
+
+ /*
+ * Boot select value is built from bits 20-17 and bit 12.
+ * The bit sequence is read as 4-2-1-0-3.
+ */
+ stat = ltq_readl(&ltq_rcu_regs->stat);
+ bootstrap = ((stat & LTQ_RCU_STAT_BOOT_H) << 4) |
+ ((stat & LTQ_RCU_STAT_BOOT_MASK) >> LTQ_RCU_STAT_BOOT_SHIFT);
+
+ switch (bootstrap) {
+ case 0:
+ return BOOT_NOR_NO_BOOTROM;
+ case 1:
+ return BOOT_RGMII1;
+ case 2:
+ return BOOT_NOR;
+ case 4:
+ return BOOT_UART_NO_EEPROM;
+ case 6:
+ return BOOT_PCI;
+ case 8:
+ return BOOT_UART;
+ case 10:
+ return BOOT_SPI;
+ case 12:
+ return BOOT_NAND;
+ default:
+ return BOOT_UNKNOWN;
+ }
+}
+
+void ltq_rcu_gphy_boot(unsigned int id, ulong addr)
+{
+ u32 module;
+ void *gfs_add;
+
+ switch (id) {
+ case 0:
+ module = LTQ_RCU_RD_GPHY0;
+ gfs_add = &ltq_rcu_regs->gfs_add0;
+ break;
+ case 1:
+ module = LTQ_RCU_RD_GPHY1;
+ gfs_add = &ltq_rcu_regs->gfs_add1;
+ break;
+ default:
+ BUG();
+ }
+
+ /* Stop and reset GPHY */
+ ltq_setbits(&ltq_rcu_regs->req, module);
+
+ /* Configure firmware and boot address */
+ ltq_writel(gfs_add, CPHYSADDR(addr & 0xFFFFC000));
+
+ /* Start GPHY by releasing reset */
+ ltq_clrbits(&ltq_rcu_regs->req, module);
+}
--- /dev/null
+++ b/arch/mips/include/asm/arch-danube/config.h
@@ -0,0 +1,163 @@
+/*
+ * Copyright (C) 2007-2010 Lantiq Deutschland GmbH
+ * Copyright (C) 2011-2013 Daniel Schwierzeck, daniel.schwierzeck@gmail.com
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ *
+ * Common board configuration for Lantiq XWAY Danube family
+ *
+ * Use following defines in your board config to enable specific features
+ * and drivers for this SoC:
+ *
+ * CONFIG_LTQ_SUPPORT_UART
+ * - support the Danube ASC/UART interface and console
+ *
+ * CONFIG_LTQ_SUPPORT_NOR_FLASH
+ * - support a parallel NOR flash via the CFI interface in flash bank 0
+ *
+ * CONFIG_LTQ_SUPPORT_ETHERNET
+ * - support the Danube ETOP and MAC interface
+ *
+ * CONFIG_LTQ_SUPPORT_SPI_FLASH
+ * - support the Danube SPI interface and serial flash drivers
+ * - specific SPI flash drivers must be configured separately
+ */
+
+#ifndef __DANUBE_CONFIG_H__
+#define __DANUBE_CONFIG_H__
+
+/* CPU and SoC type */
+#define CONFIG_SOC_LANTIQ
+#define CONFIG_SOC_XWAY_DANUBE
+
+/* Cache configuration */
+#define CONFIG_SYS_MIPS_CACHE_MODE CONF_CM_CACHABLE_NONCOHERENT
+#define CONFIG_SYS_DCACHE_SIZE (16 * 1024)
+#define CONFIG_SYS_ICACHE_SIZE (16 * 1024)
+#define CONFIG_SYS_CACHELINE_SIZE 32
+#define CONFIG_SYS_MIPS_CACHE_EXT_INIT
+
+/*
+ * Supported clock modes
+ * PLL0 clock output is 333 MHz
+ * PLL1 clock output is 262.144 MHz
+ */
+#define LTQ_CLK_CPU_333_DDR_167 0 /* Base PLL0, OCP 2 */
+#define LTQ_CLK_CPU_111_DDR_111 1 /* Base PLL0, OCP 1 */
+
+/* CPU speed */
+#define CONFIG_SYS_CLOCK_MODE LTQ_CLK_CPU_333_DDR_167
+#define CONFIG_SYS_MIPS_TIMER_FREQ 166666667
+#define CONFIG_SYS_HZ 1000
+
+/* RAM */
+#define CONFIG_NR_DRAM_BANKS 1
+#define CONFIG_SYS_SDRAM_BASE 0x80000000
+#define CONFIG_SYS_MEMTEST_START 0x81000000
+#define CONFIG_SYS_MEMTEST_END 0x82000000
+#define CONFIG_SYS_LOAD_ADDR 0x81000000
+#define CONFIG_SYS_INIT_SP_OFFSET 0x4000
+
+/* SRAM */
+#define CONFIG_SYS_SRAM_BASE 0xBE1A0000
+#define CONFIG_SYS_SRAM_SIZE 0x10000
+
+/* ASC/UART driver and console */
+#define CONFIG_LANTIQ_SERIAL
+#define CONFIG_SYS_BAUDRATE_TABLE { 9600, 19200, 38400, 57600, 115200 }
+
+/* GPIO */
+#define CONFIG_LANTIQ_GPIO
+#define CONFIG_LTQ_GPIO_MAX_BANKS 2
+
+/* FLASH driver */
+#if defined(CONFIG_LTQ_SUPPORT_NOR_FLASH)
+#define CONFIG_SYS_MAX_FLASH_BANKS 1
+#define CONFIG_SYS_MAX_FLASH_SECT 256
+#define CONFIG_SYS_FLASH_BASE 0xB0000000
+#define CONFIG_FLASH_16BIT
+#define CONFIG_SYS_FLASH_CFI
+#define CONFIG_FLASH_CFI_DRIVER
+#define CONFIG_SYS_FLASH_CFI_WIDTH FLASH_CFI_16BIT
+#define CONFIG_SYS_FLASH_USE_BUFFER_WRITE
+#define CONFIG_FLASH_SHOW_PROGRESS 50
+#define CONFIG_SYS_FLASH_PROTECTION
+#define CONFIG_CFI_FLASH_USE_WEAK_ADDR_SWAP
+
+#define CONFIG_CMD_FLASH
+#else
+#define CONFIG_SYS_NO_FLASH
+#endif /* CONFIG_NOR_FLASH */
+
+#if defined(CONFIG_LTQ_SUPPORT_SPI_FLASH)
+#define CONFIG_LANTIQ_SPI
+#define CONFIG_SPI_FLASH
+
+#define CONFIG_CMD_SF
+#define CONFIG_CMD_SPI
+#endif
+
+#if defined(CONFIG_LTQ_SUPPORT_NAND_FLASH)
+#define CONFIG_NAND_LANTIQ
+#define CONFIG_SYS_MAX_NAND_DEVICE 1
+#define CONFIG_SYS_NAND_BASE 0xB4000000
+
+#define CONFIG_CMD_NAND
+#endif
+
+#if defined(CONFIG_LTQ_SUPPORT_ETHERNET)
+#define CONFIG_LANTIQ_DMA
+#define CONFIG_LANTIQ_DANUBE_ETOP
+
+#define CONFIG_PHYLIB
+#define CONFIG_MII
+
+#define CONFIG_CMD_MII
+#define CONFIG_CMD_NET
+#endif
+
+#define CONFIG_SPL_MAX_SIZE (32 * 1024)
+#define CONFIG_SPL_BSS_MAX_SIZE (8 * 1024)
+#define CONFIG_SPL_STACK_MAX_SIZE (8 * 1024)
+#define CONFIG_SPL_MALLOC_MAX_SIZE (32 * 1024)
+/*#define CONFIG_SPL_STACK_BSS_IN_SRAM*/
+
+#if defined(CONFIG_SPL_STACK_BSS_IN_SRAM)
+#define CONFIG_SPL_STACK_BASE (CONFIG_SYS_SRAM_BASE + \
+ CONFIG_SPL_MAX_SIZE + \
+ CONFIG_SPL_STACK_MAX_SIZE - 1)
+#define CONFIG_SPL_BSS_BASE (CONFIG_SPL_STACK_BASE + 1)
+#define CONFIG_SPL_MALLOC_BASE (CONFIG_SYS_SDRAM_BASE + \
+ CONFIG_SYS_INIT_SP_OFFSET)
+#else
+#define CONFIG_SPL_STACK_BASE (CONFIG_SYS_SDRAM_BASE + \
+ CONFIG_SYS_INIT_SP_OFFSET + \
+ CONFIG_SPL_STACK_MAX_SIZE - 1)
+#define CONFIG_SPL_BSS_BASE (CONFIG_SPL_STACK_BASE + 1)
+#define CONFIG_SPL_MALLOC_BASE (CONFIG_SPL_BSS_BASE + \
+ CONFIG_SPL_BSS_MAX_SIZE)
+#endif
+
+#if defined(CONFIG_SYS_BOOT_RAM)
+#define CONFIG_SYS_TEXT_BASE 0xa0100000
+#define CONFIG_SKIP_LOWLEVEL_INIT
+#define CONFIG_SYS_DISABLE_CACHE
+#endif
+
+#if defined(CONFIG_SYS_BOOT_NOR)
+#define CONFIG_SYS_TEXT_BASE 0xB0000000
+#endif
+
+#if defined(CONFIG_SYS_BOOT_NORSPL)
+#define CONFIG_SYS_TEXT_BASE 0x80100000
+#define CONFIG_SPL_TEXT_BASE 0xB0000000
+#endif
+
+#if defined(CONFIG_SYS_BOOT_NOR) || defined(CONFIG_SYS_BOOT_NORSPL)
+#define CONFIG_SYS_XWAY_EBU_BOOTCFG 0x688C688C
+#define CONFIG_XWAY_SWAP_BYTES
+#endif
+
+#define CONFIG_SYS_MONITOR_BASE CONFIG_SYS_TEXT_BASE
+
+#endif /* __DANUBE_CONFIG_H__ */
--- /dev/null
+++ b/arch/mips/include/asm/arch-danube/gpio.h
@@ -0,0 +1,12 @@
+/*
+ * Copyright (C) 2011-2013 Daniel Schwierzeck, daniel.schwierzeck@gmail.com
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#ifndef __DANUBE_GPIO_H__
+#define __DANUBE_GPIO_H__
+
+#include <asm/lantiq/gpio.h>
+
+#endif /* __DANUBE_GPIO_H__ */
--- /dev/null
+++ b/arch/mips/include/asm/arch-danube/nand.h
@@ -0,0 +1,13 @@
+/*
+ * Copyright (C) 2012-2013 Daniel Schwierzeck, daniel.schwierzeck@gmail.com
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#ifndef __DANUBE_NAND_H__
+#define __DANUBE_NAND_H__
+
+struct nand_chip;
+int ltq_nand_init(struct nand_chip *nand);
+
+#endif /* __DANUBE_NAND_H__ */
--- /dev/null
+++ b/arch/mips/include/asm/arch-danube/soc.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2007-2010 Lantiq Deutschland GmbH
+ * Copyright (C) 2011-2013 Daniel Schwierzeck, daniel.schwierzeck@gmail.com
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#ifndef __DANUBE_SOC_H__
+#define __DANUBE_SOC_H__
+
+#define LTQ_ASC0_BASE 0x1E100400
+#define LTQ_SPI_BASE 0x1E100800
+#define LTQ_GPIO_BASE 0x1E100B00
+#define LTQ_SSIO_BASE 0x1E100BB0
+#define LTQ_ASC1_BASE 0x1E100C00
+#define LTQ_DMA_BASE 0x1E104100
+
+#define LTQ_EBU_BASE 0x1E105300
+#define LTQ_EBU_REGION0_BASE 0x10000000
+#define LTQ_EBU_REGION1_BASE 0x14000000
+#define LTQ_EBU_NAND_BASE (LTQ_EBU_BASE + 0xB0)
+
+#define LTQ_PPE_BASE 0x1E180000
+#define LTQ_PPE_ETOP_BASE (LTQ_PPE_BASE + 0x11800)
+#define LTQ_PPE_ENET0_BASE (LTQ_PPE_BASE + 0x11840)
+
+#define LTQ_PMU_BASE 0x1F102000
+#define LTQ_CGU_BASE 0x1F103000
+#define LTQ_MPS_BASE 0x1F107000
+#define LTQ_CHIPID_BASE (LTQ_MPS_BASE + 0x340)
+#define LTQ_RCU_BASE 0x1F203000
+
+#define LTQ_MC_GEN_BASE 0x1F800000
+#define LTQ_MC_SDR_BASE 0x1F800200
+#define LTQ_MC_DDR_BASE 0x1F801000
+#define LTQ_MC_DDR_DC_OFFSET(x) (x * 0x10)
+
+#endif /* __DANUBE_SOC_H__ */
--- /dev/null
+++ b/arch/mips/include/asm/arch-vrx200/config.h
@@ -0,0 +1,187 @@
+/*
+ * Copyright (C) 2010 Lantiq Deutschland GmbH
+ * Copyright (C) 2011-2013 Daniel Schwierzeck, daniel.schwierzeck@gmail.com
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ *
+ * Common board configuration for Lantiq XWAY VRX200 family
+ *
+ * Use following defines in your board config to enable specific features
+ * and drivers for this SoC:
+ *
+ * CONFIG_LTQ_SUPPORT_UART
+ * - support the VRX200 ASC/UART interface and console
+ *
+ * CONFIG_LTQ_SUPPORT_NOR_FLASH
+ * - support a parallel NOR flash via the CFI interface in flash bank 0
+ *
+ * CONFIG_LTQ_SUPPORT_ETHERNET
+ * - support the VRX200 internal switch
+ *
+ * CONFIG_LTQ_SUPPORT_SPI_FLASH
+ * - support the VRX200 SPI interface and serial flash drivers
+ * - specific SPI flash drivers must be configured separately
+ *
+ * CONFIG_LTQ_SUPPORT_SPL_SPI_FLASH
+ * - build a preloader that runs in the internal SRAM and loads
+ * the U-Boot from SPI flash into RAM
+ */
+
+#ifndef __VRX200_CONFIG_H__
+#define __VRX200_CONFIG_H__
+
+/* CPU and SoC type */
+#define CONFIG_SOC_LANTIQ
+#define CONFIG_SOC_XWAY_VRX200
+
+/* Cache configuration */
+#define CONFIG_SYS_MIPS_CACHE_MODE CONF_CM_CACHABLE_NONCOHERENT
+#define CONFIG_SYS_DCACHE_SIZE (32 * 1024)
+#define CONFIG_SYS_ICACHE_SIZE (32 * 1024)
+#define CONFIG_SYS_CACHELINE_SIZE 32
+#define CONFIG_SYS_MIPS_CACHE_EXT_INIT
+
+/*
+ * Supported clock modes
+ * PLL0 clock output is 1000 MHz
+ * PLL1 clock output is 393.219 MHz
+ */
+#define LTQ_CLK_CPU_600_DDR_300 0 /* Base PLL0, OCP 2 */
+#define LTQ_CLK_CPU_600_DDR_200 1 /* Base PLL0, OCP 3 */
+#define LTQ_CLK_CPU_500_DDR_250 2 /* Base PLL0, OCP 2 */
+#define LTQ_CLK_CPU_500_DDR_200 3 /* Base PLL0, OCP 2.5 */
+#define LTQ_CLK_CPU_333_DDR_167 4 /* Base PLL0, OCP 2 */
+#define LTQ_CLK_CPU_167_DDR_167 5 /* Base PLL0, OCP 1 */
+#define LTQ_CLK_CPU_125_DDR_125 6 /* Base PLL0, OCP 1 */
+#define LTQ_CLK_CPU_393_DDR_197 7 /* Base PLL1, OCP 2 */
+#define LTQ_CLK_CPU_197_DDR_197 8 /* Base PLL1, OCP 1 */
+
+/* CPU speed */
+#define CONFIG_SYS_CLOCK_MODE LTQ_CLK_CPU_500_DDR_250
+#define CONFIG_SYS_MIPS_TIMER_FREQ 250000000
+#define CONFIG_SYS_HZ 1000
+
+/* RAM */
+#define CONFIG_NR_DRAM_BANKS 1
+#define CONFIG_SYS_SDRAM_BASE 0x80000000
+#define CONFIG_SYS_SDRAM_BASE_UC 0xa0000000
+#define CONFIG_SYS_MEMTEST_START 0x81000000
+#define CONFIG_SYS_MEMTEST_END 0x82000000
+#define CONFIG_SYS_LOAD_ADDR 0x81000000
+#define CONFIG_SYS_INIT_SP_OFFSET (32 * 1024)
+
+/* SRAM */
+#define CONFIG_SYS_SRAM_BASE 0xBE220000
+#define CONFIG_SYS_SRAM_SIZE 0x10000
+
+/* ASC/UART driver and console */
+#define CONFIG_LANTIQ_SERIAL
+#define CONFIG_SYS_BAUDRATE_TABLE { 9600, 19200, 38400, 57600, 115200 }
+
+/* GPIO */
+#define CONFIG_LANTIQ_GPIO
+#define CONFIG_LTQ_GPIO_MAX_BANKS 3
+#define CONFIG_LTQ_HAS_GPIO_BANK3
+
+/* FLASH driver */
+#if defined(CONFIG_LTQ_SUPPORT_NOR_FLASH)
+#ifndef CONFIG_SYS_MAX_FLASH_BANKS
+#define CONFIG_SYS_MAX_FLASH_BANKS 1
+#endif
+#define CONFIG_SYS_MAX_FLASH_SECT 256
+#define CONFIG_SYS_FLASH_BASE 0xB0000000
+#define CONFIG_SYS_FLASH2_BASE 0xB4000000
+#define CONFIG_FLASH_16BIT
+#define CONFIG_SYS_FLASH_CFI
+#define CONFIG_FLASH_CFI_DRIVER
+#define CONFIG_SYS_FLASH_CFI_WIDTH FLASH_CFI_16BIT
+#define CONFIG_SYS_FLASH_USE_BUFFER_WRITE
+#define CONFIG_FLASH_SHOW_PROGRESS 50
+#define CONFIG_SYS_FLASH_PROTECTION
+#define CONFIG_CFI_FLASH_USE_WEAK_ADDR_SWAP
+
+#define CONFIG_CMD_FLASH
+#else
+#define CONFIG_SYS_NO_FLASH
+#endif /* CONFIG_NOR_FLASH */
+
+#if defined(CONFIG_LTQ_SUPPORT_SPI_FLASH)
+#define CONFIG_LANTIQ_SPI
+#define CONFIG_SPI_FLASH
+
+#define CONFIG_CMD_SF
+#define CONFIG_CMD_SPI
+#endif
+
+#if defined(CONFIG_LTQ_SUPPORT_NAND_FLASH)
+#define CONFIG_NAND_LANTIQ
+#define CONFIG_SYS_MAX_NAND_DEVICE 1
+#define CONFIG_SYS_NAND_BASE 0xB4000000
+
+#define CONFIG_CMD_NAND
+#endif
+
+#if defined(CONFIG_LTQ_SUPPORT_ETHERNET)
+#define CONFIG_LANTIQ_DMA
+#define CONFIG_LANTIQ_VRX200_SWITCH
+#define CONFIG_PHY_LANTIQ
+
+#define CONFIG_SYS_RX_ETH_BUFFER 8
+#define CONFIG_PHYLIB
+#define CONFIG_MII
+#define CONFIG_UDP_CHECKSUM
+
+#define CONFIG_CMD_MII
+#define CONFIG_CMD_NET
+#endif
+
+#define CONFIG_SPL_MAX_SIZE (32 * 1024)
+#define CONFIG_SPL_BSS_MAX_SIZE (8 * 1024)
+#define CONFIG_SPL_STACK_MAX_SIZE (8 * 1024)
+#define CONFIG_SPL_MALLOC_MAX_SIZE (32 * 1024)
+#define CONFIG_SPL_STACK_BSS_IN_SRAM
+
+#if defined(CONFIG_SPL_STACK_BSS_IN_SRAM)
+#define CONFIG_SPL_STACK_BASE (CONFIG_SYS_SRAM_BASE + \
+ CONFIG_SPL_MAX_SIZE + \
+ CONFIG_SPL_STACK_MAX_SIZE - 1)
+#define CONFIG_SPL_BSS_BASE (CONFIG_SPL_STACK_BASE + 1)
+#define CONFIG_SPL_MALLOC_BASE (CONFIG_SYS_SDRAM_BASE + \
+ CONFIG_SYS_INIT_SP_OFFSET)
+#else
+#define CONFIG_SPL_STACK_BASE (CONFIG_SYS_SDRAM_BASE + \
+ CONFIG_SYS_INIT_SP_OFFSET + \
+ CONFIG_SPL_STACK_MAX_SIZE - 1)
+#define CONFIG_SPL_BSS_BASE (CONFIG_SPL_STACK_BASE + 1)
+#define CONFIG_SPL_MALLOC_BASE (CONFIG_SPL_BSS_BASE + \
+ CONFIG_SPL_BSS_MAX_SIZE)
+#endif
+
+#if defined(CONFIG_SYS_BOOT_RAM)
+#define CONFIG_SYS_TEXT_BASE 0xA0100000
+#define CONFIG_SKIP_LOWLEVEL_INIT
+#define CONFIG_SYS_DISABLE_CACHE
+#endif
+
+#if defined(CONFIG_SYS_BOOT_NOR)
+#define CONFIG_SYS_TEXT_BASE 0xB0000000
+#endif
+
+#if defined(CONFIG_SYS_BOOT_SFSPL)
+#define CONFIG_SYS_TEXT_BASE 0x80100000
+#define CONFIG_SPL_TEXT_BASE 0xBE220000
+#endif
+
+#if defined(CONFIG_SYS_BOOT_NORSPL)
+#define CONFIG_SYS_TEXT_BASE 0x80100000
+#define CONFIG_SPL_TEXT_BASE 0xB0000000
+#endif
+
+#if defined(CONFIG_SYS_BOOT_NOR) || defined(CONFIG_SYS_BOOT_NORSPL)
+#define CONFIG_SYS_XWAY_EBU_BOOTCFG 0x688C688C
+#define CONFIG_XWAY_SWAP_BYTES
+#endif
+
+#define CONFIG_SYS_MONITOR_BASE CONFIG_SYS_TEXT_BASE
+
+#endif /* __VRX200_CONFIG_H__ */
--- /dev/null
+++ b/arch/mips/include/asm/arch-vrx200/gphy.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2011-2013 Daniel Schwierzeck, daniel.schwierzeck@gmail.com
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#ifndef __VRX200_GPHY_H__
+#define __VRX200_GPHY_H__
+
+enum ltq_gphy_clk {
+ /* XTAL 36 MHz input */
+ LTQ_GPHY_CLK_36MHZ_XTAL = 1,
+ /* 25 MHz from PLL0 with divider */
+ LTQ_GPHY_CLK_25MHZ_PLL0 = 2,
+ /* derived from PLL2 output (XTAL is 36 MHz) */
+ LTQ_GPHY_CLK_24MHZ_PLL2 = 3,
+ /* 25 MHz Clock from Pin GPIO3 */
+ LTQ_GPHY_CLK_25MHZ_GPIO3 = 4,
+};
+
+/*
+ * Load PHY11G firmware for VRX200 v1.1 to given RAM address
+ *
+ * Address must be 16k aligned!
+ */
+extern void ltq_gphy_phy11g_a1x_load(ulong addr);
+
+/*
+ * Load PHY11G firmware for VRX200 v1.2 to given RAM address
+ *
+ * Address must be 16k aligned!
+ */
+extern void ltq_gphy_phy11g_a2x_load(ulong addr);
+
+/*
+ * Load PHY22F firmware for VRX200 v1.1 to given RAM address
+ *
+ * Address must be 16k aligned!
+ */
+extern void ltq_gphy_phy22f_a1x_load(ulong addr);
+
+/*
+ * Load PHY22F firmware for VRX200 v1.2 to given RAM address
+ *
+ * Address must be 16k aligned!
+ */
+extern void ltq_gphy_phy22f_a2x_load(ulong addr);
+
+/*
+ * Set clock source of internal GPHYs
+ *
+ * According registers resides in CGU address space. Thus this function
+ * is implemented by the CGU driver.
+ */
+extern void ltq_cgu_gphy_clk_src(enum ltq_gphy_clk clk);
+
+/*
+ * Boot internal GPHY with id from given RAM address
+ *
+ * According registers resides in RCU address space. Thus this function
+ * is implemented by the RCU driver.
+ */
+extern void ltq_rcu_gphy_boot(unsigned int id, ulong addr);
+
+#endif /* __VRX200_GPHY_H__ */
--- /dev/null
+++ b/arch/mips/include/asm/arch-vrx200/gpio.h
@@ -0,0 +1,12 @@
+/*
+ * Copyright (C) 2011-2013 Daniel Schwierzeck, daniel.schwierzeck@gmail.com
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#ifndef __VRX200_GPIO_H__
+#define __VRX200_GPIO_H__
+
+#include <asm/lantiq/gpio.h>
+
+#endif /* __VRX200_GPIO_H__ */
--- /dev/null
+++ b/arch/mips/include/asm/arch-vrx200/nand.h
@@ -0,0 +1,13 @@
+/*
+ * Copyright (C) 2012-2013 Daniel Schwierzeck, daniel.schwierzeck@gmail.com
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#ifndef __VRX200_NAND_H__
+#define __VRX200_NAND_H__
+
+struct nand_chip;
+int ltq_nand_init(struct nand_chip *nand);
+
+#endif /* __VRX200_NAND_H__ */
--- /dev/null
+++ b/arch/mips/include/asm/arch-vrx200/soc.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2010 Lantiq Deutschland GmbH
+ * Copyright (C) 2011-2013 Daniel Schwierzeck, daniel.schwierzeck@gmail.com
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#ifndef __VRX200_SOC_H__
+#define __VRX200_SOC_H__
+
+#define LTQ_ASC0_BASE 0x1E100400
+#define LTQ_SPI_BASE 0x1E100800
+#define LTQ_GPIO_BASE 0x1E100B00
+#define LTQ_SSIO_BASE 0x1E100BB0
+#define LTQ_ASC1_BASE 0x1E100C00
+#define LTQ_DMA_BASE 0x1E104100
+
+#define LTQ_EBU_BASE 0x1E105300
+#define LTQ_EBU_REGION0_BASE 0x10000000
+#define LTQ_EBU_REGION1_BASE 0x14000000
+#define LTQ_EBU_NAND_BASE (LTQ_EBU_BASE + 0xB0)
+
+#define LTQ_SWITCH_BASE 0x1E108000
+#define LTQ_SWITCH_CORE_BASE LTQ_SWITCH_BASE
+#define LTQ_SWITCH_TOP_PDI_BASE LTQ_SWITCH_CORE_BASE
+#define LTQ_SWITCH_BM_PDI_BASE (LTQ_SWITCH_CORE_BASE + 4 * 0x40)
+#define LTQ_SWITCH_MAC_PDI_0_BASE (LTQ_SWITCH_CORE_BASE + 4 * 0x900)
+#define LTQ_SWITCH_MAC_PDI_X_BASE(x) (LTQ_SWITCH_MAC_PDI_0_BASE + x * 0x30)
+#define LTQ_SWITCH_TOPLEVEL_BASE (LTQ_SWITCH_BASE + 4 * 0xC40)
+#define LTQ_SWITCH_MDIO_PDI_BASE (LTQ_SWITCH_TOPLEVEL_BASE)
+#define LTQ_SWITCH_MII_PDI_BASE (LTQ_SWITCH_TOPLEVEL_BASE + 4 * 0x36)
+#define LTQ_SWITCH_PMAC_PDI_BASE (LTQ_SWITCH_TOPLEVEL_BASE + 4 * 0x82)
+
+#define LTQ_PMU_BASE 0x1F102000
+#define LTQ_CGU_BASE 0x1F103000
+#define LTQ_DCDC_BASE 0x1F106A00
+#define LTQ_MPS_BASE 0x1F107000
+#define LTQ_CHIPID_BASE (LTQ_MPS_BASE + 0x340)
+#define LTQ_RCU_BASE 0x1F203000
+
+#define LTQ_MC_GLOBAL_BASE 0x1F400000
+#define LTQ_MC_DDR_BASE 0x1F401000
+#define LTQ_MC_DDR_CCR_OFFSET(x) (x * 0x10)
+
+#endif /* __VRX200_SOC_H__ */
--- /dev/null
+++ b/arch/mips/include/asm/arch-vrx200/switch.h
@@ -0,0 +1,502 @@
+/*
+ * Copyright (C) 2012-2013 Daniel Schwierzeck, daniel.schwierzeck@gmail.com
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#ifndef __VRX200_SWITCH_H__
+#define __VRX200_SWITCH_H__
+
+/* Switch core registers */
+struct vr9_switch_core_regs {
+ __be32 swres;
+ /* TODO: implement registers */
+ __be32 rsvd0[0x3f];
+};
+
+/* Switch buffer management registers */
+struct vr9_switch_bm_regs {
+ struct bm_core {
+ __be32 ram_val3; /* RAM value 3 */
+ __be32 ram_val2; /* RAM value 2 */
+ __be32 ram_val1; /* RAM value 1 */
+ __be32 ram_val0; /* RAM value 0 */
+ __be32 ram_addr; /* RAM address */
+ __be32 ram_ctrl; /* RAM access control */
+ __be32 fsqm_gctrl; /* Free segment queue global control */
+ __be32 cons_sel; /* Number of consumed segments */
+ __be32 cons_pkt; /* Number of consumed packet pointers */
+ __be32 gctrl; /* Global control */
+ __be32 queue_gctrl; /* Queue manager global control */
+ /* TODO: implement registers */
+ __be32 rsvd0[0x35];
+ } core;
+
+ struct bm_port {
+ __be32 pcfg; /* Port config */
+ __be32 rmon_ctrl; /* RMON control */
+ } port[13];
+
+ __be32 rsvd0[0x66];
+
+ struct bm_queue {
+ __be32 rsvd0;
+ __be32 pqm_rs; /* Packet queue manager rate shape assignment */
+ } queue[32];
+
+ struct bm_shaper {
+ __be32 ctrl; /* Rate shaper control */
+ __be32 cbs; /* Rate shaper committed burst size */
+ __be32 ibs; /* Rate shaper instantaneous burst size */
+ __be32 cir_ext; /* Rate shaper rate exponent */
+ __be32 cir_mant; /* Rate shaper rate mantissa */
+ } shaper[16];
+
+ __be32 rsvd1[0x2a8];
+};
+
+/* Switch parser and classification engine registers */
+struct vr9_switch_pce_regs {
+ struct pce_core {
+ __be32 tbl_key[16]; /* Table key data */
+ __be32 tbl_mask; /* Table mask */
+ __be32 tbl_val[5]; /* Table value */
+ __be32 tbl_addr; /* Table entry address */
+ __be32 tbl_ctrl; /* Table access control */
+ __be32 tbl_stat; /* Table general status */
+ __be32 age_0; /* Aging counter config 0 */
+ __be32 age_1; /* Aging counter config 1 */
+ __be32 pmap_1; /* Port map (monitoring) */
+ __be32 pmap_2; /* Port map (multicast) */
+ __be32 pmap_3; /* Port map (unknown unicast) */
+ __be32 gctrl_0; /* Global control 0 */
+ __be32 gctrl_1; /* Global control 1 */
+ __be32 tcm_gctrl; /* Three-color marker global control */
+ __be32 igmp_ctrl; /* IGMP control */
+ __be32 igmp_drpm; /* IGMP default router port map */
+ __be32 igmp_age_0; /* IGMP aging 0 */
+ __be32 igmp_age_1; /* IGMP aging 1 */
+ __be32 igmp_stat; /* IGMP status */
+ __be32 wol_gctrl; /* Wake-on-LAN control */
+ __be32 wol_da_0; /* Wake-on-LAN destination address 0 */
+ __be32 wol_da_1; /* Wake-on-LAN destination address 1 */
+ __be32 wol_da_2; /* Wake-on-LAN destination address 2 */
+ __be32 wol_pw_0; /* Wake-on-LAN password 0 */
+ __be32 wol_pw_1; /* Wake-on-LAN password 1 */
+ __be32 wol_pw_2; /* Wake-on-LAN password 2 */
+ __be32 ier_0; /* PCE global interrupt enable 0 */
+ __be32 ier_1; /* PCE global interrupt enable 1 */
+ __be32 isr_0; /* PCE global interrupt status 0 */
+ __be32 isr_1; /* PCE global interrupt status 1 */
+ __be32 parser_stat; /* Parser status */
+ __be32 rsvd0[0x6];
+ } core;
+
+ __be32 rsvd0[0x10];
+
+ struct pce_port {
+ __be32 pctrl_0; /* Port control 0 */
+ __be32 pctrl_1; /* Port control 1 */
+ __be32 pctrl_2; /* Port control 2 */
+ __be32 pctrl_3; /* Port control 3 */
+ __be32 wol_ctrl; /* Wake-on-LAN control */
+ __be32 vlan_ctrl; /* VLAN control */
+ __be32 def_pvid; /* Default port VID */
+ __be32 pstat; /* Port status */
+ __be32 pier; /* Interrupt enable */
+ __be32 pisr; /* Interrupt status */
+ } port[13];
+
+ __be32 rsvd1[0x7e];
+
+ struct pce_meter {
+ /* TODO: implement registers */
+ __be32 rsvd0[0x7];
+ } meter[8];
+
+ __be32 rsvd2[0x308];
+};
+
+static inline unsigned int to_pce_tbl_key_id(unsigned int id)
+{
+ BUG_ON(id > 15);
+
+ return 15 - id;
+}
+
+static inline unsigned int to_pce_tbl_value_id(unsigned int id)
+{
+ BUG_ON(id > 4);
+
+ return 4 - id;
+}
+
+/* Switch ethernet MAC registers */
+struct vr9_switch_mac_regs {
+ struct mac_core {
+ __be32 test; /* MAC test */
+ __be32 pfad_cfg; /* Pause frame source address config */
+ __be32 pfsa_0; /* Pause frame source address 0 */
+ __be32 pfsa_1; /* Pause frame source address 1 */
+ __be32 pfsa_2; /* Pause frame source address 2 */
+ __be32 flen; /* Frame length */
+ __be32 vlan_etype_0; /* VLAN ethertype 0 */
+ __be32 vlan_etype_1; /* VLAN ethertype 1 */
+ __be32 ier; /* Interrupt enable */
+ __be32 isr; /* Interrupt status */
+ __be32 rsvd0[0x36];
+ } core;
+
+ struct mac_port {
+ __be32 pstat; /* Port status */
+ __be32 pisr; /* Interrupt status */
+ __be32 pier; /* Interrupt enable */
+ __be32 ctrl_0; /* Control 0 */
+ __be32 ctrl_1; /* Control 1 */
+ __be32 ctrl_2; /* Control 2 */
+ __be32 ctrl_3; /* Control 3 */
+ __be32 ctrl_4; /* Control 4 */
+ __be32 ctrl_5; /* Control 5 */
+ __be32 rsvd0[0x2];
+ __be32 testen; /* Test enable */
+ } port[13];
+
+ __be32 rsvd0[0xa4];
+};
+
+/* Switch Fetch DMA registers */
+struct vr9_switch_fdma_regs {
+ struct fdma_core {
+ __be32 ctrl; /* FDMA control */
+ __be32 stetype; /* Special tag ethertype control */
+ __be32 vtetype; /* VLAN tag ethertype control */
+ __be32 stat; /* FDMA status */
+ __be32 ier; /* FDMA interrupt enable */
+ __be32 isr; /* FDMA interrupt status */
+ } core;
+
+ __be32 rsvd0[0x3a];
+
+ struct fdma_port {
+ __be32 pctrl; /* Port control */
+ __be32 prio; /* Port priority */
+ __be32 pstat_0; /* Port status 0 */
+ __be32 pstat_1; /* Port status 1 */
+ __be32 tstamp_0; /* Egress time stamp 0 */
+ __be32 tstamp_1; /* Egress time stamp 1 */
+ } port[13];
+
+ __be32 rsvd1[0x72];
+};
+
+/* Switch Store DMA registers */
+struct vr9_switch_sdma_regs {
+ struct sdma_core {
+ __be32 ctrl; /* SDMA Control */
+ __be32 fcthr_1; /* Flow control threshold 1 */
+ __be32 rsvd0;
+ __be32 fcthr_3; /* Flow control threshold 3 */
+ __be32 fcthr_4; /* Flow control threshold 4 */
+ __be32 fcthr_5; /* Flow control threshold 5 */
+ __be32 fcthr_6; /* Flow control threshold 6 */
+ __be32 fcthr_7; /* Flow control threshold 7 */
+ __be32 stat_0; /* SDMA status 0 */
+ __be32 stat_1; /* SDMA status 1 */
+ __be32 stat_2; /* SDMA status 2 */
+ __be32 ier; /* SDMA interrupt enable */
+ __be32 isr; /* SDMA interrupt status */
+ } core;
+
+ __be32 rsvd0[0x73];
+
+ struct sdma_port {
+ __be32 pctrl; /* Port control */
+ __be32 prio; /* Port priority */
+ __be32 pstat_0; /* Port status 0 */
+ __be32 pstat_1; /* Port status 1 */
+ __be32 tstamp_0; /* Ingress time stamp 0 */
+ __be32 tstamp_1; /* Ingress time stamp 1 */
+ } port[13];
+
+ __be32 rsvd1[0x32];
+};
+
+/* Switch MDIO control and status registers */
+struct vr9_switch_mdio_regs {
+ __be32 glob_ctrl; /* Global control 0 */
+ __be32 rsvd0[7];
+ __be32 mdio_ctrl; /* MDIO control */
+ __be32 mdio_read; /* MDIO read data */
+ __be32 mdio_write; /* MDIO write data */
+ __be32 mdc_cfg_0; /* MDC clock configuration 0 */
+ __be32 mdc_cfg_1; /* MDC clock configuration 1 */
+ __be32 rsvd1[0x3];
+ __be32 phy_addr[6]; /* PHY address port 5..0 */
+ __be32 mdio_stat[6]; /* MDIO PHY polling status port 0..5 */
+ __be32 aneg_eee[6]; /* EEE auto-neg overrides port 0..5 */
+ __be32 rsvd2[0x14];
+};
+
+static inline unsigned int to_mdio_phyaddr_id(unsigned int id)
+{
+ BUG_ON(id > 5);
+
+ return 5 - id;
+}
+
+/* Switch xMII control registers */
+struct vr9_switch_mii_regs {
+ __be32 mii_cfg0; /* xMII port 0 configuration */
+ __be32 pcdu0; /* Port 0 clock delay configuration */
+ __be32 mii_cfg1; /* xMII port 1 configuration */
+ __be32 pcdu1; /* Port 1 clock delay configuration */
+ __be32 rsvd0[0x6];
+ __be32 mii_cfg5; /* xMII port 5 configuration */
+ __be32 pcdu5; /* Port 5 clock delay configuration */
+ __be32 rsvd1[0x14];
+ __be32 rxb_ctl_0; /* Port 0 receive buffer control */
+ __be32 rxb_ctl_1; /* Port 1 receive buffer control */
+ __be32 rxb_ctl_5; /* Port 5 receive buffer control */
+ __be32 rsvd2[0x28];
+ __be32 dbg_ctl; /* Debug control */
+};
+
+/* Switch Pseudo-MAC registers */
+struct vr9_switch_pmac_regs {
+ __be32 hd_ctl; /* PMAC header control */
+ __be32 tl; /* PMAC type/length */
+ __be32 sa1; /* PMAC source address 1 */
+ __be32 sa2; /* PMAC source address 2 */
+ __be32 sa3; /* PMAC source address 3 */
+ __be32 da1; /* PMAC destination address 1 */
+ __be32 da2; /* PMAC destination address 2 */
+ __be32 da3; /* PMAC destination address 3 */
+ __be32 vlan; /* PMAC VLAN */
+ __be32 rx_ipg; /* PMAC interpacket gap in RX direction */
+ __be32 st_etype; /* PMAC special tag ethertype */
+ __be32 ewan; /* PMAC ethernet WAN group */
+ __be32 ctl; /* PMAC control */
+ __be32 rsvd0[0x2];
+};
+
+struct vr9_switch_regs {
+ struct vr9_switch_core_regs core;
+ struct vr9_switch_bm_regs bm;
+ struct vr9_switch_pce_regs pce;
+ struct vr9_switch_mac_regs mac;
+ struct vr9_switch_fdma_regs fdma;
+ struct vr9_switch_sdma_regs sdma;
+ struct vr9_switch_mdio_regs mdio;
+ struct vr9_switch_mii_regs mii;
+ struct vr9_switch_pmac_regs pmac;
+};
+
+static inline void *to_pce_tbl_key(struct vr9_switch_regs *regs,
+ unsigned int id)
+{
+ return &regs->pce.core.tbl_key[to_pce_tbl_key_id(id)];
+}
+
+static inline void *to_pce_tbl_value(struct vr9_switch_regs *regs,
+ unsigned int id)
+{
+ return &regs->pce.core.tbl_val[to_pce_tbl_value_id(id)];
+}
+
+static inline void *to_mac_ctrl(struct vr9_switch_regs *regs,
+ unsigned int id, unsigned int ctrl)
+{
+ struct mac_port *mac = &regs->mac.port[id];
+
+ switch (ctrl) {
+ case 0:
+ return &mac->ctrl_0;
+ case 1:
+ return &mac->ctrl_1;
+ case 2:
+ return &mac->ctrl_2;
+ case 3:
+ return &mac->ctrl_3;
+ case 4:
+ return &mac->ctrl_4;
+ case 5:
+ return &mac->ctrl_5;
+ default:
+ return NULL;
+ }
+}
+
+static inline void *to_mdio_phyaddr(struct vr9_switch_regs *regs,
+ unsigned int id)
+{
+ return &regs->mdio.phy_addr[to_mdio_phyaddr_id(id)];
+}
+
+static inline void *to_mii_miicfg(struct vr9_switch_regs *regs,
+ unsigned int id)
+{
+ switch (id) {
+ case 0:
+ return &regs->mii.mii_cfg0;
+ case 1:
+ return &regs->mii.mii_cfg1;
+ case 5:
+ return &regs->mii.mii_cfg5;
+ default:
+ return NULL;
+ }
+}
+
+static inline void *to_mii_pcdu(struct vr9_switch_regs *regs,
+ unsigned int id)
+{
+ switch (id) {
+ case 0:
+ return &regs->mii.pcdu0;
+ case 1:
+ return &regs->mii.pcdu1;
+ case 5:
+ return &regs->mii.pcdu5;
+ default:
+ return NULL;
+ }
+}
+
+#define VR9_SWITCH_REG_OFFSET(reg) (4 * (reg))
+
+#define BUILD_CHECK_VR9_REG(name, offset) \
+ BUILD_BUG_ON(offsetof(struct vr9_switch_regs, name) != (4 * offset))
+
+static inline void build_check_vr9_registers(void)
+{
+ BUILD_CHECK_VR9_REG(core, 0x0);
+ BUILD_CHECK_VR9_REG(bm.core, 0x40);
+ BUILD_CHECK_VR9_REG(bm.core.queue_gctrl, 0x4a);
+ BUILD_CHECK_VR9_REG(bm.port[0], 0x80);
+ BUILD_CHECK_VR9_REG(bm.queue, 0x100);
+ BUILD_CHECK_VR9_REG(bm.shaper, 0x140);
+ BUILD_CHECK_VR9_REG(pce.core, 0x438);
+ BUILD_CHECK_VR9_REG(pce.core.tbl_ctrl, 0x44f);
+ BUILD_CHECK_VR9_REG(pce.core.parser_stat, 0x469);
+ BUILD_CHECK_VR9_REG(pce.port[0], 0x480);
+ BUILD_CHECK_VR9_REG(pce.meter[0], 0x580);
+ BUILD_CHECK_VR9_REG(mac.core, 0x8c0);
+ BUILD_CHECK_VR9_REG(mac.port[0].pstat, 0x900);
+ BUILD_CHECK_VR9_REG(mac.port[0].ctrl_0, 0x903);
+ BUILD_CHECK_VR9_REG(mac.port[1].pstat, 0x90c);
+ BUILD_CHECK_VR9_REG(mac.port[1].ctrl_0, 0x90f);
+ BUILD_CHECK_VR9_REG(mac.port[2].pstat, 0x918);
+ BUILD_CHECK_VR9_REG(mac.port[2].ctrl_0, 0x91b);
+ BUILD_CHECK_VR9_REG(fdma.core, 0xa40);
+ BUILD_CHECK_VR9_REG(fdma.port[0], 0xa80);
+ BUILD_CHECK_VR9_REG(sdma.core, 0xb40);
+ BUILD_CHECK_VR9_REG(sdma.port[0], 0xbc0);
+ BUILD_CHECK_VR9_REG(mdio, 0xc40);
+ BUILD_CHECK_VR9_REG(mii, (0xc40 + 0x36));
+ BUILD_CHECK_VR9_REG(pmac, (0xc40 + 0x82));
+}
+
+#define BM_GCTRL_F_SRES 1
+
+#define MAC_CTRL0_BM (1 << 12)
+#define MAC_CTRL0_APADEN (1 << 11)
+#define MAC_CTRL0_VPAD2EN (1 << 10)
+#define MAC_CTRL0_VPADEN (1 << 9)
+#define MAC_CTRL0_PADEN (1 << 8)
+#define MAC_CTRL0_FCS (1 << 7)
+#define MAC_CTRL0_FCON_SHIFT 4
+#define MAC_CTRL0_FCON_AUTO (0x0 << MAC_CTRL0_FCON_SHIFT)
+#define MAC_CTRL0_FCON_RX (0x1 << MAC_CTRL0_FCON_SHIFT)
+#define MAC_CTRL0_FCON_TX (0x2 << MAC_CTRL0_FCON_SHIFT)
+#define MAC_CTRL0_FCON_RXTX (0x3 << MAC_CTRL0_FCON_SHIFT)
+#define MAC_CTRL0_FCON_NONE (0x4 << MAC_CTRL0_FCON_SHIFT)
+#define MAC_CTRL0_FDUP_SHIFT 2
+#define MAC_CTRL0_FDUP_AUTO (0x0 << MAC_CTRL0_FDUP_SHIFT)
+#define MAC_CTRL0_FDUP_EN (0x1 << MAC_CTRL0_FDUP_SHIFT)
+#define MAC_CTRL0_FDUP_DIS (0x3 << MAC_CTRL0_FDUP_SHIFT)
+#define MAC_CTRL0_GMII_AUTO 0x0
+#define MAC_CTRL0_GMII_MII 0x1
+#define MAC_CTRL0_GMII_GMII 0x2
+#define MAC_CTRL0_GMII_GMII_2G 0x3
+
+#define MAC_CTRL1_DEFERMODE (1 << 15)
+#define MAC_CTRL1_SHORTPRE (1 << 8)
+
+#define MAC_CTRL2_MLEN (1 << 3)
+#define MAC_CTRL2_LCHKL (1 << 2)
+#define MAC_CTRL2_LCHKS_DIS 0x0
+#define MAC_CTRL2_LCHKS_UNTAG 0x1
+#define MAC_CTRL2_LCHKS_TAG 0x2
+
+#define PHY_ADDR_LNKST_SHIFT 13
+#define PHY_ADDR_LNKST_AUTO (0x0 << PHY_ADDR_LNKST_SHIFT)
+#define PHY_ADDR_LNKST_UP (0x1 << PHY_ADDR_LNKST_SHIFT)
+#define PHY_ADDR_LNKST_DOWN (0x2 << PHY_ADDR_LNKST_SHIFT)
+#define PHY_ADDR_SPEED_SHIFT 11
+#define PHY_ADDR_SPEED_M10 (0x0 << PHY_ADDR_SPEED_SHIFT)
+#define PHY_ADDR_SPEED_M100 (0x1 << PHY_ADDR_SPEED_SHIFT)
+#define PHY_ADDR_SPEED_G1 (0x2 << PHY_ADDR_SPEED_SHIFT)
+#define PHY_ADDR_SPEED_AUTO (0x3 << PHY_ADDR_SPEED_SHIFT)
+#define PHY_ADDR_FDUP_SHIFT 9
+#define PHY_ADDR_FDUP_AUTO (0x0 << PHY_ADDR_FDUP_SHIFT)
+#define PHY_ADDR_FDUP_EN (0x1 << PHY_ADDR_FDUP_SHIFT)
+#define PHY_ADDR_FDUP_DIS (0x3 << PHY_ADDR_FDUP_SHIFT)
+#define PHY_ADDR_FCONTX_SHIFT 7
+#define PHY_ADDR_FCONTX_AUTO (0x0 << PHY_ADDR_FCONTX_SHIFT)
+#define PHY_ADDR_FCONTX_EN (0x1 << PHY_ADDR_FCONTX_SHIFT)
+#define PHY_ADDR_FCONTX_DIS (0x3 << PHY_ADDR_FCONTX_SHIFT)
+#define PHY_ADDR_FCONRX_SHIFT 5
+#define PHY_ADDR_FCONRX_AUTO (0x0 << PHY_ADDR_FCONRX_SHIFT)
+#define PHY_ADDR_FCONRX_EN (0x1 << PHY_ADDR_FCONRX_SHIFT)
+#define PHY_ADDR_FCONRX_DIS (0x3 << PHY_ADDR_FCONRX_SHIFT)
+
+#define MII_CFG_RES (1 << 15)
+#define MII_CFG_EN (1 << 14)
+#define MII_CFG_LDCLKDIS (1 << 12)
+#define MII_CFG_MIIRATE_SHIFT 4
+#define MII_CFG_MIIRATE_MASK (0x7 << MII_CFG_MIIRATE_SHIFT)
+#define MII_CFG_MIIRATE_M2P5 (0x0 << MII_CFG_MIIRATE_SHIFT)
+#define MII_CFG_MIIRATE_M25 (0x1 << MII_CFG_MIIRATE_SHIFT)
+#define MII_CFG_MIIRATE_M125 (0x2 << MII_CFG_MIIRATE_SHIFT)
+#define MII_CFG_MIIRATE_M50 (0x3 << MII_CFG_MIIRATE_SHIFT)
+#define MII_CFG_MIIRATE_AUTO (0x4 << MII_CFG_MIIRATE_SHIFT)
+#define MII_CFG_MIIMODE_MASK 0xf
+#define MII_CFG_MIIMODE_MIIP 0x0
+#define MII_CFG_MIIMODE_MIIM 0x1
+#define MII_CFG_MIIMODE_RMIIP 0x2
+#define MII_CFG_MIIMODE_RMIIM 0x3
+#define MII_CFG_MIIMODE_RGMII 0x4
+
+#define PCDU_RXDLY_SHIFT 7
+#define PCDU_RXDLY_MASK (0x7 << PCDU_RXDLY_SHIFT)
+#define PCDU_TXDLY_MASK 0x7
+
+#define PMAC_HD_CTL_FC (1 << 10)
+#define PMAC_HD_CTL_CCRC (1 << 9)
+#define PMAC_HD_CTL_RST (1 << 8)
+#define PMAC_HD_CTL_AST (1 << 7)
+#define PMAC_HD_CTL_RXSH (1 << 6)
+#define PMAC_HD_CTL_RC (1 << 4)
+#define PMAC_HD_CTL_AS (1 << 3)
+#define PMAC_HD_CTL_AC (1 << 2)
+
+#define PCE_PCTRL_0_IGSTEN (1 << 11)
+
+#define FDMA_PCTRL_STEN (1 << 1)
+#define FDMA_PCTRL_EN (1 << 0)
+
+#define SDMA_PCTRL_EN (1 << 0)
+
+#define MDIO_GLOB_CTRL_SE (1 << 15)
+
+#define MDIO_MDC_CFG1_RES (1 << 15)
+#define MDIO_MDC_CFG1_MCEN (1 << 8)
+
+#define MDIO_CTRL_MBUSY (1 << 12)
+#define MDIO_CTRL_OP_READ (1 << 11)
+#define MDIO_CTRL_OP_WRITE (1 << 10)
+#define MDIO_CTRL_PHYAD_SHIFT 5
+#define MDIO_CTRL_PHYAD_MASK (0x1f << MDIO_CTRL_PHYAD_SHIFT)
+#define MDIO_CTRL_REGAD_MASK 0x1f
+
+#endif /* __VRX200_SWITCH_H__ */
--- a/arch/mips/include/asm/asm.h
+++ b/arch/mips/include/asm/asm.h
@@ -53,6 +53,7 @@
.align 2; \
.type symbol, @function; \
.ent symbol, 0; \
+ .section .text.symbol,"x"; \
symbol: .frame sp, 0, ra
/*
@@ -62,7 +63,8 @@ symbol: .frame sp, 0, ra
.globl symbol; \
.align 2; \
.type symbol, @function; \
- .ent symbol, 0; \
+ .ent symbol, 0; \
+ .section .text.symbol,"x"; \
symbol: .frame sp, framesize, rpc
/*
--- /dev/null
+++ b/arch/mips/include/asm/gpio.h
@@ -0,0 +1,6 @@
+/*
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <asm/arch/gpio.h>
+#include <asm-generic/gpio.h>
--- /dev/null
+++ b/arch/mips/include/asm/lantiq/chipid.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2011-2013 Daniel Schwierzeck, daniel.schwierzeck@gmail.com
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#ifndef __LANTIQ_CHIPID_H__
+#define __LANTIQ_CHIPID_H__
+
+enum ltq_chip_partnum {
+ LTQ_SOC_UNKNOWN = 0,
+ LTQ_SOC_VRX288_2 = 0x000B, /* VRX288 v1.2 */
+ LTQ_SOC_VRX268_2 = 0x000C, /* VRX268 v1.2 */
+ LTQ_SOC_GRX288_2 = 0x000D, /* GRX288 v1.2 */
+ LTQ_SOC_DANUBE = 0x0129,
+ LTQ_SOC_DANUBE_S = 0x012B,
+ LTQ_SOC_TWINPASS = 0x012D,
+ LTQ_SOC_VRX288 = 0x01C0, /* VRX288 v1.1 */
+ LTQ_SOC_VRX268 = 0x01C2, /* VRX268 v1.1 */
+ LTQ_SOC_GRX288 = 0x01C9, /* GRX288 v1.1 */
+};
+
+extern unsigned int ltq_chip_version_get(void);
+extern unsigned int ltq_chip_partnum_get(void);
+extern const char *ltq_chip_partnum_str(void);
+
+extern void ltq_chip_print_info(void);
+
+#ifdef CONFIG_SOC_XWAY_DANUBE
+static inline int ltq_soc_is_danube(void)
+{
+ return 1;
+}
+#else
+static inline int ltq_soc_is_danube(void)
+{
+ return 0;
+}
+#endif
+
+#ifdef CONFIG_SOC_XWAY_VRX200
+static inline int ltq_soc_is_vrx200(void)
+{
+ return 1;
+}
+
+static inline int ltq_soc_is_vrx200_v1(void)
+{
+ return ltq_chip_version_get() == 1;
+}
+
+static inline int ltq_soc_is_vrx200_v2(void)
+{
+ return ltq_chip_version_get() == 2;
+}
+#else
+static inline int ltq_soc_is_vrx200(void)
+{
+ return 0;
+}
+
+static inline int ltq_soc_is_vrx200_v1(void)
+{
+ return 0;
+}
+
+static inline int ltq_soc_is_vrx200_v2(void)
+{
+ return 0;
+}
+#endif
+
+#endif /* __LANTIQ_CHIPID_H__ */
--- /dev/null
+++ b/arch/mips/include/asm/lantiq/clk.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2007-2010 Lantiq Deutschland GmbH
+ * Copyright (C) 2011-2013 Daniel Schwierzeck, daniel.schwierzeck@gmail.com
+ * *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#ifndef __LANTIQ_CLK_H__
+#define __LANTIQ_CLK_H__
+
+/* Symbolic clock speeds */
+enum ltq_clk {
+ CLOCK_83_MHZ = 83333333,
+ CLOCK_111_MHZ = 111111111,
+ CLOCK_125_MHZ = 125000000,
+ CLOCK_133_MHZ = 133333333,
+ CLOCK_166_MHZ = 166666667,
+ CLOCK_197_MHZ = 197000000,
+ CLOCK_333_MHZ = 333333333,
+ CLOCK_393_MHZ = 393219000,
+ CLOCK_500_MHZ = 500000000,
+ CLOCK_600_MHZ = 600000000,
+ CLOCK_1000_MHZ = 1000000000,
+};
+
+extern unsigned long ltq_get_cpu_clock(void);
+extern unsigned long ltq_get_bus_clock(void);
+extern unsigned long ltq_get_io_region_clock(void);
+
+#endif /* __LANTIQ_CLK_H__ */
--- /dev/null
+++ b/arch/mips/include/asm/lantiq/config.h
@@ -0,0 +1,164 @@
+/*
+ * Copyright (C) 2007-2010 Lantiq Deutschland GmbH
+ * Copyright (C) 2011-2013 Daniel Schwierzeck, daniel.schwierzeck@gmail.com
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#ifndef __LANTIQ_CONFIG_H__
+#define __LANTIQ_CONFIG_H__
+
+/* Memory usage */
+#define CONFIG_SYS_MAXARGS 24
+#define CONFIG_SYS_MALLOC_LEN 1024*1024
+#define CONFIG_SYS_BOOTPARAMS_LEN 128*1024
+
+/* Command line */
+#define CONFIG_SYS_PROMPT CONFIG_MACH_TYPE " # "
+#define CONFIG_SYS_CBSIZE 512
+#define CONFIG_SYS_PBSIZE (CONFIG_SYS_CBSIZE + \
+ sizeof(CONFIG_SYS_PROMPT)+16)
+
+#define CONFIG_SYS_HUSH_PARSER
+#define CONFIG_SYS_PROMPT_HUSH_PS2 "> "
+
+/*
+ * Enable advanced console features on demand to reduce
+ * flash and RAM footprint
+ */
+#if defined(CONFIG_LTQ_ADVANCED_CONSOLE)
+#define CONFIG_SYS_LONGHELP
+#define CONFIG_AUTO_COMPLETE
+#define CONFIG_CMDLINE_EDITING
+#endif
+
+/* SPI flash SPL */
+#if defined(CONFIG_LTQ_SUPPORT_SPL_SPI_FLASH) && defined(CONFIG_SYS_BOOT_SFSPL)
+#define CONFIG_SPL
+#define CONFIG_SPL_SPI_SUPPORT
+#define CONFIG_SPL_SPI_FLASH_SUPPORT
+#define CONFIG_SPI_SPL_SIMPLE
+#endif
+
+#if defined(CONFIG_LTQ_SUPPORT_SPL_NOR_FLASH) && defined(CONFIG_SYS_BOOT_NORSPL)
+#define CONFIG_SPL
+#endif
+
+/* Common SPL */
+#if defined(CONFIG_SPL)
+#define CONFIG_SKIP_LOWLEVEL_INIT
+#define CONFIG_SPL_LIBGENERIC_SUPPORT
+#define CONFIG_SPL_GPIO_SUPPORT
+#define CONFIG_SPL_START_S_PATH \
+ "arch/mips/cpu/mips32/lantiq-common"
+#define CONFIG_SPL_LDSCRIPT \
+ "arch/mips/cpu/mips32/lantiq-common/u-boot-spl.lds"
+#endif
+
+#if defined(CONFIG_LTQ_SPL_CONSOLE)
+#define CONFIG_SPL_SERIAL_SUPPORT
+#define CONFIG_SPL_LIBCOMMON_SUPPORT
+#endif
+
+#if defined(CONFIG_LTQ_SPL_COMP_LZMA)
+#define CONFIG_LZMA
+#define CONFIG_SPL_LZMA_SUPPORT
+#endif
+
+#if defined(CONFIG_LTQ_SPL_COMP_LZO)
+#define CONFIG_LZO
+#define CONFIG_SPL_LZO_SUPPORT
+#endif
+
+/* Basic commands */
+#define CONFIG_CMD_BDI
+#define CONFIG_CMD_EDITENV
+#define CONFIG_CMD_IMI
+#define CONFIG_CMD_MEMORY
+#define CONFIG_CMD_RUN
+#define CONFIG_CMD_SAVEENV
+#define CONFIG_CMD_LOADB
+
+/* Other U-Boot settings */
+#define CONFIG_TIMESTAMP
+
+/* Default environment */
+#define CONFIG_ENV_CONSOLEDEV \
+ "consoledev=" CONFIG_CONSOLE_DEV "\0"
+
+#define CONFIG_ENV_ADDCONSOLE \
+ "addconsole=setenv bootargs $bootargs" \
+ " console=$consoledev,$baudrate\0"
+
+#if defined(CONFIG_NET_DEV)
+#define CONFIG_ENV_NETDEV \
+ "netdev=" CONFIG_NET_DEV "\0"
+#else
+#define CONFIG_ENV_NETDEV \
+ "netdev=eth0\0"
+#endif
+
+#define CONFIG_ENV_ADDIP \
+ "addip=setenv bootargs $bootargs" \
+ " ip=$ipaddr:$serverip::::$netdev:off\0"
+
+#define CONFIG_ENV_ADDETH \
+ "addeth=setenv bootargs $bootargs" \
+ " ethaddr=$ethaddr\0"
+
+#define CONFIG_ENV_ADDMACHTYPE \
+ "addmachtype=setenv bootargs $bootargs" \
+ " machtype=" CONFIG_MACH_TYPE "\0"
+
+#if defined(CONFIG_LTQ_SUPPORT_NOR_FLASH)
+#define CONFIG_ENV_WRITE_UBOOT_NOR \
+ "write-uboot-nor=" \
+ "protect off " __stringify(CONFIG_SYS_FLASH_BASE) " +$filesize && " \
+ "erase " __stringify(CONFIG_SYS_FLASH_BASE) " +$filesize && " \
+ "cp.b $fileaddr " __stringify(CONFIG_SYS_FLASH_BASE) " $filesize\0"
+
+#define CONFIG_ENV_LOAD_UBOOT_NOR \
+ "load-uboot-nor=tftpboot u-boot.bin\0" \
+ "load-uboot-norspl=tftpboot u-boot.ltq.norspl\0" \
+ "load-uboot-norspl-lzo=tftpboot u-boot.ltq.lzo.norspl\0" \
+ "load-uboot-norspl-lzma=tftpboot u-boot.ltq.lzma.norspl\0"
+#else
+#define CONFIG_ENV_WRITE_UBOOT_NOR
+#define CONFIG_ENV_LOAD_UBOOT_NOR
+#endif
+
+#if defined(CONFIG_LTQ_SUPPORT_SPI_FLASH)
+#define CONFIG_ENV_SF_PROBE \
+ "sf-probe=sf probe " __stringify(CONFIG_ENV_SPI_CS) " " \
+ __stringify(CONFIG_ENV_SPI_MAX_HZ) " " \
+ __stringify(CONFIG_ENV_SPI_MODE) " \0"
+
+#define CONFIG_ENV_WRITE_UBOOT_SF \
+ "write-uboot-sf=" \
+ "run sf-probe && sf erase 0 +$filesize && " \
+ "sf write $fileaddr 0 $filesize\0"
+
+#define CONFIG_ENV_LOAD_UBOOT_SF \
+ "load-uboot-sfspl=tftpboot u-boot.ltq.sfspl\0" \
+ "load-uboot-sfspl-lzo=tftpboot u-boot.ltq.lzo.sfspl\0" \
+ "load-uboot-sfspl-lzma=tftpboot u-boot.ltq.lzma.sfspl\0"
+#else
+#define CONFIG_ENV_SF_PROBE
+#define CONFIG_ENV_WRITE_UBOOT_SF
+#define CONFIG_ENV_LOAD_UBOOT_SF
+#endif
+
+#define CONFIG_ENV_LANTIQ_DEFAULTS \
+ CONFIG_ENV_CONSOLEDEV \
+ CONFIG_ENV_ADDCONSOLE \
+ CONFIG_ENV_NETDEV \
+ CONFIG_ENV_ADDIP \
+ CONFIG_ENV_ADDETH \
+ CONFIG_ENV_ADDMACHTYPE \
+ CONFIG_ENV_WRITE_UBOOT_NOR \
+ CONFIG_ENV_LOAD_UBOOT_NOR \
+ CONFIG_ENV_SF_PROBE \
+ CONFIG_ENV_WRITE_UBOOT_SF \
+ CONFIG_ENV_LOAD_UBOOT_SF
+
+#endif /* __LANTIQ_CONFIG_H__ */
--- /dev/null
+++ b/arch/mips/include/asm/lantiq/cpu.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2011-2013 Daniel Schwierzeck, daniel.schwierzeck@gmail.com
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#ifndef __LANTIQ_CPU_H__
+#define __LANTIQ_CPU_H__
+
+enum ltq_boot_select {
+ BOOT_NOR,
+ BOOT_NOR_NO_BOOTROM,
+ BOOT_UART,
+ BOOT_UART_NO_EEPROM,
+ BOOT_SPI,
+ BOOT_NAND,
+ BOOT_PCI,
+ BOOT_MII0,
+ BOOT_RMII0,
+ BOOT_RGMII1,
+ BOOT_UNKNOWN,
+};
+
+enum ltq_boot_select ltq_boot_select(void);
+const char *ltq_boot_select_str(void);
+
+void ltq_pmu_init(void);
+void ltq_ebu_init(void);
+void ltq_gpio_init(void);
+
+void ltq_pll_init(void);
+void ltq_dcdc_init(unsigned int dig_ref);
+
+#endif /* __LANTIQ_CPU_H__ */
--- /dev/null
+++ b/arch/mips/include/asm/lantiq/dma.h
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2011-2013 Daniel Schwierzeck, daniel.schwierzeck@gmail.com
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#ifndef __LANTIQ_DMA_H__
+#define __LANTIQ_DMA_H__
+
+enum ltq_dma_endianess {
+ LTQ_DMA_ENDIANESS_B0_B1_B2_B3, /* No byte swapping */
+ LTQ_DMA_ENDIANESS_B1_B0_B3_B2, /* B0B1B2B3 => B1B0B3B2 */
+ LTQ_DMA_ENDIANESS_B2_B3_B0_B1, /* B0B1B2B3 => B2B3B0B1 */
+ LTQ_DMA_ENDIANESS_B3_B2_B1_B0, /* B0B1B2B3 => B3B2B1B0 */
+};
+
+enum ltq_dma_burst_len {
+ LTQ_DMA_BURST_2WORDS = 1,
+ LTQ_DMA_BURST_4WORDS = 2,
+ LTQ_DMA_BURST_8WORDS = 3,
+};
+
+struct ltq_dma_desc {
+ u32 ctl;
+ u32 addr;
+};
+
+struct ltq_dma_channel {
+ struct ltq_dma_device *dev;
+ u8 chan_no;
+ u8 class;
+ u16 num_desc;
+ struct ltq_dma_desc *desc_base;
+ void *mem_base;
+ u32 dma_addr;
+};
+
+struct ltq_dma_device {
+ enum ltq_dma_endianess rx_endian_swap;
+ enum ltq_dma_endianess tx_endian_swap;
+ enum ltq_dma_burst_len rx_burst_len;
+ enum ltq_dma_burst_len tx_burst_len;
+ struct ltq_dma_channel rx_chan;
+ struct ltq_dma_channel tx_chan;
+ u8 port;
+};
+
+/**
+ * Initialize DMA hardware and driver
+ */
+void ltq_dma_init(void);
+
+/**
+ * Register given DMA client context
+ *
+ * @returns 0 on success, negative value otherwise
+ */
+int ltq_dma_register(struct ltq_dma_device *dev);
+
+/**
+ * Reset and halt all channels related to given DMA client
+ */
+void ltq_dma_reset(struct ltq_dma_device *dev);
+void ltq_dma_enable(struct ltq_dma_device *dev);
+void ltq_dma_disable(struct ltq_dma_device *dev);
+
+/**
+ * Map RX DMA descriptor to memory region
+ *
+ * @returns 0 on success, negative value otherwise
+ */
+int ltq_dma_rx_map(struct ltq_dma_device *dev, int index, void *data, int len);
+
+/**
+ * Check if new data is available.
+ *
+ * @returns length of received data, 0 otherwise
+ */
+int ltq_dma_rx_poll(struct ltq_dma_device *dev, int index);
+
+int ltq_dma_rx_length(struct ltq_dma_device *dev, int index);
+
+/**
+ * Map TX DMA descriptor to memory region
+ *
+ * @returns 0 on success, negative value otherwise
+ */
+int ltq_dma_tx_map(struct ltq_dma_device *dev, int index, void *data, int len,
+ unsigned long timeout);
+
+int ltq_dma_tx_wait(struct ltq_dma_device *dev, int index,
+ unsigned long timeout);
+
+#endif /* __LANTIQ_DMA_H__ */
--- /dev/null
+++ b/arch/mips/include/asm/lantiq/eth.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2011-2013 Daniel Schwierzeck, daniel.schwierzeck@gmail.com
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#ifndef __LANTIQ_ETH_H__
+#define __LANTIQ_ETH_H__
+
+#include <phy.h>
+
+enum LTQ_ETH_PORT_FLAGS {
+ LTQ_ETH_PORT_NONE = 0,
+ LTQ_ETH_PORT_PHY = 1,
+ LTQ_ETH_PORT_SWITCH = (1 << 1),
+ LTQ_ETH_PORT_MAC = (1 << 2),
+};
+
+struct ltq_eth_port_config {
+ u8 num;
+ u8 phy_addr;
+ u16 flags;
+ phy_interface_t phy_if;
+ u8 rgmii_rx_delay;
+ u8 rgmii_tx_delay;
+};
+
+struct ltq_eth_board_config {
+ const struct ltq_eth_port_config *ports;
+ int num_ports;
+};
+
+extern int ltq_eth_initialize(const struct ltq_eth_board_config *board_config);
+
+#endif /* __LANTIQ_ETH_H__ */
--- /dev/null
+++ b/arch/mips/include/asm/lantiq/gpio.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2011-2013 Daniel Schwierzeck, daniel.schwierzeck@gmail.com
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#ifndef __LANTIQ_GPIO_H__
+#define __LANTIQ_GPIO_H__
+
+enum ltq_gpio_dir {
+ GPIO_DIR_IN = 0,
+ GPIO_DIR_OUT
+};
+
+enum ltq_gpio_od {
+ GPIO_OD_ACTIVE = 0,
+ GPIO_OD_NORMAL
+};
+
+enum ltq_gpio_altsel {
+ GPIO_ALTSEL_CLR = 0,
+ GPIO_ALTSEL_SET
+};
+
+extern int gpio_set_altfunc(unsigned gpio, int altsel0, int altsel1, int dir);
+extern int gpio_set_opendrain(unsigned gpio, int od);
+
+static inline int gpio_to_port(unsigned gpio)
+{
+ return gpio >> 4;
+}
+
+static inline int gpio_to_pin(unsigned gpio)
+{
+ return gpio & 0xF;
+}
+
+static inline int gpio_to_bit(unsigned gpio)
+{
+ return 1 << gpio_to_pin(gpio);
+}
+
+static inline int gpio_to_gpio(unsigned port, unsigned pin)
+{
+ return (port << 4) | (pin & 0xF);
+}
+
+#include <asm-generic/gpio.h>
+
+#endif /* __LANTIQ_GPIO_H__ */
--- /dev/null
+++ b/arch/mips/include/asm/lantiq/io.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2010 John Crispin <blogic@openwrt.org>
+ * Copyright (C) 2011-2013 Daniel Schwierzeck, daniel.schwierzeck@gmail.com
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#ifndef __LANTIQ_IO_H__
+#define __LANTIQ_IO_H__
+
+#include <asm/io.h>
+
+#define ltq_readb(a) __raw_readb(a)
+#define ltq_writeb(a, v) __raw_writeb(v, a)
+
+#define ltq_readl(a) __raw_readl(a)
+#define ltq_writel(a, v) __raw_writel(v, a)
+
+#define ltq_clrbits(a, clear) \
+ ltq_writel(a, ltq_readl(a) & ~(clear))
+
+#define ltq_setbits(a, set) \
+ ltq_writel(a, ltq_readl(a) | (set))
+
+#define ltq_clrsetbits(a, clear, set) \
+ ltq_writel(a, (ltq_readl(a) & ~(clear)) | (set))
+
+static inline void ltq_reg_dump(const void *addr, const char *desc)
+{
+ u32 data;
+
+ data = ltq_readl(addr);
+ printf("ltq_reg_dump: %s 0x%p = 0x%08x\n",
+ desc, addr, data);
+}
+
+#endif /* __LANTIQ_IO_H__ */
--- /dev/null
+++ b/arch/mips/include/asm/lantiq/pm.h
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2011-2013 Daniel Schwierzeck, daniel.schwierzeck@gmail.com
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#ifndef __LANTIQ_PM_H__
+#define __LANTIQ_PM_H__
+
+enum ltq_pm_modules {
+ LTQ_PM_CORE,
+ LTQ_PM_DMA,
+ LTQ_PM_ETH,
+ LTQ_PM_SPI,
+};
+
+u32 ltq_pm_map(enum ltq_pm_modules module);
+int ltq_pm_enable(enum ltq_pm_modules module);
+int ltq_pm_disable(enum ltq_pm_modules module);
+
+#endif /* __LANTIQ_PM_H__ */
--- /dev/null
+++ b/arch/mips/include/asm/lantiq/reset.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2011-2013 Daniel Schwierzeck, daniel.schwierzeck@gmail.com
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#ifndef __LANTIQ_RESET_H__
+#define __LANTIQ_RESET_H__
+
+enum ltq_reset_modules {
+ LTQ_RESET_CORE,
+ LTQ_RESET_DMA,
+ LTQ_RESET_ETH,
+ LTQ_RESET_PHY,
+ LTQ_RESET_HARD,
+ LTQ_RESET_SOFT,
+};
+
+extern u32 ltq_reset_map(enum ltq_reset_modules module);
+extern int ltq_reset_activate(enum ltq_reset_modules module);
+extern int ltq_reset_deactivate(enum ltq_reset_modules module);
+
+static inline int ltq_reset_once(enum ltq_reset_modules module, ulong usec)
+{
+ int ret;
+
+ ret = ltq_reset_activate(module);
+ if (ret)
+ return ret;
+
+ __udelay(usec);
+ ret = ltq_reset_deactivate(module);
+
+ return ret;
+}
+
+#endif /* __LANTIQ_RESET_H__ */
--- a/arch/mips/include/asm/mipsregs.h
+++ b/arch/mips/include/asm/mipsregs.h
@@ -46,7 +46,10 @@
#define CP0_ENTRYLO1 $3
#define CP0_CONF $3
#define CP0_CONTEXT $4
+#define CP0_CONTEXTCONFIG $4,1
+#define CP0_USERLOCAL $4,1
#define CP0_PAGEMASK $5
+#define CP0_PAGEGRAIN $5,1
#define CP0_WIRED $6
#define CP0_INFO $7
#define CP0_BADVADDR $8
@@ -54,10 +57,19 @@
#define CP0_ENTRYHI $10
#define CP0_COMPARE $11
#define CP0_STATUS $12
+#define CP0_INTCTL $12,1
+#define CP0_SRSCTL $12,2
+#define CP0_SRSMAP $12,3
+#define CP0_SRSHIGH $12,4
#define CP0_CAUSE $13
#define CP0_EPC $14
#define CP0_PRID $15
+#define CP0_EBASE $15,1
#define CP0_CONFIG $16
+#define CP0_CONFIG1 $16,1
+#define CP0_CONFIG2 $16,2
+#define CP0_CONFIG3 $16,3
+#define CP0_CONFIG7 $16,7
#define CP0_LLADDR $17
#define CP0_WATCHLO $18
#define CP0_WATCHHI $19
@@ -70,7 +82,17 @@
#define CP0_ECC $26
#define CP0_CACHEERR $27
#define CP0_TAGLO $28
+#define CP0_ITAGLO $28
+#define CP0_IDATALO $28,1
+#define CP0_DTAGLO $28,2
+#define CP0_DDATALO $28,3
+#define CP0_L23TAGLO $28,4
+#define CP0_L23DATALO $28,5
#define CP0_TAGHI $29
+#define CP0_IDATAHI $29,1
+#define CP0_DTAGHI $29,2
+#define CP0_L23TAGHI $29,4
+#define CP0_L23DATAHI $29,5
#define CP0_ERROREPC $30
#define CP0_DESAVE $31
@@ -395,6 +417,12 @@
#define CAUSEF_BD (_ULCAST_(1) << 31)
/*
+ * Bits in the coprocessor 0 EBase register.
+ */
+#define EBASEB_CPUNUM 0
+#define EBASEF_CPUNUM (_ULCAST_(1023))
+
+/*
* Bits in the coprocessor 0 config register.
*/
/* Generic bits. */
--- a/arch/mips/include/asm/u-boot-mips.h
+++ b/arch/mips/include/asm/u-boot-mips.h
@@ -23,3 +23,4 @@ static inline unsigned long image_copy_e
}
extern int incaip_set_cpuclk(void);
+extern int arch_cpu_init(void);
--- a/arch/mips/lib/board.c
+++ b/arch/mips/lib/board.c
@@ -33,6 +33,16 @@ static char *failed = "*** failed ***\n"
*/
const unsigned long mips_io_port_base = -1;
+int __arch_cpu_init(void)
+{
+ /*
+ * Nothing to do in this dummy implementation
+ */
+ return 0;
+}
+int arch_cpu_init(void)
+ __attribute__((weak, alias("__arch_cpu_init")));
+
int __board_early_init_f(void)
{
/*
@@ -106,6 +116,7 @@ static int init_baudrate(void)
typedef int (init_fnc_t)(void);
init_fnc_t *init_sequence[] = {
+ arch_cpu_init,
board_early_init_f,
timer_init,
env_init, /* initialize environment */
--- a/drivers/dma/Makefile
+++ b/drivers/dma/Makefile
@@ -12,6 +12,7 @@ LIB := $(obj)libdma.o
COBJS-$(CONFIG_FSLDMAFEC) += MCD_tasksInit.o MCD_dmaApi.o MCD_tasks.o
COBJS-$(CONFIG_APBH_DMA) += apbh_dma.o
COBJS-$(CONFIG_FSL_DMA) += fsl_dma.o
+COBJS-$(CONFIG_LANTIQ_DMA) += lantiq_dma.o
COBJS-$(CONFIG_OMAP3_DMA) += omap3_dma.o
COBJS := $(COBJS-y)
--- /dev/null
+++ b/drivers/dma/lantiq_dma.c
@@ -0,0 +1,387 @@
+/*
+ * Copyright (C) 2011-2013 Daniel Schwierzeck, daniel.schwierzeck@gmail.com
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <malloc.h>
+#include <watchdog.h>
+#include <linux/compiler.h>
+#include <asm/lantiq/io.h>
+#include <asm/lantiq/dma.h>
+#include <asm/lantiq/pm.h>
+#include <asm/lantiq/reset.h>
+#include <asm/arch/soc.h>
+#include <asm/processor.h>
+
+#define DMA_CTRL_PKTARB (1 << 31)
+#define DMA_CTRL_MBRSTARB (1 << 30)
+#define DMA_CTRL_MBRSTCNT_SHIFT 16
+#define DMA_CTRL_MBRSTCNT_MASK (0x3ff << DMA_CTRL_MBRSTCNT_SHIFT)
+#define DMA_CTRL_DRB (1 << 8)
+#define DMA_CTRL_RESET (1 << 0)
+
+#define DMA_CPOLL_EN (1 << 31)
+#define DMA_CPOLL_CNT_SHIFT 4
+#define DMA_CPOLL_CNT_MASK (0xFFF << DMA_CPOLL_CNT_SHIFT)
+
+#define DMA_CCTRL_TXWGT_SHIFT 16
+#define DMA_CCTRL_TXWGT_MASK (0x3 << DMA_CCTRL_TXWGT_SHIFT)
+#define DMA_CCTRL_CLASS_SHIFT 9
+#define DMA_CCTRL_CLASS_MASK (0x3 << DMA_CCTRL_CLASS_SHIFT)
+#define DMA_CCTRL_RST (1 << 1)
+#define DMA_CCTRL_ONOFF (1 << 0)
+
+#define DMA_PCTRL_TXBL_SHIFT 4
+#define DMA_PCTRL_TXBL_2WORDS (1 << DMA_PCTRL_TXBL_SHIFT)
+#define DMA_PCTRL_TXBL_4WORDS (2 << DMA_PCTRL_TXBL_SHIFT)
+#define DMA_PCTRL_TXBL_8WORDS (3 << DMA_PCTRL_TXBL_SHIFT)
+#define DMA_PCTRL_RXBL_SHIFT 2
+#define DMA_PCTRL_RXBL_2WORDS (1 << DMA_PCTRL_RXBL_SHIFT)
+#define DMA_PCTRL_RXBL_4WORDS (2 << DMA_PCTRL_RXBL_SHIFT)
+#define DMA_PCTRL_RXBL_8WORDS (3 << DMA_PCTRL_RXBL_SHIFT)
+#define DMA_PCTRL_TXENDI_SHIFT 10
+#define DMA_PCTRL_TXENDI_MASK (0x3 << DMA_PCTRL_TXENDI_SHIFT)
+#define DMA_PCTRL_RXENDI_SHIFT 8
+#define DMA_PCTRL_RXENDI_MASK (0x3 << DMA_PCTRL_RXENDI_SHIFT)
+
+#define DMA_DESC_OWN (1 << 31)
+#define DMA_DESC_C (1 << 30)
+#define DMA_DESC_SOP (1 << 29)
+#define DMA_DESC_EOP (1 << 28)
+#define DMA_DESC_TX_OFFSET(x) ((x & 0x1f) << 23)
+#define DMA_DESC_RX_OFFSET(x) ((x & 0x3) << 23)
+#define DMA_DESC_LENGTH(x) (x & 0xffff)
+
+#define PTR_ALIGN(p, a) ((typeof(p))ALIGN((unsigned long)(p), (a)))
+
+struct ltq_dma_regs {
+ u32 clc; /* Clock control */
+ u32 rsvd0;
+ u32 id; /* Identification */
+ u32 rsvd1;
+ u32 ctrl; /* Control */
+ u32 cpoll; /* Channel polling */
+ u32 cs; /* Channel select */
+ u32 cctrl; /* Channel control */
+ u32 cdba; /* Channel descriptor base address */
+ u32 cdlen; /* Channel descriptor length */
+ u32 cis; /* Channel interrupt status */
+ u32 cie; /* Channel interrupt enable */
+ u32 cgbl; /* Channel global buffer length */
+ u32 cdptnrd; /* Current descriptor pointer */
+ u32 rsvd2[2];
+ u32 ps; /* Port select */
+ u32 pctrl; /* Port control */
+ u32 rsvd3[43];
+ u32 irnen; /* Interrupt node enable */
+ u32 irncr; /* Interrupt node control */
+ u32 irnicr; /* Interrupt capture */
+};
+
+static struct ltq_dma_regs *ltq_dma_regs =
+ (struct ltq_dma_regs *) CKSEG1ADDR(LTQ_DMA_BASE);
+
+static inline unsigned long ltq_dma_addr_to_virt(u32 dma_addr)
+{
+ return KSEG0ADDR(dma_addr);
+}
+
+static inline u32 ltq_virt_to_dma_addr(void *addr)
+{
+ return CPHYSADDR(addr);
+}
+
+static inline int ltq_dma_burst_align(enum ltq_dma_burst_len burst_len)
+{
+ switch (burst_len) {
+ case LTQ_DMA_BURST_2WORDS:
+ return 2 * 4;
+ case LTQ_DMA_BURST_4WORDS:
+ return 4 * 4;
+ case LTQ_DMA_BURST_8WORDS:
+ return 8 * 4;
+ }
+
+ return 0;
+}
+
+static inline void ltq_dma_sync(void)
+{
+ __asm__ __volatile__("sync");
+}
+
+static inline void ltq_dma_dcache_wb_inv(const void *ptr, size_t size)
+{
+ unsigned long addr = (unsigned long) ptr;
+
+ flush_dcache_range(addr, addr + size);
+ ltq_dma_sync();
+}
+
+static inline void ltq_dma_dcache_inv(const void *ptr, size_t size)
+{
+ unsigned long addr = (unsigned long) ptr;
+
+ invalidate_dcache_range(addr, addr + size);
+}
+
+void ltq_dma_init(void)
+{
+ /* Power up DMA */
+ ltq_pm_enable(LTQ_PM_DMA);
+
+ /* Reset DMA */
+ ltq_setbits(&ltq_dma_regs->ctrl, DMA_CTRL_RESET);
+
+ /* Disable and clear all interrupts */
+ ltq_writel(&ltq_dma_regs->irnen, 0);
+ ltq_writel(&ltq_dma_regs->irncr, 0xFFFFF);
+
+#if 0
+ /* Enable packet arbitration */
+ ltq_setbits(&ltq_dma_regs->ctrl, DMA_CTRL_PKTARB);
+#endif
+
+#if 0
+ /* Enable descriptor read back */
+ ltq_setbits(&ltq_dma_regs->ctrl, DMA_CTRL_DRB);
+#endif
+
+ /* Enable polling for descriptor fetching for all channels */
+ ltq_writel(&ltq_dma_regs->cpoll, DMA_CPOLL_EN |
+ (4 << DMA_CPOLL_CNT_SHIFT));
+}
+
+static void ltq_dma_channel_reset(struct ltq_dma_channel *chan)
+{
+ ltq_writel(&ltq_dma_regs->cs, chan->chan_no);
+ ltq_setbits(&ltq_dma_regs->cctrl, DMA_CCTRL_RST);
+}
+
+static void ltq_dma_channel_enable(struct ltq_dma_channel *chan)
+{
+ ltq_writel(&ltq_dma_regs->cs, chan->chan_no);
+ ltq_setbits(&ltq_dma_regs->cctrl, DMA_CCTRL_ONOFF);
+}
+
+static void ltq_dma_channel_disable(struct ltq_dma_channel *chan)
+{
+ ltq_writel(&ltq_dma_regs->cs, chan->chan_no);
+ ltq_clrbits(&ltq_dma_regs->cctrl, DMA_CCTRL_ONOFF);
+}
+
+static void ltq_dma_port_init(struct ltq_dma_device *dev)
+{
+ u32 pctrl;
+
+ pctrl = dev->tx_endian_swap << DMA_PCTRL_TXENDI_SHIFT;
+ pctrl |= dev->rx_endian_swap << DMA_PCTRL_RXENDI_SHIFT;
+ pctrl |= dev->tx_burst_len << DMA_PCTRL_TXBL_SHIFT;
+ pctrl |= dev->rx_burst_len << DMA_PCTRL_RXBL_SHIFT;
+
+ ltq_writel(&ltq_dma_regs->ps, dev->port);
+ ltq_writel(&ltq_dma_regs->pctrl, pctrl);
+}
+
+static int ltq_dma_alloc_descriptors(struct ltq_dma_device *dev,
+ struct ltq_dma_channel *chan)
+{
+ size_t size;
+ void *desc_base;
+
+ size = ALIGN(sizeof(struct ltq_dma_desc) * chan->num_desc +
+ ARCH_DMA_MINALIGN, ARCH_DMA_MINALIGN);
+
+ chan->mem_base = malloc(size);
+ if (!chan->mem_base)
+ return 1;
+
+ memset(chan->mem_base, 0, size);
+ ltq_dma_dcache_wb_inv(chan->mem_base, size);
+
+ desc_base = PTR_ALIGN(chan->mem_base, ARCH_DMA_MINALIGN);
+
+ debug("DMA: mem %p, desc %p\n", chan->mem_base, desc_base);
+
+ /* Align descriptor base to 8 bytes */
+ chan->desc_base = (void *) CKSEG1ADDR(desc_base);
+ chan->dma_addr = CPHYSADDR(desc_base);
+ chan->dev = dev;
+
+ debug("DMA: desc_base %p, size %u\n", chan->desc_base, size);
+
+ /* Configure hardware with location of descriptor list */
+ ltq_writel(&ltq_dma_regs->cs, chan->chan_no);
+ ltq_writel(&ltq_dma_regs->cdba, chan->dma_addr);
+ ltq_writel(&ltq_dma_regs->cdlen, chan->num_desc);
+ ltq_writel(&ltq_dma_regs->cctrl, (3 << DMA_CCTRL_TXWGT_SHIFT) |
+ (chan->class << DMA_CCTRL_CLASS_SHIFT));
+ ltq_writel(&ltq_dma_regs->cctrl, DMA_CCTRL_RST);
+
+ return 0;
+}
+
+static void ltq_dma_free_descriptors(struct ltq_dma_channel *chan)
+{
+ ltq_writel(&ltq_dma_regs->cs, chan->chan_no);
+ ltq_writel(&ltq_dma_regs->cdba, 0);
+ ltq_writel(&ltq_dma_regs->cdlen, 0);
+
+ ltq_dma_channel_reset(chan);
+
+ free(chan->mem_base);
+}
+
+int ltq_dma_register(struct ltq_dma_device *dev)
+{
+ int ret;
+
+ ltq_dma_port_init(dev);
+
+ ret = ltq_dma_alloc_descriptors(dev, &dev->rx_chan);
+ if (ret)
+ return ret;
+
+ ret = ltq_dma_alloc_descriptors(dev, &dev->tx_chan);
+ if (ret) {
+ ltq_dma_free_descriptors(&dev->rx_chan);
+ return ret;
+ }
+
+ return 0;
+}
+
+void ltq_dma_reset(struct ltq_dma_device *dev)
+{
+ ltq_dma_channel_reset(&dev->rx_chan);
+ ltq_dma_channel_reset(&dev->tx_chan);
+}
+
+void ltq_dma_enable(struct ltq_dma_device *dev)
+{
+ ltq_dma_channel_enable(&dev->rx_chan);
+ ltq_dma_channel_enable(&dev->tx_chan);
+}
+
+void ltq_dma_disable(struct ltq_dma_device *dev)
+{
+ ltq_dma_channel_disable(&dev->rx_chan);
+ ltq_dma_channel_disable(&dev->tx_chan);
+}
+
+int ltq_dma_rx_map(struct ltq_dma_device *dev, int index, void *data, int len)
+{
+ struct ltq_dma_channel *chan = &dev->rx_chan;
+ struct ltq_dma_desc *desc = &chan->desc_base[index];
+ u32 dma_addr = ltq_virt_to_dma_addr(data);
+ unsigned int offset;
+
+ offset = dma_addr % ltq_dma_burst_align(dev->rx_burst_len);
+
+ ltq_dma_dcache_inv(data, len);
+
+#if 0
+ printf("%s: index %d, data %p, dma_addr %08x, offset %u, len %d\n",
+ __func__, index, data, dma_addr, offset, len);
+#endif
+
+
+ desc->addr = dma_addr - offset;
+ desc->ctl = DMA_DESC_OWN | DMA_DESC_RX_OFFSET(offset) |
+ DMA_DESC_LENGTH(len);
+
+#if 0
+ printf("%s: index %d, desc %p, desc->ctl %08x\n",
+ __func__, index, desc, desc->ctl);
+#endif
+
+ return 0;
+}
+
+int ltq_dma_rx_poll(struct ltq_dma_device *dev, int index)
+{
+ struct ltq_dma_channel *chan = &dev->rx_chan;
+ struct ltq_dma_desc *desc = &chan->desc_base[index];
+
+#if 0
+ printf("%s: index %d, desc %p, desc->ctl %08x\n",
+ __func__, index, desc, desc->ctl);
+#endif
+
+ if (desc->ctl & DMA_DESC_OWN)
+ return 0;
+
+ if (desc->ctl & DMA_DESC_C)
+ return 1;
+
+ return 0;
+}
+
+int ltq_dma_rx_length(struct ltq_dma_device *dev, int index)
+{
+ struct ltq_dma_channel *chan = &dev->rx_chan;
+ struct ltq_dma_desc *desc = &chan->desc_base[index];
+
+ return DMA_DESC_LENGTH(desc->ctl);
+}
+
+int ltq_dma_tx_map(struct ltq_dma_device *dev, int index, void *data, int len,
+ unsigned long timeout)
+{
+ struct ltq_dma_channel *chan = &dev->tx_chan;
+ struct ltq_dma_desc *desc = &chan->desc_base[index];
+ unsigned int offset;
+ unsigned long timebase = get_timer(0);
+ u32 dma_addr = ltq_virt_to_dma_addr(data);
+
+ while (desc->ctl & DMA_DESC_OWN) {
+ WATCHDOG_RESET();
+
+ if (get_timer(timebase) >= timeout) {
+#if 0
+ printf("%s: timeout: index %d, desc %p, desc->ctl %08x\n",
+ __func__, index, desc, desc->ctl);
+#endif
+ return -1;
+ }
+ }
+
+ offset = dma_addr % ltq_dma_burst_align(dev->rx_burst_len);
+
+#if 0
+ printf("%s: index %d, desc %p, data %p, dma_addr %08x, offset %u, len %d\n",
+ __func__, index, desc, data, dma_addr, offset, len);
+#endif
+
+ ltq_dma_dcache_wb_inv(data, len);
+
+ desc->addr = dma_addr - offset;
+ desc->ctl = DMA_DESC_OWN | DMA_DESC_SOP | DMA_DESC_EOP |
+ DMA_DESC_TX_OFFSET(offset) | DMA_DESC_LENGTH(len);
+
+#if 0
+ printf("%s: index %d, desc %p, desc->ctl %08x\n",
+ __func__, index, desc, desc->ctl);
+#endif
+
+ return 0;
+}
+
+int ltq_dma_tx_wait(struct ltq_dma_device *dev, int index,
+ unsigned long timeout)
+{
+ struct ltq_dma_channel *chan = &dev->tx_chan;
+ struct ltq_dma_desc *desc = &chan->desc_base[index];
+ unsigned long timebase = get_timer(0);
+
+ while ((desc->ctl & (DMA_DESC_OWN | DMA_DESC_C)) != DMA_DESC_C) {
+ WATCHDOG_RESET();
+
+ if (get_timer(timebase) >= timeout)
+ return -1;
+ }
+
+ return 0;
+}
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -12,6 +12,7 @@ LIB := $(obj)libgpio.o
COBJS-$(CONFIG_AT91_GPIO) += at91_gpio.o
COBJS-$(CONFIG_INTEL_ICH6_GPIO) += intel_ich6_gpio.o
COBJS-$(CONFIG_KIRKWOOD_GPIO) += kw_gpio.o
+COBJS-$(CONFIG_LANTIQ_GPIO) += lantiq_gpio.o
COBJS-$(CONFIG_MARVELL_GPIO) += mvgpio.o
COBJS-$(CONFIG_MARVELL_MFP) += mvmfp.o
COBJS-$(CONFIG_MXC_GPIO) += mxc_gpio.o
--- /dev/null
+++ b/drivers/gpio/lantiq_gpio.c
@@ -0,0 +1,329 @@
+/*
+ * Copyright (C) 2011-2013 Daniel Schwierzeck, daniel.schwierzeck@gmail.com
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <asm/arch/soc.h>
+#include <asm/arch/gpio.h>
+#include <asm/lantiq/io.h>
+
+#define SSIO_GPIO_BASE 64
+
+#define SSIO_CON0_SWU (1 << 31)
+#define SSIO_CON0_RZFL (1 << 26)
+#define SSIO_CON0_GPHY1_SHIFT 27
+#define SSIO_CON0_GPHY1_CONFIG ((CONFIG_LTQ_SSIO_GPHY1_MODE & 0x7) << 27)
+
+#define SSIO_CON1_US_FPI (2 << 30)
+#define SSIO_CON1_FPID_2HZ (0 << 23)
+#define SSIO_CON1_FPID_4HZ (1 << 23)
+#define SSIO_CON1_FPID_8HZ (2 << 23)
+#define SSIO_CON1_FPID_10HZ (3 << 23)
+#define SSIO_CON1_FPIS_1_2 (1 << 20)
+#define SSIO_CON1_FPIS_1_32 (2 << 20)
+#define SSIO_CON1_FPIS_1_64 (3 << 20)
+
+#define SSIO_CON1_GPHY2_SHIFT 15
+#define SSIO_CON1_GPHY2_CONFIG ((CONFIG_LTQ_SSIO_GPHY2_MODE & 0x7) << 15)
+
+#define SSIO_CON1_GROUP2 (1 << 2)
+#define SSIO_CON1_GROUP1 (1 << 1)
+#define SSIO_CON1_GROUP0 (1 << 0)
+#define SSIO_CON1_GROUP_CONFIG (0x3)
+
+#ifdef CONFIG_LTQ_SSIO_SHIFT_REGS
+#define enable_ssio 1
+#else
+#define enable_ssio 0
+
+#define CONFIG_LTQ_SSIO_GPHY1_MODE 0
+#define CONFIG_LTQ_SSIO_GPHY2_MODE 0
+#define CONFIG_LTQ_SSIO_INIT_VALUE 0
+#endif
+
+#ifdef CONFIG_LTQ_SSIO_EDGE_FALLING
+#define SSIO_RZFL_CONFIG SSIO_CON0_RZFL
+#else
+#define SSIO_RZFL_CONFIG 0
+#endif
+
+struct ltq_gpio_port_regs {
+ __be32 out;
+ __be32 in;
+ __be32 dir;
+ __be32 altsel0;
+ __be32 altsel1;
+ __be32 od;
+ __be32 stoff;
+ __be32 pudsel;
+ __be32 puden;
+ __be32 rsvd1[3];
+};
+
+struct ltq_gpio_regs {
+ u32 rsvd[4];
+ struct ltq_gpio_port_regs ports[CONFIG_LTQ_GPIO_MAX_BANKS];
+};
+
+struct ltq_gpio3_regs {
+ u32 rsvd0[13];
+ __be32 od;
+ __be32 pudsel;
+ __be32 puden;
+ u32 rsvd1[9];
+ __be32 altsel1;
+ u32 rsvd2[14];
+ __be32 out;
+ __be32 in;
+ __be32 dir;
+ __be32 altsel0;
+};
+
+struct ltq_ssio_regs {
+ __be32 con0;
+ __be32 con1;
+ __be32 cpu0;
+ __be32 cpu1;
+ __be32 ar;
+};
+
+static struct ltq_gpio_regs *ltq_gpio_regs =
+ (struct ltq_gpio_regs *) CKSEG1ADDR(LTQ_GPIO_BASE);
+
+static struct ltq_gpio3_regs *ltq_gpio3_regs =
+ (struct ltq_gpio3_regs *) CKSEG1ADDR(LTQ_GPIO_BASE);
+
+static struct ltq_ssio_regs *ltq_ssio_regs =
+ (struct ltq_ssio_regs *) CKSEG1ADDR(LTQ_SSIO_BASE);
+
+static int is_gpio_bank3(unsigned int port)
+{
+#ifdef CONFIG_LTQ_HAS_GPIO_BANK3
+ return port == 3;
+#else
+ return 0;
+#endif
+}
+
+static int is_gpio_ssio(unsigned int gpio)
+{
+#ifdef CONFIG_LTQ_SSIO_SHIFT_REGS
+ return gpio >= SSIO_GPIO_BASE;
+#else
+ return 0;
+#endif
+}
+
+static inline int ssio_gpio_to_bit(unsigned gpio)
+{
+ return 1 << (gpio - SSIO_GPIO_BASE);
+}
+
+int ltq_gpio_init(void)
+{
+ ltq_writel(&ltq_ssio_regs->ar, 0);
+ ltq_writel(&ltq_ssio_regs->cpu0, CONFIG_LTQ_SSIO_INIT_VALUE);
+ ltq_writel(&ltq_ssio_regs->cpu1, 0);
+ ltq_writel(&ltq_ssio_regs->con0, SSIO_CON0_SWU);
+
+ if (enable_ssio) {
+ ltq_writel(&ltq_ssio_regs->con0, SSIO_CON0_GPHY1_CONFIG |
+ SSIO_RZFL_CONFIG);
+ ltq_writel(&ltq_ssio_regs->con1, SSIO_CON1_US_FPI |
+ SSIO_CON1_FPID_8HZ | SSIO_CON1_GPHY2_CONFIG |
+ SSIO_CON1_GROUP_CONFIG);
+ }
+
+ return 0;
+}
+
+int gpio_request(unsigned gpio, const char *label)
+{
+ return 0;
+}
+
+int gpio_free(unsigned gpio)
+{
+ return 0;
+}
+
+int gpio_direction_input(unsigned gpio)
+{
+ unsigned port = gpio_to_port(gpio);
+ const void *gpio_od = &ltq_gpio_regs->ports[port].od;
+ const void *gpio_altsel0 = &ltq_gpio_regs->ports[port].altsel0;
+ const void *gpio_altsel1 = &ltq_gpio_regs->ports[port].altsel1;
+ const void *gpio_dir = &ltq_gpio_regs->ports[port].dir;
+
+ if (is_gpio_ssio(gpio))
+ return 0;
+
+ if (is_gpio_bank3(port)) {
+ gpio_od = &ltq_gpio3_regs->od;
+ gpio_altsel0 = &ltq_gpio3_regs->altsel0;
+ gpio_altsel1 = &ltq_gpio3_regs->altsel1;
+ gpio_dir = &ltq_gpio3_regs->dir;
+ }
+
+ /*
+ * Reset open drain and altsel configs to workaround improper
+ * reset values or unwanted modifications by BootROM
+ */
+ ltq_clrbits(gpio_od, gpio_to_bit(gpio));
+ ltq_clrbits(gpio_altsel0, gpio_to_bit(gpio));
+ ltq_clrbits(gpio_altsel1, gpio_to_bit(gpio));
+
+ /* Switch to input */
+ ltq_clrbits(gpio_dir, gpio_to_bit(gpio));
+
+ return 0;
+}
+
+int gpio_direction_output(unsigned gpio, int value)
+{
+ unsigned port = gpio_to_port(gpio);
+ const void *gpio_od = &ltq_gpio_regs->ports[port].od;
+ const void *gpio_altsel0 = &ltq_gpio_regs->ports[port].altsel0;
+ const void *gpio_altsel1 = &ltq_gpio_regs->ports[port].altsel1;
+ const void *gpio_dir = &ltq_gpio_regs->ports[port].dir;
+ const void *gpio_out = &ltq_gpio_regs->ports[port].out;
+ u32 data = gpio_to_bit(gpio);
+
+ if (is_gpio_ssio(gpio)) {
+ data = ssio_gpio_to_bit(gpio);
+ if (value)
+ ltq_setbits(&ltq_ssio_regs->cpu0, data);
+ else
+ ltq_clrbits(&ltq_ssio_regs->cpu0, data);
+
+ return 0;
+ }
+
+ if (is_gpio_bank3(port)) {
+ gpio_od = &ltq_gpio3_regs->od;
+ gpio_altsel0 = &ltq_gpio3_regs->altsel0;
+ gpio_altsel1 = &ltq_gpio3_regs->altsel1;
+ gpio_dir = &ltq_gpio3_regs->dir;
+ gpio_out = &ltq_gpio3_regs->out;
+ }
+
+ /*
+ * Reset open drain and altsel configs to workaround improper
+ * reset values or unwanted modifications by BootROM
+ */
+ ltq_setbits(gpio_od, data);
+ ltq_clrbits(gpio_altsel0, data);
+ ltq_clrbits(gpio_altsel1, data);
+
+ if (value)
+ ltq_setbits(gpio_out, data);
+ else
+ ltq_clrbits(gpio_out, data);
+
+ /* Switch to output */
+ ltq_setbits(gpio_dir, data);
+
+ return 0;
+}
+
+int gpio_get_value(unsigned gpio)
+{
+ unsigned port = gpio_to_port(gpio);
+ const void *gpio_in = &ltq_gpio_regs->ports[port].in;
+ u32 data = gpio_to_bit(gpio);
+ u32 val;
+
+ if (is_gpio_ssio(gpio)) {
+ gpio_in = &ltq_ssio_regs->cpu0;
+ data = ssio_gpio_to_bit(gpio);
+ }
+
+ if (is_gpio_bank3(port))
+ gpio_in = &ltq_gpio3_regs->in;
+
+ val = ltq_readl(gpio_in);
+
+ return !!(val & data);
+}
+
+int gpio_set_value(unsigned gpio, int value)
+{
+ unsigned port = gpio_to_port(gpio);
+ const void *gpio_out = &ltq_gpio_regs->ports[port].out;
+ u32 data = gpio_to_bit(gpio);
+
+ if (is_gpio_ssio(gpio)) {
+ gpio_out = &ltq_ssio_regs->cpu0;
+ data = ssio_gpio_to_bit(gpio);
+ }
+
+ if (is_gpio_bank3(port))
+ gpio_out = &ltq_gpio3_regs->out;
+
+ if (value)
+ ltq_setbits(gpio_out, data);
+ else
+ ltq_clrbits(gpio_out, data);
+
+ return 0;
+}
+
+int gpio_set_altfunc(unsigned gpio, int altsel0, int altsel1, int dir)
+{
+ unsigned port = gpio_to_port(gpio);
+ const void *gpio_od = &ltq_gpio_regs->ports[port].od;
+ const void *gpio_altsel0 = &ltq_gpio_regs->ports[port].altsel0;
+ const void *gpio_altsel1 = &ltq_gpio_regs->ports[port].altsel1;
+ const void *gpio_dir = &ltq_gpio_regs->ports[port].dir;
+
+ if (is_gpio_ssio(gpio))
+ return 0;
+
+ if (is_gpio_bank3(port)) {
+ gpio_od = &ltq_gpio3_regs->od;
+ gpio_altsel0 = &ltq_gpio3_regs->altsel0;
+ gpio_altsel1 = &ltq_gpio3_regs->altsel1;
+ gpio_dir = &ltq_gpio3_regs->dir;
+ }
+
+ if (altsel0)
+ ltq_setbits(gpio_altsel0, gpio_to_bit(gpio));
+ else
+ ltq_clrbits(gpio_altsel0, gpio_to_bit(gpio));
+
+ if (altsel1)
+ ltq_setbits(gpio_altsel1, gpio_to_bit(gpio));
+ else
+ ltq_clrbits(gpio_altsel1, gpio_to_bit(gpio));
+
+ if (dir) {
+ ltq_setbits(gpio_od, gpio_to_bit(gpio));
+ ltq_setbits(gpio_dir, gpio_to_bit(gpio));
+ } else {
+ ltq_clrbits(gpio_od, gpio_to_bit(gpio));
+ ltq_clrbits(gpio_dir, gpio_to_bit(gpio));
+ }
+
+ return 0;
+}
+
+int gpio_set_opendrain(unsigned gpio, int od)
+{
+ unsigned port = gpio_to_port(gpio);
+ const void *gpio_od = &ltq_gpio_regs->ports[port].od;
+
+ if (is_gpio_ssio(gpio))
+ return 0;
+
+ if (is_gpio_bank3(port))
+ gpio_od = &ltq_gpio3_regs->od;
+
+ if (od)
+ ltq_setbits(gpio_od, gpio_to_bit(gpio));
+ else
+ ltq_clrbits(gpio_od, gpio_to_bit(gpio));
+
+ return 0;
+}
--- a/drivers/mtd/cfi_flash.c
+++ b/drivers/mtd/cfi_flash.c
@@ -161,6 +161,18 @@ u64 flash_read64(void *addr)__attribute_
#define flash_read64 __flash_read64
#endif
+static inline void *__flash_swap_addr(unsigned long addr)
+{
+ return (void *) addr;
+}
+
+#ifdef CONFIG_CFI_FLASH_USE_WEAK_ADDR_SWAP
+void *flash_swap_addr(unsigned long addr)
+ __attribute__((weak, alias("__flash_swap_addr")));
+#else
+#define flash_swap_addr __flash_swap_addr
+#endif
+
/*-----------------------------------------------------------------------
*/
#if defined(CONFIG_ENV_IS_IN_FLASH) || defined(CONFIG_ENV_ADDR_REDUND) || (CONFIG_SYS_MONITOR_BASE >= CONFIG_SYS_FLASH_BASE)
@@ -196,7 +208,7 @@ flash_map (flash_info_t * info, flash_se
{
unsigned int byte_offset = offset * info->portwidth;
- return (void *)(info->start[sect] + byte_offset);
+ return flash_swap_addr(info->start[sect] + byte_offset);
}
static inline void flash_unmap(flash_info_t *info, flash_sect_t sect,
--- a/drivers/mtd/nand/Makefile
+++ b/drivers/mtd/nand/Makefile
@@ -53,6 +53,7 @@ COBJS-$(CONFIG_NAND_JZ4740) += jz4740_na
COBJS-$(CONFIG_NAND_KB9202) += kb9202_nand.o
COBJS-$(CONFIG_NAND_KIRKWOOD) += kirkwood_nand.o
COBJS-$(CONFIG_NAND_KMETER1) += kmeter1_nand.o
+COBJS-$(CONFIG_NAND_LANTIQ) += lantiq_nand.o
COBJS-$(CONFIG_NAND_MPC5121_NFC) += mpc5121_nfc.o
COBJS-$(CONFIG_NAND_MXC) += mxc_nand.o
COBJS-$(CONFIG_NAND_MXS) += mxs_nand.o
--- /dev/null
+++ b/drivers/mtd/nand/lantiq_nand.c
@@ -0,0 +1,126 @@
+/*
+ * Copyright (C) 2012-2013 Daniel Schwierzeck, daniel.schwierzeck@gmail.com
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <linux/mtd/nand.h>
+#include <linux/compiler.h>
+#include <asm/arch/soc.h>
+#include <asm/arch/nand.h>
+#include <asm/lantiq/io.h>
+
+#define NAND_CON_ECC_ON (1 << 31)
+#define NAND_CON_LATCH_PRE (1 << 23)
+#define NAND_CON_LATCH_WP (1 << 22)
+#define NAND_CON_LATCH_SE (1 << 21)
+#define NAND_CON_LATCH_CS (1 << 20)
+#define NAND_CON_LATCH_CLE (1 << 19)
+#define NAND_CON_LATCH_ALE (1 << 18)
+#define NAND_CON_OUT_CS1 (1 << 10)
+#define NAND_CON_IN_CS1 (1 << 8)
+#define NAND_CON_PRE_P (1 << 7)
+#define NAND_CON_WP_P (1 << 6)
+#define NAND_CON_SE_P (1 << 5)
+#define NAND_CON_CS_P (1 << 4)
+#define NAND_CON_CLE_P (1 << 3)
+#define NAND_CON_ALE_P (1 << 2)
+#define NAND_CON_CSMUX (1 << 1)
+#define NAND_CON_NANDM (1 << 0)
+
+#define NAND_WAIT_WR_C (1 << 3)
+#define NAND_WAIT_RDBY (1 << 0)
+
+#define NAND_CMD_ALE (1 << 2)
+#define NAND_CMD_CLE (1 << 3)
+#define NAND_CMD_CS (1 << 4)
+#define NAND_CMD_SE (1 << 5)
+#define NAND_CMD_WP (1 << 6)
+#define NAND_CMD_PRE (1 << 7)
+
+struct ltq_nand_regs {
+ __be32 con; /* NAND controller control */
+ __be32 wait; /* NAND Flash Device RD/BY State */
+ __be32 ecc0; /* NAND Flash ECC Register 0 */
+ __be32 ecc_ac; /* NAND Flash ECC Register address counter */
+ __be32 ecc_cr; /* NAND Flash ECC Comparison */
+};
+
+static struct ltq_nand_regs *ltq_nand_regs =
+ (struct ltq_nand_regs *) CKSEG1ADDR(LTQ_EBU_NAND_BASE);
+
+static void ltq_nand_wait_ready(void)
+{
+ while ((ltq_readl(&ltq_nand_regs->wait) & NAND_WAIT_WR_C) == 0)
+ ;
+}
+
+static int ltq_nand_dev_ready(struct mtd_info *mtd)
+{
+ u32 data = ltq_readl(&ltq_nand_regs->wait);
+ return data & NAND_WAIT_RDBY;
+}
+
+static void ltq_nand_select_chip(struct mtd_info *mtd, int chip)
+{
+ if (chip == 0) {
+ ltq_setbits(&ltq_nand_regs->con, NAND_CON_NANDM);
+ ltq_setbits(&ltq_nand_regs->con, NAND_CON_LATCH_CS);
+ } else {
+ ltq_clrbits(&ltq_nand_regs->con, NAND_CON_LATCH_CS);
+ ltq_clrbits(&ltq_nand_regs->con, NAND_CON_NANDM);
+ }
+}
+
+static void ltq_nand_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl)
+{
+ struct nand_chip *chip = mtd->priv;
+ unsigned long addr = (unsigned long) chip->IO_ADDR_W;
+
+ if (ctrl & NAND_CTRL_CHANGE) {
+ if (ctrl & NAND_ALE)
+ addr |= NAND_CMD_ALE;
+ else
+ addr &= ~NAND_CMD_ALE;
+
+ if (ctrl & NAND_CLE)
+ addr |= NAND_CMD_CLE;
+ else
+ addr &= ~NAND_CMD_CLE;
+
+ chip->IO_ADDR_W = (void __iomem *) addr;
+ }
+
+ if (cmd != NAND_CMD_NONE) {
+ writeb(cmd, chip->IO_ADDR_W);
+ ltq_nand_wait_ready();
+ }
+}
+
+int ltq_nand_init(struct nand_chip *nand)
+{
+ /* Enable NAND, set NAND CS to EBU CS1, enable EBU CS mux */
+ ltq_writel(&ltq_nand_regs->con, NAND_CON_OUT_CS1 | NAND_CON_IN_CS1 |
+ NAND_CON_PRE_P | NAND_CON_WP_P | NAND_CON_SE_P |
+ NAND_CON_CS_P | NAND_CON_CSMUX);
+
+ nand->dev_ready = ltq_nand_dev_ready;
+ nand->select_chip = ltq_nand_select_chip;
+ nand->cmd_ctrl = ltq_nand_cmd_ctrl;
+
+ nand->chip_delay = 30;
+ nand->options = 0;
+ nand->ecc.mode = NAND_ECC_SOFT;
+
+ /* Enable CS bit in address offset */
+ nand->IO_ADDR_R = nand->IO_ADDR_R + NAND_CMD_CS;
+ nand->IO_ADDR_W = nand->IO_ADDR_W + NAND_CMD_CS;
+
+ return 0;
+}
+
+__weak int board_nand_init(struct nand_chip *chip)
+{
+ return ltq_nand_init(chip);
+}
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -37,6 +37,8 @@ COBJS-$(CONFIG_INCA_IP_SWITCH) += inca-i
COBJS-$(CONFIG_DRIVER_KS8695ETH) += ks8695eth.o
COBJS-$(CONFIG_KS8851_MLL) += ks8851_mll.o
COBJS-$(CONFIG_LAN91C96) += lan91c96.o
+COBJS-$(CONFIG_LANTIQ_DANUBE_ETOP) += lantiq_danube_etop.o
+COBJS-$(CONFIG_LANTIQ_VRX200_SWITCH) += lantiq_vrx200_switch.o
COBJS-$(CONFIG_MACB) += macb.o
COBJS-$(CONFIG_MCFFEC) += mcffec.o mcfmii.o
COBJS-$(CONFIG_MPC5xxx_FEC) += mpc5xxx_fec.o
--- /dev/null
+++ b/drivers/net/lantiq_danube_etop.c
@@ -0,0 +1,410 @@
+/*
+ * Copyright (C) 2011-2013 Daniel Schwierzeck, daniel.schwierzeck@gmail.com
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <malloc.h>
+#include <netdev.h>
+#include <miiphy.h>
+#include <switch.h>
+#include <asm/lantiq/io.h>
+#include <asm/lantiq/eth.h>
+#include <asm/lantiq/pm.h>
+#include <asm/lantiq/reset.h>
+#include <asm/lantiq/dma.h>
+#include <asm/arch/soc.h>
+
+#define LTQ_PPE_ETOP_MDIO_ACC_RA (1 << 31)
+#define LTQ_PPE_ETOP_MDIO_CFG_UMM1 (1 << 2)
+#define LTQ_PPE_ETOP_MDIO_CFG_UMM0 (1 << 1)
+
+#define LTQ_PPE_ETOP_CFG_TCKINV1 (1 << 11)
+#define LTQ_PPE_ETOP_CFG_TCKINV0 (1 << 10)
+#define LTQ_PPE_ETOP_CFG_FEN1 (1 << 9)
+#define LTQ_PPE_ETOP_CFG_FEN0 (1 << 8)
+#define LTQ_PPE_ETOP_CFG_SEN1 (1 << 7)
+#define LTQ_PPE_ETOP_CFG_SEN0 (1 << 6)
+#define LTQ_PPE_ETOP_CFG_TURBO1 (1 << 5)
+#define LTQ_PPE_ETOP_CFG_REMII1 (1 << 4)
+#define LTQ_PPE_ETOP_CFG_OFF1 (1 << 3)
+#define LTQ_PPE_ETOP_CFG_TURBO0 (1 << 2)
+#define LTQ_PPE_ETOP_CFG_REMII0 (1 << 1)
+#define LTQ_PPE_ETOP_CFG_OFF0 (1 << 0)
+
+#define LTQ_PPE_ENET0_MAC_CFG_CGEN (1 << 11)
+#define LTQ_PPE_ENET0_MAC_CFG_DUPLEX (1 << 2)
+#define LTQ_PPE_ENET0_MAC_CFG_SPEED (1 << 1)
+#define LTQ_PPE_ENET0_MAC_CFG_LINK (1 << 0)
+
+#define LTQ_PPE_ENETS0_CFG_FTUC (1 << 28)
+
+#define LTQ_ETH_RX_BUFFER_CNT PKTBUFSRX
+#define LTQ_ETH_TX_BUFFER_CNT 8
+#define LTQ_ETH_RX_DATA_SIZE PKTSIZE_ALIGN
+#define LTQ_ETH_IP_ALIGN 2
+
+#define LTQ_MDIO_DRV_NAME "ltq-mdio"
+#define LTQ_ETH_DRV_NAME "ltq-eth"
+
+struct ltq_ppe_etop_regs {
+ u32 mdio_cfg; /* MDIO configuration */
+ u32 mdio_acc; /* MDIO access */
+ u32 cfg; /* ETOP configuration */
+ u32 ig_vlan_cos; /* IG VLAN priority CoS mapping */
+ u32 ig_dscp_cos3; /* IG DSCP CoS mapping 3 */
+ u32 ig_dscp_cos2; /* IG DSCP CoS mapping 2 */
+ u32 ig_dscp_cos1; /* IG DSCP CoS mapping 1 */
+ u32 ig_dscp_cos0; /* IG DSCP CoS mapping 0 */
+ u32 ig_plen_ctrl; /* IG frame length control */
+ u32 rsvd0[3];
+ u32 vpid; /* VLAN protocol ID */
+};
+
+struct ltq_ppe_enet_regs {
+ u32 mac_cfg; /* MAC configuration */
+ u32 rsvd0[3];
+ u32 ig_cfg; /* Ingress configuration */
+ u32 ig_pgcnt; /* Ingress buffer used page count */
+ u32 rsvd1;
+ u32 ig_buf_ctrl; /* Ingress buffer backpressure ctrl */
+ u32 cos_cfg; /* Classification configuration */
+ u32 ig_drop; /* Total ingress drop frames */
+ u32 ig_err; /* Total ingress error frames */
+ u32 mac_da0; /* Ingress MAC address 0 */
+ u32 mac_da1; /* Ingress MAC address 1 */
+ u32 rsvd2[22];
+ u32 pgcnt; /* Page counter */
+ u32 rsvd3;
+ u32 hf_ctrl; /* Half duplex control */
+ u32 tx_ctrl; /* Transmit control */
+ u32 rsvd4;
+ u32 vlcos0; /* VLAN insertion config CoS 0 */
+ u32 vlcos1; /* VLAN insertion config CoS 1 */
+ u32 vlcos2; /* VLAN insertion config CoS 2 */
+ u32 vlcos3; /* VLAN insertion config CoS 3 */
+ u32 eg_col; /* Total egress collision frames */
+ u32 eg_drop; /* Total egress drop frames */
+};
+
+struct ltq_eth_priv {
+ struct ltq_dma_device dma_dev;
+ struct mii_dev *bus;
+ struct eth_device *dev;
+ int rx_num;
+ int tx_num;
+};
+
+struct ltq_mdio_access {
+ union {
+ struct {
+ unsigned ra:1;
+ unsigned rw:1;
+ unsigned rsvd:4;
+ unsigned phya:5;
+ unsigned rega:5;
+ unsigned phyd:16;
+ } reg;
+ u32 val;
+ };
+};
+
+static struct ltq_ppe_etop_regs *ltq_ppe_etop_regs =
+ (struct ltq_ppe_etop_regs *) CKSEG1ADDR(LTQ_PPE_ETOP_BASE);
+
+static struct ltq_ppe_enet_regs *ltq_ppe_enet0_regs =
+ (struct ltq_ppe_enet_regs *) CKSEG1ADDR(LTQ_PPE_ENET0_BASE);
+
+static inline int ltq_mdio_poll(void)
+{
+ struct ltq_mdio_access acc;
+ unsigned cnt = 10000;
+
+ while (likely(cnt--)) {
+ acc.val = ltq_readl(&ltq_ppe_etop_regs->mdio_acc);
+ if (!acc.reg.ra)
+ return 0;
+ }
+
+ return 1;
+}
+
+static int ltq_mdio_read(struct mii_dev *bus, int addr, int dev_addr,
+ int regnum)
+{
+ struct ltq_mdio_access acc;
+ int ret;
+
+ acc.val = 0;
+ acc.reg.ra = 1;
+ acc.reg.rw = 1;
+ acc.reg.phya = addr;
+ acc.reg.rega = regnum;
+
+ ret = ltq_mdio_poll();
+ if (ret)
+ return ret;
+
+ ltq_writel(&ltq_ppe_etop_regs->mdio_acc, acc.val);
+
+ ret = ltq_mdio_poll();
+ if (ret)
+ return ret;
+
+ acc.val = ltq_readl(&ltq_ppe_etop_regs->mdio_acc);
+
+ return acc.reg.phyd;
+}
+
+static int ltq_mdio_write(struct mii_dev *bus, int addr, int dev_addr,
+ int regnum, u16 val)
+{
+ struct ltq_mdio_access acc;
+ int ret;
+
+ acc.val = 0;
+ acc.reg.ra = 1;
+ acc.reg.rw = 0;
+ acc.reg.phya = addr;
+ acc.reg.rega = regnum;
+ acc.reg.phyd = val;
+
+ ret = ltq_mdio_poll();
+ if (ret)
+ return ret;
+
+ ltq_writel(&ltq_ppe_etop_regs->mdio_acc, acc.val);
+
+ return 0;
+}
+
+static inline void ltq_eth_write_hwaddr(const struct eth_device *dev)
+{
+ u32 da0, da1;
+
+ da0 = (dev->enetaddr[0] << 24) + (dev->enetaddr[1] << 16) +
+ (dev->enetaddr[2] << 8) + dev->enetaddr[3];
+ da1 = (dev->enetaddr[4] << 24) + (dev->enetaddr[5] << 16);
+
+ ltq_writel(&ltq_ppe_enet0_regs->mac_da0, da0);
+ ltq_writel(&ltq_ppe_enet0_regs->mac_da1, da1);
+}
+
+static inline u8 *ltq_eth_rx_packet_align(int rx_num)
+{
+ u8 *packet = (u8 *) NetRxPackets[rx_num];
+
+ /*
+ * IP header needs
+ */
+ return packet + LTQ_ETH_IP_ALIGN;
+}
+
+static int ltq_eth_init(struct eth_device *dev, bd_t *bis)
+{
+ struct ltq_eth_priv *priv = dev->priv;
+ struct ltq_dma_device *dma_dev = &priv->dma_dev;
+ int i;
+
+ ltq_eth_write_hwaddr(dev);
+
+ for (i = 0; i < LTQ_ETH_RX_BUFFER_CNT; i++)
+ ltq_dma_rx_map(dma_dev, i, ltq_eth_rx_packet_align(i),
+ LTQ_ETH_RX_DATA_SIZE);
+
+ ltq_dma_enable(dma_dev);
+
+ priv->rx_num = 0;
+ priv->tx_num = 0;
+
+ return 0;
+}
+
+static void ltq_eth_halt(struct eth_device *dev)
+{
+ struct ltq_eth_priv *priv = dev->priv;
+ struct ltq_dma_device *dma_dev = &priv->dma_dev;
+
+ ltq_dma_reset(dma_dev);
+}
+
+static int ltq_eth_send(struct eth_device *dev, void *packet, int length)
+{
+ struct ltq_eth_priv *priv = dev->priv;
+ struct ltq_dma_device *dma_dev = &priv->dma_dev;
+ int err;
+
+ /* Minimum payload length w/ CRC is 60 bytes */
+ if (length < 60)
+ length = 60;
+
+ err = ltq_dma_tx_map(dma_dev, priv->tx_num, packet, length, 10);
+ if (err) {
+ puts("NET: timeout on waiting for TX descriptor\n");
+ return -1;
+ }
+
+ priv->tx_num = (priv->tx_num + 1) % LTQ_ETH_TX_BUFFER_CNT;
+
+ return err;
+}
+
+static int ltq_eth_recv(struct eth_device *dev)
+{
+ struct ltq_eth_priv *priv = dev->priv;
+ struct ltq_dma_device *dma_dev = &priv->dma_dev;
+ u8 *packet;
+ int len;
+
+ if (!ltq_dma_rx_poll(dma_dev, priv->rx_num))
+ return 0;
+
+#if 0
+ printf("%s: rx_num %d\n", __func__, priv->rx_num);
+#endif
+
+ len = ltq_dma_rx_length(dma_dev, priv->rx_num);
+ packet = ltq_eth_rx_packet_align(priv->rx_num);
+
+#if 0
+ printf("%s: received: packet %p, len %u, rx_num %d\n",
+ __func__, packet, len, priv->rx_num);
+#endif
+
+ if (len)
+ NetReceive(packet, len);
+
+ ltq_dma_rx_map(dma_dev, priv->rx_num, packet,
+ LTQ_ETH_RX_DATA_SIZE);
+
+ priv->rx_num = (priv->rx_num + 1) % LTQ_ETH_RX_BUFFER_CNT;
+
+ return 0;
+}
+
+static void ltq_eth_hw_init(const struct ltq_eth_port_config *port)
+{
+ u32 data;
+
+ /* Power up ethernet subsystems */
+ ltq_pm_enable(LTQ_PM_ETH);
+
+ /* Reset ethernet subsystems */
+ ltq_reset_once(LTQ_RESET_ETH, 1);
+
+ /* Disable MDIO auto-detection */
+ ltq_clrbits(&ltq_ppe_etop_regs->mdio_cfg, LTQ_PPE_ETOP_MDIO_CFG_UMM1 |
+ LTQ_PPE_ETOP_MDIO_CFG_UMM0);
+
+ /* Enable CRC generation, Full Duplex, 100Mbps, Link up */
+ ltq_writel(&ltq_ppe_enet0_regs->mac_cfg, LTQ_PPE_ENET0_MAC_CFG_CGEN |
+ LTQ_PPE_ENET0_MAC_CFG_DUPLEX |
+ LTQ_PPE_ENET0_MAC_CFG_SPEED |
+ LTQ_PPE_ENET0_MAC_CFG_LINK);
+
+ /* Reset ETOP cfg and disable all */
+ data = LTQ_PPE_ETOP_CFG_OFF0 | LTQ_PPE_ETOP_CFG_OFF1;
+
+ /* Enable ENET0, enable store and fetch */
+ data &= ~LTQ_PPE_ETOP_CFG_OFF0;
+ data |= LTQ_PPE_ETOP_CFG_SEN0 | LTQ_PPE_ETOP_CFG_FEN0;
+
+ if (port->phy_if == PHY_INTERFACE_MODE_RMII)
+ data |= LTQ_PPE_ETOP_CFG_REMII0;
+ else
+ data &= ~LTQ_PPE_ETOP_CFG_REMII0;
+
+ ltq_writel(&ltq_ppe_etop_regs->cfg, data);
+
+ /* Set allowed packet length from 64 bytes to 1518 bytes */
+ ltq_writel(&ltq_ppe_etop_regs->ig_plen_ctrl, (64 << 16) | 1518);
+
+ /* Enable filter for unicast packets */
+ ltq_setbits(&ltq_ppe_enet0_regs->ig_cfg, LTQ_PPE_ENETS0_CFG_FTUC);
+}
+
+int ltq_eth_initialize(const struct ltq_eth_board_config *board_config)
+{
+ struct eth_device *dev;
+ struct mii_dev *bus;
+ struct ltq_eth_priv *priv;
+ struct ltq_dma_device *dma_dev;
+ const struct ltq_eth_port_config *port = &board_config->ports[0];
+ struct phy_device *phy;
+ struct switch_device *sw;
+ int ret;
+
+ ltq_dma_init();
+ ltq_eth_hw_init(port);
+
+ dev = calloc(1, sizeof(*dev));
+ if (!dev)
+ return -1;
+
+ priv = calloc(1, sizeof(*priv));
+ if (!priv)
+ return -1;
+
+ bus = mdio_alloc();
+ if (!bus)
+ return -1;
+
+ sprintf(dev->name, LTQ_ETH_DRV_NAME);
+ dev->priv = priv;
+ dev->init = ltq_eth_init;
+ dev->halt = ltq_eth_halt;
+ dev->recv = ltq_eth_recv;
+ dev->send = ltq_eth_send;
+
+ sprintf(bus->name, LTQ_MDIO_DRV_NAME);
+ bus->read = ltq_mdio_read;
+ bus->write = ltq_mdio_write;
+ bus->priv = priv;
+
+ dma_dev = &priv->dma_dev;
+ dma_dev->port = 0;
+ dma_dev->rx_chan.chan_no = 6;
+ dma_dev->rx_chan.class = 3;
+ dma_dev->rx_chan.num_desc = LTQ_ETH_RX_BUFFER_CNT;
+ dma_dev->rx_endian_swap = LTQ_DMA_ENDIANESS_B3_B2_B1_B0;
+ dma_dev->rx_burst_len = LTQ_DMA_BURST_2WORDS;
+ dma_dev->tx_chan.chan_no = 7;
+ dma_dev->tx_chan.class = 3;
+ dma_dev->tx_chan.num_desc = LTQ_ETH_TX_BUFFER_CNT;
+ dma_dev->tx_endian_swap = LTQ_DMA_ENDIANESS_B3_B2_B1_B0;
+ dma_dev->tx_burst_len = LTQ_DMA_BURST_2WORDS;
+
+ priv->bus = bus;
+ priv->dev = dev;
+
+ ret = ltq_dma_register(dma_dev);
+ if (ret)
+ return ret;
+
+ ret = mdio_register(bus);
+ if (ret)
+ return ret;
+
+ ret = eth_register(dev);
+ if (ret)
+ return ret;
+
+ if (port->flags & LTQ_ETH_PORT_SWITCH) {
+ sw = switch_connect(bus);
+ if (!sw)
+ return -1;
+
+ switch_setup(sw);
+ }
+
+ if (port->flags & LTQ_ETH_PORT_PHY) {
+ phy = phy_connect(bus, port->phy_addr, dev, port->phy_if);
+ if (!phy)
+ return -1;
+
+ phy_config(phy);
+ }
+
+ return 0;
+}
--- /dev/null
+++ b/drivers/net/lantiq_vrx200_switch.c
@@ -0,0 +1,675 @@
+/*
+ * Copyright (C) 2010-2011 Lantiq Deutschland GmbH
+ * Copyright (C) 2011-2013 Daniel Schwierzeck, daniel.schwierzeck@gmail.com
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#define DEBUG
+
+#include <common.h>
+#include <malloc.h>
+#include <netdev.h>
+#include <miiphy.h>
+#include <linux/compiler.h>
+#include <asm/gpio.h>
+#include <asm/processor.h>
+#include <asm/lantiq/io.h>
+#include <asm/lantiq/eth.h>
+#include <asm/lantiq/pm.h>
+#include <asm/lantiq/reset.h>
+#include <asm/lantiq/dma.h>
+#include <asm/arch/soc.h>
+#include <asm/arch/switch.h>
+
+#define LTQ_ETH_RX_BUFFER_CNT PKTBUFSRX
+#define LTQ_ETH_TX_BUFFER_CNT 8
+#define LTQ_ETH_RX_DATA_SIZE PKTSIZE_ALIGN
+#define LTQ_ETH_IP_ALIGN 2
+
+#define LTQ_MDIO_DRV_NAME "ltq-mdio"
+#define LTQ_ETH_DRV_NAME "ltq-eth"
+
+#define LTQ_ETHSW_MAX_GMAC 6
+#define LTQ_ETHSW_PMAC 6
+
+struct ltq_mdio_phy_addr_reg {
+ union {
+ struct {
+ unsigned rsvd:1;
+ unsigned lnkst:2; /* Link status control */
+ unsigned speed:2; /* Speed control */
+ unsigned fdup:2; /* Full duplex control */
+ unsigned fcontx:2; /* Flow control mode TX */
+ unsigned fconrx:2; /* Flow control mode RX */
+ unsigned addr:5; /* PHY address */
+ } bits;
+ u16 val;
+ };
+};
+
+enum ltq_mdio_phy_addr_lnkst {
+ LTQ_MDIO_PHY_ADDR_LNKST_AUTO = 0,
+ LTQ_MDIO_PHY_ADDR_LNKST_UP = 1,
+ LTQ_MDIO_PHY_ADDR_LNKST_DOWN = 2,
+};
+
+enum ltq_mdio_phy_addr_speed {
+ LTQ_MDIO_PHY_ADDR_SPEED_M10 = 0,
+ LTQ_MDIO_PHY_ADDR_SPEED_M100 = 1,
+ LTQ_MDIO_PHY_ADDR_SPEED_G1 = 2,
+ LTQ_MDIO_PHY_ADDR_SPEED_AUTO = 3,
+};
+
+enum ltq_mdio_phy_addr_fdup {
+ LTQ_MDIO_PHY_ADDR_FDUP_AUTO = 0,
+ LTQ_MDIO_PHY_ADDR_FDUP_ENABLE = 1,
+ LTQ_MDIO_PHY_ADDR_FDUP_DISABLE = 3,
+};
+
+enum ltq_mdio_phy_addr_fcon {
+ LTQ_MDIO_PHY_ADDR_FCON_AUTO = 0,
+ LTQ_MDIO_PHY_ADDR_FCON_ENABLE = 1,
+ LTQ_MDIO_PHY_ADDR_FCON_DISABLE = 3,
+};
+
+struct ltq_mii_mii_cfg_reg {
+ union {
+ struct {
+ unsigned res:1; /* Hardware reset */
+ unsigned en:1; /* xMII interface enable */
+ unsigned isol:1; /* xMII interface isolate */
+ unsigned ldclkdis:1; /* Link down clock disable */
+ unsigned rsvd:1;
+ unsigned crs:2; /* CRS sensitivity config */
+ unsigned rgmii_ibs:1; /* RGMII In Band status */
+ unsigned rmii:1; /* RMII ref clock direction */
+ unsigned miirate:3; /* xMII interface clock rate */
+ unsigned miimode:4; /* xMII interface mode */
+ } bits;
+ u16 val;
+ };
+};
+
+enum ltq_mii_mii_cfg_miirate {
+ LTQ_MII_MII_CFG_MIIRATE_M2P5 = 0,
+ LTQ_MII_MII_CFG_MIIRATE_M25 = 1,
+ LTQ_MII_MII_CFG_MIIRATE_M125 = 2,
+ LTQ_MII_MII_CFG_MIIRATE_M50 = 3,
+ LTQ_MII_MII_CFG_MIIRATE_AUTO = 4,
+};
+
+enum ltq_mii_mii_cfg_miimode {
+ LTQ_MII_MII_CFG_MIIMODE_MIIP = 0,
+ LTQ_MII_MII_CFG_MIIMODE_MIIM = 1,
+ LTQ_MII_MII_CFG_MIIMODE_RMIIP = 2,
+ LTQ_MII_MII_CFG_MIIMODE_RMIIM = 3,
+ LTQ_MII_MII_CFG_MIIMODE_RGMII = 4,
+};
+
+struct ltq_eth_priv {
+ struct ltq_dma_device dma_dev;
+ struct mii_dev *bus;
+ struct eth_device *dev;
+ struct phy_device *phymap[LTQ_ETHSW_MAX_GMAC];
+ int rx_num;
+ int tx_num;
+};
+
+static struct vr9_switch_regs *switch_regs =
+ (struct vr9_switch_regs *) CKSEG1ADDR(LTQ_SWITCH_BASE);
+
+static inline void vr9_switch_sync(void)
+{
+ __asm__("sync");
+}
+
+static inline int vr9_switch_mdio_is_busy(void)
+{
+ u32 mdio_ctrl = ltq_readl(&switch_regs->mdio.mdio_ctrl);
+
+ return mdio_ctrl & MDIO_CTRL_MBUSY;
+}
+
+static inline void vr9_switch_mdio_poll(void)
+{
+ while (vr9_switch_mdio_is_busy())
+ cpu_relax();
+}
+
+static int vr9_switch_mdio_read(struct mii_dev *bus, int phyad, int devad,
+ int regad)
+{
+ u32 mdio_ctrl;
+ int retval;
+
+ mdio_ctrl = MDIO_CTRL_OP_READ |
+ ((phyad << MDIO_CTRL_PHYAD_SHIFT) & MDIO_CTRL_PHYAD_MASK) |
+ (regad & MDIO_CTRL_REGAD_MASK);
+
+ vr9_switch_mdio_poll();
+ ltq_writel(&switch_regs->mdio.mdio_ctrl, mdio_ctrl);
+ vr9_switch_mdio_poll();
+ retval = ltq_readl(&switch_regs->mdio.mdio_read);
+
+ return retval;
+}
+
+static int vr9_switch_mdio_write(struct mii_dev *bus, int phyad, int devad,
+ int regad, u16 val)
+{
+ u32 mdio_ctrl;
+
+ mdio_ctrl = MDIO_CTRL_OP_WRITE |
+ ((phyad << MDIO_CTRL_PHYAD_SHIFT) & MDIO_CTRL_PHYAD_MASK) |
+ (regad & MDIO_CTRL_REGAD_MASK);
+
+ vr9_switch_mdio_poll();
+ ltq_writel(&switch_regs->mdio.mdio_write, val);
+ ltq_writel(&switch_regs->mdio.mdio_ctrl, mdio_ctrl);
+
+ return 0;
+}
+
+static void ltq_eth_gmac_update(struct phy_device *phydev, int num)
+{
+ struct ltq_mdio_phy_addr_reg phy_addr_reg;
+ struct ltq_mii_mii_cfg_reg mii_cfg_reg;
+
+ phy_addr_reg.val = ltq_readl(to_mdio_phyaddr(switch_regs, num));
+
+ switch (num) {
+ case 0:
+ case 1:
+ case 5:
+ mii_cfg_reg.val = ltq_readl(to_mii_miicfg(switch_regs, num));
+ break;
+ default:
+ mii_cfg_reg.val = 0;
+ break;
+ }
+
+ phy_addr_reg.bits.addr = phydev->addr;
+
+ if (phydev->link)
+ phy_addr_reg.bits.lnkst = LTQ_MDIO_PHY_ADDR_LNKST_UP;
+ else
+ phy_addr_reg.bits.lnkst = LTQ_MDIO_PHY_ADDR_LNKST_DOWN;
+
+ switch (phydev->speed) {
+ case SPEED_1000:
+ phy_addr_reg.bits.speed = LTQ_MDIO_PHY_ADDR_SPEED_G1;
+ mii_cfg_reg.bits.miirate = LTQ_MII_MII_CFG_MIIRATE_M125;
+ break;
+ case SPEED_100:
+ phy_addr_reg.bits.speed = LTQ_MDIO_PHY_ADDR_SPEED_M100;
+ switch (mii_cfg_reg.bits.miimode) {
+ case LTQ_MII_MII_CFG_MIIMODE_RMIIM:
+ case LTQ_MII_MII_CFG_MIIMODE_RMIIP:
+ mii_cfg_reg.bits.miirate = LTQ_MII_MII_CFG_MIIRATE_M50;
+ break;
+ default:
+ mii_cfg_reg.bits.miirate = LTQ_MII_MII_CFG_MIIRATE_M25;
+ break;
+ }
+ break;
+ default:
+ phy_addr_reg.bits.speed = LTQ_MDIO_PHY_ADDR_SPEED_M10;
+ mii_cfg_reg.bits.miirate = LTQ_MII_MII_CFG_MIIRATE_M2P5;
+ break;
+ }
+
+ if (phydev->duplex == DUPLEX_FULL)
+ phy_addr_reg.bits.fdup = LTQ_MDIO_PHY_ADDR_FDUP_ENABLE;
+ else
+ phy_addr_reg.bits.fdup = LTQ_MDIO_PHY_ADDR_FDUP_DISABLE;
+
+ ltq_writel(to_mdio_phyaddr(switch_regs, num), phy_addr_reg.val);
+
+ switch (num) {
+ case 0:
+ case 1:
+ case 5:
+ ltq_writel(to_mii_miicfg(switch_regs, num), mii_cfg_reg.val);
+ break;
+ default:
+ break;
+ }
+}
+
+static inline u8 *ltq_eth_rx_packet_align(int rx_num)
+{
+ u8 *packet = (u8 *) NetRxPackets[rx_num];
+
+ /*
+ * IP header needs
+ */
+ return packet + LTQ_ETH_IP_ALIGN;
+}
+
+static int ltq_eth_init(struct eth_device *dev, bd_t *bis)
+{
+ struct ltq_eth_priv *priv = dev->priv;
+ struct ltq_dma_device *dma_dev = &priv->dma_dev;
+ struct phy_device *phydev;
+ int i;
+
+ for (i = 0; i < LTQ_ETHSW_MAX_GMAC; i++) {
+ phydev = priv->phymap[i];
+ if (!phydev)
+ continue;
+
+ phy_startup(phydev);
+ ltq_eth_gmac_update(phydev, i);
+ }
+
+ for (i = 0; i < LTQ_ETH_RX_BUFFER_CNT; i++)
+ ltq_dma_rx_map(dma_dev, i, ltq_eth_rx_packet_align(i),
+ LTQ_ETH_RX_DATA_SIZE);
+
+ ltq_dma_enable(dma_dev);
+
+ priv->rx_num = 0;
+ priv->tx_num = 0;
+
+ return 0;
+}
+
+static void ltq_eth_halt(struct eth_device *dev)
+{
+ struct ltq_eth_priv *priv = dev->priv;
+ struct ltq_dma_device *dma_dev = &priv->dma_dev;
+ struct phy_device *phydev;
+ int i;
+
+ ltq_dma_reset(dma_dev);
+
+ for (i = 0; i < LTQ_ETHSW_MAX_GMAC; i++) {
+ phydev = priv->phymap[i];
+ if (!phydev)
+ continue;
+
+ phy_shutdown(phydev);
+ phydev->link = 0;
+ ltq_eth_gmac_update(phydev, i);
+ }
+}
+
+static int ltq_eth_send(struct eth_device *dev, void *packet, int length)
+{
+ struct ltq_eth_priv *priv = dev->priv;
+ struct ltq_dma_device *dma_dev = &priv->dma_dev;
+
+#if 0
+ printf("%s: packet %p, len %d\n", __func__, packet, length);
+#endif
+
+ ltq_dma_tx_map(dma_dev, priv->tx_num, packet, length, 10);
+ priv->tx_num = (priv->tx_num + 1) % LTQ_ETH_TX_BUFFER_CNT;
+
+ return 0;
+}
+
+static int ltq_eth_recv(struct eth_device *dev)
+{
+ struct ltq_eth_priv *priv = dev->priv;
+ struct ltq_dma_device *dma_dev = &priv->dma_dev;
+ u8 *packet;
+ int len;
+
+ if (!ltq_dma_rx_poll(dma_dev, priv->rx_num))
+ return 0;
+
+#if 0
+ printf("%s: rx_num %d\n", __func__, priv->rx_num);
+#endif
+
+ len = ltq_dma_rx_length(dma_dev, priv->rx_num);
+ packet = ltq_eth_rx_packet_align(priv->rx_num);
+
+#if 0
+ printf("%s: received: packet %p, len %u, rx_num %d\n",
+ __func__, packet, len, priv->rx_num);
+#endif
+
+ if (len)
+ NetReceive(packet, len);
+
+ ltq_dma_rx_map(dma_dev, priv->rx_num, packet,
+ LTQ_ETH_RX_DATA_SIZE);
+
+ priv->rx_num = (priv->rx_num + 1) % LTQ_ETH_RX_BUFFER_CNT;
+
+ return 0;
+}
+
+static void ltq_eth_gmac_init(int num)
+{
+ struct ltq_mdio_phy_addr_reg phy_addr_reg;
+ struct ltq_mii_mii_cfg_reg mii_cfg_reg;
+
+ /* Reset PHY status to link down */
+ phy_addr_reg.val = ltq_readl(to_mdio_phyaddr(switch_regs, num));
+ phy_addr_reg.bits.addr = num;
+ phy_addr_reg.bits.lnkst = LTQ_MDIO_PHY_ADDR_LNKST_DOWN;
+ phy_addr_reg.bits.speed = LTQ_MDIO_PHY_ADDR_SPEED_M10;
+ phy_addr_reg.bits.fdup = LTQ_MDIO_PHY_ADDR_FDUP_DISABLE;
+ ltq_writel(to_mdio_phyaddr(switch_regs, num), phy_addr_reg.val);
+
+ /* Reset and disable MII interface */
+ switch (num) {
+ case 0:
+ case 1:
+ case 5:
+ mii_cfg_reg.val = ltq_readl(to_mii_miicfg(switch_regs, num));
+ mii_cfg_reg.bits.en = 0;
+ mii_cfg_reg.bits.res = 1;
+ mii_cfg_reg.bits.miirate = LTQ_MII_MII_CFG_MIIRATE_M2P5;
+ ltq_writel(to_mii_miicfg(switch_regs, num), mii_cfg_reg.val);
+ break;
+ default:
+ break;
+ }
+
+ /*
+ * - enable frame checksum generation
+ * - enable padding of short frames
+ * - disable flow control
+ */
+ ltq_writel(to_mac_ctrl(switch_regs, num, 0),
+ MAC_CTRL0_PADEN | MAC_CTRL0_FCS | MAC_CTRL0_FCON_NONE);
+
+ vr9_switch_sync();
+}
+
+static void ltq_eth_pmac_init(void)
+{
+ /*
+ * WAR: buffer congestion:
+ * - shorten preambel to 1 byte
+ * - set TX IPG to 7 bytes
+ */
+#if 1
+ ltq_writel(to_mac_ctrl(switch_regs, LTQ_ETHSW_PMAC, 1),
+ MAC_CTRL1_SHORTPRE | 7);
+#endif
+
+ /*
+ * WAR: systematical concept weakness ACM bug
+ * - set maximum number of used buffer segments to 254
+ * - soft-reset BM FSQM
+ */
+#if 1
+ ltq_writel(&switch_regs->bm.core.fsqm_gctrl, 253);
+ ltq_setbits(&switch_regs->bm.core.gctrl, BM_GCTRL_F_SRES);
+ ltq_clrbits(&switch_regs->bm.core.gctrl, BM_GCTRL_F_SRES);
+#endif
+
+ /*
+ * WAR: switch MAC drop bug
+ */
+#if 1
+ ltq_writel(to_pce_tbl_key(switch_regs, 0), 0xf);
+ ltq_writel(to_pce_tbl_value(switch_regs, 0), 0x40);
+ ltq_writel(&switch_regs->pce.core.tbl_addr, 0x3);
+ ltq_writel(&switch_regs->pce.core.tbl_ctrl, 0x902f);
+#endif
+
+ /*
+ * Configure frame header control:
+ * - enable flow control
+ * - enable CRC check for packets from DMA to PMAC
+ * - remove special tag from packets from PMAC to DMA
+ * - add CRC for packets from DMA to PMAC
+ */
+ ltq_writel(&switch_regs->pmac.hd_ctl, /*PMAC_HD_CTL_FC |*/
+ PMAC_HD_CTL_CCRC | PMAC_HD_CTL_RST | PMAC_HD_CTL_AC |
+ PMAC_HD_CTL_RC);
+
+#if 1
+ ltq_writel(&switch_regs->pmac.rx_ipg, 0x8b);
+#endif
+
+ /*
+ * - enable frame checksum generation
+ * - enable padding of short frames
+ * - disable flow control
+ */
+ ltq_writel(to_mac_ctrl(switch_regs, LTQ_ETHSW_PMAC, 0),
+ MAC_CTRL0_PADEN | MAC_CTRL0_FCS | MAC_CTRL0_FCON_NONE);
+
+ vr9_switch_sync();
+}
+
+static void ltq_eth_hw_init(void)
+{
+ int i;
+
+ /* Power up ethernet and switch subsystems */
+ ltq_pm_enable(LTQ_PM_ETH);
+
+ /* Reset ethernet and switch subsystems */
+#if 0
+ ltq_reset_once(LTQ_RESET_ETH, 10);
+#endif
+
+ /* Enable switch macro */
+ ltq_setbits(&switch_regs->mdio.glob_ctrl, MDIO_GLOB_CTRL_SE);
+
+ /* Disable MDIO auto-polling for all ports */
+ ltq_writel(&switch_regs->mdio.mdc_cfg_0, 0);
+
+ /*
+ * Enable and set MDIO management clock to 2.5 MHz. This is the
+ * maximum clock for FE PHYs.
+ * Formula for clock is:
+ *
+ * 50 MHz
+ * x = ----------- - 1
+ * 2 * f_MDC
+ */
+ ltq_writel(&switch_regs->mdio.mdc_cfg_1, MDIO_MDC_CFG1_RES |
+ MDIO_MDC_CFG1_MCEN | 5);
+
+ vr9_switch_sync();
+
+ /* Init MAC connected to CPU */
+ ltq_eth_pmac_init();
+
+ /* Init MACs connected to external MII interfaces */
+ for (i = 0; i < LTQ_ETHSW_MAX_GMAC; i++)
+ ltq_eth_gmac_init(i);
+}
+
+static void ltq_eth_port_config(struct ltq_eth_priv *priv,
+ const struct ltq_eth_port_config *port)
+{
+ struct ltq_mii_mii_cfg_reg mii_cfg_reg;
+ struct phy_device *phydev;
+ int setup_gpio = 0;
+
+ switch (port->num) {
+ case 0: /* xMII0 */
+ case 1: /* xMII1 */
+ mii_cfg_reg.val = ltq_readl(to_mii_miicfg(switch_regs,
+ port->num));
+ mii_cfg_reg.bits.en = port->flags ? 1 : 0;
+
+ switch (port->phy_if) {
+ case PHY_INTERFACE_MODE_MII:
+ if (port->flags & LTQ_ETH_PORT_PHY)
+ /* MII MAC mode, connected to external PHY */
+ mii_cfg_reg.bits.miimode =
+ LTQ_MII_MII_CFG_MIIMODE_MIIM;
+ else
+ /* MII PHY mode, connected to external MAC */
+ mii_cfg_reg.bits.miimode =
+ LTQ_MII_MII_CFG_MIIMODE_MIIP;
+ setup_gpio = 1;
+ break;
+ case PHY_INTERFACE_MODE_RMII:
+ if (port->flags & LTQ_ETH_PORT_PHY)
+ /* RMII MAC mode, connected to external PHY */
+ mii_cfg_reg.bits.miimode =
+ LTQ_MII_MII_CFG_MIIMODE_RMIIM;
+ else
+ /* RMII PHY mode, connected to external MAC */
+ mii_cfg_reg.bits.miimode =
+ LTQ_MII_MII_CFG_MIIMODE_RMIIP;
+ setup_gpio = 1;
+ break;
+ case PHY_INTERFACE_MODE_RGMII:
+ /* RGMII MAC mode, connected to external PHY */
+ mii_cfg_reg.bits.miimode =
+ LTQ_MII_MII_CFG_MIIMODE_RGMII;
+ setup_gpio = 1;
+
+ /* RGMII clock delays */
+ ltq_writel(to_mii_pcdu(switch_regs, port->num),
+ port->rgmii_rx_delay << PCDU_RXDLY_SHIFT |
+ port->rgmii_tx_delay);
+ break;
+ default:
+ break;
+ }
+
+ ltq_writel(to_mii_miicfg(switch_regs, port->num),
+ mii_cfg_reg.val);
+ break;
+ case 2: /* internal GPHY0 */
+ case 3: /* internal GPHY0 */
+ case 4: /* internal GPHY1 */
+ switch (port->phy_if) {
+ case PHY_INTERFACE_MODE_MII:
+ case PHY_INTERFACE_MODE_GMII:
+ setup_gpio = 1;
+ break;
+ default:
+ break;
+ }
+ break;
+ case 5: /* internal GPHY1 or xMII2 */
+ mii_cfg_reg.val = ltq_readl(to_mii_miicfg(switch_regs,
+ port->num));
+ mii_cfg_reg.bits.en = port->flags ? 1 : 0;
+
+ switch (port->phy_if) {
+ case PHY_INTERFACE_MODE_MII:
+ /* MII MAC mode, connected to internal GPHY */
+ mii_cfg_reg.bits.miimode =
+ LTQ_MII_MII_CFG_MIIMODE_MIIM;
+ setup_gpio = 1;
+ break;
+ case PHY_INTERFACE_MODE_RGMII:
+ /* RGMII MAC mode, connected to external PHY */
+ mii_cfg_reg.bits.miimode =
+ LTQ_MII_MII_CFG_MIIMODE_RGMII;
+ setup_gpio = 1;
+
+ /* RGMII clock delays */
+ ltq_writel(to_mii_pcdu(switch_regs, port->num),
+ port->rgmii_rx_delay << PCDU_RXDLY_SHIFT |
+ port->rgmii_tx_delay);
+ break;
+ default:
+ break;
+ }
+
+ ltq_writel(to_mii_miicfg(switch_regs, port->num),
+ mii_cfg_reg.val);
+ break;
+ default:
+ break;
+ }
+
+ /* Setup GPIOs for MII with external PHYs/MACs */
+ if (setup_gpio) {
+ /* MII/MDIO */
+ gpio_set_altfunc(42, GPIO_ALTSEL_SET, GPIO_ALTSEL_CLR,
+ GPIO_DIR_OUT);
+ /* MII/MDC */
+ gpio_set_altfunc(43, GPIO_ALTSEL_SET, GPIO_ALTSEL_CLR,
+ GPIO_DIR_OUT);
+ }
+
+ /* Connect to internal/external PHYs */
+ if (port->flags & LTQ_ETH_PORT_PHY) {
+ phydev = phy_connect(priv->bus, port->phy_addr, priv->dev,
+ port->phy_if);
+ if (phydev)
+ phy_config(phydev);
+
+ priv->phymap[port->num] = phydev;
+ }
+}
+
+int ltq_eth_initialize(const struct ltq_eth_board_config *board_config)
+{
+ struct eth_device *dev;
+ struct mii_dev *bus;
+ struct ltq_eth_priv *priv;
+ struct ltq_dma_device *dma_dev;
+ int i, ret;
+
+ build_check_vr9_registers();
+
+ ltq_dma_init();
+ ltq_eth_hw_init();
+
+ dev = calloc(1, sizeof(struct eth_device));
+ if (!dev)
+ return -1;
+
+ priv = calloc(1, sizeof(struct ltq_eth_priv));
+ if (!priv)
+ return -1;
+
+ bus = mdio_alloc();
+ if (!bus)
+ return -1;
+
+ sprintf(dev->name, LTQ_ETH_DRV_NAME);
+ dev->priv = priv;
+ dev->init = ltq_eth_init;
+ dev->halt = ltq_eth_halt;
+ dev->recv = ltq_eth_recv;
+ dev->send = ltq_eth_send;
+
+ sprintf(bus->name, LTQ_MDIO_DRV_NAME);
+ bus->read = vr9_switch_mdio_read;
+ bus->write = vr9_switch_mdio_write;
+ bus->priv = priv;
+
+ dma_dev = &priv->dma_dev;
+ dma_dev->port = 0;
+ dma_dev->rx_chan.chan_no = 0;
+ dma_dev->rx_chan.class = 0;
+ dma_dev->rx_chan.num_desc = LTQ_ETH_RX_BUFFER_CNT;
+ dma_dev->rx_endian_swap = LTQ_DMA_ENDIANESS_B3_B2_B1_B0;
+ dma_dev->rx_burst_len = LTQ_DMA_BURST_2WORDS;
+ dma_dev->tx_chan.chan_no = 1;
+ dma_dev->tx_chan.class = 0;
+ dma_dev->tx_chan.num_desc = LTQ_ETH_TX_BUFFER_CNT;
+ dma_dev->tx_endian_swap = LTQ_DMA_ENDIANESS_B3_B2_B1_B0;
+ dma_dev->tx_burst_len = LTQ_DMA_BURST_2WORDS;
+
+ priv->bus = bus;
+ priv->dev = dev;
+
+ ret = ltq_dma_register(dma_dev);
+ if (ret)
+ return -1;
+
+ ret = mdio_register(bus);
+ if (ret)
+ return -1;
+
+ ret = eth_register(dev);
+ if (ret)
+ return -1;
+
+ for (i = 0; i < board_config->num_ports; i++)
+ ltq_eth_port_config(priv, &board_config->ports[i]);
+
+ return 0;
+}
--- a/drivers/net/phy/Makefile
+++ b/drivers/net/phy/Makefile
@@ -20,6 +20,7 @@ COBJS-$(CONFIG_PHY_BROADCOM) += broadcom
COBJS-$(CONFIG_PHY_DAVICOM) += davicom.o
COBJS-$(CONFIG_PHY_ET1011C) += et1011c.o
COBJS-$(CONFIG_PHY_ICPLUS) += icplus.o
+COBJS-$(CONFIG_PHY_LANTIQ) += lantiq.o
COBJS-$(CONFIG_PHY_LXT) += lxt.o
COBJS-$(CONFIG_PHY_MARVELL) += marvell.o
COBJS-$(CONFIG_PHY_MICREL) += micrel.o
--- /dev/null
+++ b/drivers/net/phy/lantiq.c
@@ -0,0 +1,238 @@
+/*
+ * Copyright (C) 2011-2013 Daniel Schwierzeck, daniel.schwierzeck@gmail.com
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#define DEBUG
+
+#include <common.h>
+#include <miiphy.h>
+
+#define ADVERTIZE_MPD (1 << 10)
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/*
+ * Update link status.
+ *
+ * Based on genphy_update_link in phylib.c
+ */
+static int ltq_phy_update_link(struct phy_device *phydev)
+{
+ unsigned int mii_reg;
+
+ mii_reg = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMSR);
+
+ /*
+ * If we already saw the link up, and it hasn't gone down, then
+ * we don't need to wait for autoneg again
+ */
+ if (phydev->link && mii_reg & BMSR_LSTATUS)
+ return 0;
+
+ if ((mii_reg & BMSR_ANEGCAPABLE) && !(mii_reg & BMSR_ANEGCOMPLETE)) {
+ phydev->link = 0;
+ return 0;
+ } else {
+ /* Read the link a second time to clear the latched state */
+ mii_reg = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMSR);
+
+ if (mii_reg & BMSR_LSTATUS)
+ phydev->link = 1;
+ else
+ phydev->link = 0;
+ }
+
+ return 0;
+}
+
+/*
+ * Update speed and duplex.
+ *
+ * Based on genphy_parse_link in phylib.c
+ */
+static int ltq_phy_parse_link(struct phy_device *phydev)
+{
+ unsigned int mii_reg;
+
+ mii_reg = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMSR);
+
+ /* We're using autonegotiation */
+ if (mii_reg & BMSR_ANEGCAPABLE) {
+ u32 lpa = 0;
+ u32 gblpa = 0;
+
+ /* Check for gigabit capability */
+ if (mii_reg & BMSR_ERCAP) {
+ /* We want a list of states supported by
+ * both PHYs in the link
+ */
+ gblpa = phy_read(phydev, MDIO_DEVAD_NONE, MII_STAT1000);
+ gblpa &= phy_read(phydev,
+ MDIO_DEVAD_NONE, MII_CTRL1000) << 2;
+ }
+
+ /* Set the baseline so we only have to set them
+ * if they're different
+ */
+ phydev->speed = SPEED_10;
+ phydev->duplex = DUPLEX_HALF;
+
+ /* Check the gigabit fields */
+ if (gblpa & (PHY_1000BTSR_1000FD | PHY_1000BTSR_1000HD)) {
+ phydev->speed = SPEED_1000;
+
+ if (gblpa & PHY_1000BTSR_1000FD)
+ phydev->duplex = DUPLEX_FULL;
+
+ /* We're done! */
+ return 0;
+ }
+
+ lpa = phy_read(phydev, MDIO_DEVAD_NONE, MII_ADVERTISE);
+ lpa &= phy_read(phydev, MDIO_DEVAD_NONE, MII_LPA);
+
+ if (lpa & (LPA_100FULL | LPA_100HALF)) {
+ phydev->speed = SPEED_100;
+
+ if (lpa & LPA_100FULL)
+ phydev->duplex = DUPLEX_FULL;
+
+ } else if (lpa & LPA_10FULL)
+ phydev->duplex = DUPLEX_FULL;
+ } else {
+ u32 bmcr = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMCR);
+
+ phydev->speed = SPEED_10;
+ phydev->duplex = DUPLEX_HALF;
+
+ if (bmcr & BMCR_FULLDPLX)
+ phydev->duplex = DUPLEX_FULL;
+
+ if (bmcr & BMCR_SPEED1000)
+ phydev->speed = SPEED_1000;
+ else if (bmcr & BMCR_SPEED100)
+ phydev->speed = SPEED_100;
+ }
+
+ return 0;
+}
+
+static int ltq_phy_config(struct phy_device *phydev)
+{
+ u16 val;
+
+ /* Advertise as Multi-port device */
+ val = phy_read(phydev, MDIO_DEVAD_NONE, MII_CTRL1000);
+ val |= ADVERTIZE_MPD;
+ phy_write(phydev, MDIO_DEVAD_NONE, MII_CTRL1000, val);
+
+ genphy_config_aneg(phydev);
+
+ return 0;
+}
+
+static int ltq_phy_startup(struct phy_device *phydev)
+{
+ /*
+ * Update PHY status immediately without any delays as genphy_startup
+ * does because VRX200 switch needs to be configured dependent
+ * on this information.
+ */
+ ltq_phy_update_link(phydev);
+ ltq_phy_parse_link(phydev);
+
+ debug("ltq_phy: addr %d, link %d, speed %d, duplex %d\n",
+ phydev->addr, phydev->link, phydev->speed, phydev->duplex);
+
+ return 0;
+}
+
+static struct phy_driver xrx_11g_13_driver = {
+ .name = "Lantiq XWAY XRX PHY11G v1.3 and earlier",
+ .uid = 0x030260D0,
+ .mask = 0xFFFFFFF0,
+ .features = PHY_GBIT_FEATURES,
+ .config = ltq_phy_config,
+ .startup = ltq_phy_startup,
+ .shutdown = genphy_shutdown,
+};
+
+static struct phy_driver xrx_11g_14_driver = {
+ .name = "Lantiq XWAY XRX PHY11G v1.4 and later",
+ .uid = 0xd565a408,
+ .mask = 0xFFFFFFF8,
+ .features = PHY_GBIT_FEATURES,
+ .config = ltq_phy_config,
+ .startup = ltq_phy_startup,
+ .shutdown = genphy_shutdown,
+};
+
+static struct phy_driver xrx_22f_14_driver = {
+ .name = "Lantiq XWAY XRX PHY22F v1.4 and later",
+ .uid = 0xd565a418,
+ .mask = 0xFFFFFFF8,
+ .features = PHY_BASIC_FEATURES,
+ .config = ltq_phy_config,
+ .startup = ltq_phy_startup,
+ .shutdown = genphy_shutdown,
+};
+
+static struct phy_driver pef7071_driver = {
+ .name = "Lantiq XWAY PEF7071",
+ .uid = 0xd565a400,
+ .mask = 0xFFFFFFFF,
+ .features = PHY_GBIT_FEATURES,
+ .config = ltq_phy_config,
+ .startup = ltq_phy_startup,
+ .shutdown = genphy_shutdown,
+};
+
+static struct phy_driver xrx_genphy_driver = {
+ .name = "Generic PHY at Lantiq XWAY XRX switch",
+ .uid = 0,
+ .mask = 0,
+ .features = 0,
+ .config = genphy_config,
+ .startup = ltq_phy_startup,
+ .shutdown = genphy_shutdown,
+};
+
+int phy_lantiq_init(void)
+{
+#ifdef CONFIG_NEEDS_MANUAL_RELOC
+ xrx_11g_13_driver.config = ltq_phy_config;
+ xrx_11g_13_driver.startup = ltq_phy_startup;
+ xrx_11g_13_driver.shutdown = genphy_shutdown;
+ xrx_11g_13_driver.name += gd->reloc_off;
+
+ xrx_11g_14_driver.config = ltq_phy_config;
+ xrx_11g_14_driver.startup = ltq_phy_startup;
+ xrx_11g_14_driver.shutdown = genphy_shutdown;
+ xrx_11g_14_driver.name += gd->reloc_off;
+
+ xrx_22f_14_driver.config = ltq_phy_config;
+ xrx_22f_14_driver.startup = ltq_phy_startup;
+ xrx_22f_14_driver.shutdown = genphy_shutdown;
+ xrx_22f_14_driver.name += gd->reloc_off;
+
+ pef7071_driver.config = ltq_phy_config;
+ pef7071_driver.startup = ltq_phy_startup;
+ pef7071_driver.shutdown = genphy_shutdown;
+ pef7071_driver.name += gd->reloc_off;
+
+ xrx_genphy_driver.config = genphy_config;
+ xrx_genphy_driver.startup = ltq_phy_startup;
+ xrx_genphy_driver.shutdown = genphy_shutdown;
+ xrx_genphy_driver.name += gd->reloc_off;
+#endif
+
+ phy_register(&xrx_11g_13_driver);
+ phy_register(&xrx_11g_14_driver);
+ phy_register(&xrx_22f_14_driver);
+ phy_register(&pef7071_driver);
+ phy_register(&xrx_genphy_driver);
+
+ return 0;
+}
--- a/drivers/net/phy/phy.c
+++ b/drivers/net/phy/phy.c
@@ -16,9 +16,10 @@
#include <command.h>
#include <miiphy.h>
#include <phy.h>
-#include <errno.h>
#include <linux/err.h>
+DECLARE_GLOBAL_DATA_PTR;
+
/* Generic PHY support and helper functions */
/**
@@ -440,6 +441,16 @@ static LIST_HEAD(phy_drivers);
int phy_init(void)
{
+#ifdef CONFIG_NEEDS_MANUAL_RELOC
+ INIT_LIST_HEAD(&phy_drivers);
+
+ genphy_driver.config = genphy_config;
+ genphy_driver.startup = genphy_startup;
+ genphy_driver.shutdown = genphy_shutdown;
+
+ genphy_driver.name += gd->reloc_off;
+#endif
+
#ifdef CONFIG_PHY_ATHEROS
phy_atheros_init();
#endif
@@ -455,6 +466,9 @@ int phy_init(void)
#ifdef CONFIG_PHY_ICPLUS
phy_icplus_init();
#endif
+#ifdef CONFIG_PHY_LANTIQ
+ phy_lantiq_init();
+#endif
#ifdef CONFIG_PHY_LXT
phy_lxt_init();
#endif
--- a/drivers/serial/Makefile
+++ b/drivers/serial/Makefile
@@ -24,6 +24,7 @@ COBJS-$(CONFIG_SYS_NS16550_SERIAL) += se
COBJS-$(CONFIG_IMX_SERIAL) += serial_imx.o
COBJS-$(CONFIG_IXP_SERIAL) += serial_ixp.o
COBJS-$(CONFIG_KS8695_SERIAL) += serial_ks8695.o
+COBJS-$(CONFIG_LANTIQ_SERIAL) += serial_lantiq.o
COBJS-$(CONFIG_MAX3100_SERIAL) += serial_max3100.o
COBJS-$(CONFIG_MXC_UART) += serial_mxc.o
COBJS-$(CONFIG_PL010_SERIAL) += serial_pl01x.o
--- a/drivers/serial/serial.c
+++ b/drivers/serial/serial.c
@@ -160,6 +160,7 @@ serial_initfunc(sa1100_serial_initialize
serial_initfunc(sh_serial_initialize);
serial_initfunc(arm_dcc_initialize);
serial_initfunc(mxs_auart_initialize);
+serial_initfunc(ltq_serial_initialize);
/**
* serial_register() - Register serial driver with serial driver core
@@ -253,6 +254,7 @@ void serial_initialize(void)
sh_serial_initialize();
arm_dcc_initialize();
mxs_auart_initialize();
+ ltq_serial_initialize();
serial_assign(default_serial_console()->name);
}
--- /dev/null
+++ b/drivers/serial/serial_lantiq.c
@@ -0,0 +1,263 @@
+/*
+ * Copyright (C) 2010 Thomas Langer <thomas.langer@lantiq.com>
+ * Copyright (C) 2011-2013 Daniel Schwierzeck, daniel.schwierzeck@gmail.com
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <serial.h>
+#include <asm/errno.h>
+#include <asm/arch/soc.h>
+#include <asm/lantiq/clk.h>
+#include <asm/lantiq/io.h>
+
+#if CONFIG_CONSOLE_ASC == 0
+#define LTQ_ASC_BASE LTQ_ASC0_BASE
+#else
+#define LTQ_ASC_BASE LTQ_ASC1_BASE
+#endif
+
+#define LTQ_ASC_ID_TXFS_SHIFT 24
+#define LTQ_ASC_ID_TXFS_MASK (0x3F << LTQ_ASC_ID_TXFS_SHIFT)
+#define LTQ_ASC_ID_RXFS_SHIFT 16
+#define LTQ_ASC_ID_RXFS_MASK (0x3F << LTQ_ASC_ID_RXFS_SHIFT)
+
+#define LTQ_ASC_MCON_R (1 << 15)
+#define LTQ_ASC_MCON_FDE (1 << 9)
+
+#define LTQ_ASC_WHBSTATE_SETREN (1 << 1)
+#define LTQ_ASC_WHBSTATE_CLRREN (1 << 0)
+
+#define LTQ_ASC_RXFCON_RXFITL_SHIFT 8
+#define LTQ_ASC_RXFCON_RXFITL_MASK (0x3F << LTQ_ASC_RXFCON_RXFITL_SHIFT)
+#define LTQ_ASC_RXFCON_RXFITL_RXFFLU (1 << 1)
+#define LTQ_ASC_RXFCON_RXFITL_RXFEN (1 << 0)
+
+#define LTQ_ASC_TXFCON_TXFITL_SHIFT 8
+#define LTQ_ASC_TXFCON_TXFITL_MASK (0x3F << LTQ_ASC_TXFCON_TXFITL_SHIFT)
+#define LTQ_ASC_TXFCON_TXFITL_TXFFLU (1 << 1)
+#define LTQ_ASC_TXFCON_TXFITL_TXFEN (1 << 0)
+
+#define LTQ_ASC_FSTAT_TXFREE_SHIFT 24
+#define LTQ_ASC_FSTAT_TXFREE_MASK (0x3F << LTQ_ASC_FSTAT_TXFREE_SHIFT)
+#define LTQ_ASC_FSTAT_RXFREE_SHIFT 16
+#define LTQ_ASC_FSTAT_RXFREE_MASK (0x3F << LTQ_ASC_FSTAT_RXFREE_SHIFT)
+#define LTQ_ASC_FSTAT_TXFFL_SHIFT 8
+#define LTQ_ASC_FSTAT_TXFFL_MASK (0x3F << LTQ_ASC_FSTAT_TXFFL_SHIFT)
+#define LTQ_ASC_FSTAT_RXFFL_MASK 0x3F
+
+#ifdef __BIG_ENDIAN
+#define LTQ_ASC_RBUF_OFFSET 3
+#define LTQ_ASC_TBUF_OFFSET 3
+#else
+#define LTQ_ASC_RBUF_OFFSET 0
+#define LTQ_ASC_TBUF_OFFSET 0
+#endif
+
+struct ltq_asc_regs {
+ u32 clc;
+ u32 pisel;
+ u32 id;
+ u32 rsvd0;
+ u32 mcon;
+ u32 state;
+ u32 whbstate;
+ u32 rsvd1;
+ u8 tbuf[4];
+ u8 rbuf[4];
+ u32 rsvd2[2];
+ u32 abcon;
+ u32 abstat;
+ u32 whbabcon;
+ u32 whbabstat;
+ u32 rxfcon;
+ u32 txfcon;
+ u32 fstat;
+ u32 rsvd3;
+ u32 bg;
+ u32 bg_timer;
+ u32 fdv;
+ u32 pmw;
+ u32 modcon;
+ u32 modstat;
+};
+
+DECLARE_GLOBAL_DATA_PTR;
+
+static struct ltq_asc_regs *ltq_asc_regs =
+ (struct ltq_asc_regs *) CKSEG1ADDR(LTQ_ASC_BASE);
+
+static int ltq_serial_init(void)
+{
+ /* Set clock divider for normal run mode to 1 and enable module */
+ ltq_writel(&ltq_asc_regs->clc, 0x100);
+
+ /* Reset MCON register */
+ ltq_writel(&ltq_asc_regs->mcon, 0);
+
+ /* Use Port A as receiver input */
+ ltq_writel(&ltq_asc_regs->pisel, 0);
+
+ /* Enable and flush RX/TX FIFOs */
+ ltq_setbits(&ltq_asc_regs->rxfcon,
+ LTQ_ASC_RXFCON_RXFITL_RXFFLU | LTQ_ASC_RXFCON_RXFITL_RXFEN);
+ ltq_setbits(&ltq_asc_regs->txfcon,
+ LTQ_ASC_TXFCON_TXFITL_TXFFLU | LTQ_ASC_TXFCON_TXFITL_TXFEN);
+
+ serial_setbrg();
+
+ /* Disable error flags, enable receiver */
+ ltq_writel(&ltq_asc_regs->whbstate, LTQ_ASC_WHBSTATE_SETREN);
+
+ return 0;
+}
+
+/*
+ * fdv asc_clk
+ * Baudrate = ----- * -------------
+ * 512 16 * (bg + 1)
+ */
+static void ltq_serial_calc_br_fdv(unsigned long asc_clk,
+ unsigned long baudrate, u16 *fdv,
+ u16 *bg)
+{
+ const u32 c = asc_clk / (16 * 512);
+ u32 diff1, diff2;
+ u32 bg_calc, br_calc, i;
+
+ diff1 = baudrate;
+ for (i = 512; i > 0; i--) {
+ /* Calc bg for current fdv value */
+ bg_calc = i * c / baudrate;
+
+ /* Impossible baudrate */
+ if (!bg_calc)
+ return;
+
+ /*
+ * Calc diff to target baudrate dependent on current
+ * bg and fdv values
+ */
+ br_calc = i * c / bg_calc;
+ if (br_calc > baudrate)
+ diff2 = br_calc - baudrate;
+ else
+ diff2 = baudrate - br_calc;
+
+ /* Perfect values found */
+ if (diff2 == 0) {
+ *fdv = i;
+ *bg = bg_calc - 1;
+ return;
+ }
+
+ if (diff2 < diff1) {
+ *fdv = i;
+ *bg = bg_calc - 1;
+ diff1 = diff2;
+ }
+ }
+}
+
+static void ltq_serial_setbrg(void)
+{
+ unsigned long asc_clk, baudrate;
+ u16 bg = 0;
+ u16 fdv = 511;
+
+ /* ASC clock is same as FPI clock with CLC.RMS = 1 */
+ asc_clk = ltq_get_bus_clock();
+ baudrate = gd->baudrate;
+
+ /* Calculate FDV and BG values */
+ ltq_serial_calc_br_fdv(asc_clk, baudrate, &fdv, &bg);
+
+ /* Disable baudrate generator */
+ ltq_clrbits(&ltq_asc_regs->mcon, LTQ_ASC_MCON_R);
+
+ /* Enable fractional divider */
+ ltq_setbits(&ltq_asc_regs->mcon, LTQ_ASC_MCON_FDE);
+
+ /* Set fdv and bg values */
+ ltq_writel(&ltq_asc_regs->fdv, fdv);
+ ltq_writel(&ltq_asc_regs->bg, bg);
+
+ /* Enable baudrate generator */
+ ltq_setbits(&ltq_asc_regs->mcon, LTQ_ASC_MCON_R);
+}
+
+static unsigned int ltq_serial_tx_free(void)
+{
+ unsigned int txfree;
+
+ txfree = (ltq_readl(&ltq_asc_regs->fstat) &
+ LTQ_ASC_FSTAT_TXFREE_MASK) >>
+ LTQ_ASC_FSTAT_TXFREE_SHIFT;
+
+ return txfree;
+}
+
+static unsigned int ltq_serial_rx_fill(void)
+{
+ unsigned int rxffl;
+
+ rxffl = ltq_readl(&ltq_asc_regs->fstat) & LTQ_ASC_FSTAT_RXFFL_MASK;
+
+ return rxffl;
+}
+
+static void ltq_serial_tx(const char c)
+{
+ ltq_writeb(&ltq_asc_regs->tbuf[LTQ_ASC_TBUF_OFFSET], c);
+}
+
+static u8 ltq_serial_rx(void)
+{
+ return ltq_readb(&ltq_asc_regs->rbuf[LTQ_ASC_RBUF_OFFSET]);
+}
+
+static void ltq_serial_putc(const char c)
+{
+ if (c == '\n')
+ ltq_serial_putc('\r');
+
+ while (!ltq_serial_tx_free())
+ ;
+
+ ltq_serial_tx(c);
+}
+
+static int ltq_serial_getc(void)
+{
+ while (!ltq_serial_rx_fill())
+ ;
+
+ return ltq_serial_rx();
+}
+
+static int ltq_serial_tstc(void)
+{
+ return (0 != ltq_serial_rx_fill());
+}
+
+static struct serial_device ltq_serial_drv = {
+ .name = "ltq_serial",
+ .start = ltq_serial_init,
+ .stop = NULL,
+ .setbrg = ltq_serial_setbrg,
+ .putc = ltq_serial_putc,
+ .puts = default_serial_puts,
+ .getc = ltq_serial_getc,
+ .tstc = ltq_serial_tstc,
+};
+
+void ltq_serial_initialize(void)
+{
+ serial_register(&ltq_serial_drv);
+}
+
+__weak struct serial_device *default_serial_console(void)
+{
+ return &ltq_serial_drv;
+}
--- a/drivers/spi/Makefile
+++ b/drivers/spi/Makefile
@@ -25,6 +25,7 @@ COBJS-$(CONFIG_DAVINCI_SPI) += davinci_s
COBJS-$(CONFIG_EXYNOS_SPI) += exynos_spi.o
COBJS-$(CONFIG_ICH_SPI) += ich.o
COBJS-$(CONFIG_KIRKWOOD_SPI) += kirkwood_spi.o
+COBJS-$(CONFIG_LANTIQ_SPI) += lantiq_spi.o
COBJS-$(CONFIG_MPC52XX_SPI) += mpc52xx_spi.o
COBJS-$(CONFIG_MPC8XXX_SPI) += mpc8xxx_spi.o
COBJS-$(CONFIG_MXC_SPI) += mxc_spi.o
--- /dev/null
+++ b/drivers/spi/lantiq_spi.c
@@ -0,0 +1,666 @@
+/*
+ * Copyright (C) 2011-2013 Daniel Schwierzeck, daniel.schwierzeck@gmail.com
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <spi.h>
+#include <malloc.h>
+#include <watchdog.h>
+#include <asm/gpio.h>
+#include <asm/lantiq/io.h>
+#include <asm/lantiq/clk.h>
+#include <asm/lantiq/pm.h>
+#include <asm/arch/soc.h>
+
+#define LTQ_SPI_CLC_RMC_SHIFT 8
+#define LTQ_SPI_CLC_RMC_MASK (0xFF << LTQ_SPI_CLC_RMC_SHIFT)
+#define LTQ_SPI_CLC_DISS (1 << 1)
+#define LTQ_SPI_CLC_DISR 1
+
+#define LTQ_SPI_ID_TXFS_SHIFT 24
+#define LTQ_SPI_ID_TXFS_MASK (0x3F << LTQ_SPI_ID_TXFS_SHIFT)
+#define LTQ_SPI_ID_RXFS_SHIFT 16
+#define LTQ_SPI_ID_RXFS_MASK (0x3F << LTQ_SPI_ID_RXFS_SHIFT)
+
+#define LTQ_SPI_CON_ENBV (1 << 22)
+#define LTQ_SPI_CON_BM_SHIFT 16
+#define LTQ_SPI_CON_BM_MASK (0x1F << LTQ_SPI_CON_BM_SHIFT)
+#define LTQ_SPI_CON_IDLE (1 << 23)
+#define LTQ_SPI_CON_RUEN (1 << 12)
+#define LTQ_SPI_CON_AEN (1 << 10)
+#define LTQ_SPI_CON_REN (1 << 9)
+#define LTQ_SPI_CON_TEN (1 << 8)
+#define LTQ_SPI_CON_LB (1 << 7)
+#define LTQ_SPI_CON_PO (1 << 6)
+#define LTQ_SPI_CON_PH (1 << 5)
+#define LTQ_SPI_CON_HB (1 << 4)
+#define LTQ_SPI_CON_RXOFF (1 << 1)
+#define LTQ_SPI_CON_TXOFF 1
+
+#define LTQ_SPI_STAT_RXBV_SHIFT 28
+#define LTQ_SPI_STAT_RXBV_MASK (0x7 << LTQ_SPI_STAT_RXBV_SHIFT)
+#define LTQ_SPI_STAT_BSY (1 << 13)
+
+#define LTQ_SPI_WHBSTATE_SETMS (1 << 3)
+#define LTQ_SPI_WHBSTATE_CLRMS (1 << 2)
+#define LTQ_SPI_WHBSTATE_SETEN (1 << 1)
+#define LTQ_SPI_WHBSTATE_CLREN 1
+#define LTQ_SPI_WHBSTATE_CLR_ERRORS 0x0F50
+
+#define LTQ_SPI_TXFCON_TXFLU (1 << 1)
+#define LTQ_SPI_TXFCON_TXFEN 1
+
+#define LTQ_SPI_RXFCON_RXFLU (1 << 1)
+#define LTQ_SPI_RXFCON_RXFEN 1
+
+#define LTQ_SPI_FSTAT_RXFFL_MASK 0x3f
+#define LTQ_SPI_FSTAT_TXFFL_SHIFT 8
+#define LTQ_SPI_FSTAT_TXFFL_MASK (0x3f << LTQ_SPI_FSTAT_TXFFL_SHIFT)
+
+#define LTQ_SPI_RXREQ_RXCNT_MASK 0xFFFF
+#define LTQ_SPI_RXCNT_TODO_MASK 0xFFFF
+
+#define LTQ_SPI_GPIO_DIN 16
+#define LTQ_SPI_GPIO_DOUT 17
+#define LTQ_SPI_GPIO_CLK 18
+
+struct ltq_spi_regs {
+ __be32 clc; /* Clock control */
+ __be32 pisel; /* Port input select */
+ __be32 id; /* Identification */
+ __be32 rsvd0;
+ __be32 con; /* Control */
+ __be32 stat; /* Status */
+ __be32 whbstate; /* Write HW modified state */
+ __be32 rsvd1;
+ __be32 tb; /* Transmit buffer */
+ __be32 rb; /* Receive buffer */
+ __be32 rsvd2[2];
+ __be32 rxfcon; /* Recevie FIFO control */
+ __be32 txfcon; /* Transmit FIFO control */
+ __be32 fstat; /* FIFO status */
+ __be32 rsvd3;
+ __be32 brt; /* Baudrate timer */
+ __be32 brstat; /* Baudrate timer status */
+ __be32 rsvd4[6];
+ __be32 sfcon; /* Serial frame control */
+ __be32 sfstat; /* Serial frame status */
+ __be32 rsvd5[2];
+ __be32 gpocon; /* General purpose output control */
+ __be32 gpostat; /* General purpose output status */
+ __be32 fgpo; /* Force general purpose output */
+ __be32 rsvd6;
+ __be32 rxreq; /* Receive request */
+ __be32 rxcnt; /* Receive count */
+ __be32 rsvd7[25];
+ __be32 dmacon; /* DMA control */
+ __be32 rsvd8;
+ __be32 irnen; /* Interrupt node enable */
+ __be32 irnicr; /* Interrupt node interrupt capture */
+ __be32 irncr; /* Interrupt node control */
+};
+
+struct ltq_spi_drv_data {
+ struct ltq_spi_regs __iomem *regs;
+
+ struct spi_slave slave;
+ unsigned int max_hz;
+ unsigned int mode;
+ unsigned int tx_todo;
+ unsigned int rx_todo;
+ unsigned int rx_req;
+ unsigned int bits_per_word;
+ unsigned int speed_hz;
+ const u8 *tx;
+ u8 *rx;
+ int status;
+};
+
+static struct ltq_spi_drv_data *to_ltq_spi_slave(struct spi_slave *slave)
+{
+ return container_of(slave, struct ltq_spi_drv_data, slave);
+}
+
+#ifdef CONFIG_SPL_BUILD
+/*
+ * We do not have or want malloc in a SPI flash SPL.
+ * Neither we have to support multiple SPI slaves. Thus we put the
+ * SPI slave context in BSS for SPL builds.
+ */
+static struct ltq_spi_drv_data ltq_spi_slave;
+
+static struct ltq_spi_drv_data *ltq_spi_slave_alloc(unsigned int bus,
+ unsigned int cs)
+{
+ ltq_spi_slave.slave.bus = bus;
+ ltq_spi_slave.slave.cs = cs;
+
+ return &ltq_spi_slave;
+}
+
+static void ltq_spi_slave_free(struct spi_slave *slave)
+{
+}
+#else
+static struct ltq_spi_drv_data *ltq_spi_slave_alloc(unsigned int bus,
+ unsigned int cs)
+{
+ return spi_alloc_slave(struct ltq_spi_drv_data, bus, cs);
+}
+
+static void ltq_spi_slave_free(struct spi_slave *slave)
+{
+ struct ltq_spi_drv_data *drv;
+
+ if (slave) {
+ drv = to_ltq_spi_slave(slave);
+ free(drv);
+ }
+}
+#endif
+
+static unsigned int tx_fifo_size(struct ltq_spi_drv_data *drv)
+{
+ u32 id = ltq_readl(&drv->regs->id);
+
+ return (id & LTQ_SPI_ID_TXFS_MASK) >> LTQ_SPI_ID_TXFS_SHIFT;
+}
+
+static unsigned int rx_fifo_size(struct ltq_spi_drv_data *drv)
+{
+ u32 id = ltq_readl(&drv->regs->id);
+
+ return (id & LTQ_SPI_ID_RXFS_MASK) >> LTQ_SPI_ID_RXFS_SHIFT;
+}
+
+static unsigned int tx_fifo_level(struct ltq_spi_drv_data *drv)
+{
+ u32 fstat = ltq_readl(&drv->regs->fstat);
+
+ return (fstat & LTQ_SPI_FSTAT_TXFFL_MASK) >> LTQ_SPI_FSTAT_TXFFL_SHIFT;
+}
+
+static unsigned int rx_fifo_level(struct ltq_spi_drv_data *drv)
+{
+ u32 fstat = ltq_readl(&drv->regs->fstat);
+
+ return fstat & LTQ_SPI_FSTAT_RXFFL_MASK;
+}
+
+static unsigned int tx_fifo_free(struct ltq_spi_drv_data *drv)
+{
+ return tx_fifo_size(drv) - tx_fifo_level(drv);
+}
+
+static void hw_power_on(struct ltq_spi_drv_data *drv)
+{
+ u32 clc;
+
+ /* Power-up mdule */
+ ltq_pm_enable(LTQ_PM_SPI);
+
+ /*
+ * Set clock divider for run mode to 1 to
+ * run at same frequency as FPI bus
+ */
+ clc = (1 << LTQ_SPI_CLC_RMC_SHIFT);
+ ltq_writel(&drv->regs->clc, clc);
+}
+
+static void hw_reset_fifos(struct ltq_spi_drv_data *drv)
+{
+ u32 val;
+
+ val = LTQ_SPI_TXFCON_TXFEN | LTQ_SPI_TXFCON_TXFLU;
+ ltq_writel(&drv->regs->txfcon, val);
+
+ val = LTQ_SPI_RXFCON_RXFEN | LTQ_SPI_RXFCON_RXFLU;
+ ltq_writel(&drv->regs->rxfcon, val);
+}
+
+static int hw_is_busy(struct ltq_spi_drv_data *drv)
+{
+ u32 stat = ltq_readl(&drv->regs->stat);
+
+ return stat & LTQ_SPI_STAT_BSY;
+}
+
+static void hw_enter_config_mode(struct ltq_spi_drv_data *drv)
+{
+ ltq_writel(&drv->regs->whbstate, LTQ_SPI_WHBSTATE_CLREN);
+}
+
+static void hw_enter_active_mode(struct ltq_spi_drv_data *drv)
+{
+ ltq_writel(&drv->regs->whbstate, LTQ_SPI_WHBSTATE_SETEN);
+}
+
+static void hw_setup_speed_hz(struct ltq_spi_drv_data *drv,
+ unsigned int max_speed_hz)
+{
+ unsigned int spi_hz, speed_hz, brt;
+
+ /*
+ * SPI module clock is derived from FPI bus clock dependent on
+ * divider value in CLC.RMS which is always set to 1.
+ *
+ * f_SPI
+ * baudrate = --------------
+ * 2 * (BR + 1)
+ */
+ spi_hz = ltq_get_bus_clock() / 2;
+
+ /* TODO: optimize baudrate calculation */
+ for (brt = 0; brt < 0xFFFF; brt++) {
+ speed_hz = spi_hz / (brt + 1);
+ if (speed_hz <= max_speed_hz)
+ break;
+ }
+
+ ltq_writel(&drv->regs->brt, brt);
+}
+
+static void hw_setup_bits_per_word(struct ltq_spi_drv_data *drv,
+ unsigned int bits_per_word)
+{
+ u32 bm;
+
+ /* CON.BM value = bits_per_word - 1 */
+ bm = (bits_per_word - 1) << LTQ_SPI_CON_BM_SHIFT;
+
+ ltq_clrsetbits(&drv->regs->con, LTQ_SPI_CON_BM_MASK, bm);
+}
+
+static void hw_setup_clock_mode(struct ltq_spi_drv_data *drv, unsigned int mode)
+{
+ u32 con_set = 0, con_clr = 0;
+
+ /*
+ * SPI mode mapping in CON register:
+ * Mode CPOL CPHA CON.PO CON.PH
+ * 0 0 0 0 1
+ * 1 0 1 0 0
+ * 2 1 0 1 1
+ * 3 1 1 1 0
+ */
+ if (mode & SPI_CPHA)
+ con_clr |= LTQ_SPI_CON_PH;
+ else
+ con_set |= LTQ_SPI_CON_PH;
+
+ if (mode & SPI_CPOL)
+ con_set |= LTQ_SPI_CON_PO | LTQ_SPI_CON_IDLE;
+ else
+ con_clr |= LTQ_SPI_CON_PO | LTQ_SPI_CON_IDLE;
+
+ /* Set heading control */
+ if (mode & SPI_LSB_FIRST)
+ con_clr |= LTQ_SPI_CON_HB;
+ else
+ con_set |= LTQ_SPI_CON_HB;
+
+ /* Set loopback mode */
+ if (mode & SPI_LOOP)
+ con_set |= LTQ_SPI_CON_LB;
+ else
+ con_clr |= LTQ_SPI_CON_LB;
+
+ ltq_clrsetbits(&drv->regs->con, con_clr, con_set);
+}
+
+static void hw_set_rxtx(struct ltq_spi_drv_data *drv)
+{
+ u32 con;
+
+ /* Configure transmitter and receiver */
+ con = ltq_readl(&drv->regs->con);
+ if (drv->tx)
+ con &= ~LTQ_SPI_CON_TXOFF;
+ else
+ con |= LTQ_SPI_CON_TXOFF;
+
+ if (drv->rx)
+ con &= ~LTQ_SPI_CON_RXOFF;
+ else
+ con |= LTQ_SPI_CON_RXOFF;
+
+ ltq_writel(&drv->regs->con, con);
+}
+
+static void hw_init(struct ltq_spi_drv_data *drv)
+{
+ hw_power_on(drv);
+
+ /* Put controller into config mode */
+ hw_enter_config_mode(drv);
+
+ /* Disable all interrupts */
+ ltq_writel(&drv->regs->irnen, 0);
+
+ /* Clear error flags */
+ ltq_clrsetbits(&drv->regs->whbstate, 0, LTQ_SPI_WHBSTATE_CLR_ERRORS);
+
+ /* Enable error checking, disable TX/RX */
+ ltq_writel(&drv->regs->con, LTQ_SPI_CON_RUEN | LTQ_SPI_CON_AEN |
+ LTQ_SPI_CON_TEN | LTQ_SPI_CON_REN | LTQ_SPI_CON_TXOFF |
+ LTQ_SPI_CON_RXOFF);
+
+ /* Setup default SPI mode */
+ drv->bits_per_word = 8;
+ drv->speed_hz = 0;
+ hw_setup_bits_per_word(drv, drv->bits_per_word);
+ hw_setup_clock_mode(drv, SPI_MODE_0);
+
+ /* Enable master mode and clear error flags */
+ ltq_writel(&drv->regs->whbstate, LTQ_SPI_WHBSTATE_SETMS |
+ LTQ_SPI_WHBSTATE_CLR_ERRORS);
+
+ /* Reset GPIO/CS registers */
+ ltq_writel(&drv->regs->gpocon, 0);
+ ltq_writel(&drv->regs->fgpo, 0xFF00);
+
+ /* Enable and flush FIFOs */
+ hw_reset_fifos(drv);
+
+ /* SPI/DIN input */
+ gpio_set_altfunc(16, GPIO_ALTSEL_SET, GPIO_ALTSEL_CLR, GPIO_DIR_IN);
+ /* SPI/DOUT output */
+ gpio_set_altfunc(17, GPIO_ALTSEL_SET, GPIO_ALTSEL_CLR, GPIO_DIR_OUT);
+ /* SPI/CLK output */
+ gpio_set_altfunc(18, GPIO_ALTSEL_SET, GPIO_ALTSEL_CLR, GPIO_DIR_OUT);
+}
+
+static void tx_fifo_write(struct ltq_spi_drv_data *drv)
+{
+ const u8 *tx8;
+ const u16 *tx16;
+ const u32 *tx32;
+ u32 data;
+ unsigned int tx_free = tx_fifo_free(drv);
+
+ while (drv->tx_todo && tx_free) {
+ switch (drv->bits_per_word) {
+ case 8:
+ tx8 = drv->tx;
+ data = *tx8;
+ drv->tx_todo--;
+ drv->tx++;
+ break;
+ case 16:
+ tx16 = (u16 *) drv->tx;
+ data = *tx16;
+ drv->tx_todo -= 2;
+ drv->tx += 2;
+ break;
+ case 32:
+ tx32 = (u32 *) drv->tx;
+ data = *tx32;
+ drv->tx_todo -= 4;
+ drv->tx += 4;
+ break;
+ default:
+ return;
+ }
+
+ ltq_writel(&drv->regs->tb, data);
+ tx_free--;
+ }
+}
+
+static void rx_fifo_read_full_duplex(struct ltq_spi_drv_data *drv)
+{
+ u8 *rx8;
+ u16 *rx16;
+ u32 *rx32;
+ u32 data;
+ unsigned int rx_fill = rx_fifo_level(drv);
+
+ while (rx_fill) {
+ data = ltq_readl(&drv->regs->rb);
+
+ switch (drv->bits_per_word) {
+ case 8:
+ rx8 = drv->rx;
+ *rx8 = data;
+ drv->rx_todo--;
+ drv->rx++;
+ break;
+ case 16:
+ rx16 = (u16 *) drv->rx;
+ *rx16 = data;
+ drv->rx_todo -= 2;
+ drv->rx += 2;
+ break;
+ case 32:
+ rx32 = (u32 *) drv->rx;
+ *rx32 = data;
+ drv->rx_todo -= 4;
+ drv->rx += 4;
+ break;
+ default:
+ return;
+ }
+
+ rx_fill--;
+ }
+}
+
+static void rx_fifo_read_half_duplex(struct ltq_spi_drv_data *drv)
+{
+ u32 data, *rx32;
+ u8 *rx8;
+ unsigned int rxbv, shift;
+ unsigned int rx_fill = rx_fifo_level(drv);
+
+ /*
+ * In RX-only mode the bits per word value is ignored by HW. A value
+ * of 32 is used instead. Thus all 4 bytes per FIFO must be read.
+ * If remaining RX bytes are less than 4, the FIFO must be read
+ * differently. The amount of received and valid bytes is indicated
+ * by STAT.RXBV register value.
+ */
+ while (rx_fill) {
+ if (drv->rx_todo < 4) {
+ rxbv = (ltq_readl(&drv->regs->stat) &
+ LTQ_SPI_STAT_RXBV_MASK) >>
+ LTQ_SPI_STAT_RXBV_SHIFT;
+ data = ltq_readl(&drv->regs->rb);
+
+ shift = (rxbv - 1) * 8;
+ rx8 = drv->rx;
+
+ while (rxbv) {
+ *rx8++ = (data >> shift) & 0xFF;
+ rxbv--;
+ shift -= 8;
+ drv->rx_todo--;
+ drv->rx++;
+
+ if (drv->rx_req)
+ drv->rx_req --;
+ }
+ } else {
+ data = ltq_readl(&drv->regs->rb);
+ rx32 = (u32 *) drv->rx;
+
+ *rx32++ = data;
+ drv->rx_todo -= 4;
+ drv->rx += 4;
+
+ if (drv->rx_req >= 4)
+ drv->rx_req -= 4;
+ }
+ rx_fill--;
+ }
+}
+
+static void rx_request(struct ltq_spi_drv_data *drv)
+{
+ unsigned int rxreq, rxreq_max;
+
+ if (drv->rx_req)
+ return;
+
+ /*
+ * To avoid receive overflows at high clocks it is better to request
+ * only the amount of bytes that fits into all FIFOs. This value
+ * depends on the FIFO size implemented in hardware.
+ */
+ rxreq = drv->rx_todo;
+ rxreq_max = rx_fifo_size(drv) * 4;
+ if (rxreq > rxreq_max)
+ rxreq = rxreq_max;
+
+ drv->rx_req = rxreq;
+ ltq_writel(&drv->regs->rxreq, rxreq);
+}
+
+void spi_init(void)
+{
+}
+
+struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
+ unsigned int max_hz, unsigned int mode)
+{
+ struct ltq_spi_drv_data *drv;
+
+ if (!spi_cs_is_valid(bus, cs))
+ return NULL;
+
+ drv = ltq_spi_slave_alloc(bus, cs);
+ if (!drv)
+ return NULL;
+
+ drv->regs = (struct ltq_spi_regs *) CKSEG1ADDR(LTQ_SPI_BASE);
+
+ hw_init(drv);
+
+ drv->max_hz = max_hz;
+ drv->mode = mode;
+
+ return &drv->slave;
+}
+
+void spi_free_slave(struct spi_slave *slave)
+{
+ ltq_spi_slave_free(slave);
+}
+
+static int ltq_spi_wait_ready(struct ltq_spi_drv_data *drv)
+{
+ const unsigned long timeout = 20000;
+ unsigned long timebase;
+
+ timebase = get_timer(0);
+
+ do {
+ WATCHDOG_RESET();
+
+ if (!hw_is_busy(drv))
+ return 0;
+ } while (get_timer(timebase) < timeout);
+
+ return 1;
+}
+
+int spi_claim_bus(struct spi_slave *slave)
+{
+ struct ltq_spi_drv_data *drv = to_ltq_spi_slave(slave);
+ int ret;
+
+ ret = ltq_spi_wait_ready(drv);
+ if (ret) {
+ debug("cannot claim bus\n");
+ return ret;
+ }
+
+ hw_enter_config_mode(drv);
+ hw_setup_clock_mode(drv, drv->mode);
+ hw_setup_speed_hz(drv, drv->max_hz);
+ hw_setup_bits_per_word(drv, drv->bits_per_word);
+ hw_enter_active_mode(drv);
+
+ return 0;
+}
+
+void spi_release_bus(struct spi_slave *slave)
+{
+ struct ltq_spi_drv_data *drv = to_ltq_spi_slave(slave);
+
+ hw_enter_config_mode(drv);
+}
+
+int spi_xfer(struct spi_slave *slave, unsigned int bitlen,
+ const void *dout, void *din, unsigned long flags)
+{
+
+ struct ltq_spi_drv_data *drv = to_ltq_spi_slave(slave);
+ int ret = 0;
+
+ if (bitlen % 8)
+ return 1;
+
+ if (!bitlen) {
+ ret = 0;
+ goto done;
+ }
+
+ if (flags & SPI_XFER_BEGIN)
+ spi_cs_activate(slave);
+
+ drv->tx = dout;
+ drv->tx_todo = 0;
+ drv->rx = din;
+ drv->rx_todo = 0;
+ hw_set_rxtx(drv);
+
+ if (drv->tx) {
+ drv->tx_todo = bitlen / 8;
+
+ tx_fifo_write(drv);
+ }
+
+ if (drv->rx) {
+ drv->rx_todo = bitlen / 8;
+
+ if (!drv->tx)
+ rx_request(drv);
+ }
+
+ for (;;) {
+ if (drv->tx) {
+ if (drv->rx && drv->rx_todo)
+ rx_fifo_read_full_duplex(drv);
+
+ if (drv->tx_todo)
+ tx_fifo_write(drv);
+ else
+ goto done;
+ } else if (drv->rx) {
+ if (drv->rx_todo) {
+ rx_fifo_read_half_duplex(drv);
+
+ if (drv->rx_todo)
+ rx_request(drv);
+ else
+ goto done;
+ } else {
+ goto done;
+ }
+ }
+ }
+
+done:
+ ret = ltq_spi_wait_ready(drv);
+
+ drv->rx = NULL;
+ drv->tx = NULL;
+ hw_set_rxtx(drv);
+
+ if (flags & SPI_XFER_END)
+ spi_cs_deactivate(slave);
+
+ return ret;
+}
--- a/include/phy.h
+++ b/include/phy.h
@@ -214,6 +214,7 @@ int phy_atheros_init(void);
int phy_broadcom_init(void);
int phy_davicom_init(void);
int phy_et1011c_init(void);
+int phy_lantiq_init(void);
int phy_lxt_init(void);
int phy_marvell_init(void);
int phy_micrel_init(void);
--- a/spl/Makefile
+++ b/spl/Makefile
@@ -100,6 +100,8 @@ LIBS-$(CONFIG_SPL_USBETH_SUPPORT) += dri
LIBS-$(CONFIG_SPL_MUSB_NEW_SUPPORT) += drivers/usb/musb-new/libusb_musb-new.o
LIBS-$(CONFIG_SPL_USBETH_SUPPORT) += drivers/usb/gadget/libusb_gadget.o
LIBS-$(CONFIG_SPL_WATCHDOG_SUPPORT) += drivers/watchdog/libwatchdog.o
+LIBS-$(CONFIG_SPL_LZMA_SUPPORT) += lib/lzma/liblzma.o
+LIBS-$(CONFIG_SPL_LZO_SUPPORT) += lib/lzo/liblzo.o
ifneq ($(CONFIG_OMAP_COMMON),)
LIBS-y += $(CPUDIR)/omap-common/libomap-common.o
--- a/tools/.gitignore
+++ b/tools/.gitignore
@@ -2,6 +2,7 @@
/envcrc
/gen_eth_addr
/img2srec
+/ltq-boot-image
/kwboot
/mkenvimage
/mkimage
--- a/tools/Makefile
+++ b/tools/Makefile
@@ -49,6 +49,7 @@ BIN_FILES-$(CONFIG_VIDEO_LOGO) += bmp_lo
BIN_FILES-$(CONFIG_BUILD_ENVCRC) += envcrc$(SFX)
BIN_FILES-$(CONFIG_CMD_NET) += gen_eth_addr$(SFX)
BIN_FILES-$(CONFIG_CMD_LOADS) += img2srec$(SFX)
+BIN_FILES-$(CONFIG_SOC_LANTIQ) += ltq-boot-image$(SFX)
BIN_FILES-$(CONFIG_XWAY_SWAP_BYTES) += xway-swap-bytes$(SFX)
BIN_FILES-y += mkenvimage$(SFX)
BIN_FILES-y += mkimage$(SFX)
@@ -95,6 +96,7 @@ OBJ_FILES-$(CONFIG_MX28) += mxsboot.o
OBJ_FILES-$(CONFIG_NETCONSOLE) += ncb.o
OBJ_FILES-$(CONFIG_SHA1_CHECK_UB_IMG) += ubsha1.o
OBJ_FILES-$(CONFIG_SMDK5250) += mkexynosspl.o
+OBJ_FILES-$(CONFIG_SOC_LANTIQ) += ltq-boot-image.o
OBJ_FILES-$(CONFIG_VIDEO_LOGO) += bmp_logo.o
OBJ_FILES-$(CONFIG_XWAY_SWAP_BYTES) += xway-swap-bytes.o
@@ -195,6 +197,10 @@ $(obj)img2srec$(SFX): $(obj)img2srec.o
$(HOSTCC) $(HOSTCFLAGS) $(HOSTLDFLAGS) -o $@ $^
$(HOSTSTRIP) $@
+$(obj)ltq-boot-image$(SFX): $(obj)ltq-boot-image.o
+ $(HOSTCC) $(HOSTCFLAGS) $(HOSTLDFLAGS) -o $@ $^
+ $(HOSTSTRIP) $@
+
$(obj)xway-swap-bytes$(SFX): $(obj)xway-swap-bytes.o
$(HOSTCC) $(HOSTCFLAGS) $(HOSTLDFLAGS) -o $@ $^
$(HOSTSTRIP) $@
--- /dev/null
+++ b/tools/ltq-boot-image.c
@@ -0,0 +1,315 @@
+/*
+ * Copyright (C) 2011-2013 Daniel Schwierzeck, daniel.schwierzeck@gmail.com
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <getopt.h>
+#include <compiler.h>
+#include <sys/stat.h>
+
+enum image_types {
+ IMAGE_NONE,
+ IMAGE_SFSPL
+};
+
+/* Lantiq non-volatile bootstrap command IDs */
+enum nvb_cmd_ids {
+ NVB_CMD_DEBUG = 0x11,
+ NVB_CMD_REGCFG = 0x22,
+ NVB_CMD_IDWNLD = 0x33,
+ NVB_CMD_CDWNLD = 0x44,
+ NVB_CMD_DWNLD = 0x55,
+ NVB_CMD_IFCFG = 0x66,
+ NVB_CMD_START = 0x77
+};
+
+/* Lantiq non-volatile bootstrap command flags */
+enum nvb_cmd_flags {
+ NVB_FLAG_START = 1,
+ NVB_FLAG_DEC = (1 << 1),
+ NVB_FLAG_DBG = (1 << 2),
+ NVB_FLAG_SDBG = (1 << 3),
+ NVB_FLAG_CFG0 = (1 << 4),
+ NVB_FLAG_CFG1 = (1 << 5),
+ NVB_FLAG_CFG2 = (1 << 6),
+ NVB_FLAG_RST = (1 << 7)
+};
+
+struct args {
+ enum image_types type;
+ __u32 entry_addr;
+ const char *uboot_bin;
+ const char *spl_bin;
+ const char *out_bin;
+};
+
+static void usage_msg(const char *name)
+{
+ fprintf(stderr, "%s: [-h] -t type -e entry-addr -u uboot-bin [-s spl-bin] -o out-bin\n",
+ name);
+ fprintf(stderr, " Image types:\n"
+ " sfspl - SPL + [compressed] U-Boot for SPI flash\n");
+}
+
+static enum image_types parse_image_type(const char *type)
+{
+ if (!type)
+ return IMAGE_NONE;
+
+ if (!strncmp(type, "sfspl", 6))
+ return IMAGE_SFSPL;
+
+ return IMAGE_NONE;
+}
+
+static int parse_args(int argc, char *argv[], struct args *arg)
+{
+ int opt;
+
+ memset(arg, 0, sizeof(*arg));
+
+ while ((opt = getopt(argc, argv, "ht:e:u:s:o:")) != -1) {
+ switch (opt) {
+ case 'h':
+ usage_msg(argv[0]);
+ return 1;
+ case 't':
+ arg->type = parse_image_type(optarg);
+ break;
+ case 'e':
+ arg->entry_addr = strtoul(optarg, NULL, 16);
+ break;
+ case 'u':
+ arg->uboot_bin = optarg;
+ break;
+ case 's':
+ arg->spl_bin = optarg;
+ break;
+ case 'o':
+ arg->out_bin = optarg;
+ break;
+ default:
+ fprintf(stderr, "Invalid option -%c\n", opt);
+ goto parse_error;
+ }
+ }
+
+ if (arg->type == IMAGE_NONE) {
+ fprintf(stderr, "Invalid image type\n");
+ goto parse_error;
+ }
+
+ if (!arg->uboot_bin) {
+ fprintf(stderr, "Missing U-Boot binary\n");
+ goto parse_error;
+ }
+
+ if (!arg->out_bin) {
+ fprintf(stderr, "Missing output binary\n");
+ goto parse_error;
+ }
+
+ if (arg->type == IMAGE_SFSPL && !arg->spl_bin) {
+ fprintf(stderr, "Missing SPL binary\n");
+ goto parse_error;
+ }
+
+ return 0;
+
+parse_error:
+ usage_msg(argv[0]);
+ return -1;
+}
+
+static __u32 build_nvb_command(unsigned cmdid, unsigned cmdflags)
+{
+ __u32 cmd;
+ __u16 tag;
+
+ tag = (cmdid << 8) | cmdflags;
+ cmd = (tag << 16) | (0xFFFF - tag);
+
+ return cpu_to_be32(cmd);
+}
+
+static int write_header(int fd, const void *hdr, size_t size)
+{
+ ssize_t n;
+
+ n = write(fd, hdr, size);
+ if (n != size) {
+ fprintf(stderr, "Cannot write header: %s\n",
+ strerror(errno));
+ return -1;
+ }
+
+ return 0;
+}
+
+static int write_nvb_dwnld_header(int fd, size_t size, __u32 addr)
+{
+ __u32 hdr[3];
+
+ hdr[0] = build_nvb_command(NVB_CMD_DWNLD, NVB_FLAG_START |
+ NVB_FLAG_SDBG);
+ hdr[1] = cpu_to_be32(size + 4);
+ hdr[2] = cpu_to_be32(addr);
+
+ return write_header(fd, hdr, sizeof(hdr));
+}
+
+static int write_nvb_start_header(int fd, __u32 addr)
+{
+ __u32 hdr[3];
+
+ hdr[0] = build_nvb_command(NVB_CMD_START, NVB_FLAG_SDBG);
+ hdr[1] = cpu_to_be32(4);
+ hdr[2] = cpu_to_be32(addr);
+
+ return write_header(fd, hdr, sizeof(hdr));
+}
+
+static int open_input_bin(const char *name, void **ptr, size_t *size)
+{
+ struct stat sbuf;
+ int ret, fd;
+
+ fd = open(name, O_RDONLY | O_BINARY);
+ if (0 > fd) {
+ fprintf(stderr, "Cannot open %s: %s\n", name,
+ strerror(errno));
+ return -1;
+ }
+
+ ret = fstat(fd, &sbuf);
+ if (0 > ret) {
+ fprintf(stderr, "Cannot fstat %s: %s\n", name,
+ strerror(errno));
+ return -1;
+ }
+
+ *ptr = mmap(0, sbuf.st_size, PROT_READ, MAP_SHARED, fd, 0);
+ if (*ptr == MAP_FAILED) {
+ fprintf(stderr, "Cannot mmap %s: %s\n", name,
+ strerror(errno));
+ return -1;
+ }
+
+ *size = sbuf.st_size;
+
+ return fd;
+}
+
+static void close_input_bin(int fd, void *ptr, size_t size)
+{
+ munmap(ptr, size);
+ close(fd);
+}
+
+static int copy_bin(int fd, void *ptr, size_t size)
+{
+ ssize_t n;
+
+ n = write(fd, ptr, size);
+ if (n != size) {
+ fprintf(stderr, "Cannot copy binary: %s\n", strerror(errno));
+ return -1;
+ }
+
+ return 0;
+}
+
+static int open_output_bin(const char *name)
+{
+ int fd;
+
+ fd = open(name, O_RDWR | O_CREAT | O_TRUNC | O_BINARY, 0666);
+ if (0 > fd) {
+ fprintf(stderr, "Cannot open %s: %s\n", name,
+ strerror(errno));
+ return -1;
+ }
+
+ return fd;
+}
+
+static int create_sfspl(const struct args *arg)
+{
+ int out_fd, uboot_fd, spl_fd, ret;
+ void *uboot_ptr, *spl_ptr;
+ size_t uboot_size, spl_size;
+
+ out_fd = open_output_bin(arg->out_bin);
+ if (0 > out_fd)
+ goto err;
+
+ spl_fd = open_input_bin(arg->spl_bin, &spl_ptr, &spl_size);
+ if (0 > spl_fd)
+ goto err_spl;
+
+ uboot_fd = open_input_bin(arg->uboot_bin, &uboot_ptr, &uboot_size);
+ if (0 > uboot_fd)
+ goto err_uboot;
+
+ ret = write_nvb_dwnld_header(out_fd, spl_size, arg->entry_addr);
+ if (ret)
+ goto err_write;
+
+ ret = copy_bin(out_fd, spl_ptr, spl_size);
+ if (ret)
+ goto err_write;
+
+ ret = write_nvb_start_header(out_fd, arg->entry_addr);
+ if (ret)
+ goto err_write;
+
+ ret = copy_bin(out_fd, uboot_ptr, uboot_size);
+ if (ret)
+ goto err_write;
+
+ close_input_bin(uboot_fd, uboot_ptr, uboot_size);
+ close_input_bin(spl_fd, spl_ptr, spl_size);
+ close(out_fd);
+
+ return 0;
+
+err_write:
+ close_input_bin(uboot_fd, uboot_ptr, uboot_size);
+err_uboot:
+ close_input_bin(spl_fd, spl_ptr, spl_size);
+err_spl:
+ close(out_fd);
+err:
+ return -1;
+}
+
+int main(int argc, char *argv[])
+{
+ int ret;
+ struct args arg;
+
+ ret = parse_args(argc, argv, &arg);
+ if (ret)
+ goto done;
+
+ switch (arg.type) {
+ case IMAGE_SFSPL:
+ ret = create_sfspl(&arg);
+ break;
+ default:
+ fprintf(stderr, "Image type not implemented\n");
+ ret = -1;
+ break;
+ }
+
+done:
+ if (ret >= 0)
+ return EXIT_SUCCESS;
+
+ return EXIT_FAILURE;
+}