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