summaryrefslogtreecommitdiff
path: root/arch/mips/mach-jz47xx/jz4780
diff options
context:
space:
mode:
authorPaul Burton <paul.burton@imgtec.com>2018-12-16 19:25:22 -0300
committerDaniel Schwierzeck <daniel.schwierzeck@gmail.com>2018-12-19 15:23:01 +0100
commitcd71b1d5d26dfff15222f5df8a5a6df68fc41df7 (patch)
treed2151922fd418631781095a603ce9befb176e5cd /arch/mips/mach-jz47xx/jz4780
parentb325c4dcd72246a107580280ff66f4c86b23254a (diff)
mips: jz47xx: Add JZ4780 SoC support
Add initial support for the Ingenic JZ47xx MIPS SoC. Cc: Daniel Schwierzeck <daniel.schwierzeck@gmail.com> Signed-off-by: Paul Burton <paul.burton@imgtec.com> Signed-off-by: Marek Vasut <marek.vasut@gmail.com> Signed-off-by: Ezequiel Garcia <ezequiel@collabora.com> Reviewed-by: Marek Vasut <marex@denx.de>
Diffstat (limited to 'arch/mips/mach-jz47xx/jz4780')
-rw-r--r--arch/mips/mach-jz47xx/jz4780/Makefile3
-rw-r--r--arch/mips/mach-jz47xx/jz4780/TODO4
-rw-r--r--arch/mips/mach-jz47xx/jz4780/gpio.c39
-rw-r--r--arch/mips/mach-jz47xx/jz4780/jz4780.c83
-rw-r--r--arch/mips/mach-jz47xx/jz4780/pll.c530
-rw-r--r--arch/mips/mach-jz47xx/jz4780/reset.c53
-rw-r--r--arch/mips/mach-jz47xx/jz4780/sdram.c270
-rw-r--r--arch/mips/mach-jz47xx/jz4780/timer.c239
-rw-r--r--arch/mips/mach-jz47xx/jz4780/u-boot-spl.lds50
9 files changed, 1271 insertions, 0 deletions
diff --git a/arch/mips/mach-jz47xx/jz4780/Makefile b/arch/mips/mach-jz47xx/jz4780/Makefile
new file mode 100644
index 0000000000..5b3c354327
--- /dev/null
+++ b/arch/mips/mach-jz47xx/jz4780/Makefile
@@ -0,0 +1,3 @@
+# SPDX-License-Identifier: GPL-2.0+
+
+obj-y := gpio.o jz4780.o pll.o reset.o sdram.o timer.o
diff --git a/arch/mips/mach-jz47xx/jz4780/TODO b/arch/mips/mach-jz47xx/jz4780/TODO
new file mode 100644
index 0000000000..99ad6225b0
--- /dev/null
+++ b/arch/mips/mach-jz47xx/jz4780/TODO
@@ -0,0 +1,4 @@
+- dm gpio driver
+- ethernet driver for the dm9000
+- reduce the hundreds of definitions of register addresses to the ones really needed in assembly or SPL.
+- define the remaining register base addresses as physical addresses and establish a mapping with ioremap_nocache()
diff --git a/arch/mips/mach-jz47xx/jz4780/gpio.c b/arch/mips/mach-jz47xx/jz4780/gpio.c
new file mode 100644
index 0000000000..cee2328ab1
--- /dev/null
+++ b/arch/mips/mach-jz47xx/jz4780/gpio.c
@@ -0,0 +1,39 @@
+// SPDX-License-Identifier: GPL-2.0+
+
+#include <config.h>
+#include <common.h>
+#include <asm/io.h>
+#include <mach/jz4780.h>
+
+int jz47xx_gpio_get_value(unsigned int gpio)
+{
+ void __iomem *gpio_regs = (void __iomem *)GPIO_BASE;
+ int port = gpio / 32;
+ int pin = gpio % 32;
+
+ return readl(gpio_regs + GPIO_PXPIN(port)) & BIT(pin);
+}
+
+void jz47xx_gpio_direction_input(unsigned int gpio)
+{
+ void __iomem *gpio_regs = (void __iomem *)GPIO_BASE;
+ int port = gpio / 32;
+ int pin = gpio % 32;
+
+ writel(BIT(pin), gpio_regs + GPIO_PXINTC(port));
+ writel(BIT(pin), gpio_regs + GPIO_PXMASKS(port));
+ writel(BIT(pin), gpio_regs + GPIO_PXPAT1S(port));
+}
+
+void jz47xx_gpio_direction_output(unsigned int gpio, int value)
+{
+ void __iomem *gpio_regs = (void __iomem *)GPIO_BASE;
+ int port = gpio / 32;
+ int pin = gpio % 32;
+
+ writel(BIT(pin), gpio_regs + GPIO_PXINTC(port));
+ writel(BIT(pin), gpio_regs + GPIO_PXMASKS(port));
+ writel(BIT(pin), gpio_regs + GPIO_PXPAT1C(port));
+ writel(BIT(pin), gpio_regs +
+ (value ? GPIO_PXPAT0S(port) : GPIO_PXPAT0C(port)));
+}
diff --git a/arch/mips/mach-jz47xx/jz4780/jz4780.c b/arch/mips/mach-jz47xx/jz4780/jz4780.c
new file mode 100644
index 0000000000..dbd328cb49
--- /dev/null
+++ b/arch/mips/mach-jz47xx/jz4780/jz4780.c
@@ -0,0 +1,83 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * JZ4780 common routines
+ *
+ * Copyright (c) 2013 Imagination Technologies
+ * Author: Paul Burton <paul.burton@imgtec.com>
+ */
+
+#include <config.h>
+#include <common.h>
+#include <asm/io.h>
+#include <asm/sections.h>
+#include <mach/jz4780.h>
+#include <mach/jz4780_dram.h>
+#include <mmc.h>
+#include <spl.h>
+
+#ifdef CONFIG_SPL_BUILD
+/* Pointer to the global data structure for SPL */
+DECLARE_GLOBAL_DATA_PTR;
+gd_t gdata __attribute__ ((section(".bss")));
+
+void board_init_f(ulong dummy)
+{
+ typedef void __noreturn (*image_entry_noargs_t)(void);
+ struct mmc *mmc;
+ unsigned long count;
+ struct image_header *header;
+ int ret;
+
+ /* Set global data pointer */
+ gd = &gdata;
+
+ timer_init();
+ pll_init();
+ sdram_init();
+ enable_caches();
+
+ /* Clear the BSS */
+ memset(__bss_start, 0, (char *)&__bss_end - __bss_start);
+
+ gd->flags |= GD_FLG_SPL_INIT;
+
+ ret = mmc_initialize(NULL);
+ if (ret)
+ hang();
+
+ mmc = find_mmc_device(BOOT_DEVICE_MMC1);
+ if (ret)
+ hang();
+
+ ret = mmc_init(mmc);
+ if (ret)
+ hang();
+
+ header = (struct image_header *)(CONFIG_SYS_TEXT_BASE -
+ sizeof(struct image_header));
+
+ count = blk_dread(mmc_get_blk_desc(mmc),
+ CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_SECTOR,
+ 0x800, header);
+ if (count == 0)
+ hang();
+
+ image_entry_noargs_t image_entry =
+ (image_entry_noargs_t)CONFIG_SYS_TEXT_BASE;
+
+ image_entry();
+
+ hang();
+}
+#endif /* CONFIG_SPL_BUILD */
+
+ulong board_get_usable_ram_top(ulong total_size)
+{
+ return CONFIG_SYS_SDRAM_BASE + (256 * 1024 * 1024);
+}
+
+int print_cpuinfo(void)
+{
+ printf("CPU: Ingenic JZ4780\n");
+ return 0;
+}
diff --git a/arch/mips/mach-jz47xx/jz4780/pll.c b/arch/mips/mach-jz47xx/jz4780/pll.c
new file mode 100644
index 0000000000..9a46198f36
--- /dev/null
+++ b/arch/mips/mach-jz47xx/jz4780/pll.c
@@ -0,0 +1,530 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * JZ4780 PLL setup
+ *
+ * Copyright (c) 2013 Imagination Technologies
+ * Author: Paul Burton <paul.burton@imgtec.com>
+ */
+
+#include <config.h>
+#include <common.h>
+#include <asm/io.h>
+#include <mach/jz4780.h>
+
+#define CPM_CPCCR 0x00
+#define CPM_LCR 0x04
+#define CPM_RSR 0x08
+#define CPM_CPPCR 0x0c
+#define CPM_CPAPCR 0x10
+#define CPM_CPMPCR 0x14
+#define CPM_CPEPCR 0x18
+#define CPM_CPVPCR 0x1c
+#define CPM_CLKGR0 0x20
+#define CPM_OPCR 0x24
+#define CPM_CLKGR1 0x28
+#define CPM_DDCDR 0x2c
+#define CPM_VPUCDR 0x30
+#define CPM_CPSPR 0x34
+#define CPM_CPSPPR 0x38
+#define CPM_USBPCR 0x3c
+#define CPM_USBRDT 0x40
+#define CPM_USBVBFIL 0x44
+#define CPM_USBPCR1 0x48
+#define CPM_USBCDR 0x50
+#define CPM_LPCDR 0x54
+#define CPM_I2SCDR 0x60
+#define CPM_LPCDR1 0x64
+#define CPM_MSCCDR 0x68
+#define CPM_UHCCDR 0x6c
+#define CPM_SSICDR 0x74
+#define CPM_CIMCDR 0x7c
+#define CPM_PCMCDR 0x84
+#define CPM_GPUCDR 0x88
+#define CPM_HDMICDR 0x8c
+#define CPM_I2S1CDR 0xa0
+#define CPM_MSCCDR1 0xa4
+#define CPM_MSCCDR2 0xa8
+#define CPM_BCHCDR 0xac
+#define CPM_SPCR0 0xb8
+#define CPM_SPCR1 0xbc
+#define CPM_CPCSR 0xd4
+#define CPM_PSWCST(n) ((0x4 * (n)) + 0x90)
+
+/* Clock control register */
+#define CPM_CPCCR_SEL_SRC_BIT 30
+#define CPM_CPCCR_SEL_SRC_MASK (0x3 << CPM_CPCCR_SEL_SRC_BIT)
+#define CPM_SRC_SEL_STOP 0
+#define CPM_SRC_SEL_APLL 1
+#define CPM_SRC_SEL_EXCLK 2
+#define CPM_SRC_SEL_RTCLK 3
+#define CPM_CPCCR_SEL_CPLL_BIT 28
+#define CPM_CPCCR_SEL_CPLL_MASK (0x3 << CPM_CPCCR_SEL_CPLL_BIT)
+#define CPM_CPCCR_SEL_H0PLL_BIT 26
+#define CPM_CPCCR_SEL_H0PLL_MASK (0x3 << CPM_CPCCR_SEL_H0PLL_BIT)
+#define CPM_CPCCR_SEL_H2PLL_BIT 24
+#define CPM_CPCCR_SEL_H2PLL_MASK (0x3 << CPM_CPCCR_SEL_H2PLL_BIT)
+#define CPM_PLL_SEL_STOP 0
+#define CPM_PLL_SEL_SRC 1
+#define CPM_PLL_SEL_MPLL 2
+#define CPM_PLL_SEL_EPLL 3
+#define CPM_CPCCR_CE_CPU (0x1 << 22)
+#define CPM_CPCCR_CE_AHB0 (0x1 << 21)
+#define CPM_CPCCR_CE_AHB2 (0x1 << 20)
+#define CPM_CPCCR_PDIV_BIT 16
+#define CPM_CPCCR_PDIV_MASK (0xf << CPM_CPCCR_PDIV_BIT)
+#define CPM_CPCCR_H2DIV_BIT 12
+#define CPM_CPCCR_H2DIV_MASK (0xf << CPM_CPCCR_H2DIV_BIT)
+#define CPM_CPCCR_H0DIV_BIT 8
+#define CPM_CPCCR_H0DIV_MASK (0x0f << CPM_CPCCR_H0DIV_BIT)
+#define CPM_CPCCR_L2DIV_BIT 4
+#define CPM_CPCCR_L2DIV_MASK (0x0f << CPM_CPCCR_L2DIV_BIT)
+#define CPM_CPCCR_CDIV_BIT 0
+#define CPM_CPCCR_CDIV_MASK (0x0f << CPM_CPCCR_CDIV_BIT)
+
+/* Clock Status register */
+#define CPM_CPCSR_H2DIV_BUSY BIT(2)
+#define CPM_CPCSR_H0DIV_BUSY BIT(1)
+#define CPM_CPCSR_CDIV_BUSY BIT(0)
+
+/* PLL control register */
+#define CPM_CPPCR_PLLST_BIT 0
+#define CPM_CPPCR_PLLST_MASK (0xff << CPM_CPPCR_PLLST_BIT)
+
+/* XPLL control register */
+#define CPM_CPXPCR_XPLLM_BIT 19
+#define CPM_CPXPCR_XPLLM_MASK (0x1fff << CPM_CPXPCR_XPLLM_BIT)
+#define CPM_CPXPCR_XPLLN_BIT 13
+#define CPM_CPXPCR_XPLLN_MASK (0x3f << CPM_CPXPCR_XPLLN_BIT)
+#define CPM_CPXPCR_XPLLOD_BIT 9
+#define CPM_CPXPCR_XPLLOD_MASK (0xf << CPM_CPXPCR_XPLLOD_BIT)
+#define CPM_CPXPCR_XLOCK BIT(6)
+#define CPM_CPXPCR_XPLL_ON BIT(4)
+#define CPM_CPXPCR_XF_MODE BIT(3)
+#define CPM_CPXPCR_XPLLBP BIT(1)
+#define CPM_CPXPCR_XPLLEN BIT(0)
+
+/* CPM scratch protected register */
+#define CPM_CPSPPR_BIT 0
+#define CPM_CPSPPR_MASK (0xffff << CPM_CPSPPR_BIT)
+
+/* USB parameter control register */
+#define CPM_USBPCR_USB_MODE BIT(31) /* 1: OTG, 0: UDC*/
+#define CPM_USBPCR_AVLD_REG BIT(30)
+#define CPM_USBPCR_IDPULLUP_MASK_BIT 28
+#define CPM_USBPCR_IDPULLUP_MASK_MASK (0x02 << IDPULLUP_MASK_BIT)
+#define CPM_USBPCR_INCR_MASK BIT(27)
+#define CPM_USBPCR_CLK12_EN BIT(26)
+#define CPM_USBPCR_COMMONONN BIT(25)
+#define CPM_USBPCR_VBUSVLDEXT BIT(24)
+#define CPM_USBPCR_VBUSVLDEXTSEL BIT(23)
+#define CPM_USBPCR_POR BIT(22)
+#define CPM_USBPCR_SIDDQ BIT(21)
+#define CPM_USBPCR_OTG_DISABLE BIT(20)
+#define CPM_USBPCR_COMPDISTUNE_BIT 17
+#define CPM_USBPCR_COMPDISTUNE_MASK (0x07 << COMPDISTUNE_BIT)
+#define CPM_USBPCR_OTGTUNE_BIT 14
+#define CPM_USBPCR_OTGTUNE_MASK (0x07 << OTGTUNE_BIT)
+#define CPM_USBPCR_SQRXTUNE_BIT 11
+#define CPM_USBPCR_SQRXTUNE_MASK (0x7x << SQRXTUNE_BIT)
+#define CPM_USBPCR_TXFSLSTUNE_BIT 7
+#define CPM_USBPCR_TXFSLSTUNE_MASK (0x0f << TXFSLSTUNE_BIT)
+#define CPM_USBPCR_TXPREEMPHTUNE BIT(6)
+#define CPM_USBPCR_TXRISETUNE_BIT 4
+#define CPM_USBPCR_TXRISETUNE_MASK (0x03 << TXRISETUNE_BIT)
+#define CPM_USBPCR_TXVREFTUNE_BIT 0
+#define CPM_USBPCR_TXVREFTUNE_MASK (0x0f << TXVREFTUNE_BIT)
+
+/* DDR memory clock divider register */
+#define CPM_DDRCDR_DCS_BIT 30
+#define CPM_DDRCDR_DCS_MASK (0x3 << CPM_DDRCDR_DCS_BIT)
+#define CPM_DDRCDR_DCS_STOP (0x0 << CPM_DDRCDR_DCS_BIT)
+#define CPM_DDRCDR_DCS_SRC (0x1 << CPM_DDRCDR_DCS_BIT)
+#define CPM_DDRCDR_DCS_MPLL (0x2 << CPM_DDRCDR_DCS_BIT)
+#define CPM_DDRCDR_CE_DDR BIT(29)
+#define CPM_DDRCDR_DDR_BUSY BIT(28)
+#define CPM_DDRCDR_DDR_STOP BIT(27)
+#define CPM_DDRCDR_DDRDIV_BIT 0
+#define CPM_DDRCDR_DDRDIV_MASK (0xf << CPM_DDRCDR_DDRDIV_BIT)
+
+/* USB reset detect timer register */
+#define CPM_USBRDT_VBFIL_LD_EN BIT(25)
+#define CPM_USBRDT_IDDIG_EN BIT(24)
+#define CPM_USBRDT_IDDIG_REG BIT(23)
+#define CPM_USBRDT_USBRDT_BIT 0
+#define CPM_USBRDT_USBRDT_MASK (0x7fffff << CPM_USBRDT_USBRDT_BIT)
+
+/* USB OTG PHY clock divider register */
+#define CPM_USBCDR_UCS BIT(31)
+#define CPM_USBCDR_UPCS BIT(30)
+#define CPM_USBCDR_CEUSB BIT(29)
+#define CPM_USBCDR_USB_BUSY BIT(28)
+#define CPM_USBCDR_OTGDIV_BIT 0
+#define CPM_USBCDR_OTGDIV_MASK (0xff << CPM_USBCDR_OTGDIV_BIT)
+
+/* I2S device clock divider register */
+#define CPM_I2SCDR_I2CS BIT(31)
+#define CPM_I2SCDR_I2PCS BIT(30)
+#define CPM_I2SCDR_I2SDIV_BIT 0
+#define CPM_I2SCDR_I2SDIV_MASK (0x1ff << CPM_I2SCDR_I2SDIV_BIT)
+
+/* LCD0 pix clock divider register */
+#define CPM_LPCDR_LPCS_BIT 30
+#define CPM_LPCDR_LPCS_MASK (0x3 << CPM_LPCDR_LPCS_BIT)
+#define CPM_LPCDR_CELCD BIT(28)
+#define CPM_LPCDR_LCD_BUSY BIT(27)
+#define CPM_LPCDR_LCD_STOP BIT(26)
+#define CPM_LPCDR_PIXDIV_BIT 0
+#define CPM_LPCDR_PIXDIV_MASK (0xff << CPM_LPCDR_PIXDIV_BIT)
+
+/* MSC clock divider register */
+#define CPM_MSCCDR_MPCS_BIT 30
+#define CPM_MSCCDR_MPCS_MASK (3 << CPM_MSCCDR_MPCS_BIT)
+#define CPM_MSCCDR_MPCS_STOP (0x0 << CPM_MSCCDR_MPCS_BIT)
+#define CPM_MSCCDR_MPCS_SRC (0x1 << CPM_MSCCDR_MPCS_BIT)
+#define CPM_MSCCDR_MPCS_MPLL (0x2 << CPM_MSCCDR_MPCS_BIT)
+#define CPM_MSCCDR_CE BIT(29)
+#define CPM_MSCCDR_MSC_BUSY BIT(28)
+#define CPM_MSCCDR_MSC_STOP BIT(27)
+#define CPM_MSCCDR_MSC_CLK0_SEL BIT(15)
+#define CPM_MSCCDR_MSCDIV_BIT 0
+#define CPM_MSCCDR_MSCDIV_MASK (0xff << CPM_MSCCDR_MSCDIV_BIT)
+
+/* UHC 48M clock divider register */
+#define CPM_UHCCDR_UHCS_BIT 30
+#define CPM_UHCCDR_UHCS_MASK (0x3 << CPM_UHCCDR_UHCS_BIT)
+#define CPM_UHCCDR_UHCS_SRC (0x0 << CPM_UHCCDR_UHCS_BIT)
+#define CPM_UHCCDR_UHCS_MPLL (0x1 << CPM_UHCCDR_UHCS_BIT)
+#define CPM_UHCCDR_UHCS_EPLL (0x2 << CPM_UHCCDR_UHCS_BIT)
+#define CPM_UHCCDR_UHCS_OTG (0x3 << CPM_UHCCDR_UHCS_BIT)
+#define CPM_UHCCDR_CE_UHC BIT(29)
+#define CPM_UHCCDR_UHC_BUSY BIT(28)
+#define CPM_UHCCDR_UHC_STOP BIT(27)
+#define CPM_UHCCDR_UHCDIV_BIT 0
+#define CPM_UHCCDR_UHCDIV_MASK (0xff << CPM_UHCCDR_UHCDIV_BIT)
+
+/* SSI clock divider register */
+#define CPM_SSICDR_SCS BIT(31)
+#define CPM_SSICDR_SSIDIV_BIT 0
+#define CPM_SSICDR_SSIDIV_MASK (0x3f << CPM_SSICDR_SSIDIV_BIT)
+
+/* CIM MCLK clock divider register */
+#define CPM_CIMCDR_CIMDIV_BIT 0
+#define CPM_CIMCDR_CIMDIV_MASK (0xff << CPM_CIMCDR_CIMDIV_BIT)
+
+/* GPS clock divider register */
+#define CPM_GPSCDR_GPCS BIT(31)
+#define CPM_GPSCDR_GPSDIV_BIT 0
+#define CPM_GSPCDR_GPSDIV_MASK (0xf << CPM_GPSCDR_GPSDIV_BIT)
+
+/* PCM device clock divider register */
+#define CPM_PCMCDR_PCMS BIT(31)
+#define CPM_PCMCDR_PCMPCS BIT(30)
+#define CPM_PCMCDR_PCMDIV_BIT 0
+#define CPM_PCMCDR_PCMDIV_MASK (0x1ff << CPM_PCMCDR_PCMDIV_BIT)
+
+/* GPU clock divider register */
+#define CPM_GPUCDR_GPCS BIT(31)
+#define CPM_GPUCDR_GPUDIV_BIT 0
+#define CPM_GPUCDR_GPUDIV_MASK (0x7 << CPM_GPUCDR_GPUDIV_BIT)
+
+/* HDMI clock divider register */
+#define CPM_HDMICDR_HPCS_BIT 30
+#define CPM_HDMICDR_HPCS_MASK (0x3 << CPM_HDMICDR_HPCS_BIT)
+#define CPM_HDMICDR_CEHDMI BIT(29)
+#define CPM_HDMICDR_HDMI_BUSY BIT(28)
+#define CPM_HDMICDR_HDMI_STOP BIT(26)
+#define CPM_HDMICDR_HDMIDIV_BIT 0
+#define CPM_HDMICDR_HDMIDIV_MASK (0xff << CPM_HDMICDR_HDMIDIV_BIT)
+
+/* Low Power Control Register */
+#define CPM_LCR_PD_SCPU BIT(31)
+#define CPM_LCR_PD_VPU BIT(30)
+#define CPM_LCR_PD_GPU BIT(29)
+#define CPM_LCR_PD_GPS BIT(28)
+#define CPM_LCR_SCPUS BIT(27)
+#define CPM_LCR_VPUS BIT(26)
+#define CPM_LCR_GPUS BIT(25)
+#define CPM_LCR_GPSS BIT(24)
+#define CPM_LCR_GPU_IDLE BIT(20)
+#define CPM_LCR_PST_BIT 8
+#define CPM_LCR_PST_MASK (0xfff << CPM_LCR_PST_BIT)
+#define CPM_LCR_DOZE_DUTY_BIT 3
+#define CPM_LCR_DOZE_DUTY_MASK (0x1f << CPM_LCR_DOZE_DUTY_BIT)
+#define CPM_LCR_DOZE_ON BIT(2)
+#define CPM_LCR_LPM_BIT 0
+#define CPM_LCR_LPM_MASK (0x3 << CPM_LCR_LPM_BIT)
+#define CPM_LCR_LPM_IDLE (0x0 << CPM_LCR_LPM_BIT)
+#define CPM_LCR_LPM_SLEEP (0x1 << CPM_LCR_LPM_BIT)
+
+/* Clock Gate Register0 */
+#define CPM_CLKGR0_DDR1 BIT(31)
+#define CPM_CLKGR0_DDR0 BIT(30)
+#define CPM_CLKGR0_IPU BIT(29)
+#define CPM_CLKGR0_LCD1 BIT(28)
+#define CPM_CLKGR0_LCD BIT(27)
+#define CPM_CLKGR0_CIM BIT(26)
+#define CPM_CLKGR0_I2C2 BIT(25)
+#define CPM_CLKGR0_UHC BIT(24)
+#define CPM_CLKGR0_MAC BIT(23)
+#define CPM_CLKGR0_GPS BIT(22)
+#define CPM_CLKGR0_PDMAC BIT(21)
+#define CPM_CLKGR0_SSI2 BIT(20)
+#define CPM_CLKGR0_SSI1 BIT(19)
+#define CPM_CLKGR0_UART3 BIT(18)
+#define CPM_CLKGR0_UART2 BIT(17)
+#define CPM_CLKGR0_UART1 BIT(16)
+#define CPM_CLKGR0_UART0 BIT(15)
+#define CPM_CLKGR0_SADC BIT(14)
+#define CPM_CLKGR0_KBC BIT(13)
+#define CPM_CLKGR0_MSC2 BIT(12)
+#define CPM_CLKGR0_MSC1 BIT(11)
+#define CPM_CLKGR0_OWI BIT(10)
+#define CPM_CLKGR0_TSSI BIT(9)
+#define CPM_CLKGR0_AIC BIT(8)
+#define CPM_CLKGR0_SCC BIT(7)
+#define CPM_CLKGR0_I2C1 BIT(6)
+#define CPM_CLKGR0_I2C0 BIT(5)
+#define CPM_CLKGR0_SSI0 BIT(4)
+#define CPM_CLKGR0_MSC0 BIT(3)
+#define CPM_CLKGR0_OTG BIT(2)
+#define CPM_CLKGR0_BCH BIT(1)
+#define CPM_CLKGR0_NEMC BIT(0)
+
+/* Clock Gate Register1 */
+#define CPM_CLKGR1_P1 BIT(15)
+#define CPM_CLKGR1_X2D BIT(14)
+#define CPM_CLKGR1_DES BIT(13)
+#define CPM_CLKGR1_I2C4 BIT(12)
+#define CPM_CLKGR1_AHB BIT(11)
+#define CPM_CLKGR1_UART4 BIT(10)
+#define CPM_CLKGR1_HDMI BIT(9)
+#define CPM_CLKGR1_OTG1 BIT(8)
+#define CPM_CLKGR1_GPVLC BIT(7)
+#define CPM_CLKGR1_AIC1 BIT(6)
+#define CPM_CLKGR1_COMPRES BIT(5)
+#define CPM_CLKGR1_GPU BIT(4)
+#define CPM_CLKGR1_PCM BIT(3)
+#define CPM_CLKGR1_VPU BIT(2)
+#define CPM_CLKGR1_TSSI1 BIT(1)
+#define CPM_CLKGR1_I2C3 BIT(0)
+
+/* Oscillator and Power Control Register */
+#define CPM_OPCR_O1ST_BIT 8
+#define CPM_OPCR_O1ST_MASK (0xff << CPM_OPCR_O1ST_BIT)
+#define CPM_OPCR_SPENDN BIT(7)
+#define CPM_OPCR_GPSEN BIT(6)
+#define CPM_OPCR_SPENDH BIT(5)
+#define CPM_OPCR_O1SE BIT(4)
+#define CPM_OPCR_ERCS BIT(2) /* 0: select EXCLK/512 clock, 1: RTCLK clock */
+#define CPM_OPCR_USBM BIT(0) /* 0: select EXCLK/512 clock, 1: RTCLK clock */
+
+/* Reset Status Register */
+#define CPM_RSR_P0R BIT(2)
+#define CPM_RSR_WR BIT(1)
+#define CPM_RSR_PR BIT(0)
+
+/* BCH clock divider register */
+#define CPM_BCHCDR_BPCS_BIT 30
+#define CPM_BCHCDR_BPCS_MASK (0x3 << CPM_BCHCDR_BPCS_BIT)
+#define CPM_BCHCDR_BPCS_STOP (0X0 << CPM_BCHCDR_BPCS_BIT)
+#define CPM_BCHCDR_BPCS_SRC_CLK (0x1 << CPM_BCHCDR_BPCS_BIT)
+#define CPM_BCHCDR_BPCS_MPLL (0x2 << CPM_BCHCDR_BPCS_BIT)
+#define CPM_BCHCDR_BPCS_EPLL (0x3 << CPM_BCHCDR_BPCS_BIT)
+#define CPM_BCHCDR_CE_BCH BIT(29)
+#define CPM_BCHCDR_BCH_BUSY BIT(28)
+#define CPM_BCHCDR_BCH_STOP BIT(27)
+#define CPM_BCHCDR_BCHCDR_BIT 0
+#define CPM_BCHCDR_BCHCDR_MASK (0x7 << CPM_BCHCDR_BCHCDR_BIT)
+
+/* CPM scratch pad protected register(CPSPPR) */
+#define CPSPPR_CPSPR_WRITABLE 0x00005a5a
+#define RECOVERY_SIGNATURE 0x1a1a /* means "RECY" */
+#define RECOVERY_SIGNATURE_SEC 0x800 /* means "RECY" */
+
+#define REBOOT_SIGNATURE 0x3535 /* means reboot */
+
+/* XPLL control register */
+#define XLOCK (1 << 6)
+#define XPLL_ON (1 << 4)
+#define XF_MODE (1 << 3)
+#define XPLLBP (1 << 1)
+#define XPLLEN (1 << 0)
+
+enum PLLS {
+ EXTCLK = 0,
+ APLL,
+ MPLL,
+ EPLL,
+ VPLL,
+};
+
+#define M_N_OD(m, n, od) \
+ ((((m) - 1) << 19) | (((n) - 1) << 13) | (((od) - 1) << 9))
+
+struct cgu_pll_select {
+ u8 reg;
+ u8 pll;
+ u8 pll_shift;
+};
+
+static void pll_init_one(int pll, int m, int n, int od)
+{
+ void __iomem *cpm_regs = (void __iomem *)CPM_BASE;
+ void __iomem *pll_reg = cpm_regs + CPM_CPAPCR + ((pll - 1) * 4);
+
+ setbits_le32(pll_reg, M_N_OD(m, n, od) | XPLLEN);
+
+ /* FIXME */
+ while (!(readl(pll_reg) & XPLL_ON))
+ ;
+}
+
+static void cpu_mux_select(int pll)
+{
+ void __iomem *cpm_regs = (void __iomem *)CPM_BASE;
+ u32 clk_ctrl;
+ unsigned int selectplls[] = {
+ CPM_PLL_SEL_STOP,
+ CPM_PLL_SEL_SRC,
+ CPM_PLL_SEL_MPLL,
+ CPM_PLL_SEL_EPLL
+ };
+
+ /* Init CPU, L2CACHE, AHB0, AHB2, APB clock */
+ clk_ctrl = CPM_CPCCR_CE_CPU | CPM_CPCCR_CE_AHB0 | CPM_CPCCR_CE_AHB2 |
+ ((6 - 1) << CPM_CPCCR_H2DIV_BIT) |
+ ((3 - 1) << CPM_CPCCR_H0DIV_BIT) |
+ ((2 - 1) << CPM_CPCCR_L2DIV_BIT) |
+ ((1 - 1) << CPM_CPCCR_CDIV_BIT);
+
+ if (CONFIG_SYS_MHZ >= 1000)
+ clk_ctrl |= (12 - 1) << CPM_CPCCR_PDIV_BIT;
+ else
+ clk_ctrl |= (6 - 1) << CPM_CPCCR_PDIV_BIT;
+
+ clrsetbits_le32(cpm_regs + CPM_CPCCR, 0x00ffffff, clk_ctrl);
+
+ while (readl(cpm_regs + CPM_CPCSR) & (CPM_CPCSR_CDIV_BUSY |
+ CPM_CPCSR_H0DIV_BUSY | CPM_CPCSR_H2DIV_BUSY))
+ ;
+
+ clk_ctrl = (selectplls[pll] << CPM_CPCCR_SEL_CPLL_BIT) |
+ (selectplls[MPLL] << CPM_CPCCR_SEL_H0PLL_BIT) |
+ (selectplls[MPLL] << CPM_CPCCR_SEL_H2PLL_BIT);
+ if (pll == APLL)
+ clk_ctrl |= CPM_PLL_SEL_SRC << CPM_CPCCR_SEL_SRC_BIT;
+ else
+ clk_ctrl |= CPM_SRC_SEL_EXCLK << CPM_CPCCR_SEL_SRC_BIT;
+
+ clrsetbits_le32(cpm_regs + CPM_CPCCR, 0xff << 24, clk_ctrl);
+}
+
+static void ddr_mux_select(int pll)
+{
+ void __iomem *cpm_regs = (void __iomem *)CPM_BASE;
+ int selectplls[] = { CPM_DDRCDR_DCS_STOP,
+ CPM_DDRCDR_DCS_SRC,
+ CPM_DDRCDR_DCS_MPLL};
+
+ writel(selectplls[pll] | CPM_DDRCDR_CE_DDR | (JZ4780_SYS_MEM_DIV - 1),
+ cpm_regs + CPM_DDCDR);
+
+ while (readl(cpm_regs + CPM_DDCDR) & CPM_DDRCDR_DDR_BUSY)
+ ;
+
+ clrbits_le32(cpm_regs + CPM_CLKGR0, CPM_CLKGR0_DDR0);
+
+ mdelay(200);
+}
+
+static void cgu_mux_init(struct cgu_pll_select *cgu, unsigned int num)
+{
+ void __iomem *cpm_regs = (void __iomem *)CPM_BASE;
+ unsigned int selectplls[] = {0, 1, 2, 3, 2, 6};
+ int i;
+
+ for (i = 0; i < num; i++)
+ writel(selectplls[cgu[i].pll] << cgu[i].pll_shift,
+ cpm_regs + cgu[i].reg);
+}
+
+void pll_init(void)
+{
+ void __iomem *cpm_regs = (void __iomem *)CPM_BASE;
+ struct cgu_pll_select cgu_mux[] = {
+ { CPM_MSCCDR, MPLL, 30 },
+ { CPM_LPCDR, VPLL, 30 },
+ { CPM_LPCDR1, VPLL, 30 },
+ { CPM_GPUCDR, MPLL, 30 },
+ { CPM_HDMICDR, VPLL, 30 },
+ { CPM_I2SCDR, EPLL, 30 },
+ { CPM_BCHCDR, MPLL, 30 },
+ { CPM_VPUCDR, 0x1, 30 },
+ { CPM_UHCCDR, 0x3, 30 },
+ { CPM_CIMCDR, 0x1, 31 },
+ { CPM_PCMCDR, 0x5, 29 },
+ { CPM_SSICDR, 0x3, 30 },
+ };
+
+ /* PLL stable time set to default -- 1ms */
+ clrsetbits_le32(cpm_regs + CPM_CPPCR, 0xfffff, (16 << 8) | 0x20);
+
+ pll_init_one(APLL, JZ4780_APLL_M, JZ4780_APLL_N, JZ4780_APLL_OD);
+ pll_init_one(MPLL, JZ4780_MPLL_M, JZ4780_MPLL_N, JZ4780_MPLL_OD);
+ pll_init_one(VPLL, JZ4780_VPLL_M, JZ4780_VPLL_N, JZ4780_VPLL_OD);
+ pll_init_one(EPLL, JZ4780_EPLL_M, JZ4780_EPLL_N, JZ4780_EPLL_OD);
+
+ cpu_mux_select(MPLL);
+ ddr_mux_select(MPLL);
+ cgu_mux_init(cgu_mux, ARRAY_SIZE(cgu_mux));
+}
+
+const u32 jz4780_clk_get_efuse_clk(void)
+{
+ void __iomem *cpm_regs = (void __iomem *)CPM_BASE;
+ u32 cpccr = readl(cpm_regs + CPM_CPCCR);
+ u32 ahb2_div = ((cpccr & CPM_CPCCR_H2DIV_MASK) >>
+ CPM_CPCCR_H2DIV_BIT) + 1;
+ return JZ4780_SYS_MEM_SPEED / ahb2_div;
+}
+
+void jz4780_clk_ungate_ethernet(void)
+{
+ void __iomem *cpm_regs = (void __iomem *)CPM_BASE;
+
+ clrbits_le32(cpm_regs + CPM_CLKGR0, CPM_CLKGR0_MAC);
+ clrbits_le32(cpm_regs + CPM_CLKGR0, CPM_CLKGR0_NEMC);
+}
+
+void jz4780_clk_ungate_mmc(void)
+{
+ void __iomem *cpm_regs = (void __iomem *)CPM_BASE;
+ u32 msc_cdr = JZ4780_SYS_MEM_SPEED / 24000000 / 2 - 1;
+
+ msc_cdr |= CPM_MSCCDR_MPCS_MPLL | CPM_MSCCDR_CE;
+ writel(msc_cdr, cpm_regs + CPM_MSCCDR);
+ writel(msc_cdr, cpm_regs + CPM_MSCCDR1);
+ writel(msc_cdr, cpm_regs + CPM_MSCCDR2);
+
+ /* The wait_for_bit() won't fit, thus unbounded loop here. */
+ while (readl(cpm_regs + CPM_MSCCDR1) & CPM_MSCCDR_MSC_BUSY)
+ ;
+}
+
+void jz4780_clk_ungate_uart(const unsigned int uart)
+{
+ void __iomem *cpm_regs = (void __iomem *)CPM_BASE;
+
+ if (uart == 0)
+ clrbits_le32(cpm_regs + CPM_CLKGR0, CPM_CLKGR0_UART0);
+ else if (uart == 1)
+ clrbits_le32(cpm_regs + CPM_CLKGR0, CPM_CLKGR0_UART1);
+ else if (uart == 2)
+ clrbits_le32(cpm_regs + CPM_CLKGR0, CPM_CLKGR0_UART2);
+ else if (uart == 3)
+ clrbits_le32(cpm_regs + CPM_CLKGR0, CPM_CLKGR0_UART3);
+ else if (uart == 4)
+ clrbits_le32(cpm_regs + CPM_CLKGR1, CPM_CLKGR1_UART4);
+ else
+ printf("%s[%i]: Invalid UART %d\n", __func__, __LINE__, uart);
+}
diff --git a/arch/mips/mach-jz47xx/jz4780/reset.c b/arch/mips/mach-jz47xx/jz4780/reset.c
new file mode 100644
index 0000000000..73af34721f
--- /dev/null
+++ b/arch/mips/mach-jz47xx/jz4780/reset.c
@@ -0,0 +1,53 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * JZ4780 common routines
+ *
+ * Copyright (c) 2013 Imagination Technologies
+ * Author: Paul Burton <paul.burton@imgtec.com>
+ */
+
+#include <config.h>
+#include <common.h>
+#include <asm/io.h>
+#include <mach/jz4780.h>
+
+/* WDT */
+#define WDT_TDR 0x00
+#define WDT_TCER 0x04
+#define WDT_TCNT 0x08
+#define WDT_TCSR 0x0C
+
+/* Register definition */
+#define WDT_TCSR_PRESCALE_BIT 3
+#define WDT_TCSR_PRESCALE_MASK (0x7 << WDT_TCSR_PRESCALE_BIT)
+ #define WDT_TCSR_PRESCALE1 (0x0 << WDT_TCSR_PRESCALE_BIT)
+ #define WDT_TCSR_PRESCALE4 (0x1 << WDT_TCSR_PRESCALE_BIT)
+ #define WDT_TCSR_PRESCALE16 (0x2 << WDT_TCSR_PRESCALE_BIT)
+ #define WDT_TCSR_PRESCALE64 (0x3 << WDT_TCSR_PRESCALE_BIT)
+ #define WDT_TCSR_PRESCALE256 (0x4 << WDT_TCSR_PRESCALE_BIT)
+ #define WDT_TCSR_PRESCALE1024 (0x5 << WDT_TCSR_PRESCALE_BIT)
+#define WDT_TCSR_EXT_EN BIT(2)
+#define WDT_TCSR_RTC_EN BIT(1)
+#define WDT_TCSR_PCK_EN BIT(0)
+
+#define WDT_TCER_TCEN BIT(0)
+
+void _machine_restart(void)
+{
+ void __iomem *wdt_regs = (void __iomem *)WDT_BASE;
+
+ /* EXTAL as the timer clock input. */
+ writew(WDT_TCSR_PRESCALE1 | WDT_TCSR_EXT_EN, wdt_regs + WDT_TCSR);
+
+ /* Reset the WDT counter and timeout. */
+ writew(0, wdt_regs + WDT_TCNT);
+ writew(0, wdt_regs + WDT_TDR);
+
+ jz4780_tcu_wdt_start();
+
+ /* WDT start */
+ writeb(WDT_TCER_TCEN, wdt_regs + WDT_TCER);
+
+ for (;;)
+ ;
+}
diff --git a/arch/mips/mach-jz47xx/jz4780/sdram.c b/arch/mips/mach-jz47xx/jz4780/sdram.c
new file mode 100644
index 0000000000..5b25c8d002
--- /dev/null
+++ b/arch/mips/mach-jz47xx/jz4780/sdram.c
@@ -0,0 +1,270 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * JZ4780 DDR initialization
+ *
+ * Copyright (c) 2013 Imagination Technologies
+ * Author: Paul Burton <paul.burton@imgtec.com>
+ *
+ * Based on spl/common/{jz4780_ddr,jz_ddr3_init}.c from X-Boot
+ * Copyright (c) 2006-2013 Ingenic Semiconductor
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <mach/jz4780.h>
+#include <mach/jz4780_dram.h>
+
+static const u32 get_mem_clk(void)
+{
+ const u32 mpll_out = ((u64)JZ4780_SYS_EXTAL * JZ4780_MPLL_M) /
+ (JZ4780_MPLL_N * JZ4780_MPLL_OD);
+ return mpll_out / JZ4780_SYS_MEM_DIV;
+}
+
+u32 sdram_size(int cs)
+{
+ u32 dw = DDR_DW32 ? 4 : 2;
+ u32 banks = DDR_BANK8 ? 8 : 4;
+ u32 size = 0;
+
+ if ((cs == 0) && DDR_CS0EN) {
+ size = (1 << (DDR_ROW + DDR_COL)) * dw * banks;
+ if (DDR_CS1EN && (size > 0x20000000))
+ size = 0x20000000;
+ } else if ((cs == 1) && DDR_CS1EN) {
+ size = (1 << (DDR_ROW + DDR_COL)) * dw * banks;
+ }
+
+ return size;
+}
+
+static void ddr_cfg_init(void)
+{
+ void __iomem *ddr_ctl_regs = (void __iomem *)DDRC_BASE;
+ u32 ddrc_cfg, tmp;
+
+ tmp = DDR_CL;
+ if (tmp)
+ tmp--;
+ if (tmp > 4)
+ tmp = 4;
+
+ ddrc_cfg = DDRC_CFG_TYPE_DDR3 | DDRC_CFG_IMBA |
+ DDR_DW32 | DDRC_CFG_MPRT | ((tmp | 0x8) << 2) |
+ ((DDR_ROW - 12) << 11) | ((DDR_COL - 8) << 8) |
+ (DDR_CS0EN << 6) | (DDR_BANK8 << 1) |
+ ((DDR_ROW - 12) << 27) | ((DDR_COL - 8) << 24) |
+ (DDR_CS1EN << 7) | (DDR_BANK8 << 23);
+
+ if (DDR_BL > 4)
+ ddrc_cfg |= BIT(21);
+
+ writel(ddrc_cfg, ddr_ctl_regs + DDRC_CFG);
+}
+
+static void ddr_phy_init(const struct jz4780_ddr_config *ddr_config)
+{
+ void __iomem *ddr_ctl_regs = (void __iomem *)DDRC_BASE;
+ void __iomem *ddr_phy_regs = ddr_ctl_regs + DDR_PHY_OFFSET;
+ unsigned int count = 0, i;
+ u32 reg, mask;
+
+ writel(DDRP_DCR_TYPE_DDR3 | (DDR_BANK8 << 3), ddr_phy_regs + DDRP_DCR);
+
+ writel(ddr_config->mr0, ddr_phy_regs + DDRP_MR0);
+ writel(ddr_config->mr1, ddr_phy_regs + DDRP_MR1);
+ writel(0, ddr_phy_regs + DDRP_ODTCR);
+ writel(0, ddr_phy_regs + DDRP_MR2);
+
+ writel(ddr_config->ptr0, ddr_phy_regs + DDRP_PTR0);
+ writel(ddr_config->ptr1, ddr_phy_regs + DDRP_PTR1);
+ writel(ddr_config->ptr2, ddr_phy_regs + DDRP_PTR2);
+
+ writel(ddr_config->dtpr0, ddr_phy_regs + DDRP_DTPR0);
+ writel(ddr_config->dtpr1, ddr_phy_regs + DDRP_DTPR1);
+ writel(ddr_config->dtpr2, ddr_phy_regs + DDRP_DTPR2);
+
+ writel(DDRP_PGCR_DQSCFG | (7 << DDRP_PGCR_CKEN_BIT) |
+ (2 << DDRP_PGCR_CKDV_BIT) |
+ (DDR_CS0EN | (DDR_CS1EN << 1)) << DDRP_PGCR_RANKEN_BIT |
+ DDRP_PGCR_ZCKSEL_32 | DDRP_PGCR_PDDISDX,
+ ddr_phy_regs + DDRP_PGCR);
+
+ for (i = 0; i < 8; i++)
+ clrbits_le32(ddr_phy_regs + DDRP_DXGCR(i), 0x3 << 9);
+
+ count = 0;
+ mask = DDRP_PGSR_IDONE | DDRP_PGSR_DLDONE | DDRP_PGSR_ZCDONE;
+ for (;;) {
+ reg = readl(ddr_phy_regs + DDRP_PGSR);
+ if ((reg == mask) || (reg == 0x1f))
+ break;
+ if (count++ == 10000)
+ hang();
+ }
+
+ /* DQS extension and early set to 1 */
+ clrsetbits_le32(ddr_phy_regs + DDRP_DSGCR, 0x7E << 4, 0x12 << 4);
+
+ /* 500 pull up and 500 pull down */
+ clrsetbits_le32(ddr_phy_regs + DDRP_DXCCR, 0xFF << 4, 0xC4 << 4);
+
+ /* Initialise phy */
+ writel(DDRP_PIR_INIT | DDRP_PIR_DRAMINT | DDRP_PIR_DRAMRST,
+ ddr_phy_regs + DDRP_PIR);
+
+ count = 0;
+ mask |= DDRP_PGSR_DIDONE;
+ for (;;) {
+ reg = readl(ddr_phy_regs + DDRP_PGSR);
+ if ((reg == mask) || (reg == 0x1f))
+ break;
+ if (count++ == 20000)
+ hang();
+ }
+
+ writel(DDRP_PIR_INIT | DDRP_PIR_QSTRN, ddr_phy_regs + DDRP_PIR);
+
+ count = 0;
+ mask |= DDRP_PGSR_DTDONE;
+ for (;;) {
+ reg = readl(ddr_phy_regs + DDRP_PGSR);
+ if (reg == mask)
+ break;
+ if (count++ != 50000)
+ continue;
+ reg &= DDRP_PGSR_DTDONE | DDRP_PGSR_DTERR | DDRP_PGSR_DTIERR;
+ if (reg)
+ hang();
+ count = 0;
+ }
+
+ /* Override impedance */
+ clrsetbits_le32(ddr_phy_regs + DDRP_ZQXCR0(0), 0x3ff,
+ ((ddr_config->pullup & 0x1f) << DDRP_ZQXCR_PULLUP_IMPE_BIT) |
+ ((ddr_config->pulldn & 0x1f) << DDRP_ZQXCR_PULLDOWN_IMPE_BIT) |
+ DDRP_ZQXCR_ZDEN);
+}
+
+#define JZBIT(bit) ((bit % 4) * 8)
+#define JZMASK(bit) (0x1f << JZBIT(bit))
+
+static void remap_swap(int a, int b)
+{
+ void __iomem *ddr_ctl_regs = (void __iomem *)DDRC_BASE;
+ u32 remmap[2], tmp[2];
+
+ remmap[0] = readl(ddr_ctl_regs + DDRC_REMMAP(a / 4));
+ remmap[1] = readl(ddr_ctl_regs + DDRC_REMMAP(b / 4));
+
+ tmp[0] = (remmap[0] & JZMASK(a)) >> JZBIT(a);
+ tmp[1] = (remmap[1] & JZMASK(b)) >> JZBIT(b);
+
+ remmap[0] &= ~JZMASK(a);
+ remmap[1] &= ~JZMASK(b);
+
+ writel(remmap[0] | (tmp[1] << JZBIT(a)),
+ ddr_ctl_regs + DDRC_REMMAP(a / 4));
+ writel(remmap[1] | (tmp[0] << JZBIT(b)),
+ ddr_ctl_regs + DDRC_REMMAP(b / 4));
+}
+
+static void mem_remap(void)
+{
+ u32 start = (DDR_ROW + DDR_COL + (DDR_DW32 ? 4 : 2) / 2) - 12;
+ u32 num = DDR_BANK8 ? 3 : 2;
+
+ if (DDR_CS0EN && DDR_CS1EN)
+ num++;
+
+ for (; num > 0; num--)
+ remap_swap(0 + num - 1, start + num - 1);
+}
+
+/* Fetch DRAM config from board file */
+__weak const struct jz4780_ddr_config *jz4780_get_ddr_config(void)
+{
+ return NULL;
+}
+
+void sdram_init(void)
+{
+ const struct jz4780_ddr_config *ddr_config = jz4780_get_ddr_config();
+ void __iomem *ddr_ctl_regs = (void __iomem *)DDRC_BASE;
+ void __iomem *ddr_phy_regs = ddr_ctl_regs + DDR_PHY_OFFSET;
+ void __iomem *cpm_regs = (void __iomem *)CPM_BASE;
+ u32 mem_clk, tmp, i;
+ u32 mem_base0, mem_base1;
+ u32 mem_mask0, mem_mask1;
+ u32 mem_size0, mem_size1;
+
+ if (!ddr_config)
+ hang();
+
+ /* Reset DLL in DDR PHY */
+ writel(0x3, cpm_regs + 0xd0);
+ mdelay(400);
+ writel(0x1, cpm_regs + 0xd0);
+ mdelay(400);
+
+ /* Enter reset */
+ writel(0xf << 20, ddr_ctl_regs + DDRC_CTRL);
+
+ mem_clk = get_mem_clk();
+
+ tmp = 1000000000 / mem_clk;
+ if (1000000000 % mem_clk)
+ tmp++;
+ tmp = DDR_tREFI / tmp;
+ tmp = tmp / (16 * (1 << DDR_CLK_DIV)) - 1;
+ if (tmp > 0xff)
+ tmp = 0xff;
+ if (tmp < 1)
+ tmp = 1;
+
+ writel(0x0, ddr_ctl_regs + DDRC_CTRL);
+
+ writel(0x150000, ddr_phy_regs + DDRP_DTAR);
+ ddr_phy_init(ddr_config);
+
+ writel(DDRC_CTRL_CKE | DDRC_CTRL_ALH, ddr_ctl_regs + DDRC_CTRL);
+ writel(0x0, ddr_ctl_regs + DDRC_CTRL);
+
+ ddr_cfg_init();
+
+ for (i = 0; i < 6; i++)
+ writel(ddr_config->timing[i], ddr_ctl_regs + DDRC_TIMING(i));
+
+ mem_size0 = sdram_size(0);
+ mem_size1 = sdram_size(1);
+
+ if (!mem_size1 && mem_size0 > 0x20000000) {
+ mem_base0 = 0x0;
+ mem_mask0 = ~(((mem_size0 * 2) >> 24) - 1) & DDRC_MMAP_MASK_MASK;
+ } else {
+ mem_base0 = (DDR_MEM_PHY_BASE >> 24) & 0xff;
+ mem_mask0 = ~((mem_size0 >> 24) - 1) & DDRC_MMAP_MASK_MASK;
+ }
+
+ if (mem_size1) {
+ mem_mask1 = ~((mem_size1 >> 24) - 1) & DDRC_MMAP_MASK_MASK;
+ mem_base1 = ((DDR_MEM_PHY_BASE + mem_size0) >> 24) & 0xff;
+ } else {
+ mem_mask1 = 0;
+ mem_base1 = 0xff;
+ }
+
+ writel(mem_base0 << DDRC_MMAP_BASE_BIT | mem_mask0,
+ ddr_ctl_regs + DDRC_MMAP0);
+ writel(mem_base1 << DDRC_MMAP_BASE_BIT | mem_mask1,
+ ddr_ctl_regs + DDRC_MMAP1);
+ writel(DDRC_CTRL_CKE | DDRC_CTRL_ALH, ddr_ctl_regs + DDRC_CTRL);
+ writel((DDR_CLK_DIV << 1) | DDRC_REFCNT_REF_EN |
+ (tmp << DDRC_REFCNT_CON_BIT),
+ ddr_ctl_regs + DDRC_REFCNT);
+ writel((1 << 15) | (4 << 12) | (1 << 11) | (1 << 8) | (0 << 6) |
+ (1 << 4) | (1 << 3) | (1 << 2) | (1 << 1),
+ ddr_ctl_regs + DDRC_CTRL);
+ mem_remap();
+ clrbits_le32(ddr_ctl_regs + DDRC_ST, 0x40);
+}
diff --git a/arch/mips/mach-jz47xx/jz4780/timer.c b/arch/mips/mach-jz47xx/jz4780/timer.c
new file mode 100644
index 0000000000..a689b9d71a
--- /dev/null
+++ b/arch/mips/mach-jz47xx/jz4780/timer.c
@@ -0,0 +1,239 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * JZ4780 timer
+ *
+ * Copyright (c) 2013 Imagination Technologies
+ * Author: Paul Burton <paul.burton@imgtec.com>
+ */
+
+#include <config.h>
+#include <common.h>
+#include <div64.h>
+#include <asm/io.h>
+#include <asm/mipsregs.h>
+#include <mach/jz4780.h>
+
+#define TCU_TSR 0x1C /* Timer Stop Register */
+#define TCU_TSSR 0x2C /* Timer Stop Set Register */
+#define TCU_TSCR 0x3C /* Timer Stop Clear Register */
+#define TCU_TER 0x10 /* Timer Counter Enable Register */
+#define TCU_TESR 0x14 /* Timer Counter Enable Set Register */
+#define TCU_TECR 0x18 /* Timer Counter Enable Clear Register */
+#define TCU_TFR 0x20 /* Timer Flag Register */
+#define TCU_TFSR 0x24 /* Timer Flag Set Register */
+#define TCU_TFCR 0x28 /* Timer Flag Clear Register */
+#define TCU_TMR 0x30 /* Timer Mask Register */
+#define TCU_TMSR 0x34 /* Timer Mask Set Register */
+#define TCU_TMCR 0x38 /* Timer Mask Clear Register */
+/* n = 0,1,2,3,4,5 */
+#define TCU_TDFR(n) (0x40 + (n) * 0x10) /* Timer Data Full Reg */
+#define TCU_TDHR(n) (0x44 + (n) * 0x10) /* Timer Data Half Reg */
+#define TCU_TCNT(n) (0x48 + (n) * 0x10) /* Timer Counter Reg */
+#define TCU_TCSR(n) (0x4C + (n) * 0x10) /* Timer Control Reg */
+
+#define TCU_OSTCNTL 0xe4
+#define TCU_OSTCNTH 0xe8
+#define TCU_OSTCSR 0xec
+#define TCU_OSTCNTHBUF 0xfc
+
+/* Register definitions */
+#define TCU_TCSR_PWM_SD BIT(9)
+#define TCU_TCSR_PWM_INITL_HIGH BIT(8)
+#define TCU_TCSR_PWM_EN BIT(7)
+#define TCU_TCSR_PRESCALE_BIT 3
+#define TCU_TCSR_PRESCALE_MASK (0x7 << TCU_TCSR_PRESCALE_BIT)
+#define TCU_TCSR_PRESCALE1 (0x0 << TCU_TCSR_PRESCALE_BIT)
+#define TCU_TCSR_PRESCALE4 (0x1 << TCU_TCSR_PRESCALE_BIT)
+#define TCU_TCSR_PRESCALE16 (0x2 << TCU_TCSR_PRESCALE_BIT)
+#define TCU_TCSR_PRESCALE64 (0x3 << TCU_TCSR_PRESCALE_BIT)
+#define TCU_TCSR_PRESCALE256 (0x4 << TCU_TCSR_PRESCALE_BIT)
+#define TCU_TCSR_PRESCALE1024 (0x5 << TCU_TCSR_PRESCALE_BIT)
+#define TCU_TCSR_EXT_EN BIT(2)
+#define TCU_TCSR_RTC_EN BIT(1)
+#define TCU_TCSR_PCK_EN BIT(0)
+
+#define TCU_TER_TCEN5 BIT(5)
+#define TCU_TER_TCEN4 BIT(4)
+#define TCU_TER_TCEN3 BIT(3)
+#define TCU_TER_TCEN2 BIT(2)
+#define TCU_TER_TCEN1 BIT(1)
+#define TCU_TER_TCEN0 BIT(0)
+
+#define TCU_TESR_TCST5 BIT(5)
+#define TCU_TESR_TCST4 BIT(4)
+#define TCU_TESR_TCST3 BIT(3)
+#define TCU_TESR_TCST2 BIT(2)
+#define TCU_TESR_TCST1 BIT(1)
+#define TCU_TESR_TCST0 BIT(0)
+
+#define TCU_TECR_TCCL5 BIT(5)
+#define TCU_TECR_TCCL4 BIT(4)
+#define TCU_TECR_TCCL3 BIT(3)
+#define TCU_TECR_TCCL2 BIT(2)
+#define TCU_TECR_TCCL1 BIT(1)
+#define TCU_TECR_TCCL0 BIT(0)
+
+#define TCU_TFR_HFLAG5 BIT(21)
+#define TCU_TFR_HFLAG4 BIT(20)
+#define TCU_TFR_HFLAG3 BIT(19)
+#define TCU_TFR_HFLAG2 BIT(18)
+#define TCU_TFR_HFLAG1 BIT(17)
+#define TCU_TFR_HFLAG0 BIT(16)
+#define TCU_TFR_FFLAG5 BIT(5)
+#define TCU_TFR_FFLAG4 BIT(4)
+#define TCU_TFR_FFLAG3 BIT(3)
+#define TCU_TFR_FFLAG2 BIT(2)
+#define TCU_TFR_FFLAG1 BIT(1)
+#define TCU_TFR_FFLAG0 BIT(0)
+
+#define TCU_TFSR_HFLAG5 BIT(21)
+#define TCU_TFSR_HFLAG4 BIT(20)
+#define TCU_TFSR_HFLAG3 BIT(19)
+#define TCU_TFSR_HFLAG2 BIT(18)
+#define TCU_TFSR_HFLAG1 BIT(17)
+#define TCU_TFSR_HFLAG0 BIT(16)
+#define TCU_TFSR_FFLAG5 BIT(5)
+#define TCU_TFSR_FFLAG4 BIT(4)
+#define TCU_TFSR_FFLAG3 BIT(3)
+#define TCU_TFSR_FFLAG2 BIT(2)
+#define TCU_TFSR_FFLAG1 BIT(1)
+#define TCU_TFSR_FFLAG0 BIT(0)
+
+#define TCU_TFCR_HFLAG5 BIT(21)
+#define TCU_TFCR_HFLAG4 BIT(20)
+#define TCU_TFCR_HFLAG3 BIT(19)
+#define TCU_TFCR_HFLAG2 BIT(18)
+#define TCU_TFCR_HFLAG1 BIT(17)
+#define TCU_TFCR_HFLAG0 BIT(16)
+#define TCU_TFCR_FFLAG5 BIT(5)
+#define TCU_TFCR_FFLAG4 BIT(4)
+#define TCU_TFCR_FFLAG3 BIT(3)
+#define TCU_TFCR_FFLAG2 BIT(2)
+#define TCU_TFCR_FFLAG1 BIT(1)
+#define TCU_TFCR_FFLAG0 BIT(0)
+
+#define TCU_TMR_HMASK5 BIT(21)
+#define TCU_TMR_HMASK4 BIT(20)
+#define TCU_TMR_HMASK3 BIT(19)
+#define TCU_TMR_HMASK2 BIT(18)
+#define TCU_TMR_HMASK1 BIT(17)
+#define TCU_TMR_HMASK0 BIT(16)
+#define TCU_TMR_FMASK5 BIT(5)
+#define TCU_TMR_FMASK4 BIT(4)
+#define TCU_TMR_FMASK3 BIT(3)
+#define TCU_TMR_FMASK2 BIT(2)
+#define TCU_TMR_FMASK1 BIT(1)
+#define TCU_TMR_FMASK0 BIT(0)
+
+#define TCU_TMSR_HMST5 BIT(21)
+#define TCU_TMSR_HMST4 BIT(20)
+#define TCU_TMSR_HMST3 BIT(19)
+#define TCU_TMSR_HMST2 BIT(18)
+#define TCU_TMSR_HMST1 BIT(17)
+#define TCU_TMSR_HMST0 BIT(16)
+#define TCU_TMSR_FMST5 BIT(5)
+#define TCU_TMSR_FMST4 BIT(4)
+#define TCU_TMSR_FMST3 BIT(3)
+#define TCU_TMSR_FMST2 BIT(2)
+#define TCU_TMSR_FMST1 BIT(1)
+#define TCU_TMSR_FMST0 BIT(0)
+
+#define TCU_TMCR_HMCL5 BIT(21)
+#define TCU_TMCR_HMCL4 BIT(20)
+#define TCU_TMCR_HMCL3 BIT(19)
+#define TCU_TMCR_HMCL2 BIT(18)
+#define TCU_TMCR_HMCL1 BIT(17)
+#define TCU_TMCR_HMCL0 BIT(16)
+#define TCU_TMCR_FMCL5 BIT(5)
+#define TCU_TMCR_FMCL4 BIT(4)
+#define TCU_TMCR_FMCL3 BIT(3)
+#define TCU_TMCR_FMCL2 BIT(2)
+#define TCU_TMCR_FMCL1 BIT(1)
+#define TCU_TMCR_FMCL0 BIT(0)
+
+#define TCU_TSR_WDTS BIT(16)
+#define TCU_TSR_STOP5 BIT(5)
+#define TCU_TSR_STOP4 BIT(4)
+#define TCU_TSR_STOP3 BIT(3)
+#define TCU_TSR_STOP2 BIT(2)
+#define TCU_TSR_STOP1 BIT(1)
+#define TCU_TSR_STOP0 BIT(0)
+
+#define TCU_TSSR_WDTSS BIT(16)
+#define TCU_TSSR_STPS5 BIT(5)
+#define TCU_TSSR_STPS4 BIT(4)
+#define TCU_TSSR_STPS3 BIT(3)
+#define TCU_TSSR_STPS2 BIT(2)
+#define TCU_TSSR_STPS1 BIT(1)
+#define TCU_TSSR_STPS0 BIT(0)
+
+#define TCU_TSSR_WDTSC BIT(16)
+#define TCU_TSSR_STPC5 BIT(5)
+#define TCU_TSSR_STPC4 BIT(4)
+#define TCU_TSSR_STPC3 BIT(3)
+#define TCU_TSSR_STPC2 BIT(2)
+#define TCU_TSSR_STPC1 BIT(1)
+#define TCU_TSSR_STPC0 BIT(0)
+
+#define TER_OSTEN BIT(15)
+
+#define OSTCSR_CNT_MD BIT(15)
+#define OSTCSR_SD BIT(9)
+#define OSTCSR_PRESCALE_16 (0x2 << 3)
+#define OSTCSR_EXT_EN BIT(2)
+
+int timer_init(void)
+{
+ void __iomem *regs = (void __iomem *)TCU_BASE;
+
+ writel(OSTCSR_SD, regs + TCU_OSTCSR);
+ reset_timer();
+ writel(OSTCSR_CNT_MD | OSTCSR_EXT_EN | OSTCSR_PRESCALE_16,
+ regs + TCU_OSTCSR);
+ writew(TER_OSTEN, regs + TCU_TESR);
+ return 0;
+}
+
+void reset_timer(void)
+{
+ void __iomem *regs = (void __iomem *)TCU_BASE;
+
+ writel(0, regs + TCU_OSTCNTH);
+ writel(0, regs + TCU_OSTCNTL);
+}
+
+static u64 get_timer64(void)
+{
+ void __iomem *regs = (void __iomem *)TCU_BASE;
+ u32 low = readl(regs + TCU_OSTCNTL);
+ u32 high = readl(regs + TCU_OSTCNTHBUF);
+
+ return ((u64)high << 32) | low;
+}
+
+ulong get_timer(ulong base)
+{
+ return lldiv(get_timer64(), 3000) - base;
+}
+
+void __udelay(unsigned long usec)
+{
+ /* OST count increments at 3MHz */
+ u64 end = get_timer64() + ((u64)usec * 3);
+
+ while (get_timer64() < end)
+ ;
+}
+
+unsigned long long get_ticks(void)
+{
+ return get_timer64();
+}
+
+void jz4780_tcu_wdt_start(void)
+{
+ void __iomem *tcu_regs = (void __iomem *)TCU_BASE;
+
+ /* Enable WDT clock */
+ writel(TCU_TSSR_WDTSC, tcu_regs + TCU_TSCR);
+}
diff --git a/arch/mips/mach-jz47xx/jz4780/u-boot-spl.lds b/arch/mips/mach-jz47xx/jz4780/u-boot-spl.lds
new file mode 100644
index 0000000000..347cabc450
--- /dev/null
+++ b/arch/mips/mach-jz47xx/jz4780/u-boot-spl.lds
@@ -0,0 +1,50 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+
+MEMORY { .sram : ORIGIN = CONFIG_SPL_TEXT_BASE,\
+ LENGTH = CONFIG_SPL_MAX_SIZE }
+MEMORY { .sdram : ORIGIN = CONFIG_SPL_BSS_START_ADDR, \
+ LENGTH = CONFIG_SPL_BSS_MAX_SIZE }
+
+OUTPUT_ARCH(mips)
+ENTRY(_start)
+SECTIONS
+{
+ .text :
+ {
+ __image_copy_start = .;
+ arch/mips/mach-jz47xx/start.o (.text*)
+ *(.text*)
+ } >.sram
+
+ . = ALIGN(4);
+ .rodata : { *(SORT_BY_ALIGNMENT(.rodata*)) } >.sram
+
+ . = ALIGN(4);
+ .data : { *(SORT_BY_ALIGNMENT(.data*)) } >.sram
+
+ . = ALIGN(4);
+ __image_copy_end = .;
+
+ .bss : {
+ . = ALIGN(4);
+ __bss_start = .;
+ *(.sbss.*)
+ *(.bss.*)
+ *(COMMON)
+ . = ALIGN(4);
+ __bss_end = .;
+ } >.sdram
+
+ /DISCARD/ : {
+ *(.dynbss)
+ *(.dynstr)
+ *(.dynamic)
+ *(.interp)
+ *(.hash)
+ *(.gnu.*)
+ *(.plt)
+ *(.got.plt)
+ *(.rel.plt)
+ *(.rel.dyn)
+ }
+}