aboutsummaryrefslogtreecommitdiffstats
path: root/roms/u-boot/arch/arm/mach-uniphier/arm32
diff options
context:
space:
mode:
Diffstat (limited to 'roms/u-boot/arch/arm/mach-uniphier/arm32')
-rw-r--r--roms/u-boot/arch/arm/mach-uniphier/arm32/Makefile12
-rw-r--r--roms/u-boot/arch/arm/mach-uniphier/arm32/arm-mpcore.h48
-rw-r--r--roms/u-boot/arch/arm/mach-uniphier/arm32/cache-uniphier.c292
-rw-r--r--roms/u-boot/arch/arm/mach-uniphier/arm32/cache-uniphier.h20
-rw-r--r--roms/u-boot/arch/arm/mach-uniphier/arm32/debug_ll.S175
-rw-r--r--roms/u-boot/arch/arm/mach-uniphier/arm32/late_lowlevel_init.S13
-rw-r--r--roms/u-boot/arch/arm/mach-uniphier/arm32/lowlevel_init.S138
-rw-r--r--roms/u-boot/arch/arm/mach-uniphier/arm32/psci.c162
-rw-r--r--roms/u-boot/arch/arm/mach-uniphier/arm32/psci_smp.S39
-rw-r--r--roms/u-boot/arch/arm/mach-uniphier/arm32/timer.c39
10 files changed, 938 insertions, 0 deletions
diff --git a/roms/u-boot/arch/arm/mach-uniphier/arm32/Makefile b/roms/u-boot/arch/arm/mach-uniphier/arm32/Makefile
new file mode 100644
index 000000000..3cd00b7e5
--- /dev/null
+++ b/roms/u-boot/arch/arm/mach-uniphier/arm32/Makefile
@@ -0,0 +1,12 @@
+# SPDX-License-Identifier: GPL-2.0+
+
+ifdef CONFIG_SPL_BUILD
+obj-y += lowlevel_init.o
+obj-$(CONFIG_DEBUG_LL) += debug_ll.o
+else
+obj-y += late_lowlevel_init.o
+obj-y += cache-uniphier.o
+obj-$(CONFIG_ARMV7_PSCI) += psci.o psci_smp.o
+endif
+
+obj-y += timer.o
diff --git a/roms/u-boot/arch/arm/mach-uniphier/arm32/arm-mpcore.h b/roms/u-boot/arch/arm/mach-uniphier/arm32/arm-mpcore.h
new file mode 100644
index 000000000..27eac90a0
--- /dev/null
+++ b/roms/u-boot/arch/arm/mach-uniphier/arm32/arm-mpcore.h
@@ -0,0 +1,48 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright (C) 2011-2014 Panasonic Corporation
+ */
+
+#ifndef ARCH_ARM_MPCORE_H
+#define ARCH_ARM_MPCORE_H
+
+/* Snoop Control Unit */
+#define SCU_OFFSET 0x00
+
+/* SCU Control Register */
+#define SCU_CTRL 0x00
+#define SCU_ENABLE (1 << 0)
+#define SCU_STANDBY_ENABLE (1 << 5)
+
+/* SCU Configuration Register */
+#define SCU_CONF 0x04
+/* SCU CPU Power Status Register */
+#define SCU_PWR_STATUS 0x08
+/* SCU Invalidate All Registers in Secure State */
+#define SCU_INV_ALL 0x0C
+/* SCU Filtering Start Address Register */
+#define SCU_FILTER_START 0x40
+/* SCU Filtering End Address Register */
+#define SCU_FILTER_END 0x44
+/* SCU Access Control Register */
+#define SCU_SAC 0x50
+/* SCU Non-secure Access Control Register */
+#define SCU_SNSAC 0x54
+
+/* Global Timer */
+#define GLOBAL_TIMER_OFFSET 0x200
+
+/* Global Timer Counter Registers */
+#define GTIMER_CNT_L 0x00
+#define GTIMER_CNT_H 0x04
+/* Global Timer Control Register */
+#define GTIMER_CTRL 0x08
+/* Global Timer Interrupt Status Register */
+#define GTIMER_STAT 0x0C
+/* Comparator Value Registers */
+#define GTIMER_CMP_L 0x10
+#define GTIMER_CMP_H 0x14
+/* Auto-increment Register */
+#define GTIMER_INC 0x18
+
+#endif /* ARCH_ARM_MPCORE_H */
diff --git a/roms/u-boot/arch/arm/mach-uniphier/arm32/cache-uniphier.c b/roms/u-boot/arch/arm/mach-uniphier/arm32/cache-uniphier.c
new file mode 100644
index 000000000..cde2a8124
--- /dev/null
+++ b/roms/u-boot/arch/arm/mach-uniphier/arm32/cache-uniphier.c
@@ -0,0 +1,292 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2012-2014 Panasonic Corporation
+ * Copyright (C) 2015-2016 Socionext Inc.
+ * Author: Masahiro Yamada <yamada.masahiro@socionext.com>
+ */
+
+#include <cpu_func.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <asm/armv7.h>
+#include <asm/processor.h>
+
+#include "cache-uniphier.h"
+
+/* control registers */
+#define UNIPHIER_SSCC 0x500c0000 /* Control Register */
+#define UNIPHIER_SSCC_BST (0x1 << 20) /* UCWG burst read */
+#define UNIPHIER_SSCC_ACT (0x1 << 19) /* Inst-Data separate */
+#define UNIPHIER_SSCC_WTG (0x1 << 18) /* WT gathering on */
+#define UNIPHIER_SSCC_PRD (0x1 << 17) /* enable pre-fetch */
+#define UNIPHIER_SSCC_ON (0x1 << 0) /* enable cache */
+#define UNIPHIER_SSCLPDAWCR 0x500c0030 /* Unified/Data Active Way Control */
+#define UNIPHIER_SSCLPIAWCR 0x500c0034 /* Instruction Active Way Control */
+
+/* revision registers */
+#define UNIPHIER_SSCID 0x503c0100 /* ID Register */
+
+/* operation registers */
+#define UNIPHIER_SSCOPE 0x506c0244 /* Cache Operation Primitive Entry */
+#define UNIPHIER_SSCOPE_CM_INV 0x0 /* invalidate */
+#define UNIPHIER_SSCOPE_CM_CLEAN 0x1 /* clean */
+#define UNIPHIER_SSCOPE_CM_FLUSH 0x2 /* flush */
+#define UNIPHIER_SSCOPE_CM_SYNC 0x8 /* sync (drain bufs) */
+#define UNIPHIER_SSCOPE_CM_FLUSH_PREFETCH 0x9 /* flush p-fetch buf */
+#define UNIPHIER_SSCOQM 0x506c0248
+#define UNIPHIER_SSCOQM_TID_MASK (0x3 << 21)
+#define UNIPHIER_SSCOQM_TID_LRU_DATA (0x0 << 21)
+#define UNIPHIER_SSCOQM_TID_LRU_INST (0x1 << 21)
+#define UNIPHIER_SSCOQM_TID_WAY (0x2 << 21)
+#define UNIPHIER_SSCOQM_S_MASK (0x3 << 17)
+#define UNIPHIER_SSCOQM_S_RANGE (0x0 << 17)
+#define UNIPHIER_SSCOQM_S_ALL (0x1 << 17)
+#define UNIPHIER_SSCOQM_S_WAY (0x2 << 17)
+#define UNIPHIER_SSCOQM_CE (0x1 << 15) /* notify completion */
+#define UNIPHIER_SSCOQM_CW (0x1 << 14)
+#define UNIPHIER_SSCOQM_CM_MASK (0x7)
+#define UNIPHIER_SSCOQM_CM_INV 0x0 /* invalidate */
+#define UNIPHIER_SSCOQM_CM_CLEAN 0x1 /* clean */
+#define UNIPHIER_SSCOQM_CM_FLUSH 0x2 /* flush */
+#define UNIPHIER_SSCOQM_CM_PREFETCH 0x3 /* prefetch to cache */
+#define UNIPHIER_SSCOQM_CM_PREFETCH_BUF 0x4 /* prefetch to pf-buf */
+#define UNIPHIER_SSCOQM_CM_TOUCH 0x5 /* touch */
+#define UNIPHIER_SSCOQM_CM_TOUCH_ZERO 0x6 /* touch to zero */
+#define UNIPHIER_SSCOQM_CM_TOUCH_DIRTY 0x7 /* touch with dirty */
+#define UNIPHIER_SSCOQAD 0x506c024c /* Cache Operation Queue Address */
+#define UNIPHIER_SSCOQSZ 0x506c0250 /* Cache Operation Queue Size */
+#define UNIPHIER_SSCOQMASK 0x506c0254 /* Cache Operation Queue Address Mask */
+#define UNIPHIER_SSCOQWN 0x506c0258 /* Cache Operation Queue Way Number */
+#define UNIPHIER_SSCOPPQSEF 0x506c025c /* Cache Operation Queue Set Complete */
+#define UNIPHIER_SSCOPPQSEF_FE (0x1 << 1)
+#define UNIPHIER_SSCOPPQSEF_OE (0x1 << 0)
+#define UNIPHIER_SSCOLPQS 0x506c0260 /* Cache Operation Queue Status */
+#define UNIPHIER_SSCOLPQS_EF (0x1 << 2)
+#define UNIPHIER_SSCOLPQS_EST (0x1 << 1)
+#define UNIPHIER_SSCOLPQS_QST (0x1 << 0)
+
+#define UNIPHIER_SSC_LINE_SIZE 128
+#define UNIPHIER_SSC_RANGE_OP_MAX_SIZE (0x00400000 - (UNIPHIER_SSC_LINE_SIZE))
+
+#define UNIPHIER_SSCOQAD_IS_NEEDED(op) \
+ ((op & UNIPHIER_SSCOQM_S_MASK) == UNIPHIER_SSCOQM_S_RANGE)
+#define UNIPHIER_SSCOQWM_IS_NEEDED(op) \
+ (((op & UNIPHIER_SSCOQM_S_MASK) == UNIPHIER_SSCOQM_S_WAY) || \
+ ((op & UNIPHIER_SSCOQM_TID_MASK) == UNIPHIER_SSCOQM_TID_WAY))
+
+/* uniphier_cache_sync - perform a sync point for a particular cache level */
+static void uniphier_cache_sync(void)
+{
+ /* drain internal buffers */
+ writel(UNIPHIER_SSCOPE_CM_SYNC, UNIPHIER_SSCOPE);
+ /* need a read back to confirm */
+ readl(UNIPHIER_SSCOPE);
+}
+
+/**
+ * uniphier_cache_maint_common - run a queue operation
+ *
+ * @start: start address of range operation (don't care for "all" operation)
+ * @size: data size of range operation (don't care for "all" operation)
+ * @ways: target ways (don't care for operations other than pre-fetch, touch
+ * @operation: flags to specify the desired cache operation
+ */
+static void uniphier_cache_maint_common(u32 start, u32 size, u32 ways,
+ u32 operation)
+{
+ /* clear the complete notification flag */
+ writel(UNIPHIER_SSCOLPQS_EF, UNIPHIER_SSCOLPQS);
+
+ do {
+ /* set cache operation */
+ writel(UNIPHIER_SSCOQM_CE | operation, UNIPHIER_SSCOQM);
+
+ /* set address range if needed */
+ if (likely(UNIPHIER_SSCOQAD_IS_NEEDED(operation))) {
+ writel(start, UNIPHIER_SSCOQAD);
+ writel(size, UNIPHIER_SSCOQSZ);
+ }
+
+ /* set target ways if needed */
+ if (unlikely(UNIPHIER_SSCOQWM_IS_NEEDED(operation)))
+ writel(ways, UNIPHIER_SSCOQWN);
+ } while (unlikely(readl(UNIPHIER_SSCOPPQSEF) &
+ (UNIPHIER_SSCOPPQSEF_FE | UNIPHIER_SSCOPPQSEF_OE)));
+
+ /* wait until the operation is completed */
+ while (likely(readl(UNIPHIER_SSCOLPQS) != UNIPHIER_SSCOLPQS_EF))
+ cpu_relax();
+}
+
+static void uniphier_cache_maint_all(u32 operation)
+{
+ uniphier_cache_maint_common(0, 0, 0, UNIPHIER_SSCOQM_S_ALL | operation);
+
+ uniphier_cache_sync();
+}
+
+static void uniphier_cache_maint_range(u32 start, u32 end, u32 ways,
+ u32 operation)
+{
+ u32 size;
+
+ /*
+ * If the start address is not aligned,
+ * perform a cache operation for the first cache-line
+ */
+ start = start & ~(UNIPHIER_SSC_LINE_SIZE - 1);
+
+ size = end - start;
+
+ if (unlikely(size >= (u32)(-UNIPHIER_SSC_LINE_SIZE))) {
+ /* this means cache operation for all range */
+ uniphier_cache_maint_all(operation);
+ return;
+ }
+
+ /*
+ * If the end address is not aligned,
+ * perform a cache operation for the last cache-line
+ */
+ size = ALIGN(size, UNIPHIER_SSC_LINE_SIZE);
+
+ while (size) {
+ u32 chunk_size = min_t(u32, size, UNIPHIER_SSC_RANGE_OP_MAX_SIZE);
+
+ uniphier_cache_maint_common(start, chunk_size, ways,
+ UNIPHIER_SSCOQM_S_RANGE | operation);
+
+ start += chunk_size;
+ size -= chunk_size;
+ }
+
+ uniphier_cache_sync();
+}
+
+void uniphier_cache_prefetch_range(u32 start, u32 end, u32 ways)
+{
+ uniphier_cache_maint_range(start, end, ways,
+ UNIPHIER_SSCOQM_TID_WAY |
+ UNIPHIER_SSCOQM_CM_PREFETCH);
+}
+
+void uniphier_cache_touch_range(u32 start, u32 end, u32 ways)
+{
+ uniphier_cache_maint_range(start, end, ways,
+ UNIPHIER_SSCOQM_TID_WAY |
+ UNIPHIER_SSCOQM_CM_TOUCH);
+}
+
+void uniphier_cache_touch_zero_range(u32 start, u32 end, u32 ways)
+{
+ uniphier_cache_maint_range(start, end, ways,
+ UNIPHIER_SSCOQM_TID_WAY |
+ UNIPHIER_SSCOQM_CM_TOUCH_ZERO);
+}
+
+void uniphier_cache_inv_way(u32 ways)
+{
+ uniphier_cache_maint_common(0, 0, ways,
+ UNIPHIER_SSCOQM_S_WAY |
+ UNIPHIER_SSCOQM_CM_INV);
+}
+
+void uniphier_cache_set_active_ways(int cpu, u32 active_ways)
+{
+ void __iomem *base = (void __iomem *)UNIPHIER_SSCC + 0xc00;
+
+ switch (readl(UNIPHIER_SSCID)) { /* revision */
+ case 0x12: /* LD4 */
+ case 0x16: /* sld8 */
+ base = (void __iomem *)UNIPHIER_SSCC + 0x840;
+ break;
+ default:
+ base = (void __iomem *)UNIPHIER_SSCC + 0xc00;
+ break;
+ }
+
+ writel(active_ways, base + 4 * cpu);
+}
+
+static void uniphier_cache_endisable(int enable)
+{
+ u32 tmp;
+
+ tmp = readl(UNIPHIER_SSCC);
+ if (enable)
+ tmp |= UNIPHIER_SSCC_ON;
+ else
+ tmp &= ~UNIPHIER_SSCC_ON;
+ writel(tmp, UNIPHIER_SSCC);
+}
+
+void uniphier_cache_enable(void)
+{
+ uniphier_cache_endisable(1);
+}
+
+void uniphier_cache_disable(void)
+{
+ uniphier_cache_endisable(0);
+}
+
+#ifdef CONFIG_CACHE_UNIPHIER
+void v7_outer_cache_flush_all(void)
+{
+ uniphier_cache_maint_all(UNIPHIER_SSCOQM_CM_FLUSH);
+}
+
+void v7_outer_cache_inval_all(void)
+{
+ uniphier_cache_maint_all(UNIPHIER_SSCOQM_CM_INV);
+}
+
+void v7_outer_cache_flush_range(u32 start, u32 end)
+{
+ uniphier_cache_maint_range(start, end, 0, UNIPHIER_SSCOQM_CM_FLUSH);
+}
+
+void v7_outer_cache_inval_range(u32 start, u32 end)
+{
+ if (start & (UNIPHIER_SSC_LINE_SIZE - 1)) {
+ start &= ~(UNIPHIER_SSC_LINE_SIZE - 1);
+ uniphier_cache_maint_range(start, UNIPHIER_SSC_LINE_SIZE, 0,
+ UNIPHIER_SSCOQM_CM_FLUSH);
+ start += UNIPHIER_SSC_LINE_SIZE;
+ }
+
+ if (start >= end) {
+ uniphier_cache_sync();
+ return;
+ }
+
+ if (end & (UNIPHIER_SSC_LINE_SIZE - 1)) {
+ end &= ~(UNIPHIER_SSC_LINE_SIZE - 1);
+ uniphier_cache_maint_range(end, UNIPHIER_SSC_LINE_SIZE, 0,
+ UNIPHIER_SSCOQM_CM_FLUSH);
+ }
+
+ if (start >= end) {
+ uniphier_cache_sync();
+ return;
+ }
+
+ uniphier_cache_maint_range(start, end, 0, UNIPHIER_SSCOQM_CM_INV);
+}
+
+void v7_outer_cache_enable(void)
+{
+ uniphier_cache_set_active_ways(0, U32_MAX); /* activate all ways */
+ uniphier_cache_enable();
+}
+
+void v7_outer_cache_disable(void)
+{
+ uniphier_cache_disable();
+}
+#endif
+
+void enable_caches(void)
+{
+ dcache_enable();
+}
diff --git a/roms/u-boot/arch/arm/mach-uniphier/arm32/cache-uniphier.h b/roms/u-boot/arch/arm/mach-uniphier/arm32/cache-uniphier.h
new file mode 100644
index 000000000..40838244d
--- /dev/null
+++ b/roms/u-boot/arch/arm/mach-uniphier/arm32/cache-uniphier.h
@@ -0,0 +1,20 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright (C) 2016 Socionext Inc.
+ * Author: Masahiro Yamada <yamada.masahiro@socionext.com>
+ */
+
+#ifndef __CACHE_UNIPHIER_H
+#define __CACHE_UNIPHIER_H
+
+#include <linux/types.h>
+
+void uniphier_cache_prefetch_range(u32 start, u32 end, u32 ways);
+void uniphier_cache_touch_range(u32 start, u32 end, u32 ways);
+void uniphier_cache_touch_zero_range(u32 start, u32 end, u32 ways);
+void uniphier_cache_inv_way(u32 ways);
+void uniphier_cache_set_active_ways(int cpu, u32 active_ways);
+void uniphier_cache_enable(void);
+void uniphier_cache_disable(void);
+
+#endif /* __CACHE_UNIPHIER_H */
diff --git a/roms/u-boot/arch/arm/mach-uniphier/arm32/debug_ll.S b/roms/u-boot/arch/arm/mach-uniphier/arm32/debug_ll.S
new file mode 100644
index 000000000..3fed7985f
--- /dev/null
+++ b/roms/u-boot/arch/arm/mach-uniphier/arm32/debug_ll.S
@@ -0,0 +1,175 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * On-chip UART initializaion for low-level debugging
+ *
+ * Copyright (C) 2014-2015 Masahiro Yamada <yamada.masahiro@socionext.com>
+ */
+
+#include <linux/serial_reg.h>
+#include <linux/linkage.h>
+
+#include "../bcu/bcu-regs.h"
+#include "../sc-regs.h"
+#include "../sg-regs.h"
+
+#if !defined(CONFIG_DEBUG_SEMIHOSTING)
+#include CONFIG_DEBUG_LL_INCLUDE
+#endif
+
+#define SG_REVISION_TYPE_SHIFT 16
+#define SG_REVISION_TYPE_MASK (0xff << SG_REVISION_TYPE_SHIFT)
+#define BAUDRATE 115200
+#define DIV_ROUND(x, d) (((x) + ((d) / 2)) / (d))
+
+.macro sg_set_pinsel, pin, muxval, mux_bits, reg_stride, ra, rd
+ ldr \ra, =(SG_BASE + SG_PINCTRL_BASE + \pin * \mux_bits / 32 * \reg_stride)
+ ldr \rd, [\ra]
+ and \rd, \rd, #~(((1 << \mux_bits) - 1) << (\pin * \mux_bits % 32))
+ orr \rd, \rd, #(\muxval << (\pin * \mux_bits % 32))
+ str \rd, [\ra]
+.endm
+
+ENTRY(debug_ll_init)
+ ldr r0, =(SG_BASE + SG_REVISION)
+ ldr r1, [r0]
+ and r1, r1, #SG_REVISION_TYPE_MASK
+ mov r1, r1, lsr #SG_REVISION_TYPE_SHIFT
+
+#if defined(CONFIG_ARCH_UNIPHIER_LD4)
+#define UNIPHIER_LD4_UART_CLK 36864000
+ cmp r1, #0x26
+ bne ld4_end
+
+ ldr r0, =(SG_BASE + SG_IECTRL)
+ ldr r1, [r0]
+ orr r1, r1, #1
+ str r1, [r0]
+
+ sg_set_pinsel 88, 1, 8, 4, r0, r1 @ HSDOUT6 -> TXD0
+
+ ldr r3, =DIV_ROUND(UNIPHIER_LD4_UART_CLK, 16 * BAUDRATE)
+
+ b init_uart
+ld4_end:
+#endif
+#if defined(CONFIG_ARCH_UNIPHIER_PRO4)
+#define UNIPHIER_PRO4_UART_CLK 73728000
+ cmp r1, #0x28
+ bne pro4_end
+
+ sg_set_pinsel 128, 0, 4, 8, r0, r1 @ TXD0 -> TXD0
+
+ ldr r0, =(SG_BASE + SG_LOADPINCTRL)
+ mov r1, #1
+ str r1, [r0]
+
+ ldr r0, =(SC_BASE + SC_CLKCTRL)
+ ldr r1, [r0]
+ orr r1, r1, #SC_CLKCTRL_CEN_PERI
+ str r1, [r0]
+
+ ldr r3, =DIV_ROUND(UNIPHIER_PRO4_UART_CLK, 16 * BAUDRATE)
+
+ b init_uart
+pro4_end:
+#endif
+#if defined(CONFIG_ARCH_UNIPHIER_SLD8)
+#define UNIPHIER_SLD8_UART_CLK 80000000
+ cmp r1, #0x29
+ bne sld8_end
+
+ ldr r0, =(SG_BASE + SG_IECTRL)
+ ldr r1, [r0]
+ orr r1, r1, #1
+ str r1, [r0]
+
+ sg_set_pinsel 70, 3, 8, 4, r0, r1 @ HSDOUT0 -> TXD0
+
+ ldr r3, =DIV_ROUND(UNIPHIER_SLD8_UART_CLK, 16 * BAUDRATE)
+
+ b init_uart
+sld8_end:
+#endif
+#if defined(CONFIG_ARCH_UNIPHIER_PRO5)
+#define UNIPHIER_PRO5_UART_CLK 73728000
+ cmp r1, #0x2A
+ bne pro5_end
+
+ sg_set_pinsel 47, 0, 4, 8, r0, r1 @ TXD0 -> TXD0
+ sg_set_pinsel 49, 0, 4, 8, r0, r1 @ TXD1 -> TXD1
+ sg_set_pinsel 51, 0, 4, 8, r0, r1 @ TXD2 -> TXD2
+ sg_set_pinsel 53, 0, 4, 8, r0, r1 @ TXD3 -> TXD3
+
+ ldr r0, =(SG_BASE + SG_LOADPINCTRL)
+ mov r1, #1
+ str r1, [r0]
+
+ ldr r0, =(SC_BASE + SC_CLKCTRL)
+ ldr r1, [r0]
+ orr r1, r1, #SC_CLKCTRL_CEN_PERI
+ str r1, [r0]
+
+ ldr r3, =DIV_ROUND(UNIPHIER_PRO5_UART_CLK, 16 * BAUDRATE)
+
+ b init_uart
+pro5_end:
+#endif
+#if defined(CONFIG_ARCH_UNIPHIER_PXS2)
+#define UNIPHIER_PXS2_UART_CLK 88900000
+ cmp r1, #0x2E
+ bne pxs2_end
+
+ ldr r0, =(SG_BASE + SG_IECTRL)
+ ldr r1, [r0]
+ orr r1, r1, #1
+ str r1, [r0]
+
+ sg_set_pinsel 217, 8, 8, 4, r0, r1 @ TXD0 -> TXD0
+ sg_set_pinsel 115, 8, 8, 4, r0, r1 @ TXD1 -> TXD1
+ sg_set_pinsel 113, 8, 8, 4, r0, r1 @ TXD2 -> TXD2
+ sg_set_pinsel 219, 8, 8, 4, r0, r1 @ TXD3 -> TXD3
+
+ ldr r0, =(SC_BASE + SC_CLKCTRL)
+ ldr r1, [r0]
+ orr r1, r1, #SC_CLKCTRL_CEN_PERI
+ str r1, [r0]
+
+ ldr r3, =DIV_ROUND(UNIPHIER_PXS2_UART_CLK, 16 * BAUDRATE)
+
+ b init_uart
+pxs2_end:
+#endif
+#if defined(CONFIG_ARCH_UNIPHIER_LD6B)
+#define UNIPHIER_LD6B_UART_CLK 88900000
+ cmp r1, #0x2F
+ bne ld6b_end
+
+ ldr r0, =(SG_BASE + SG_IECTRL)
+ ldr r1, [r0]
+ orr r1, r1, #1
+ str r1, [r0]
+
+ sg_set_pinsel 135, 3, 8, 4, r0, r1 @ PORT10 -> TXD0
+ sg_set_pinsel 115, 0, 8, 4, r0, r1 @ TXD1 -> TXD1
+ sg_set_pinsel 113, 2, 8, 4, r0, r1 @ SBO0 -> TXD2
+
+ ldr r0, =(SC_BASE + SC_CLKCTRL)
+ ldr r1, [r0]
+ orr r1, r1, #SC_CLKCTRL_CEN_PERI
+ str r1, [r0]
+
+ ldr r3, =DIV_ROUND(UNIPHIER_LD6B_UART_CLK, 16 * BAUDRATE)
+
+ b init_uart
+ld6b_end:
+#endif
+ mov pc, lr
+
+init_uart:
+ addruart r0, r1, r2
+ mov r1, #UART_LCR_WLEN8 << 8
+ str r1, [r0, #0x10]
+ str r3, [r0, #0x24]
+
+ mov pc, lr
+ENDPROC(debug_ll_init)
diff --git a/roms/u-boot/arch/arm/mach-uniphier/arm32/late_lowlevel_init.S b/roms/u-boot/arch/arm/mach-uniphier/arm32/late_lowlevel_init.S
new file mode 100644
index 000000000..36db50fd9
--- /dev/null
+++ b/roms/u-boot/arch/arm/mach-uniphier/arm32/late_lowlevel_init.S
@@ -0,0 +1,13 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright (C) 2015 Socionext Inc.
+ * Author: Masahiro Yamada <yamada.masahiro@socionext.com>
+ */
+
+#include <config.h>
+#include <linux/linkage.h>
+
+ENTRY(lowlevel_init)
+ ldr sp, = CONFIG_SYS_INIT_SP_ADDR
+ b uniphier_cache_disable
+ENDPROC(lowlevel_init)
diff --git a/roms/u-boot/arch/arm/mach-uniphier/arm32/lowlevel_init.S b/roms/u-boot/arch/arm/mach-uniphier/arm32/lowlevel_init.S
new file mode 100644
index 000000000..3f9f135bc
--- /dev/null
+++ b/roms/u-boot/arch/arm/mach-uniphier/arm32/lowlevel_init.S
@@ -0,0 +1,138 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright (C) 2012-2015 Panasonic Corporation
+ * Copyright (C) 2015-2016 Socionext Inc.
+ * Author: Masahiro Yamada <yamada.masahiro@socionext.com>
+ */
+
+#include <config.h>
+#include <linux/linkage.h>
+#include <linux/sizes.h>
+#include <asm/system.h>
+
+ENTRY(lowlevel_init)
+ mov r8, lr @ persevere link reg across call
+
+ /*
+ * The UniPhier Boot ROM loads SPL code to the L2 cache.
+ * But CPUs can only do instruction fetch now because start.S has
+ * cleared C and M bits.
+ * First we need to turn on MMU and Dcache again to get back
+ * data access to L2.
+ */
+ mrc p15, 0, r0, c1, c0, 0 @ SCTLR (System Control Register)
+ orr r0, r0, #(CR_C | CR_M) @ enable MMU and Dcache
+ mcr p15, 0, r0, c1, c0, 0
+
+#ifdef CONFIG_DEBUG_LL
+ bl debug_ll_init
+#endif
+
+ bl setup_init_ram @ RAM area for stack and page table
+
+ /*
+ * Now we are using the page table embedded in the Boot ROM.
+ * What we need to do next is to create a page table and switch
+ * over to it.
+ */
+ bl create_page_table
+ bl __v7_flush_dcache_all
+
+ /* Disable MMU and Dcache before switching Page Table */
+ mrc p15, 0, r0, c1, c0, 0 @ SCTLR (System Control Register)
+ bic r0, r0, #(CR_C | CR_M) @ disable MMU and Dcache
+ mcr p15, 0, r0, c1, c0, 0
+
+ bl enable_mmu
+
+ mov lr, r8 @ restore link
+ mov pc, lr @ back to my caller
+ENDPROC(lowlevel_init)
+
+ENTRY(enable_mmu)
+ mrc p15, 0, r0, c2, c0, 2 @ TTBCR (Translation Table Base Control Register)
+ bic r0, r0, #0x37
+ orr r0, r0, #0x20 @ disable TTBR1
+ mcr p15, 0, r0, c2, c0, 2
+
+ orr r0, r12, #0x8 @ Outer Cacheability for table walks: WBWA
+ mcr p15, 0, r0, c2, c0, 0 @ TTBR0
+
+ mov r0, #0
+ mcr p15, 0, r0, c8, c7, 0 @ invalidate TLBs
+
+ mov r0, #-1 @ manager for all domains (No permission check)
+ mcr p15, 0, r0, c3, c0, 0 @ DACR (Domain Access Control Register)
+
+ dsb
+ isb
+ /*
+ * MMU on:
+ * TLBs was already invalidated in "../start.S"
+ * So, we don't need to invalidate it here.
+ */
+ mrc p15, 0, r0, c1, c0, 0 @ SCTLR (System Control Register)
+ orr r0, r0, #(CR_C | CR_M) @ MMU and Dcache enable
+ mcr p15, 0, r0, c1, c0, 0
+
+ mov pc, lr
+ENDPROC(enable_mmu)
+
+/*
+ * For PH1-Pro4 or older SoCs, the size of WAY is 32KB.
+ * It is large enough for tmp RAM.
+ */
+#define BOOT_RAM_SIZE (SZ_32K)
+#define BOOT_RAM_BASE ((CONFIG_SPL_STACK) - (BOOT_RAM_SIZE))
+#define BOOT_RAM_WAYS (0x00000100) @ way 8
+
+#define SSCO_BASE 0x506c0000
+#define SSCOPE 0x244
+#define SSCOQM 0x248
+#define SSCOQAD 0x24c
+#define SSCOQSZ 0x250
+#define SSCOQWN 0x258
+#define SSCOPPQSEF 0x25c
+#define SSCOLPQS 0x260
+
+ENTRY(setup_init_ram)
+ ldr r1, = SSCO_BASE
+
+ /* Touch to zero for the boot way */
+0: ldr r0, = 0x00408006 @ touch to zero with address range
+ str r0, [r1, #SSCOQM]
+ ldr r0, = BOOT_RAM_BASE
+ str r0, [r1, #SSCOQAD]
+ ldr r0, = BOOT_RAM_SIZE
+ str r0, [r1, #SSCOQSZ]
+ ldr r0, = BOOT_RAM_WAYS
+ str r0, [r1, #SSCOQWN]
+ ldr r0, [r1, #SSCOPPQSEF]
+ cmp r0, #0 @ check if the command is successfully set
+ bne 0b @ try again if an error occurs
+
+1: ldr r0, [r1, #SSCOLPQS]
+ cmp r0, #0x4
+ bne 1b @ wait until the operation is completed
+ str r0, [r1, #SSCOLPQS] @ clear the complete notification flag
+
+ mov pc, lr
+ENDPROC(setup_init_ram)
+
+#define DEVICE 0x00002002 /* Non-shareable Device */
+#define NORMAL 0x0000000e /* Normal Memory Write-Back, No Write-Allocate */
+
+ENTRY(create_page_table)
+ ldr r0, = DEVICE
+ ldr r1, = BOOT_RAM_BASE
+ mov r12, r1 @ r12 is preserved during D-cache flush
+0: str r0, [r1], #4 @ specify all the sections as Device
+ adds r0, r0, #0x00100000
+ bcc 0b
+
+ ldr r0, = NORMAL
+ str r0, [r12] @ mark the first section as Normal
+ add r0, r0, #0x00100000
+ str r0, [r12, #4] @ mark the second section as Normal
+ mov pc, lr
+ENDPROC(create_page_table)
diff --git a/roms/u-boot/arch/arm/mach-uniphier/arm32/psci.c b/roms/u-boot/arch/arm/mach-uniphier/arm32/psci.c
new file mode 100644
index 000000000..fbb6ebca7
--- /dev/null
+++ b/roms/u-boot/arch/arm/mach-uniphier/arm32/psci.c
@@ -0,0 +1,162 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2016 Socionext Inc.
+ * Author: Masahiro Yamada <yamada.masahiro@socionext.com>
+ */
+
+#include <cpu_func.h>
+#include <linux/bitops.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/printk.h>
+#include <linux/psci.h>
+#include <linux/sizes.h>
+#include <asm/processor.h>
+#include <asm/psci.h>
+#include <asm/secure.h>
+#include <asm/system.h>
+
+#include "../debug.h"
+#include "../soc-info.h"
+#include "arm-mpcore.h"
+#include "cache-uniphier.h"
+
+#define UNIPHIER_SMPCTRL_ROM_RSV2 0x59801208
+
+void uniphier_smp_trampoline(void);
+void uniphier_smp_trampoline_end(void);
+u32 uniphier_smp_booted[CONFIG_ARMV7_PSCI_NR_CPUS];
+
+static int uniphier_get_nr_cpus(void)
+{
+ switch (uniphier_get_soc_id()) {
+ case UNIPHIER_PRO4_ID:
+ case UNIPHIER_PRO5_ID:
+ return 2;
+ case UNIPHIER_PXS2_ID:
+ case UNIPHIER_LD6B_ID:
+ return 4;
+ default:
+ return 1;
+ }
+}
+
+static void uniphier_smp_kick_all_cpus(void)
+{
+ const u32 target_ways = BIT(0);
+ size_t trmp_size;
+ u32 trmp_src = (unsigned long)uniphier_smp_trampoline;
+ u32 trmp_src_end = (unsigned long)uniphier_smp_trampoline_end;
+ u32 trmp_dest, trmp_dest_end;
+ int nr_cpus, i;
+ int timeout = 1000;
+
+ nr_cpus = uniphier_get_nr_cpus();
+ if (nr_cpus == 1)
+ return;
+
+ for (i = 0; i < nr_cpus; i++) /* lock ways for all CPUs */
+ uniphier_cache_set_active_ways(i, 0);
+ uniphier_cache_inv_way(target_ways);
+ uniphier_cache_enable();
+
+ /* copy trampoline code */
+ uniphier_cache_prefetch_range(trmp_src, trmp_src_end, target_ways);
+
+ trmp_size = trmp_src_end - trmp_src;
+
+ trmp_dest = trmp_src & (SZ_64K - 1);
+ trmp_dest += SZ_1M - SZ_64K * 2;
+
+ trmp_dest_end = trmp_dest + trmp_size;
+
+ uniphier_cache_touch_range(trmp_dest, trmp_dest_end, target_ways);
+
+ writel(trmp_dest, UNIPHIER_SMPCTRL_ROM_RSV2);
+
+ asm("dsb ishst\n" /* Ensure the write to ROM_RSV2 is visible */
+ "sev"); /* Bring up all secondary CPUs from Boot ROM into U-Boot */
+
+ while (--timeout) {
+ int all_booted = 1;
+
+ for (i = 1; i < nr_cpus; i++)
+ if (!uniphier_smp_booted[i])
+ all_booted = 0;
+ if (all_booted)
+ break;
+ udelay(1);
+
+ /* barrier here because uniphier_smp_booted[] may be updated */
+ cpu_relax();
+ }
+
+ if (!timeout)
+ pr_warn("warning: some of secondary CPUs may not boot\n");
+
+ uniphier_cache_disable();
+}
+
+void psci_board_init(void)
+{
+ unsigned long scu_base;
+ u32 scu_ctrl, tmp;
+
+ asm("mrc p15, 4, %0, c15, c0, 0" : "=r" (scu_base));
+
+ scu_ctrl = readl(scu_base + 0x30);
+ if (!(scu_ctrl & 1))
+ writel(scu_ctrl | 0x1, scu_base + 0x30);
+
+ scu_ctrl = readl(scu_base + SCU_CTRL);
+ scu_ctrl |= SCU_ENABLE | SCU_STANDBY_ENABLE;
+ writel(scu_ctrl, scu_base + SCU_CTRL);
+
+ tmp = readl(scu_base + SCU_SNSAC);
+ tmp |= 0xfff;
+ writel(tmp, scu_base + SCU_SNSAC);
+
+ uniphier_smp_kick_all_cpus();
+}
+
+void psci_arch_init(void)
+{
+ u32 actlr;
+
+ asm("mrc p15, 0, %0, c1, c0, 1" : "=r" (actlr));
+ actlr |= 0x41; /* set SMP and FW bits */
+ asm("mcr p15, 0, %0, c1, c0, 1" : : "r" (actlr));
+}
+
+u32 uniphier_psci_holding_pen_release __secure_data = 0xffffffff;
+
+s32 __secure psci_cpu_on(u32 function_id, u32 cpuid, u32 entry_point,
+ u32 context_id)
+{
+ u32 cpu = cpuid & 0xff;
+
+ debug_puts("[U-Boot PSCI] psci_cpu_on: cpuid=");
+ debug_puth(cpuid);
+ debug_puts(", entry_point=");
+ debug_puth(entry_point);
+ debug_puts(", context_id=");
+ debug_puth(context_id);
+ debug_puts("\n");
+
+ psci_save(cpu, entry_point, context_id);
+
+ /* We assume D-cache is off, so do not call flush_dcache() here */
+ uniphier_psci_holding_pen_release = cpu;
+
+ /* Send an event to wake up the secondary CPU. */
+ asm("dsb ishst\n"
+ "sev");
+
+ return PSCI_RET_SUCCESS;
+}
+
+void __secure psci_system_reset(void)
+{
+ reset_cpu();
+}
diff --git a/roms/u-boot/arch/arm/mach-uniphier/arm32/psci_smp.S b/roms/u-boot/arch/arm/mach-uniphier/arm32/psci_smp.S
new file mode 100644
index 000000000..65a06ae23
--- /dev/null
+++ b/roms/u-boot/arch/arm/mach-uniphier/arm32/psci_smp.S
@@ -0,0 +1,39 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright (C) 2016 Socionext Inc.
+ * Author: Masahiro Yamada <yamada.masahiro@socionext.com>
+ */
+
+#include <linux/linkage.h>
+#include <asm/system.h>
+
+ .section ._secure.text, "ax"
+
+ENTRY(uniphier_smp_trampoline)
+ ldr r0, 0f
+ mrc p15, 0, r1, c1, c0, 0 @ SCTLR (System Control Register)
+ orr r1, r1, #CR_I @ Enable ICache
+ bic r1, r1, #(CR_C | CR_M) @ Disable MMU and Dcache
+ mcr p15, 0, r1, c1, c0, 0
+
+ bx r0
+0: .word uniphier_secondary_startup
+ .globl uniphier_smp_trampoline_end
+uniphier_smp_trampoline_end:
+ENDPROC(uniphier_smp_trampoline)
+
+LENTRY(uniphier_secondary_startup)
+ mrc p15, 0, r1, c0, c0, 5 @ MPIDR (Multiprocessor Affinity Reg)
+ and r1, r1, #0xff
+
+ ldr r2, =uniphier_smp_booted
+ mov r0, #1
+ str r0, [r2, r1, lsl #2]
+
+ ldr r2, =uniphier_psci_holding_pen_release
+pen: ldr r0, [r2]
+ cmp r0, r1
+ beq psci_cpu_entry
+ wfe
+ b pen
+ENDPROC(uniphier_secondary_startup)
diff --git a/roms/u-boot/arch/arm/mach-uniphier/arm32/timer.c b/roms/u-boot/arch/arm/mach-uniphier/arm32/timer.c
new file mode 100644
index 000000000..a40bdf170
--- /dev/null
+++ b/roms/u-boot/arch/arm/mach-uniphier/arm32/timer.c
@@ -0,0 +1,39 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2012-2015 Masahiro Yamada <yamada.masahiro@socionext.com>
+ */
+
+#include <config.h>
+#include <init.h>
+#include <linux/io.h>
+
+#include "arm-mpcore.h"
+
+#define PERIPHCLK (50 * 1000 * 1000) /* 50 MHz */
+#define PRESCALER ((PERIPHCLK) / (CONFIG_SYS_TIMER_RATE) - 1)
+
+static void *get_global_timer_base(void)
+{
+ void *val;
+
+ asm("mrc p15, 4, %0, c15, c0, 0" : "=r" (val) : : "memory");
+
+ return val + GLOBAL_TIMER_OFFSET;
+}
+
+unsigned long timer_read_counter(void)
+{
+ /*
+ * ARM 64bit Global Timer is too much for our purpose.
+ * We use only lower 32 bit of the timer counter.
+ */
+ return readl(get_global_timer_base() + GTIMER_CNT_L);
+}
+
+int timer_init(void)
+{
+ /* enable timer */
+ writel(PRESCALER << 8 | 1, get_global_timer_base() + GTIMER_CTRL);
+
+ return 0;
+}