[U-Boot] [PATCH] mflash u-boot support
unsik Kim
donari75 at gmail.com
Mon Feb 2 09:32:52 CET 2009
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
Signed-off-by: unsik Kim <donari75 at 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 | 629 +++++++++++++++++++++++++++++++++++++++++++
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, 1119 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 <donari75 at 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 <donari75 at 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..fb74b90
--- /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 value should be multiple of
+MG_SECTOR_SIZE (512Byte). 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 10485760
+
+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 642582b..32e134c 100644
--- a/drivers/block/Makefile
+++ b/drivers/block/Makefile
@@ -25,12 +25,13 @@ 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_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..4454fca
--- /dev/null
+++ b/drivers/block/mg_disk.c
@@ -0,0 +1,629 @@
+/*
+ * (C) Copyright 2009 mGine co.
+ * unsik Kim <donari75 at 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
+
+#if (CONFIG_MG_DISK_RES % MG_SECTOR_SIZE != 0)
+#error "CONFIG_MG_DISK_RES should be MG_SECTOR_SIZE algined"
+#endif
+
+#define MG_DISK_RES ((CONFIG_MG_DISK_RES) / MG_SECTOR_SIZE)
+
+#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;
+ 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
+ mg_disk_dev.lba = (iop->lba_capacity << 16) | (iop->lba_capacity >> 16);
+#else /* ! __BIG_ENDIAN */
+ mg_disk_dev.lba = iop->lba_capacity;
+#endif /* __BIG_ENDIAN */
+
+ 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_DISK_RES;
+ 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_DISK_RES;
+ 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 <donari75 at 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 <donari75 at 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/1/28 Wolfgang Denk <wd at denx.de>:
> Dear Kim,
>
> In message <57afda040901052341g3b00f741r445c0ce8d33b7b71 at 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 <donari75 at 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: wd at 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
>
More information about the U-Boot
mailing list