contrib: replace the GPLv2-or-later license tag
[fw/openocd] / contrib / loaders / flash / lpcspifi_erase.S
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2
3 /***************************************************************************
4  *   Copyright (C) 2012 by George Harris                                   *
5  *   george@luminairecoffee.com                                            *
6  ***************************************************************************/
7
8         .text
9         .syntax unified
10         .cpu cortex-m3
11         .thumb
12         .thumb_func
13
14 /*
15  * Params :
16  * r0 = start address, status (out)
17  * r1 = count
18  * r2 = erase command
19  * r3 = block size
20  */
21
22 #define SSP_BASE_HIGH                           0x4008
23 #define SSP_BASE_LOW                            0x3000
24 #define SSP_CR0_OFFSET                          0x00
25 #define SSP_CR1_OFFSET                          0x04
26 #define SSP_DATA_OFFSET                         0x08
27 #define SSP_CPSR_OFFSET                         0x10
28 #define SSP_SR_OFFSET                           0x0c
29
30 #define SSP_CLOCK_BASE_HIGH             0x4005
31 #define SSP_CLOCK_BASE_LOW                      0x0000
32 #define SSP_BRANCH_CLOCK_BASE_HIGH      0x4005
33 #define SSP_BRANCH_CLOCK_BASE_LOW       0x2000
34 #define SSP_BASE_CLOCK_OFFSET           0x94
35 #define SSP_BRANCH_CLOCK_OFFSET         0x700
36
37 #define IOCONFIG_BASE_HIGH                      0x4008
38 #define IOCONFIG_BASE_LOW                       0x6000
39 #define IOCONFIG_SCK_OFFSET                     0x18c
40 #define IOCONFIG_HOLD_OFFSET            0x190
41 #define IOCONFIG_WP_OFFSET                      0x194
42 #define IOCONFIG_MISO_OFFSET            0x198
43 #define IOCONFIG_MOSI_OFFSET            0x19c
44 #define IOCONFIG_CS_OFFSET                      0x1a0
45
46 #define IO_BASE_HIGH                            0x400f
47 #define IO_BASE_LOW                             0x4000
48 #define IO_CS_OFFSET                            0xab
49 #define IODIR_BASE_HIGH                         0x400f
50 #define IODIR_BASE_LOW                          0x6000
51 #define IO_CS_DIR_OFFSET                        0x14
52
53
54 setup: /* Initialize SSP pins and module */
55         mov.w   r10, #IOCONFIG_BASE_LOW
56         movt    r10, #IOCONFIG_BASE_HIGH
57         mov.w   r8, #0xea
58         str.w   r8, [r10, #IOCONFIG_SCK_OFFSET]         /* Configure SCK pin function */
59         mov.w   r8, #0x40
60         str.w   r8, [r10, #IOCONFIG_HOLD_OFFSET]        /* Configure /HOLD pin function */
61         mov.w   r8, #0x40
62         str.w   r8, [r10, #IOCONFIG_WP_OFFSET]          /* Configure /WP pin function */
63         mov.w   r8, #0xed
64         str.w   r8, [r10, #IOCONFIG_MISO_OFFSET]        /* Configure MISO pin function */
65         mov.w   r8, #0xed
66         str.w   r8, [r10, #IOCONFIG_MOSI_OFFSET]        /* Configure MOSI pin function */
67         mov.w   r8, #0x44
68         str.w   r8, [r10, #IOCONFIG_CS_OFFSET]          /* Configure CS pin function */
69
70         mov.w   r10, #IODIR_BASE_LOW
71         movt    r10, #IODIR_BASE_HIGH
72         mov.w   r8, #0x800
73         str     r8, [r10, #IO_CS_DIR_OFFSET]            /* Set CS as output */
74         mov.w   r10, #IO_BASE_LOW
75         movt    r10, #IO_BASE_HIGH
76         mov.w   r8, #0xff
77         str.w   r8, [r10, #IO_CS_OFFSET]                        /* Set CS high */
78
79         mov.w   r10, #SSP_CLOCK_BASE_LOW
80         movt    r10, #SSP_CLOCK_BASE_HIGH
81         mov.w   r8, #0x0000
82         movt    r8, #0x0100
83         str.w   r8, [r10, #SSP_BASE_CLOCK_OFFSET]       /* Configure SSP0 base clock (use 12 MHz IRC) */
84
85         mov.w   r10, #SSP_BRANCH_CLOCK_BASE_LOW
86         movt    r10, #SSP_BRANCH_CLOCK_BASE_HIGH
87         mov.w   r8, #0x01
88         str.w   r8, [r10, #SSP_BRANCH_CLOCK_OFFSET] /* Configure (enable) SSP0 branch clock */
89
90         mov.w   r10, #SSP_BASE_LOW
91         movt    r10, #SSP_BASE_HIGH
92         mov.w   r8, #0x07
93         str.w   r8, [r10, #SSP_CR0_OFFSET]                      /* Set clock postscale */
94         mov.w   r8, #0x02
95         str.w   r8, [r10, #SSP_CPSR_OFFSET]             /* Set clock prescale */
96         str.w   r8, [r10, #SSP_CR1_OFFSET]                      /* Enable SSP in SPI mode */
97 write_enable:
98         bl              cs_down
99         mov.w   r9, #0x06               /* Send the write enable command */
100         bl              write_data
101         bl              cs_up
102
103         bl              cs_down
104         mov.w   r9, #0x05               /* Get status register */
105         bl              write_data
106         mov.w   r9, #0x00               /* Dummy data to clock in status */
107         bl              write_data
108         bl              cs_up
109
110         tst     r9, #0x02               /* If the WE bit isn't set, we have a problem. */
111         beq     error
112 erase:
113         bl              cs_down
114         mov.w   r9, r2                  /* Send the erase command */
115         bl              write_data
116 write_address:
117         lsr     r9, r0, #16     /* Send the current 24-bit write address, MSB first */
118         bl              write_data
119         lsr     r9, r0, #8
120         bl              write_data
121         mov.w   r9, r0
122         bl              write_data
123         bl              cs_up
124 wait_flash_busy:                        /* Wait for the flash to finish the previous erase */
125         bl              cs_down
126         mov.w   r9, #0x05               /* Get status register */
127         bl              write_data
128         mov.w   r9, #0x00               /* Dummy data to clock in status */
129         bl              write_data
130         bl              cs_up
131         tst     r9, #0x01               /* If it isn't done, keep waiting */
132         bne     wait_flash_busy
133
134         subs    r1, r1, #1                                      /* decrement count */
135         cbz             r1, exit                                        /* Exit if we have written everything */
136         add     r0, r3                                          /* Move the address up by the block size */
137         b               write_enable                            /* Start a new block erase */
138 write_data:                                                     /* Send/receive 1 byte of data over SSP */
139         mov.w   r10, #SSP_BASE_LOW
140         movt    r10, #SSP_BASE_HIGH
141         str.w   r9, [r10, #SSP_DATA_OFFSET]     /* Write supplied data to the SSP data reg */
142 wait_transmit:
143         ldr     r9, [r10, #SSP_SR_OFFSET]       /* Check SSP status */
144         tst     r9, #0x0010                                     /* Check if BSY bit is set */
145         bne     wait_transmit                           /* If still transmitting, keep waiting */
146         ldr     r9, [r10, #SSP_DATA_OFFSET]     /* Load received data */
147         bx              lr                                                      /* Exit subroutine */
148 cs_up:
149         mov.w   r8, #0xff
150         b               cs_write
151 cs_down:
152         mov.w   r8, #0x0000
153 cs_write:
154         mov.w   r10, #IO_BASE_LOW
155         movt    r10, #IO_BASE_HIGH
156         str.w   r8, [r10, #IO_CS_OFFSET]
157         bx              lr
158 error:
159         movs    r0, #0
160 exit:
161         bkpt    #0x00
162
163         .end