/* * Rockchip rk3288 resume code * * This code is intended to be linked into the embedded resume binary * for the rk3288 SoC * * Copyright (c) 2014 Google, Inc * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ #include #include "rk3288_resume.h" #include "rk3288_resume_embedded.h" #define INIT_CPSR (PSR_I_BIT | PSR_F_BIT | SVC_MODE) static __noreturn void rk3288_resume(void); /* Parameters of early board initialization in SPL */ struct rk3288_resume_params rk3288_resume_params __attribute__((section(".resume_params"))) = { .resume_loc = rk3288_resume, }; /** * rk3288_resume_c - Main C entry point for rk3288 at resume time * * This function is called by rk3288_resume() and does the brunt of * any resume processing. After it's done it will call the kernel's * cpu_resume() function (which it finds through its params structure). * * At the time this function is called: * - We know we're on CPU0. * - Interrupts are disabled. * - We've got a stack. * - The cache is turned off, so all addresses are physical. * - SDRAM hasn't been restored yet (if it was off). * * WARNING: This code, the stack and the params structure are all sitting in * PMU SRAM. If you try to write to that memory using an 8-bit access (or even * 16-bit) you'll get an imprecise data abort and it will be very hard to debug. * Keep everything in here as 32-bit wide and aligned. YOU'VE BEEN WARNED. */ static void __noreturn rk3288_resume_c(void) { #ifdef CONFIG_ARM_ERRATA_818325 u32 val = 0; asm("mrc p15, 0, %0, c15, c0, 1" : "=r" (val)); val |= BIT(12); asm("mcr p15, 0, %0, c15, c0, 1" : : "r" (val)); #endif if (rk3288_resume_params.l2ctlr_f) asm("mcr p15, 1, %0, c9, c0, 2" : : "r" (rk3288_resume_params.l2ctlr)); if (rk3288_resume_params.ddr_resume_f) rk3288_ddr_resume_early(&rk3288_resume_params.ddr_save_data); rk3288_resume_params.cpu_resume(); } /** * rk3288_resume - First entry point for rk3288 at resume time * * A pointer to this function is stored in rk3288_resume_params. The * kernel uses the pointer in that structure to find this function and * to put its (physical) address in a location that it will get jumped * to at resume time. * * There is no stack at the time this function is called, so this * function is in charge of setting it up. We get to a function with * a normal stack pointer ASAP. */ static void __naked __noreturn rk3288_resume(void) { /* Make sure we're on CPU0, no IRQs and get a stack setup */ asm volatile ( "msr cpsr_cxf, %0\n" /* Only cpu0 continues to run, the others halt here */ "mrc p15, 0, r1, c0, c0, 5\n" "and r1, r1, #0xf\n" "cmp r1, #0\n" "beq cpu0run\n" "secondary_loop:\n" "wfe\n" "b secondary_loop\n" "cpu0run:\n" "mov sp, %1\n" : : "i" (INIT_CPSR), "r" (&__stack_start) : "cc", "r1", "sp"); /* Now get into a normal function that can use a stack */ rk3288_resume_c(); }