[U-Boot] [U-BOOT][PATCH 1/3] Initial mflash support
Jean-Christophe PLAGNIOL-VILLARD
plagnioj at jcrosoft.com
Sat Feb 14 12:51:17 CET 2009
> + *
> + * 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 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
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.
More information about the U-Boot
mailing list