contrib: replace the GPLv2-or-later license tag
[fw/openocd] / contrib / loaders / flash / efm32.S
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2
3 /***************************************************************************
4  *   Copyright (C) 2011 by Andreas Fritiofson                              *
5  *   andreas.fritiofson@gmail.com                                          *
6  *   Copyright (C) 2013 by Roman Dmitrienko                                *
7  *   me@iamroman.org                                                       *
8  ***************************************************************************/
9
10         .text
11         .syntax unified
12         .cpu cortex-m0
13         .thumb
14         .thumb_func
15
16         /* Params:
17          * r0 - flash base (in), status (out)
18          * r1 - count (word-32bit)
19          * r2 - workarea start
20          * r3 - workarea end
21          * r4 - target address
22          * Clobbered:
23          * r5 - rp
24          * r6 - wp, tmp
25          * r7 - tmp
26          */
27
28 /* offsets of registers from flash reg base */
29 #define EFM32_MSC_WRITECTRL_OFFSET      0x008
30 #define EFM32_MSC_WRITECMD_OFFSET       0x00c
31 #define EFM32_MSC_ADDRB_OFFSET          0x010
32 #define EFM32_MSC_WDATA_OFFSET          0x018
33 #define EFM32_MSC_STATUS_OFFSET         0x01c
34
35         /* set WREN to 1 */
36         movs    r6, #1
37         str     r6, [r0, #EFM32_MSC_WRITECTRL_OFFSET]
38
39 wait_fifo:
40         ldr     r6, [r2, #0]    /* read wp */
41         cmp     r6, #0          /* abort if wp == 0 */
42         beq     exit
43         ldr     r5, [r2, #4]    /* read rp */
44         cmp     r5, r6          /* wait until rp != wp */
45         beq     wait_fifo
46
47         /* store address in MSC_ADDRB */
48         str     r4, [r0, #EFM32_MSC_ADDRB_OFFSET]
49         /* set LADDRIM bit */
50         movs    r6, #1
51         str     r6, [r0, #EFM32_MSC_WRITECMD_OFFSET]
52         /* check status for INVADDR and/or LOCKED */
53         ldr     r6, [r0, #EFM32_MSC_STATUS_OFFSET]
54         movs    r7, #6
55         tst     r6, r7
56         bne     error
57
58         /* wait for WDATAREADY */
59 wait_wdataready:
60         ldr     r6, [r0, #EFM32_MSC_STATUS_OFFSET]
61         movs    r7, #8
62         tst     r6, r7
63         beq     wait_wdataready
64
65         /* load data to WDATA */
66         ldr     r6, [r5]
67         str     r6, [r0, #EFM32_MSC_WDATA_OFFSET]
68         /* set WRITEONCE bit */
69         movs    r6, #8
70         str     r6, [r0, #EFM32_MSC_WRITECMD_OFFSET]
71
72         adds    r5, #4          /* rp++ */
73         adds    r4, #4          /* target_address++ */
74
75         /* wait until BUSY flag is reset */
76 busy:
77         ldr     r6, [r0, #EFM32_MSC_STATUS_OFFSET]
78         movs    r7, #1
79         tst     r6, r7
80         bne     busy
81
82         cmp     r5, r3          /* wrap rp at end of buffer */
83         bcc     no_wrap
84         mov     r5, r2
85         adds    r5, #8
86 no_wrap:
87         str     r5, [r2, #4]    /* store rp */
88         subs    r1, r1, #1      /* decrement word count */
89         cmp     r1, #0
90         beq     exit            /* loop if not done */
91         b       wait_fifo
92 error:
93         movs    r0, #0
94         str     r0, [r2, #4]    /* set rp = 0 on error */
95 exit:
96         mov     r0, r6          /* return status in r0 */
97         bkpt    #0