Back to home page

LXR

 
 

    


File indexing completed on 2025-05-11 08:23:44

0001 /*  memcard.c
0002  *
0003  *  Milkymist memory card driver for RTEMS
0004  *
0005  *  The license and distribution terms for this file may be
0006  *  found in the file LICENSE in this distribution or at
0007  *  http://www.rtems.org/license/LICENSE.
0008  *
0009  *  COPYRIGHT (c) 2010, 2011 Sebastien Bourdeauducq
0010  */
0011 
0012 #define RTEMS_STATUS_CHECKS_USE_PRINTK
0013 
0014 #include <rtems.h>
0015 #include <rtems/libio.h>
0016 #include <rtems/blkdev.h>
0017 #include <rtems/status-checks.h>
0018 #include <errno.h>
0019 #include <bsp.h>
0020 #include "../include/system_conf.h"
0021 #include <bsp/milkymist_memcard.h>
0022 
0023 //#define MEMCARD_DEBUG
0024 
0025 #define BLOCK_SIZE 512
0026 
0027 static void memcard_start_cmd_tx(void)
0028 {
0029   MM_WRITE(MM_MEMCARD_ENABLE, MEMCARD_ENABLE_CMD_TX);
0030 }
0031 
0032 static void memcard_start_cmd_rx(void)
0033 {
0034   MM_WRITE(MM_MEMCARD_PENDING, MEMCARD_PENDING_CMD_RX);
0035   MM_WRITE(MM_MEMCARD_START, MEMCARD_START_CMD_RX);
0036   MM_WRITE(MM_MEMCARD_ENABLE, MEMCARD_ENABLE_CMD_RX);
0037 }
0038 
0039 static void memcard_start_cmd_dat_rx(void)
0040 {
0041   MM_WRITE(MM_MEMCARD_PENDING, MEMCARD_PENDING_CMD_RX|MEMCARD_PENDING_DAT_RX);
0042   MM_WRITE(MM_MEMCARD_START, MEMCARD_START_CMD_RX|MEMCARD_START_DAT_RX);
0043   MM_WRITE(MM_MEMCARD_ENABLE, MEMCARD_ENABLE_CMD_RX|MEMCARD_ENABLE_DAT_RX);
0044 }
0045 
0046 static void memcard_send_command(unsigned char cmd, unsigned int arg)
0047 {
0048   unsigned char packet[6];
0049   int a;
0050   int i;
0051   unsigned char data;
0052   unsigned char crc;
0053 
0054   packet[0] = cmd | 0x40;
0055   packet[1] = ((arg >> 24) & 0xff);
0056   packet[2] = ((arg >> 16) & 0xff);
0057   packet[3] = ((arg >> 8) & 0xff);
0058   packet[4] = (arg & 0xff);
0059 
0060   crc = 0;
0061   for(a=0;a<5;a++) {
0062     data = packet[a];
0063     for(i=0;i<8;i++) {
0064       crc <<= 1;
0065       if((data & 0x80) ^ (crc & 0x80))
0066         crc ^= 0x09;
0067       data <<= 1;
0068     }
0069   }
0070   crc = (crc<<1) | 1;
0071 
0072   packet[5] = crc;
0073 
0074 #ifdef MEMCARD_DEBUG
0075   printk(">> %02x %02x %02x %02x %02x %02x\n",
0076     packet[0], packet[1], packet[2], packet[3], packet[4], packet[5]);
0077 #endif
0078 
0079   for(i=0;i<6;i++) {
0080     MM_WRITE(MM_MEMCARD_CMD, packet[i]);
0081     while(MM_READ(MM_MEMCARD_PENDING) & MEMCARD_PENDING_CMD_TX);
0082   }
0083 }
0084 
0085 static void memcard_send_dummy(void)
0086 {
0087   MM_WRITE(MM_MEMCARD_CMD, 0xff);
0088   while(MM_READ(MM_MEMCARD_PENDING) & MEMCARD_PENDING_CMD_TX);
0089 }
0090 
0091 static bool memcard_receive_command(unsigned char *buffer, int len)
0092 {
0093   int i;
0094   int timeout;
0095 
0096   for(i=0;i<len;i++) {
0097     timeout = 2000000;
0098     while(!(MM_READ(MM_MEMCARD_PENDING) & MEMCARD_PENDING_CMD_RX)) {
0099       timeout--;
0100       if(timeout == 0) {
0101         #ifdef MEMCARD_DEBUG
0102         printk("Command receive timeout\n");
0103         #endif
0104         return false;
0105       }
0106     }
0107     buffer[i] = MM_READ(MM_MEMCARD_CMD);
0108     MM_WRITE(MM_MEMCARD_PENDING, MEMCARD_PENDING_CMD_RX);
0109   }
0110 
0111   while(!(MM_READ(MM_MEMCARD_PENDING) & MEMCARD_PENDING_CMD_RX));
0112 
0113   #ifdef MEMCARD_DEBUG
0114   printk("<< ");
0115   for(i=0;i<len;i++)
0116     printk("%02x ", buffer[i]);
0117   printk("\n");
0118   #endif
0119 
0120   return true;
0121 }
0122 
0123 static bool memcard_receive_command_data(unsigned char *command,
0124   unsigned int *data)
0125 {
0126   int i, j;
0127   int timeout;
0128 
0129   i = 0;
0130   j = 0;
0131   while(j < 128) {
0132     timeout = 2000000;
0133     while(!(MM_READ(MM_MEMCARD_PENDING) &
0134       (MEMCARD_PENDING_CMD_RX|MEMCARD_PENDING_DAT_RX))) {
0135       timeout--;
0136       if(timeout == 0) {
0137         #ifdef MEMCARD_DEBUG
0138         printk("Command receive timeout\n");
0139         #endif
0140         return false;
0141       }
0142     }
0143     if(MM_READ(MM_MEMCARD_PENDING) & MEMCARD_PENDING_CMD_RX) {
0144       command[i++] = MM_READ(MM_MEMCARD_CMD);
0145       MM_WRITE(MM_MEMCARD_PENDING, MEMCARD_PENDING_CMD_RX);
0146       if(i == 6)
0147         /* disable command RX */
0148         MM_WRITE(MM_MEMCARD_ENABLE, MEMCARD_ENABLE_DAT_RX);
0149     }
0150     if(MM_READ(MM_MEMCARD_PENDING) & MEMCARD_PENDING_DAT_RX) {
0151       data[j++] = MM_READ(MM_MEMCARD_DAT);
0152       MM_WRITE(MM_MEMCARD_PENDING, MEMCARD_PENDING_DAT_RX);
0153     }
0154   }
0155 
0156   /* Get CRC (ignored) */
0157   for(i=0;i<2;i++) {
0158     while(!(MM_READ(MM_MEMCARD_PENDING) & MEMCARD_PENDING_DAT_RX));
0159     #ifdef MEMCARD_DEBUG
0160     printk("CRC: %08x\n", MM_READ(MM_MEMCARD_DAT));
0161     #endif
0162     MM_WRITE(MM_MEMCARD_PENDING, MEMCARD_PENDING_DAT_RX);
0163   }
0164 
0165   while(!(MM_READ(MM_MEMCARD_PENDING) & MEMCARD_PENDING_DAT_RX));
0166 
0167   #ifdef MEMCARD_DEBUG
0168   printk("<< %02x %02x %02x %02x %02x %02x\n",
0169     command[0], command[1], command[2], command[3], command[4], command[5]);
0170   #endif
0171 
0172   //for(i=0;i<128;i++)
0173   //  printk("%08x ", data[i]);
0174   //printk("\n");
0175 
0176   return true;
0177 }
0178 
0179 static unsigned int block_count;
0180 
0181 static int memcard_disk_block_read(rtems_blkdev_request *r)
0182 {
0183   unsigned char b[6];
0184   unsigned int i, nblocks;
0185   unsigned int block;
0186 
0187   block = RTEMS_BLKDEV_START_BLOCK(r);
0188   nblocks = r->bufnum;
0189 
0190   for(i=0;i<nblocks;i++) {
0191     /* CMD17 - read block */
0192     memcard_start_cmd_tx();
0193     memcard_send_command(17, (block+i)*BLOCK_SIZE);
0194     memcard_start_cmd_dat_rx();
0195     if(!memcard_receive_command_data(b, (unsigned int *)r->bufs[i].buffer))
0196       return -RTEMS_IO_ERROR;
0197   }
0198 
0199   rtems_blkdev_request_done(r, RTEMS_SUCCESSFUL);
0200 
0201   return 0;
0202 }
0203 
0204 static int memcard_disk_block_write(rtems_blkdev_request *r)
0205 {
0206   rtems_blkdev_request_done(r, RTEMS_IO_ERROR);
0207 
0208   return 0;
0209 }
0210 
0211 static rtems_status_code memcard_init(void)
0212 {
0213   unsigned char b[17];
0214   unsigned int rca;
0215   unsigned int block_shift;
0216   unsigned int c_size;
0217   unsigned int c_size_mult;
0218 
0219   MM_WRITE(MM_MEMCARD_CLK2XDIV, 250);
0220 
0221   /* CMD0 */
0222   memcard_start_cmd_tx();
0223   memcard_send_command(0, 0);
0224 
0225   memcard_send_dummy();
0226 
0227   /* CMD8 */
0228   memcard_send_command(8, 0x1aa);
0229   memcard_start_cmd_rx();
0230   if(!memcard_receive_command(b, 6)) return RTEMS_IO_ERROR;
0231 
0232   /* ACMD41 - initialize */
0233   while(1) {
0234     memcard_start_cmd_tx();
0235     memcard_send_command(55, 0);
0236     memcard_start_cmd_rx();
0237     if(!memcard_receive_command(b, 6)) return RTEMS_IO_ERROR;
0238     memcard_start_cmd_tx();
0239     memcard_send_command(41, 0x00300000);
0240     memcard_start_cmd_rx();
0241     if(!memcard_receive_command(b, 6)) return RTEMS_IO_ERROR;
0242     if(b[1] & 0x80) break;
0243     #ifdef MEMCARD_DEBUG
0244     printk("Card is busy, retrying\n");
0245     #endif
0246   }
0247 
0248   /* CMD2 - get CID */
0249   memcard_start_cmd_tx();
0250   memcard_send_command(2, 0);
0251   memcard_start_cmd_rx();
0252   if(!memcard_receive_command(b, 17)) return RTEMS_IO_ERROR;
0253 
0254   /* CMD3 - get RCA */
0255   memcard_start_cmd_tx();
0256   memcard_send_command(3, 0);
0257   memcard_start_cmd_rx();
0258   if(!memcard_receive_command(b, 6)) return RTEMS_IO_ERROR;
0259   rca = (((unsigned int)b[1]) << 8)|((unsigned int)b[2]);
0260   #ifdef MEMCARD_DEBUG
0261   printk("RCA: %04x\n", rca);
0262   #endif
0263 
0264   /* CMD9 - get CSD */
0265   memcard_start_cmd_tx();
0266   memcard_send_command(9, rca << 16);
0267   memcard_start_cmd_rx();
0268   if(!memcard_receive_command(b, 17)) return RTEMS_IO_ERROR;
0269 
0270   if(((b)[0] >> 6) != 0)
0271     return RTEMS_IO_ERROR;
0272 
0273   block_shift = ((unsigned int)(b)[5] & 0xf);
0274   c_size = ((((unsigned int)(b)[6] & 0x3) << 10)
0275     + (((unsigned int)(b)[7]) << 2)
0276     + ((((unsigned int)(b)[8]) >> 6) & 0x3));
0277   c_size_mult = ((((b)[9] & 0x3) << 1) + (((b)[10] >> 7) & 0x1));
0278   block_count = (c_size + 1) * (1U << (c_size_mult + 2));
0279 
0280   /* convert to 512-byte blocks for the sake of simplicity */
0281   if(block_shift < 9)
0282     return RTEMS_IO_ERROR;
0283   block_count <<= block_shift - 9;
0284 
0285   /* CMD7 - select card */
0286   memcard_start_cmd_tx();
0287   memcard_send_command(7, rca << 16);
0288   memcard_start_cmd_rx();
0289   if(!memcard_receive_command(b, 6)) return RTEMS_IO_ERROR;
0290 
0291   /* ACMD6 - set bus width */
0292   memcard_start_cmd_tx();
0293   memcard_send_command(55, rca << 16);
0294   memcard_start_cmd_rx();
0295   if(!memcard_receive_command(b, 6)) return RTEMS_IO_ERROR;
0296   memcard_start_cmd_tx();
0297   memcard_send_command(6, 2);
0298   memcard_start_cmd_rx();
0299   if(!memcard_receive_command(b, 6)) return RTEMS_IO_ERROR;
0300 
0301   MM_WRITE(MM_MEMCARD_CLK2XDIV, 3);
0302 
0303   return RTEMS_SUCCESSFUL;
0304 }
0305 
0306 static int memcard_disk_ioctl(rtems_disk_device *dd, uint32_t req, void *arg)
0307 {
0308   if (req == RTEMS_BLKIO_REQUEST) {
0309     rtems_blkdev_request *r = (rtems_blkdev_request *)arg;
0310     switch (r->req) {
0311       case RTEMS_BLKDEV_REQ_READ:
0312         return memcard_disk_block_read(r);
0313       case RTEMS_BLKDEV_REQ_WRITE:
0314         return memcard_disk_block_write(r);
0315       default:
0316         errno = EINVAL;
0317         return -1;
0318     }
0319   } else if (req == RTEMS_BLKIO_CAPABILITIES) {
0320     *(uint32_t *)arg = RTEMS_BLKDEV_CAP_MULTISECTOR_CONT;
0321     return 0;
0322   } else {
0323     errno = EINVAL;
0324     return -1;
0325   }
0326 }
0327 
0328 rtems_status_code memcard_register(void)
0329 {
0330   rtems_status_code sc;
0331 
0332   sc = memcard_init();
0333   RTEMS_CHECK_SC(sc, "Initialize memory card");
0334 
0335   sc = rtems_blkdev_create("/dev/memcard", BLOCK_SIZE, block_count,
0336     memcard_disk_ioctl, NULL);
0337   RTEMS_CHECK_SC(sc, "Create disk device");
0338 
0339   return RTEMS_SUCCESSFUL;
0340 }