* [U-Boot] [U-BOOT][PATCH 1/3] Initial mflash support
@ 2009-02-13 11:06 unsik Kim
2009-02-14 11:51 ` Jean-Christophe PLAGNIOL-VILLARD
0 siblings, 1 reply; 5+ messages in thread
From: unsik Kim @ 2009-02-13 11:06 UTC (permalink / raw)
To: u-boot
Mflash is fusion memory device mainly targeted consumer eletronic and
mobile phone.
Internally, it have nand flash and other hardware logics and supports
some different operation (ATA, IO, XIP) modes.
IO mode is custom mode for the host that doesn't have IDE interface.
(Many mobile targeted SoC doesn't have IDE bus)
This driver support mflash IO mode.
Followings are brief descriptions about IO mode.
1. IO mode based on ATA protocol and uses some custom command. (read
confirm, write confirm)
2. IO mode uses SRAM bus interface.
Signed-off-by: unsik Kim <donari75@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(-)
create mode 100644 common/cmd_mgdisk.c
create mode 100644 common/env_mgdisk.c
create mode 100644 doc/README.mflash
create mode 100644 drivers/block/mg_disk.c
create mode 100644 drivers/block/mg_disk_prv.h
create mode 100644 include/mg_disk.h
diff --git a/common/Makefile b/common/Makefile
index f13cd11..72e8b7d 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@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@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 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..4454fca
--- /dev/null
+++ b/drivers/block/mg_disk.c
@@ -0,0 +1,629 @@
+/*
+ * (C) Copyright 2009 mGine co.
+ * unsik Kim <donari75@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@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@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);
--
1.5.6.6
^ permalink raw reply related [flat|nested] 5+ messages in thread
* [U-Boot] [U-BOOT][PATCH 1/3] Initial mflash support
2009-02-13 11:06 [U-Boot] [U-BOOT][PATCH 1/3] Initial mflash support unsik Kim
@ 2009-02-14 11:51 ` Jean-Christophe PLAGNIOL-VILLARD
2009-02-17 7:09 ` [U-Boot] [PATCH " unsik Kim
0 siblings, 1 reply; 5+ messages in thread
From: Jean-Christophe PLAGNIOL-VILLARD @ 2009-02-14 11:51 UTC (permalink / raw)
To: u-boot
> + *
> + * 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
> +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;
add an empty line
> + 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");
please add an empty line to be concistant with the function
> + 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 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
why?
> 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..4454fca
> --- /dev/null
> +++ b/drivers/block/mg_disk.c
> @@ -0,0 +1,629 @@
> +/*
> + * (C) Copyright 2009 mGine co.
> + * unsik Kim <donari75@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
no need please remove
> +
> +#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)
an inline function will be better
> +
> +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
not supposed to append anymore
CONFIG_SYS_HZ supposed to be always 1000
if not thi smust be fix
> +#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==' '))
please add a space before and after '<' '==' & co
> + ++src;
> +
> + /* copy string, omitting trailing white space */
> + while ((*src) && (src<end)) {
> + *dst++ = *src;
> + if (*src++ != ' ')
> + last = dst;
> + }
> +OUT:
> + *last = '\0';
> +}
why do you need this?
> +
> +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
maybe use only one ifdef __LITTLE_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;
> + }
maybe you could use the same coding style in the same file?
> +
> + 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);
please add an empty line
> + 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);
please use debug(x)
> + 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;
> + }
is there any better way to calculate it?
> +
> + 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;
> + }
plase do not duplicate it create common code
and as precedently is there any better way to calculate it?
> +
> + 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;
> +}
please do an compile error not a run time error
> +
> +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;
Best Regards,
J.
^ permalink raw reply [flat|nested] 5+ messages in thread
* [U-Boot] [PATCH 1/3] Initial mflash support
2009-02-14 11:51 ` Jean-Christophe PLAGNIOL-VILLARD
@ 2009-02-17 7:09 ` unsik Kim
2009-02-17 8:41 ` Jean-Christophe PLAGNIOL-VILLARD
0 siblings, 1 reply; 5+ messages in thread
From: unsik Kim @ 2009-02-17 7:09 UTC (permalink / raw)
To: u-boot
Hello?
Thanks for comments.
Some patches will be posted for your requests.
Also I wrote my opinion for some comments.
>> 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
> why?
This list badly sorted before I add. I just resort it to
alphabetical order and add new option. Nothing removed.
>> 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..4454fca
>> --- /dev/null
>> +++ b/drivers/block/mg_disk.c
>> +
>> +#define MG_BASE (host.drv_data->base)
> an inline function will be better
This isn't a function.
>> +
>> +
>> +/*
>> + * 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==' '))
> please add a space before and after '<' '==' & co
>> + ++src;
>> +
>> + /* copy string, omitting trailing white space */
>> + while ((*src) && (src<end)) {
>> + *dst++ = *src;
>> + if (*src++ != ' ')
>> + last = dst;
>> + }
>> +OUT:
>> + *last = '\0';
>> +}
> why do you need this?
for parsing string parts of ATAID
>> +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));
> ??
I can't guess your intention. Please write more clearly
>> + 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);
> please use debug(x)
MG_DBG prints lots of messages. I think changing MG_DBG to debug might
confuse other driver's debug message.
If u-boot policy only allow debug(x), I'll follow.
>> + err = mg_do_read_sects(buff_ptr, sect_num, residue);
>> + }
>> +
>> + return err;
>> +}
>> +/* 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;
>> +}
> please do an compile error not a run time error
IMHO, compile error (or warning) is not a good choice for this case.
Compile time error always generate error even though override function
exist.
Also mg_disk_init() function will generate run time error when weak
function used. Typically, users will be read README.mflash that explains
how to override this function and finally port appropriately.
Regards,
unsik Kim
^ permalink raw reply [flat|nested] 5+ messages in thread
* [U-Boot] [PATCH 1/3] Initial mflash support
2009-02-17 7:09 ` [U-Boot] [PATCH " unsik Kim
@ 2009-02-17 8:41 ` Jean-Christophe PLAGNIOL-VILLARD
2009-02-18 3:32 ` unsik Kim
0 siblings, 1 reply; 5+ messages in thread
From: Jean-Christophe PLAGNIOL-VILLARD @ 2009-02-17 8:41 UTC (permalink / raw)
To: u-boot
On 16:09 Tue 17 Feb , unsik Kim wrote:
> Hello?
>
> Thanks for comments.
> Some patches will be posted for your requests.
> Also I wrote my opinion for some comments.
>
>>> 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
>> why?
> This list badly sorted before I add. I just resort it to
> alphabetical order and add new option. Nothing removed.
>
>>> 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..4454fca
>>> --- /dev/null
>>> +++ b/drivers/block/mg_disk.c
>>> +
>>> +#define MG_BASE (host.drv_data->base)
>> an inline function will be better
> This isn't a function.
yes but please use an inline function which will allow better compiler check
and error message
as done in a lots of the linux drivers as example the netdev with this
static inline void *netdev_priv(const struct net_device *dev)
{
return dev->priv;
}
>>> +
>
>>> +
>>> +/*
>>> + * 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==' '))
>> please add a space before and after '<' '==' & co
>>> + ++src;
>>> +
>>> + /* copy string, omitting trailing white space */
>>> + while ((*src) && (src<end)) {
>>> + *dst++ = *src;
>>> + if (*src++ != ' ')
>>> + last = dst;
>>> + }
>>> +OUT:
>>> + *last = '\0';
>>> +}
>> why do you need this?
> for parsing string parts of ATAID
it's mflash specific??
>
>>> +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));
>> ??
> I can't guess your intention. Please write more clearly
you store a u16 in a u8 :(
>>> + 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);
>> please use debug(x)
> MG_DBG prints lots of messages. I think changing MG_DBG to debug might
> confuse other driver's debug message.
> If u-boot policy only allow debug(x), I'll follow.
>>> + err = mg_do_read_sects(buff_ptr, sect_num, residue);
>>> + }
>>> +
>>> + return err;
>>> +}
>
>>> +/* 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;
>>> +}
>> please do an compile error not a run time error
> IMHO, compile error (or warning) is not a good choice for this case.
sorry no beacause everyone does not have the board to test it, a compile error
will at least help use to check if we brake the board or not
> Compile time error always generate error even though override function
> exist.
not necessarely
does you driver allow multiple instance of mflash?
if no you does not implement the function
Best Regards,
J.
^ permalink raw reply [flat|nested] 5+ messages in thread
* [U-Boot] [PATCH 1/3] Initial mflash support
2009-02-17 8:41 ` Jean-Christophe PLAGNIOL-VILLARD
@ 2009-02-18 3:32 ` unsik Kim
0 siblings, 0 replies; 5+ messages in thread
From: unsik Kim @ 2009-02-18 3:32 UTC (permalink / raw)
To: u-boot
>>>> +/* 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;
>>>> +}
>>> please do an compile error not a run time error
>> IMHO, compile error (or warning) is not a good choice for this case.
> sorry no beacause everyone does not have the board to test it, a compile error
> will at least help use to check if we brake the board or not
Ok, I understand.
>> Compile time error always generate error even though override function
>> exist.
> not necessarely
> does you driver allow multiple instance of mflash?
> if no you does not implement the function
mflash driver doesn't use multiple instance.
I can't understand your thought exactly.
If I remove mg_get_drv_data() default weak function and just add weak attribute
to it's prototype, build works well but it's logically same as original one.
User still don't get any information at build time.
Do you want to just leave mg_get_drv_data() to unresolved symbol ?
If user does not port it, link error will be generate. Is it U-boot's driver
policy ?
Regards,
unsik Kim
^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2009-02-18 3:32 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2009-02-13 11:06 [U-Boot] [U-BOOT][PATCH 1/3] Initial mflash support unsik Kim
2009-02-14 11:51 ` Jean-Christophe PLAGNIOL-VILLARD
2009-02-17 7:09 ` [U-Boot] [PATCH " unsik Kim
2009-02-17 8:41 ` Jean-Christophe PLAGNIOL-VILLARD
2009-02-18 3:32 ` unsik Kim
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox