1 /***************************************************************************
2 * Copyright (C) 2012 by George Harris *
3 * george@luminairecoffee.com *
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. *
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. *
15 * You should have received a copy of the GNU General Public License *
16 * along with this program; if not, write to the *
17 * Free Software Foundation, Inc., *
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. *
19 ***************************************************************************/
29 * r0 = start address, status (out)
35 #define SSP_BASE_HIGH 0x4008
36 #define SSP_BASE_LOW 0x3000
37 #define SSP_CR0_OFFSET 0x00
38 #define SSP_CR1_OFFSET 0x04
39 #define SSP_DATA_OFFSET 0x08
40 #define SSP_CPSR_OFFSET 0x10
41 #define SSP_SR_OFFSET 0x0c
43 #define SSP_CLOCK_BASE_HIGH 0x4005
44 #define SSP_CLOCK_BASE_LOW 0x0000
45 #define SSP_BRANCH_CLOCK_BASE_HIGH 0x4005
46 #define SSP_BRANCH_CLOCK_BASE_LOW 0x2000
47 #define SSP_BASE_CLOCK_OFFSET 0x94
48 #define SSP_BRANCH_CLOCK_OFFSET 0x700
50 #define IOCONFIG_BASE_HIGH 0x4008
51 #define IOCONFIG_BASE_LOW 0x6000
52 #define IOCONFIG_SCK_OFFSET 0x18c
53 #define IOCONFIG_HOLD_OFFSET 0x190
54 #define IOCONFIG_WP_OFFSET 0x194
55 #define IOCONFIG_MISO_OFFSET 0x198
56 #define IOCONFIG_MOSI_OFFSET 0x19c
57 #define IOCONFIG_CS_OFFSET 0x1a0
59 #define IO_BASE_HIGH 0x400f
60 #define IO_BASE_LOW 0x4000
61 #define IO_CS_OFFSET 0xab
62 #define IODIR_BASE_HIGH 0x400f
63 #define IODIR_BASE_LOW 0x6000
64 #define IO_CS_DIR_OFFSET 0x14
67 setup: /* Initialize SSP pins and module */
68 mov.w r10, #IOCONFIG_BASE_LOW
69 movt r10, #IOCONFIG_BASE_HIGH
71 str.w r8, [r10, #IOCONFIG_SCK_OFFSET] /* Configure SCK pin function */
73 str.w r8, [r10, #IOCONFIG_HOLD_OFFSET] /* Configure /HOLD pin function */
75 str.w r8, [r10, #IOCONFIG_WP_OFFSET] /* Configure /WP pin function */
77 str.w r8, [r10, #IOCONFIG_MISO_OFFSET] /* Configure MISO pin function */
79 str.w r8, [r10, #IOCONFIG_MOSI_OFFSET] /* Configure MOSI pin function */
81 str.w r8, [r10, #IOCONFIG_CS_OFFSET] /* Configure CS pin function */
83 mov.w r10, #IODIR_BASE_LOW
84 movt r10, #IODIR_BASE_HIGH
86 str r8, [r10, #IO_CS_DIR_OFFSET] /* Set CS as output */
87 mov.w r10, #IO_BASE_LOW
88 movt r10, #IO_BASE_HIGH
90 str.w r8, [r10, #IO_CS_OFFSET] /* Set CS high */
92 mov.w r10, #SSP_CLOCK_BASE_LOW
93 movt r10, #SSP_CLOCK_BASE_HIGH
96 str.w r8, [r10, #SSP_BASE_CLOCK_OFFSET] /* Configure SSP0 base clock (use 12 MHz IRC) */
98 mov.w r10, #SSP_BRANCH_CLOCK_BASE_LOW
99 movt r10, #SSP_BRANCH_CLOCK_BASE_HIGH
101 str.w r8, [r10, #SSP_BRANCH_CLOCK_OFFSET] /* Configure (enable) SSP0 branch clock */
103 mov.w r10, #SSP_BASE_LOW
104 movt r10, #SSP_BASE_HIGH
106 str.w r8, [r10, #SSP_CR0_OFFSET] /* Set clock postscale */
108 str.w r8, [r10, #SSP_CPSR_OFFSET] /* Set clock prescale */
109 str.w r8, [r10, #SSP_CR1_OFFSET] /* Enable SSP in SPI mode */
112 mov.w r9, #0x06 /* Send the write enable command */
117 mov.w r9, #0x05 /* Get status register */
119 mov.w r9, #0x00 /* Dummy data to clock in status */
123 tst r9, #0x02 /* If the WE bit isn't set, we have a problem. */
127 mov.w r9, r2 /* Send the erase command */
130 lsr r9, r0, #16 /* Send the current 24-bit write address, MSB first */
137 wait_flash_busy: /* Wait for the flash to finish the previous erase */
139 mov.w r9, #0x05 /* Get status register */
141 mov.w r9, #0x00 /* Dummy data to clock in status */
144 tst r9, #0x01 /* If it isn't done, keep waiting */
147 subs r1, r1, #1 /* decrement count */
148 cbz r1, exit /* Exit if we have written everything */
149 add r0, r3 /* Move the address up by the block size */
150 b write_enable /* Start a new block erase */
151 write_data: /* Send/receive 1 byte of data over SSP */
152 mov.w r10, #SSP_BASE_LOW
153 movt r10, #SSP_BASE_HIGH
154 str.w r9, [r10, #SSP_DATA_OFFSET] /* Write supplied data to the SSP data reg */
156 ldr r9, [r10, #SSP_SR_OFFSET] /* Check SSP status */
157 tst r9, #0x0010 /* Check if BSY bit is set */
158 bne wait_transmit /* If still transmitting, keep waiting */
159 ldr r9, [r10, #SSP_DATA_OFFSET] /* Load received data */
160 bx lr /* Exit subroutine */
167 mov.w r10, #IO_BASE_LOW
168 movt r10, #IO_BASE_HIGH
169 str.w r8, [r10, #IO_CS_OFFSET]