aboutsummaryrefslogtreecommitdiff
path: root/arch
diff options
context:
space:
mode:
Diffstat (limited to 'arch')
-rw-r--r--arch/arm/Kconfig3
-rw-r--r--arch/arm/cpu/arm926ejs/Makefile1
-rw-r--r--arch/arm/cpu/arm926ejs/cpu.c13
-rw-r--r--arch/arm/cpu/arm926ejs/start.S19
-rw-r--r--arch/arm/cpu/arm926ejs/sunxi/Makefile5
-rw-r--r--arch/arm/cpu/arm926ejs/sunxi/config.mk6
-rw-r--r--arch/arm/cpu/arm926ejs/sunxi/fel_utils.S33
-rw-r--r--arch/arm/cpu/arm926ejs/sunxi/u-boot-spl.lds48
-rw-r--r--arch/arm/cpu/armv7/Kconfig5
-rw-r--r--arch/arm/cpu/armv7/start.S11
-rw-r--r--arch/arm/cpu/armv7/sunxi/Makefile4
-rw-r--r--arch/arm/cpu/armv7/sunxi/sram.c40
-rw-r--r--arch/arm/cpu/armv8/Makefile1
-rw-r--r--arch/arm/cpu/armv8/lowlevel_init.S43
-rw-r--r--arch/arm/dts/Makefile2
-rw-r--r--arch/arm/dts/suniv-f1c100s-licheepi-nano.dts26
-rw-r--r--arch/arm/dts/suniv-f1c100s.dtsi144
-rw-r--r--arch/arm/dts/sunxi-u-boot.dtsi2
-rw-r--r--arch/arm/include/asm/arch-sunxi/clock.h2
-rw-r--r--arch/arm/include/asm/arch-sunxi/clock_sun6i.h13
-rw-r--r--arch/arm/include/asm/arch-sunxi/cpu_sun4i.h7
-rw-r--r--arch/arm/include/asm/arch-sunxi/dram.h2
-rw-r--r--arch/arm/include/asm/arch-sunxi/dram_suniv.h46
-rw-r--r--arch/arm/include/asm/arch-sunxi/gpio.h1
-rw-r--r--arch/arm/mach-sunxi/Kconfig18
-rw-r--r--arch/arm/mach-sunxi/Makefile5
-rw-r--r--arch/arm/mach-sunxi/board.c109
-rw-r--r--arch/arm/mach-sunxi/clock.c3
-rw-r--r--arch/arm/mach-sunxi/clock_sun6i.c86
-rw-r--r--arch/arm/mach-sunxi/cpu_info.c2
-rw-r--r--arch/arm/mach-sunxi/dram_helpers.c4
-rw-r--r--arch/arm/mach-sunxi/dram_suniv.c420
-rw-r--r--arch/arm/mach-sunxi/timer.c (renamed from arch/arm/cpu/armv7/sunxi/timer.c)7
33 files changed, 988 insertions, 143 deletions
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index eb0f5bcfe54..9a62b557869 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -452,9 +452,6 @@ config ENABLE_ARM_SOC_BOOT0_HOOK
values, then choose this option, and create a file included as
<asm/arch/boot0.h> which contains the required assembler code.
-config ARM_CORTEX_CPU_IS_UP
- bool
-
config USE_ARCH_MEMCPY
bool "Use an assembly optimized implementation of memcpy"
default y if !ARM64
diff --git a/arch/arm/cpu/arm926ejs/Makefile b/arch/arm/cpu/arm926ejs/Makefile
index b901b7c5c90..7f1436d76e1 100644
--- a/arch/arm/cpu/arm926ejs/Makefile
+++ b/arch/arm/cpu/arm926ejs/Makefile
@@ -15,6 +15,7 @@ endif
obj-$(CONFIG_MX27) += mx27/
obj-$(if $(filter mxs,$(SOC)),y) += mxs/
obj-$(if $(filter spear,$(SOC)),y) += spear/
+obj-$(CONFIG_ARCH_SUNXI) += sunxi/
# some files can only build in ARM or THUMB2, not THUMB1
diff --git a/arch/arm/cpu/arm926ejs/cpu.c b/arch/arm/cpu/arm926ejs/cpu.c
index 93d7a02ed4c..2ce413a7f86 100644
--- a/arch/arm/cpu/arm926ejs/cpu.c
+++ b/arch/arm/cpu/arm926ejs/cpu.c
@@ -21,6 +21,19 @@
static void cache_flush(void);
+/************************************************************
+ * sdelay() - simple spin loop. Will be constant time as
+ * its generally used in bypass conditions only. This
+ * is necessary until timers are accessible.
+ *
+ * not inline to increase chances its in cache when called
+ *************************************************************/
+void sdelay(unsigned long loops)
+{
+ __asm__ volatile ("1:\n" "subs %0, %1, #1\n"
+ "bne 1b":"=r" (loops):"0"(loops));
+}
+
int cleanup_before_linux (void)
{
/*
diff --git a/arch/arm/cpu/arm926ejs/start.S b/arch/arm/cpu/arm926ejs/start.S
index 0afcc47aad7..aca7793c579 100644
--- a/arch/arm/cpu/arm926ejs/start.S
+++ b/arch/arm/cpu/arm926ejs/start.S
@@ -17,6 +17,7 @@
#include <asm-offsets.h>
#include <config.h>
#include <common.h>
+#include <linux/linkage.h>
/*
*************************************************************************
@@ -32,8 +33,13 @@
*/
.globl reset
+ .globl save_boot_params_ret
+ .type save_boot_params_ret,%function
reset:
+ /* Allow the board to save important registers */
+ b save_boot_params
+save_boot_params_ret:
/*
* set the cpu to SVC32 mode
*/
@@ -110,3 +116,16 @@ flush_dcache:
#endif
mov pc, lr /* back to my caller */
#endif /* CONFIG_IS_ENABLED(SKIP_LOWLEVEL_INIT) */
+
+/*************************************************************************
+ *
+ * void save_boot_params(u32 r0, u32 r1, u32 r2, u32 r3)
+ * __attribute__((weak));
+ *
+ * Stack pointer is not yet initialized at this moment
+ * Don't save anything to stack even if compiled with -O0
+ *
+ *************************************************************************/
+WEAK(save_boot_params)
+ b save_boot_params_ret /* back to my caller */
+ENDPROC(save_boot_params)
diff --git a/arch/arm/cpu/arm926ejs/sunxi/Makefile b/arch/arm/cpu/arm926ejs/sunxi/Makefile
new file mode 100644
index 00000000000..7d8b959dcd1
--- /dev/null
+++ b/arch/arm/cpu/arm926ejs/sunxi/Makefile
@@ -0,0 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0+
+# (C) Copyright 2012 Henrik Nordstrom <henrik@henriknordstrom.net>
+
+obj-y += fel_utils.o
+CFLAGS_fel_utils.o := -marm
diff --git a/arch/arm/cpu/arm926ejs/sunxi/config.mk b/arch/arm/cpu/arm926ejs/sunxi/config.mk
new file mode 100644
index 00000000000..76ffec9df6a
--- /dev/null
+++ b/arch/arm/cpu/arm926ejs/sunxi/config.mk
@@ -0,0 +1,6 @@
+# Build a combined spl + u-boot image
+ifdef CONFIG_SPL
+ifndef CONFIG_SPL_BUILD
+ALL-y += u-boot-sunxi-with-spl.bin
+endif
+endif
diff --git a/arch/arm/cpu/arm926ejs/sunxi/fel_utils.S b/arch/arm/cpu/arm926ejs/sunxi/fel_utils.S
new file mode 100644
index 00000000000..08be7ed11aa
--- /dev/null
+++ b/arch/arm/cpu/arm926ejs/sunxi/fel_utils.S
@@ -0,0 +1,33 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Utility functions for FEL mode.
+ *
+ * Copyright (c) 2015 Google, Inc
+ */
+
+#include <asm-offsets.h>
+#include <config.h>
+#include <asm/system.h>
+#include <linux/linkage.h>
+
+ENTRY(save_boot_params)
+ ldr r0, =fel_stash
+ str sp, [r0, #0]
+ str lr, [r0, #4]
+ mrs lr, cpsr @ Read CPSR
+ str lr, [r0, #8]
+ mrc p15, 0, lr, c1, c0, 0 @ Read CP15 SCTLR Register
+ str lr, [r0, #12]
+ b save_boot_params_ret
+ENDPROC(save_boot_params)
+
+ENTRY(return_to_fel)
+ mov sp, r0
+ mov lr, r1
+ ldr r0, =fel_stash
+ ldr r1, [r0, #16]
+ mcr p15, 0, r1, c1, c0, 0 @ Write CP15 Control Register
+ ldr r1, [r0, #12]
+ msr cpsr, r1 @ Write CPSR
+ bx lr
+ENDPROC(return_to_fel)
diff --git a/arch/arm/cpu/arm926ejs/sunxi/u-boot-spl.lds b/arch/arm/cpu/arm926ejs/sunxi/u-boot-spl.lds
new file mode 100644
index 00000000000..9a000ac5d38
--- /dev/null
+++ b/arch/arm/cpu/arm926ejs/sunxi/u-boot-spl.lds
@@ -0,0 +1,48 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * (C) Copyright 2018
+ * Icenowy Zheng <icenowy@aosc.io>
+ *
+ * Based on arch/arm/cpu/armv7/sunxi/u-boot-spl.lds:
+ */
+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_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
+OUTPUT_ARCH(arm)
+ENTRY(_start)
+SECTIONS
+{
+ .text :
+ {
+ __start = .;
+ *(.vectors)
+ *(.text*)
+ } > .sram
+
+ . = ALIGN(4);
+ .rodata : { *(SORT_BY_ALIGNMENT(.rodata*)) } >.sram
+
+ . = ALIGN(4);
+ .data : { *(SORT_BY_ALIGNMENT(.data*)) } >.sram
+
+ . = ALIGN(4);
+ .u_boot_list : {
+ KEEP(*(SORT(.u_boot_list*)));
+ } > .sram
+
+ . = ALIGN(4);
+ __image_copy_end = .;
+ _end = .;
+
+ .bss :
+ {
+ . = ALIGN(4);
+ __bss_start = .;
+ *(.bss*)
+ . = ALIGN(4);
+ __bss_end = .;
+ } > .sdram
+}
diff --git a/arch/arm/cpu/armv7/Kconfig b/arch/arm/cpu/armv7/Kconfig
index 60bb0a9e1ec..2eeef3cba96 100644
--- a/arch/arm/cpu/armv7/Kconfig
+++ b/arch/arm/cpu/armv7/Kconfig
@@ -76,4 +76,9 @@ config ARMV7_LPAE
Say Y here to use the long descriptor page table format. This is
required if U-Boot runs in HYP mode.
+config SPL_ARMV7_SET_CORTEX_SMPEN
+ bool
+ help
+ Enable the ARM Cortex ACTLR.SMP enable bit on SPL startup.
+
endif
diff --git a/arch/arm/cpu/armv7/start.S b/arch/arm/cpu/armv7/start.S
index 698e15b8e18..af87a5432ae 100644
--- a/arch/arm/cpu/armv7/start.S
+++ b/arch/arm/cpu/armv7/start.S
@@ -173,6 +173,17 @@ ENDPROC(switch_to_hypervisor)
*
*************************************************************************/
ENTRY(cpu_init_cp15)
+
+#if CONFIG_IS_ENABLED(ARMV7_SET_CORTEX_SMPEN)
+ /*
+ * The Arm Cortex-A7 TRM says this bit must be enabled before
+ * "any cache or TLB maintenance operations are performed".
+ */
+ mrc p15, 0, r0, c1, c0, 1 @ read auxilary control register
+ orr r0, r0, #1 << 6 @ set SMP bit to enable coherency
+ mcr p15, 0, r0, c1, c0, 1 @ write auxilary control register
+#endif
+
/*
* Invalidate L1 I/D
*/
diff --git a/arch/arm/cpu/armv7/sunxi/Makefile b/arch/arm/cpu/armv7/sunxi/Makefile
index 1d40d6a18dc..3e975b366c4 100644
--- a/arch/arm/cpu/armv7/sunxi/Makefile
+++ b/arch/arm/cpu/armv7/sunxi/Makefile
@@ -5,11 +5,13 @@
# Based on some other Makefile
# (C) Copyright 2000-2003
# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
-obj-y += timer.o
obj-$(CONFIG_MACH_SUN6I) += tzpc.o
obj-$(CONFIG_MACH_SUN8I_H3) += tzpc.o
+obj-$(CONFIG_MACH_SUN6I) += sram.o
+obj-$(CONFIG_MACH_SUN8I) += sram.o
+
ifndef CONFIG_SPL_BUILD
obj-$(CONFIG_ARMV7_PSCI) += psci.o
endif
diff --git a/arch/arm/cpu/armv7/sunxi/sram.c b/arch/arm/cpu/armv7/sunxi/sram.c
new file mode 100644
index 00000000000..28564c2846a
--- /dev/null
+++ b/arch/arm/cpu/armv7/sunxi/sram.c
@@ -0,0 +1,40 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2012 Henrik Nordstrom <henrik@henriknordstrom.net>
+ *
+ * (C) Copyright 2007-2011
+ * Allwinner Technology Co., Ltd. <www.allwinnertech.com>
+ * Tom Cubie <tangliang@allwinnertech.com>
+ *
+ * SRAM init for older sunxi SoCs.
+ */
+
+#include <common.h>
+#include <init.h>
+#include <asm/io.h>
+
+void sunxi_sram_init(void)
+{
+ /*
+ * Undocumented magic taken from boot0, without this DRAM
+ * access gets messed up (seems cache related).
+ * The boot0 sources describe this as: "config ema for cache sram"
+ * Newer SoCs (A83T, H3 and anything beyond) don't need this anymore.
+ */
+ if (IS_ENABLED(CONFIG_MACH_SUN6I))
+ setbits_le32(SUNXI_SRAMC_BASE + 0x44, 0x1800);
+
+ if (IS_ENABLED(CONFIG_MACH_SUN8I)) {
+ uint version = sunxi_get_sram_id();
+
+ if (IS_ENABLED(CONFIG_MACH_SUN8I_A23)) {
+ if (version == 0x1650)
+ setbits_le32(SUNXI_SRAMC_BASE + 0x44, 0x1800);
+ else /* 0x1661 ? */
+ setbits_le32(SUNXI_SRAMC_BASE + 0x44, 0xc0);
+ } else if (IS_ENABLED(CONFIG_MACH_SUN8I_A33)) {
+ if (version != 0x1667)
+ setbits_le32(SUNXI_SRAMC_BASE + 0x44, 0xc0);
+ }
+ }
+}
diff --git a/arch/arm/cpu/armv8/Makefile b/arch/arm/cpu/armv8/Makefile
index d85ddde430a..85fe0475c86 100644
--- a/arch/arm/cpu/armv8/Makefile
+++ b/arch/arm/cpu/armv8/Makefile
@@ -42,6 +42,5 @@ obj-$(CONFIG_FSL_LAYERSCAPE) += fsl-layerscape/
obj-$(CONFIG_S32V234) += s32v234/
obj-$(CONFIG_TARGET_HIKEY) += hisilicon/
obj-$(CONFIG_ARMV8_PSCI) += psci.o
-obj-$(CONFIG_ARCH_SUNXI) += lowlevel_init.o
obj-$(CONFIG_TARGET_BCMNS3) += bcmns3/
obj-$(CONFIG_XEN) += xen/
diff --git a/arch/arm/cpu/armv8/lowlevel_init.S b/arch/arm/cpu/armv8/lowlevel_init.S
deleted file mode 100644
index f4f0cdce9b3..00000000000
--- a/arch/arm/cpu/armv8/lowlevel_init.S
+++ /dev/null
@@ -1,43 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0+ */
-/*
- * A lowlevel_init function that sets up the stack to call a C function to
- * perform further init.
- */
-
-#include <asm-offsets.h>
-#include <config.h>
-#include <linux/linkage.h>
-
-ENTRY(lowlevel_init)
- /*
- * Setup a temporary stack. Global data is not available yet.
- */
-#if defined(CONFIG_SPL_BUILD) && defined(CONFIG_SPL_STACK)
- ldr w0, =CONFIG_SPL_STACK
-#else
- ldr w0, =CONFIG_SYS_INIT_SP_ADDR
-#endif
- bic sp, x0, #0xf /* 16-byte alignment for ABI compliance */
-
- /*
- * Save the old LR(passed in x29) and the current LR to stack
- */
- stp x29, x30, [sp, #-16]!
-
- /*
- * Call the very early init function. This should do only the
- * absolute bare minimum to get started. It should not:
- *
- * - set up DRAM
- * - use global_data
- * - clear BSS
- * - try to start a console
- *
- * For boards with SPL this should be empty since SPL can do all of
- * this init in the SPL board_init_f() function which is called
- * immediately after this.
- */
- bl s_init
- ldp x29, x30, [sp]
- ret
-ENDPROC(lowlevel_init)
diff --git a/arch/arm/dts/Makefile b/arch/arm/dts/Makefile
index 0ed8de2a8f1..75ea7e8e375 100644
--- a/arch/arm/dts/Makefile
+++ b/arch/arm/dts/Makefile
@@ -504,6 +504,8 @@ dtb-$(CONFIG_STM32H7) += stm32h743i-disco.dtb \
stm32h743i-eval.dtb \
stm32h750i-art-pi.dtb
+dtb-$(CONFIG_MACH_SUNIV) += \
+ suniv-f1c100s-licheepi-nano.dtb
dtb-$(CONFIG_MACH_SUN4I) += \
sun4i-a10-a1000.dtb \
sun4i-a10-ba10-tvbox.dtb \
diff --git a/arch/arm/dts/suniv-f1c100s-licheepi-nano.dts b/arch/arm/dts/suniv-f1c100s-licheepi-nano.dts
new file mode 100644
index 00000000000..a1154e6c7cb
--- /dev/null
+++ b/arch/arm/dts/suniv-f1c100s-licheepi-nano.dts
@@ -0,0 +1,26 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR X11)
+/*
+ * Copyright 2018 Icenowy Zheng <icenowy@aosc.io>
+ */
+
+/dts-v1/;
+#include "suniv-f1c100s.dtsi"
+
+/ {
+ model = "Lichee Pi Nano";
+ compatible = "licheepi,licheepi-nano", "allwinner,suniv-f1c100s";
+
+ aliases {
+ serial0 = &uart0;
+ };
+
+ chosen {
+ stdout-path = "serial0:115200n8";
+ };
+};
+
+&uart0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart0_pe_pins>;
+ status = "okay";
+};
diff --git a/arch/arm/dts/suniv-f1c100s.dtsi b/arch/arm/dts/suniv-f1c100s.dtsi
new file mode 100644
index 00000000000..6100d3b75f6
--- /dev/null
+++ b/arch/arm/dts/suniv-f1c100s.dtsi
@@ -0,0 +1,144 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR X11)
+/*
+ * Copyright 2018 Icenowy Zheng <icenowy@aosc.io>
+ * Copyright 2018 Mesih Kilinc <mesihkilinc@gmail.com>
+ */
+
+/ {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ interrupt-parent = <&intc>;
+
+ clocks {
+ osc24M: clk-24M {
+ #clock-cells = <0>;
+ compatible = "fixed-clock";
+ clock-frequency = <24000000>;
+ clock-output-names = "osc24M";
+ };
+
+ osc32k: clk-32k {
+ #clock-cells = <0>;
+ compatible = "fixed-clock";
+ clock-frequency = <32768>;
+ clock-output-names = "osc32k";
+ };
+ };
+
+ cpus {
+ cpu {
+ compatible = "arm,arm926ej-s";
+ device_type = "cpu";
+ };
+ };
+
+ soc {
+ compatible = "simple-bus";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
+
+ sram-controller@1c00000 {
+ compatible = "allwinner,suniv-f1c100s-system-control",
+ "allwinner,sun4i-a10-system-control";
+ reg = <0x01c00000 0x30>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
+
+ sram_d: sram@10000 {
+ compatible = "mmio-sram";
+ reg = <0x00010000 0x1000>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges = <0 0x00010000 0x1000>;
+
+ otg_sram: sram-section@0 {
+ compatible = "allwinner,suniv-f1c100s-sram-d",
+ "allwinner,sun4i-a10-sram-d";
+ reg = <0x0000 0x1000>;
+ status = "disabled";
+ };
+ };
+ };
+
+ ccu: clock@1c20000 {
+ compatible = "allwinner,suniv-f1c100s-ccu";
+ reg = <0x01c20000 0x400>;
+ clocks = <&osc24M>, <&osc32k>;
+ clock-names = "hosc", "losc";
+ #clock-cells = <1>;
+ #reset-cells = <1>;
+ };
+
+ intc: interrupt-controller@1c20400 {
+ compatible = "allwinner,suniv-f1c100s-ic";
+ reg = <0x01c20400 0x400>;
+ interrupt-controller;
+ #interrupt-cells = <1>;
+ };
+
+ pio: pinctrl@1c20800 {
+ compatible = "allwinner,suniv-f1c100s-pinctrl";
+ reg = <0x01c20800 0x400>;
+ interrupts = <38>, <39>, <40>;
+ clocks = <&ccu 37>, <&osc24M>, <&osc32k>;
+ clock-names = "apb", "hosc", "losc";
+ gpio-controller;
+ interrupt-controller;
+ #interrupt-cells = <3>;
+ #gpio-cells = <3>;
+
+ uart0_pe_pins: uart0-pe-pins {
+ pins = "PE0", "PE1";
+ function = "uart0";
+ };
+ };
+
+ timer@1c20c00 {
+ compatible = "allwinner,suniv-f1c100s-timer";
+ reg = <0x01c20c00 0x90>;
+ interrupts = <13>;
+ clocks = <&osc24M>;
+ };
+
+ wdt: watchdog@1c20ca0 {
+ compatible = "allwinner,suniv-f1c100s-wdt",
+ "allwinner,sun4i-a10-wdt";
+ reg = <0x01c20ca0 0x20>;
+ };
+
+ uart0: serial@1c25000 {
+ compatible = "snps,dw-apb-uart";
+ reg = <0x01c25000 0x400>;
+ interrupts = <1>;
+ reg-shift = <2>;
+ reg-io-width = <4>;
+ clocks = <&ccu 38>;
+ resets = <&ccu 24>;
+ status = "disabled";
+ };
+
+ uart1: serial@1c25400 {
+ compatible = "snps,dw-apb-uart";
+ reg = <0x01c25400 0x400>;
+ interrupts = <2>;
+ reg-shift = <2>;
+ reg-io-width = <4>;
+ clocks = <&ccu 39>;
+ resets = <&ccu 25>;
+ status = "disabled";
+ };
+
+ uart2: serial@1c25800 {
+ compatible = "snps,dw-apb-uart";
+ reg = <0x01c25800 0x400>;
+ interrupts = <3>;
+ reg-shift = <2>;
+ reg-io-width = <4>;
+ clocks = <&ccu 40>;
+ resets = <&ccu 26>;
+ status = "disabled";
+ };
+ };
+};
diff --git a/arch/arm/dts/sunxi-u-boot.dtsi b/arch/arm/dts/sunxi-u-boot.dtsi
index f2d7361b84f..0f573e6d7ae 100644
--- a/arch/arm/dts/sunxi-u-boot.dtsi
+++ b/arch/arm/dts/sunxi-u-boot.dtsi
@@ -12,7 +12,9 @@
/ {
aliases {
+#ifndef CONFIG_MACH_SUNIV
mmc0 = &mmc0;
+#endif
#if CONFIG_MMC_SUNXI_SLOT_EXTRA == 2
mmc1 = &mmc2;
#endif
diff --git a/arch/arm/include/asm/arch-sunxi/clock.h b/arch/arm/include/asm/arch-sunxi/clock.h
index cbbe5c7a1e6..2cfd5407423 100644
--- a/arch/arm/include/asm/arch-sunxi/clock.h
+++ b/arch/arm/include/asm/arch-sunxi/clock.h
@@ -19,7 +19,7 @@
#elif defined(CONFIG_SUN50I_GEN_H6)
#include <asm/arch/clock_sun50i_h6.h>
#elif defined(CONFIG_MACH_SUN6I) || defined(CONFIG_MACH_SUN8I) || \
- defined(CONFIG_MACH_SUN50I)
+ defined(CONFIG_MACH_SUN50I) || defined(CONFIG_MACH_SUNIV)
#include <asm/arch/clock_sun6i.h>
#elif defined(CONFIG_MACH_SUN9I)
#include <asm/arch/clock_sun9i.h>
diff --git a/arch/arm/include/asm/arch-sunxi/clock_sun6i.h b/arch/arm/include/asm/arch-sunxi/clock_sun6i.h
index ee387127f37..7fcf340db69 100644
--- a/arch/arm/include/asm/arch-sunxi/clock_sun6i.h
+++ b/arch/arm/include/asm/arch-sunxi/clock_sun6i.h
@@ -226,7 +226,12 @@ struct sunxi_ccm_reg {
#define CCM_PLL5_CTRL_SIGMA_DELTA_EN (0x1 << 24)
#define CCM_PLL5_CTRL_EN (0x1 << 31)
+#ifdef CONFIG_MACH_SUNIV
+/* suniv pll6 doesn't have postdiv 2, so k is set to 0 */
+#define PLL6_CFG_DEFAULT 0x90041801
+#else
#define PLL6_CFG_DEFAULT 0x90041811 /* 600 MHz */
+#endif
#define CCM_PLL6_CTRL_N_SHIFT 8
#define CCM_PLL6_CTRL_N_MASK (0x1f << CCM_PLL6_CTRL_N_SHIFT)
@@ -488,6 +493,14 @@ struct sunxi_ccm_reg {
#define AHB_RESET_OFFSET_EPHY 2
#define AHB_RESET_OFFSET_LVDS 0
+/* apb1 reset */
+#ifdef CONFIG_MACH_SUNIV
+#define APB1_GATE_UART_SHIFT (20)
+#define APB1_GATE_TWI_SHIFT (16)
+#define APB1_RESET_UART_SHIFT (20)
+#define APB1_RESET_TWI_SHIFT (16)
+#endif
+
/* apb2 reset */
#define APB2_RESET_UART_SHIFT (16)
#define APB2_RESET_UART_MASK (0xff << APB2_RESET_UART_SHIFT)
diff --git a/arch/arm/include/asm/arch-sunxi/cpu_sun4i.h b/arch/arm/include/asm/arch-sunxi/cpu_sun4i.h
index d4c795d89cb..f7ecc790dbf 100644
--- a/arch/arm/include/asm/arch-sunxi/cpu_sun4i.h
+++ b/arch/arm/include/asm/arch-sunxi/cpu_sun4i.h
@@ -129,9 +129,15 @@ defined(CONFIG_MACH_SUN50I)
#define SUNXI_CPUCFG_BASE 0x01c25c00
#endif
+#ifdef CONFIG_MACH_SUNIV
+#define SUNXI_UART0_BASE 0x01c25000
+#define SUNXI_UART1_BASE 0x01c25400
+#define SUNXI_UART2_BASE 0x01c25800
+#else
#define SUNXI_UART0_BASE 0x01c28000
#define SUNXI_UART1_BASE 0x01c28400
#define SUNXI_UART2_BASE 0x01c28800
+#endif
#define SUNXI_UART3_BASE 0x01c28c00
#define SUNXI_UART4_BASE 0x01c29000
#define SUNXI_UART5_BASE 0x01c29400
@@ -226,6 +232,7 @@ void sunxi_board_init(void);
void sunxi_reset(void);
int sunxi_get_ss_bonding_id(void);
int sunxi_get_sid(unsigned int *sid);
+unsigned int sunxi_get_sram_id(void);
#endif /* __ASSEMBLY__ */
#endif /* _SUNXI_CPU_SUN4I_H */
diff --git a/arch/arm/include/asm/arch-sunxi/dram.h b/arch/arm/include/asm/arch-sunxi/dram.h
index c3b3e1f512b..682daae6b1a 100644
--- a/arch/arm/include/asm/arch-sunxi/dram.h
+++ b/arch/arm/include/asm/arch-sunxi/dram.h
@@ -31,6 +31,8 @@
#include <asm/arch/dram_sun50i_h6.h>
#elif defined(CONFIG_MACH_SUN50I_H616)
#include <asm/arch/dram_sun50i_h616.h>
+#elif defined(CONFIG_MACH_SUNIV)
+#include <asm/arch/dram_suniv.h>
#else
#include <asm/arch/dram_sun4i.h>
#endif
diff --git a/arch/arm/include/asm/arch-sunxi/dram_suniv.h b/arch/arm/include/asm/arch-sunxi/dram_suniv.h
new file mode 100644
index 00000000000..6f4c0512d65
--- /dev/null
+++ b/arch/arm/include/asm/arch-sunxi/dram_suniv.h
@@ -0,0 +1,46 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * suniv DRAM controller register definition
+ *
+ * Copyright (C) 2018 Icenowy Zheng <icenowy@aosc.io>
+ *
+ * Based on xboot's arch/arm32/mach-f1c100s/sys-dram.c, which is:
+ *
+ * Copyright(c) 2007-2018 Jianjun Jiang <8192542@qq.com>
+ */
+
+#define PIO_SDRAM_DRV (0x2c0)
+#define PIO_SDRAM_PULL (0x2c4)
+
+#define DRAM_SCONR (0x00)
+#define DRAM_STMG0R (0x04)
+#define DRAM_STMG1R (0x08)
+#define DRAM_SCTLR (0x0c)
+#define DRAM_SREFR (0x10)
+#define DRAM_SEXTMR (0x14)
+#define DRAM_DDLYR (0x24)
+#define DRAM_DADRR (0x28)
+#define DRAM_DVALR (0x2c)
+#define DRAM_DRPTR0 (0x30)
+#define DRAM_DRPTR1 (0x34)
+#define DRAM_DRPTR2 (0x38)
+#define DRAM_DRPTR3 (0x3c)
+#define DRAM_SEFR (0x40)
+#define DRAM_MAE (0x44)
+#define DRAM_ASPR (0x48)
+#define DRAM_SDLY0 (0x4C)
+#define DRAM_SDLY1 (0x50)
+#define DRAM_SDLY2 (0x54)
+#define DRAM_MCR0 (0x100)
+#define DRAM_MCR1 (0x104)
+#define DRAM_MCR2 (0x108)
+#define DRAM_MCR3 (0x10c)
+#define DRAM_MCR4 (0x110)
+#define DRAM_MCR5 (0x114)
+#define DRAM_MCR6 (0x118)
+#define DRAM_MCR7 (0x11c)
+#define DRAM_MCR8 (0x120)
+#define DRAM_MCR9 (0x124)
+#define DRAM_MCR10 (0x128)
+#define DRAM_MCR11 (0x12c)
+#define DRAM_BWCR (0x140)
diff --git a/arch/arm/include/asm/arch-sunxi/gpio.h b/arch/arm/include/asm/arch-sunxi/gpio.h
index 106605adf5e..7f7eb0517cf 100644
--- a/arch/arm/include/asm/arch-sunxi/gpio.h
+++ b/arch/arm/include/asm/arch-sunxi/gpio.h
@@ -165,6 +165,7 @@ enum sunxi_gpio_number {
#define SUNXI_GPD_LVDS0 3
#define SUNXI_GPD_PWM 2
+#define SUNIV_GPE_UART0 5
#define SUN8I_GPE_TWI2 3
#define SUN50I_GPE_TWI2 3
diff --git a/arch/arm/mach-sunxi/Kconfig b/arch/arm/mach-sunxi/Kconfig
index d7f9a03152f..205fe3c9d3c 100644
--- a/arch/arm/mach-sunxi/Kconfig
+++ b/arch/arm/mach-sunxi/Kconfig
@@ -1,6 +1,7 @@
if ARCH_SUNXI
config SPL_LDSCRIPT
+ default "arch/arm/cpu/arm926ejs/sunxi/u-boot-spl.lds" if MACH_SUNIV
default "arch/arm/cpu/armv7/sunxi/u-boot-spl.lds" if !ARM64
config IDENT_STRING
@@ -183,10 +184,15 @@ choice
prompt "Sunxi SoC Variant"
optional
+config MACH_SUNIV
+ bool "suniv (Allwinner F1C100s/F1C200s/F1C600/R6)"
+ select CPU_ARM926EJS
+ select SUNXI_GEN_SUN6I
+ select SUPPORT_SPL
+
config MACH_SUN4I
bool "sun4i (Allwinner A10)"
select CPU_V7A
- select ARM_CORTEX_CPU_IS_UP
select PHY_SUN4I_USB
select DRAM_SUN4I
select SUNXI_GEN_SUN4I
@@ -197,7 +203,6 @@ config MACH_SUN4I
config MACH_SUN5I
bool "sun5i (Allwinner A13)"
select CPU_V7A
- select ARM_CORTEX_CPU_IS_UP
select DRAM_SUN4I
select PHY_SUN4I_USB
select SUNXI_GEN_SUN4I
@@ -212,6 +217,7 @@ config MACH_SUN6I
select CPU_V7_HAS_NONSEC
select CPU_V7_HAS_VIRT
select ARCH_SUPPORT_PSCI
+ select SPL_ARMV7_SET_CORTEX_SMPEN
select DRAM_SUN6I
select PHY_SUN4I_USB
select SPL_I2C
@@ -227,6 +233,7 @@ config MACH_SUN7I
select CPU_V7_HAS_NONSEC
select CPU_V7_HAS_VIRT
select ARCH_SUPPORT_PSCI
+ select SPL_ARMV7_SET_CORTEX_SMPEN
select DRAM_SUN4I
select PHY_SUN4I_USB
select SUNXI_GEN_SUN4I
@@ -315,6 +322,7 @@ config MACH_SUN8I_V3S
config MACH_SUN9I
bool "sun9i (Allwinner A80)"
select CPU_V7A
+ select SPL_ARMV7_SET_CORTEX_SMPEN
select DRAM_SUN9I
select SPL_I2C
select SUN6I_PRCM
@@ -365,6 +373,7 @@ endchoice
# The sun8i SoCs share a lot, this helps to avoid a lot of "if A23 || A33"
config MACH_SUN8I
bool
+ select SPL_ARMV7_SET_CORTEX_SMPEN if !ARM64
select SUN6I_PRCM
default y if MACH_SUN8I_A23
default y if MACH_SUN8I_A33
@@ -587,6 +596,7 @@ config DRAM_ODT_CORRECTION
endif
config SYS_CLK_FREQ
+ default 408000000 if MACH_SUNIV
default 1008000000 if MACH_SUN4I
default 1008000000 if MACH_SUN5I
default 1008000000 if MACH_SUN6I
@@ -598,6 +608,7 @@ config SYS_CLK_FREQ
default 1008000000 if MACH_SUN50I_H616
config SYS_CONFIG_NAME
+ default "suniv" if MACH_SUNIV
default "sun4i" if MACH_SUN4I
default "sun5i" if MACH_SUN5I
default "sun6i" if MACH_SUN6I
@@ -815,7 +826,7 @@ config VIDEO_SUNXI
config VIDEO_HDMI
bool "HDMI output support"
- depends on VIDEO_SUNXI && !MACH_SUN8I
+ depends on VIDEO_SUNXI && !MACH_SUN8I && !MACH_SUNIV
default y
---help---
Say Y here to add support for outputting video over HDMI.
@@ -1015,6 +1026,7 @@ config GMAC_TX_DELAY
Set the GMAC Transmit Clock Delay Chain value.
config SPL_STACK_R_ADDR
+ default 0x81e00000 if MACH_SUNIV
default 0x4fe00000 if MACH_SUN4I
default 0x4fe00000 if MACH_SUN5I
default 0x4fe00000 if MACH_SUN6I
diff --git a/arch/arm/mach-sunxi/Makefile b/arch/arm/mach-sunxi/Makefile
index 5d3fd70f749..58f807cb82d 100644
--- a/arch/arm/mach-sunxi/Makefile
+++ b/arch/arm/mach-sunxi/Makefile
@@ -13,6 +13,7 @@ obj-y += dram_helpers.o
obj-y += pinmux.o
obj-$(CONFIG_SUN6I_PRCM) += prcm.o
obj-$(CONFIG_AXP_PMIC_BUS) += pmic_bus.o
+obj-$(CONFIG_MACH_SUNIV) += clock_sun6i.o
obj-$(CONFIG_MACH_SUN4I) += clock_sun4i.o
obj-$(CONFIG_MACH_SUN5I) += clock_sun4i.o
obj-$(CONFIG_MACH_SUN6I) += clock_sun6i.o
@@ -25,8 +26,12 @@ obj-$(CONFIG_MACH_SUN8I) += clock_sun6i.o
endif
obj-$(CONFIG_MACH_SUN9I) += clock_sun9i.o gtbus_sun9i.o
obj-$(CONFIG_SUN50I_GEN_H6) += clock_sun50i_h6.o
+ifndef CONFIG_ARM64
+obj-y += timer.o
+endif
ifdef CONFIG_SPL_BUILD
+obj-$(CONFIG_MACH_SUNIV) += dram_suniv.o
obj-$(CONFIG_DRAM_SUN4I) += dram_sun4i.o
obj-$(CONFIG_DRAM_SUN6I) += dram_sun6i.o
obj-$(CONFIG_DRAM_SUN8I_A23) += dram_sun8i_a23.o
diff --git a/arch/arm/mach-sunxi/board.c b/arch/arm/mach-sunxi/board.c
index 3ef179742c5..57078f7a7b2 100644
--- a/arch/arm/mach-sunxi/board.c
+++ b/arch/arm/mach-sunxi/board.c
@@ -75,6 +75,7 @@ ulong board_get_usable_ram_top(ulong total_size)
}
#endif
+#ifdef CONFIG_SPL_BUILD
static int gpio_init(void)
{
__maybe_unused uint val;
@@ -86,7 +87,8 @@ static int gpio_init(void)
sunxi_gpio_set_cfgpin(SUNXI_GPB(22), SUNXI_GPIO_INPUT);
sunxi_gpio_set_cfgpin(SUNXI_GPB(23), SUNXI_GPIO_INPUT);
#endif
-#if defined(CONFIG_MACH_SUN8I) && !defined(CONFIG_MACH_SUN8I_R40)
+#if (defined(CONFIG_MACH_SUN8I) && !defined(CONFIG_MACH_SUN8I_R40)) || \
+ defined(CONFIG_MACH_SUNIV)
sunxi_gpio_set_cfgpin(SUNXI_GPF(2), SUN8I_GPF_UART0);
sunxi_gpio_set_cfgpin(SUNXI_GPF(4), SUN8I_GPF_UART0);
#else
@@ -94,6 +96,10 @@ static int gpio_init(void)
sunxi_gpio_set_cfgpin(SUNXI_GPF(4), SUNXI_GPF_UART0);
#endif
sunxi_gpio_set_pull(SUNXI_GPF(4), 1);
+#elif CONFIG_CONS_INDEX == 1 && defined(CONFIG_MACH_SUNIV)
+ sunxi_gpio_set_cfgpin(SUNXI_GPE(0), SUNIV_GPE_UART0);
+ sunxi_gpio_set_cfgpin(SUNXI_GPE(1), SUNIV_GPE_UART0);
+ sunxi_gpio_set_pull(SUNXI_GPE(1), SUNXI_GPIO_PULL_UP);
#elif CONFIG_CONS_INDEX == 1 && (defined(CONFIG_MACH_SUN4I) || \
defined(CONFIG_MACH_SUN7I) || \
defined(CONFIG_MACH_SUN8I_R40))
@@ -172,7 +178,6 @@ static int gpio_init(void)
return 0;
}
-#if defined(CONFIG_SPL_BOARD_LOAD_IMAGE) && defined(CONFIG_SPL_BUILD)
static int spl_board_load_image(struct spl_image_info *spl_image,
struct spl_boot_device *bootdev)
{
@@ -184,63 +189,6 @@ static int spl_board_load_image(struct spl_image_info *spl_image,
SPL_LOAD_IMAGE_METHOD("FEL", 0, BOOT_DEVICE_BOARD, spl_board_load_image);
#endif
-void s_init(void)
-{
- /*
- * Undocumented magic taken from boot0, without this DRAM
- * access gets messed up (seems cache related).
- * The boot0 sources describe this as: "config ema for cache sram"
- */
-#if defined CONFIG_MACH_SUN6I
- setbits_le32(SUNXI_SRAMC_BASE + 0x44, 0x1800);
-#elif defined CONFIG_MACH_SUN8I
- __maybe_unused uint version;
-
- /* Unlock sram version info reg, read it, relock */
- setbits_le32(SUNXI_SRAMC_BASE + 0x24, (1 << 15));
- version = readl(SUNXI_SRAMC_BASE + 0x24) >> 16;
- clrbits_le32(SUNXI_SRAMC_BASE + 0x24, (1 << 15));
-
- /*
- * Ideally this would be a switch case, but we do not know exactly
- * which versions there are and which version needs which settings,
- * so reproduce the per SoC code from the BSP.
- */
-#if defined CONFIG_MACH_SUN8I_A23
- if (version == 0x1650)
- setbits_le32(SUNXI_SRAMC_BASE + 0x44, 0x1800);
- else /* 0x1661 ? */
- setbits_le32(SUNXI_SRAMC_BASE + 0x44, 0xc0);
-#elif defined CONFIG_MACH_SUN8I_A33
- if (version != 0x1667)
- setbits_le32(SUNXI_SRAMC_BASE + 0x44, 0xc0);
-#endif
- /* A83T BSP never modifies SUNXI_SRAMC_BASE + 0x44 */
- /* No H3 BSP, boot0 seems to not modify SUNXI_SRAMC_BASE + 0x44 */
-#endif
-
-#if !defined(CONFIG_ARM_CORTEX_CPU_IS_UP) && !defined(CONFIG_ARM64)
- /* Enable SMP mode for CPU0, by setting bit 6 of Auxiliary Ctl reg */
- asm volatile(
- "mrc p15, 0, r0, c1, c0, 1\n"
- "orr r0, r0, #1 << 6\n"
- "mcr p15, 0, r0, c1, c0, 1\n"
- ::: "r0");
-#endif
-#if defined CONFIG_MACH_SUN6I || defined CONFIG_MACH_SUN8I_H3
- /* Enable non-secure access to some peripherals */
- tzpc_init();
-#endif
-
- clock_init();
- timer_init();
- gpio_init();
-#if !CONFIG_IS_ENABLED(DM_I2C)
- i2c_init_board();
-#endif
- eth_init_board();
-}
-
#define SUNXI_INVALID_BOOT_SOURCE -1
static int sunxi_get_boot_source(void)
@@ -328,18 +276,61 @@ unsigned long spl_mmc_get_uboot_raw_sector(struct mmc *mmc,
return sector;
}
+#ifdef CONFIG_MACH_SUNIV
+/*
+ * The suniv BROM does not pass the boot media type to SPL, so we try with the
+ * boot sequence in BROM: mmc0->spinor->fail.
+ * TODO: This has the slight chance of being wrong (invalid SPL signature,
+ * but valid U-Boot legacy image on the SD card), but this should be rare.
+ * It looks like we can deduce from some BROM state upon entering the SPL
+ * (registers, SP, or stack itself) where the BROM was coming from and use
+ * that here.
+ */
+void board_boot_order(u32 *spl_boot_list)
+{
+ /*
+ * See the comments above in sunxi_get_boot_device() for information
+ * about FEL boot.
+ */
+ if (!is_boot0_magic(SPL_ADDR + 4)) {
+ spl_boot_list[0] = BOOT_DEVICE_BOARD;
+ return;
+ }
+
+ spl_boot_list[0] = BOOT_DEVICE_MMC1;
+ spl_boot_list[1] = BOOT_DEVICE_SPI;
+}
+#else
u32 spl_boot_device(void)
{
return sunxi_get_boot_device();
}
+#endif
+
+__weak void sunxi_sram_init(void)
+{
+}
void board_init_f(ulong dummy)
{
+ sunxi_sram_init();
+
+#if defined CONFIG_MACH_SUN6I || defined CONFIG_MACH_SUN8I_H3
+ /* Enable non-secure access to some peripherals */
+ tzpc_init();
+#endif
+
+ clock_init();
+ timer_init();
+ gpio_init();
+ eth_init_board();
+
spl_init();
preloader_console_init();
#if CONFIG_IS_ENABLED(I2C) && CONFIG_IS_ENABLED(SYS_I2C_LEGACY)
/* Needed early by sunxi_board_init if PMU is enabled */
+ i2c_init_board();
i2c_init(CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE);
#endif
sunxi_board_init();
diff --git a/arch/arm/mach-sunxi/clock.c b/arch/arm/mach-sunxi/clock.c
index de7e8752988..da3a0eb0584 100644
--- a/arch/arm/mach-sunxi/clock.c
+++ b/arch/arm/mach-sunxi/clock.c
@@ -35,7 +35,8 @@ int clock_init(void)
}
/* These functions are shared between various SoCs so put them here. */
-#if defined CONFIG_SUNXI_GEN_SUN6I && !defined CONFIG_MACH_SUN9I
+#if defined CONFIG_SUNXI_GEN_SUN6I && !defined CONFIG_MACH_SUN9I && \
+ !defined CONFIG_MACH_SUNIV
int clock_twi_onoff(int port, int state)
{
struct sunxi_ccm_reg *const ccm =
diff --git a/arch/arm/mach-sunxi/clock_sun6i.c b/arch/arm/mach-sunxi/clock_sun6i.c
index 8e84062bd7c..cda6949dff0 100644
--- a/arch/arm/mach-sunxi/clock_sun6i.c
+++ b/arch/arm/mach-sunxi/clock_sun6i.c
@@ -23,7 +23,8 @@ void clock_init_safe(void)
struct sunxi_ccm_reg * const ccm =
(struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
-#if !defined(CONFIG_MACH_SUNXI_H3_H5) && !defined(CONFIG_MACH_SUN50I)
+#if !defined(CONFIG_MACH_SUNXI_H3_H5) && !defined(CONFIG_MACH_SUN50I) && \
+ !defined(CONFIG_MACH_SUNIV)
struct sunxi_prcm_reg * const prcm =
(struct sunxi_prcm_reg *)SUNXI_PRCM_BASE;
@@ -49,9 +50,11 @@ void clock_init_safe(void)
writel(AHB1_ABP1_DIV_DEFAULT, &ccm->ahb1_apb1_div);
- writel(MBUS_CLK_DEFAULT, &ccm->mbus0_clk_cfg);
- if (IS_ENABLED(CONFIG_MACH_SUN6I))
- writel(MBUS_CLK_DEFAULT, &ccm->mbus1_clk_cfg);
+ if (!IS_ENABLED(CONFIG_MACH_SUNIV)) {
+ writel(MBUS_CLK_DEFAULT, &ccm->mbus0_clk_cfg);
+ if (IS_ENABLED(CONFIG_MACH_SUN6I))
+ writel(MBUS_CLK_DEFAULT, &ccm->mbus1_clk_cfg);
+ }
#if defined(CONFIG_MACH_SUN8I_R40) && defined(CONFIG_SUNXI_AHCI)
setbits_le32(&ccm->sata_pll_cfg, CCM_SATA_PLL_DEFAULT);
@@ -87,22 +90,36 @@ void clock_init_uart(void)
struct sunxi_ccm_reg *const ccm =
(struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
- /* uart clock source is apb2 */
- writel(APB2_CLK_SRC_OSC24M|
- APB2_CLK_RATE_N_1|
- APB2_CLK_RATE_M(1),
- &ccm->apb2_div);
-
- /* open the clock for uart */
- setbits_le32(&ccm->apb2_gate,
- CLK_GATE_OPEN << (APB2_GATE_UART_SHIFT +
- CONFIG_CONS_INDEX - 1));
-
- /* deassert uart reset */
- setbits_le32(&ccm->apb2_reset_cfg,
- 1 << (APB2_RESET_UART_SHIFT +
- CONFIG_CONS_INDEX - 1));
+#ifdef CONFIG_MACH_SUNIV
+ /* suniv doesn't have apb2, UART clock source is always apb1 */
+
+ /* open the clock for uart */
+ setbits_le32(&ccm->apb1_gate,
+ CLK_GATE_OPEN << (APB1_GATE_UART_SHIFT +
+ CONFIG_CONS_INDEX - 1));
+
+ /* deassert uart reset */
+ setbits_le32(&ccm->apb1_reset_cfg,
+ 1 << (APB1_RESET_UART_SHIFT +
+ CONFIG_CONS_INDEX - 1));
#else
+ /* uart clock source is apb2 */
+ writel(APB2_CLK_SRC_OSC24M|
+ APB2_CLK_RATE_N_1|
+ APB2_CLK_RATE_M(1),
+ &ccm->apb2_div);
+
+ /* open the clock for uart */
+ setbits_le32(&ccm->apb2_gate,
+ CLK_GATE_OPEN << (APB2_GATE_UART_SHIFT +
+ CONFIG_CONS_INDEX - 1));
+
+ /* deassert uart reset */
+ setbits_le32(&ccm->apb2_reset_cfg,
+ 1 << (APB2_RESET_UART_SHIFT +
+ CONFIG_CONS_INDEX - 1));
+#endif /* !CONFIG_MACH_SUNIV */
+#else /* CONFIG_CONS_INDEX >= 5 */
/* enable R_PIO and R_UART clocks, and de-assert resets */
prcm_apb0_enable(PRCM_APB0_GATE_PIO | PRCM_APB0_GATE_UART);
#endif
@@ -125,10 +142,15 @@ void clock_set_pll1(unsigned int clk)
}
/* Switch to 24MHz clock while changing PLL1 */
- writel(AXI_DIV_3 << AXI_DIV_SHIFT |
- ATB_DIV_2 << ATB_DIV_SHIFT |
- CPU_CLK_SRC_OSC24M << CPU_CLK_SRC_SHIFT,
- &ccm->cpu_axi_cfg);
+ if (IS_ENABLED(CONFIG_MACH_SUNIV)) {
+ writel(CPU_CLK_SRC_OSC24M << CPU_CLK_SRC_SHIFT,
+ &ccm->cpu_axi_cfg);
+ } else {
+ writel(AXI_DIV_3 << AXI_DIV_SHIFT |
+ ATB_DIV_2 << ATB_DIV_SHIFT |
+ CPU_CLK_SRC_OSC24M << CPU_CLK_SRC_SHIFT,
+ &ccm->cpu_axi_cfg);
+ }
/*
* sun6i: PLL1 rate = ((24000000 * n * k) >> 0) / m (p is ignored)
@@ -140,10 +162,15 @@ void clock_set_pll1(unsigned int clk)
sdelay(200);
/* Switch CPU to PLL1 */
- writel(AXI_DIV_3 << AXI_DIV_SHIFT |
- ATB_DIV_2 << ATB_DIV_SHIFT |
- CPU_CLK_SRC_PLL1 << CPU_CLK_SRC_SHIFT,
- &ccm->cpu_axi_cfg);
+ if (IS_ENABLED(CONFIG_MACH_SUNIV)) {
+ writel(CPU_CLK_SRC_PLL1 << CPU_CLK_SRC_SHIFT,
+ &ccm->cpu_axi_cfg);
+ } else {
+ writel(AXI_DIV_3 << AXI_DIV_SHIFT |
+ ATB_DIV_2 << ATB_DIV_SHIFT |
+ CPU_CLK_SRC_PLL1 << CPU_CLK_SRC_SHIFT,
+ &ccm->cpu_axi_cfg);
+ }
}
#endif
@@ -317,7 +344,10 @@ unsigned int clock_get_pll6(void)
uint32_t rval = readl(&ccm->pll6_cfg);
int n = ((rval & CCM_PLL6_CTRL_N_MASK) >> CCM_PLL6_CTRL_N_SHIFT) + 1;
int k = ((rval & CCM_PLL6_CTRL_K_MASK) >> CCM_PLL6_CTRL_K_SHIFT) + 1;
- return 24000000 * n * k / 2;
+ if (IS_ENABLED(CONFIG_MACH_SUNIV))
+ return 24000000 * n * k;
+ else
+ return 24000000 * n * k / 2;
}
unsigned int clock_get_mipi_pll(void)
diff --git a/arch/arm/mach-sunxi/cpu_info.c b/arch/arm/mach-sunxi/cpu_info.c
index ba33ef24300..7eef178859b 100644
--- a/arch/arm/mach-sunxi/cpu_info.c
+++ b/arch/arm/mach-sunxi/cpu_info.c
@@ -57,6 +57,8 @@ int print_cpuinfo(void)
{
#ifdef CONFIG_MACH_SUN4I
puts("CPU: Allwinner A10 (SUN4I)\n");
+#elif defined CONFIG_MACH_SUNIV
+ puts("CPU: Allwinner F Series (SUNIV)\n");
#elif defined CONFIG_MACH_SUN5I
u32 val = readl(SUNXI_SID_BASE + 0x08);
switch ((val >> 12) & 0xf) {
diff --git a/arch/arm/mach-sunxi/dram_helpers.c b/arch/arm/mach-sunxi/dram_helpers.c
index 520b597fcc0..2c873192e60 100644
--- a/arch/arm/mach-sunxi/dram_helpers.c
+++ b/arch/arm/mach-sunxi/dram_helpers.c
@@ -26,7 +26,10 @@ void mctl_await_completion(u32 *reg, u32 mask, u32 val)
/*
* Test if memory at offset offset matches memory at begin of DRAM
+ *
+ * Note: dsb() is not available on ARMv5 in Thumb mode
*/
+#ifndef CONFIG_MACH_SUNIV
bool mctl_mem_matches(u32 offset)
{
/* Try to write different values to RAM at two addresses */
@@ -37,3 +40,4 @@ bool mctl_mem_matches(u32 offset)
return readl(CONFIG_SYS_SDRAM_BASE) ==
readl((ulong)CONFIG_SYS_SDRAM_BASE + offset);
}
+#endif
diff --git a/arch/arm/mach-sunxi/dram_suniv.c b/arch/arm/mach-sunxi/dram_suniv.c
new file mode 100644
index 00000000000..56c2d557ff1
--- /dev/null
+++ b/arch/arm/mach-sunxi/dram_suniv.c
@@ -0,0 +1,420 @@
+// SPDX-License-Identifier: (GPL-2.0+)
+/*
+ * suniv DRAM initialization
+ *
+ * Copyright (C) 2018 Icenowy Zheng <icenowy@aosc.io>
+ *
+ * Based on xboot's arch/arm32/mach-f1c100s/sys-dram.c, which is:
+ *
+ * Copyright(c) 2007-2018 Jianjun Jiang <8192542@qq.com>
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <asm/arch/clock.h>
+#include <asm/arch/dram.h>
+#include <asm/arch/gpio.h>
+#include <linux/bitops.h>
+#include <linux/delay.h>
+#include <hang.h>
+
+#define SDR_T_CAS (0x2)
+#define SDR_T_RAS (0x8)
+#define SDR_T_RCD (0x3)
+#define SDR_T_RP (0x3)
+#define SDR_T_WR (0x3)
+#define SDR_T_RFC (0xd)
+#define SDR_T_XSR (0xf9)
+#define SDR_T_RC (0xb)
+#define SDR_T_INIT (0x8)
+#define SDR_T_INIT_REF (0x7)
+#define SDR_T_WTR (0x2)
+#define SDR_T_RRD (0x2)
+#define SDR_T_XP (0x0)
+
+enum dram_type {
+ DRAM_TYPE_SDR = 0,
+ DRAM_TYPE_DDR = 1,
+ /* Not supported yet. */
+ DRAM_TYPE_MDDR = 2,
+};
+
+struct dram_para {
+ u32 size; /* dram size (unit: MByte) */
+ u32 clk; /* dram work clock (unit: MHz) */
+ u32 access_mode; /* 0: interleave mode 1: sequence mode */
+ u32 cs_num; /* dram chip count 1: one chip 2: two chip */
+ u32 ddr8_remap; /* for 8bits data width DDR 0: normal 1: 8bits */
+ enum dram_type sdr_ddr;
+ u32 bwidth; /* dram bus width */
+ u32 col_width; /* column address width */
+ u32 row_width; /* row address width */
+ u32 bank_size; /* dram bank count */
+ u32 cas; /* dram cas */
+};
+
+struct dram_para suniv_dram_para = {
+ .size = 32,
+ .clk = 156,
+ .access_mode = 1,
+ .cs_num = 1,
+ .ddr8_remap = 0,
+ .sdr_ddr = DRAM_TYPE_DDR,
+ .bwidth = 16,
+ .col_width = 10,
+ .row_width = 13,
+ .bank_size = 4,
+ .cas = 0x3,
+};
+
+static int dram_initial(void)
+{
+ unsigned int time = 0xffffff;
+
+ setbits_le32(SUNXI_DRAMC_BASE + DRAM_SCTLR, 0x1);
+ while ((readl(SUNXI_DRAMC_BASE + DRAM_SCTLR) & 0x1) && time--) {
+ if (time == 0)
+ return 0;
+ }
+ return 1;
+}
+
+static int dram_delay_scan(void)
+{
+ unsigned int time = 0xffffff;
+
+ setbits_le32(SUNXI_DRAMC_BASE + DRAM_DDLYR, 0x1);
+ while ((readl(SUNXI_DRAMC_BASE + DRAM_DDLYR) & 0x1) && time--) {
+ if (time == 0)
+ return 0;
+ }
+ return 1;
+}
+
+static void dram_set_autofresh_cycle(u32 clk)
+{
+ u32 val = 0;
+ u32 row = 0;
+ u32 temp = 0;
+
+ row = readl(SUNXI_DRAMC_BASE + DRAM_SCONR);
+ row &= 0x1e0;
+ row >>= 0x5;
+
+ if (row == 0xc) {
+ if (clk >= 1000000) {
+ temp = clk + (clk >> 3) + (clk >> 4) + (clk >> 5);
+ while (temp >= (10000000 >> 6)) {
+ temp -= (10000000 >> 6);
+ val++;
+ }
+ } else {
+ val = (clk * 499) >> 6;
+ }
+ } else if (row == 0xb) {
+ if (clk >= 1000000) {
+ temp = clk + (clk >> 3) + (clk >> 4) + (clk >> 5);
+ while (temp >= (10000000 >> 7)) {
+ temp -= (10000000 >> 7);
+ val++;
+ }
+ } else {
+ val = (clk * 499) >> 5;
+ }
+ }
+ writel(val, SUNXI_DRAMC_BASE + DRAM_SREFR);
+}
+
+static int dram_para_setup(struct dram_para *para)
+{
+ u32 val = 0;
+
+ val = (para->ddr8_remap) | (0x1 << 1) |
+ ((para->bank_size >> 2) << 3) |
+ ((para->cs_num >> 1) << 4) |
+ ((para->row_width - 1) << 5) |
+ ((para->col_width - 1) << 9) |
+ ((para->sdr_ddr ? (para->bwidth >> 4) : (para->bwidth >> 5)) << 13) |
+ (para->access_mode << 15) |
+ (para->sdr_ddr << 16);
+
+ writel(val, SUNXI_DRAMC_BASE + DRAM_SCONR);
+ setbits_le32(SUNXI_DRAMC_BASE + DRAM_SCTLR, 0x1 << 19);
+ return dram_initial();
+}
+
+static u32 dram_check_delay(u32 bwidth)
+{
+ u32 dsize;
+ int i, j;
+ u32 num = 0;
+ u32 dflag = 0;
+
+ dsize = ((bwidth == 16) ? 4 : 2);
+ for (i = 0; i < dsize; i++) {
+ if (i == 0)
+ dflag = readl(SUNXI_DRAMC_BASE + DRAM_DRPTR0);
+ else if (i == 1)
+ dflag = readl(SUNXI_DRAMC_BASE + DRAM_DRPTR1);
+ else if (i == 2)
+ dflag = readl(SUNXI_DRAMC_BASE + DRAM_DRPTR2);
+ else if (i == 3)
+ dflag = readl(SUNXI_DRAMC_BASE + DRAM_DRPTR3);
+
+ for (j = 0; j < 32; j++) {
+ if (dflag & 0x1)
+ num++;
+ dflag >>= 1;
+ }
+ }
+ return num;
+}
+
+static int sdr_readpipe_scan(void)
+{
+ u32 k = 0;
+
+ for (k = 0; k < 32; k++)
+ writel(k, CONFIG_SYS_SDRAM_BASE + 4 * k);
+ for (k = 0; k < 32; k++) {
+ if (readl(CONFIG_SYS_SDRAM_BASE + 4 * k) != k)
+ return 0;
+ }
+ return 1;
+}
+
+static u32 sdr_readpipe_select(void)
+{
+ u32 value = 0;
+ u32 i = 0;
+
+ for (i = 0; i < 8; i++) {
+ clrsetbits_le32(SUNXI_DRAMC_BASE + DRAM_SCTLR,
+ 0x7 << 6, i << 6);
+ if (sdr_readpipe_scan()) {
+ value = i;
+ return value;
+ }
+ }
+ return value;
+}
+
+static u32 dram_check_type(struct dram_para *para)
+{
+ u32 times = 0;
+ int i;
+
+ for (i = 0; i < 8; i++) {
+ clrsetbits_le32(SUNXI_DRAMC_BASE + DRAM_SCTLR,
+ 0x7 << 6, i << 6);
+ dram_delay_scan();
+ if (readl(SUNXI_DRAMC_BASE + DRAM_DDLYR) & 0x30)
+ times++;
+ }
+
+ if (times == 8) {
+ para->sdr_ddr = DRAM_TYPE_SDR;
+ return 0;
+ }
+ para->sdr_ddr = DRAM_TYPE_DDR;
+ return 1;
+}
+
+static u32 dram_scan_readpipe(struct dram_para *para)
+{
+ u32 rp_best = 0, rp_val = 0;
+ u32 readpipe[8];
+ int i;
+
+ if (para->sdr_ddr == DRAM_TYPE_DDR) {
+ for (i = 0; i < 8; i++) {
+ clrsetbits_le32(SUNXI_DRAMC_BASE + DRAM_SCTLR,
+ 0x7 << 6, i << 6);
+ dram_delay_scan();
+ readpipe[i] = 0;
+ if ((((readl(SUNXI_DRAMC_BASE + DRAM_DDLYR) >> 4) & 0x3) == 0x0) &&
+ (((readl(SUNXI_DRAMC_BASE + DRAM_DDLYR) >> 4) & 0x1) == 0x0))
+ readpipe[i] = dram_check_delay(para->bwidth);
+ if (rp_val < readpipe[i]) {
+ rp_val = readpipe[i];
+ rp_best = i;
+ }
+ }
+ clrsetbits_le32(SUNXI_DRAMC_BASE + DRAM_SCTLR,
+ 0x7 << 6, rp_best << 6);
+ dram_delay_scan();
+ } else {
+ clrbits_le32(SUNXI_DRAMC_BASE + DRAM_SCONR,
+ (0x1 << 16) | (0x3 << 13));
+ rp_best = sdr_readpipe_select();
+ clrsetbits_le32(SUNXI_DRAMC_BASE + DRAM_SCTLR,
+ 0x7 << 6, rp_best << 6);
+ }
+ return 0;
+}
+
+static u32 dram_get_dram_size(struct dram_para *para)
+{
+ u32 colflag = 10, rowflag = 13;
+ u32 val1 = 0;
+ u32 count = 0;
+ u32 addr1, addr2;
+ int i;
+
+ para->col_width = colflag;
+ para->row_width = rowflag;
+ dram_para_setup(para);
+ dram_scan_readpipe(para);
+ for (i = 0; i < 32; i++) {
+ *((u8 *)(CONFIG_SYS_SDRAM_BASE + 0x200 + i)) = 0x11;
+ *((u8 *)(CONFIG_SYS_SDRAM_BASE + 0x600 + i)) = 0x22;
+ }
+ for (i = 0; i < 32; i++) {
+ val1 = *((u8 *)(CONFIG_SYS_SDRAM_BASE + 0x200 + i));
+ if (val1 == 0x22)
+ count++;
+ }
+ if (count == 32)
+ colflag = 9;
+ else
+ colflag = 10;
+ count = 0;
+ para->col_width = colflag;
+ para->row_width = rowflag;
+ dram_para_setup(para);
+ if (colflag == 10) {
+ addr1 = CONFIG_SYS_SDRAM_BASE + 0x400000;
+ addr2 = CONFIG_SYS_SDRAM_BASE + 0xc00000;
+ } else {
+ addr1 = CONFIG_SYS_SDRAM_BASE + 0x200000;
+ addr2 = CONFIG_SYS_SDRAM_BASE + 0x600000;
+ }
+ for (i = 0; i < 32; i++) {
+ *((u8 *)(addr1 + i)) = 0x33;
+ *((u8 *)(addr2 + i)) = 0x44;
+ }
+ for (i = 0; i < 32; i++) {
+ val1 = *((u8 *)(addr1 + i));
+ if (val1 == 0x44)
+ count++;
+ }
+ if (count == 32)
+ rowflag = 12;
+ else
+ rowflag = 13;
+ para->col_width = colflag;
+ para->row_width = rowflag;
+ if (para->row_width != 13)
+ para->size = 16;
+ else if (para->col_width == 10)
+ para->size = 64;
+ else
+ para->size = 32;
+ dram_set_autofresh_cycle(para->clk);
+ para->access_mode = 0;
+ dram_para_setup(para);
+
+ return 0;
+}
+
+static void simple_dram_check(void)
+{
+ volatile u32 *dram = (u32 *)CONFIG_SYS_SDRAM_BASE;
+ int i;
+
+ for (i = 0; i < 0x40; i++)
+ dram[i] = i;
+
+ for (i = 0; i < 0x40; i++) {
+ if (dram[i] != i) {
+ printf("DRAM initialization failed: dram[0x%x] != 0x%x.", i, dram[i]);
+ hang();
+ }
+ }
+
+ for (i = 0; i < 0x10000; i += 0x40)
+ dram[i] = i;
+
+ for (i = 0; i < 0x10000; i += 0x40) {
+ if (dram[i] != i) {
+ printf("DRAM initialization failed: dram[0x%x] != 0x%x.", i, dram[i]);
+ hang();
+ }
+ }
+}
+
+static void do_dram_init(struct dram_para *para)
+{
+ struct sunxi_ccm_reg * const ccm =
+ (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
+ u32 val;
+ u8 m; /* PLL_DDR clock factor */
+
+ sunxi_gpio_set_cfgpin(SUNXI_GPB(3), 0x7);
+ mdelay(5);
+ /* TODO: dig out what's them... some analog register? */
+ if ((para->cas >> 3) & 0x1)
+ setbits_le32(SUNXI_PIO_BASE + 0x2c4, (0x1 << 23) | (0x20 << 17));
+
+ if (para->clk >= 144 && para->clk <= 180)
+ writel(0xaaa, SUNXI_PIO_BASE + 0x2c0);
+ if (para->clk >= 180)
+ writel(0xfff, SUNXI_PIO_BASE + 0x2c0);
+
+ if (para->cas & BIT(4))
+ writel(0xd1303333, &ccm->pll5_pattern_cfg);
+ else if (para->cas & BIT(5))
+ writel(0xcce06666, &ccm->pll5_pattern_cfg);
+ else if (para->cas & BIT(6))
+ writel(0xc8909999, &ccm->pll5_pattern_cfg);
+ else if (para->cas & BIT(7))
+ writel(0xc440cccc, &ccm->pll5_pattern_cfg);
+
+ if (para->clk <= 96)
+ m = 2;
+ else
+ m = 1;
+
+ val = CCM_PLL5_CTRL_EN | CCM_PLL5_CTRL_UPD |
+ CCM_PLL5_CTRL_N((para->clk * 2) / (24 / m)) |
+ CCM_PLL5_CTRL_K(1) | CCM_PLL5_CTRL_M(m);
+ if (para->cas & GENMASK(7, 4))
+ val |= CCM_PLL5_CTRL_SIGMA_DELTA_EN;
+ writel(val, &ccm->pll5_cfg);
+ setbits_le32(&ccm->pll5_cfg, CCM_PLL5_CTRL_UPD);
+ mctl_await_completion(&ccm->pll5_cfg, BIT(28), BIT(28));
+ mdelay(5);
+
+ setbits_le32(&ccm->ahb_gate0, (1 << AHB_GATE_OFFSET_MCTL));
+ clrbits_le32(&ccm->ahb_reset0_cfg, (1 << AHB_RESET_OFFSET_MCTL));
+ udelay(50);
+ setbits_le32(&ccm->ahb_reset0_cfg, (1 << AHB_RESET_OFFSET_MCTL));
+
+ clrsetbits_le32(SUNXI_PIO_BASE + 0x2c4, (1 << 16),
+ ((para->sdr_ddr == DRAM_TYPE_DDR) << 16));
+
+ val = (SDR_T_CAS << 0) | (SDR_T_RAS << 3) | (SDR_T_RCD << 7) |
+ (SDR_T_RP << 10) | (SDR_T_WR << 13) | (SDR_T_RFC << 15) |
+ (SDR_T_XSR << 19) | (SDR_T_RC << 28);
+ writel(val, SUNXI_DRAMC_BASE + DRAM_STMG0R);
+ val = (SDR_T_INIT << 0) | (SDR_T_INIT_REF << 16) | (SDR_T_WTR << 20) |
+ (SDR_T_RRD << 22) | (SDR_T_XP << 25);
+ writel(val, SUNXI_DRAMC_BASE + DRAM_STMG1R);
+ dram_para_setup(para);
+ dram_check_type(para);
+
+ clrsetbits_le32(SUNXI_PIO_BASE + 0x2c4, (1 << 16),
+ ((para->sdr_ddr == DRAM_TYPE_DDR) << 16));
+
+ dram_set_autofresh_cycle(para->clk);
+ dram_scan_readpipe(para);
+ dram_get_dram_size(para);
+ simple_dram_check();
+}
+
+unsigned long sunxi_dram_init(void)
+{
+ do_dram_init(&suniv_dram_para);
+
+ return suniv_dram_para.size * 1024 * 1024;
+}
diff --git a/arch/arm/cpu/armv7/sunxi/timer.c b/arch/arm/mach-sunxi/timer.c
index b7585996369..fc9d419a25e 100644
--- a/arch/arm/cpu/armv7/sunxi/timer.c
+++ b/arch/arm/mach-sunxi/timer.c
@@ -51,6 +51,7 @@ int timer_init(void)
struct sunxi_timer_reg *timers =
(struct sunxi_timer_reg *)SUNXI_TIMER_BASE;
struct sunxi_timer *timer = &timers->timer[TIMER_NUM];
+
writel(TIMER_LOAD_VAL, &timer->inter);
writel(TIMER_MODE | TIMER_DIV | TIMER_SRC | TIMER_RELOAD | TIMER_EN,
&timer->ctl);
@@ -58,15 +59,14 @@ int timer_init(void)
return 0;
}
-/* timer without interrupts */
static ulong get_timer_masked(void)
{
/* current tick value */
ulong now = TICKS_TO_HZ(read_timer());
- if (now >= gd->arch.lastinc) /* normal (non rollover) */
+ if (now >= gd->arch.lastinc) { /* normal (non rollover) */
gd->arch.tbl += (now - gd->arch.lastinc);
- else {
+ } else {
/* rollover */
gd->arch.tbl += (TICKS_TO_HZ(TIMER_LOAD_VAL)
- gd->arch.lastinc) + now;
@@ -76,6 +76,7 @@ static ulong get_timer_masked(void)
return gd->arch.tbl;
}
+/* timer without interrupts */
ulong get_timer(ulong base)
{
return get_timer_masked() - base;