From 4906d7f77fdaecdbbd650980462bd9da7db0115a Mon Sep 17 00:00:00 2001 From: Philippe Simons Date: Mon, 25 Jul 2005 19:18:09 +0000 Subject: 2005-07-25 Philippe Simons * Makefile.am: added smc.rel. * smc/smc.c, smc/smc.h: New files. --- c/src/lib/libbsp/arm/gp32/ChangeLog | 5 + c/src/lib/libbsp/arm/gp32/Makefile.am | 12 +- c/src/lib/libbsp/arm/gp32/smc/smc.c | 641 ++++++++++++++++++++++++++++++++++ c/src/lib/libbsp/arm/gp32/smc/smc.h | 28 ++ 4 files changed, 685 insertions(+), 1 deletion(-) create mode 100644 c/src/lib/libbsp/arm/gp32/smc/smc.c create mode 100644 c/src/lib/libbsp/arm/gp32/smc/smc.h (limited to 'c') diff --git a/c/src/lib/libbsp/arm/gp32/ChangeLog b/c/src/lib/libbsp/arm/gp32/ChangeLog index a89adf75aa..e51d335b19 100644 --- a/c/src/lib/libbsp/arm/gp32/ChangeLog +++ b/c/src/lib/libbsp/arm/gp32/ChangeLog @@ -1,3 +1,8 @@ +2005-07-25 Philippe Simons + + * Makefile.am: added smc.rel. + * smc/smc.c, smc/smc.h: New files. + 2005-07-07 Philippe Simons * Makefile.am: Remove lcd.rel, added console/uart.c, diff --git a/c/src/lib/libbsp/arm/gp32/Makefile.am b/c/src/lib/libbsp/arm/gp32/Makefile.am index a6a69868a0..67e697a3b0 100644 --- a/c/src/lib/libbsp/arm/gp32/Makefile.am +++ b/c/src/lib/libbsp/arm/gp32/Makefile.am @@ -10,6 +10,7 @@ include $(top_srcdir)/../../bsp.am dist_project_lib_DATA = bsp_specs include_HEADERS = include/bsp.h +include_HEADERS += smc/smc.h include_HEADERS += include/tm27.h nodist_include_HEADERS = include/bspopts.h @@ -39,9 +40,14 @@ console_rel_SOURCES = console/uart.c ../../shared/console.c console_rel_CPPFLAGS = $(AM_CPPFLAGS) console_rel_LDFLAGS = $(RTEMS_RELLDFLAGS) +noinst_PROGRAMS += smc.rel +smc_rel_SOURCES = smc/smc.c smc/smc.h +smc_rel_CPPFLAGS = $(AM_CPPFLAGS) +smc_rel_LDFLAGS = $(RTEMS_RELLDFLAGS) + noinst_LIBRARIES = libbsp.a libbsp_a_SOURCES = -libbsp_a_LIBADD = startup.rel console.rel +libbsp_a_LIBADD = startup.rel console.rel smc.rel libbsp_a_LIBADD += ../../../libcpu/@RTEMS_CPU@/shared/arm920.rel \ ../../../libcpu/@RTEMS_CPU@/@RTEMS_CPU_MODEL@/clock.rel \ ../../../libcpu/@RTEMS_CPU@/@RTEMS_CPU_MODEL@/timer.rel \ @@ -71,6 +77,10 @@ $(PROJECT_INCLUDE)/bsp.h: include/bsp.h $(PROJECT_INCLUDE)/$(dirstamp) $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/bsp.h PREINSTALL_FILES += $(PROJECT_INCLUDE)/bsp.h +$(PROJECT_INCLUDE)/smc.h: smc/smc.h $(PROJECT_INCLUDE)/$(dirstamp) + $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/smc.h +PREINSTALL_FILES += $(PROJECT_INCLUDE)/smc.h + $(PROJECT_INCLUDE)/tm27.h: include/tm27.h $(PROJECT_INCLUDE)/$(dirstamp) $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/tm27.h PREINSTALL_FILES += $(PROJECT_INCLUDE)/tm27.h diff --git a/c/src/lib/libbsp/arm/gp32/smc/smc.c b/c/src/lib/libbsp/arm/gp32/smc/smc.c new file mode 100644 index 0000000000..0ce0691dac --- /dev/null +++ b/c/src/lib/libbsp/arm/gp32/smc/smc.c @@ -0,0 +1,641 @@ +/* smc.c -- s3c2400 smc disk block device implementation + + Squidge's SMC Low-level access routines. + Inspired and derived from routines provided by Samsung Electronics M/M R&D Center & FireFly. + +*/ + +#include +#include +#include +#include +#include +#include +#include + +#include "rtems/blkdev.h" +#include "rtems/diskdevs.h" +#include "smc.h" +#include + +#define SMC_DEVICE_NAME "/dev/smc" +#define SMC_SAMSUNG_ID 0xEC +#define SMC_TOSHIBA_ID 0x98 + +#define SMC_16MB 0x73 +#define SMC_32MB 0x75 +#define SMC_64MB 0x76 +#define SMC_128MB 0x79 + +#define LBA_UNUSED 0x80000000 +#define LBA_RESERVED 0x80000001 + +#define BLOCK_UNUSED 0x80000000 +#define BLOCK_RESERVED 0x80000001 + +/* SmartMedia Command */ +#define SEQ_DATA_INPUT_CMD 0x80 +#define READ1_CMD 0x00 +#define READ1_1_CMD 0x01 +#define READ2_CMD 0x50 +#define READ_ID_CMD 0x90 +#define RESET_CMD 0xFF +#define PAGE_PROGRAM_CMD 0x10 +#define BLOCK_ERASE_CMD 0x60 +#define BLOCK_ERASE_CFM_CMD 0xD0 +#define READ_STATUS_CMD 0x70 +#define RESET_PTR_CMD 0x00 + + +/* Internal SMC disk descriptor */ +struct SMC_INFO +{ + uint8_t id[3]; + uint32_t bytes_per_page; + uint32_t pages_per_block; + uint32_t blocks; + uint32_t mb; +}; + +static struct SMC_INFO smc_info; + +uint32_t smc_l2p[0x2000]; +uint32_t smc_p2l[0x2000]; + +#define sm_busy() while (!(rPDDAT & 0x200)) +#define sm_chip_en() rPDDAT &= (~0x80) +#define sm_chip_dis() rPDDAT |= 0x80 +#define sm_cle_en() rPEDAT |= 0x20 +#define sm_cle_dis() rPEDAT &= (~0x20) +#define sm_ale_en() rPEDAT |= 0x10 +#define sm_ale_dis() rPEDAT &= (~0x10) +#define sm_wp_en() rPDDAT &= (~0x40) +#define sm_wp_dis() rPDDAT |= 0x40 +#define sm_read_en() rPBCON &= 0xFFFF0000 +#define sm_read_dis() rPBCON = (rPBCON & 0xFFFF0000) | 0x5555 +#define sm_write_en() sm_read_dis() +#define sm_write_dis() sm_read_en() + +static void sm_write( uint8_t data) +{ + rPBDAT = (rPBDAT & 0xFF00) | data; + rPEDAT &= (~0x08); + rPEDAT |= 0x08; +} + +static uint8_t sm_read() +{ + uint8_t data; + + rPDDAT &= (~0x100); + data = rPBDAT & 0xFF; + rPDDAT |= 0x100; + return data; +} + + +/* assumes chip enabled + bit 7: write protected = 0, write enabled = 1 + bit 6: busy = 0, ready = 1 + bit 0: success = 0, failed = 1 + + returns 1 on success, 0 on fail +*/ +static uint8_t sm_status() +{ + uint8_t status; + + sm_cle_en(); + sm_write_en(); + sm_write(READ_STATUS_CMD); + sm_write_dis(); + sm_cle_dis(); + + sm_read_en(); + status = sm_read(); + sm_read_dis(); + + if (status == 0xC0) + return 1; + else + return 0; +} + + +void smc_read_id( uint8_t* buf, uint32_t length) +{ + + uint32_t i; + + sm_chip_en(); + + sm_cle_en(); + sm_write_en(); + sm_write(READ_ID_CMD); + sm_write_dis(); + sm_cle_dis(); + + sm_ale_en(); + sm_write_en(); + sm_write( 0); + sm_write_dis(); + sm_ale_dis(); + + sm_read_en(); + for (i=0;i> 5; + if (smc_l2p[block] < LBA_UNUSED) { + page = smc_l2p[block] << 5; + page += (lpage & 0x1F); + } + else + return 0; + + sm_chip_en(); + + sm_cle_en(); + sm_write_en(); + sm_write(READ1_CMD); + sm_write_dis(); + sm_cle_dis(); + + sm_ale_en(); + sm_write_en(); + sm_write( 0x00); + sm_write( (uint8_t)(page >> 0)); + sm_write( (uint8_t)(page >> 8)); + if (smc_info.mb >= 64) sm_write( (uint8_t)(page >> 16)); + sm_write_dis(); + sm_ale_dis(); + + sm_busy(); + + sm_read_en(); + for (i = 0; i < 512; i++) + { + *buf = sm_read(); + buf++; + } + sm_read_dis(); + sm_chip_dis(); + + sm_busy(); + return 1; +} + +void smc_read_spare( uint32_t page, uint8_t* buf, uint8_t length) +{ + uint32_t i; + + + sm_chip_en(); + + sm_cle_en(); + sm_read_dis(); + sm_write(READ2_CMD); + sm_read_en(); + sm_cle_dis(); + + sm_ale_en(); + sm_read_dis(); + sm_write( 0x00); + sm_write( (uint8_t)(page >> 0)); + sm_write( (uint8_t)(page >> 8)); + if (smc_info.mb >= 64) sm_write( (uint8_t)(page >> 16)); + sm_read_en(); + sm_ale_dis(); + + sm_busy(); + + sm_read_en(); + for (i=0;i> 10; /* divide by 1024 to get zone */ + if ((data[5] == 0xFF) && ((data[6]&0xF8) == 0x10)) + { + lblock = ((((data[6]<<8)|(data[7]<<0)) >> 1) & 0x03FF) + (zone * 1000); + smc_l2p[lblock] = pblock; + smc_p2l[pblock] = lblock; + cnt1++; + } + else + { + count = 0; + for (j=0;j<16;j++) + { + if (data[j] == 0xFF) count++; + } + if (count == 16) + { + smc_p2l[pblock] = BLOCK_UNUSED; + cnt2++; + } + else + { + smc_p2l[pblock] = BLOCK_RESERVED; + cnt3++; + } + } + } +} + + +void smc_detect( uint8_t id1, uint8_t id2, uint8_t id3) +{ + smc_info.id[0] = id1; + smc_info.id[1] = id2; + smc_info.id[2] = id3; + smc_info.mb = 0; + smc_info.bytes_per_page = 0; + smc_info.pages_per_block = 0; + smc_info.blocks = 0; + + switch (id1) + { + case SMC_SAMSUNG_ID: + case SMC_TOSHIBA_ID: + { + switch (id2) + { + case SMC_16MB : smc_info.mb = 16; break; + case SMC_32MB : smc_info.mb = 32; break; + case SMC_64MB : smc_info.mb = 64; break; + case SMC_128MB : smc_info.mb = 128; break; + } + break; + } + } + + switch (smc_info.mb) + { + case 16 : smc_info.bytes_per_page = 512; smc_info.pages_per_block = 32; smc_info.blocks = 0x0400; break; + case 32 : smc_info.bytes_per_page = 512; smc_info.pages_per_block = 32; smc_info.blocks = 0x0800; break; + case 64 : smc_info.bytes_per_page = 512; smc_info.pages_per_block = 32; smc_info.blocks = 0x1000; break; + case 128 : smc_info.bytes_per_page = 512; smc_info.pages_per_block = 32; smc_info.blocks = 0x2000; break; + } +} + +void smc_init( void) +{ + unsigned char buf[32]; + int i; + + /* reset smc */ + sm_chip_en(); + sm_cle_en(); + sm_write_en(); + sm_write(0xFF); + sm_write_dis(); + sm_cle_dis(); + for(i=0;i<10;i++); + sm_busy(); + sm_chip_dis(); + + smc_read_id (buf, 4); + smc_detect (buf[0], buf[1], buf[2]); + printk ("SMC: [%02X-%02X-%02X-%02X]\n", buf[0], buf[1], buf[2], buf[3]); + printk ("SMC size: %dMB detected\n",smc_info.mb); + smc_make_l2p(); +} + +/********** + * Function: sm_ECCEncode (completely ripped, unaltered, from the samsung routines) + * Remark: + * - adopted from "ECC Algorithm for SmartMedia V3.0" + * by Memory Product & Technology, Samsung Electronics Co. (ecc30.pdf) + **********/ +int sm_ECCEncode(const uint8_t * p_buf, uint8_t * p_ecc) +{ + uint32_t i, j; + uint8_t paritr[256], tmp = 0, tmp2 = 0; + uint8_t data_table0[16] = { 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0 }; + uint8_t data_table1[16] = { 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1 }; + uint8_t sum = 0, paritc = 0; + uint8_t parit0c = 0, parit1c = 0, parit2c = 0, parit3c = 0; + uint8_t parit4c = 0, parit5c = 0, parit6c = 0, parit7c = 0; + uint8_t parit1_1, parit1_2, parit2_1, parit2_2, parit4_1, parit4_2; + uint8_t parit8_1 = 0, parit8_2 = 0, parit16_1 = 0, parit16_2 = 0, parit32_1 = 0, parit32_2 = 0; + uint8_t parit64_1 = 0, parit64_2 = 0, parit128_1 = 0, parit128_2 = 0, parit256_1 = 0, parit256_2 = 0; + uint8_t parit512_1 = 0, parit512_2 = 0, parit1024_1 = 0, parit1024_2 = 0; + uint8_t* paritr_ptr; + + paritr_ptr = paritr; + for (i = 0; i < 256; ++i, ++paritr_ptr, ++p_buf) + { + paritc ^= *p_buf; + tmp = (*p_buf & 0xf0) >> 4; + tmp2 = *p_buf & 0x0f; + + switch (tmp) + { + case 0: + case 3: + case 5: + case 6: + case 9: + case 10: + case 12: + case 15: + *paritr_ptr = *(data_table0 + tmp2); + break; + + case 1: + case 2: + case 4: + case 7: + case 8: + case 11: + case 13: + case 14: + *paritr_ptr = *(data_table1 + tmp2); + break; + } + } + + parit0c = (paritc & 0x01) ? 1 : 0; + parit1c = (paritc & 0x02) ? 1 : 0; + parit2c = (paritc & 0x04) ? 1 : 0; + parit3c = (paritc & 0x08) ? 1 : 0; + parit4c = (paritc & 0x10) ? 1 : 0; + parit5c = (paritc & 0x20) ? 1 : 0; + parit6c = (paritc & 0x40) ? 1 : 0; + parit7c = (paritc & 0x80) ? 1 : 0; + parit1_2 = parit6c ^ parit4c ^ parit2c ^ parit0c; + parit1_1 = parit7c ^ parit5c ^ parit3c ^ parit1c; + parit2_2 = parit5c ^ parit4c ^ parit1c ^ parit0c; + parit2_1 = parit7c ^ parit6c ^ parit3c ^ parit2c; + parit4_2 = parit3c ^ parit2c ^ parit1c ^ parit0c; + parit4_1 = parit7c ^ parit6c ^ parit5c ^ parit4c; + + paritr_ptr = paritr; + for (i = 0; i < 256; ++i, ++paritr_ptr) + { + sum ^= *paritr_ptr; + } + + paritr_ptr = paritr; + for (i = 0; i < 256; i += 2, paritr_ptr += 2) + { + parit8_2 ^= *paritr_ptr; + } + + paritr_ptr = paritr; + for (i = 0; i < 256; i += 4, paritr_ptr += 4) + { + parit16_2 ^= *paritr_ptr; + parit16_2 ^= *(paritr_ptr + 1); + } + + paritr_ptr = paritr; + for (i = 0; i < 256; i += 8, paritr_ptr += 8) + { + for (j = 0; j <= 3; ++j) + { + parit32_2 ^= *(paritr_ptr + j); + } + } + + paritr_ptr = paritr; + for (i = 0; i < 256; i += 16, paritr_ptr += 16) + { + for (j = 0; j <= 7; ++j) + { + parit64_2 ^= *(paritr_ptr + j); + } + } + + paritr_ptr = paritr; + for (i = 0; i < 256; i += 32, paritr_ptr += 32) + { + for (j = 0; j <= 15; ++j) + { + parit128_2 ^= *(paritr_ptr + j); + } + } + + paritr_ptr = paritr; + for (i = 0; i < 256; i += 64, paritr_ptr += 64) + { + for (j = 0; j <= 31; ++j) + { + parit256_2 ^= *(paritr_ptr + j); + } + } + + paritr_ptr = paritr; + for (i = 0; i < 256; i += 128, paritr_ptr += 128) + { + for (j = 0; j <= 63; ++j) + { + parit512_2 ^= *(paritr_ptr + j); + } + } + + paritr_ptr = paritr; + for (i = 0; i < 256; i += 256, paritr_ptr += 256) + { + for (j = 0; j <= 127; ++j) + { + parit1024_2 ^= *(paritr_ptr + j); + } + } + + if (sum==0) + { + parit1024_1 = parit1024_2; + parit512_1 = parit512_2; + parit256_1 = parit256_2; + parit128_1 = parit128_2; + parit64_1 = parit64_2; + parit32_1 = parit32_2; + parit16_1 = parit16_2; + parit8_1 = parit8_2; + } + else + { + parit1024_1 = parit1024_2 ? 0 : 1; + parit512_1 = parit512_2 ? 0 : 1; + parit256_1 = parit256_2 ? 0 : 1; + parit128_1 = parit128_2 ? 0 : 1; + parit64_1 = parit64_2 ? 0 : 1; + parit32_1 = parit32_2 ? 0 : 1; + parit16_1 = parit16_2 ? 0 : 1; + parit8_1 = parit8_2 ? 0 : 1; + } + + parit1_2 <<= 2; + parit1_1 <<= 3; + parit2_2 <<= 4; + parit2_1 <<= 5; + parit4_2 <<= 6; + parit4_1 <<= 7; + parit128_1 <<= 1; + parit256_2 <<= 2; + parit256_1 <<= 3; + parit512_2 <<= 4; + parit512_1 <<= 5; + parit1024_2 <<= 6; + parit1024_1 <<= 7; + parit8_1 <<= 1; + parit16_2 <<= 2; + parit16_1 <<= 3; + parit32_2 <<= 4; + parit32_1 <<= 5; + parit64_2 <<= 6; + parit64_1 <<= 7; + + p_ecc[0] = ~(parit64_1 | parit64_2 | parit32_1 | parit32_2 | parit16_1 | parit16_2 | parit8_1 | parit8_2); + p_ecc[1] = ~(parit1024_1 |parit1024_2 | parit512_1 | parit512_2 | parit256_1 | parit256_2 | parit128_1 | parit128_2); + p_ecc[2] = ~(parit4_1 | parit4_2 | parit2_1 | parit2_2 | parit1_1 | parit1_2); + + return 0; +} + +/* smc_write -- + * write stub +*/ +static int smc_write(blkdev_request *req) +{ + req->req_done(req->done_arg, RTEMS_SUCCESSFUL, 0); + return 0; +} + + +/* smc_read -- + * PARAMETERS: + * req - pointer to the READ block device request info + * + * RETURNS: + * ioctl return value + */ +static int +smc_read(blkdev_request *req) +{ + uint32_t i; + blkdev_sg_buffer *sg; + uint32_t remains; + + remains = smc_info.bytes_per_page * req->count; + sg = req->bufs; + for (i = 0; (remains > 0) && (i < req->bufnum); i++, sg++) + { + int count = sg->length; + if (count > remains) + count = remains; + smc_read_page(req->start,sg->buffer); + remains -= count; + } + req->req_done(req->done_arg, RTEMS_SUCCESSFUL, 0); + return 0; +} + +/* smc_ioctl -- + * IOCTL handler for SMC device. + * + * PARAMETERS: + * dev - device number (major, minor number) + * req - IOCTL request code + * argp - IOCTL argument + * + * RETURNS: + * IOCTL return value + */ +static int +smc_ioctl(dev_t dev, uint32_t req, void *argp) +{ + switch (req) + { + case BLKIO_REQUEST: + { + blkdev_request *r = argp; + switch (r->req) + { + case BLKDEV_REQ_READ: + return smc_read(r); + case BLKDEV_REQ_WRITE: + return smc_write(r); + default: + errno = EBADRQC; + return -1; + } + break; + } + + default: + errno = EBADRQC; + return -1; + } +} + +/* smc_initialize -- + * RAM disk device driver initialization. Run through RAM disk + * configuration information and configure appropriate RAM disks. + * + * PARAMETERS: + * major - RAM disk major device number + * minor - minor device number, not applicable + * arg - initialization argument, not applicable + * + * RETURNS: + * none + */ +rtems_device_driver +smc_initialize( + rtems_device_major_number major, + rtems_device_minor_number minor, + void *arg) +{ + rtems_status_code rc; + dev_t dev; + uint32_t block_num; + + rc = rtems_disk_io_initialize(); + if (rc != RTEMS_SUCCESSFUL) + return rc; + + smc_init(); + block_num = smc_info.blocks << 5; + + dev = rtems_filesystem_make_dev_t(major, 0); + rc = rtems_disk_create_phys(dev, 512, block_num, + smc_ioctl, SMC_DEVICE_NAME); + + return RTEMS_SUCCESSFUL; +} diff --git a/c/src/lib/libbsp/arm/gp32/smc/smc.h b/c/src/lib/libbsp/arm/gp32/smc/smc.h new file mode 100644 index 0000000000..6088caddd7 --- /dev/null +++ b/c/src/lib/libbsp/arm/gp32/smc/smc.h @@ -0,0 +1,28 @@ +#ifndef __SMC_H__ +#define __SMC_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#include "rtems/blkdev.h" + +/* smc_initialize -- + * SMC disk driver initialization entry point. + */ +rtems_device_driver +smc_initialize( + rtems_device_major_number major, + rtems_device_minor_number minor, + void *arg); + +#define SMC_DRIVER_TABLE_ENTRY \ + { smc_initialize, GENERIC_BLOCK_DEVICE_DRIVER_ENTRIES } + +#ifdef __cplusplus +} +#endif + +#endif -- cgit v1.2.3