[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