bfb2662ca36e64e205f476073ab4da1f3518ca1a
[fw/openocd] / contrib / loaders / flash / stmqspi / stmqspi_crc32.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), crc32 (out)
27  * r1 - flash page size
28  * r2 - address offset into flash
29  * r3 - QSPI io_base
30
31  * Clobbered:
32  * r4 - rp
33  * r5 - address of QSPI_DR
34  * r7 - tmp
35  */
36
37 #include "../../../../src/flash/nor/stmqspi.h"
38
39         .macro  qspi_abort
40         movs    r5, #(1<<SPI_ABORT)                     /* abort bit mask */
41         ldr             r7, [r3, #QSPI_CR]                      /* get QSPI_CR register */
42         orrs    r7, r7, r5                                      /* set abort bit */
43         str             r7, [r3, #QSPI_CR]                      /* store new CR register */
44         .endm
45
46         .macro  wait_busy
47 0:
48         ldr             r7, [r3, #QSPI_SR]                      /* load status */
49         lsrs    r7, r7, #(SPI_BUSY+1)           /* shift BUSY into C */
50         bcs             0b                                                      /* loop until BUSY cleared */
51         movs    r7, #(1<<SPI_TCF)                       /* TCF bitmask */
52         str             r7, [r3, #QSPI_FCR]                     /* clear TCF flag */
53         .endm
54
55 start:
56         subs    r0, r0, #1                                      /* decrement count for DLR */
57         subs    r1, r1, #1                                      /* page size mask and for DLR */
58         movs    r4, #0x00                                       /* initialize crc */
59         mvns    r4, r4                                          /* to 0xFFFFFFFF */
60 start_read:
61         qspi_abort                                                      /* start in clean state */
62         movs    r5, #QSPI_DR                            /* load QSPI_DR address offset */
63         adds    r5, r5, r3                                      /* address of QSPI_DR */
64         wait_busy
65         mov             r7, r2                                          /* get current start address */
66         orrs    r7, r7, r1                                      /* end of current page */
67         subs    r7, r7, r2                                      /* count-1 to end of page */
68         cmp             r7, r0                                          /* if this count <= remaining */
69         bls             write_dlr                                       /* then read to end of page */
70         mov             r7, r0                                          /* else read all remaining */
71 write_dlr:
72         str             r7, [r3, #QSPI_DLR]                     /* size-1 in DLR register */
73         ldr             r7, ccr_page_read                       /* CCR for page read */
74         str             r7, [r3, #QSPI_CCR]                     /* initiate transfer */
75         str             r2, [r3, #QSPI_AR]                      /* store SPI start address */
76         ldr             r7, [r3, #QSPI_SR]                      /* wait for command startup */
77         ldr             r6, =0x04C11DB7                         /* CRC32 polynomial */
78 read_loop:
79         ldrb    r7, [r5]                                        /* read next byte from DR */
80         lsls    r7, r7, #24                                     /* shift into msb */
81         eors    r4, r4, r7
82         .rept   8                                                       /* unrolled bit loop */
83         asrs    r7, r4, #31                                     /* copy bit 31 into bits 0 to 31 */
84         ands    r7, r7, r6                                      /* r7 neg. -> CRC32XOR, pos. -> 0x0 */
85         lsls    r4, r4, #1                                      /* shift result */
86         eors    r4, r4, r7                                      /* eor by CRC32XOR or 0x0 */
87         .endr
88         adds    r2, r2, #1                                      /* increment address */
89         subs    r0, r0, #1                                      /* decrement (count-1) */
90         bmi             exit                                            /* stop if no data left */
91         tst             r2, r1                                          /* page end ? */
92         bne             read_loop                                       /* if not, then next byte */
93 page_end:
94         bal             start_read                                      /* then next page */
95         .pool
96
97 exit:
98         mvns    r0, r4                                          /* invert to get final result */
99         qspi_abort                                                      /* to idle state */
100         .align  2                                                       /* align to word, bkpt is 4 words */
101         bkpt    #0                                                      /* before code end for exit_point */
102         .align  2                                                       /* align to word */
103
104         .space  4                                                       /* not used */
105 ccr_page_read:
106         .space  4                                                       /* QSPI_CCR value for read command */
107         .space  4                                                       /* not used */
108         .space  4                                                       /* not used */