source: rtems/c/src/lib/libbsp/arm/gp32/smc/smc.c @ 0afac6a

4.115
Last change on this file since 0afac6a was 3c743901, checked in by Joel Sherrill <joel.sherrill@…>, on Oct 13, 2014 at 6:20:35 PM

arm/gp32/smc/smc.c: Remove unused sm_ECCEncode() and sm_status()

  • Property mode set to 100644
File size: 8.9 KB
Line 
1/*
2 * s3c2400 smc disk block device implementation
3 *
4 * Squidge's SMC Low-level access routines.
5 * Inspired and derived from routines provided by Samsung Electronics
6 *  M/M R&D Center & FireFly.
7 */
8
9#include <rtems.h>
10#include <rtems/libio.h>
11#include <errno.h>
12#include <stdlib.h>
13#include <stdio.h>
14#include <string.h>
15#include <inttypes.h>
16
17#include "rtems/blkdev.h"
18#include "rtems/diskdevs.h"
19#include "smc.h"
20#include <rtems/bspIo.h>
21#include <s3c24xx.h>
22
23#define SMC_DEVICE_NAME "/dev/smc"
24#define SMC_SAMSUNG_ID    0xEC
25#define SMC_TOSHIBA_ID    0x98
26
27#define SMC_16MB  0x73
28#define SMC_32MB  0x75
29#define SMC_64MB  0x76
30#define SMC_128MB  0x79
31
32#define LBA_UNUSED      0x80000000
33#define LBA_RESERVED    0x80000001
34
35#define BLOCK_UNUSED    0x80000000
36#define BLOCK_RESERVED  0x80000001
37
38/* SmartMedia Command */
39#define SEQ_DATA_INPUT_CMD   0x80
40#define READ1_CMD            0x00
41#define READ1_1_CMD          0x01
42#define READ2_CMD            0x50
43#define READ_ID_CMD          0x90
44#define RESET_CMD            0xFF
45#define PAGE_PROGRAM_CMD     0x10
46#define BLOCK_ERASE_CMD      0x60
47#define BLOCK_ERASE_CFM_CMD  0xD0
48#define READ_STATUS_CMD      0x70
49#define RESET_PTR_CMD        0x00
50
51
52/* Internal SMC disk descriptor */
53struct SMC_INFO {
54  uint8_t  id[3];
55  uint32_t bytes_per_page;
56  uint32_t pages_per_block;
57  uint32_t blocks;
58  uint32_t mb;
59};
60
61/* Ths S3c2410 uses a different register map */
62#ifdef CPU_S3C2410
63#define rPBDAT rGPBDAT
64#define rPBCON rGPBCON
65#define rPDDAT rGPDDAT
66#define rPEDAT rGPEDAT
67#endif
68
69
70static struct SMC_INFO smc_info;
71
72uint32_t smc_l2p[0x2000];
73uint32_t smc_p2l[0x2000];
74
75#define sm_busy() while (!(rPDDAT & 0x200))
76#define sm_chip_en() rPDDAT &= (~0x80)
77#define sm_chip_dis() rPDDAT |= 0x80
78#define sm_cle_en() rPEDAT |= 0x20
79#define sm_cle_dis() rPEDAT &= (~0x20)
80#define sm_ale_en() rPEDAT |= 0x10
81#define sm_ale_dis() rPEDAT &= (~0x10)
82#define sm_wp_en() rPDDAT &= (~0x40)
83#define sm_wp_dis() rPDDAT |= 0x40
84#define sm_read_en() rPBCON &= 0xFFFF0000
85#define sm_read_dis() rPBCON = (rPBCON & 0xFFFF0000) | 0x5555
86#define sm_write_en() sm_read_dis()
87#define sm_write_dis() sm_read_en()
88
89static void sm_write( uint8_t data)
90{
91  rPBDAT = (rPBDAT & 0xFF00) | data;
92  rPEDAT &= (~0x08);
93  rPEDAT |= 0x08;
94}
95
96static uint8_t sm_read(void)
97{
98  uint8_t data;
99
100  rPDDAT &= (~0x100);
101  data = rPBDAT & 0xFF;
102  rPDDAT |= 0x100;
103  return data;
104}
105
106static void smc_read_id( uint8_t* buf, uint32_t length)
107{
108  uint32_t i;
109
110  sm_chip_en();
111
112  sm_cle_en();
113  sm_write_en();
114  sm_write(READ_ID_CMD);
115  sm_write_dis();
116  sm_cle_dis();
117
118  sm_ale_en();
119  sm_write_en();
120  sm_write( 0);
121  sm_write_dis();
122  sm_ale_dis();
123
124  sm_read_en();
125  for (i=0;i<length;i++) *(buf+i) = sm_read();
126  sm_read_dis();
127
128  sm_chip_dis();
129}
130
131/* read an entire logical page of 512 bytes.*/
132static uint8_t smc_read_page (uint32_t lpage, uint8_t* buf)
133{
134  uint32_t block, page, i;
135
136  /* convert logical block to physical block
137     and then convert into page suitable for read1 command...
138  */
139  block = lpage >> 5;
140  if (smc_l2p[block] < LBA_UNUSED) {
141    page = smc_l2p[block] << 5;
142    page += (lpage & 0x1F);
143  }
144  else
145    return 0;
146
147  sm_chip_en();
148
149  sm_cle_en();
150  sm_write_en();
151  sm_write(READ1_CMD);
152  sm_write_dis();
153  sm_cle_dis();
154
155  sm_ale_en();
156  sm_write_en();
157  sm_write( 0x00);
158  sm_write( (uint8_t)(page >> 0));
159  sm_write( (uint8_t)(page >> 8));
160  if (smc_info.mb >= 64)
161    sm_write( (uint8_t)(page >> 16));
162  sm_write_dis();
163  sm_ale_dis();
164
165  sm_busy();
166
167  sm_read_en();
168  for (i = 0; i < 512; i++) {
169    *buf = sm_read();
170    buf++;
171  }
172  sm_read_dis();
173  sm_chip_dis();
174
175  sm_busy();
176  return 1;
177}
178
179static void smc_read_spare( uint32_t page, uint8_t* buf, uint8_t length)
180{
181  uint32_t i;
182
183  sm_chip_en();
184
185  sm_cle_en();
186  sm_read_dis();
187  sm_write(READ2_CMD);
188  sm_read_en();
189  sm_cle_dis();
190
191  sm_ale_en();
192  sm_read_dis();
193  sm_write( 0x00);
194  sm_write( (uint8_t)(page >> 0));
195  sm_write( (uint8_t)(page >> 8));
196  if (smc_info.mb >= 64)
197    sm_write( (uint8_t)(page >> 16));
198  sm_read_en();
199  sm_ale_dis();
200
201  sm_busy();
202
203  sm_read_en();
204  for (i=0;i<length;i++)
205    *(buf+i) = sm_read();
206  sm_read_dis();
207
208  sm_chip_dis();
209
210}
211
212static void smc_make_l2p(void)
213{
214  uint32_t pblock, i, j, lblock, zone, count, cnt1, cnt2, cnt3;
215  uint8_t data[512];
216
217  cnt1 = 0;
218  cnt2 = 0;
219  cnt3 = 0;
220
221  for (i=0;i<0x2000;i++) {
222    smc_l2p[i] = LBA_RESERVED;
223    smc_p2l[i] = BLOCK_RESERVED;
224  }
225
226  for (pblock=0;pblock<smc_info.blocks;pblock++) {
227    /* read physical block - first page */
228    smc_read_spare( pblock*smc_info.pages_per_block, (uint8_t*)&data, 16);
229
230    zone = pblock >> 10; /* divide by 1024 to get zone */
231    if ((data[5] == 0xFF) && ((data[6]&0xF8) == 0x10)) {
232      lblock = ((((data[6]<<8)|(data[7]<<0)) >> 1) & 0x03FF) + (zone * 1000);
233      smc_l2p[lblock] = pblock;
234      smc_p2l[pblock] = lblock;
235      cnt1++;
236    } else {
237      count = 0;
238      for (j=0;j<16;j++) {
239        if (data[j] == 0xFF) count++;
240      }
241      if (count == 16) {
242        smc_p2l[pblock] = BLOCK_UNUSED;
243        cnt2++;
244      } else {
245        smc_p2l[pblock] = BLOCK_RESERVED;
246        cnt3++;
247      }
248    }
249  }
250}
251
252
253static void smc_detect( uint8_t id1, uint8_t id2, uint8_t id3)
254{
255  smc_info.id[0] = id1;
256  smc_info.id[1] = id2;
257  smc_info.id[2] = id3;
258  smc_info.mb    = 0;
259  smc_info.bytes_per_page  = 0;
260  smc_info.pages_per_block = 0;
261  smc_info.blocks          = 0;
262
263  switch (id1) {
264    case SMC_SAMSUNG_ID:
265    case SMC_TOSHIBA_ID: {
266      switch (id2) {
267        case SMC_16MB  : smc_info.mb = 16; break;
268        case SMC_32MB  : smc_info.mb = 32; break;
269        case SMC_64MB  : smc_info.mb = 64; break;
270        case SMC_128MB : smc_info.mb = 128; break;
271      }
272      break;
273    }
274  }
275
276  switch (smc_info.mb) {
277    case 16  : smc_info.bytes_per_page = 512; smc_info.pages_per_block = 32; smc_info.blocks = 0x0400; break;
278    case 32  : smc_info.bytes_per_page = 512; smc_info.pages_per_block = 32; smc_info.blocks = 0x0800; break;
279    case 64  : smc_info.bytes_per_page = 512; smc_info.pages_per_block = 32; smc_info.blocks = 0x1000; break;
280    case 128 : smc_info.bytes_per_page = 512; smc_info.pages_per_block = 32; smc_info.blocks = 0x2000; break;
281  }
282}
283
284static void smc_init( void)
285{
286  unsigned char buf[32];
287  int i;
288
289  /* reset smc */
290  sm_chip_en();
291  sm_cle_en();
292  sm_write_en();
293  sm_write(0xFF);
294  sm_write_dis();
295  sm_cle_dis();
296  for(i=0;i<10;i++);
297  sm_busy();
298  sm_chip_dis();
299
300  smc_read_id (buf, 4);
301  smc_detect (buf[0], buf[1], buf[2]);
302  printk ("SMC: [%02X-%02X-%02X-%02X]\n", buf[0], buf[1], buf[2], buf[3]);
303  printk ("SMC size: %dMB detected\n",smc_info.mb);
304  smc_make_l2p();
305}
306
307/* smc_write --
308 * write stub
309 */
310static int smc_write(rtems_blkdev_request *req)
311{
312  rtems_blkdev_request_done(req, RTEMS_SUCCESSFUL);
313  return 0;
314}
315
316
317/* smc_read --
318 * PARAMETERS:
319 *     req - pointer to the READ block device request info
320 *
321 * RETURNS:
322 *     ioctl return value
323 */
324static int
325smc_read(rtems_blkdev_request *req)
326{
327    uint32_t   i;
328    rtems_blkdev_sg_buffer *sg;
329    uint32_t   remains;
330
331    remains = smc_info.bytes_per_page * req->bufnum;
332    sg = req->bufs;
333    for (i = 0; (remains > 0) && (i < req->bufnum); i++, sg++)
334    {
335        int count = sg->length;
336        if (count > remains)
337            count = remains;
338        smc_read_page(sg->block,sg->buffer);
339        remains -= count;
340    }
341    rtems_blkdev_request_done(req, RTEMS_SUCCESSFUL);
342    return 0;
343}
344
345/* smc_ioctl --
346 *     IOCTL handler for SMC device.
347 *
348 * PARAMETERS:
349 *      dev  - device number (major, minor number)
350 *      req  - IOCTL request code
351 *      argp - IOCTL argument
352 *
353 * RETURNS:
354 *     IOCTL return value
355 */
356static int
357smc_ioctl(rtems_disk_device *dd, uint32_t req, void *argp)
358{
359    switch (req)
360    {
361        case RTEMS_BLKIO_REQUEST:
362        {
363            rtems_blkdev_request *r = argp;
364            switch (r->req)
365            {
366                case RTEMS_BLKDEV_REQ_READ:
367                    return smc_read(r);
368                case RTEMS_BLKDEV_REQ_WRITE:
369                    return smc_write(r);
370                default:
371                    errno = EINVAL;
372                    return -1;
373            }
374            break;
375        }
376
377        default:
378            errno = EINVAL;
379            return -1;
380    }
381}
382
383/* smc_initialize --
384 *     RAM disk device driver initialization. Run through RAM disk
385 *     configuration information and configure appropriate RAM disks.
386 *
387 * PARAMETERS:
388 *     major - RAM disk major device number
389 *     minor - minor device number, not applicable
390 *     arg   - initialization argument, not applicable
391 *
392 * RETURNS:
393 *     none
394 */
395rtems_device_driver
396smc_initialize(
397    rtems_device_major_number major,
398    rtems_device_minor_number minor,
399    void *arg)
400{
401    rtems_status_code rc;
402    dev_t dev;
403    uint32_t block_num;
404
405    rc = rtems_disk_io_initialize();
406    if (rc != RTEMS_SUCCESSFUL)
407        return rc;
408
409    smc_init();
410    block_num = smc_info.blocks << 5;
411
412    dev = rtems_filesystem_make_dev_t(major, 0);
413    rc = rtems_disk_create_phys(dev, 512, block_num,
414                                    smc_ioctl, NULL, SMC_DEVICE_NAME);
415
416    return RTEMS_SUCCESSFUL;
417}
Note: See TracBrowser for help on using the repository browser.