File indexing completed on 2025-05-11 08:23:05
0001
0002
0003
0004
0005
0006
0007
0008
0009 #include <rtems.h>
0010 #include <rtems/libio.h>
0011 #include <errno.h>
0012 #include <stdlib.h>
0013 #include <stdio.h>
0014 #include <string.h>
0015 #include <inttypes.h>
0016
0017 #include <rtems/blkdev.h>
0018 #include "smc.h"
0019 #include <rtems/bspIo.h>
0020 #include <s3c24xx.h>
0021
0022 #define SMC_DEVICE_NAME "/dev/smc"
0023 #define SMC_SAMSUNG_ID 0xEC
0024 #define SMC_TOSHIBA_ID 0x98
0025
0026 #define SMC_16MB 0x73
0027 #define SMC_32MB 0x75
0028 #define SMC_64MB 0x76
0029 #define SMC_128MB 0x79
0030
0031 #define LBA_UNUSED 0x80000000
0032 #define LBA_RESERVED 0x80000001
0033
0034 #define BLOCK_UNUSED 0x80000000
0035 #define BLOCK_RESERVED 0x80000001
0036
0037
0038 #define SEQ_DATA_INPUT_CMD 0x80
0039 #define READ1_CMD 0x00
0040 #define READ1_1_CMD 0x01
0041 #define READ2_CMD 0x50
0042 #define READ_ID_CMD 0x90
0043 #define RESET_CMD 0xFF
0044 #define PAGE_PROGRAM_CMD 0x10
0045 #define BLOCK_ERASE_CMD 0x60
0046 #define BLOCK_ERASE_CFM_CMD 0xD0
0047 #define READ_STATUS_CMD 0x70
0048 #define RESET_PTR_CMD 0x00
0049
0050
0051
0052 struct SMC_INFO {
0053 uint8_t id[3];
0054 uint32_t bytes_per_page;
0055 uint32_t pages_per_block;
0056 uint32_t blocks;
0057 uint32_t mb;
0058 };
0059
0060
0061 #ifdef CPU_S3C2410
0062 #define rPBDAT rGPBDAT
0063 #define rPBCON rGPBCON
0064 #define rPDDAT rGPDDAT
0065 #define rPEDAT rGPEDAT
0066 #endif
0067
0068
0069 static struct SMC_INFO smc_info;
0070
0071 uint32_t smc_l2p[0x2000];
0072 uint32_t smc_p2l[0x2000];
0073
0074 #define sm_busy() while (!(rPDDAT & 0x200))
0075 #define sm_chip_en() rPDDAT &= (~0x80)
0076 #define sm_chip_dis() rPDDAT |= 0x80
0077 #define sm_cle_en() rPEDAT |= 0x20
0078 #define sm_cle_dis() rPEDAT &= (~0x20)
0079 #define sm_ale_en() rPEDAT |= 0x10
0080 #define sm_ale_dis() rPEDAT &= (~0x10)
0081 #define sm_wp_en() rPDDAT &= (~0x40)
0082 #define sm_wp_dis() rPDDAT |= 0x40
0083 #define sm_read_en() rPBCON &= 0xFFFF0000
0084 #define sm_read_dis() rPBCON = (rPBCON & 0xFFFF0000) | 0x5555
0085 #define sm_write_en() sm_read_dis()
0086 #define sm_write_dis() sm_read_en()
0087
0088 static void sm_write( uint8_t data)
0089 {
0090 rPBDAT = (rPBDAT & 0xFF00) | data;
0091 rPEDAT &= (~0x08);
0092 rPEDAT |= 0x08;
0093 }
0094
0095 static uint8_t sm_read(void)
0096 {
0097 uint8_t data;
0098
0099 rPDDAT &= (~0x100);
0100 data = rPBDAT & 0xFF;
0101 rPDDAT |= 0x100;
0102 return data;
0103 }
0104
0105 static void smc_read_id( uint8_t* buf, uint32_t length)
0106 {
0107 uint32_t i;
0108
0109 sm_chip_en();
0110
0111 sm_cle_en();
0112 sm_write_en();
0113 sm_write(READ_ID_CMD);
0114 sm_write_dis();
0115 sm_cle_dis();
0116
0117 sm_ale_en();
0118 sm_write_en();
0119 sm_write( 0);
0120 sm_write_dis();
0121 sm_ale_dis();
0122
0123 sm_read_en();
0124 for (i=0;i<length;i++) *(buf+i) = sm_read();
0125 sm_read_dis();
0126
0127 sm_chip_dis();
0128 }
0129
0130
0131 static uint8_t smc_read_page (uint32_t lpage, uint8_t* buf)
0132 {
0133 uint32_t block, page, i;
0134
0135
0136
0137
0138 block = lpage >> 5;
0139 if (smc_l2p[block] < LBA_UNUSED) {
0140 page = smc_l2p[block] << 5;
0141 page += (lpage & 0x1F);
0142 }
0143 else
0144 return 0;
0145
0146 sm_chip_en();
0147
0148 sm_cle_en();
0149 sm_write_en();
0150 sm_write(READ1_CMD);
0151 sm_write_dis();
0152 sm_cle_dis();
0153
0154 sm_ale_en();
0155 sm_write_en();
0156 sm_write( 0x00);
0157 sm_write( (uint8_t)(page >> 0));
0158 sm_write( (uint8_t)(page >> 8));
0159 if (smc_info.mb >= 64)
0160 sm_write( (uint8_t)(page >> 16));
0161 sm_write_dis();
0162 sm_ale_dis();
0163
0164 sm_busy();
0165
0166 sm_read_en();
0167 for (i = 0; i < 512; i++) {
0168 *buf = sm_read();
0169 buf++;
0170 }
0171 sm_read_dis();
0172 sm_chip_dis();
0173
0174 sm_busy();
0175 return 1;
0176 }
0177
0178 static void smc_read_spare( uint32_t page, uint8_t* buf, uint8_t length)
0179 {
0180 uint32_t i;
0181
0182 sm_chip_en();
0183
0184 sm_cle_en();
0185 sm_read_dis();
0186 sm_write(READ2_CMD);
0187 sm_read_en();
0188 sm_cle_dis();
0189
0190 sm_ale_en();
0191 sm_read_dis();
0192 sm_write( 0x00);
0193 sm_write( (uint8_t)(page >> 0));
0194 sm_write( (uint8_t)(page >> 8));
0195 if (smc_info.mb >= 64)
0196 sm_write( (uint8_t)(page >> 16));
0197 sm_read_en();
0198 sm_ale_dis();
0199
0200 sm_busy();
0201
0202 sm_read_en();
0203 for (i=0;i<length;i++)
0204 *(buf+i) = sm_read();
0205 sm_read_dis();
0206
0207 sm_chip_dis();
0208
0209 }
0210
0211 static void smc_make_l2p(void)
0212 {
0213 uint32_t pblock, i, j, lblock, zone, count;
0214 uint8_t data[512];
0215
0216 for (i=0;i<0x2000;i++) {
0217 smc_l2p[i] = LBA_RESERVED;
0218 smc_p2l[i] = BLOCK_RESERVED;
0219 }
0220
0221 for (pblock=0;pblock<smc_info.blocks;pblock++) {
0222
0223 smc_read_spare( pblock*smc_info.pages_per_block, (uint8_t*)&data, 16);
0224
0225 zone = pblock >> 10;
0226 if ((data[5] == 0xFF) && ((data[6]&0xF8) == 0x10)) {
0227 lblock = ((((data[6]<<8)|(data[7]<<0)) >> 1) & 0x03FF) + (zone * 1000);
0228 smc_l2p[lblock] = pblock;
0229 smc_p2l[pblock] = lblock;
0230 } else {
0231 count = 0;
0232 for (j=0;j<16;j++) {
0233 if (data[j] == 0xFF) count++;
0234 }
0235 if (count == 16) {
0236 smc_p2l[pblock] = BLOCK_UNUSED;
0237 } else {
0238 smc_p2l[pblock] = BLOCK_RESERVED;
0239 }
0240 }
0241 }
0242 }
0243
0244
0245 static void smc_detect( uint8_t id1, uint8_t id2, uint8_t id3)
0246 {
0247 smc_info.id[0] = id1;
0248 smc_info.id[1] = id2;
0249 smc_info.id[2] = id3;
0250 smc_info.mb = 0;
0251 smc_info.bytes_per_page = 0;
0252 smc_info.pages_per_block = 0;
0253 smc_info.blocks = 0;
0254
0255 switch (id1) {
0256 case SMC_SAMSUNG_ID:
0257 case SMC_TOSHIBA_ID: {
0258 switch (id2) {
0259 case SMC_16MB : smc_info.mb = 16; break;
0260 case SMC_32MB : smc_info.mb = 32; break;
0261 case SMC_64MB : smc_info.mb = 64; break;
0262 case SMC_128MB : smc_info.mb = 128; break;
0263 }
0264 break;
0265 }
0266 }
0267
0268 switch (smc_info.mb) {
0269 case 16 : smc_info.bytes_per_page = 512; smc_info.pages_per_block = 32; smc_info.blocks = 0x0400; break;
0270 case 32 : smc_info.bytes_per_page = 512; smc_info.pages_per_block = 32; smc_info.blocks = 0x0800; break;
0271 case 64 : smc_info.bytes_per_page = 512; smc_info.pages_per_block = 32; smc_info.blocks = 0x1000; break;
0272 case 128 : smc_info.bytes_per_page = 512; smc_info.pages_per_block = 32; smc_info.blocks = 0x2000; break;
0273 }
0274 }
0275
0276 static void smc_init( void)
0277 {
0278 unsigned char buf[32];
0279 int i;
0280
0281
0282 sm_chip_en();
0283 sm_cle_en();
0284 sm_write_en();
0285 sm_write(0xFF);
0286 sm_write_dis();
0287 sm_cle_dis();
0288 for(i=0;i<10;i++);
0289 sm_busy();
0290 sm_chip_dis();
0291
0292 smc_read_id (buf, 4);
0293 smc_detect (buf[0], buf[1], buf[2]);
0294 printk ("SMC: [%02X-%02X-%02X-%02X]\n", buf[0], buf[1], buf[2], buf[3]);
0295 printk ("SMC size: %" PRIu32 "MB detected\n",smc_info.mb);
0296 smc_make_l2p();
0297 }
0298
0299
0300
0301
0302 static int smc_write(rtems_blkdev_request *req)
0303 {
0304 rtems_blkdev_request_done(req, RTEMS_SUCCESSFUL);
0305 return 0;
0306 }
0307
0308
0309
0310
0311
0312
0313
0314
0315
0316 static int
0317 smc_read(rtems_blkdev_request *req)
0318 {
0319 uint32_t i;
0320 rtems_blkdev_sg_buffer *sg;
0321 uint32_t remains;
0322
0323 remains = smc_info.bytes_per_page * req->bufnum;
0324 sg = req->bufs;
0325 for (i = 0; (remains > 0) && (i < req->bufnum); i++, sg++)
0326 {
0327 int count = sg->length;
0328 if (count > remains)
0329 count = remains;
0330 smc_read_page(sg->block,sg->buffer);
0331 remains -= count;
0332 }
0333 rtems_blkdev_request_done(req, RTEMS_SUCCESSFUL);
0334 return 0;
0335 }
0336
0337
0338
0339
0340
0341
0342
0343
0344
0345
0346
0347
0348 static int
0349 smc_ioctl(rtems_disk_device *dd, uint32_t req, void *argp)
0350 {
0351 switch (req)
0352 {
0353 case RTEMS_BLKIO_REQUEST:
0354 {
0355 rtems_blkdev_request *r = argp;
0356 switch (r->req)
0357 {
0358 case RTEMS_BLKDEV_REQ_READ:
0359 return smc_read(r);
0360 case RTEMS_BLKDEV_REQ_WRITE:
0361 return smc_write(r);
0362 default:
0363 errno = EINVAL;
0364 return -1;
0365 }
0366 break;
0367 }
0368
0369 default:
0370 errno = EINVAL;
0371 return -1;
0372 }
0373 }
0374
0375
0376
0377
0378
0379
0380
0381
0382
0383
0384
0385
0386
0387 rtems_device_driver
0388 smc_initialize(
0389 rtems_device_major_number major,
0390 rtems_device_minor_number minor,
0391 void *arg)
0392 {
0393 rtems_status_code rc;
0394 uint32_t block_num;
0395
0396 smc_init();
0397 block_num = smc_info.blocks << 5;
0398
0399 rc = rtems_blkdev_create(SMC_DEVICE_NAME, 512, block_num, smc_ioctl, NULL);
0400
0401 return rc;
0402 }