LPCOpen Platform for LPC18XX/43XX microcontrollers  18XX43XX
LPCOpen Platform for the NXP LPC18XX/43XX family of Microcontrollers
sdio_18xx_43xx.c
Go to the documentation of this file.
1 /*
2  * @brief LPC18xx/43xx SDIO Card driver
3  *
4  * @note
5  * Copyright(C) NXP Semiconductors, 2012
6  * All rights reserved.
7  *
8  * @par
9  * Software that is described herein is for illustrative purposes only
10  * which provides customers with programming information regarding the
11  * LPC products. This software is supplied "AS IS" without any warranties of
12  * any kind, and NXP Semiconductors and its licensor disclaim any and
13  * all warranties, express or implied, including all implied warranties of
14  * merchantability, fitness for a particular purpose and non-infringement of
15  * intellectual property rights. NXP Semiconductors assumes no responsibility
16  * or liability for the use of the software, conveys no license or rights under any
17  * patent, copyright, mask work right, or any other intellectual property rights in
18  * or to any products. NXP Semiconductors reserves the right to make changes
19  * in the software without notification. NXP Semiconductors also makes no
20  * representation or warranty that such application will be suitable for the
21  * specified use without further testing or modification.
22  *
23  * @par
24  * Permission to use, copy, modify, and distribute this software and its
25  * documentation is hereby granted, under NXP Semiconductors' and its
26  * licensor's relevant copyrights in the software, without fee, provided that it
27  * is used in conjunction with NXP Semiconductors microcontrollers. This
28  * copyright, permission, and disclaimer notice must appear in all copies of
29  * this code.
30  */
31 
32 #include "chip.h"
33 
34 /*****************************************************************************
35  * Private types/enumerations/variables
36  ****************************************************************************/
37 
38 #define SDIO_CMD_INT_MSK 0xA146 /* Interrupts to be enabled for CMD */
39 #define SDIO_DATA_INT_MSK 0xBE88 /* Interrupts to enable for data transfer */
40 #define SDIO_CARD_INT_MSK (1UL << 16) /* SDIO Card interrupt */
41 
42 static struct
43 {
44  void (*wake_evt)(LPC_SDMMC_T *pSDMMC, uint32_t event, void *arg);
45  uint32_t (*wait_evt)(LPC_SDMMC_T *pSDMMC, uint32_t event, void *arg);
46  uint32_t flag;
47  uint32_t response[4];
48  int fnum;
49  uint16_t blkSz[8]; /* Block size setting for the 8- function blocks */
50  sdif_device sdev; /* SDIO interface device structure */
52 
53 /*****************************************************************************
54  * Public types/enumerations/variables
55  ****************************************************************************/
56 
57 /*****************************************************************************
58  * Private functions
59  ****************************************************************************/
60 
61 /* Set the SDIO Card voltage level to 3v3 */
62 static int SDIO_Card_SetVoltage(LPC_SDMMC_T *pSDMMC)
63 {
64  int ret, i;
65  uint32_t val;
66 
67  ret = SDIO_Send_Command(pSDMMC, CMD5, 0);
68  if (ret) return ret;
69  val = sdioif->response[0];
70 
71  /* Number of functions supported by the card */
72  sdioif->fnum = (val >> 28) & 7;
73 
74  /* Check number of I/O functions*/
75  if(sdioif->fnum == 0) {
76  /* Number of I/O functions */
77  return SDIO_ERR_FNUM;
78  }
79 
80  /* ---- check OCR ---- */
81  if((val & SDIO_VOLT_3_3) == 0){
82  /* invalid voltage */
83  return SDIO_ERR_VOLT;
84  }
85 
86  /* ==== send CMD5 write new voltage === */
87  for(i = 0; i < 100; i++){
88  ret = SDIO_Send_Command(pSDMMC, CMD5, SDIO_VOLT_3_3);
89  if (ret) return ret;
90  val = sdioif->response[0];
91 
92  /* Is card ready ? */
93  if(val & (1UL << 31)){
94  break;
95  }
96 
97  sdioif->wait_evt(pSDMMC, SDIO_WAIT_DELAY, (void *)10);
98  }
99 
100  /* ==== Check C bit ==== */
101  if(val & (1UL << 31)){
102  return 0;
103  }
104 
105  return SDIO_ERR_VOLT; /* error end */
106 }
107 
108 /* Set SDIO Card RCA */
109 static int SDIO_CARD_SetRCA(LPC_SDMMC_T *pSDMMC)
110 {
111  int ret;
112 
113  /* ==== send CMD3 get RCA ==== */
114  ret = SDIO_Send_Command(pSDMMC, CMD3, 0);
115  if (ret) return ret;
116 
117  /* R6 response to CMD3 */
118  if((sdioif->response[0] & 0x0000e000) != 0){
119  /* COM_CRC_ERROR */
120  /* ILLEGAL_CRC_ERROR */
121  /* ERROR */
122  return SDIO_ERR_RCA;
123  }
124 
125  /* change card state */
126  sdioif->flag |= SDIO_POWER_INIT;
127 
128  /* New published RCA */
129  sdioif->response[0] &= 0xffff0000;
130 
131  /* ==== change state to Stanby State ==== */
132  return SDIO_Send_Command(pSDMMC, CMD7, sdioif->response[0]);
133 }
134 
135 /* Set the Clock speed and mode [1/4 bit] of the card */
136 static int SDIO_Card_SetMode(LPC_SDMMC_T *pSDMMC, uint32_t clk, int mode_4bit)
137 {
138  int ret;
139  uint32_t val;
140 
142 
143  if (!mode_4bit)
144  return 0;
145 
146  val = 0x02;
147  ret = SDIO_WriteRead_Direct(pSDMMC, SDIO_AREA_CIA, 0x07, &val);
148  if (ret) return ret;
149 
150  if (val & 0x02) {
152  }
153  return 0;
154 }
155 
156 /*****************************************************************************
157  * Public functions
158  ****************************************************************************/
159 /* Set the block size of a function */
160 int SDIO_Card_SetBlockSize(LPC_SDMMC_T *pSDMMC, uint32_t func, uint32_t blkSize)
161 {
162  int ret;
163  uint32_t tmp, asz;
164  if (func > sdioif->fnum)
165  return SDIO_ERR_INVFUNC;
166 
167  if (blkSize > 2048)
168  return SDIO_ERR_INVARG;
169 
170  tmp = blkSize & 0xFF;
171  ret = SDIO_WriteRead_Direct(pSDMMC, SDIO_AREA_CIA, (func << 8) + 0x10, &tmp);
172  if (ret) return ret;
173  asz = tmp;
174 
175  tmp = blkSize >> 8;
176  ret = SDIO_WriteRead_Direct(pSDMMC, SDIO_AREA_CIA, (func << 8) + 0x11, &tmp);
177  if (ret) return ret;
178  asz |= tmp << 8;
179  sdioif->blkSz[func] = asz;
180  return 0;
181 }
182 
183 /* Get the block size of a particular function */
184 uint32_t SDIO_Card_GetBlockSize(LPC_SDMMC_T *pSDMMC, uint32_t func)
185 {
186  if (func > sdioif->fnum)
187  return 0;
188 
189  return sdioif->blkSz[func];
190 }
191 
192 /* Write data to SDIO Card */
193 int SDIO_Card_WriteData(LPC_SDMMC_T *pSDMMC, uint32_t func,
194  uint32_t dest_addr, const uint8_t *src_addr,
195  uint32_t size, uint32_t flags)
196 {
197  int ret;
198  uint32_t bs = size, bsize = size;
199  uint32_t cmd = CMD53 | (1UL << 10);
200 
201  if (func > sdioif->fnum)
202  return SDIO_ERR_INVFUNC;
203 
204  if (bsize > 512 || bsize == 0)
205  return SDIO_ERR_INVARG;
206 
207  if (flags & SDIO_MODE_BLOCK) {
208  uint32_t bs = SDIO_Card_GetBlockSize(pSDMMC, func);
209  if (!bs) return SDIO_ERR_INVARG;
210  size *= bs;
211  }
212 
213  /* Set Block Size */
214  Chip_SDIF_SetBlkSize(pSDMMC, bs);
215 
216  /* set number of bytes to read */
217  Chip_SDIF_SetByteCnt(pSDMMC, size);
218 
219  sdioif->wait_evt(pSDMMC, SDIO_START_DATA, 0);
220  Chip_SDIF_DmaSetup(pSDMMC, &sdioif->sdev, (uint32_t) src_addr, size);
221 
222  ret = SDIO_Send_Command(pSDMMC, cmd, (func << 28) | (dest_addr << 9) | (bsize & 0x1FF) | (1UL << 31) | (flags & (0x3 << 26)));
223  if (ret) return ret;
224 
225  /* Check response for errors */
226  if(sdioif->response[0] & 0xcb00){
227  /* COM_CRC_ERROR */
228  /* ILLEGAL_CRC_ERROR */
229  /* ERROR */
230  /* RFU FUNCTION_NUMBER */
231  /* OUT_OF_RANGE */
232  /* Response flag error */
233  return SDIO_ERR_READWRITE;
234  }
235  return sdioif->wait_evt(pSDMMC, SDIO_WAIT_DATA, 0);
236 }
237 
238 /* Write data to SDIO Card */
239 int SDIO_Card_ReadData(LPC_SDMMC_T *pSDMMC, uint32_t func, uint8_t *dest_addr, uint32_t src_addr, uint32_t size, uint32_t flags)
240 {
241  int ret;
242  uint32_t bs = size, bsize = size;
243  uint32_t cmd = CMD53;
244 
245  if (func > sdioif->fnum)
246  return SDIO_ERR_INVFUNC;
247 
248  if (bsize > 512 || bsize == 0)
249  return SDIO_ERR_INVARG;
250 
251  if (flags & SDIO_MODE_BLOCK) {
252  bs = SDIO_Card_GetBlockSize(pSDMMC, func);
253  if (!bs) return SDIO_ERR_INVARG;
254  size *= bs;
255  }
256  /* Set the block size */
257  Chip_SDIF_SetBlkSize(pSDMMC, bs);
258 
259  /* set number of bytes to read */
260  Chip_SDIF_SetByteCnt(pSDMMC, size);
261 
262  sdioif->wait_evt(pSDMMC, SDIO_START_DATA, 0);
263  Chip_SDIF_DmaSetup(pSDMMC, &sdioif->sdev, (uint32_t) dest_addr, size);
264 
265  ret = SDIO_Send_Command(pSDMMC, cmd | (1 << 13), (func << 28) | (src_addr << 9) | (bsize & 0x1FF) | (flags & (0x3 << 26)));
266  if (ret) return ret;
267 
268  /* Check response for errors */
269  if(sdioif->response[0] & 0xcb00){
270  /* COM_CRC_ERROR */
271  /* ILLEGAL_CRC_ERROR */
272  /* ERROR */
273  /* RFU FUNCTION_NUMBER */
274  /* OUT_OF_RANGE */
275  /* Response flag error */
276  return SDIO_ERR_READWRITE;
277  }
278 
279  return sdioif->wait_evt(pSDMMC, SDIO_WAIT_DATA, 0);
280 }
281 
282 /* Enable SDIO function interrupt */
283 int SDIO_Card_EnableInt(LPC_SDMMC_T *pSDMMC, uint32_t func)
284 {
285  int ret;
286  uint32_t val;
287 
288  if (func > sdioif->fnum)
289  return SDIO_ERR_INVFUNC;
290 
291  ret = SDIO_Read_Direct(pSDMMC, SDIO_AREA_CIA, 0x04, &val);
292  if (ret) return ret;
293  val |= (1 << func) | 1;
294  ret = SDIO_Write_Direct(pSDMMC, SDIO_AREA_CIA, 0x04, val);
295  if (ret) return ret;
296  pSDMMC->INTMASK |= SDIO_CARD_INT_MSK;
297 
298  return 0;
299 }
300 
301 /* Disable SDIO function interrupt */
302 int SDIO_Card_DisableInt(LPC_SDMMC_T *pSDMMC, uint32_t func)
303 {
304  int ret;
305  uint32_t val;
306 
307  if (func > sdioif->fnum)
308  return SDIO_ERR_INVFUNC;
309 
310  ret = SDIO_Read_Direct(pSDMMC, SDIO_AREA_CIA, 0x04, &val);
311  if (ret) return ret;
312  val &= ~(1 << func);
313 
314  /* Disable master interrupt if it is the only thing enabled */
315  if (val == 1)
316  val = 0;
317  ret = SDIO_Write_Direct(pSDMMC, SDIO_AREA_CIA, 0x04, val);
318  if (ret) return ret;
319  if (!val)
320  pSDMMC->INTMASK &= ~SDIO_CARD_INT_MSK;
321 
322  return 0;
323 }
324 
325 /* Initialize the SDIO card */
326 int SDIO_Card_Init(LPC_SDMMC_T *pSDMMC, uint32_t freq)
327 {
328  int ret;
329  uint32_t val;
330 
331  /* Set Clock to 400KHz */
333  Chip_SDIF_SetCardType(pSDMMC, 0);
334 
335  sdioif->wait_evt(pSDMMC, SDIO_WAIT_DELAY, (void *) 100); /* Wait for card to wake up */
336 
337  if (sdioif->flag & SDIO_POWER_INIT) {
338  /* Write to the Reset Bit */
339  ret = SDIO_Write_Direct(pSDMMC, SDIO_AREA_CIA, 0x06, 0x08);
340  if (ret) return ret;
341  }
342 
343  /* Set Voltage level to 3v3 */
344  ret = SDIO_Card_SetVoltage(pSDMMC);
345  if (ret) return ret;
346 
347  /* Set the RCA */
348  ret = SDIO_CARD_SetRCA(pSDMMC);
349  if (ret) return ret;
350 
351  /* ==== check card capability ==== */
352  val = 0x02;
353  ret = SDIO_WriteRead_Direct(pSDMMC, SDIO_AREA_CIA, 0x13, &val);
354  if (ret) return ret;
355 
356  /* FIXME: Verify */
357  /* FIFO threshold settings for DMA, DMA burst of 4, FIFO watermark at 16 */
359 
360  /* Enable internal DMA, burst size of 4, fixed burst */
361  pSDMMC->BMOD = MCI_BMOD_DE | MCI_BMOD_PBL1 | MCI_BMOD_DSL(0);
362 
363  /* High Speed Support? */
364  if ((val & 0x03) == 3) {
365  return SDIO_Card_SetMode(pSDMMC, SDIO_CLK_HISPEED, 1);
366  }
367 
368  ret = SDIO_Read_Direct(pSDMMC, SDIO_AREA_CIA, 0x08, &val);
369  if (ret) return ret;
370 
371  /* Full Speed Support? */
372  if (val & SDIO_CCCR_LSC) {
373  return SDIO_Card_SetMode(pSDMMC, SDIO_CLK_FULLSPEED, 1);
374  }
375 
376  /* Low Speed Card */
377  return SDIO_Card_SetMode(pSDMMC, SDIO_CLK_LOWSPEED, val & SDIO_CCCR_4BLS);
378 }
379 
380 /* Write given data to register space of the CARD */
381 int SDIO_Write_Direct(LPC_SDMMC_T *pSDMMC, uint32_t func, uint32_t addr, uint32_t data)
382 {
383  int ret;
384 
385  ret = SDIO_Send_Command(pSDMMC, CMD52, (func << 28) | (addr << 9) | (data & 0xFF) | (1UL << 31));
386  if (ret) return ret;
387 
388  /* Check response for errors */
389  if(sdioif->response[0] & 0xcb00){
390  /* COM_CRC_ERROR */
391  /* ILLEGAL_CRC_ERROR */
392  /* ERROR */
393  /* RFU FUNCTION_NUMBER */
394  /* OUT_OF_RANGE */
395  /* Response flag error */
396  return SDIO_ERR_READWRITE;
397  }
398  return data != (sdioif->response[0] & 0xFF);
399 }
400 
401 /* Write given data to register, and read back the register into data */
402 int SDIO_WriteRead_Direct(LPC_SDMMC_T *pSDMMC, uint32_t func, uint32_t addr, uint32_t *data)
403 {
404  int ret;
405 
406  ret = SDIO_Send_Command(pSDMMC, CMD52, (func << 28) | (1 << 27) | (addr << 9) | ((*data) & 0xFF) | (1UL << 31));
407  if (ret) return ret;
408 
409  /* Check response for errors */
410  if(sdioif->response[0] & 0xcb00){
411  /* COM_CRC_ERROR */
412  /* ILLEGAL_CRC_ERROR */
413  /* ERROR */
414  /* RFU FUNCTION_NUMBER */
415  /* OUT_OF_RANGE */
416  /* Response flag error */
417  return SDIO_ERR_READWRITE;
418  }
419  *data = sdioif->response[0] & 0xFF;
420  return 0;
421 }
422 
423 /* Read a register from the register address space of the CARD */
424 int SDIO_Read_Direct(LPC_SDMMC_T *pSDMMC, uint32_t func, uint32_t addr, uint32_t *data)
425 {
426  int ret;
427  ret = SDIO_Send_Command(pSDMMC, CMD52, ((func & 7) << 28) | ((addr & 0x1FFFF) << 9));
428  if (ret) return ret;
429 
430  /* Check response for errors */
431  if(sdioif->response[0] & 0xcb00){
432  /* COM_CRC_ERROR */
433  /* ILLEGAL_CRC_ERROR */
434  /* ERROR */
435  /* RFU FUNCTION_NUMBER */
436  /* OUT_OF_RANGE */
437  /* Response flag error */
438  return SDIO_ERR_READWRITE;
439  }
440  *data = sdioif->response[0] & 0xFF;
441  return 0;
442 }
443 
444 /* Set up the wait and wake call-back functions */
446  void (*wake_evt)(LPC_SDMMC_T *pSDMMC, uint32_t event, void *arg),
447  uint32_t (*wait_evt)(LPC_SDMMC_T *pSDMMC, uint32_t event, void *arg))
448 {
449  sdioif->wake_evt = wake_evt;
450  sdioif->wait_evt = wait_evt;
451 }
452 
453 /* Send and SD Command to the SDIO Card */
454 uint32_t SDIO_Send_Command(LPC_SDMMC_T *pSDMMC, uint32_t cmd, uint32_t arg)
455 {
456  uint32_t ret, ival;
457  uint32_t imsk = pSDMMC->INTMASK;
458  ret = sdioif->wait_evt(pSDMMC, SDIO_START_COMMAND, (void *)(cmd & 0x3F));
459  ival = SDIO_CMD_INT_MSK & ~ret;
460 
461  /* Set data interrupts for data commands */
462  if (cmd & SDIO_CMD_DATA) {
463  ival |= SDIO_DATA_INT_MSK;
464  imsk |= SDIO_DATA_INT_MSK;
465  }
466 
467  Chip_SDIF_SetIntMask(pSDMMC, ival);
468  Chip_SDIF_SendCmd(pSDMMC, cmd, arg);
469  ret = sdioif->wait_evt(pSDMMC, SDIO_WAIT_COMMAND, 0);
470  if (!ret && (cmd & SDIO_CMD_RESP_R1)) {
471  Chip_SDIF_GetResponse(pSDMMC, &sdioif->response[0]);
472  }
473 
474  Chip_SDIF_SetIntMask(pSDMMC, imsk);
475  return ret;
476 }
477 
478 /* SDIO Card interrupt handler */
480 {
481  uint32_t status = pSDMMC->MINTSTS;
482  uint32_t iclr = 0;
483 
484  /* Card Detected */
485  if (status & 1) {
486  sdioif->wake_evt(pSDMMC, SDIO_CARD_DETECT, 0);
487  iclr = 1;
488  }
489 
490  /* Command event error */
491  if (status & (SDIO_CMD_INT_MSK & ~4)) {
492  sdioif->wake_evt(pSDMMC, SDIO_CMD_ERR, (void *) (status & (SDIO_CMD_INT_MSK & ~4)));
493  iclr |= status & SDIO_CMD_INT_MSK;
494  } else if (status & 4) {
495  /* Command event done */
496  sdioif->wake_evt(pSDMMC, SDIO_CMD_DONE, (void *) status);
497  iclr |= status & SDIO_CMD_INT_MSK;
498  }
499 
500  /* Command event error */
501  if (status & (SDIO_DATA_INT_MSK & ~8)) {
502  sdioif->wake_evt(pSDMMC, SDIO_DATA_ERR, (void *) (status & (SDIO_DATA_INT_MSK & ~8)));
503  iclr |= (status & SDIO_DATA_INT_MSK) | (3 << 4);
504  } else if (status & 8) {
505  /* Command event done */
506  sdioif->wake_evt(pSDMMC, SDIO_DATA_DONE, (void *) status);
507  iclr |= (status & SDIO_DATA_INT_MSK) | (3 << 4);
508  }
509 
510  /* Handle Card interrupt */
511  if (status & SDIO_CARD_INT_MSK) {
512  sdioif->wake_evt(pSDMMC, SDIO_CARD_INT, 0);
513  iclr |= status & SDIO_CARD_INT_MSK;
514  }
515 
516  /* Clear the interrupts */
517  pSDMMC->RINTSTS = iclr;
518 }