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

4.115
Last change on this file since bb2b825 was 965dc55, checked in by Joel Sherrill <joel.sherrill@…>, on Feb 26, 2010 at 2:23:23 PM

2010-02-26 Joel Sherrill <joel.sherrill@…>

  • smc/smc.c: Replace EBADRQC with EINVAL.
  • Property mode set to 100644
File size: 13.7 KB
Line 
1/* smc.c -- s3c2400 smc disk block device implementation
2
3 Squidge's SMC Low-level access routines.
4 Inspired and derived from routines provided by Samsung Electronics M/M R&D Center & FireFly.
5
6*/
7
8#include <rtems.h>
9#include <rtems/libio.h>
10#include <errno.h>
11#include <stdlib.h>
12#include <stdio.h>
13#include <string.h>
14#include <inttypes.h>
15
16#include "rtems/blkdev.h"
17#include "rtems/diskdevs.h"
18#include "smc.h"
19#include <rtems/bspIo.h>
20#include <s3c24xx.h>
21
22#define SMC_DEVICE_NAME "/dev/smc"
23#define SMC_SAMSUNG_ID          0xEC
24#define SMC_TOSHIBA_ID          0x98
25
26#define SMC_16MB        0x73
27#define SMC_32MB        0x75
28#define SMC_64MB        0x76
29#define SMC_128MB       0x79
30
31#define LBA_UNUSED              0x80000000
32#define LBA_RESERVED            0x80000001
33
34#define BLOCK_UNUSED            0x80000000
35#define BLOCK_RESERVED          0x80000001
36
37/* SmartMedia Command */
38#define SEQ_DATA_INPUT_CMD      0x80
39#define READ1_CMD               0x00
40#define READ1_1_CMD             0x01
41#define READ2_CMD               0x50
42#define READ_ID_CMD             0x90
43#define RESET_CMD               0xFF
44#define PAGE_PROGRAM_CMD        0x10
45#define BLOCK_ERASE_CMD         0x60
46#define BLOCK_ERASE_CFM_CMD     0xD0
47#define READ_STATUS_CMD         0x70
48#define RESET_PTR_CMD           0x00
49
50
51/* Internal SMC disk descriptor */
52struct SMC_INFO
53{
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
106
107/* assumes chip enabled
108   bit 7: write protected = 0, write enabled = 1
109   bit 6: busy = 0, ready = 1
110   bit 0: success = 0, failed = 1
111
112   returns 1 on success, 0 on fail
113*/
114#if UNUSED
115static uint8_t sm_status()
116{
117  uint8_t status;
118
119  sm_cle_en();
120  sm_write_en();
121  sm_write(READ_STATUS_CMD);
122  sm_write_dis();
123  sm_cle_dis();
124
125  sm_read_en();
126  status = sm_read();
127  sm_read_dis();
128
129  if (status == 0xC0)
130    return 1;
131  else
132    return 0;
133}
134#endif
135
136void smc_read_id( uint8_t* buf, uint32_t length)
137{
138
139  uint32_t i;
140
141  sm_chip_en();
142
143  sm_cle_en();
144  sm_write_en();
145  sm_write(READ_ID_CMD);
146  sm_write_dis();
147  sm_cle_dis();
148
149  sm_ale_en();
150  sm_write_en();
151  sm_write( 0);
152  sm_write_dis();
153  sm_ale_dis();
154
155  sm_read_en();
156  for (i=0;i<length;i++) *(buf+i) = sm_read();
157  sm_read_dis();
158
159  sm_chip_dis();
160}
161
162/* read an entire logical page of 512 bytes.*/
163uint8_t smc_read_page (uint32_t lpage, uint8_t* buf)
164{
165        uint32_t block, page, i;
166
167        /* convert logical block to physical block
168           and then convert into page suitable for read1 command...
169        */
170        block = lpage >> 5;
171        if (smc_l2p[block] < LBA_UNUSED) {
172                page = smc_l2p[block] << 5;
173                page += (lpage & 0x1F);
174        }
175        else
176                return 0;
177
178        sm_chip_en();
179
180        sm_cle_en();
181        sm_write_en();
182        sm_write(READ1_CMD);
183        sm_write_dis();
184        sm_cle_dis();
185
186                        sm_ale_en();
187                        sm_write_en();
188                        sm_write( 0x00);
189                        sm_write( (uint8_t)(page >> 0));
190                        sm_write( (uint8_t)(page >> 8));
191                        if (smc_info.mb >= 64) sm_write( (uint8_t)(page >> 16));
192                        sm_write_dis();
193                        sm_ale_dis();
194
195                        sm_busy();
196
197                        sm_read_en();
198                        for (i = 0; i < 512; i++)
199                        {
200                                *buf = sm_read();
201                                buf++;
202                        }
203                        sm_read_dis();
204                        sm_chip_dis();
205
206                        sm_busy();
207        return 1;
208}
209
210void smc_read_spare( uint32_t page, uint8_t* buf, uint8_t length)
211{
212  uint32_t i;
213
214
215  sm_chip_en();
216
217  sm_cle_en();
218  sm_read_dis();
219  sm_write(READ2_CMD);
220  sm_read_en();
221  sm_cle_dis();
222
223  sm_ale_en();
224  sm_read_dis();
225  sm_write( 0x00);
226  sm_write( (uint8_t)(page >> 0));
227  sm_write( (uint8_t)(page >> 8));
228  if (smc_info.mb >= 64) sm_write( (uint8_t)(page >> 16));
229  sm_read_en();
230  sm_ale_dis();
231
232  sm_busy();
233
234  sm_read_en();
235  for (i=0;i<length;i++) *(buf+i) = sm_read();
236  sm_read_dis();
237
238  sm_chip_dis();
239
240}
241
242void smc_make_l2p(void)
243{
244  uint32_t pblock, i, j, lblock, zone, count, cnt1, cnt2, cnt3;
245  uint8_t data[512];
246
247  cnt1 = 0;
248  cnt2 = 0;
249  cnt3 = 0;
250
251  for (i=0;i<0x2000;i++)
252  {
253    smc_l2p[i] = LBA_RESERVED;
254    smc_p2l[i] = BLOCK_RESERVED;
255  }
256  for (pblock=0;pblock<smc_info.blocks;pblock++)
257  {
258    /* read physical block - first page */
259    smc_read_spare( pblock*smc_info.pages_per_block, (uint8_t*)&data, 16);
260
261    zone = pblock >> 10; /* divide by 1024 to get zone */
262    if ((data[5] == 0xFF) && ((data[6]&0xF8) == 0x10))
263    {
264      lblock = ((((data[6]<<8)|(data[7]<<0)) >> 1) & 0x03FF) + (zone * 1000);
265      smc_l2p[lblock] = pblock;
266      smc_p2l[pblock] = lblock;
267      cnt1++;
268    }
269    else
270    {
271      count = 0;
272      for (j=0;j<16;j++)
273      {
274        if (data[j] == 0xFF) count++;
275      }
276      if (count == 16)
277      {
278        smc_p2l[pblock] = BLOCK_UNUSED;
279        cnt2++;
280      }
281      else
282      {
283        smc_p2l[pblock] = BLOCK_RESERVED;
284        cnt3++;
285      }
286    }
287  }
288}
289
290
291void smc_detect( uint8_t id1, uint8_t id2, uint8_t id3)
292{
293  smc_info.id[0] = id1;
294  smc_info.id[1] = id2;
295  smc_info.id[2] = id3;
296  smc_info.mb    = 0;
297  smc_info.bytes_per_page  = 0;
298  smc_info.pages_per_block = 0;
299  smc_info.blocks          = 0;
300
301  switch (id1)
302  {
303    case SMC_SAMSUNG_ID:
304    case SMC_TOSHIBA_ID:
305    {
306      switch (id2)
307      {
308        case SMC_16MB  : smc_info.mb = 16; break;
309        case SMC_32MB  : smc_info.mb = 32; break;
310        case SMC_64MB  : smc_info.mb = 64; break;
311        case SMC_128MB : smc_info.mb = 128; break;
312      }
313      break;
314    }
315  }
316
317  switch (smc_info.mb)
318  {
319    case 16  : smc_info.bytes_per_page = 512; smc_info.pages_per_block = 32; smc_info.blocks = 0x0400; break;
320    case 32  : smc_info.bytes_per_page = 512; smc_info.pages_per_block = 32; smc_info.blocks = 0x0800; break;
321    case 64  : smc_info.bytes_per_page = 512; smc_info.pages_per_block = 32; smc_info.blocks = 0x1000; break;
322    case 128 : smc_info.bytes_per_page = 512; smc_info.pages_per_block = 32; smc_info.blocks = 0x2000; break;
323  }
324}
325
326void smc_init( void)
327{
328        unsigned char buf[32];
329        int i;
330
331        /* reset smc */
332        sm_chip_en();
333        sm_cle_en();
334        sm_write_en();
335        sm_write(0xFF);
336        sm_write_dis();
337        sm_cle_dis();
338        for(i=0;i<10;i++);
339        sm_busy();
340        sm_chip_dis();
341
342        smc_read_id (buf, 4);
343        smc_detect (buf[0], buf[1], buf[2]);
344        printk ("SMC: [%02X-%02X-%02X-%02X]\n", buf[0], buf[1], buf[2], buf[3]);
345        printk ("SMC size: %dMB detected\n",smc_info.mb);
346        smc_make_l2p();
347}
348
349/**********
350 * Function: sm_ECCEncode (completely ripped, unaltered, from the samsung routines)
351 * Remark:
352 *      - adopted from "ECC Algorithm for SmartMedia V3.0"
353 *              by Memory Product & Technology, Samsung Electronics Co. (ecc30.pdf)
354 **********/
355int sm_ECCEncode(const uint8_t * p_buf, uint8_t * p_ecc)
356{
357        uint32_t i, j;
358        uint8_t paritr[256], tmp = 0, tmp2 = 0;
359        uint8_t data_table0[16] = { 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0 };
360        uint8_t data_table1[16] = { 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1 };
361        uint8_t sum = 0, paritc = 0;
362        uint8_t parit0c = 0, parit1c = 0, parit2c = 0, parit3c = 0;
363        uint8_t parit4c = 0, parit5c = 0, parit6c = 0, parit7c = 0;
364        uint8_t parit1_1, parit1_2, parit2_1, parit2_2, parit4_1, parit4_2;
365        uint8_t parit8_1 = 0, parit8_2 = 0, parit16_1 = 0, parit16_2 = 0, parit32_1 = 0, parit32_2 = 0;
366        uint8_t parit64_1 = 0, parit64_2 = 0, parit128_1 = 0, parit128_2 = 0, parit256_1 = 0, parit256_2 = 0;
367        uint8_t parit512_1 = 0, parit512_2 = 0, parit1024_1 = 0, parit1024_2 = 0;
368        uint8_t* paritr_ptr;
369
370        paritr_ptr = paritr;
371        for (i = 0; i < 256; ++i, ++paritr_ptr, ++p_buf)
372        {
373                paritc ^= *p_buf;
374                tmp = (*p_buf & 0xf0) >> 4;
375                tmp2 = *p_buf & 0x0f;
376
377                switch (tmp)
378                {
379                        case 0:
380                        case 3:
381                        case 5:
382                        case 6:
383                        case 9:
384                        case 10:
385                        case 12:
386                        case 15:
387                                *paritr_ptr = *(data_table0 + tmp2);
388                                break;
389
390                        case 1:
391                        case 2:
392                        case 4:
393                        case 7:
394                        case 8:
395                        case 11:
396                        case 13:
397                        case 14:
398                                *paritr_ptr = *(data_table1 + tmp2);
399                                break;
400                }
401        }
402
403        parit0c = (paritc & 0x01) ? 1 : 0;
404        parit1c = (paritc & 0x02) ? 1 : 0;
405        parit2c = (paritc & 0x04) ? 1 : 0;
406        parit3c = (paritc & 0x08) ? 1 : 0;
407        parit4c = (paritc & 0x10) ? 1 : 0;
408        parit5c = (paritc & 0x20) ? 1 : 0;
409        parit6c = (paritc & 0x40) ? 1 : 0;
410        parit7c = (paritc & 0x80) ? 1 : 0;
411        parit1_2 = parit6c ^ parit4c ^ parit2c ^ parit0c;
412        parit1_1 = parit7c ^ parit5c ^ parit3c ^ parit1c;
413        parit2_2 = parit5c ^ parit4c ^ parit1c ^ parit0c;
414        parit2_1 = parit7c ^ parit6c ^ parit3c ^ parit2c;
415        parit4_2 = parit3c ^ parit2c ^ parit1c ^ parit0c;
416        parit4_1 = parit7c ^ parit6c ^ parit5c ^ parit4c;
417
418        paritr_ptr = paritr;
419        for (i = 0; i < 256; ++i, ++paritr_ptr)
420        {
421                sum ^= *paritr_ptr;
422        }
423
424        paritr_ptr = paritr;
425        for (i = 0; i < 256; i += 2, paritr_ptr += 2)
426        {
427                parit8_2 ^= *paritr_ptr;
428        }
429
430        paritr_ptr = paritr;
431        for (i = 0; i < 256; i += 4, paritr_ptr += 4)
432        {
433                parit16_2 ^= *paritr_ptr;
434                parit16_2 ^= *(paritr_ptr + 1);
435        }
436
437        paritr_ptr = paritr;
438        for (i = 0; i < 256; i += 8, paritr_ptr += 8)
439        {
440                for (j = 0; j <= 3; ++j)
441                {
442                        parit32_2 ^= *(paritr_ptr + j);
443                }
444        }
445
446        paritr_ptr = paritr;
447        for (i = 0; i < 256; i += 16, paritr_ptr += 16)
448        {
449                for (j = 0; j <= 7; ++j)
450                {
451                        parit64_2 ^= *(paritr_ptr + j);
452                }
453        }
454
455        paritr_ptr = paritr;
456        for (i = 0; i < 256; i += 32, paritr_ptr += 32)
457        {
458                for (j = 0; j <= 15; ++j)
459                {
460                        parit128_2 ^= *(paritr_ptr + j);
461                }
462        }
463
464        paritr_ptr = paritr;
465        for (i = 0; i < 256; i += 64, paritr_ptr += 64)
466        {
467                for (j = 0; j <= 31; ++j)
468                {
469                        parit256_2 ^= *(paritr_ptr + j);
470                }
471        }
472
473        paritr_ptr = paritr;
474        for (i = 0; i < 256; i += 128, paritr_ptr += 128)
475        {
476                for (j = 0; j <= 63; ++j)
477                {
478                        parit512_2 ^= *(paritr_ptr + j);
479                }
480        }
481
482        paritr_ptr = paritr;
483        for (i = 0; i < 256; i += 256, paritr_ptr += 256)
484        {
485                for (j = 0; j <= 127; ++j)
486                {
487                        parit1024_2 ^= *(paritr_ptr + j);
488                }
489        }
490
491        if (sum==0)
492        {
493                parit1024_1 = parit1024_2;
494                parit512_1 = parit512_2;
495                parit256_1 = parit256_2;
496                parit128_1 = parit128_2;
497                parit64_1 = parit64_2;
498                parit32_1 = parit32_2;
499                parit16_1 = parit16_2;
500                parit8_1 = parit8_2;
501        }
502        else
503        {
504                parit1024_1 = parit1024_2 ? 0 : 1;
505                parit512_1 = parit512_2 ? 0 : 1;
506                parit256_1 = parit256_2 ? 0 : 1;
507                parit128_1 = parit128_2 ? 0 : 1;
508                parit64_1 = parit64_2 ? 0 : 1;
509                parit32_1 = parit32_2 ? 0 : 1;
510                parit16_1 = parit16_2 ? 0 : 1;
511                parit8_1 = parit8_2 ? 0 : 1;
512        }
513
514        parit1_2 <<= 2;
515        parit1_1 <<= 3;
516        parit2_2 <<= 4;
517        parit2_1 <<= 5;
518        parit4_2 <<= 6;
519        parit4_1 <<= 7;
520        parit128_1 <<= 1;
521        parit256_2 <<= 2;
522        parit256_1 <<= 3;
523        parit512_2 <<= 4;
524        parit512_1 <<= 5;
525        parit1024_2 <<= 6;
526        parit1024_1 <<= 7;
527        parit8_1 <<= 1;
528        parit16_2 <<= 2;
529        parit16_1 <<= 3;
530        parit32_2 <<= 4;
531        parit32_1 <<= 5;
532        parit64_2 <<= 6;
533        parit64_1 <<= 7;
534
535        p_ecc[0] = ~(parit64_1 | parit64_2 | parit32_1 | parit32_2 | parit16_1 | parit16_2 | parit8_1 | parit8_2);
536        p_ecc[1] = ~(parit1024_1 |parit1024_2 | parit512_1 | parit512_2 | parit256_1 | parit256_2 | parit128_1 | parit128_2);
537        p_ecc[2] = ~(parit4_1 | parit4_2 | parit2_1 | parit2_2 | parit1_1 | parit1_2);
538
539        return 0;
540}
541
542/* smc_write --
543 * write stub
544*/
545static int smc_write(rtems_blkdev_request *req)
546{
547        req->req_done(req->done_arg, RTEMS_SUCCESSFUL);
548        return 0;
549}
550
551
552/* smc_read --
553 * PARAMETERS:
554 *     req - pointer to the READ block device request info
555 *
556 * RETURNS:
557 *     ioctl return value
558 */
559static int
560smc_read(rtems_blkdev_request *req)
561{
562    uint32_t   i;
563    rtems_blkdev_sg_buffer *sg;
564    uint32_t   remains;
565
566    remains = smc_info.bytes_per_page * req->bufnum;
567    sg = req->bufs;
568    for (i = 0; (remains > 0) && (i < req->bufnum); i++, sg++)
569    {
570        int count = sg->length;
571        if (count > remains)
572            count = remains;
573        smc_read_page(sg->block,sg->buffer);
574        remains -= count;
575    }
576    req->req_done(req->done_arg, RTEMS_SUCCESSFUL);
577    return 0;
578}
579
580/* smc_ioctl --
581 *     IOCTL handler for SMC device.
582 *
583 * PARAMETERS:
584 *      dev  - device number (major, minor number)
585 *      req  - IOCTL request code
586 *      argp - IOCTL argument
587 *
588 * RETURNS:
589 *     IOCTL return value
590 */
591static int
592smc_ioctl(rtems_disk_device *dd, uint32_t req, void *argp)
593{
594    switch (req)
595    {
596        case RTEMS_BLKIO_REQUEST:
597        {
598            rtems_blkdev_request *r = argp;
599            switch (r->req)
600            {
601                case RTEMS_BLKDEV_REQ_READ:
602                    return smc_read(r);
603                case RTEMS_BLKDEV_REQ_WRITE:
604                    return smc_write(r);
605                default:
606                    errno = EINVAL;
607                    return -1;
608            }
609            break;
610        }
611
612        default:
613            errno = EINVAL;
614            return -1;
615    }
616}
617
618/* smc_initialize --
619 *     RAM disk device driver initialization. Run through RAM disk
620 *     configuration information and configure appropriate RAM disks.
621 *
622 * PARAMETERS:
623 *     major - RAM disk major device number
624 *     minor - minor device number, not applicable
625 *     arg   - initialization argument, not applicable
626 *
627 * RETURNS:
628 *     none
629 */
630rtems_device_driver
631smc_initialize(
632    rtems_device_major_number major,
633    rtems_device_minor_number minor,
634    void *arg)
635{
636    rtems_status_code rc;
637    dev_t dev;
638    uint32_t block_num;
639
640    rc = rtems_disk_io_initialize();
641    if (rc != RTEMS_SUCCESSFUL)
642        return rc;
643
644    smc_init();
645    block_num = smc_info.blocks << 5;
646
647    dev = rtems_filesystem_make_dev_t(major, 0);
648    rc = rtems_disk_create_phys(dev, 512, block_num,
649                                    smc_ioctl, NULL, SMC_DEVICE_NAME);
650
651    return RTEMS_SUCCESSFUL;
652}
Note: See TracBrowser for help on using the repository browser.