[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を選択 */
|
---|
| 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 | }
|
---|