rk3026: add reset support
author黄涛 <huangtao@rock-chips.com>
Thu, 8 Aug 2013 08:22:16 +0000 (16:22 +0800)
committer黄涛 <huangtao@rock-chips.com>
Thu, 8 Aug 2013 09:53:53 +0000 (17:53 +0800)
arch/arm/mach-rk3026/Makefile
arch/arm/mach-rk3026/reset.c [new file with mode: 0644]

index a35540cca77488b6408e0b33c5487f233c2b5801..55150cdc112183bb4235a1fec3049b48d2988b3c 100644 (file)
@@ -2,7 +2,7 @@ ifneq ($(CONFIG_RK_FPGA),y)
 obj-y += ../plat-rk/clock.o
 obj-y += clock_data.o
 obj-y += ../mach-rk2928/ddr.o
-obj-y += ../mach-rk30/reset.o
+obj-y += reset.o
 obj-$(CONFIG_PM) += ../mach-rk2928/pm.o
 endif
 obj-y += common.o
diff --git a/arch/arm/mach-rk3026/reset.c b/arch/arm/mach-rk3026/reset.c
new file mode 100644 (file)
index 0000000..24cce14
--- /dev/null
@@ -0,0 +1,163 @@
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <mach/system.h>
+#include <linux/string.h>
+#include <mach/cru.h>
+#include <mach/grf.h>
+#include <mach/loader.h>
+#include <mach/board.h>
+
+//#define DEBUG // for jtag debug
+
+#define cru_readl(offset)     readl_relaxed(RK30_CRU_BASE + offset)
+#define cru_writel(v, offset) do { writel_relaxed(v, RK30_CRU_BASE + offset); dsb(); } while (0)
+#define grf_readl(offset)     readl_relaxed(RK30_GRF_BASE + offset)
+#define grf_writel(v, offset) do { writel_relaxed(v, RK30_GRF_BASE + offset); dsb(); } while (0)
+
+static bool is_panic = false;
+
+static int panic_event(struct notifier_block *this, unsigned long event, void *ptr)
+{
+       is_panic = true;
+       return NOTIFY_DONE;
+}
+
+static struct notifier_block panic_block = {
+       .notifier_call  = panic_event,
+};
+
+static int __init arch_reset_init(void)
+{
+       atomic_notifier_chain_register(&panic_notifier_list, &panic_block);
+       return 0;
+}
+core_initcall(arch_reset_init);
+
+#ifdef DEBUG
+__sramdata volatile int reset_loop = 1;
+#endif
+
+static void __sramfunc __noreturn soft_reset(void)
+{
+       /* pll enter slow mode */
+       cru_writel(0xffff0000, CRU_MODE_CON);
+
+       /* restore clock select and divide */
+       cru_writel(0xffff0200, CRU_CLKSELS_CON(0));
+       cru_writel(0xffff3113, CRU_CLKSELS_CON(1));
+       cru_writel(0xfff00000, CRU_CLKSELS_CON(2)); // 3:0 reserved
+       cru_writel(0xffff0200, CRU_CLKSELS_CON(3));
+       cru_writel(0x003f0000, CRU_CLKSELS_CON(4)); // 15:6 reserved
+       cru_writel(0x003f0000, CRU_CLKSELS_CON(5)); // 15:6 reserved
+       cru_writel(0x0bb8ea60, CRU_CLKSELS_CON(6));
+       cru_writel(0x0bb8ea60, CRU_CLKSELS_CON(7));
+       cru_writel(0xffff2100, CRU_CLKSELS_CON(10));
+       cru_writel(0x007f0017, CRU_CLKSELS_CON(11)); // 15:7 reserved
+       cru_writel(0xffff1717, CRU_CLKSELS_CON(12));
+       cru_writel(0xffff0200, CRU_CLKSELS_CON(13));
+       cru_writel(0xffff0200, CRU_CLKSELS_CON(14));
+       cru_writel(0xffff0200, CRU_CLKSELS_CON(15));
+       cru_writel(0x0bb8ea60, CRU_CLKSELS_CON(17));
+       cru_writel(0x0bb8ea60, CRU_CLKSELS_CON(18));
+       cru_writel(0x0bb8ea60, CRU_CLKSELS_CON(19));
+       cru_writel(0x0bb8ea60, CRU_CLKSELS_CON(23));
+       cru_writel(0xffff1700, CRU_CLKSELS_CON(24));
+       cru_writel(0x017f0107, CRU_CLKSELS_CON(25)); // 15:9 7 reserved
+       cru_writel(0xffff0000, CRU_CLKSELS_CON(26));
+       cru_writel(0xffff0700, CRU_CLKSELS_CON(27));
+       cru_writel(0xffff0700, CRU_CLKSELS_CON(28));
+       cru_writel(0xffff0012, CRU_CLKSELS_CON(29));
+       cru_writel(0xffff0300, CRU_CLKSELS_CON(30));
+       cru_writel(0xffff0001, CRU_CLKSELS_CON(31));
+       cru_writel(0xffff0303, CRU_CLKSELS_CON(32));
+       cru_writel(0xffff0003, CRU_CLKSELS_CON(34));
+
+       /* idle request PERI/VIO/VPU/GPU */
+       grf_writel(0x1e00ffff, GRF_SOC_CON2);
+       while ((grf_readl(GRF_SOC_STATUS0) & (0x1e << 16)) != (0x1e << 16))
+               ;
+       while ((grf_readl(GRF_SOC_STATUS0) & (0x1e << 22)) != (0x1e << 22))
+               ;
+
+       /* software reset modules */
+#ifdef DEBUG
+       cru_writel(0xfff3ffff, CRU_SOFTRSTS_CON(8)); // CORE_DBG/DBG_APB
+#else
+       cru_writel(0xffffffff, CRU_SOFTRSTS_CON(8));
+#endif
+       cru_writel(0xffffffff, CRU_SOFTRSTS_CON(7));
+       cru_writel(0xffffffff, CRU_SOFTRSTS_CON(6));
+       cru_writel(0xffffffff, CRU_SOFTRSTS_CON(5));
+       cru_writel(0x7fffffff, CRU_SOFTRSTS_CON(4)); // DDRMSCH
+#ifdef DEBUG
+       cru_writel(0xff63ffff, CRU_SOFTRSTS_CON(3)); // DAP_PO/DAP/DAP_SYS
+#else
+       cru_writel(0xff7fffff, CRU_SOFTRSTS_CON(3)); // GRF
+#endif
+       cru_writel(0xfff0ffff, CRU_SOFTRSTS_CON(2)); // GPIO0/1/2/3
+       cru_writel(0xffdfffff, CRU_SOFTRSTS_CON(1)); // INTMEM
+#ifdef DEBUG
+       cru_writel(0x1e60ffff, CRU_SOFTRSTS_CON(0)); // MCORE_DBG/CORE0_DBG
+#else
+       cru_writel(0x1fe0ffff, CRU_SOFTRSTS_CON(0)); // CORE_SRST_WDT_SEL/MCORE/CORE0/CORE1/ACLK_CORE/STRC_SYS_AXI/L2C
+#endif
+
+       sram_udelay(1000);
+
+       cru_writel(0xffff0000, CRU_SOFTRSTS_CON(0));
+       cru_writel(0xffff0000, CRU_SOFTRSTS_CON(1));
+       cru_writel(0xffff0000, CRU_SOFTRSTS_CON(2));
+       cru_writel(0xffff0000, CRU_SOFTRSTS_CON(3));
+       cru_writel(0xffff0000, CRU_SOFTRSTS_CON(4));
+       cru_writel(0xffff0000, CRU_SOFTRSTS_CON(5));
+       cru_writel(0xffff0000, CRU_SOFTRSTS_CON(6));
+       cru_writel(0xffff0000, CRU_SOFTRSTS_CON(7));
+       cru_writel(0xffff0000, CRU_SOFTRSTS_CON(8));
+
+       /* disable idle request */
+       grf_writel(0x3f000000, GRF_SOC_CON2);
+       while (grf_readl(GRF_SOC_STATUS0) & (0x3f << 16))
+               ;
+       while (grf_readl(GRF_SOC_STATUS0) & (0x3f << 22))
+               ;
+
+#ifdef DEBUG
+//     while (reset_loop);
+#endif
+
+       cru_writel(0x801cffff, CRU_SOFTRSTS_CON(0)); // MCORE/CORE0/CORE1/L2C
+
+       while (1);
+}
+
+static void rk30_arch_reset(char mode, const char *cmd)
+{
+       unsigned i;
+       u32 boot_flag = 0;
+       u32 boot_mode = BOOT_MODE_REBOOT;
+
+       if (cmd) {
+               if (!strcmp(cmd, "loader") || !strcmp(cmd, "bootloader"))
+                       boot_flag = SYS_LOADER_REBOOT_FLAG + BOOT_LOADER;
+               else if(!strcmp(cmd, "recovery"))
+                       boot_flag = SYS_LOADER_REBOOT_FLAG + BOOT_RECOVER;
+               else if (!strcmp(cmd, "charge"))
+                       boot_mode = BOOT_MODE_CHARGE;
+       } else {
+               if (is_panic)
+                       boot_mode = BOOT_MODE_PANIC;
+       }
+       grf_writel(boot_flag, GRF_OS_REG4);     // for loader
+       grf_writel(boot_mode, GRF_OS_REG5);     // for linux
+
+       /* enable all clock */
+       for (i = 0; i < CRU_CLKGATES_CON_CNT; i++)
+               cru_writel(0xffff0000, CRU_CLKGATES_CON(i));
+
+       /* disable remap */
+       grf_writel(1 << (12 + 16), GRF_SOC_CON0);
+
+       ((void(*)(void))((u32)soft_reset - (u32)RK30_IMEM_BASE + (u32)RK30_IMEM_NONCACHED))();
+}
+
+void (*arch_reset)(char, const char *) = rk30_arch_reset;