[164] | 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 | }
|
---|