source: rtems/c/src/lib/libbsp/lm32/shared/milkymist_memcard/memcard.c @ 9f0a68c

4.115
Last change on this file since 9f0a68c was 9f0a68c, checked in by Sebastian Huber <sebastian.huber@…>, on 10/31/12 at 10:54:39

libblock: Block device transfer request API change

Add and use rtems_blkdev_request_done(). Block device transfer requests
must signal the completion status now with rtems_blkdev_request_done().
The return value of the block device IO control will be ignored for
transfer requests.

The first parameter of rtems_blkdev_request_cb is now the transfer
request structure.

Renamed rtems_blkdev_request::req_done to rtems_blkdev_request::done to
break third party drivers at compile time, otherwise this API change
would result in runtime errors.

  • Property mode set to 100644
File size: 9.2 KB
Line 
1/*  memcard.c
2 *
3 *  Milkymist memory card driver for RTEMS
4 *
5 *  The license and distribution terms for this file may be
6 *  found in the file LICENSE in this distribution or at
7 *  http://www.rtems.com/license/LICENSE.
8 *
9 *  COPYRIGHT (c) 2010, 2011 Sebastien Bourdeauducq
10 */
11
12#define RTEMS_STATUS_CHECKS_USE_PRINTK
13
14#include <rtems.h>
15#include <rtems/libio.h>
16#include <rtems/diskdevs.h>
17#include <rtems/blkdev.h>
18#include <rtems/status-checks.h>
19#include <errno.h>
20#include <bsp.h>
21#include "../include/system_conf.h"
22#include "milkymist_memcard.h"
23
24//#define MEMCARD_DEBUG
25
26#define BLOCK_SIZE 512
27
28static void memcard_start_cmd_tx(void)
29{
30  MM_WRITE(MM_MEMCARD_ENABLE, MEMCARD_ENABLE_CMD_TX);
31}
32
33static void memcard_start_cmd_rx(void)
34{
35  MM_WRITE(MM_MEMCARD_PENDING, MEMCARD_PENDING_CMD_RX);
36  MM_WRITE(MM_MEMCARD_START, MEMCARD_START_CMD_RX);
37  MM_WRITE(MM_MEMCARD_ENABLE, MEMCARD_ENABLE_CMD_RX);
38}
39
40static void memcard_start_cmd_dat_rx(void)
41{
42  MM_WRITE(MM_MEMCARD_PENDING, MEMCARD_PENDING_CMD_RX|MEMCARD_PENDING_DAT_RX);
43  MM_WRITE(MM_MEMCARD_START, MEMCARD_START_CMD_RX|MEMCARD_START_DAT_RX);
44  MM_WRITE(MM_MEMCARD_ENABLE, MEMCARD_ENABLE_CMD_RX|MEMCARD_ENABLE_DAT_RX);
45}
46
47static void memcard_send_command(unsigned char cmd, unsigned int arg)
48{
49  unsigned char packet[6];
50  int a;
51  int i;
52  unsigned char data;
53  unsigned char crc;
54
55  packet[0] = cmd | 0x40;
56  packet[1] = ((arg >> 24) & 0xff);
57  packet[2] = ((arg >> 16) & 0xff);
58  packet[3] = ((arg >> 8) & 0xff);
59  packet[4] = (arg & 0xff);
60
61  crc = 0;
62  for(a=0;a<5;a++) {
63    data = packet[a];
64    for(i=0;i<8;i++) {
65      crc <<= 1;
66      if((data & 0x80) ^ (crc & 0x80))
67        crc ^= 0x09;
68      data <<= 1;
69    }
70  }
71  crc = (crc<<1) | 1;
72
73  packet[5] = crc;
74
75#ifdef MEMCARD_DEBUG
76  printk(">> %02x %02x %02x %02x %02x %02x\n",
77    packet[0], packet[1], packet[2], packet[3], packet[4], packet[5]);
78#endif
79
80  for(i=0;i<6;i++) {
81    MM_WRITE(MM_MEMCARD_CMD, packet[i]);
82    while(MM_READ(MM_MEMCARD_PENDING) & MEMCARD_PENDING_CMD_TX);
83  }
84}
85
86static void memcard_send_dummy(void)
87{
88  MM_WRITE(MM_MEMCARD_CMD, 0xff);
89  while(MM_READ(MM_MEMCARD_PENDING) & MEMCARD_PENDING_CMD_TX);
90}
91
92static bool memcard_receive_command(unsigned char *buffer, int len)
93{
94  int i;
95  int timeout;
96
97  for(i=0;i<len;i++) {
98    timeout = 2000000;
99    while(!(MM_READ(MM_MEMCARD_PENDING) & MEMCARD_PENDING_CMD_RX)) {
100      timeout--;
101      if(timeout == 0) {
102        #ifdef MEMCARD_DEBUG
103        printk("Command receive timeout\n");
104        #endif
105        return false;
106      }
107    }
108    buffer[i] = MM_READ(MM_MEMCARD_CMD);
109    MM_WRITE(MM_MEMCARD_PENDING, MEMCARD_PENDING_CMD_RX);
110  }
111
112  while(!(MM_READ(MM_MEMCARD_PENDING) & MEMCARD_PENDING_CMD_RX));
113
114  #ifdef MEMCARD_DEBUG
115  printk("<< ");
116  for(i=0;i<len;i++)
117    printk("%02x ", buffer[i]);
118  printk("\n");
119  #endif
120
121  return true;
122}
123
124static bool memcard_receive_command_data(unsigned char *command,
125  unsigned int *data)
126{
127  int i, j;
128  int timeout;
129
130  i = 0;
131  j = 0;
132  while(j < 128) {
133    timeout = 2000000;
134    while(!(MM_READ(MM_MEMCARD_PENDING) &
135      (MEMCARD_PENDING_CMD_RX|MEMCARD_PENDING_DAT_RX))) {
136      timeout--;
137      if(timeout == 0) {
138        #ifdef MEMCARD_DEBUG
139        printk("Command receive timeout\n");
140        #endif
141        return false;
142      }
143    }
144    if(MM_READ(MM_MEMCARD_PENDING) & MEMCARD_PENDING_CMD_RX) {
145      command[i++] = MM_READ(MM_MEMCARD_CMD);
146      MM_WRITE(MM_MEMCARD_PENDING, MEMCARD_PENDING_CMD_RX);
147      if(i == 6)
148        /* disable command RX */
149        MM_WRITE(MM_MEMCARD_ENABLE, MEMCARD_ENABLE_DAT_RX);
150    }
151    if(MM_READ(MM_MEMCARD_PENDING) & MEMCARD_PENDING_DAT_RX) {
152      data[j++] = MM_READ(MM_MEMCARD_DAT);
153      MM_WRITE(MM_MEMCARD_PENDING, MEMCARD_PENDING_DAT_RX);
154    }
155  }
156
157  /* Get CRC (ignored) */
158  for(i=0;i<2;i++) {
159    while(!(MM_READ(MM_MEMCARD_PENDING) & MEMCARD_PENDING_DAT_RX));
160    #ifdef MEMCARD_DEBUG
161    printk("CRC: %08x\n", MM_READ(MM_MEMCARD_DAT));
162    #endif
163    MM_WRITE(MM_MEMCARD_PENDING, MEMCARD_PENDING_DAT_RX);
164  }
165
166  while(!(MM_READ(MM_MEMCARD_PENDING) & MEMCARD_PENDING_DAT_RX));
167
168  #ifdef MEMCARD_DEBUG
169  printk("<< %02x %02x %02x %02x %02x %02x\n",
170    command[0], command[1], command[2], command[3], command[4], command[5]);
171  #endif
172
173  //for(i=0;i<128;i++)
174  //  printk("%08x ", data[i]);
175  //printk("\n");
176
177  return true;
178}
179
180static unsigned int block_count;
181
182static int memcard_disk_block_read(rtems_blkdev_request *r)
183{
184  unsigned char b[6];
185  unsigned int i, nblocks;
186  unsigned int block;
187
188  block = RTEMS_BLKDEV_START_BLOCK(r);
189  nblocks = r->bufnum;
190
191  for(i=0;i<nblocks;i++) {
192    /* CMD17 - read block */
193    memcard_start_cmd_tx();
194    memcard_send_command(17, (block+i)*BLOCK_SIZE);
195    memcard_start_cmd_dat_rx();
196    if(!memcard_receive_command_data(b, (unsigned int *)r->bufs[i].buffer))
197      return -RTEMS_IO_ERROR;
198  }
199
200  rtems_blkdev_request_done(r, RTEMS_SUCCESSFUL);
201
202  return 0;
203}
204
205static int memcard_disk_block_write(rtems_blkdev_request *r)
206{
207  rtems_blkdev_request_done(r, RTEMS_IO_ERROR);
208
209  return 0;
210}
211
212static rtems_status_code memcard_init(void)
213{
214  unsigned char b[17];
215  unsigned int rca;
216  unsigned int block_shift;
217  unsigned int c_size;
218  unsigned int c_size_mult;
219
220  MM_WRITE(MM_MEMCARD_CLK2XDIV, 250);
221
222  /* CMD0 */
223  memcard_start_cmd_tx();
224  memcard_send_command(0, 0);
225
226  memcard_send_dummy();
227
228  /* CMD8 */
229  memcard_send_command(8, 0x1aa);
230  memcard_start_cmd_rx();
231  if(!memcard_receive_command(b, 6)) return RTEMS_IO_ERROR;
232
233  /* ACMD41 - initialize */
234  while(1) {
235    memcard_start_cmd_tx();
236    memcard_send_command(55, 0);
237    memcard_start_cmd_rx();
238    if(!memcard_receive_command(b, 6)) return RTEMS_IO_ERROR;
239    memcard_start_cmd_tx();
240    memcard_send_command(41, 0x00300000);
241    memcard_start_cmd_rx();
242    if(!memcard_receive_command(b, 6)) return RTEMS_IO_ERROR;
243    if(b[1] & 0x80) break;
244    #ifdef MEMCARD_DEBUG
245    printk("Card is busy, retrying\n");
246    #endif
247  }
248
249  /* CMD2 - get CID */
250  memcard_start_cmd_tx();
251  memcard_send_command(2, 0);
252  memcard_start_cmd_rx();
253  if(!memcard_receive_command(b, 17)) return RTEMS_IO_ERROR;
254
255  /* CMD3 - get RCA */
256  memcard_start_cmd_tx();
257  memcard_send_command(3, 0);
258  memcard_start_cmd_rx();
259  if(!memcard_receive_command(b, 6)) return RTEMS_IO_ERROR;
260  rca = (((unsigned int)b[1]) << 8)|((unsigned int)b[2]);
261  #ifdef MEMCARD_DEBUG
262  printk("RCA: %04x\n", rca);
263  #endif
264
265  /* CMD9 - get CSD */
266  memcard_start_cmd_tx();
267  memcard_send_command(9, rca << 16);
268  memcard_start_cmd_rx();
269  if(!memcard_receive_command(b, 17)) return RTEMS_IO_ERROR;
270
271  if(((b)[0] >> 6) != 0)
272    return RTEMS_IO_ERROR;
273
274  block_shift = ((unsigned int)(b)[5] & 0xf);
275  c_size = ((((unsigned int)(b)[6] & 0x3) << 10)
276    + (((unsigned int)(b)[7]) << 2)
277    + ((((unsigned int)(b)[8]) >> 6) & 0x3));
278  c_size_mult = ((((b)[9] & 0x3) << 1) + (((b)[10] >> 7) & 0x1));
279  block_count = (c_size + 1) * (1U << (c_size_mult + 2));
280
281  /* convert to 512-byte blocks for the sake of simplicity */
282  if(block_shift < 9)
283    return RTEMS_IO_ERROR;
284  block_count <<= block_shift - 9;
285
286  /* CMD7 - select card */
287  memcard_start_cmd_tx();
288  memcard_send_command(7, rca << 16);
289  memcard_start_cmd_rx();
290  if(!memcard_receive_command(b, 6)) return RTEMS_IO_ERROR;
291
292  /* ACMD6 - set bus width */
293  memcard_start_cmd_tx();
294  memcard_send_command(55, rca << 16);
295  memcard_start_cmd_rx();
296  if(!memcard_receive_command(b, 6)) return RTEMS_IO_ERROR;
297  memcard_start_cmd_tx();
298  memcard_send_command(6, 2);
299  memcard_start_cmd_rx();
300  if(!memcard_receive_command(b, 6)) return RTEMS_IO_ERROR;
301
302  MM_WRITE(MM_MEMCARD_CLK2XDIV, 3);
303
304  return RTEMS_SUCCESSFUL;
305}
306
307static int memcard_disk_ioctl(rtems_disk_device *dd, uint32_t req, void *arg)
308{
309  if (req == RTEMS_BLKIO_REQUEST) {
310    rtems_blkdev_request *r = (rtems_blkdev_request *)arg;
311    switch (r->req) {
312      case RTEMS_BLKDEV_REQ_READ:
313        return memcard_disk_block_read(r);
314      case RTEMS_BLKDEV_REQ_WRITE:
315        return memcard_disk_block_write(r);
316      default:
317        errno = EINVAL;
318        return -1;
319    }
320  } else if (req == RTEMS_BLKIO_CAPABILITIES) {
321    *(uint32_t *)arg = RTEMS_BLKDEV_CAP_MULTISECTOR_CONT;
322    return 0;
323  } else {
324    errno = EINVAL;
325    return -1;
326  }
327}
328
329static rtems_status_code memcard_disk_init(
330  rtems_device_major_number major, rtems_device_minor_number minor,
331  void *arg)
332{
333  rtems_status_code sc;
334  dev_t dev;
335
336  sc = rtems_disk_io_initialize();
337  RTEMS_CHECK_SC(sc, "Initialize RTEMS disk IO");
338
339  dev = rtems_filesystem_make_dev_t(major, 0);
340
341  sc = memcard_init();
342  RTEMS_CHECK_SC(sc, "Initialize memory card");
343
344  sc = rtems_disk_create_phys(dev, BLOCK_SIZE, block_count, memcard_disk_ioctl,
345    NULL, "/dev/memcard");
346  RTEMS_CHECK_SC(sc, "Create disk device");
347
348  return RTEMS_SUCCESSFUL;
349}
350
351
352static const rtems_driver_address_table memcard_disk_ops = {
353  .initialization_entry = memcard_disk_init,
354  .open_entry = rtems_blkdev_generic_open,
355  .close_entry = rtems_blkdev_generic_close,
356  .read_entry = rtems_blkdev_generic_read,
357  .write_entry = rtems_blkdev_generic_write,
358  .control_entry = rtems_blkdev_generic_ioctl
359};
360
361rtems_status_code memcard_register(void)
362{
363  rtems_status_code sc = RTEMS_SUCCESSFUL;
364  rtems_device_major_number major = 0;
365
366  sc = rtems_io_register_driver(0, &memcard_disk_ops, &major);
367  RTEMS_CHECK_SC(sc, "Register disk memory card driver");
368
369  return RTEMS_SUCCESSFUL;
370}
Note: See TracBrowser for help on using the repository browser.