b84d4ebd72b597cd353957311ab953de947418c7
[fw/openocd] / contrib / loaders / flash / stmqspi / stmqspi_read.S
1 /***************************************************************************
2  *   Copyright (C) 2019 by Andreas Bolsch                                  *
3  *   andreas.bolsch@mni.thm.de                                             *
4  *                                                                         *
5  *   This program is free software; you can redistribute it and/or modify  *
6  *   it under the terms of the GNU General Public License as published by  *
7  *   the Free Software Foundation; either version 2 of the License, or     *
8  *   (at your option) any later version.                                   *
9  *                                                                         *
10  *   This program is distributed in the hope that it will be useful,       *
11  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
12  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
13  *   GNU General Public License for more details.                          *
14  *                                                                         *
15  *   You should have received a copy of the GNU General Public License     *
16  *   along with this program.  If not, see <http://www.gnu.org/licenses/>. *
17  ***************************************************************************/
18
19         .text
20         .syntax unified
21         .cpu cortex-m0
22         .thumb
23         .thumb_func
24
25 /* Params:
26  * r0 - total count (bytes), remaining bytes (out, 0 means successful)
27  * r1 - flash page size
28  * r2 - address offset into flash
29  * r3 - QSPI io_base
30  * r8 - fifo start
31  * r9 - fifo end + 1
32
33  * Clobbered:
34  * r4 - wp
35  * r5 - address of QSPI_DR
36  * r7 - tmp
37  */
38
39 #include "../../../../src/flash/nor/stmqspi.h"
40
41         .macro  qspi_abort
42         movs    r5, #(1<<SPI_ABORT)                     /* abort bit mask */
43         ldr             r7, [r3, #QSPI_CR]                      /* get QSPI_CR register */
44         orrs    r7, r7, r5                                      /* set abort bit */
45         str             r7, [r3, #QSPI_CR]                      /* store new CR register */
46         .endm
47
48         .macro  wait_busy
49 0:
50         ldr             r7, [r3, #QSPI_SR]                      /* load status */
51         lsrs    r7, r7, #(SPI_BUSY+1)           /* shift BUSY into C */
52         bcs             0b                                                      /* loop until BUSY cleared */
53         movs    r7, #(1<<SPI_TCF)                       /* TCF bitmask */
54         str             r7, [r3, #QSPI_FCR]                     /* clear TCF flag */
55         .endm
56
57 start:
58         subs    r0, r0, #1                                      /* decrement count for DLR */
59         subs    r1, r1, #1                                      /* page size mask and for DLR */
60         ldr             r4, wp                                          /* load wp */
61 start_read:
62         qspi_abort                                                      /* start in clean state */
63         movs    r5, #QSPI_DR                            /* load QSPI_DR address offset */
64         adds    r5, r5, r3                                      /* address of QSPI_DR */
65         wait_busy
66         mov             r7, r2                                          /* get current start address */
67         orrs    r7, r7, r1                                      /* end of current page */
68         subs    r7, r7, r2                                      /* count-1 to end of page */
69         cmp             r7, r0                                          /* if this count <= remaining */
70         bls             write_dlr                                       /* then read to end of page */
71         mov             r7, r0                                          /* else read all remaining */
72 write_dlr:
73         str             r7, [r3, #QSPI_DLR]                     /* size-1 in DLR register */
74         ldr             r7, ccr_page_read                       /* CCR for page read */
75         str             r7, [r3, #QSPI_CCR]                     /* initiate transfer */
76         str             r2, [r3, #QSPI_AR]                      /* store SPI start address */
77         ldr             r7, [r3, #QSPI_SR]                      /* wait for command startup */
78 read_loop:
79         ldrb    r7, [r5]                                        /* read next byte from DR */
80         strb    r7, [r4, #0]                            /* write next byte */
81         adds    r4, r4, #1                                      /* increment internal wp */
82         cmp             r4, r9                                          /* internal wp beyond end? */
83         blo             wait_fifo                                       /* if no, then ok */
84         mov             r4, r8                                          /* else wrap around */
85 wait_fifo:
86         ldr             r7, rp                                          /* get rp */
87         cmp             r7, #0                                          /* if rp equals 0 */
88         beq             exit                                            /* then abort */
89         cmp             r4, r7                                          /* check if fifo full */
90         beq             wait_fifo                                       /* wait until not full */
91         adr             r7, wp                                          /* get address of wp */
92         str             r4, [r7]                                        /* store updated wp */
93         adds    r2, r2, #1                                      /* increment address */
94         subs    r0, r0, #1                                      /* decrement (count-1) */
95         bmi             exit                                            /* stop if no data left */
96         tst             r2, r1                                          /* page end ? */
97         bne             read_loop                                       /* if not, then next byte */
98 page_end:
99         bal             start_read                                      /* then next page */
100
101 exit:
102         adds    r0, r0, #1                                      /* increment count due to the -1 */
103         qspi_abort                                                      /* to idle state */
104
105         .align  2                                                       /* align to word, bkpt is 4 words */
106         bkpt    #0                                                      /* before code end for exit_point */
107         .align  2                                                       /* align to word */
108
109         .space  4                                                       /* not used */
110         .space  4                                                       /* not used */
111         .space  4                                                       /* not used */
112         .space  4                                                       /* not used */
113
114         .space  4                                                       /* not used */
115         .space  4                                                       /* not used */
116         .space  4                                                       /* not used */
117         .space  4                                                       /* not used */
118
119         .space  4                                                       /* not used */
120 ccr_page_read:
121         .space  4                                                       /* QSPI_CCR value for read command */
122         .space  4                                                       /* not used */
123         .space  4                                                       /* not used */
124
125         .equ wp, .                                                      /* wp, uint32_t */
126         .equ rp, wp + 4                                         /* rp, uint32_t */
127         .equ buffer, rp + 4                                     /* buffer follows right away */