1 | /*------------------------------------------------------------------------*/
|
---|
2 | /* FRK-RX62N: MMCv3/SDv1/SDv2 (SPI mode) Control Module */
|
---|
3 | /*------------------------------------------------------------------------*/
|
---|
4 | /*
|
---|
5 | / Copyright (C) 2014, ChaN, all right reserved.
|
---|
6 | /
|
---|
7 | / * This software is a free software and there is NO WARRANTY.
|
---|
8 | / * No restriction on use. You can use, modify and redistribute it for
|
---|
9 | / personal, non-profit or commercial products UNDER YOUR RESPONSIBILITY.
|
---|
10 | / * Redistributions of source code must retain the above copyright notice.
|
---|
11 | /
|
---|
12 | /-------------------------------------------------------------------------*/
|
---|
13 |
|
---|
14 | #include <kernel.h> /* Platform dependent include file */
|
---|
15 | #include "diskio.h" /* Common include file for ff.c and disk layer */
|
---|
16 | #include <sil.h>
|
---|
17 | #ifdef __RX
|
---|
18 | #include <rx630_ccrx/prc_rename.h>
|
---|
19 | #else
|
---|
20 | #include <rx630_msvc/prc_rename.h>
|
---|
21 | #endif
|
---|
22 | #include "target_config.h"
|
---|
23 | #include "mmc_rspi.h"
|
---|
24 | #include "kernel_cfg.h"
|
---|
25 | #include <t_syslog.h>
|
---|
26 | #include <string.h>
|
---|
27 |
|
---|
28 | static void CS_LOW()
|
---|
29 | {
|
---|
30 | sil_wrb_mem(PORTC_PODR_ADDR, sil_reb_mem(PORTC_PODR_ADDR) & ~PORT_PODR_B0_BIT); /* Set CS# low */
|
---|
31 | }
|
---|
32 |
|
---|
33 | static void CS_HIGH()
|
---|
34 | {
|
---|
35 | sil_wrb_mem(PORTC_PODR_ADDR, sil_reb_mem(PORTC_PODR_ADDR) | PORT_PODR_B0_BIT); /* Set CS# high */
|
---|
36 | }
|
---|
37 |
|
---|
38 | static bool_t WP()
|
---|
39 | {
|
---|
40 | return false;
|
---|
41 | }
|
---|
42 |
|
---|
43 | static bool_t INS()
|
---|
44 | {
|
---|
45 | return (sil_reb_mem(PORT1_PIDR_ADDR) & PORT_PIDR_B5_BIT) == 0;
|
---|
46 | }
|
---|
47 |
|
---|
48 | static void CTRL_INIT()
|
---|
49 | {
|
---|
50 | /* CS=OUT */
|
---|
51 | sil_wrb_mem(PORTC_PDR_ADDR, sil_reb_mem(PORTC_PDR_ADDR) | PORT_PDR_B0_BIT);
|
---|
52 | /* INS=IN */
|
---|
53 | sil_wrb_mem(PORT1_PDR_ADDR, sil_reb_mem(PORT1_PDR_ADDR) & ~PORT_PDR_B5_BIT);
|
---|
54 | /* SPICLK,SPIMOSI=OUT */
|
---|
55 | sil_wrb_mem(PORTC_PDR_ADDR, sil_reb_mem(PORTC_PDR_ADDR) | PORT_PDR_B5_BIT | PORT_PDR_B6_BIT);
|
---|
56 | /* CS,SPICLK,SPIMOSI=HI */
|
---|
57 | sil_wrb_mem(PORTC_PODR_ADDR, sil_reb_mem(PORTC_PODR_ADDR) | PORT_PODR_B0_BIT | PORT_PDR_B5_BIT | PORT_PDR_B6_BIT);
|
---|
58 | /* SPIMISO=IN */
|
---|
59 | sil_wrb_mem(PORTC_PDR_ADDR, sil_reb_mem(PORTC_PDR_ADDR) & ~PORT_PDR_B7_BIT);
|
---|
60 | /* SPIMISO=PULLUP */
|
---|
61 | sil_wrb_mem(PORTC_PCR_ADDR, sil_reb_mem(PORTC_PDR_ADDR) | PORT_PDR_B7_BIT);
|
---|
62 | /* CMOSðIð */
|
---|
63 | sil_wrb_mem(PORTC_ODR0_ADDR, 0x00);
|
---|
64 | /* CMOSðIð */
|
---|
65 | sil_wrb_mem(PORTC_ODR1_ADDR, 0x00);
|
---|
66 | }
|
---|
67 |
|
---|
68 | #define F_PCLK 48000000UL /* PCLK frequency (configured by SCKCR.PCK) */
|
---|
69 | #define SCLK_FAST 24000000UL /* SCLK frequency (R/W) */
|
---|
70 | #define SCLK_SLOW 375000UL /* SCLK frequency (Init) */
|
---|
71 |
|
---|
72 | static void RSPI_ATTACH()
|
---|
73 | {
|
---|
74 | /*
|
---|
75 | * W
|
---|
76 | [Xgbv@\ÌÝè(RSPI0)
|
---|
77 | */
|
---|
78 | sil_wrh_mem(SYSTEM_PRCR_ADDR, (uint16_t)0xA502); /* ÝÂ */
|
---|
79 | sil_wrw_mem(SYSTEM_MSTPCRB_ADDR,
|
---|
80 | sil_rew_mem(SYSTEM_MSTPCRB_ADDR) & ~SYSTEM_MSTPCRB_MSTPB17_BIT);
|
---|
81 | sil_wrh_mem(SYSTEM_PRCR_ADDR, (uint16_t)0xA500); /* ÝÖ~ */
|
---|
82 |
|
---|
83 | /* P15ðGPIOƵÄgp */
|
---|
84 | sil_wrb_mem(PORT1_PMR_ADDR,
|
---|
85 | sil_reb_mem(PORT1_PMR_ADDR) & ~PORT_PMR_B5_BIT);
|
---|
86 | /* PC0ðGPIOƵÄgp */
|
---|
87 | sil_wrb_mem(PORTC_PMR_ADDR,
|
---|
88 | sil_reb_mem(PORTC_PMR_ADDR) & ~PORT_PMR_B0_BIT);
|
---|
89 | /* PC5, PC6, PC7ðüÓ@\ƵÄgp */
|
---|
90 | sil_wrb_mem(PORTC_PMR_ADDR,
|
---|
91 | sil_reb_mem(PORTC_PMR_ADDR) | PORT_PMR_B5_BIT | PORT_PMR_B6_BIT | PORT_PMR_B7_BIT);
|
---|
92 |
|
---|
93 | /* «ÝveNgWX^ÌÝè PFSWErbgÖÌ«Ýð */
|
---|
94 | sil_wrb_mem(MPC_PWPR_ADDR, 0x00);
|
---|
95 | /* «ÝveNgWX^ÌÝè PxxFSWX^ÖÌ«Ýð */
|
---|
96 | sil_wrb_mem(MPC_PWPR_ADDR, 0x40);
|
---|
97 |
|
---|
98 | /* RSPCKAðIð */
|
---|
99 | sil_wrb_mem(MPC_PC5PFS_ADDR, 0x0d);
|
---|
100 | /* MOSIAðIð */
|
---|
101 | sil_wrb_mem(MPC_PC6PFS_ADDR, 0x0d);
|
---|
102 | /* MISOAðIð */
|
---|
103 | sil_wrb_mem(MPC_PC7PFS_ADDR, 0x0d);
|
---|
104 |
|
---|
105 | /* «ÝveNgWX^ÌÝè «ÝðÖ~ */
|
---|
106 | sil_wrb_mem(MPC_PWPR_ADDR, 0x80);
|
---|
107 | }
|
---|
108 |
|
---|
109 | static void FCLK_FAST()
|
---|
110 | {
|
---|
111 | /* RSPI@\ð³ø» */
|
---|
112 | sil_wrb_mem(RSPI0_SPCR_ADDR,
|
---|
113 | sil_reb_mem(RSPI0_SPCR_ADDR) & ~RSPI_SPCR_SPE_BIT);
|
---|
114 | /* rbg[gÝè */
|
---|
115 | sil_wrb_mem(RSPI0_SPBR_ADDR, F_PCLK / 2 / SCLK_FAST - 1);
|
---|
116 | /* RSPI@\ðLø» */
|
---|
117 | sil_wrb_mem(RSPI0_SPCR_ADDR,
|
---|
118 | sil_reb_mem(RSPI0_SPCR_ADDR) | RSPI_SPCR_SPE_BIT);
|
---|
119 | }
|
---|
120 |
|
---|
121 | #ifdef SIL_ENDIAN_LITTLE
|
---|
122 | #define LDDW(x) rev_endian_uint32(x) /* Little endian: swap bytes */
|
---|
123 | #else
|
---|
124 | #define LDDW(x) x /* Big endian: no swap */
|
---|
125 | #endif
|
---|
126 |
|
---|
127 |
|
---|
128 |
|
---|
129 | /*--------------------------------------------------------------------------
|
---|
130 |
|
---|
131 | Module Private Functions
|
---|
132 |
|
---|
133 | ---------------------------------------------------------------------------*/
|
---|
134 |
|
---|
135 | /* MMC/SD command */
|
---|
136 | #define CMD0 (0) /* GO_IDLE_STATE */
|
---|
137 | #define CMD1 (1) /* SEND_OP_COND (MMC) */
|
---|
138 | #define ACMD41 (0x80+41) /* SEND_OP_COND (SDC) */
|
---|
139 | #define CMD8 (8) /* SEND_IF_COND */
|
---|
140 | #define CMD9 (9) /* SEND_CSD */
|
---|
141 | #define CMD10 (10) /* SEND_CID */
|
---|
142 | #define CMD12 (12) /* STOP_TRANSMISSION */
|
---|
143 | #define ACMD13 (0x80+13) /* SD_STATUS (SDC) */
|
---|
144 | #define CMD16 (16) /* SET_BLOCKLEN */
|
---|
145 | #define CMD17 (17) /* READ_SINGLE_BLOCK */
|
---|
146 | #define CMD18 (18) /* READ_MULTIPLE_BLOCK */
|
---|
147 | #define CMD23 (23) /* SET_BLOCK_COUNT (MMC) */
|
---|
148 | #define ACMD23 (0x80+23) /* SET_WR_BLK_ERASE_COUNT (SDC) */
|
---|
149 | #define CMD24 (24) /* WRITE_BLOCK */
|
---|
150 | #define CMD25 (25) /* WRITE_MULTIPLE_BLOCK */
|
---|
151 | #define CMD32 (32) /* ERASE_ER_BLK_START */
|
---|
152 | #define CMD33 (33) /* ERASE_ER_BLK_END */
|
---|
153 | #define CMD38 (38) /* ERASE */
|
---|
154 | #define CMD55 (55) /* APP_CMD */
|
---|
155 | #define CMD58 (58) /* READ_OCR */
|
---|
156 |
|
---|
157 |
|
---|
158 |
|
---|
159 | static volatile
|
---|
160 | DSTATUS Stat = STA_NOINIT; /* Physical drive status */
|
---|
161 |
|
---|
162 | static volatile
|
---|
163 | WORD Timer1, Timer2; /* 1000Hz decrement timer stopped at zero (driven by disk_timerproc()) */
|
---|
164 |
|
---|
165 | static
|
---|
166 | BYTE CardType; /* Card type flags */
|
---|
167 |
|
---|
168 | static
|
---|
169 | BYTE CSD[16], CID[16];
|
---|
170 |
|
---|
171 | static
|
---|
172 | uint64_t CardCapacity;
|
---|
173 |
|
---|
174 | static
|
---|
175 | uint32_t CardBlockSize;
|
---|
176 |
|
---|
177 | /*-----------------------------------------------------------------------*/
|
---|
178 | /* Control SPI module */
|
---|
179 | /*-----------------------------------------------------------------------*/
|
---|
180 | /* Only these five functions are platform dependent. Any other functions */
|
---|
181 | /* are portable to different system. */
|
---|
182 |
|
---|
183 | /*---------------------------------*/
|
---|
184 | /* Enable SPI and MMC/SDC controls */
|
---|
185 | /*---------------------------------*/
|
---|
186 | static
|
---|
187 | void power_on(void)
|
---|
188 | {
|
---|
189 | /* Initialize CS/INS/WP port */
|
---|
190 | CTRL_INIT();
|
---|
191 |
|
---|
192 | /* Attach RSPI0 module to I/O pads, disable module stop */
|
---|
193 | RSPI_ATTACH();
|
---|
194 |
|
---|
195 | /* Initialize RSPI module */
|
---|
196 | sil_wrb_mem(RSPI0_SPCR_ADDR, 0); /* Stop RSPI module */
|
---|
197 | sil_wrb_mem(RSPI0_SPPCR_ADDR, 0); /* Fixed idle value, disable loop-back mode */
|
---|
198 | sil_wrb_mem(RSPI0_SPSCR_ADDR, 0); /* Disable sequence control */
|
---|
199 | sil_wrb_mem(RSPI0_SPDCR_ADDR, 0x20); /* SPLW=1 */
|
---|
200 | sil_wrh_mem(RSPI0_SPCMD0_ADDR, 0x0700); /* LSBF=0, SPB=7, BRDV=0, CPOL=0, CPHA=0 */
|
---|
201 | sil_wrb_mem(RSPI0_SPBR_ADDR, F_PCLK / 2 / SCLK_SLOW - 1); /* Bit rate */
|
---|
202 | sil_wrb_mem(RSPI0_SPCR_ADDR, 0xC9); /* Start RSPI in master mode */
|
---|
203 |
|
---|
204 | ena_int(INTNO_MMC_RSPI_SPRI);
|
---|
205 | ena_int(INTNO_MMC_RSPI_SPTI);
|
---|
206 | ena_int(INTNO_MMC_RSPI_SPII);
|
---|
207 |
|
---|
208 | sta_cyc(MMC_RSPI_CYC);
|
---|
209 | }
|
---|
210 |
|
---|
211 |
|
---|
212 | /*---------------------*/
|
---|
213 | /* Disable SPI */
|
---|
214 | /*---------------------*/
|
---|
215 | static
|
---|
216 | void power_off(void) /* Disable MMC/SDC interface */
|
---|
217 | {
|
---|
218 | stp_cyc(MMC_RSPI_CYC);
|
---|
219 |
|
---|
220 | dis_int(INTNO_MMC_RSPI_SPRI);
|
---|
221 | dis_int(INTNO_MMC_RSPI_SPTI);
|
---|
222 | dis_int(INTNO_MMC_RSPI_SPII);
|
---|
223 |
|
---|
224 | sil_wrb_mem(RSPI0_SPCR_ADDR, 0); /* Stop RSPI module */
|
---|
225 | }
|
---|
226 |
|
---|
227 |
|
---|
228 | /*---------------------*/
|
---|
229 | /* Send/Receive a byte */
|
---|
230 | /*---------------------*/
|
---|
231 | static
|
---|
232 | BYTE xchg_spi(
|
---|
233 | BYTE dat /* Data to send */
|
---|
234 | )
|
---|
235 | {
|
---|
236 | sil_wrb_mem(RSPI0_SPSR_ADDR, 0xA0);
|
---|
237 | sil_wrw_mem(RSPI0_SPDR_ADDR, dat); /* Start transmission (lower 8bits) */
|
---|
238 | /*while ((sil_reb_mem(RSPI0_SPSR_ADDR) & RSPI_SPSR_SPRF_BIT) == 0); /* Wait for end of transfer */
|
---|
239 | wai_sem(MMC_RSPI_SEMAPHORE);
|
---|
240 | return sil_rew_mem(RSPI0_SPDR_ADDR); /* Returen received byte (lower 8bits) */
|
---|
241 | }
|
---|
242 |
|
---|
243 |
|
---|
244 | /*---------------------*/
|
---|
245 | /* Send multiple bytes */
|
---|
246 | /*---------------------*/
|
---|
247 | static
|
---|
248 | void xmit_spi_multi(
|
---|
249 | const BYTE *buff, /* Pointer to the data */
|
---|
250 | UINT btx /* Number of bytes to send (multiple of 4) */
|
---|
251 | )
|
---|
252 | {
|
---|
253 | const DWORD *lp = (const DWORD*)buff;
|
---|
254 |
|
---|
255 | sil_wrh_mem(RSPI0_SPCMD0_ADDR,
|
---|
256 | (sil_reh_mem(RSPI0_SPCMD0_ADDR) & ~RSPI_SPCMD_SPB_MASK) | (3 << RSPI_SPCMD_SPB_OFFSET)); /* Set 32-bit mode */
|
---|
257 |
|
---|
258 | do {
|
---|
259 | sil_wrb_mem(RSPI0_SPSR_ADDR, 0xA0);
|
---|
260 | sil_wrw_mem(RSPI0_SPDR_ADDR, LDDW(*lp++)); /* Send four data bytes */
|
---|
261 | /*while ((sil_reb_mem(RSPI0_SPSR_ADDR) & RSPI_SPSR_SPRF_BIT) == 0); /* Wait for end of transfer */
|
---|
262 | wai_sem(MMC_RSPI_SEMAPHORE);
|
---|
263 | sil_rew_mem(RSPI0_SPDR_ADDR); /* Discard four received bytes */
|
---|
264 | } while (btx -= 4); /* Repeat until all data sent */
|
---|
265 |
|
---|
266 | sil_wrh_mem(RSPI0_SPCMD0_ADDR,
|
---|
267 | (sil_reh_mem(RSPI0_SPCMD0_ADDR) & ~RSPI_SPCMD_SPB_MASK) | (7 << RSPI_SPCMD_SPB_OFFSET)); /* Set 8-bit mode */
|
---|
268 | }
|
---|
269 |
|
---|
270 |
|
---|
271 | /*------------------------*/
|
---|
272 | /* Receive multiple bytes */
|
---|
273 | /*------------------------*/
|
---|
274 | static
|
---|
275 | void rcvr_spi_multi(
|
---|
276 | BYTE *buff, /* Pointer to data buffer */
|
---|
277 | UINT btr /* Number of bytes to receive (multiple of 4) */
|
---|
278 | )
|
---|
279 | {
|
---|
280 | DWORD *lp = (DWORD*)buff;
|
---|
281 |
|
---|
282 | sil_wrh_mem(RSPI0_SPCMD0_ADDR,
|
---|
283 | (sil_reh_mem(RSPI0_SPCMD0_ADDR) & ~RSPI_SPCMD_SPB_MASK) | (3 << RSPI_SPCMD_SPB_OFFSET)); /* Set 32-bit mode */
|
---|
284 |
|
---|
285 | do {
|
---|
286 | sil_wrb_mem(RSPI0_SPSR_ADDR, 0xA0);
|
---|
287 | sil_wrw_mem(RSPI0_SPDR_ADDR, 0xFFFFFFFF); /* Send four 0xFFs */
|
---|
288 | /*while ((sil_reb_mem(RSPI0_SPSR_ADDR) & RSPI_SPSR_SPRF_BIT) == 0); /* Wait for end of transfer */
|
---|
289 | wai_sem(MMC_RSPI_SEMAPHORE);
|
---|
290 | *lp++ = LDDW(sil_rew_mem(RSPI0_SPDR_ADDR)); /* Store four received bytes */
|
---|
291 | } while (btr -= 4); /* Repeat until all data received */
|
---|
292 |
|
---|
293 | sil_wrh_mem(RSPI0_SPCMD0_ADDR,
|
---|
294 | (sil_reh_mem(RSPI0_SPCMD0_ADDR) & ~RSPI_SPCMD_SPB_MASK) | (7 << RSPI_SPCMD_SPB_OFFSET)); /* Set 8-bit mode */
|
---|
295 | }
|
---|
296 |
|
---|
297 |
|
---|
298 |
|
---|
299 |
|
---|
300 | /*-----------------------------------------------------------------------*/
|
---|
301 | /* Wait for card ready */
|
---|
302 | /*-----------------------------------------------------------------------*/
|
---|
303 |
|
---|
304 | static
|
---|
305 | int wait_ready( /* 1:Ready, 0:Timeout */
|
---|
306 | UINT wt /* Timeout [ms] */
|
---|
307 | )
|
---|
308 | {
|
---|
309 | Timer2 = (WORD)wt;
|
---|
310 |
|
---|
311 | do {
|
---|
312 | if (xchg_spi(0xFF) == 0xFF) return 1; /* Card goes ready */
|
---|
313 | /* This loop takes a time. Insert rot_rdq() here for multitask envilonment. */
|
---|
314 | } while (Timer2); /* Wait until card goes ready or timeout */
|
---|
315 |
|
---|
316 | return 0; /* Timeout occured */
|
---|
317 | }
|
---|
318 |
|
---|
319 |
|
---|
320 |
|
---|
321 | /*-----------------------------------------------------------------------*/
|
---|
322 | /* Deselect card and release SPI */
|
---|
323 | /*-----------------------------------------------------------------------*/
|
---|
324 |
|
---|
325 | static
|
---|
326 | void deselect(void)
|
---|
327 | {
|
---|
328 | CS_HIGH(); /* Set CS# high */
|
---|
329 | xchg_spi(0xFF); /* Dummy clock (force DO hi-z for multiple slave SPI) */
|
---|
330 | }
|
---|
331 |
|
---|
332 |
|
---|
333 |
|
---|
334 | /*-----------------------------------------------------------------------*/
|
---|
335 | /* Select card and wait for ready */
|
---|
336 | /*-----------------------------------------------------------------------*/
|
---|
337 |
|
---|
338 | static
|
---|
339 | int select(void) /* 1:OK, 0:Timeout */
|
---|
340 | {
|
---|
341 | CS_LOW(); /* Set CS# low */
|
---|
342 | xchg_spi(0xFF); /* Dummy clock (force DO enabled) */
|
---|
343 |
|
---|
344 | if (wait_ready(500)) return 1; /* Wait for card ready */
|
---|
345 |
|
---|
346 | deselect();
|
---|
347 | return 0; /* Failed to select the card due to timeout */
|
---|
348 | }
|
---|
349 |
|
---|
350 |
|
---|
351 |
|
---|
352 | /*-----------------------------------------------------------------------*/
|
---|
353 | /* Receive a data packet from the MMC */
|
---|
354 | /*-----------------------------------------------------------------------*/
|
---|
355 |
|
---|
356 | static
|
---|
357 | int rcvr_datablock( /* 1:OK, 0:Error */
|
---|
358 | BYTE *buff, /* Data buffer */
|
---|
359 | UINT btr /* Data block length (byte) */
|
---|
360 | )
|
---|
361 | {
|
---|
362 | BYTE token;
|
---|
363 |
|
---|
364 |
|
---|
365 | Timer1 = 200;
|
---|
366 | do { /* Wait for DataStart token in timeout of 200ms */
|
---|
367 | token = xchg_spi(0xFF);
|
---|
368 | /* This loop will take a time. Insert rot_rdq() here for multitask envilonment. */
|
---|
369 | } while ((token == 0xFF) && Timer1);
|
---|
370 | if (token != 0xFE) return 0; /* Function fails if invalid DataStart token or timeout */
|
---|
371 |
|
---|
372 | rcvr_spi_multi(buff, btr); /* Store trailing data to the buffer */
|
---|
373 | xchg_spi(0xFF); xchg_spi(0xFF); /* Discard CRC */
|
---|
374 |
|
---|
375 | return 1; /* Function succeeded */
|
---|
376 | }
|
---|
377 |
|
---|
378 |
|
---|
379 |
|
---|
380 | /*-----------------------------------------------------------------------*/
|
---|
381 | /* Send a data packet to the MMC */
|
---|
382 | /*-----------------------------------------------------------------------*/
|
---|
383 |
|
---|
384 | #if _USE_WRITE
|
---|
385 | static
|
---|
386 | int xmit_datablock( /* 1:OK, 0:Failed */
|
---|
387 | const BYTE *buff, /* Ponter to 512 byte data to be sent */
|
---|
388 | BYTE token /* Token */
|
---|
389 | )
|
---|
390 | {
|
---|
391 | BYTE resp;
|
---|
392 |
|
---|
393 |
|
---|
394 | if (!wait_ready(500)) return 0; /* Wait for card ready */
|
---|
395 |
|
---|
396 | xchg_spi(token); /* Send token */
|
---|
397 | if (token != 0xFD) { /* Send data if token is other than StopTran */
|
---|
398 | xmit_spi_multi(buff, 512); /* Data */
|
---|
399 | xchg_spi(0xFF); xchg_spi(0xFF); /* Dummy CRC */
|
---|
400 |
|
---|
401 | resp = xchg_spi(0xFF); /* Receive data resp */
|
---|
402 | if ((resp & 0x1F) != 0x05) /* Function fails if the data packet was not accepted */
|
---|
403 | return 0;
|
---|
404 | }
|
---|
405 | return 1;
|
---|
406 | }
|
---|
407 | #endif /* _USE_WRITE */
|
---|
408 |
|
---|
409 |
|
---|
410 |
|
---|
411 | /*-----------------------------------------------------------------------*/
|
---|
412 | /* Send a command packet to the MMC */
|
---|
413 | /*-----------------------------------------------------------------------*/
|
---|
414 |
|
---|
415 | static
|
---|
416 | BYTE send_cmd( /* Return value: R1 resp (bit7==1:Failed to send) */
|
---|
417 | BYTE cmd, /* Command index */
|
---|
418 | DWORD arg /* Argument */
|
---|
419 | )
|
---|
420 | {
|
---|
421 | BYTE n, res;
|
---|
422 |
|
---|
423 |
|
---|
424 | if (cmd & 0x80) { /* Send a CMD55 prior to ACMD<n> */
|
---|
425 | cmd &= 0x7F;
|
---|
426 | res = send_cmd(CMD55, 0);
|
---|
427 | if (res > 1) return res;
|
---|
428 | }
|
---|
429 |
|
---|
430 | /* Select the card and wait for ready except to stop multiple block read */
|
---|
431 | if (cmd != CMD12) {
|
---|
432 | deselect();
|
---|
433 | if (!select()) return 0xFF;
|
---|
434 | }
|
---|
435 |
|
---|
436 | /* Send command packet */
|
---|
437 | xchg_spi(0x40 | cmd); /* Start + command index */
|
---|
438 | xchg_spi((BYTE)(arg >> 24)); /* Argument[31..24] */
|
---|
439 | xchg_spi((BYTE)(arg >> 16)); /* Argument[23..16] */
|
---|
440 | xchg_spi((BYTE)(arg >> 8)); /* Argument[15..8] */
|
---|
441 | xchg_spi((BYTE)arg); /* Argument[7..0] */
|
---|
442 | n = 0x01; /* Dummy CRC + Stop */
|
---|
443 | if (cmd == CMD0) n = 0x95; /* Valid CRC for CMD0(0) */
|
---|
444 | if (cmd == CMD8) n = 0x87; /* Valid CRC for CMD8(0x1AA) */
|
---|
445 | xchg_spi(n);
|
---|
446 |
|
---|
447 | /* Receive command resp */
|
---|
448 | if (cmd == CMD12) xchg_spi(0xFF); /* Diacard stuff byte on CMD12 */
|
---|
449 | n = 10; /* Wait for response (10 bytes max) */
|
---|
450 | do
|
---|
451 | res = xchg_spi(0xFF);
|
---|
452 | while ((res & 0x80) && --n);
|
---|
453 |
|
---|
454 | return res; /* Return received response */
|
---|
455 | }
|
---|
456 |
|
---|
457 |
|
---|
458 |
|
---|
459 | /*--------------------------------------------------------------------------
|
---|
460 |
|
---|
461 | Public Functions
|
---|
462 |
|
---|
463 | ---------------------------------------------------------------------------*/
|
---|
464 |
|
---|
465 |
|
---|
466 | /*-----------------------------------------------------------------------*/
|
---|
467 | /* Initialize disk drive */
|
---|
468 | /*-----------------------------------------------------------------------*/
|
---|
469 |
|
---|
470 | DSTATUS disk_initialize(
|
---|
471 | BYTE drv /* Physical drive number (0) */
|
---|
472 | )
|
---|
473 | {
|
---|
474 | BYTE n, cmd, ty, ocr[4];
|
---|
475 |
|
---|
476 |
|
---|
477 | if (drv) return STA_NOINIT; /* Supports only drive 0 */
|
---|
478 |
|
---|
479 | power_on(); /* Initialize RSPI */
|
---|
480 | for (n = 10; n; n--) xchg_spi(0xFF);/* Send 80 dummy clocks */
|
---|
481 |
|
---|
482 | ty = 0;
|
---|
483 | if (send_cmd(CMD0, 0) == 1) { /* Put the card SPI/Idle state */
|
---|
484 | Timer1 = 1000; /* Initialization timeout = 1 sec */
|
---|
485 | if (send_cmd(CMD8, 0x1AA) == 1) { /* SDv2? */
|
---|
486 | for (n = 0; n < 4; n++) ocr[n] = xchg_spi(0xFF); /* Get 32 bit return value of R7 resp */
|
---|
487 | if (ocr[2] == 0x01 && ocr[3] == 0xAA) { /* Is the card supports vcc of 2.7-3.6V? */
|
---|
488 | while (Timer1 && send_cmd(ACMD41, 1UL << 30)); /* Wait for end of initialization with ACMD41(HCS) */
|
---|
489 | if (Timer1 && send_cmd(CMD58, 0) == 0) { /* Check CCS bit in the OCR */
|
---|
490 | for (n = 0; n < 4; n++) ocr[n] = xchg_spi(0xFF);
|
---|
491 | ty = (ocr[0] & 0x40) ? CT_SD2 | CT_BLOCK : CT_SD2; /* Card id SDv2 */
|
---|
492 | }
|
---|
493 | }
|
---|
494 | }
|
---|
495 | else { /* Not SDv2 card */
|
---|
496 | if (send_cmd(ACMD41, 0) <= 1) { /* SDv1 or MMC? */
|
---|
497 | ty = CT_SD1; cmd = ACMD41; /* SDv1 (ACMD41(0)) */
|
---|
498 | }
|
---|
499 | else {
|
---|
500 | ty = CT_MMC; cmd = CMD1; /* MMCv3 (CMD1(0)) */
|
---|
501 | }
|
---|
502 | while (Timer1 && send_cmd(cmd, 0)); /* Wait for end of initialization */
|
---|
503 | //if (!Timer1 || send_cmd(CMD16, 512) != 0) /* Set block length: 512 */
|
---|
504 | // ty = 0;
|
---|
505 | }
|
---|
506 | if (ty) {
|
---|
507 | if (send_cmd(CMD9, 0) == 0 /* READ_CSD */
|
---|
508 | && rcvr_datablock(CSD, 16)){
|
---|
509 | /* CSD Ver.1.0 */
|
---|
510 | if ((CSD[0] & 0xC0) == 0) {
|
---|
511 | CardBlockSize = 1 << (CSD[5] & 0x0F);
|
---|
512 | CardCapacity = (((CSD[6] & 0x03) << 10) | (CSD[7] << 2) | ((CSD[8] & 0xC0) >> 6)) + 1;
|
---|
513 | CardCapacity *= (((uint64_t)1) << ((((CSD[9] & 0x03) << 1) | (CSD[10] & 0x80) >> 7) + 2));
|
---|
514 | CardCapacity *= (uint64_t)CardBlockSize;
|
---|
515 | }
|
---|
516 | else {
|
---|
517 | CardBlockSize = 512;
|
---|
518 | CardCapacity = ((uint64_t)((((CSD[7] & 0x3F) << 16) | (CSD[8] << 8) | CSD[9]) + 1)) * 512 * 1024;
|
---|
519 | }
|
---|
520 | if (send_cmd(CMD10, 0) != 0 /* READ_CID */
|
---|
521 | || !rcvr_datablock(CID, 16)) {
|
---|
522 | ty = 0;
|
---|
523 | }
|
---|
524 | }
|
---|
525 | else {
|
---|
526 | ty = 0;
|
---|
527 | }
|
---|
528 | }
|
---|
529 | }
|
---|
530 | CardType = ty; /* Card type */
|
---|
531 | deselect();
|
---|
532 |
|
---|
533 | if (ty) { /* OK */
|
---|
534 | FCLK_FAST(); /* Set fast clock */
|
---|
535 | Stat &= ~STA_NOINIT; /* Clear STA_NOINIT flag */
|
---|
536 | }
|
---|
537 | else { /* Failed */
|
---|
538 | power_off();
|
---|
539 | Stat = STA_NOINIT;
|
---|
540 | }
|
---|
541 |
|
---|
542 | return Stat;
|
---|
543 | }
|
---|
544 |
|
---|
545 |
|
---|
546 |
|
---|
547 | /*-----------------------------------------------------------------------*/
|
---|
548 | /* Get disk status */
|
---|
549 | /*-----------------------------------------------------------------------*/
|
---|
550 |
|
---|
551 | DSTATUS disk_status(
|
---|
552 | BYTE drv /* Physical drive number (0) */
|
---|
553 | )
|
---|
554 | {
|
---|
555 | if (drv) return STA_NOINIT; /* Supports only drive 0 */
|
---|
556 |
|
---|
557 | return Stat; /* Return disk status */
|
---|
558 | }
|
---|
559 |
|
---|
560 |
|
---|
561 |
|
---|
562 | /*-----------------------------------------------------------------------*/
|
---|
563 | /* Read sector(s) */
|
---|
564 | /*-----------------------------------------------------------------------*/
|
---|
565 |
|
---|
566 | DRESULT disk_read(
|
---|
567 | BYTE drv, /* Physical drive number (0) */
|
---|
568 | BYTE *buff, /* Pointer to the data buffer to store read data */
|
---|
569 | DWORD sector, /* Start sector number (LBA) */
|
---|
570 | UINT count /* Number of sectors to read (1..128) */
|
---|
571 | )
|
---|
572 | {
|
---|
573 | if (drv || !count) return RES_PARERR; /* Check parameter */
|
---|
574 | if (Stat & STA_NOINIT) return RES_NOTRDY; /* Check if drive is ready */
|
---|
575 |
|
---|
576 | if (!(CardType & CT_BLOCK)) sector *= 512; /* LBA ot BA conversion (byte addressing cards) */
|
---|
577 |
|
---|
578 | if (count == 1) { /* Single sector read */
|
---|
579 | if ((send_cmd(CMD17, sector) == 0) /* READ_SINGLE_BLOCK */
|
---|
580 | && rcvr_datablock(buff, 512))
|
---|
581 | count = 0;
|
---|
582 | }
|
---|
583 | else { /* Multiple sector read */
|
---|
584 | if (send_cmd(CMD18, sector) == 0) { /* READ_MULTIPLE_BLOCK */
|
---|
585 | do {
|
---|
586 | if (!rcvr_datablock(buff, 512)) break;
|
---|
587 | buff += 512;
|
---|
588 | } while (--count);
|
---|
589 | send_cmd(CMD12, 0); /* STOP_TRANSMISSION */
|
---|
590 | }
|
---|
591 | }
|
---|
592 | deselect();
|
---|
593 |
|
---|
594 | return count ? RES_ERROR : RES_OK; /* Return result */
|
---|
595 | }
|
---|
596 |
|
---|
597 |
|
---|
598 |
|
---|
599 | /*-----------------------------------------------------------------------*/
|
---|
600 | /* Write sector(s) */
|
---|
601 | /*-----------------------------------------------------------------------*/
|
---|
602 |
|
---|
603 | #if _USE_WRITE
|
---|
604 | DRESULT disk_write(
|
---|
605 | BYTE drv, /* Physical drive number (0) */
|
---|
606 | const BYTE *buff, /* Ponter to the data to write */
|
---|
607 | DWORD sector, /* Start sector number (LBA) */
|
---|
608 | UINT count /* Number of sectors to write (1..128) */
|
---|
609 | )
|
---|
610 | {
|
---|
611 | if (drv || !count) return RES_PARERR; /* Check parameter */
|
---|
612 | if (Stat & STA_NOINIT) return RES_NOTRDY; /* Check drive status */
|
---|
613 | if (Stat & STA_PROTECT) return RES_WRPRT; /* Check write protect */
|
---|
614 |
|
---|
615 | if (!(CardType & CT_BLOCK)) sector *= 512; /* LBA ==> BA conversion (byte addressing cards) */
|
---|
616 |
|
---|
617 | if (count == 1) { /* Single sector write */
|
---|
618 | if ((send_cmd(CMD24, sector) == 0) /* WRITE_BLOCK */
|
---|
619 | && xmit_datablock(buff, 0xFE))
|
---|
620 | count = 0;
|
---|
621 | }
|
---|
622 | else { /* Multiple sector write */
|
---|
623 | if (CardType & CT_SDC) send_cmd(ACMD23, count);
|
---|
624 | if (send_cmd(CMD25, sector) == 0) { /* WRITE_MULTIPLE_BLOCK */
|
---|
625 | do {
|
---|
626 | if (!xmit_datablock(buff, 0xFC)) break;
|
---|
627 | buff += 512;
|
---|
628 | } while (--count);
|
---|
629 | if (!xmit_datablock(0, 0xFD)) /* STOP_TRAN token */
|
---|
630 | count = 1;
|
---|
631 | }
|
---|
632 | }
|
---|
633 | deselect();
|
---|
634 |
|
---|
635 | return count ? RES_ERROR : RES_OK; /* Return result */
|
---|
636 | }
|
---|
637 | #endif /* _USE_WRITE */
|
---|
638 |
|
---|
639 |
|
---|
640 |
|
---|
641 | /*-----------------------------------------------------------------------*/
|
---|
642 | /* Miscellaneous drive controls other than data read/write */
|
---|
643 | /*-----------------------------------------------------------------------*/
|
---|
644 |
|
---|
645 | #if _USE_IOCTL
|
---|
646 | DRESULT disk_ioctl(
|
---|
647 | BYTE drv, /* Physical drive number (0) */
|
---|
648 | BYTE ctrl, /* Control command code */
|
---|
649 | void *buff /* Pointer to the conrtol data */
|
---|
650 | )
|
---|
651 | {
|
---|
652 | DRESULT res;
|
---|
653 | BYTE n, csd[16], *ptr = buff;
|
---|
654 | DWORD *dp, st, ed;
|
---|
655 |
|
---|
656 |
|
---|
657 | if (drv) return RES_PARERR; /* Check parameter */
|
---|
658 | if (Stat & STA_NOINIT) return RES_NOTRDY; /* Check if drive is ready */
|
---|
659 |
|
---|
660 | res = RES_ERROR;
|
---|
661 |
|
---|
662 | switch (ctrl) {
|
---|
663 | case CTRL_SYNC: /* Wait for end of internal write process of the drive */
|
---|
664 | if (select()) res = RES_OK;
|
---|
665 | break;
|
---|
666 |
|
---|
667 | case GET_SECTOR_SIZE:
|
---|
668 | *(WORD*)buff = 512;
|
---|
669 | res = RES_OK;
|
---|
670 | break;
|
---|
671 |
|
---|
672 | case GET_SECTOR_COUNT:
|
---|
673 | *(DWORD*)buff = CardCapacity / 512;
|
---|
674 | res = RES_OK;
|
---|
675 | break;
|
---|
676 |
|
---|
677 | case GET_BLOCK_SIZE:
|
---|
678 | *(DWORD*)buff = CardBlockSize;
|
---|
679 | res = RES_OK;
|
---|
680 | break;
|
---|
681 |
|
---|
682 | case CTRL_TRIM: /* Erase a block of sectors (used when _USE_TRIM == 1) */
|
---|
683 | if (!(CardType & CT_SDC)) break; /* Check if the card is SDC */
|
---|
684 | if (disk_ioctl(drv, MMC_GET_CSD, csd)) break; /* Get CSD */
|
---|
685 | if (!(csd[0] >> 6) && !(csd[10] & 0x40)) break; /* Check if sector erase can be applied to the card */
|
---|
686 | dp = buff; st = dp[0]; ed = dp[1]; /* Load sector block */
|
---|
687 | if (!(CardType & CT_BLOCK)) {
|
---|
688 | st *= 512; ed *= 512;
|
---|
689 | }
|
---|
690 | if (send_cmd(CMD32, st) == 0 && send_cmd(CMD33, ed) == 0 && send_cmd(CMD38, 0) == 0 && wait_ready(30000)) /* Erase sector block */
|
---|
691 | res = RES_OK;
|
---|
692 | break;
|
---|
693 |
|
---|
694 | /* Following command are not used by FatFs module */
|
---|
695 |
|
---|
696 | case MMC_GET_TYPE: /* Get MMC/SDC type (BYTE) */
|
---|
697 | *ptr = CardType;
|
---|
698 | res = RES_OK;
|
---|
699 | break;
|
---|
700 |
|
---|
701 | case MMC_GET_CSD: /* Read CSD (16 bytes) */
|
---|
702 | memcpy(ptr, CSD, sizeof(CSD));
|
---|
703 | res = RES_OK;
|
---|
704 | break;
|
---|
705 |
|
---|
706 | case MMC_GET_CID: /* Read CID (16 bytes) */
|
---|
707 | memcpy(ptr, CID, sizeof(CID));
|
---|
708 | res = RES_OK;
|
---|
709 | break;
|
---|
710 |
|
---|
711 | case MMC_GET_OCR: /* Read OCR (4 bytes) */
|
---|
712 | if (send_cmd(CMD58, 0) == 0) { /* READ_OCR */
|
---|
713 | for (n = 4; n; n--) *ptr++ = xchg_spi(0xFF);
|
---|
714 | res = RES_OK;
|
---|
715 | }
|
---|
716 | break;
|
---|
717 |
|
---|
718 | case MMC_GET_SDSTAT: /* Read SD status (64 bytes) */
|
---|
719 | if (send_cmd(ACMD13, 0) == 0) { /* SD_STATUS */
|
---|
720 | xchg_spi(0xFF);
|
---|
721 | if (rcvr_datablock(ptr, 64))
|
---|
722 | res = RES_OK;
|
---|
723 | }
|
---|
724 | break;
|
---|
725 |
|
---|
726 | default:
|
---|
727 | res = RES_PARERR;
|
---|
728 | }
|
---|
729 |
|
---|
730 | deselect();
|
---|
731 |
|
---|
732 | return res;
|
---|
733 | }
|
---|
734 | #endif /* _USE_IOCTL */
|
---|
735 |
|
---|
736 |
|
---|
737 | /*-----------------------------------------------------------------------*/
|
---|
738 | /* Device timer function */
|
---|
739 | /*-----------------------------------------------------------------------*/
|
---|
740 | /* This function must be called from system timer process
|
---|
741 | / in period of 1 ms to generate card control timing.
|
---|
742 | */
|
---|
743 |
|
---|
744 | void disk_timerproc(void)
|
---|
745 | {
|
---|
746 | WORD n;
|
---|
747 | BYTE s;
|
---|
748 |
|
---|
749 |
|
---|
750 | n = Timer1; /* 1kHz decrement timer stopped at 0 */
|
---|
751 | if (n) Timer1 = --n;
|
---|
752 | n = Timer2;
|
---|
753 | if (n) Timer2 = --n;
|
---|
754 |
|
---|
755 | s = Stat;
|
---|
756 | if (WP()) /* Write protected */
|
---|
757 | s |= STA_PROTECT;
|
---|
758 | else /* Write enabled */
|
---|
759 | s &= ~STA_PROTECT;
|
---|
760 | if (INS()) /* Card is in socket */
|
---|
761 | s &= ~STA_NODISK;
|
---|
762 | else /* Socket empty */
|
---|
763 | s |= (STA_NODISK | STA_NOINIT);
|
---|
764 | Stat = s;
|
---|
765 | }
|
---|
766 |
|
---|
767 | void mmc_rspi_spri_handler(void)
|
---|
768 | {
|
---|
769 | i_begin_int(INTNO_MMC_RSPI_SPRI);
|
---|
770 |
|
---|
771 | isig_sem(MMC_RSPI_SEMAPHORE);
|
---|
772 |
|
---|
773 | i_end_int(INTNO_MMC_RSPI_SPRI);
|
---|
774 | }
|
---|
775 |
|
---|
776 | void mmc_rspi_spti_handler(void)
|
---|
777 | {
|
---|
778 | i_begin_int(INTNO_MMC_RSPI_SPTI);
|
---|
779 |
|
---|
780 | i_end_int(INTNO_MMC_RSPI_SPTI);
|
---|
781 | }
|
---|
782 |
|
---|
783 | void mmc_rspi_spii_handler(void)
|
---|
784 | {
|
---|
785 | i_begin_int(INTNO_MMC_RSPI_SPII);
|
---|
786 |
|
---|
787 | i_end_int(INTNO_MMC_RSPI_SPII);
|
---|
788 | }
|
---|
789 |
|
---|
790 | void mmc_rspi_cychdr(intptr_t exinf)
|
---|
791 | {
|
---|
792 | disk_timerproc();
|
---|
793 | }
|
---|