1/*
2 * Copyright (c) 2023 Renesas Electronics Corporation
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7#if __ZEPHYR__
8
9#define RESETHANDLER            __start
10#define RAM_TEXT_SECTION        .ramfunc
11
12#if defined(CONFIG_FPU)
13#define USE_FPU 1
14#else
15#define USE_FPU 0
16#endif
17/* No MTB support for Zephyr */
18#define USE_MTB 0
19
20#elif defined(MYNEWT)
21 #include <syscfg/syscfg.h>
22#define RESETHANDLER            ResetHandler
23#define RAM_TEXT_SECTION        .text_ram
24#define USE_FPU                 MYNEWT_VAL(HARDFLOAT)
25#define USE_MTB                 1
26#endif
27
28    .syntax unified
29    .section .bss
30    .global da1469x_sleep_context
31    .type da1469x_sleep_context, %object
32    .align 4
33da1469x_sleep_context:
34.saved_primask:
35    .space 4    /* PRIMASK */
36.saved_msp:
37    .space 4    /* MSP */
38.saved_psp:
39    .space 4    /* PSP */
40.saved_control:
41    .space 4    /* CONTROL */
42.saved_regs:
43    .space 40   /* R4-R12, LR */
44.saved_nvic:
45    .space 8    /* ISER[0..1] */
46    .space 44   /* IPR[0..43] */
47.saved_scb:
48    .space 28   /* SCR, CCR, SHPR[0..11], CPACR */
49#if defined(FPU)
50.saved_fpu:
51    .space 8    /* FPCCR, FPDSCR */
52#endif
53
54    .equ CLK_AMBA_REG,              0x50000000
55    .equ RESET_STAT_REG,            0x500000BC
56    .equ NVIC_BASE,                 0xE000E100
57    .equ NVIC_IPR_OFFSET,           0x300
58    .equ SCB_BASE,                  0xE000ED00
59    .equ SCB_SCR_OFFSET,            0x010
60    .equ SCB_SHCSR_OFFSET,          0x024
61    .equ SCB_CPACR_OFFSET,          0x088
62    .equ FPU_BASE,                  0xE000EF30
63    .equ FPU_FPCCR_OFFSET,          0x004
64    .equ FPU_FPDSCR_OFFSET,         0x00C
65    .equ QSPIC_BASE,                0x38000000
66    .equ QSPIC_CTRLBUS_OFFSET,      0x000
67    .equ QSPIC_CTRLMOD_OFFSET,      0x004
68    .equ QSPIC_WRITEDATA_OFFSET,    0x018
69
70    .equ SCB_CPACR_MASK,            0x00F00000  /* CP10 and CP11 */
71    .equ SCB_SHCSR_MASK,            0x000F0000  /* xxxFAULTENA */
72    .equ FPU_FPCCR_MASK,            0xF0000000  /* ASPEN, LSPEN, LSPENS, CLRONRET */
73
74    .section RAM_TEXT_SECTION, "ax"
75    .thumb
76    .thumb_func
77    .align  2
78    .globl  da1469x_enter_sleep
79    .type   da1469x_enter_sleep, %function
80da1469x_enter_sleep:
81    ldr     r3, =da1469x_sleep_context
82
83/* Disable interrupts and save original PRIMASK */
84    mrs     r0, PRIMASK
85    cpsid   i
86    stmia   r3!, {r0}
87
88/* Save MSP, PSP, CONTROL and general purpose registers */
89    mrs     r0, MSP
90    mrs     r1, PSP
91    mrs     r2, CONTROL
92    stmia   r3!, {r0-r2,r4-r12, lr}
93
94/* Save NVIC state (ISER[0..1] and IPR[0..43]) */
95    ldr     r0, =NVIC_BASE
96    add     r1, r0, NVIC_IPR_OFFSET
97    ldmia   r0!, {r4-r5}
98    stmia   r3!, {r4-r5}
99    ldmia   r1, {r0, r2, r4-r12}
100    stmia   r3!, {r0, r2, r4-r12}
101
102/* Save SCB state (SCR, CCR, SHPR and SHCSR) */
103    ldr     r0, =(SCB_BASE + SCB_SCR_OFFSET)
104    ldmia   r0, {r4-r9}
105    and     r9, r9, #(SCB_SHCSR_MASK)
106    ldr     r10, [r0, #(SCB_CPACR_OFFSET - SCB_SCR_OFFSET)]
107    and     r10, r10, #(SCB_CPACR_MASK)
108    stmia   r3!, {r4-r10}
109
110#if USE_FPU
111/* Save FPU state (FPCCR and FPDSCR) */
112    ldr     r0, =FPU_BASE
113    ldr     r4, [r0, #(FPU_FPCCR_OFFSET)]
114    and     r4, r4, #(FPU_FPCCR_MASK)
115    ldr     r5, [r0, #(FPU_FPDSCR_OFFSET)]
116    stmia   r3!, {r4-r5}
117#endif
118
119/* Clear RESET_STAT_REG so wakeup handler can detect wakeup from deep sleep */
120    ldr     r0, =RESET_STAT_REG
121    movs    r3, #0
122    str     r3, [r0, #0]
123
124/* Disable QSPI continuous mode to achieve flash standby */
125    ldr     r0, =QSPIC_BASE
126    ldr     r1, [r0, #(QSPIC_CTRLMOD_OFFSET)]
127    bic     r1, r1, #1      /* Clear automode */
128    orr     r1, r1, #0x3c   /* Set IO2/IO3 DAT and OEN */
129    str     r1, [r0, #(QSPIC_CTRLMOD_OFFSET)]
130    mov     r1, #1          /* Set single */
131    str     r1, [r0, #(QSPIC_CTRLBUS_OFFSET)]
132    mov     r1, #8          /* Enable CS */
133    str     r1, [r0, #(QSPIC_CTRLBUS_OFFSET)]
134    mov     r1, #0xff       /* Exit QPI mode */
135    strb    r1, [r0, #(QSPIC_WRITEDATA_OFFSET)]
136    mov     r1, #16         /* Disable CS */
137    str     r1, [r0, #(QSPIC_CTRLBUS_OFFSET)]
138
139/* Disable QSPI controller clock */
140    ldr     r0, =CLK_AMBA_REG
141    ldr     r1, [r0, #0]
142    bic     r1, r1, #0x1000
143    str     r1, [r0, #0]
144
145/* Set SCB->SCR[SLEEPDEEP] so we can enter deep sleep */
146    ldr     r0, =(SCB_BASE + SCB_SCR_OFFSET)
147    ldr     r1, [r0, #0]
148    orr     r1, r1, #4      /* SLEEPDEEP */
149    str     r1, [r0, #0]
150
151/* Sleep! */
152    dsb
153    wfi
154
155/*
156 * If deep sleep was executed we'll restart in reset handler, otherwise we just
157 * restore registers and continue by returning false to caller to indicate we
158 * did not sleep.
159 */
160    str     r1, [r0, #0]
161
162/* Enable QSPI controller clock */
163    ldr     r2, =CLK_AMBA_REG
164    ldr     r1, [r2, #0]
165    orr     r1, r1, #0x1000
166    str     r1, [r2, #0]
167
168/* Put flash back into automode. We need to do this before we start executing code
169   from flash again.
170*/
171    ldr     r0, =QSPIC_BASE
172    str     r1, [r0, #(QSPIC_CTRLBUS_OFFSET)]
173    mov     r1, #4          /* Set quad */
174    str     r1, [r0, #(QSPIC_CTRLBUS_OFFSET)]
175    ldr     r1, [r0, #(QSPIC_CTRLMOD_OFFSET)]
176    bic     r1, r1, #0xc    /* Clear IO2/IO3 OEN */
177    orr     r1, r1, #1      /* Enable automode */
178    str     r1, [r0, #(QSPIC_CTRLMOD_OFFSET)]
179
180    mov     r0, #0
181    b       da1469x_restore_state
182
183    .section RAM_TEXT_SECTION, "ax"
184    .globl  da1469x_wakeup
185    .type   da1469x_wakeup, %function
186da1469x_wakeup:
187/* Disable interrupts, we'll restore proper PRIMASK at the end */
188    cpsid   i
189
190 /*
191  * Temporarily restore saved MSP as temporary stack pointer to allow proper
192  * stacking in case of an exception.
193  */
194    ldr     r3, =.saved_msp
195    ldr     sp, [r3, #0]
196
197 /* Restore NVIC state */
198    ldr     r3, =.saved_nvic
199    ldr     r0, =NVIC_BASE
200    add     r1, r0, NVIC_IPR_OFFSET
201    ldmia   r3!, {r4-r5}
202    stmia   r0!, {r4-r5}
203    ldmia   r3!, {r0, r2, r4-r12}
204    stmia   r1, {r0, r2, r4-r12}
205
206 /* Restore SCB state */
207    ldmia   r3!, {r4-r10}
208    ldr     r0, =(SCB_BASE + SCB_SCR_OFFSET)
209    ldr     r1, [r0, #(SCB_CPACR_OFFSET - SCB_SCR_OFFSET)]
210    orr     r10, r10, r1
211    str     r10, [r0, #(SCB_CPACR_OFFSET - SCB_SCR_OFFSET)]
212    ldr     r1, [r0, #(SCB_SHCSR_OFFSET - SCB_SCR_OFFSET)]
213    orr     r9, r9, r1
214    stmia   r0!, {r4-r9}
215
216#if USE_FPU
217/* Restore FPU state */
218    ldmia   r3!, {r4-r5}
219    ldr     r0, =FPU_BASE
220    ldr     r1, [r0, #(FPU_FPCCR_OFFSET)]
221    orr     r4, r4, r1
222    str     r4, [r0, #(FPU_FPCCR_OFFSET)]
223    str     r5, [r0, #(FPU_FPDSCR_OFFSET)]
224#endif
225
226/* Restore MSP, PSP and CONTROL */
227    ldr     r3, =.saved_msp
228    ldmia   r3!, {r0-r2}
229    msr     MSP, r0
230    msr     PSP, r1
231    msr     CONTROL, r2
232
233/* Enable QSPI controller clock */
234    ldr     r0, =CLK_AMBA_REG
235    ldr     r1, [r0, #0]
236    orr     r1, r1, #0x1000
237    str     r1, [r0, #0]
238
239/*
240 * Flash is likely in QPI mode but QSPIC assumes it is in single mode so we
241 * should make sure both are in sync by forcing exit from QPI mode and then
242 * re-enter it. We need to do this before we start executing code from flash
243 * again.
244 */
245    ldr     r0, =QSPIC_BASE
246    ldr     r1, [r0, #(QSPIC_CTRLMOD_OFFSET)]
247    bic     r1, r1, #1      /* Clear automode */
248    orr     r1, r1, #0x3c   /* Set IO2/IO3 DAT and OEN */
249    str     r1, [r0, #(QSPIC_CTRLMOD_OFFSET)]
250    mov     r1, #1          /* Set single */
251    str     r1, [r0, #(QSPIC_CTRLBUS_OFFSET)]
252    mov     r1, #8          /* Enable CS */
253    str     r1, [r0, #(QSPIC_CTRLBUS_OFFSET)]
254    mov     r1, #0xff       /* Exit QPI mode */
255    strb    r1, [r0, #(QSPIC_WRITEDATA_OFFSET)]
256    mov     r1, #16         /* Disable CS */
257    str     r1, [r0, #(QSPIC_CTRLBUS_OFFSET)]
258    mov     r1, #4          /* Set quad */
259    str     r1, [r0, #(QSPIC_CTRLBUS_OFFSET)]
260    ldr     r1, [r0, #(QSPIC_CTRLMOD_OFFSET)]
261    bic     r1, r1, #0xc    /* Clear IO2/IO3 OEN */
262    orr     r1, r1, #1      /* Enable automode */
263    str     r1, [r0, #(QSPIC_CTRLMOD_OFFSET)]
264
265/* Finish restore, return true to caller to indicate we slept */
266    mov     r0, #1
267    ldr     r3, =da1469x_restore_state
268    bx      r3
269
270    .section RAM_TEXT_SECTION, "ax"
271    .globl  da1469x_restore_state
272    .type   da1469x_restore_state, %function
273da1469x_restore_state:
274    ldr     r3, =.saved_regs
275    ldmia   r3!, {r4-r12, lr}
276
277    ldr     r3, =.saved_primask
278    ldr     r3, [r3, #0]
279    msr     PRIMASK, r3
280
281    bx      lr
282
283    .section RAM_TEXT_SECTION, "ax"
284    .globl  da1469x_wakeup_handler
285    .type   da1469x_wakeup_handler, %function
286da1469x_wakeup_handler:
287    ldr     r0, =RESET_STAT_REG
288    ldr     r0, [r0, #0]
289    teq     r0, #0
290    ite     eq
291    ldreq   r3, =da1469x_wakeup
292    ldrne   r3, =RESETHANDLER
293    bx      r3
294