Marc Zyngier | d5db702 | 2014-07-18 21:06:38 +0100 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (C) 2013 - ARM Ltd |
| 3 | * Author: Marc Zyngier <marc.zyngier@arm.com> |
| 4 | * |
| 5 | * Based on code by Carl van Schaik <carl@ok-labs.com>. |
| 6 | * |
| 7 | * This program is free software; you can redistribute it and/or modify |
| 8 | * it under the terms of the GNU General Public License version 2 as |
| 9 | * published by the Free Software Foundation. |
| 10 | * |
| 11 | * This program is distributed in the hope that it will be useful, |
| 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 14 | * GNU General Public License for more details. |
| 15 | * |
| 16 | * You should have received a copy of the GNU General Public License |
| 17 | * along with this program. If not, see <http://www.gnu.org/licenses/>. |
| 18 | */ |
| 19 | |
| 20 | #include <config.h> |
| 21 | #include <asm/psci.h> |
| 22 | #include <asm/arch/cpu.h> |
| 23 | |
| 24 | /* |
| 25 | * Memory layout: |
| 26 | * |
| 27 | * SECURE_RAM to text_end : |
| 28 | * ._secure_text section |
| 29 | * text_end to ALIGN_PAGE(text_end): |
| 30 | * nothing |
| 31 | * ALIGN_PAGE(text_end) to ALIGN_PAGE(text_end) + 0x1000) |
| 32 | * 1kB of stack per CPU (4 CPUs max). |
| 33 | */ |
| 34 | |
| 35 | .pushsection ._secure.text, "ax" |
| 36 | |
| 37 | .arch_extension sec |
| 38 | |
| 39 | #define ONE_MS (CONFIG_SYS_CLK_FREQ / 1000) |
| 40 | #define TEN_MS (10 * ONE_MS) |
| 41 | |
| 42 | .macro timer_wait reg, ticks |
| 43 | @ Program CNTP_TVAL |
| 44 | movw \reg, #(\ticks & 0xffff) |
| 45 | movt \reg, #(\ticks >> 16) |
| 46 | mcr p15, 0, \reg, c14, c2, 0 |
| 47 | isb |
| 48 | @ Enable physical timer, mask interrupt |
| 49 | mov \reg, #3 |
| 50 | mcr p15, 0, \reg, c14, c2, 1 |
| 51 | @ Poll physical timer until ISTATUS is on |
| 52 | 1: isb |
| 53 | mrc p15, 0, \reg, c14, c2, 1 |
| 54 | ands \reg, \reg, #4 |
| 55 | bne 1b |
| 56 | @ Disable timer |
| 57 | mov \reg, #0 |
| 58 | mcr p15, 0, \reg, c14, c2, 1 |
| 59 | isb |
| 60 | .endm |
| 61 | |
| 62 | .globl psci_arch_init |
| 63 | psci_arch_init: |
| 64 | mrc p15, 0, r5, c1, c1, 0 @ Read SCR |
| 65 | bic r5, r5, #1 @ Secure mode |
| 66 | mcr p15, 0, r5, c1, c1, 0 @ Write SCR |
| 67 | isb |
| 68 | |
| 69 | mrc p15, 0, r4, c0, c0, 5 @ MPIDR |
| 70 | and r4, r4, #3 @ cpu number in cluster |
Jan Kiszka | 3f6242e | 2014-11-27 09:38:50 +0100 | [diff] [blame] | 71 | mov r5, #0x400 @ 1kB of stack per CPU |
Marc Zyngier | d5db702 | 2014-07-18 21:06:38 +0100 | [diff] [blame] | 72 | mul r4, r4, r5 |
| 73 | |
| 74 | adr r5, text_end @ end of text |
| 75 | add r5, r5, #0x2000 @ Skip two pages |
| 76 | lsr r5, r5, #12 @ Align to start of page |
| 77 | lsl r5, r5, #12 |
| 78 | sub sp, r5, r4 @ here's our stack! |
| 79 | |
| 80 | bx lr |
| 81 | |
| 82 | @ r1 = target CPU |
| 83 | @ r2 = target PC |
| 84 | .globl psci_cpu_on |
| 85 | psci_cpu_on: |
| 86 | adr r0, _target_pc |
| 87 | str r2, [r0] |
| 88 | dsb |
| 89 | |
Hans de Goede | 9d8a533 | 2014-10-27 23:59:27 +0100 | [diff] [blame] | 90 | movw r0, #(SUN7I_CPUCFG_BASE & 0xffff) |
| 91 | movt r0, #(SUN7I_CPUCFG_BASE >> 16) |
Marc Zyngier | d5db702 | 2014-07-18 21:06:38 +0100 | [diff] [blame] | 92 | |
| 93 | @ CPU mask |
| 94 | and r1, r1, #3 @ only care about first cluster |
| 95 | mov r4, #1 |
| 96 | lsl r4, r4, r1 |
| 97 | |
| 98 | adr r6, _sunxi_cpu_entry |
| 99 | str r6, [r0, #0x1a4] @ PRIVATE_REG (boot vector) |
| 100 | |
| 101 | @ Assert reset on target CPU |
| 102 | mov r6, #0 |
| 103 | lsl r5, r1, #6 @ 64 bytes per CPU |
| 104 | add r5, r5, #0x40 @ Offset from base |
| 105 | add r5, r5, r0 @ CPU control block |
| 106 | str r6, [r5] @ Reset CPU |
| 107 | |
| 108 | @ l1 invalidate |
| 109 | ldr r6, [r0, #0x184] |
| 110 | bic r6, r6, r4 |
| 111 | str r6, [r0, #0x184] |
| 112 | |
| 113 | @ Lock CPU |
| 114 | ldr r6, [r0, #0x1e4] |
| 115 | bic r6, r6, r4 |
| 116 | str r6, [r0, #0x1e4] |
| 117 | |
| 118 | @ Release power clamp |
| 119 | movw r6, #0x1ff |
| 120 | movt r6, #0 |
| 121 | 1: lsrs r6, r6, #1 |
| 122 | str r6, [r0, #0x1b0] |
| 123 | bne 1b |
| 124 | |
| 125 | timer_wait r1, TEN_MS |
| 126 | |
| 127 | @ Clear power gating |
| 128 | ldr r6, [r0, #0x1b4] |
| 129 | bic r6, r6, #1 |
| 130 | str r6, [r0, #0x1b4] |
| 131 | |
| 132 | @ Deassert reset on target CPU |
| 133 | mov r6, #3 |
| 134 | str r6, [r5] |
| 135 | |
| 136 | @ Unlock CPU |
| 137 | ldr r6, [r0, #0x1e4] |
| 138 | orr r6, r6, r4 |
| 139 | str r6, [r0, #0x1e4] |
| 140 | |
| 141 | mov r0, #ARM_PSCI_RET_SUCCESS @ Return PSCI_RET_SUCCESS |
| 142 | mov pc, lr |
| 143 | |
| 144 | _target_pc: |
| 145 | .word 0 |
| 146 | |
| 147 | _sunxi_cpu_entry: |
| 148 | @ Set SMP bit |
| 149 | mrc p15, 0, r0, c1, c0, 1 |
| 150 | orr r0, r0, #0x40 |
| 151 | mcr p15, 0, r0, c1, c0, 1 |
| 152 | isb |
| 153 | |
| 154 | bl _nonsec_init |
| 155 | bl psci_arch_init |
| 156 | |
| 157 | adr r0, _target_pc |
| 158 | ldr r0, [r0] |
| 159 | b _do_nonsec_entry |
| 160 | |
| 161 | text_end: |
| 162 | .popsection |