Hello? I fixed miscalculated total sectors when using reserve area feature.
Also I changed CONFIG_MG_DISK_RES's unit to KB. (Byte is too small and also needs sector size alignment.) Any comments will be appreciated. Signed-off-by: unsik Kim <donar...@gmail.com> --- common/Makefile | 2 + common/cmd_mgdisk.c | 76 +++++ common/cmd_nvedit.c | 8 +- common/env_mgdisk.c | 90 ++++++ disk/part.c | 8 +- disk/part_amiga.c | 5 +- disk/part_dos.c | 1 + disk/part_efi.c | 1 + disk/part_iso.c | 1 + disk/part_mac.c | 1 + doc/README.mflash | 93 +++++++ drivers/block/Makefile | 5 +- drivers/block/mg_disk.c | 635 +++++++++++++++++++++++++++++++++++++++++++ drivers/block/mg_disk_prv.h | 140 ++++++++++ fs/fat/fat.c | 2 + include/config_cmd_all.h | 1 + include/environment.h | 12 + include/mg_disk.h | 51 ++++ include/part.h | 1 + 19 files changed, 1125 insertions(+), 8 deletions(-) diff --git a/common/Makefile b/common/Makefile index 93e3963..3a85c2a 100644 --- a/common/Makefile +++ b/common/Makefile @@ -53,6 +53,7 @@ COBJS-$(CONFIG_ENV_IS_IN_DATAFLASH) += env_dataflash.o COBJS-$(CONFIG_ENV_IS_IN_EEPROM) += env_eeprom.o COBJS-y += env_embedded.o COBJS-$(CONFIG_ENV_IS_IN_FLASH) += env_flash.o +COBJS-$(CONFIG_ENV_IS_IN_MG_DISK) += env_mgdisk.o COBJS-$(CONFIG_ENV_IS_IN_NAND) += env_nand.o COBJS-$(CONFIG_ENV_IS_IN_NVRAM) += env_nvram.o COBJS-$(CONFIG_ENV_IS_IN_ONENAND) += env_onenand.o @@ -104,6 +105,7 @@ COBJS-$(CONFIG_LOGBUFFER) += cmd_log.o COBJS-$(CONFIG_ID_EEPROM) += cmd_mac.o COBJS-$(CONFIG_CMD_MEMORY) += cmd_mem.o COBJS-$(CONFIG_CMD_MFSL) += cmd_mfsl.o +COBJS-$(CONFIG_CMD_MG_DISK) += cmd_mgdisk.o COBJS-$(CONFIG_MII) += miiphyutil.o COBJS-$(CONFIG_CMD_MII) += miiphyutil.o COBJS-$(CONFIG_CMD_MII) += cmd_mii.o diff --git a/common/cmd_mgdisk.c b/common/cmd_mgdisk.c new file mode 100644 index 0000000..f2f5061 --- /dev/null +++ b/common/cmd_mgdisk.c @@ -0,0 +1,76 @@ +/* + * (C) Copyright 2009 mGine co. + * unsik Kim <donar...@gmail.com> + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include <common.h> +#include <command.h> + +#if defined (CONFIG_CMD_MG_DISK) + +#include <mg_disk.h> + +int do_mg_disk_cmd (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) +{ + u32 from, to, size; + + switch (argc) { + case 2: + if (!strcmp(argv[1], "init")) + mg_disk_init(); + else + return 1; + break; + case 4: + from = simple_strtoul(argv[2], NULL, 0); + to = simple_strtoul(argv[3], NULL, 0); + size = simple_strtoul(argv[4], NULL, 0); + + if (!strcmp(argv[1], "read")) + mg_disk_read(from, (u8 *)to, size); + else if (!strcmp(argv[1], "write")) + mg_disk_write(to, (u8 *)from, size); + else if (!strcmp(argv[1], "readsec")) + mg_disk_read_sects((void *)to, from, size); + else if (!strcmp(argv[1], "writesec")) + mg_disk_write_sects((void *)from, to, size); + else + return 1; + break; + default: + printf("Usage:\n%s\n", cmdtp->usage); + return 1; + } + return 0; +} + +U_BOOT_CMD( + mgd, 5, 0, do_mg_disk_cmd, + "mgd - mgine m[g]flash command\n", + ": mgine mflash IO mode (disk) command\n" + " - initialize : mgd init\n" + " - random read : mgd read [from] [to] [size]\n" + " - random write : mgd write [from] [to] [size]\n" + " - sector read : mgd readsec [sector] [to] [counts]\n" + " - sector write : mgd writesec [from] [sector] [counts]\n" +); + +#endif diff --git a/common/cmd_nvedit.c b/common/cmd_nvedit.c index 1fcb4c9..649b23d 100644 --- a/common/cmd_nvedit.c +++ b/common/cmd_nvedit.c @@ -52,15 +52,17 @@ DECLARE_GLOBAL_DATA_PTR; -#if !defined(CONFIG_ENV_IS_IN_NVRAM) && \ - !defined(CONFIG_ENV_IS_IN_EEPROM) && \ +#if !defined(CONFIG_ENV_IS_IN_EEPROM) && \ !defined(CONFIG_ENV_IS_IN_FLASH) && \ !defined(CONFIG_ENV_IS_IN_DATAFLASH) && \ + !defined(CONFIG_ENV_IS_IN_MG_DISK) && \ !defined(CONFIG_ENV_IS_IN_NAND) && \ + !defined(CONFIG_ENV_IS_IN_NVRAM) && \ !defined(CONFIG_ENV_IS_IN_ONENAND) && \ !defined(CONFIG_ENV_IS_IN_SPI_FLASH) && \ !defined(CONFIG_ENV_IS_NOWHERE) -# error Define one of CONFIG_ENV_IS_IN_{NVRAM|EEPROM|FLASH|DATAFLASH|ONENAND|SPI_FLASH|NOWHERE} +# error Define one of CONFIG_ENV_IS_IN_{EEPROM|FLASH|DATAFLASH|ONENAND|\ +SPI_FLASH|MG_DISK|NVRAM|NOWHERE} #endif #define XMK_STR(x) #x diff --git a/common/env_mgdisk.c b/common/env_mgdisk.c new file mode 100644 index 0000000..2b4949f --- /dev/null +++ b/common/env_mgdisk.c @@ -0,0 +1,90 @@ +/* + * (C) Copyright 2009 mGine co. + * unsik Kim <donar...@gmail.com> + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include <common.h> +#include <command.h> +#include <environment.h> +#include <linux/stddef.h> +#include <mg_disk.h> + +/* references to names in env_common.c */ +extern uchar default_environment[]; +extern int default_environment_size; + +char * env_name_spec = "MG_DISK"; + +env_t *env_ptr = 0; + +DECLARE_GLOBAL_DATA_PTR; + +uchar env_get_char_spec(int index) +{ + return (*((uchar *) (gd->env_addr + index))); +} + +void env_relocate_spec(void) +{ + unsigned int err; + + err = mg_disk_init(); + if (err) { + puts ("*** Warning - mg_disk_init error"); + goto OUT; + } + err = mg_disk_read(CONFIG_ENV_ADDR, (u_char *)env_ptr, CONFIG_ENV_SIZE); + if (err) { + puts ("*** Warning - mg_disk_read error"); + goto OUT; + } + + if (crc32(0, env_ptr->data, ENV_SIZE) != env_ptr->crc) { + puts ("*** Warning - CRC error"); + goto OUT; + } + + return; + +OUT: + printf (", using default environment\n\n"); + set_default_env(); +} + +int saveenv(void) +{ + unsigned int err; + env_ptr->crc = crc32(0, env_ptr->data, ENV_SIZE); + err = mg_disk_write(CONFIG_ENV_ADDR, (u_char *)env_ptr, + CONFIG_ENV_SIZE); + if (err) + puts ("*** Warning - mg_disk_write error\n\n"); + return err; +} + +int env_init(void) +{ + /* use default */ + gd->env_addr = (ulong) & default_environment[0]; + gd->env_valid = 1; + + return 0; +} diff --git a/disk/part.c b/disk/part.c index e353cee..fe299c7 100644 --- a/disk/part.c +++ b/disk/part.c @@ -35,6 +35,7 @@ #endif #if (defined(CONFIG_CMD_IDE) || \ + defined(CONFIG_CMD_MG_DISK) || \ defined(CONFIG_CMD_SATA) || \ defined(CONFIG_CMD_SCSI) || \ defined(CONFIG_CMD_USB) || \ @@ -65,6 +66,9 @@ static const struct block_drvr block_drvr[] = { #if defined(CONFIG_SYSTEMACE) { .name = "ace", .get_dev = systemace_get_dev, }, #endif +#if defined(CONFIG_CMD_MG_DISK) + { .name = "mgd", .get_dev = mg_disk_get_dev, }, +#endif { }, }; @@ -91,6 +95,7 @@ block_dev_desc_t *get_dev(char* ifname, int dev) #endif #if (defined(CONFIG_CMD_IDE) || \ + defined(CONFIG_CMD_MG_DISK) || \ defined(CONFIG_CMD_SATA) || \ defined(CONFIG_CMD_SCSI) || \ defined(CONFIG_CMD_USB) || \ @@ -203,11 +208,12 @@ void dev_print (block_dev_desc_t *dev_desc) #endif #if (defined(CONFIG_CMD_IDE) || \ + defined(CONFIG_CMD_MG_DISK) || \ defined(CONFIG_CMD_SATA) || \ defined(CONFIG_CMD_SCSI) || \ defined(CONFIG_CMD_USB) || \ defined(CONFIG_MMC) || \ - defined(CONFIG_SYSTEMACE) ) + defined(CONFIG_SYSTEMACE) ) #if defined(CONFIG_MAC_PARTITION) || \ defined(CONFIG_DOS_PARTITION) || \ diff --git a/disk/part_amiga.c b/disk/part_amiga.c index 6c3d748..6f25173 100644 --- a/disk/part_amiga.c +++ b/disk/part_amiga.c @@ -27,6 +27,7 @@ #include "part_amiga.h" #if (defined(CONFIG_CMD_IDE) || \ + defined(CONFIG_CMD_MG_DISK) || \ defined(CONFIG_CMD_SCSI) || \ defined(CONFIG_CMD_USB) || \ defined(CONFIG_MMC) || \ @@ -154,7 +155,7 @@ struct rigid_disk_block *get_rdisk(block_dev_desc_t *dev_desc) s = getenv("amiga_scanlimit"); if (s) - limit = atoi(s); + limit = simple_strtoul(s, NULL, 10); else limit = AMIGA_BLOCK_LIMIT; @@ -195,7 +196,7 @@ struct bootcode_block *get_bootcode(block_dev_desc_t *dev_desc) s = getenv("amiga_scanlimit"); if (s) - limit = atoi(s); + limit = simple_strtoul(s, NULL, 10); else limit = AMIGA_BLOCK_LIMIT; diff --git a/disk/part_dos.c b/disk/part_dos.c index 4d778ec..845cdb6 100644 --- a/disk/part_dos.c +++ b/disk/part_dos.c @@ -36,6 +36,7 @@ #include "part_dos.h" #if (defined(CONFIG_CMD_IDE) || \ + defined(CONFIG_CMD_MG_DISK) || \ defined(CONFIG_CMD_SATA) || \ defined(CONFIG_CMD_SCSI) || \ defined(CONFIG_CMD_USB) || \ diff --git a/disk/part_efi.c b/disk/part_efi.c index d8a8111..4cf79fb 100644 --- a/disk/part_efi.c +++ b/disk/part_efi.c @@ -37,6 +37,7 @@ #include "part_efi.h" #if (defined(CONFIG_CMD_IDE) || \ + defined(CONFIG_CMD_MG_DISK) || \ defined(CONFIG_CMD_SATA) || \ defined(CONFIG_CMD_SCSI) || \ defined(CONFIG_CMD_USB) || \ diff --git a/disk/part_iso.c b/disk/part_iso.c index 72ff868..8348ce8 100644 --- a/disk/part_iso.c +++ b/disk/part_iso.c @@ -26,6 +26,7 @@ #include "part_iso.h" #if (defined(CONFIG_CMD_IDE) || \ + defined(CONFIG_CMD_MG_DISK) || \ defined(CONFIG_CMD_SCSI) || \ defined(CONFIG_CMD_SATA) || \ defined(CONFIG_CMD_USB) || \ diff --git a/disk/part_mac.c b/disk/part_mac.c index 1922fe5..fce4cc7 100644 --- a/disk/part_mac.c +++ b/disk/part_mac.c @@ -35,6 +35,7 @@ #include "part_mac.h" #if (defined(CONFIG_CMD_IDE) || \ + defined(CONFIG_CMD_MG_DISK) || \ defined(CONFIG_CMD_SCSI) || \ defined(CONFIG_CMD_SATA) || \ defined(CONFIG_CMD_USB) || \ diff --git a/doc/README.mflash b/doc/README.mflash new file mode 100644 index 0000000..d0d0f7b --- /dev/null +++ b/doc/README.mflash @@ -0,0 +1,93 @@ + +This document describes m[g]flash support in u-boot. + +Contents + 1. Overview + 2. Porting mflash driver + 3. Mflash command + 4. Misc. + +1. Overview +Mflash and gflash are embedded flash drive. The only difference is mflash is +MCP(Multi Chip Package) device. These two device operate exactly same way. +So the rest mflash repersents mflash and gflash altogether. + +2. Porting mflash driver + +2-1. Board configuration +* Mflash driver support +#define CONFIG_CMD_MG_DISK + +* Environment variable support (optional) +#define CONFIG_ENV_IS_IN_MG_DISK +Also CONFIG_ENV_ADDR and CONFIG_ENV_SIZE should be defined. +CONFIG_ENV_ADDR is byte offset starting from 0. + +Following example sets environment variable location to 0x80000 (1024'th +sector) and size of 0x400 (1024 byte) +#define CONFIG_ENV_ADDR 0x80000 +#define CONFIG_ENV_SIZE 0x400 + +* Reserved size config (optional) +If you want to use some reserved area for bootloader, environment variable or +whatever, use CONFIG_MG_DISK_RES. The unit is KB. Mflash's block operation +method use this value as start offset. So any u-boot's partition table parser +and file system command work consistently. You can access this area by using +mflash command. + +Following example sets 10MB of reserved area. +#define CONFIG_MG_DISK_RES 10240 + +2-2. Porting mg_get_drv_data function +Mflash is active device and need some gpio control for proper operation. +This board dependency resolved by using mg_get_drv_data function. +Port this function at your board init file. See include/mg_disk.h + +Here is some pseudo example. + +static void custom_hdrst_pin (u8 level) +{ + if (level) + /* set hard reset pin to high */ + else + /* set hard reset pin to low */ +} + +static void custom_ctrl_pin_init (void) +{ + /* Set hard reset, write protect, deep power down pins + * to gpio. + * Set these pins to output high + */ +} + +struct mg_drv_data* mg_get_drv_data (void) +{ + static struct mg_drv_data prv; + + prv.base = /* base address of mflash */ + prv.mg_ctrl_pin_init = custom_ctrl_pin_init; + prv.mg_hdrst_pin = custom_hdrst_pin; + + return &prv; +} + +3. Mflash command + +* initialize : mgd init +* random read : mgd read [from] [to] [size] + ex) read 256 bytes from 0x300000 of mflash to 0xA0100000 of host memory + mgd read 0x300000 0xA0100000 256 +* random write : mgd write [from] [to] [size] +* sector read : mgd readsec [sector] [to] [count] + ex) read 10 sectors starts from 400 sector to 0xA0100000 + mgd readsec 400 0xA0100000 10 +* sector write : mgd writesec [from] [sector] [count] + +4. Misc. +Mflash's device interface name for block driver is "mgd". +Here is ext2 file system access example. + + mgd init + ext2ls mgd 0:1 /boot + ext2load mgd 0:1 0xa0010000 /boot/uImage 1954156 diff --git a/drivers/block/Makefile b/drivers/block/Makefile index 59388d9..eccefc1 100644 --- a/drivers/block/Makefile +++ b/drivers/block/Makefile @@ -25,13 +25,14 @@ include $(TOPDIR)/config.mk LIB := $(obj)libblock.a -COBJS-$(CONFIG_SCSI_AHCI) += ahci.o COBJS-$(CONFIG_ATA_PIIX) += ata_piix.o +COBJS-$(CONFIG_CMD_MG_DISK) += mg_disk.o COBJS-$(CONFIG_FSL_SATA) += fsl_sata.o +COBJS-$(CONFIG_IDE_SIL680) += sil680.o COBJS-$(CONFIG_LIBATA) += libata.o COBJS-$(CONFIG_PATA_BFIN) += pata_bfin.o COBJS-$(CONFIG_SATA_SIL3114) += sata_sil3114.o -COBJS-$(CONFIG_IDE_SIL680) += sil680.o +COBJS-$(CONFIG_SCSI_AHCI) += ahci.o COBJS-$(CONFIG_SCSI_SYM53C8XX) += sym53c8xx.o COBJS-$(CONFIG_SYSTEMACE) += systemace.o diff --git a/drivers/block/mg_disk.c b/drivers/block/mg_disk.c new file mode 100644 index 0000000..193a441 --- /dev/null +++ b/drivers/block/mg_disk.c @@ -0,0 +1,635 @@ +/* + * (C) Copyright 2009 mGine co. + * unsik Kim <donar...@gmail.com> + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include <common.h> +#include <malloc.h> +#include <part.h> +#include <ata.h> +#include <asm/io.h> +#include "mg_disk_prv.h" + +#ifdef CONFIG_CMD_MG_DISK + +#ifndef CONFIG_MG_DISK_RES +#define CONFIG_MG_DISK_RES 0 +#endif + +#define MG_RES_SEC ((CONFIG_MG_DISK_RES) << 1) + +#define MG_BASE (host.drv_data->base) + +static struct mg_host host; + +static block_dev_desc_t mg_disk_dev = { + .if_type = IF_TYPE_ATAPI, + .part_type = PART_TYPE_UNKNOWN, + .type = DEV_TYPE_HARDDISK, + .blksz = MG_SECTOR_SIZE, + .priv = &host }; + +static void mg_dump_status (const char *msg, unsigned int stat, unsigned err) +{ + char *name = MG_DEV_NAME; + + printf("%s: %s: status=0x%02x { ", name, msg, stat & 0xff); + if (stat & MG_REG_STATUS_BIT_BUSY) + printf("Busy "); + if (stat & MG_REG_STATUS_BIT_READY) + printf("DriveReady "); + if (stat & MG_REG_STATUS_BIT_WRITE_FAULT) + printf("WriteFault "); + if (stat & MG_REG_STATUS_BIT_SEEK_DONE) + printf("SeekComplete "); + if (stat & MG_REG_STATUS_BIT_DATA_REQ) + printf("DataRequest "); + if (stat & MG_REG_STATUS_BIT_CORRECTED_ERROR) + printf("CorrectedError "); + if (stat & MG_REG_STATUS_BIT_ERROR) + printf("Error "); + printf("}\n"); + + if ((stat & MG_REG_STATUS_BIT_ERROR)) { + printf("%s: %s: error=0x%02x { ", name, msg, err & 0xff); + if (err & MG_REG_ERR_BBK) + printf("BadSector "); + if (err & MG_REG_ERR_UNC) + printf("UncorrectableError "); + if (err & MG_REG_ERR_IDNF) + printf("SectorIdNotFound "); + if (err & MG_REG_ERR_ABRT) + printf("DriveStatusError "); + if (err & MG_REG_ERR_AMNF) + printf("AddrMarkNotFound "); + printf("}\n"); + } +} + +#if CONFIG_SYS_HZ == 1000 +#define msecs_to_hz(s) (s) +#else +static unsigned int msecs_to_hz (u32 msec) +{ + u32 hz = CONFIG_SYS_HZ / 1000 * msec; + + if (!hz) + hz = 1; + + return hz; +} +#endif + +/* + * copy src to dest, skipping leading and trailing blanks and null + * terminate the string + * "len" is the size of available memory including the terminating '\0' + */ +static void mg_ident_cpy (unsigned char *dst, unsigned char *src, + unsigned int len) +{ + unsigned char *end, *last; + + last = dst; + end = src + len - 1; + + /* reserve space for '\0' */ + if (len < 2) + goto OUT; + + /* skip leading white space */ + while ((*src) && (src<end) && (*src==' ')) + ++src; + + /* copy string, omitting trailing white space */ + while ((*src) && (src<end)) { + *dst++ = *src; + if (*src++ != ' ') + last = dst; + } +OUT: + *last = '\0'; +} + +static unsigned int mg_wait (u32 expect, u32 msec) +{ + u8 status; + u32 from, cur, expire, err; + + err = MG_ERR_NONE; + reset_timer(); + from = get_timer(0); + expire = msecs_to_hz(msec); + + status = readb(MG_BASE + MG_REG_STATUS); + do { + cur = get_timer(from); + if (status & MG_REG_STATUS_BIT_BUSY) { + if (expect == MG_REG_STATUS_BIT_BUSY) + break; + } else { + /* Check the error condition! */ + if (status & MG_REG_STATUS_BIT_ERROR) { + err = readb(MG_BASE + MG_REG_ERROR); + mg_dump_status("mg_wait", status, err); + break; + } + + if (expect == MG_STAT_READY) + if (MG_READY_OK(status)) + break; + + if (expect == MG_REG_STATUS_BIT_DATA_REQ) + if (status & MG_REG_STATUS_BIT_DATA_REQ) + break; + } + status = readb(MG_BASE + MG_REG_STATUS); + } while (cur < expire); + + if (cur >= expire) + err = MG_ERR_TIMEOUT; + + return err; +} + +static int mg_get_disk_id (void) +{ + u32 iobuf[(MG_SECTOR_SIZE / sizeof(u32))]; + hd_driveid_t *iop = (hd_driveid_t *)iobuf; + u32 i, err, res; + u16 *buff = (u16 *)iobuf; + + writeb(MG_CMD_ID, MG_BASE + MG_REG_COMMAND); + err = mg_wait(MG_REG_STATUS_BIT_DATA_REQ, 3000); + if (err) + return err; + + for(i = 0; i < (MG_SECTOR_SIZE / sizeof(u32)) >> 1; i++) + buff[i] = readw(MG_BASE + MG_BUFF_OFFSET + i * 2); + + writeb(MG_CMD_RD_CONF, MG_BASE + MG_REG_COMMAND); + err = mg_wait(MG_STAT_READY, 3000); + if (err) + return err; + + if((iop->field_valid & 1) == 0) + return MG_ERR_TRANSLATION; + + mg_ident_cpy((unsigned char*)mg_disk_dev.revision, iop->fw_rev, + sizeof(mg_disk_dev.revision)); + mg_ident_cpy((unsigned char*)mg_disk_dev.vendor, iop->model, + sizeof(mg_disk_dev.vendor)); + mg_ident_cpy((unsigned char*)mg_disk_dev.product, iop->serial_no, + sizeof(mg_disk_dev.product)); +#ifdef __LITTLE_ENDIAN + /* + * firmware revision, model, and serial number have Big Endian Byte + * order in Word. Convert all three to little endian. + * + * See CF+ and CompactFlash Specification Revision 2.0: + * 6.2.1.6: Identify Drive, Table 39 for more details + */ + + strswab(mg_disk_dev.revision); + strswab(mg_disk_dev.vendor); + strswab(mg_disk_dev.product); +#endif /* __LITTLE_ENDIAN */ + +#ifdef __BIG_ENDIAN + iop->lba_capacity = (iop->lba_capacity << 16) | + (iop->lba_capacity >> 16); +#endif /* __BIG_ENDIAN */ + + if (MG_RES_SEC) { + MG_DBG("MG_RES_SEC=%d\n", MG_RES_SEC); + iop->cyls = (iop->lba_capacity - MG_RES_SEC) / + iop->sectors / iop->heads; + res = iop->lba_capacity - + iop->cyls * iop->heads * iop->sectors; + iop->lba_capacity -= res; + printf("mg_disk: %d sectors reserved\n", res); + } + + mg_disk_dev.lba = iop->lba_capacity; + return MG_ERR_NONE; +} + +static int mg_disk_reset (void) +{ + struct mg_drv_data *prv_data = host.drv_data; + s32 err; + u8 init_status; + + /* hdd rst low */ + prv_data->mg_hdrst_pin(0); + err = mg_wait(MG_REG_STATUS_BIT_BUSY, 300); + if(err) + return err; + + /* hdd rst high */ + prv_data->mg_hdrst_pin(1); + err = mg_wait(MG_STAT_READY, 3000); + if(err) + return err; + + /* soft reset on */ + writeb(MG_REG_CTRL_RESET | MG_REG_CTRL_INTR_DISABLE, + MG_BASE + MG_REG_DRV_CTRL); + err = mg_wait(MG_REG_STATUS_BIT_BUSY, 3000); + if(err) + return err; + + /* soft reset off */ + writeb(MG_REG_CTRL_INTR_DISABLE, MG_BASE + MG_REG_DRV_CTRL); + err = mg_wait(MG_STAT_READY, 3000); + if(err) + return err; + + init_status = readb(MG_BASE + MG_REG_STATUS) & 0xf; + + if (init_status == 0xf) + return MG_ERR_INIT_STAT; + + return err; +} + + +static unsigned int mg_out(unsigned int sect_num, + unsigned int sect_cnt, + unsigned int cmd) +{ + u32 err = MG_ERR_NONE; + + if ((err = mg_wait(MG_STAT_READY, 3000))) { + return err; + } + + writeb((u8)sect_cnt, MG_BASE + MG_REG_SECT_CNT); + writeb((u8)sect_num, MG_BASE + MG_REG_SECT_NUM); + writeb((u8)(sect_num >> 8), MG_BASE + MG_REG_CYL_LOW); + writeb((u8)(sect_num >> 16), MG_BASE + MG_REG_CYL_HIGH); + writeb((u8)((sect_num >> 24) | MG_REG_HEAD_LBA_MODE), + MG_BASE + MG_REG_DRV_HEAD); + writeb(cmd, MG_BASE + MG_REG_COMMAND); + return err; +} + +static unsigned int mg_do_read_sects(void *buff, u32 sect_num, u32 sect_cnt) +{ + u32 i, j, err; + u8 *buff_ptr = buff; + + err = mg_out(sect_num, sect_cnt, MG_CMD_RD); + if (err) + return err; + + for (i = 0; i < sect_cnt; i++) { + err = mg_wait(MG_REG_STATUS_BIT_DATA_REQ, 3000); + if (err) + return err; + + /* TODO : u16 unaligned case */ + for(j = 0; j < MG_SECTOR_SIZE >> 1; j++) { + *(u16 *)buff_ptr = + readw(MG_BASE + MG_BUFF_OFFSET + (j << 1)); + buff_ptr += 2; + } + + writeb(MG_CMD_RD_CONF, MG_BASE + MG_REG_COMMAND); + + MG_DBG("%u (0x%8.8x) sector read", sect_num + i, + (sect_num + i) * MG_SECTOR_SIZE); + } + + return err; +} + +unsigned int mg_disk_read_sects(void *buff, u32 sect_num, u32 sect_cnt) +{ + u32 quotient, residue, i, err; + u8 *buff_ptr = buff; + + quotient = sect_cnt >> 8; + residue = sect_cnt % 256; + + for (i = 0; i < quotient; i++) { + MG_DBG("sect num : %u buff : 0x%8.8x", sect_num, (u32)buff_ptr); + err = mg_do_read_sects(buff_ptr, sect_num, 256); + if (err) + return err; + sect_num += 256; + buff_ptr += 256 * MG_SECTOR_SIZE; + } + + if (residue) { + MG_DBG("sect num : %u buff : %8.8x", sect_num, (u32)buff_ptr); + err = mg_do_read_sects(buff_ptr, sect_num, residue); + } + + return err; +} + +unsigned long mg_block_read (int dev, unsigned long start, + lbaint_t blkcnt, void *buffer) +{ + start += MG_RES_SEC; + if (! mg_disk_read_sects(buffer, start, blkcnt)) + return blkcnt; + else + return 0; +} + +unsigned int mg_disk_read (u32 addr, u8 *buff, u32 len) +{ + u8 *sect_buff, *buff_ptr = buff; + u32 cur_addr, next_sec_addr, end_addr, cnt, sect_num; + u32 err = MG_ERR_NONE; + + /* TODO : sanity chk */ + cnt = 0; + cur_addr = addr; + end_addr = addr + len; + + sect_buff = malloc(MG_SECTOR_SIZE); + + if (cur_addr & MG_SECTOR_SIZE_MASK) { + next_sec_addr = (cur_addr + MG_SECTOR_SIZE) & + ~MG_SECTOR_SIZE_MASK; + sect_num = cur_addr >> MG_SECTOR_SIZE_SHIFT; + err = mg_disk_read_sects(sect_buff, sect_num, 1); + if (err) + goto mg_read_exit; + + if (end_addr < next_sec_addr) { + memcpy(buff_ptr, + sect_buff + (cur_addr & MG_SECTOR_SIZE_MASK), + end_addr - cur_addr); + MG_DBG("copies %u byte from sector offset 0x%8.8x", + end_addr - cur_addr, cur_addr); + cur_addr = end_addr; + } else { + memcpy(buff_ptr, + sect_buff + (cur_addr & MG_SECTOR_SIZE_MASK), + next_sec_addr - cur_addr); + MG_DBG("copies %u byte from sector offset 0x%8.8x", + next_sec_addr - cur_addr, cur_addr); + buff_ptr += (next_sec_addr - cur_addr); + cur_addr = next_sec_addr; + } + } + + if (cur_addr < end_addr) { + sect_num = cur_addr >> MG_SECTOR_SIZE_SHIFT; + next_sec_addr = cur_addr + MG_SECTOR_SIZE; + + while (next_sec_addr <= end_addr) { + cnt++; + next_sec_addr += MG_SECTOR_SIZE; + } + + if (cnt) + err = mg_disk_read_sects(buff_ptr, sect_num, cnt); + if (err) + goto mg_read_exit; + + buff_ptr += cnt * MG_SECTOR_SIZE; + cur_addr += cnt * MG_SECTOR_SIZE; + + if (cur_addr < end_addr) { + sect_num = cur_addr >> MG_SECTOR_SIZE_SHIFT; + err = mg_disk_read_sects(sect_buff, sect_num, 1); + if (err) + goto mg_read_exit; + memcpy(buff_ptr, sect_buff, end_addr - cur_addr); + MG_DBG("copies %u byte", end_addr - cur_addr); + } + } + +mg_read_exit: + free(sect_buff); + + return err; +} + +static int mg_do_write_sects(void *buff, u32 sect_num, u32 sect_cnt) +{ + u32 i, j, err; + u8 *buff_ptr = buff; + + err = mg_out(sect_num, sect_cnt, MG_CMD_WR); + if (err) + return err; + + for (i = 0; i < sect_cnt; i++) { + err = mg_wait(MG_REG_STATUS_BIT_DATA_REQ, 3000); + if (err) + return err; + + /* TODO : u16 unaligned case */ + for(j = 0; j < MG_SECTOR_SIZE >> 1; j++) { + writew(*(u16 *)buff_ptr, + MG_BASE + MG_BUFF_OFFSET + (j << 1)); + buff_ptr += 2; + } + + writeb(MG_CMD_WR_CONF, MG_BASE + MG_REG_COMMAND); + + MG_DBG("%u (0x%8.8x) sector write", + sect_num + i, (sect_num + i) * MG_SECTOR_SIZE); + } + + return err; +} + +unsigned int mg_disk_write_sects(void *buff, u32 sect_num, u32 sect_cnt) +{ + u32 quotient, residue, i; + u32 err = MG_ERR_NONE; + u8 *buff_ptr = buff; + + quotient = sect_cnt >> 8; + residue = sect_cnt % 256; + + for (i = 0; i < quotient; i++) { + MG_DBG("sect num : %u buff : %8.8x", sect_num, (u32)buff_ptr); + err = mg_do_write_sects(buff_ptr, sect_num, 256); + if (err) + return err; + sect_num += 256; + buff_ptr += 256 * MG_SECTOR_SIZE; + } + + if (residue) { + MG_DBG("sect num : %u buff : %8.8x", sect_num, (u32)buff_ptr); + err = mg_do_write_sects(buff_ptr, sect_num, residue); + } + + return err; +} + +unsigned long mg_block_write (int dev, unsigned long start, + lbaint_t blkcnt, const void *buffer) +{ + start += MG_RES_SEC; + if (!mg_disk_write_sects((void *)buffer, start, blkcnt)) + return blkcnt; + else + return 0; +} + +unsigned int mg_disk_write(u32 addr, u8 *buff, u32 len) +{ + u8 *sect_buff, *buff_ptr = buff; + u32 cur_addr, next_sec_addr, end_addr, cnt, sect_num; + u32 err = MG_ERR_NONE; + + /* TODO : sanity chk */ + cnt = 0; + cur_addr = addr; + end_addr = addr + len; + + sect_buff = malloc(MG_SECTOR_SIZE); + + if (cur_addr & MG_SECTOR_SIZE_MASK) { + + next_sec_addr = (cur_addr + MG_SECTOR_SIZE) & + ~MG_SECTOR_SIZE_MASK; + sect_num = cur_addr >> MG_SECTOR_SIZE_SHIFT; + err = mg_disk_read_sects(sect_buff, sect_num, 1); + if (err) + goto mg_write_exit; + + if (end_addr < next_sec_addr) { + memcpy(sect_buff + (cur_addr & MG_SECTOR_SIZE_MASK), + buff_ptr, end_addr - cur_addr); + MG_DBG("copies %u byte to sector offset 0x%8.8x", + end_addr - cur_addr, cur_addr); + cur_addr = end_addr; + } else { + memcpy(sect_buff + (cur_addr & MG_SECTOR_SIZE_MASK), + buff_ptr, next_sec_addr - cur_addr); + MG_DBG("copies %u byte to sector offset 0x%8.8x", + next_sec_addr - cur_addr, cur_addr); + buff_ptr += (next_sec_addr - cur_addr); + cur_addr = next_sec_addr; + } + + err = mg_disk_write_sects(sect_buff, sect_num, 1); + if (err) + goto mg_write_exit; + } + + if (cur_addr < end_addr) { + + sect_num = cur_addr >> MG_SECTOR_SIZE_SHIFT; + next_sec_addr = cur_addr + MG_SECTOR_SIZE; + + while (next_sec_addr <= end_addr) { + cnt++; + next_sec_addr += MG_SECTOR_SIZE; + } + + if (cnt) + err = mg_disk_write_sects(buff_ptr, sect_num, cnt); + if (err) + goto mg_write_exit; + + buff_ptr += cnt * MG_SECTOR_SIZE; + cur_addr += cnt * MG_SECTOR_SIZE; + + if (cur_addr < end_addr) { + sect_num = cur_addr >> MG_SECTOR_SIZE_SHIFT; + err = mg_disk_read_sects(sect_buff, sect_num, 1); + if (err) + goto mg_write_exit; + memcpy(sect_buff, buff_ptr, end_addr - cur_addr); + MG_DBG("copies %u byte", end_addr - cur_addr); + err = mg_disk_write_sects(sect_buff, sect_num, 1); + } + + } + +mg_write_exit: + free(sect_buff); + + return err; +} + +block_dev_desc_t *mg_disk_get_dev(int dev) +{ + return ((block_dev_desc_t *) & mg_disk_dev); +} + +/* must override this function */ +struct mg_drv_data * __attribute__((weak)) mg_get_drv_data (void) +{ + puts ("### WARNING ### port mg_get_drv_data function\n"); + return NULL; +} + +unsigned int mg_disk_init (void) +{ + struct mg_drv_data *prv_data; + u32 err = MG_ERR_NONE; + + prv_data = mg_get_drv_data(); + if (! prv_data) { + printf("%s:%d fail (no driver_data)\n", __func__, __LINE__); + err = MG_ERR_NO_DRV_DATA; + return err; + } + + ((struct mg_host *)mg_disk_dev.priv)->drv_data = prv_data; + + /* init ctrl pin */ + if (prv_data->mg_ctrl_pin_init) + prv_data->mg_ctrl_pin_init(); + + if (! prv_data->mg_hdrst_pin) { + err = MG_ERR_CTRL_RST; + return err; + } + + /* disk reset */ + err = mg_disk_reset(); + if (err) { + printf("%s:%d fail (err code : %d)\n", __func__, __LINE__, err); + return err; + } + + /* get disk id */ + err = mg_get_disk_id(); + if (err) { + printf("%s:%d fail (err code : %d)\n", __func__, __LINE__, err); + return err; + } + + mg_disk_dev.block_read = mg_block_read; + mg_disk_dev.block_write = mg_block_write; + + init_part(&mg_disk_dev); + + dev_print(&mg_disk_dev); + + return err; +} + +#endif /* CONFIG_CMD_MG_DISK */ diff --git a/drivers/block/mg_disk_prv.h b/drivers/block/mg_disk_prv.h new file mode 100644 index 0000000..a6b7299 --- /dev/null +++ b/drivers/block/mg_disk_prv.h @@ -0,0 +1,140 @@ +/* + * (C) Copyright 2009 mGine co. + * unsik Kim <donar...@gmail.com> + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#ifndef __MG_DISK_PRV_H__ +#define __MG_DISK_PRV_H__ + +#include <mg_disk.h> + +/* name for block device */ +#define MG_DISK_NAME "mgd" +/* name for platform device */ +#define MG_DEV_NAME "mg_disk" + +#define MG_DISK_MAJ 240 +#define MG_DISK_MAX_PART 16 +#define MG_SECTOR_SIZE 512 +#define MG_SECTOR_SIZE_MASK (512 - 1) +#define MG_SECTOR_SIZE_SHIFT (9) +#define MG_MAX_SECTS 256 + +/* Register offsets */ +#define MG_BUFF_OFFSET 0x8000 +#define MG_STORAGE_BUFFER_SIZE 0x200 +#define MG_REG_OFFSET 0xC000 +#define MG_REG_FEATURE (MG_REG_OFFSET + 2) /* write case */ +#define MG_REG_ERROR (MG_REG_OFFSET + 2) /* read case */ +#define MG_REG_SECT_CNT (MG_REG_OFFSET + 4) +#define MG_REG_SECT_NUM (MG_REG_OFFSET + 6) +#define MG_REG_CYL_LOW (MG_REG_OFFSET + 8) +#define MG_REG_CYL_HIGH (MG_REG_OFFSET + 0xA) +#define MG_REG_DRV_HEAD (MG_REG_OFFSET + 0xC) +#define MG_REG_COMMAND (MG_REG_OFFSET + 0xE) /* write case */ +#define MG_REG_STATUS (MG_REG_OFFSET + 0xE) /* read case */ +#define MG_REG_DRV_CTRL (MG_REG_OFFSET + 0x10) +#define MG_REG_BURST_CTRL (MG_REG_OFFSET + 0x12) + +/* "Drive Select/Head Register" bit values */ +#define MG_REG_HEAD_MUST_BE_ON 0xA0 /* These 2 bits are always on */ +#define MG_REG_HEAD_DRIVE_MASTER (0x00 | MG_REG_HEAD_MUST_BE_ON) +#define MG_REG_HEAD_DRIVE_SLAVE (0x10 | MG_REG_HEAD_MUST_BE_ON) +#define MG_REG_HEAD_LBA_MODE (0x40 | MG_REG_HEAD_MUST_BE_ON) + + +/* "Device Control Register" bit values */ +#define MG_REG_CTRL_INTR_ENABLE 0x0 +#define MG_REG_CTRL_INTR_DISABLE (0x1 << 1) +#define MG_REG_CTRL_RESET (0x1 << 2) +#define MG_REG_CTRL_INTR_POLA_ACTIVE_HIGH 0x0 +#define MG_REG_CTRL_INTR_POLA_ACTIVE_LOW (0x1 << 4) +#define MG_REG_CTRL_DPD_POLA_ACTIVE_LOW 0x0 +#define MG_REG_CTRL_DPD_POLA_ACTIVE_HIGH (0x1 << 5) +#define MG_REG_CTRL_DPD_DISABLE 0x0 +#define MG_REG_CTRL_DPD_ENABLE (0x1 << 6) + +/* Status register bit */ + /* error bit in status register */ +#define MG_REG_STATUS_BIT_ERROR 0x01 + /* corrected error in status register */ +#define MG_REG_STATUS_BIT_CORRECTED_ERROR 0x04 + /* data request bit in status register */ +#define MG_REG_STATUS_BIT_DATA_REQ 0x08 + /* DSC - Drive Seek Complete */ +#define MG_REG_STATUS_BIT_SEEK_DONE 0x10 + /* DWF - Drive Write Fault */ +#define MG_REG_STATUS_BIT_WRITE_FAULT 0x20 +#define MG_REG_STATUS_BIT_READY 0x40 +#define MG_REG_STATUS_BIT_BUSY 0x80 + +/* handy status */ +#define MG_STAT_READY (MG_REG_STATUS_BIT_READY | MG_REG_STATUS_BIT_SEEK_DONE) +#define MG_READY_OK(s) (((s) & (MG_STAT_READY | \ + (MG_REG_STATUS_BIT_BUSY | \ + MG_REG_STATUS_BIT_WRITE_FAULT | \ + MG_REG_STATUS_BIT_ERROR))) == MG_STAT_READY) + +/* Error register */ +#define MG_REG_ERR_AMNF 0x01 +#define MG_REG_ERR_ABRT 0x04 +#define MG_REG_ERR_IDNF 0x10 +#define MG_REG_ERR_UNC 0x40 +#define MG_REG_ERR_BBK 0x80 + +/* error code for others */ +#define MG_ERR_NONE 0 +#define MG_ERR_TIMEOUT 0x100 +#define MG_ERR_INIT_STAT 0x101 +#define MG_ERR_TRANSLATION 0x102 +#define MG_ERR_CTRL_RST 0x103 +#define MG_ERR_NO_DRV_DATA 0x104 + +#define MG_MAX_ERRORS 16 /* Max read/write errors/sector */ +#define MG_RESET_FREQ 4 /* Reset controller every 4th retry */ + +/* command */ +#define MG_CMD_RD 0x20 +#define MG_CMD_WR 0x30 +#define MG_CMD_SLEEP 0x99 +#define MG_CMD_WAKEUP 0xC3 +#define MG_CMD_ID 0xEC +#define MG_CMD_WR_CONF 0x3C +#define MG_CMD_RD_CONF 0x40 + +/* main structure for mflash driver */ +struct mg_host { + struct mg_drv_data *drv_data; + /* for future use */ +}; + +/* + * Debugging macro and defines + */ +#undef DO_MG_DEBUG +#ifdef DO_MG_DEBUG +# define MG_DBG(fmt, args...) printf("%s:%d "fmt"\n", __func__, __LINE__,##args) +#else /* CONFIG_MG_DEBUG */ +# define MG_DBG(fmt, args...) do { } while(0) +#endif /* CONFIG_MG_DEBUG */ + +#endif + diff --git a/fs/fat/fat.c b/fs/fat/fat.c index 8081ee7..602edae 100644 --- a/fs/fat/fat.c +++ b/fs/fat/fat.c @@ -84,6 +84,7 @@ fat_register_device(block_dev_desc_t *dev_desc, int part_no) return -1; } #if (defined(CONFIG_CMD_IDE) || \ + defined(CONFIG_CMD_MG_DISK) || \ defined(CONFIG_CMD_SATA) || \ defined(CONFIG_CMD_SCSI) || \ defined(CONFIG_CMD_USB) || \ @@ -987,6 +988,7 @@ file_fat_detectfs(void) return 1; } #if defined(CONFIG_CMD_IDE) || \ + defined(CONFIG_CMD_MG_DISK) || \ defined(CONFIG_CMD_SATA) || \ defined(CONFIG_CMD_SCSI) || \ defined(CONFIG_CMD_USB) || \ diff --git a/include/config_cmd_all.h b/include/config_cmd_all.h index d771696..0ee2b58 100644 --- a/include/config_cmd_all.h +++ b/include/config_cmd_all.h @@ -83,5 +83,6 @@ #define CONFIG_CMD_VFD /* VFD support (TRAB) */ #define CONFIG_CMD_XIMG /* Load part of Multi Image */ #define CONFIG_CMD_AT91_SPIMUX /* AT91 MMC/SPI Mux Support */ +#define CONFIG_CMD_MG_DISK /* mGine m(g)flash IO node support */ #endif /* _CONFIG_CMD_ALL_H */ diff --git a/include/environment.h b/include/environment.h index ea6b4d1..507e832 100644 --- a/include/environment.h +++ b/include/environment.h @@ -84,6 +84,18 @@ # endif #endif /* CONFIG_ENV_IS_IN_NAND */ +#if defined(CONFIG_ENV_IS_IN_MG_DISK) +# ifndef CONFIG_ENV_ADDR +# error "Need to define CONFIG_ENV_ADDR when using CONFIG_ENV_IS_IN_MG_DISK" +# endif +# ifndef CONFIG_ENV_SIZE +# error "Need to define CONFIG_ENV_SIZE when using CONFIG_ENV_IS_IN_MG_DISK" +# endif +# ifdef CONFIG_ENV_IS_EMBEDDED +# error "CONFIG_ENV_IS_EMBEDDED not supported when using CONFIG_ENV_IS_IN_MG_DISK" +# endif +#endif /* CONFIG_ENV_IS_IN_MG_DISK */ + #ifdef USE_HOSTCC # include <stdint.h> #else diff --git a/include/mg_disk.h b/include/mg_disk.h new file mode 100644 index 0000000..bd767a1 --- /dev/null +++ b/include/mg_disk.h @@ -0,0 +1,51 @@ +/* + * (C) Copyright 2009 mGine co. + * unsik Kim <donar...@gmail.com> + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#ifndef MG_DISK_H_ +#define MG_DISK_H_ + +#include <asm/types.h> + +/* private driver data */ +struct mg_drv_data { + /* base address of mflash */ + u32 base; + /* Initialize hard reset, write protect, deep power down pins. + * Set these pins to GPIO and output high + */ + void (*mg_ctrl_pin_init) (void); + /* Set hard reset pin for given level + * level : logical level of hard reset pin (0 or 1) + */ + void (*mg_hdrst_pin) (u8 level); +}; + +struct mg_drv_data* mg_get_drv_data (void); + +unsigned int mg_disk_init (void); +unsigned int mg_disk_read (u32 addr, u8 *buff, u32 len); +unsigned int mg_disk_write(u32 addr, u8 *buff, u32 len); +unsigned int mg_disk_write_sects(void *buff, u32 sect_num, u32 sect_cnt); +unsigned int mg_disk_read_sects(void *buff, u32 sect_num, u32 sect_cnt); + +#endif /*MG_DISK_H_*/ diff --git a/include/part.h b/include/part.h index 980fd04..3cdae02 100644 --- a/include/part.h +++ b/include/part.h @@ -100,6 +100,7 @@ block_dev_desc_t* scsi_get_dev(int dev); block_dev_desc_t* usb_stor_get_dev(int dev); block_dev_desc_t* mmc_get_dev(int dev); block_dev_desc_t* systemace_get_dev(int dev); +block_dev_desc_t* mg_disk_get_dev(int dev); /* disk/part.c */ int get_partition_info (block_dev_desc_t * dev_desc, int part, disk_partition_t *info); --- 2009/2/2 unsik Kim <donar...@gmail.com>: > Hello? > > I fixed and added followings for your requests. > > 1. too long line length => fixed > > 2. not a linux coding style => fixed > > 3. add document (doc/README.mflash) > > 4. ARM only dependency and always init problem => fixed > > 5. msecs_to_hz function is changed. > In some ARM platform, CONFIG_SYS_HZ is not 1000 (samsung s3c24xx, > intel pxa25x, pxa27x) > and get_timer() just return elapsed tick of OS timer. > For the compatibility of these, I use #ifdef. > > Any comments, advice will be appreciated. > > Here is fixed patch. > > unsik Kim > > 2009/1/28 Wolfgang Denk <w...@denx.de>: >> Dear Kim, >> >> In message <57afda040901052341g3b00f741r445c0ce8d33b7...@mail.gmail.com> you >> wrote: >>> >>> I wrote mflash IO mode block device driver for U-Boot. >> >> Thanks for your contribution. Here a few comments: >> >>> diff --git a/common/Makefile b/common/Makefile >>> index 93e3963..f93e575 100644 >>> --- a/common/Makefile >>> +++ b/common/Makefile >>> @@ -57,6 +57,7 @@ COBJS-$(CONFIG_ENV_IS_IN_NAND) += env_nand.o >>> COBJS-$(CONFIG_ENV_IS_IN_NVRAM) += env_nvram.o >>> COBJS-$(CONFIG_ENV_IS_IN_ONENAND) += env_onenand.o >>> COBJS-$(CONFIG_ENV_IS_IN_SPI_FLASH) += env_sf.o >>> +COBJS-$(CONFIG_ENV_IS_IN_MG_DISK) += env_mgdisk.o >>> COBJS-$(CONFIG_ENV_IS_NOWHERE) += env_nowhere.o >>> >>> # command >>> @@ -138,6 +139,7 @@ endif >>> COBJS-$(CONFIG_CMD_XIMG) += cmd_ximg.o >>> COBJS-$(CONFIG_YAFFS2) += cmd_yaffs2.o >>> COBJS-$(CONFIG_VFD) += cmd_vfd.o >>> +COBJS-$(CONFIG_CMD_MG_DISK) += cmd_mgdisk.o >> >> Please keep such lists sorted. >> >> ... >>> +U_BOOT_CMD( >>> + mgd, 5, 0, do_mg_disk_cmd, >>> + "mgd - mgine m[g]flash command\n", >>> + ": mgine mflash IO mode (disk) command\n" >>> + "\t- initialize : mgd init\n" >>> + "\t- random read : mgd read [from] [to] [size]\n" >>> + "\t\tbelow example read 256 bytes from 0x300000 of mflash\n" >>> + "\t\tto 0xA0100000 of host memory\n" >>> + "\t\tex) mgd read 0x300000 0xA0100000 256\n" >>> + "\t- random write : mgd write [from] [to] [size]\n" >>> + "\t\tex) mgd write 0xA0100000 0x300000 256\n" >>> + "\t- sector read : mgd readsec [sector] [to] [counts]\n" >>> + "\t\tbelow example read 10 sectors starts from 400 sector\n" >>> + "\t\tto 0xA0100000\n" >>> + "\t\tex) mgd readsec 400 0xA0100000 10\n" >>> + "\t- sector write : mgd writesec [from] [sector] [counts]\n" >>> +); >> >> Please avoid using TAB characters here. >> >> Also,pleas ebe terse - don;t give examples here. Rather add a >> README.mflash file to the doc/ directory. >> >>> diff --git a/common/cmd_nvedit.c b/common/cmd_nvedit.c >>> index 85025da..4945aeb 100644 >>> --- a/common/cmd_nvedit.c >>> +++ b/common/cmd_nvedit.c >>> @@ -59,8 +59,9 @@ DECLARE_GLOBAL_DATA_PTR; >>> !defined(CONFIG_ENV_IS_IN_NAND) && \ >>> !defined(CONFIG_ENV_IS_IN_ONENAND) && \ >>> !defined(CONFIG_ENV_IS_IN_SPI_FLASH) && \ >>> + !defined(CONFIG_ENV_IS_IN_MG_DISK) && \ >>> !defined(CONFIG_ENV_IS_NOWHERE) >> >> Please keep lists sorted. >> >>> -# error Define one of >>> CONFIG_ENV_IS_IN_{NVRAM|EEPROM|FLASH|DATAFLASH|ONENAND|SPI_FLASH|NOWHERE} >>> +# error Define one of >>> CONFIG_ENV_IS_IN_{NVRAM|EEPROM|FLASH|DATAFLASH|ONENAND|SPI_FLASH|MG_DISK|NOWHERE} >> >> Please keep lists sorted. >> >> Also note that your mailer wrapped long lines here, thus corrupting >> the patch. Please fix your mailer. >> >> And please avoid such long lines, too! >> >> ... >>> +void env_relocate_spec(void) >>> +{ >>> + unsigned int err; >>> + err = mg_disk_read(CONFIG_ENV_ADDR, (u_char *) env_ptr, >>> CONFIG_ENV_SIZE); >>> + if (err) { >>> + puts ("*** Warning - mg_disk_read error, using default >>> environment\n\n"); >> >> Line too long. >> >> >>> + set_default_env(); >>> + return; >>> + } >>> + >>> + if (crc32(0, env_ptr->data, ENV_SIZE) != env_ptr->crc) { >>> + puts ("*** Warning - CRC error, using default >>> environment\n\n"); >>> + set_default_env(); >>> + } >>> +} >>> + >>> +int saveenv(void) >>> +{ >>> + unsigned int err; >>> + env_ptr->crc = crc32(0, env_ptr->data, ENV_SIZE); >>> + err = mg_disk_write(CONFIG_ENV_ADDR, (u_char *) env_ptr, >>> CONFIG_ENV_SIZE); >> >> Line too long. >> >>> + if (err) >>> + puts ("*** Warning - mg_disk_write error\n\n"); >>> + return (int)err; >> >> The cast should not be needed here. >> >>> diff --git a/disk/part.c b/disk/part.c >>> index e353cee..c007060 100644 >>> --- a/disk/part.c >>> +++ b/disk/part.c >>> @@ -39,7 +39,8 @@ >>> defined(CONFIG_CMD_SCSI) || \ >>> defined(CONFIG_CMD_USB) || \ >>> defined(CONFIG_MMC) || \ >>> - defined(CONFIG_SYSTEMACE) ) >>> + defined(CONFIG_SYSTEMACE) || \ >>> + defined(CONFIG_CMD_MG_DISK)) >> >> Please keep lists sorted. >> >>> @@ -95,7 +99,8 @@ block_dev_desc_t *get_dev(char* ifname, int dev) >>> defined(CONFIG_CMD_SCSI) || \ >>> defined(CONFIG_CMD_USB) || \ >>> defined(CONFIG_MMC) || \ >>> - defined(CONFIG_SYSTEMACE) ) >>> + defined(CONFIG_SYSTEMACE) || \ >>> + defined(CONFIG_CMD_MG_DISK)) >> >> Ditto. >> >>> @@ -207,7 +212,8 @@ void dev_print (block_dev_desc_t *dev_desc) >>> defined(CONFIG_CMD_SCSI) || \ >>> defined(CONFIG_CMD_USB) || \ >>> defined(CONFIG_MMC) || \ >>> - defined(CONFIG_SYSTEMACE) ) >>> + defined(CONFIG_SYSTEMACE) || \ >>> + defined(CONFIG_CMD_MG_DISK)) >> >> Ditto. >> >>> diff --git a/disk/part_amiga.c b/disk/part_amiga.c >>> index 6c3d748..b4c2820 100644 >>> --- a/disk/part_amiga.c >>> +++ b/disk/part_amiga.c >>> @@ -30,7 +30,8 @@ >>> defined(CONFIG_CMD_SCSI) || \ >>> defined(CONFIG_CMD_USB) || \ >>> defined(CONFIG_MMC) || \ >>> - defined(CONFIG_SYSTEMACE) ) && defined(CONFIG_AMIGA_PARTITION) >>> + defined(CONFIG_SYSTEMACE) || \ >>> + defined(CONFIG_CMD_MG_DISK)) && defined(CONFIG_AMIGA_PARTITION) >> >> Ditto. >> >>> @@ -40,6 +41,8 @@ >>> #define PRINTF(fmt, args...) >>> #endif >>> >>> +#define atoi(x) simple_strtoul(x,NULL,10) >> >> Please avoid that. >> >>> struct block_header >>> { >>> u32 id; >>> diff --git a/disk/part_dos.c b/disk/part_dos.c >>> index 4d778ec..30dc39f 100644 >>> --- a/disk/part_dos.c >>> +++ b/disk/part_dos.c >>> @@ -40,7 +40,8 @@ >>> defined(CONFIG_CMD_SCSI) || \ >>> defined(CONFIG_CMD_USB) || \ >>> defined(CONFIG_MMC) || \ >>> - defined(CONFIG_SYSTEMACE) ) && defined(CONFIG_DOS_PARTITION) >>> + defined(CONFIG_SYSTEMACE) || \ >>> + defined(CONFIG_CMD_MG_DISK)) && defined(CONFIG_DOS_PARTITION) >> >> more incorrect sort order, even more following below. >> >>> diff --git a/drivers/block/mg_disk.c b/drivers/block/mg_disk.c >>> new file mode 100644 >>> index 0000000..06c9bd8 >>> --- /dev/null >>> +++ b/drivers/block/mg_disk.c >>> @@ -0,0 +1,595 @@ >>> +/* >>> + * (C) Copyright 2009 mGine co. >>> + * unsik Kim <donar...@gmail.com> >>> + * >>> + * See file CREDITS for list of people who contributed to this >>> + * project. >>> + * >>> + * This program is free software; you can redistribute it and/or >>> + * modify it under the terms of the GNU General Public License as >>> + * published by the Free Software Foundation; either version 2 of >>> + * the License, or (at your option) any later version. >>> + * >>> + * This program is distributed in the hope that it will be useful, >>> + * but WITHOUT ANY WARRANTY; without even the implied warranty of >>> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the >>> + * GNU General Public License for more details. >>> + * >>> + * You should have received a copy of the GNU General Public License >>> + * along with this program; if not, write to the Free Software >>> + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, >>> + * MA 02111-1307 USA >>> + */ >>> + >>> +#include <common.h> >>> +#include <malloc.h> >>> +#include <part.h> >>> +#include <ata.h> >>> +#include "mg_disk_prv.h" >>> + >>> +#ifdef CONFIG_CMD_MG_DISK >>> + >>> +#undef printk >>> +#define printk printf >> >> Please don't. >> >>> +#undef KERN_ERR >>> +#define KERN_ERR >>> +#undef KERN_DEBUG >>> +#define KERN_DEBUG >>> +#undef KERN_INFO >>> +#define KERN_INFO >> >> Please don't. >> >>> +#undef inb >>> +#undef inw >>> +#undef outb >>> +#undef outw >>> + >>> +#define inb(a) (*(volatile unsigned char *)(a)) >>> +#define inw(a) (*(volatile unsigned short *)(a)) >>> +#define outb(v, a) (*(volatile unsigned char *)(a) = (v)) >>> +#define outw(v, a) (*(volatile unsigned short *)(a) = (v)) >> >> A strict NO, NO here. Please never do that. >> >> Please do use theproper accessor functions that are needed for the >> respective architecture. PLain volatile pointer accesses are bound to >> fail. Never do that. >> >> ... >>> + printk("%s: %s: status=0x%02x { ", name, msg, stat & 0xff); >>> + if (stat & MG_REG_STATUS_BIT_BUSY) printk("Busy >>> "); >>> + if (stat & MG_REG_STATUS_BIT_READY) >>> printk("DriveReady "); >>> + if (stat & MG_REG_STATUS_BIT_WRITE_FAULT) >>> printk("WriteFault "); >>> + if (stat & MG_REG_STATUS_BIT_SEEK_DONE) printk("SeekComplete >>> "); >>> + if (stat & MG_REG_STATUS_BIT_DATA_REQ) printk("DataRequest >>> "); >>> + if (stat & MG_REG_STATUS_BIT_CORRECTED_ERROR) >>> printk("CorrectedError "); >>> + if (stat & MG_REG_STATUS_BIT_ERROR) printk("Error >>> "); >> >> Bad coding style. Please reformat. >> >>> + printk("}\n"); >>> + if ((stat & MG_REG_STATUS_BIT_ERROR)) { >>> + printk("%s: %s: error=0x%02x { ", name, msg, err & 0xff); >>> + if (err & MG_REG_ERR_BBK) printk("BadSector "); >>> + if (err & MG_REG_ERR_UNC) printk("UncorrectableError "); >>> + if (err & MG_REG_ERR_IDNF) printk("SectorIdNotFound "); >>> + if (err & MG_REG_ERR_ABRT) printk("DriveStatusError "); >>> + if (err & MG_REG_ERR_AMNF) printk("AddrMarkNotFound "); >> >> Ditto. >> >>> +static unsigned int msecs_to_hz (u32 msec) >>> +{ >>> + u32 hz = CONFIG_SYS_HZ / 1000 * msec; >>> + >>> + if (!hz) >>> + hz = 1; >>> + >>> + return hz; >> >> This makes no sense. CONFIG_SYS_HZ is always 1000. Please consider it >> a constant. >> >> ... >>> + from = get_timer(0); >>> + expire = from + msecs_to_hz(msec); >> >> I don;t understand y ou logic here. get_timer() is defined to operate >> in munits of millisconds. What's the msecs_to_hz() stuff gotta do >> here? >> >>> + } while (cur < expire); >> >> You are aware of the overflow issues buried here, are you? >> >>> + if (!err) { >>> + if((iop->field_valid & 1) == 0) { >>> + err = MG_ERR_TRANSLATION; >>> + } else { >>> + mg_ident_cpy((unsigned >>> char*)mg_disk_dev.revision, iop->fw_rev, >>> sizeof(mg_disk_dev.revision)); >>> + mg_ident_cpy((unsigned >>> char*)mg_disk_dev.vendor, iop->model, >>> sizeof(mg_disk_dev.vendor)); >>> + mg_ident_cpy((unsigned >>> char*)mg_disk_dev.product, iop->serial_no, >>> sizeof(mg_disk_dev.product)); >> >> Lines way too long, and wrapped by mailer. >> >>> +static int mg_disk_reset (void) >>> +{ >>> + struct mg_drv_data *prv_data = MG_HOST->drv_data; >>> + s32 err; >>> + u8 init_status; >>> + >>> + /* hdd rst low */ >>> + prv_data->mg_hdrst_pin(0); >>> + err = mg_wait(MG_REG_STATUS_BIT_BUSY, 300); >>> + if(err) return err; >> >> Please refoemat according to CodingStyle requirements. >> >>> + if ((err = mg_wait(MG_STAT_READY, 3000))) { >>> + return err; >>> + } >> >> No braces for one-liners, please. >> >>> +static unsigned int mg_do_read_sects(void *buff, u32 sect_num, u32 >>> sect_cnt) >>> +{ >>> + u32 i, j, err; >>> + u8 *buff_ptr = buff; >>> + >>> + if ((err = mg_out(sect_num, sect_cnt, MG_CMD_RD))) { >>> + return err; >>> + } >> >> Ditto. >> >>> + for (i = 0; i < sect_cnt; i++) { >>> + if ((err = mg_wait(MG_REG_STATUS_BIT_DATA_REQ, 3000))) { >>> + return err; >>> + } >> >> Ditto. And so on. >> >>> + MG_DBG("%u (0x%8.8x) sector read", sect_num + i, (sect_num + >>> i) * >>> MG_SECTOR_SIZE); >> >> Please check all line lengths! >> >>> diff --git a/lib_arm/board.c b/lib_arm/board.c >>> index 2358beb..6a26bd2 100644 >>> --- a/lib_arm/board.c >>> +++ b/lib_arm/board.c >>> @@ -48,6 +48,7 @@ >>> #include <serial.h> >>> #include <nand.h> >>> #include <onenand_uboot.h> >>> +#include <mg_disk.h> >>> >>> #ifdef CONFIG_DRIVER_SMC91111 >>> #include "../drivers/net/smc91111.h" >>> @@ -348,6 +349,10 @@ void start_armboot (void) >>> onenand_init(); >>> #endif >>> >>> +#if defined(CONFIG_CMD_MG_DISK) >>> + mg_disk_init(); >>> +#endif >> >> Please don't. >> >> First it's wrong to add it for ARM only - what about other >> architectures that want to use that technology? >> >> Second it's wrong to always call the init code. This shall be done >> only upon first access. See the longish discussion we had for example >> about how to handle the S-ATA init code - please see the archives. >> >> Best regards, >> >> Wolfgang Denk >> >> -- >> DENX Software Engineering GmbH, MD: Wolfgang Denk & Detlev Zundel >> HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany >> Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: w...@denx.de >> What is wanted is not the will to believe, but the will to find out, >> which is the exact opposite. >> -- Bertrand Russell, "Skeptical Essays", 1928 >> > -- unsik Kim <donar...@gmail.com> _______________________________________________ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot