summaryrefslogtreecommitdiff
path: root/arch/arm/mach-uniphier/arm32
diff options
context:
space:
mode:
authorMasahiro Yamada <yamada.masahiro@socionext.com>2016-02-26 18:59:44 +0900
committerMasahiro Yamada <yamada.masahiro@socionext.com>2016-03-01 00:33:24 +0900
commitfe5ea57bdbdeb8429793faaca2d6bd5f38218fe3 (patch)
tree9d438a0865a464935e49f0eec198904a3dfd2cd8 /arch/arm/mach-uniphier/arm32
parent2247c332db395ef87a0e2f6ed16a9de6959fe204 (diff)
downloadu-boot-imx-fe5ea57bdbdeb8429793faaca2d6bd5f38218fe3.zip
u-boot-imx-fe5ea57bdbdeb8429793faaca2d6bd5f38218fe3.tar.gz
u-boot-imx-fe5ea57bdbdeb8429793faaca2d6bd5f38218fe3.tar.bz2
ARM: uniphier: prepare directory structure for ARMv8 SoC support
Before adding ARMv8 support, this commit refactors the directory structure. Move ARMv7 specific files to arch/arm/mach-uniphier/arm32 to avoid a mess by mixture of ARMv7 and ARMv8 code. Also move the "select CPU_V7" to the lower-level menu because we will have to select ARM64 instead of CPU_V7 for ARMv8 SoCs. Signed-off-by: Masahiro Yamada <yamada.masahiro@socionext.com>
Diffstat (limited to 'arch/arm/mach-uniphier/arm32')
-rw-r--r--arch/arm/mach-uniphier/arm32/Makefile13
-rw-r--r--arch/arm/mach-uniphier/arm32/arm-mpcore.h46
-rw-r--r--arch/arm/mach-uniphier/arm32/cache_uniphier.c156
-rw-r--r--arch/arm/mach-uniphier/arm32/debug_ll.S186
-rw-r--r--arch/arm/mach-uniphier/arm32/late_lowlevel_init.S18
-rw-r--r--arch/arm/mach-uniphier/arm32/lowlevel_init.S207
-rw-r--r--arch/arm/mach-uniphier/arm32/ssc-regs.h65
-rw-r--r--arch/arm/mach-uniphier/arm32/timer.c39
8 files changed, 730 insertions, 0 deletions
diff --git a/arch/arm/mach-uniphier/arm32/Makefile b/arch/arm/mach-uniphier/arm32/Makefile
new file mode 100644
index 0000000..376c06b
--- /dev/null
+++ b/arch/arm/mach-uniphier/arm32/Makefile
@@ -0,0 +1,13 @@
+#
+# 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
+endif
+
+obj-y += timer.o
diff --git a/arch/arm/mach-uniphier/arm32/arm-mpcore.h b/arch/arm/mach-uniphier/arm32/arm-mpcore.h
new file mode 100644
index 0000000..cf7cd46
--- /dev/null
+++ b/arch/arm/mach-uniphier/arm32/arm-mpcore.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2011-2014 Panasonic Corporation
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#ifndef ARCH_ARM_MPCORE_H
+#define ARCH_ARM_MPCORE_H
+
+/* Snoop Control Unit */
+#define SCU_OFFSET 0x00
+
+/* SCU Control Register */
+#define SCU_CTRL 0x00
+/* 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/arch/arm/mach-uniphier/arm32/cache_uniphier.c b/arch/arm/mach-uniphier/arm32/cache_uniphier.c
new file mode 100644
index 0000000..4398114
--- /dev/null
+++ b/arch/arm/mach-uniphier/arm32/cache_uniphier.c
@@ -0,0 +1,156 @@
+/*
+ * Copyright (C) 2012-2015 Masahiro Yamada <yamada.masahiro@socionext.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <linux/io.h>
+#include <asm/armv7.h>
+
+#include "ssc-regs.h"
+
+#ifdef CONFIG_UNIPHIER_L2CACHE_ON
+static void uniphier_cache_sync(void)
+{
+ writel(SSCOPE_CM_SYNC, SSCOPE); /* drain internal buffers */
+ readl(SSCOPE); /* need a read back to confirm */
+}
+
+static void uniphier_cache_maint_all(u32 operation)
+{
+ /* try until the command is successfully set */
+ do {
+ writel(SSCOQM_S_ALL | SSCOQM_CE | operation, SSCOQM);
+ } while (readl(SSCOPPQSEF) & (SSCOPPQSEF_FE | SSCOPPQSEF_OE));
+
+ /* wait until the operation is completed */
+ while (readl(SSCOLPQS) != SSCOLPQS_EF)
+ ;
+
+ /* clear the complete notification flag */
+ writel(SSCOLPQS_EF, SSCOLPQS);
+
+ uniphier_cache_sync();
+}
+
+void v7_outer_cache_flush_all(void)
+{
+ uniphier_cache_maint_all(SSCOQM_CM_WB_INV);
+}
+
+void v7_outer_cache_inval_all(void)
+{
+ uniphier_cache_maint_all(SSCOQM_CM_INV);
+}
+
+static void __uniphier_cache_maint_range(u32 start, u32 size, u32 operation)
+{
+ /* try until the command is successfully set */
+ do {
+ writel(SSCOQM_S_ADDRESS | SSCOQM_CE | operation, SSCOQM);
+ writel(start, SSCOQAD);
+ writel(size, SSCOQSZ);
+
+ } while (readl(SSCOPPQSEF) & (SSCOPPQSEF_FE | SSCOPPQSEF_OE));
+
+ /* wait until the operation is completed */
+ while (readl(SSCOLPQS) != SSCOLPQS_EF)
+ ;
+
+ /* clear the complete notification flag */
+ writel(SSCOLPQS_EF, SSCOLPQS);
+}
+
+static void uniphier_cache_maint_range(u32 start, u32 end, u32 operation)
+{
+ u32 size;
+
+ /*
+ * If start address is not aligned to cache-line,
+ * do cache operation for the first cache-line
+ */
+ start = start & ~(SSC_LINE_SIZE - 1);
+
+ size = end - start;
+
+ if (unlikely(size >= (u32)(-SSC_LINE_SIZE))) {
+ /* this means cache operation for all range */
+ uniphier_cache_maint_all(operation);
+ return;
+ }
+
+ /*
+ * If end address is not aligned to cache-line,
+ * do cache operation for the last cache-line
+ */
+ size = ALIGN(size, SSC_LINE_SIZE);
+
+ while (size) {
+ u32 chunk_size = size > SSC_RANGE_OP_MAX_SIZE ?
+ SSC_RANGE_OP_MAX_SIZE : size;
+ __uniphier_cache_maint_range(start, chunk_size, operation);
+
+ start += chunk_size;
+ size -= chunk_size;
+ }
+
+ uniphier_cache_sync();
+}
+
+void v7_outer_cache_flush_range(u32 start, u32 end)
+{
+ uniphier_cache_maint_range(start, end, SSCOQM_CM_WB_INV);
+}
+
+void v7_outer_cache_inval_range(u32 start, u32 end)
+{
+ if (start & (SSC_LINE_SIZE - 1)) {
+ start &= ~(SSC_LINE_SIZE - 1);
+ __uniphier_cache_maint_range(start, SSC_LINE_SIZE,
+ SSCOQM_CM_WB_INV);
+ start += SSC_LINE_SIZE;
+ }
+
+ if (start >= end) {
+ uniphier_cache_sync();
+ return;
+ }
+
+ if (end & (SSC_LINE_SIZE - 1)) {
+ end &= ~(SSC_LINE_SIZE - 1);
+ __uniphier_cache_maint_range(end, SSC_LINE_SIZE,
+ SSCOQM_CM_WB_INV);
+ }
+
+ if (start >= end) {
+ uniphier_cache_sync();
+ return;
+ }
+
+ uniphier_cache_maint_range(start, end, SSCOQM_CM_INV);
+}
+
+void v7_outer_cache_enable(void)
+{
+ u32 tmp;
+
+ writel(U32_MAX, SSCLPDAWCR); /* activate all ways */
+ tmp = readl(SSCC);
+ tmp |= SSCC_ON;
+ writel(tmp, SSCC);
+}
+#endif
+
+void v7_outer_cache_disable(void)
+{
+ u32 tmp;
+ tmp = readl(SSCC);
+ tmp &= ~SSCC_ON;
+ writel(tmp, SSCC);
+}
+
+void enable_caches(void)
+{
+ dcache_enable();
+}
diff --git a/arch/arm/mach-uniphier/arm32/debug_ll.S b/arch/arm/mach-uniphier/arm32/debug_ll.S
new file mode 100644
index 0000000..a70954c
--- /dev/null
+++ b/arch/arm/mach-uniphier/arm32/debug_ll.S
@@ -0,0 +1,186 @@
+/*
+ * On-chip UART initializaion for low-level debugging
+ *
+ * Copyright (C) 2014-2015 Masahiro Yamada <yamada.masahiro@socionext.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#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 BAUDRATE 115200
+#define DIV_ROUND(x, d) (((x) + ((d) / 2)) / (d))
+
+ENTRY(debug_ll_init)
+ ldr r0, =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_PH1_SLD3)
+#define PH1_SLD3_UART_CLK 36864000
+ cmp r1, #0x25
+ bne ph1_sld3_end
+
+ sg_set_pinsel 64, 1, 4, 4, r0, r1 @ TXD0 -> TXD0
+
+ ldr r0, =BCSCR5
+ ldr r1, =0x24440000
+ str r1, [r0]
+
+ ldr r0, =SC_CLKCTRL
+ ldr r1, [r0]
+ orr r1, r1, #SC_CLKCTRL_CEN_PERI
+ str r1, [r0]
+
+ ldr r3, =DIV_ROUND(PH1_SLD3_UART_CLK, 16 * BAUDRATE)
+
+ b init_uart
+ph1_sld3_end:
+#endif
+#if defined(CONFIG_ARCH_UNIPHIER_PH1_LD4)
+#define PH1_LD4_UART_CLK 36864000
+ cmp r1, #0x26
+ bne ph1_ld4_end
+
+ ldr r0, =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(PH1_LD4_UART_CLK, 16 * BAUDRATE)
+
+ b init_uart
+ph1_ld4_end:
+#endif
+#if defined(CONFIG_ARCH_UNIPHIER_PH1_PRO4)
+#define PH1_PRO4_UART_CLK 73728000
+ cmp r1, #0x28
+ bne ph1_pro4_end
+
+ sg_set_pinsel 128, 0, 4, 8, r0, r1 @ TXD0 -> TXD0
+
+ ldr r0, =SG_LOADPINCTRL
+ mov r1, #1
+ str r1, [r0]
+
+ ldr r0, =SC_CLKCTRL
+ ldr r1, [r0]
+ orr r1, r1, #SC_CLKCTRL_CEN_PERI
+ str r1, [r0]
+
+ ldr r3, =DIV_ROUND(PH1_PRO4_UART_CLK, 16 * BAUDRATE)
+
+ b init_uart
+ph1_pro4_end:
+#endif
+#if defined(CONFIG_ARCH_UNIPHIER_PH1_SLD8)
+#define PH1_SLD8_UART_CLK 80000000
+ cmp r1, #0x29
+ bne ph1_sld8_end
+
+ ldr r0, =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(PH1_SLD8_UART_CLK, 16 * BAUDRATE)
+
+ b init_uart
+ph1_sld8_end:
+#endif
+#if defined(CONFIG_ARCH_UNIPHIER_PH1_PRO5)
+#define PH1_PRO5_UART_CLK 73728000
+ cmp r1, #0x2A
+ bne ph1_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_LOADPINCTRL
+ mov r1, #1
+ str r1, [r0]
+
+ ldr r0, =SC_CLKCTRL
+ ldr r1, [r0]
+ orr r1, r1, #SC_CLKCTRL_CEN_PERI
+ str r1, [r0]
+
+ ldr r3, =DIV_ROUND(PH1_PRO5_UART_CLK, 16 * BAUDRATE)
+
+ b init_uart
+ph1_pro5_end:
+#endif
+#if defined(CONFIG_ARCH_UNIPHIER_PROXSTREAM2)
+#define PROXSTREAM2_UART_CLK 88900000
+ cmp r1, #0x2E
+ bne proxstream2_end
+
+ ldr r0, =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_CLKCTRL
+ ldr r1, [r0]
+ orr r1, r1, #SC_CLKCTRL_CEN_PERI
+ str r1, [r0]
+
+ ldr r3, =DIV_ROUND(PROXSTREAM2_UART_CLK, 16 * BAUDRATE)
+
+ b init_uart
+proxstream2_end:
+#endif
+#if defined(CONFIG_ARCH_UNIPHIER_PH1_LD6B)
+#define PH1_LD6B_UART_CLK 88900000
+ cmp r1, #0x2F
+ bne ph1_ld6b_end
+
+ ldr r0, =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_CLKCTRL
+ ldr r1, [r0]
+ orr r1, r1, #SC_CLKCTRL_CEN_PERI
+ str r1, [r0]
+
+ ldr r3, =DIV_ROUND(PH1_LD6B_UART_CLK, 16 * BAUDRATE)
+
+ b init_uart
+ph1_ld6b_end:
+#endif
+
+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/arch/arm/mach-uniphier/arm32/late_lowlevel_init.S b/arch/arm/mach-uniphier/arm32/late_lowlevel_init.S
new file mode 100644
index 0000000..cce91df
--- /dev/null
+++ b/arch/arm/mach-uniphier/arm32/late_lowlevel_init.S
@@ -0,0 +1,18 @@
+/*
+ * Copyright (C) 2015 Socionext Inc.
+ * Author: Masahiro Yamada <yamada.masahiro@socionext.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <linux/linkage.h>
+
+#include "ssc-regs.h"
+
+ENTRY(lowlevel_init)
+ ldr r1, = SSCC
+ ldr r0, [r1]
+ bic r0, r0, #SSCC_ON @ L2 disable
+ str r0, [r1]
+ mov pc, lr
+ENDPROC(lowlevel_init)
diff --git a/arch/arm/mach-uniphier/arm32/lowlevel_init.S b/arch/arm/mach-uniphier/arm32/lowlevel_init.S
new file mode 100644
index 0000000..dd03ad8
--- /dev/null
+++ b/arch/arm/mach-uniphier/arm32/lowlevel_init.S
@@ -0,0 +1,207 @@
+/*
+ * Copyright (C) 2012-2015 Masahiro Yamada <yamada.masahiro@socionext.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <config.h>
+#include <linux/linkage.h>
+#include <linux/sizes.h>
+#include <asm/system.h>
+
+#include "ssc-regs.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 talbe
+
+ /*
+ * Now we are using the page table embedded in the Boot ROM.
+ * It is not handy since it is not a straight mapped table for sLD3.
+ * Also, the access to the external bus is prohibited. 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_WAY_BITS (0x00000100) /* way 8 */
+
+ENTRY(setup_init_ram)
+ /*
+ * Touch to zero for the boot way
+ */
+0:
+ /*
+ * set SSCOQM, SSCOQAD, SSCOQSZ, SSCOQWN in this order
+ */
+ ldr r0, = 0x00408006 @ touch to zero with address range
+ ldr r1, = SSCOQM
+ str r0, [r1]
+ ldr r0, = BOOT_RAM_BASE
+ ldr r1, = SSCOQAD
+ str r0, [r1]
+ ldr r0, = BOOT_RAM_SIZE
+ ldr r1, = SSCOQSZ
+ str r0, [r1]
+ ldr r0, = BOOT_WAY_BITS
+ ldr r1, = SSCOQWN
+ str r0, [r1]
+ ldr r1, = SSCOPPQSEF
+ ldr r0, [r1]
+ cmp r0, #0 @ check if the command is successfully set
+ bne 0b @ try again if an error occurs
+
+ ldr r1, = SSCOLPQS
+1:
+ ldr r0, [r1]
+ cmp r0, #0x4
+ bne 1b @ wait until the operation is completed
+ str r0, [r1] @ 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)
+
+/* We don't use Thumb instructions for now */
+#define ARM(x...) x
+#define THUMB(x...)
+
+/*
+ * v7_flush_dcache_all()
+ *
+ * Flush the whole D-cache.
+ *
+ * Corrupted registers: r0-r7, r9-r11 (r6 only in Thumb mode)
+ *
+ * - mm - mm_struct describing address space
+ *
+ * Note: copied from arch/arm/mm/cache-v7.S of Linux 4.4
+ */
+ENTRY(v7_flush_dcache_all)
+ dmb @ ensure ordering with previous memory accesses
+ mrc p15, 1, r0, c0, c0, 1 @ read clidr
+ mov r3, r0, lsr #23 @ move LoC into position
+ ands r3, r3, #7 << 1 @ extract LoC*2 from clidr
+ beq finished @ if loc is 0, then no need to clean
+start_flush_levels:
+ mov r10, #0 @ start clean at cache level 0
+flush_levels:
+ add r2, r10, r10, lsr #1 @ work out 3x current cache level
+ mov r1, r0, lsr r2 @ extract cache type bits from clidr
+ and r1, r1, #7 @ mask of the bits for current cache only
+ cmp r1, #2 @ see what cache we have at this level
+ blt skip @ skip if no cache, or just i-cache
+ mcr p15, 2, r10, c0, c0, 0 @ select current cache level in cssr
+ isb @ isb to sych the new cssr&csidr
+ mrc p15, 1, r1, c0, c0, 0 @ read the new csidr
+ and r2, r1, #7 @ extract the length of the cache lines
+ add r2, r2, #4 @ add 4 (line length offset)
+ movw r4, #0x3ff
+ ands r4, r4, r1, lsr #3 @ find maximum number on the way size
+ clz r5, r4 @ find bit position of way size increment
+ movw r7, #0x7fff
+ ands r7, r7, r1, lsr #13 @ extract max number of the index size
+loop1:
+ mov r9, r7 @ create working copy of max index
+loop2:
+ ARM( orr r11, r10, r4, lsl r5 ) @ factor way and cache number into r11
+ THUMB( lsl r6, r4, r5 )
+ THUMB( orr r11, r10, r6 ) @ factor way and cache number into r11
+ ARM( orr r11, r11, r9, lsl r2 ) @ factor index number into r11
+ THUMB( lsl r6, r9, r2 )
+ THUMB( orr r11, r11, r6 ) @ factor index number into r11
+ mcr p15, 0, r11, c7, c14, 2 @ clean & invalidate by set/way
+ subs r9, r9, #1 @ decrement the index
+ bge loop2
+ subs r4, r4, #1 @ decrement the way
+ bge loop1
+skip:
+ add r10, r10, #2 @ increment cache number
+ cmp r3, r10
+ bgt flush_levels
+finished:
+ mov r10, #0 @ swith back to cache level 0
+ mcr p15, 2, r10, c0, c0, 0 @ select current cache level in cssr
+ dsb st
+ isb
+ mov pc, lr
+ENDPROC(v7_flush_dcache_all)
diff --git a/arch/arm/mach-uniphier/arm32/ssc-regs.h b/arch/arm/mach-uniphier/arm32/ssc-regs.h
new file mode 100644
index 0000000..02fca3b
--- /dev/null
+++ b/arch/arm/mach-uniphier/arm32/ssc-regs.h
@@ -0,0 +1,65 @@
+/*
+ * UniPhier System Cache (L2 Cache) registers
+ *
+ * Copyright (C) 2011-2014 Panasonic Corporation
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#ifndef ARCH_SSC_REGS_H
+#define ARCH_SSC_REGS_H
+
+#define SSCC 0x500c0000
+#define SSCC_BST (0x1 << 20)
+#define SSCC_ACT (0x1 << 19)
+#define SSCC_WTG (0x1 << 18)
+#define SSCC_PRD (0x1 << 17)
+#define SSCC_WBWA (0x1 << 16)
+#define SSCC_EX (0x1 << 13)
+#define SSCC_ON (0x1 << 0)
+
+#define SSCLPDAWCR 0x500c0030
+
+#define SSCOPE 0x506c0244
+#define SSCOPE_CM_SYNC 0x00000008
+
+#define SSCOQM 0x506c0248
+#define SSCOQM_TID_MASK (0x3 << 21)
+#define SSCOQM_TID_BY_WAY (0x2 << 21)
+#define SSCOQM_TID_BY_INST_WAY (0x1 << 21)
+#define SSCOQM_TID_BY_DATA_WAY (0x0 << 21)
+#define SSCOQM_S_MASK (0x3 << 17)
+#define SSCOQM_S_WAY (0x2 << 17)
+#define SSCOQM_S_ALL (0x1 << 17)
+#define SSCOQM_S_ADDRESS (0x0 << 17)
+#define SSCOQM_CE (0x1 << 15)
+#define SSCOQM_CW (0x1 << 14)
+#define SSCOQM_CM_MASK (0x7)
+#define SSCOQM_CM_DIRT_TOUCH (0x7)
+#define SSCOQM_CM_ZERO_TOUCH (0x6)
+#define SSCOQM_CM_NORM_TOUCH (0x5)
+#define SSCOQM_CM_PREF_FETCH (0x4)
+#define SSCOQM_CM_SSC_FETCH (0x3)
+#define SSCOQM_CM_WB_INV (0x2)
+#define SSCOQM_CM_WB (0x1)
+#define SSCOQM_CM_INV (0x0)
+
+#define SSCOQAD 0x506c024c
+#define SSCOQSZ 0x506c0250
+#define SSCOQWN 0x506c0258
+
+#define SSCOPPQSEF 0x506c025c
+#define SSCOPPQSEF_FE (0x1 << 1)
+#define SSCOPPQSEF_OE (0x1 << 0)
+
+#define SSCOLPQS 0x506c0260
+#define SSCOLPQS_EF (0x1 << 2)
+#define SSCOLPQS_EST (0x1 << 1)
+#define SSCOLPQS_QST (0x1 << 0)
+
+#define SSCOQCE0 0x506c0270
+
+#define SSC_LINE_SIZE 128
+#define SSC_RANGE_OP_MAX_SIZE (0x00400000 - (SSC_LINE_SIZE))
+
+#endif /* ARCH_SSC_REGS_H */
diff --git a/arch/arm/mach-uniphier/arm32/timer.c b/arch/arm/mach-uniphier/arm32/timer.c
new file mode 100644
index 0000000..a34e30b
--- /dev/null
+++ b/arch/arm/mach-uniphier/arm32/timer.c
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2012-2015 Masahiro Yamada <yamada.masahiro@socionext.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.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;
+}