README: note the vivado version requirements
[freedom-sifive.git] / bootrom / sdboot / sd.c
1 // See LICENSE for license details.
2 #include <stdint.h>
3
4 #include <platform.h>
5
6 #include "common.h"
7
8 #define DEBUG
9 #include "kprintf.h"
10
11 #define MAX_CORES 8
12
13 #define PAYLOAD_SIZE (16 << 11)
14
15 #define F_CLK 50000000UL
16
17 static volatile uint32_t * const spi = (void *)(SPI_CTRL_ADDR);
18
19 static inline uint8_t spi_xfer(uint8_t d)
20 {
21 int32_t r;
22
23 REG32(spi, SPI_REG_TXFIFO) = d;
24 do {
25 r = REG32(spi, SPI_REG_RXFIFO);
26 } while (r < 0);
27 return r;
28 }
29
30 static inline uint8_t sd_dummy(void)
31 {
32 return spi_xfer(0xFF);
33 }
34
35 static uint8_t sd_cmd(uint8_t cmd, uint32_t arg, uint8_t crc)
36 {
37 unsigned long n;
38 uint8_t r;
39
40 REG32(spi, SPI_REG_CSMODE) = SPI_CSMODE_HOLD;
41 sd_dummy();
42 spi_xfer(cmd);
43 spi_xfer(arg >> 24);
44 spi_xfer(arg >> 16);
45 spi_xfer(arg >> 8);
46 spi_xfer(arg);
47 spi_xfer(crc);
48
49 n = 1000;
50 do {
51 r = sd_dummy();
52 if (!(r & 0x80)) {
53 // dprintf("sd:cmd: %hx\r\n", r);
54 goto done;
55 }
56 } while (--n > 0);
57 kputs("sd_cmd: timeout");
58 done:
59 return r;
60 }
61
62 static inline void sd_cmd_end(void)
63 {
64 sd_dummy();
65 REG32(spi, SPI_REG_CSMODE) = SPI_CSMODE_AUTO;
66 }
67
68
69 static void sd_poweron(void)
70 {
71 long i;
72 REG32(spi, SPI_REG_SCKDIV) = (F_CLK / 300000UL);
73 REG32(spi, SPI_REG_CSMODE) = SPI_CSMODE_OFF;
74 for (i = 10; i > 0; i--) {
75 sd_dummy();
76 }
77 REG32(spi, SPI_REG_CSMODE) = SPI_CSMODE_AUTO;
78 }
79
80 static int sd_cmd0(void)
81 {
82 int rc;
83 dputs("CMD0");
84 rc = (sd_cmd(0x40, 0, 0x95) != 0x01);
85 sd_cmd_end();
86 return rc;
87 }
88
89 static int sd_cmd8(void)
90 {
91 int rc;
92 dputs("CMD8");
93 rc = (sd_cmd(0x48, 0x000001AA, 0x87) != 0x01);
94 sd_dummy(); /* command version; reserved */
95 sd_dummy(); /* reserved */
96 rc |= ((sd_dummy() & 0xF) != 0x1); /* voltage */
97 rc |= (sd_dummy() != 0xAA); /* check pattern */
98 sd_cmd_end();
99 return rc;
100 }
101
102 static void sd_cmd55(void)
103 {
104 sd_cmd(0x77, 0, 0x65);
105 sd_cmd_end();
106 }
107
108 static int sd_acmd41(void)
109 {
110 uint8_t r;
111 dputs("ACMD41");
112 do {
113 sd_cmd55();
114 r = sd_cmd(0x69, 0x40000000, 0x77); /* HCS = 1 */
115 } while (r == 0x01);
116 return (r != 0x00);
117 }
118
119 static int sd_cmd58(void)
120 {
121 int rc;
122 dputs("CMD58");
123 rc = (sd_cmd(0x7A, 0, 0xFD) != 0x00);
124 rc |= ((sd_dummy() & 0x80) != 0x80); /* Power up status */
125 sd_dummy();
126 sd_dummy();
127 sd_dummy();
128 sd_cmd_end();
129 return rc;
130 }
131
132 static int sd_cmd16(void)
133 {
134 int rc;
135 dputs("CMD16");
136 rc = (sd_cmd(0x50, 0x200, 0x15) != 0x00);
137 sd_cmd_end();
138 return rc;
139 }
140
141 static uint16_t crc16_round(uint16_t crc, uint8_t data) {
142 crc = (uint8_t)(crc >> 8) | (crc << 8);
143 crc ^= data;
144 crc ^= (uint8_t)(crc >> 4) & 0xf;
145 crc ^= crc << 12;
146 crc ^= (crc & 0xff) << 5;
147 return crc;
148 }
149
150 #define SPIN_SHIFT 6
151 #define SPIN_UPDATE(i) (!((i) & ((1 << SPIN_SHIFT)-1)))
152 #define SPIN_INDEX(i) (((i) >> SPIN_SHIFT) & 0x3)
153
154 static const char spinner[] = { '-', '/', '|', '\\' };
155
156 static int copy(void)
157 {
158 volatile uint8_t *p = (void *)(PAYLOAD_DEST);
159 long i = PAYLOAD_SIZE;
160 int rc = 0;
161
162 dputs("CMD18");
163 kprintf("LOADING ");
164
165 REG32(spi, SPI_REG_SCKDIV) = (F_CLK / 20000000UL);
166 if (sd_cmd(0x52, 0, 0xE1) != 0x00) {
167 sd_cmd_end();
168 return 1;
169 }
170 do {
171 uint16_t crc, crc_exp;
172 long n;
173
174 crc = 0;
175 n = 512;
176 while (sd_dummy() != 0xFE);
177 do {
178 uint8_t x = sd_dummy();
179 *p++ = x;
180 crc = crc16_round(crc, x);
181 } while (--n > 0);
182
183 crc_exp = ((uint16_t)sd_dummy() << 8);
184 crc_exp |= sd_dummy();
185
186 if (crc != crc_exp) {
187 kputs("\b- CRC mismatch ");
188 rc = 1;
189 break;
190 }
191
192 if (SPIN_UPDATE(i)) {
193 kputc('\b');
194 kputc(spinner[SPIN_INDEX(i)]);
195 }
196 } while (--i > 0);
197 sd_cmd_end();
198
199 sd_cmd(0x4C, 0, 0x01);
200 sd_cmd_end();
201 kputs("\b ");
202 return rc;
203 }
204
205 int main(void)
206 {
207 REG32(uart, UART_REG_TXCTRL) = UART_TXEN;
208
209 kputs("INIT");
210 sd_poweron();
211 if (sd_cmd0() ||
212 sd_cmd8() ||
213 sd_acmd41() ||
214 sd_cmd58() ||
215 sd_cmd16() ||
216 copy()) {
217 kputs("ERROR");
218 return 1;
219 }
220
221 kputs("BOOT");
222
223 __asm__ __volatile__ ("fence.i" : : : "memory");
224 return 0;
225 }