From 9def12cae33d2d3ea2dd56b197fd3dfb3ad60bf4 Mon Sep 17 00:00:00 2001 From: Stefan Roese Date: Thu, 27 Nov 2008 14:05:15 +0100 Subject: MTD: Fix problem based on non-working relocation (list head mtd_partitions) Don't use LIST_HEAD() but initialize the struct via INIT_LIST_HEAD() upon first call of add_mtd_partitions(). Otherwise this won't work on platforms where the relocation is broken (like MIPS or PPC). Signed-off-by: Stefan Roese --- drivers/mtd/mtdpart.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mtd/mtdpart.c b/drivers/mtd/mtdpart.c index 9a3bf6f..f010f5e 100644 --- a/drivers/mtd/mtdpart.c +++ b/drivers/mtd/mtdpart.c @@ -20,7 +20,7 @@ #include /* Our partition linked list */ -static LIST_HEAD(mtd_partitions); +struct list_head mtd_partitions; /* Our partition node structure */ struct mtd_part { @@ -349,6 +349,14 @@ int add_mtd_partitions(struct mtd_info *master, u_int32_t cur_offset = 0; int i; + /* + * Need to init the list here, since LIST_INIT() does not + * work on platforms where relocation has problems (like MIPS + * & PPC). + */ + if (mtd_partitions.next == NULL) + INIT_LIST_HEAD(&mtd_partitions); + printk (KERN_NOTICE "Creating %d MTD partitions on \"%s\":\n", nbparts, master->name); for (i = 0; i < nbparts; i++) { -- cgit v1.1 From 2ee951ba2ac9874d2a93d52e7a187d3184be937e Mon Sep 17 00:00:00 2001 From: Stefan Roese Date: Thu, 27 Nov 2008 14:07:09 +0100 Subject: UBI: Enable re-initializing of the "ubi part" command With this patch now, the user can call "ubi part" multiple times to re-connect the UBI device to another MTD partition. Signed-off-by: Stefan Roese --- drivers/mtd/ubi/build.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/mtd/ubi/build.c b/drivers/mtd/ubi/build.c index 17cabb2..bdf75c9 100644 --- a/drivers/mtd/ubi/build.c +++ b/drivers/mtd/ubi/build.c @@ -1059,6 +1059,7 @@ void __exit ubi_exit(void) misc_deregister(&ubi_ctrl_cdev); class_remove_file(ubi_class, &ubi_version); class_destroy(ubi_class); + mtd_devs = 0; } module_exit(ubi_exit); -- cgit v1.1 From 817329351639a8895cd9b87b33aeff043f3d5a44 Mon Sep 17 00:00:00 2001 From: Stefan Roese Date: Wed, 10 Dec 2008 10:28:33 +0100 Subject: UBI: Return -ENOMEM upon failing malloc Return with correct error code (-ENOMEM) from ubi_attach_mtd_dev() upon failing malloc(). Signed-off-by: Stefan Roese --- drivers/mtd/ubi/build.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/ubi/build.c b/drivers/mtd/ubi/build.c index bdf75c9..f4b01a9 100644 --- a/drivers/mtd/ubi/build.c +++ b/drivers/mtd/ubi/build.c @@ -784,19 +784,20 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num, int vid_hdr_offset) if (err) goto out_free; + err = -ENOMEM; ubi->peb_buf1 = vmalloc(ubi->peb_size); if (!ubi->peb_buf1) goto out_free; ubi->peb_buf2 = vmalloc(ubi->peb_size); if (!ubi->peb_buf2) - goto out_free; + goto out_free; #ifdef CONFIG_MTD_UBI_DEBUG mutex_init(&ubi->dbg_buf_mutex); ubi->dbg_peb_buf = vmalloc(ubi->peb_size); if (!ubi->dbg_peb_buf) - goto out_free; + goto out_free; #endif err = attach_by_scanning(ubi); -- cgit v1.1 From 15e2697c9f7fb2ba672a1a70f07cd6d9d4e92b51 Mon Sep 17 00:00:00 2001 From: Nobuhiro Iwamatsu Date: Mon, 17 Nov 2008 16:53:09 +0900 Subject: sh: Update SuperH serial driver The address of SCFSR register is wrong at SH7720/SH7721. This patch fix this. Signed-off-by: Nobuhiro Iwamatsu Signed-off-by: Nobuhiro Iwamatsu --- drivers/serial/serial_sh.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/serial/serial_sh.c b/drivers/serial/serial_sh.c index f30532b..1d76a19 100644 --- a/drivers/serial/serial_sh.c +++ b/drivers/serial/serial_sh.c @@ -94,7 +94,7 @@ # define LSR_ORER 1 # define FIFOLEVEL_MASK 0x1F #elif defined(CONFIG_CPU_SH7720) -# define SCLSR (vu_short *)(SCIF_BASE + 0x24) +# define SCLSR SCFSR # define LSR_ORER 0x0200 # define FIFOLEVEL_MASK 0x1F #elif defined(CONFIG_CPU_SH7710) || \ -- cgit v1.1 From a319f1496210117b73198e3d889ffffaf6825d00 Mon Sep 17 00:00:00 2001 From: Jean-Christophe PLAGNIOL-VILLARD Date: Fri, 5 Dec 2008 07:27:37 +0100 Subject: sh: r2dplus fix register access Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD Signed-off-by: Nobuhiro Iwamatsu --- drivers/pci/pci_sh7751.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/pci/pci_sh7751.c b/drivers/pci/pci_sh7751.c index e3a0ea0..df6d76f 100644 --- a/drivers/pci/pci_sh7751.c +++ b/drivers/pci/pci_sh7751.c @@ -187,8 +187,8 @@ int pci_sh7751_init(struct pci_controller *hose) /* Copy BSC registers into PCI BSC */ p4_out(inl(SH7751_BCR1), SH7751_PCIBCR1); - p4_out(inl(SH7751_BCR2), SH7751_PCIBCR2); - p4_out(inl(SH7751_BCR3), SH7751_PCIBCR3); + p4_out(inw(SH7751_BCR2), SH7751_PCIBCR2); + p4_out(inw(SH7751_BCR3), SH7751_PCIBCR3); p4_out(inl(SH7751_WCR1), SH7751_PCIWCR1); p4_out(inl(SH7751_WCR2), SH7751_PCIWCR2); p4_out(inl(SH7751_WCR3), SH7751_PCIWCR3); -- cgit v1.1 From ecf5f077c8e77454f532eaac3e3afb7cfc48c62d Mon Sep 17 00:00:00 2001 From: Timur Tabi Date: Wed, 3 Dec 2008 11:28:30 -0600 Subject: i2c: merge all i2c_reg_read() and i2c_reg_write() into inline functions All implementations of the functions i2c_reg_read() and i2c_reg_write() are identical. We can save space and simplify the code by converting these functions into inlines and putting them in i2c.h. Signed-off-by: Timur Tabi Acked-By: Jean-Christophe PLAGNIOL-VILLARD --- drivers/i2c/fsl_i2c.c | 16 ---------------- drivers/i2c/soft_i2c.c | 19 ------------------- 2 files changed, 35 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/fsl_i2c.c b/drivers/i2c/fsl_i2c.c index 3b5c06b..ce646fd 100644 --- a/drivers/i2c/fsl_i2c.c +++ b/drivers/i2c/fsl_i2c.c @@ -367,22 +367,6 @@ i2c_probe(uchar chip) return i2c_read(chip, 0, 0, NULL, 0); } -uchar -i2c_reg_read(uchar i2c_addr, uchar reg) -{ - uchar buf[1]; - - i2c_read(i2c_addr, reg, 1, buf, 1); - - return buf[0]; -} - -void -i2c_reg_write(uchar i2c_addr, uchar reg, uchar val) -{ - i2c_write(i2c_addr, reg, 1, &val, 1); -} - int i2c_set_bus_num(unsigned int bus) { #ifdef CONFIG_SYS_I2C2_OFFSET diff --git a/drivers/i2c/soft_i2c.c b/drivers/i2c/soft_i2c.c index d2a5142..f12dedf 100644 --- a/drivers/i2c/soft_i2c.c +++ b/drivers/i2c/soft_i2c.c @@ -435,22 +435,3 @@ int i2c_write(uchar chip, uint addr, int alen, uchar *buffer, int len) return(failures); } -/*----------------------------------------------------------------------- - * Read a register - */ -uchar i2c_reg_read(uchar i2c_addr, uchar reg) -{ - uchar buf; - - i2c_read(i2c_addr, reg, 1, &buf, 1); - - return(buf); -} - -/*----------------------------------------------------------------------- - * Write a register - */ -void i2c_reg_write(uchar i2c_addr, uchar reg, uchar val) -{ - i2c_write(i2c_addr, reg, 1, &val, 1); -} -- cgit v1.1 From 84bc72d90c505fec3ef4b693995407a0bd4064e5 Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Thu, 11 Dec 2008 18:39:08 -0500 Subject: spi/stmicro: fix debug() display of cmd The stmicro_wait_ready() func tries to show the actual opcode that was sent to the device, but instead it displays the array pointer. Fix it to pull out the opcode from the start of the array. Signed-off-by: Mike Frysinger --- drivers/mtd/spi/stmicro.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mtd/spi/stmicro.c b/drivers/mtd/spi/stmicro.c index b8b835a..86324e4 100644 --- a/drivers/mtd/spi/stmicro.c +++ b/drivers/mtd/spi/stmicro.c @@ -137,7 +137,7 @@ static int stmicro_wait_ready(struct spi_flash *flash, unsigned long timeout) ret = spi_xfer(spi, 32, &cmd[0], NULL, SPI_XFER_BEGIN); if (ret) { - debug("SF: Failed to send command %02x: %d\n", cmd, ret); + debug("SF: Failed to send command %02x: %d\n", cmd[0], ret); return ret; } -- cgit v1.1 From 455ae7e87f67c44e6aea68865c83acadd3fcd36c Mon Sep 17 00:00:00 2001 From: Wolfgang Denk Date: Tue, 16 Dec 2008 01:02:17 +0100 Subject: Coding style cleanup, update CHANGELOG. Signed-off-by: Wolfgang Denk --- drivers/i2c/soft_i2c.c | 1 - drivers/mtd/ubi/crc32.c | 2 +- drivers/mtd/ubi/io.c | 2 +- drivers/mtd/ubi/vmt.c | 2 +- 4 files changed, 3 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/soft_i2c.c b/drivers/i2c/soft_i2c.c index f12dedf..a27de5a 100644 --- a/drivers/i2c/soft_i2c.c +++ b/drivers/i2c/soft_i2c.c @@ -434,4 +434,3 @@ int i2c_write(uchar chip, uint addr, int alen, uchar *buffer, int len) send_stop(); return(failures); } - diff --git a/drivers/mtd/ubi/crc32.c b/drivers/mtd/ubi/crc32.c index 5273ca3..a7e26b0 100644 --- a/drivers/mtd/ubi/crc32.c +++ b/drivers/mtd/ubi/crc32.c @@ -97,7 +97,7 @@ u32 crc32_le(u32 crc, unsigned char const *p, size_t len) # else # define DO_CRC(x) crc = tab[ ((crc >> 24) ^ (x)) & 255] ^ (crc<<8) # endif - //printf("Crc32_le crc=%x\n",crc); + /* printf("Crc32_le crc=%x\n",crc); */ crc = __cpu_to_le32(crc); /* Align it */ if((((long)b)&3 && len)){ diff --git a/drivers/mtd/ubi/io.c b/drivers/mtd/ubi/io.c index 2d44f23..8423894 100644 --- a/drivers/mtd/ubi/io.c +++ b/drivers/mtd/ubi/io.c @@ -186,7 +186,7 @@ retry: if (read != len && err == -EBADMSG) { ubi_assert(0); printk("%s[%d] not here\n", __func__, __LINE__); -// err = -EIO; +/* err = -EIO; */ } } else { ubi_assert(len == read); diff --git a/drivers/mtd/ubi/vmt.c b/drivers/mtd/ubi/vmt.c index a87a2f3..061da64 100644 --- a/drivers/mtd/ubi/vmt.c +++ b/drivers/mtd/ubi/vmt.c @@ -260,7 +260,7 @@ int ubi_create_volume(struct ubi_device *ubi, struct ubi_mkvol_req *req) goto out_unlock; } - /* Calculate how many eraseblocks are requested */ + /* Calculate how many eraseblocks are requested */ vol->usable_leb_size = ubi->leb_size - ubi->leb_size % req->alignment; bytes = req->bytes; if (do_div(bytes, vol->usable_leb_size)) -- cgit v1.1 From ff49ea8977b56916edd5b1766d9939010e30b181 Mon Sep 17 00:00:00 2001 From: Scott Wood Date: Tue, 16 Dec 2008 14:24:16 -0600 Subject: NAND: Mark the BBT as scanned prior to calling scan_bbt. Otherwise, recursion can occur if scan_bbt does not find a bad block table, and tries to write one, and the attempt to erase the BBT area causes a bad block check. Signed-off-by: Scott Wood --- drivers/mtd/nand/nand_base.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index ba05b76..94a65d4 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -460,8 +460,8 @@ static int nand_block_checkbad(struct mtd_info *mtd, loff_t ofs, int getchip, struct nand_chip *chip = mtd->priv; if (!(chip->options & NAND_BBT_SCANNED)) { - chip->scan_bbt(mtd); chip->options |= NAND_BBT_SCANNED; + chip->scan_bbt(mtd); } if (!chip->bbt) -- cgit v1.1 From 7a8979591171676417ab36852d8811a8c46accd8 Mon Sep 17 00:00:00 2001 From: Peter Tyser Date: Wed, 29 Oct 2008 12:39:26 -0500 Subject: pci/fsl_pci_init: Enable inbound PCI config cycles Add fsl_pci_config_unlock() function to enable a PCI/PCIe interface configured in agent/endpoint mode to respond to inbound PCI configuration cycles. Signed-off-by: Peter Tyser --- drivers/pci/fsl_pci_init.c | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) (limited to 'drivers') diff --git a/drivers/pci/fsl_pci_init.c b/drivers/pci/fsl_pci_init.c index 1db42fd..db68f26 100644 --- a/drivers/pci/fsl_pci_init.c +++ b/drivers/pci/fsl_pci_init.c @@ -37,6 +37,11 @@ DECLARE_GLOBAL_DATA_PTR; #include #include +/* Freescale-specific PCI config registers */ +#define FSL_PCI_PBFR 0x44 +#define FSL_PCIE_CAP_ID 0x4c +#define FSL_PCIE_CFG_RDY 0x4b0 + void pciauto_prescan_setup_bridge(struct pci_controller *hose, pci_dev_t dev, int sub_bus); void pciauto_postscan_setup_bridge(struct pci_controller *hose, @@ -306,6 +311,30 @@ void fsl_pci_init(struct pci_controller *hose) } } +/* Enable inbound PCI config cycles for agent/endpoint interface */ +void fsl_pci_config_unlock(struct pci_controller *hose) +{ + pci_dev_t dev = PCI_BDF(hose->first_busno,0,0); + u8 agent; + u8 pcie_cap; + u16 pbfr; + + pci_hose_read_config_byte(hose, dev, PCI_CLASS_PROG, &agent); + if (!agent) + return; + + pci_hose_read_config_byte(hose, dev, FSL_PCIE_CAP_ID, &pcie_cap); + if (pcie_cap != 0x0) { + /* PCIe - set CFG_READY bit of Configuration Ready Register */ + pci_hose_write_config_byte(hose, dev, FSL_PCIE_CFG_RDY, 0x1); + } else { + /* PCI - clear ACL bit of PBFR */ + pci_hose_read_config_word(hose, dev, FSL_PCI_PBFR, &pbfr); + pbfr &= ~0x20; + pci_hose_write_config_word(hose, dev, FSL_PCI_PBFR, pbfr); + } +} + #ifdef CONFIG_OF_BOARD_SETUP #include #include -- cgit v1.1 From e92739d34e2d6b6aca93b2598248210710897ce8 Mon Sep 17 00:00:00 2001 From: Peter Tyser Date: Wed, 17 Dec 2008 16:36:21 -0600 Subject: Add support for PCA953x I2C gpio devices Initial support for NXP's 4 and 8 bit I2C gpio expanders (eg pca9537, pca9557, etc). The CONFIG_PCA953X define enables support for the devices while the CONFIG_CMD_PCA953X define enables the pca953x command. The CONFIG_CMD_PCA953X_INFO define enables an 'info' sub-command which provides summary information for the given pca953x device. Signed-off-by: Peter Tyser --- drivers/gpio/Makefile | 47 ++++++++++ drivers/gpio/pca953x.c | 227 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 274 insertions(+) create mode 100644 drivers/gpio/Makefile create mode 100644 drivers/gpio/pca953x.c (limited to 'drivers') diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile new file mode 100644 index 0000000..dd618ed --- /dev/null +++ b/drivers/gpio/Makefile @@ -0,0 +1,47 @@ +# +# Copyright 2000-2008 +# Wolfgang Denk, DENX Software Engineering, wd@denx.de. +# +# 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 $(TOPDIR)/config.mk + +LIB := $(obj)libgpio.a + +COBJS-$(CONFIG_PCA953X) += pca953x.o + +COBJS := $(COBJS-y) +SRCS := $(COBJS:.o=.c) +OBJS := $(addprefix $(obj),$(COBJS)) + +all: $(LIB) + +$(LIB): $(obj).depend $(OBJS) + $(AR) $(ARFLAGS) $@ $(OBJS) + + +######################################################################### + +# defines $(obj).depend target +include $(SRCTREE)/rules.mk + +sinclude $(obj).depend + +######################################################################## diff --git a/drivers/gpio/pca953x.c b/drivers/gpio/pca953x.c new file mode 100644 index 0000000..390d99a --- /dev/null +++ b/drivers/gpio/pca953x.c @@ -0,0 +1,227 @@ +/* + * Copyright 2008 Extreme Engineering Solutions, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * Version 2 as published by the Free Software Foundation. + * + * 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 + */ + +/* + * Driver for NXP's 4 and 8 bit I2C gpio expanders (eg pca9537, pca9557, etc) + * TODO: support additional devices with more than 8-bits GPIO + */ + +#include +#include +#include + +/* Default to an address that hopefully won't corrupt other i2c devices */ +#ifndef CONFIG_SYS_I2C_PCA953X_ADDR +#define CONFIG_SYS_I2C_PCA953X_ADDR (~0) +#endif + +enum { + PCA953X_CMD_INFO, + PCA953X_CMD_DEVICE, + PCA953X_CMD_OUTPUT, + PCA953X_CMD_INPUT, + PCA953X_CMD_INVERT, +}; + +/* + * Modify masked bits in register + */ +static int pca953x_reg_write(uint8_t chip, uint addr, uint mask, uint data) +{ + uint8_t val; + + if (i2c_read(chip, addr, 1, &val, 1)) + return -1; + + val &= ~mask; + val |= data; + + return i2c_write(chip, addr, 1, &val, 1); +} + +/* + * Set output value of IO pins in 'mask' to corresponding value in 'data' + * 0 = low, 1 = high + */ +int pca953x_set_val(uint8_t chip, uint mask, uint data) +{ + return pca953x_reg_write(chip, PCA953X_OUT, mask, data); +} + +/* + * Set read polarity of IO pins in 'mask' to corresponding value in 'data' + * 0 = read pin value, 1 = read inverted pin value + */ +int pca953x_set_pol(uint8_t chip, uint mask, uint data) +{ + return pca953x_reg_write(chip, PCA953X_POL, mask, data); +} + +/* + * Set direction of IO pins in 'mask' to corresponding value in 'data' + * 0 = output, 1 = input + */ +int pca953x_set_dir(uint8_t chip, uint mask, uint data) +{ + return pca953x_reg_write(chip, PCA953X_CONF, mask, data); +} + +/* + * Read current logic level of all IO pins + */ +int pca953x_get_val(uint8_t chip) +{ + uint8_t val; + + if (i2c_read(chip, 0, 1, &val, 1)) + return -1; + + return (int)val; +} + +#ifdef CONFIG_CMD_PCA953X +#ifdef CONFIG_CMD_PCA953X_INFO +/* + * Display pca953x information + */ +static int pca953x_info(uint8_t chip) +{ + int i; + uint8_t data; + + printf("pca953x@ 0x%x:\n\n", chip); + printf("gpio pins: 76543210\n"); + printf("-------------------\n"); + + if (i2c_read(chip, PCA953X_CONF, 1, &data, 1)) + return -1; + printf("conf: "); + for (i = 7; i >= 0; i--) + printf("%c", data & (1 << i) ? 'i' : 'o'); + printf("\n"); + + if (i2c_read(chip, PCA953X_POL, 1, &data, 1)) + return -1; + printf("invert: "); + for (i = 7; i >= 0; i--) + printf("%c", data & (1 << i) ? '1' : '0'); + printf("\n"); + + if (i2c_read(chip, PCA953X_IN, 1, &data, 1)) + return -1; + printf("input: "); + for (i = 7; i >= 0; i--) + printf("%c", data & (1 << i) ? '1' : '0'); + printf("\n"); + + if (i2c_read(chip, PCA953X_OUT, 1, &data, 1)) + return -1; + printf("output: "); + for (i = 7; i >= 0; i--) + printf("%c", data & (1 << i) ? '1' : '0'); + printf("\n"); + + return 0; +} +#endif /* CONFIG_CMD_PCA953X_INFO */ + +cmd_tbl_t cmd_pca953x[] = { + U_BOOT_CMD_MKENT(device, 3, 0, (void *)PCA953X_CMD_DEVICE, "", ""), + U_BOOT_CMD_MKENT(output, 4, 0, (void *)PCA953X_CMD_OUTPUT, "", ""), + U_BOOT_CMD_MKENT(input, 3, 0, (void *)PCA953X_CMD_INPUT, "", ""), + U_BOOT_CMD_MKENT(invert, 4, 0, (void *)PCA953X_CMD_INVERT, "", ""), +#ifdef CONFIG_CMD_PCA953X_INFO + U_BOOT_CMD_MKENT(info, 2, 0, (void *)PCA953X_CMD_INFO, "", ""), +#endif +}; + +int do_pca953x(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) +{ + static uint8_t chip = CONFIG_SYS_I2C_PCA953X_ADDR; + int val; + ulong ul_arg2 = 0; + ulong ul_arg3 = 0; + cmd_tbl_t *c; + + c = find_cmd_tbl(argv[1], cmd_pca953x, ARRAY_SIZE(cmd_pca953x)); + + /* All commands but "device" require 'maxargs' arguments */ + if (!c || !((argc == (c->maxargs)) || + (((int)c->cmd == PCA953X_CMD_DEVICE) && + (argc == (c->maxargs - 1))))) { + printf("Usage:\n%s\n", cmdtp->usage); + return 1; + } + + /* arg2 used as chip number or pin number */ + if (argc > 2) + ul_arg2 = simple_strtoul(argv[2], NULL, 16); + + /* arg3 used as pin or invert value */ + if (argc > 3) + ul_arg3 = simple_strtoul(argv[3], NULL, 16) & 0x1; + + switch ((int)c->cmd) { +#ifdef CONFIG_CMD_PCA953X_INFO + case PCA953X_CMD_INFO: + return pca953x_info(chip); +#endif + case PCA953X_CMD_DEVICE: + if (argc == 3) + chip = (uint8_t)ul_arg2; + printf("Current device address: 0x%x\n", chip); + return 0; + case PCA953X_CMD_INPUT: + pca953x_set_dir(chip, (1 << ul_arg2), + PCA953X_DIR_IN << ul_arg2); + val = (pca953x_get_val(chip) & (1 << ul_arg2)) != 0; + + printf("chip 0x%02x, pin 0x%lx = %d\n", chip, ul_arg2, val); + return val; + case PCA953X_CMD_OUTPUT: + pca953x_set_dir(chip, (1 << ul_arg2), + (PCA953X_DIR_OUT << ul_arg2)); + return pca953x_set_val(chip, (1 << ul_arg2), + (ul_arg3 << ul_arg2)); + case PCA953X_CMD_INVERT: + return pca953x_set_pol(chip, (1 << ul_arg2), + (ul_arg3 << ul_arg2)); + default: + /* We should never get here */ + return 1; + } +} + +U_BOOT_CMD( + pca953x, 5, 1, do_pca953x, + "pca953x - pca953x gpio access\n", + "device [dev]\n" + " - show or set current device address\n" +#ifdef CONFIG_CMD_PCA953X_INFO + "pca953x info\n" + " - display info for current chip\n" +#endif + "pca953x output pin 0|1\n" + " - set pin as output and drive low or high\n" + "pca953x invert pin 0|1\n" + " - disable/enable polarity inversion for reads\n" + "pca953x intput pin\n" + " - set pin as input and read value\n" +); + +#endif /* CONFIG_CMD_PCA953X */ -- cgit v1.1 From 9d94aff699eed38b286814fcbb335f3eb8516a0e Mon Sep 17 00:00:00 2001 From: Kumar Gala Date: Tue, 16 Dec 2008 14:59:22 -0600 Subject: NAND FSL elbc: Use virt_to_phys to determine which bank is in use The current code that determines which bank/chipselect is used for a given NAND instance only worked for 32-bit addresses and assumed a 1:1 mapping. This breaks in 36-bit physical configs. The proper way to handle this is to use the virt_to_phys() and BR_PHYS_ADDR() routinues to match the 34-bit lbc bus address with the the virtual address the NAND code uses. Signed-off-by: Kumar Gala Acked-by: Scott Wood --- drivers/mtd/nand/fsl_elbc_nand.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/fsl_elbc_nand.c b/drivers/mtd/nand/fsl_elbc_nand.c index 367c7d7..3f318e0 100644 --- a/drivers/mtd/nand/fsl_elbc_nand.c +++ b/drivers/mtd/nand/fsl_elbc_nand.c @@ -718,7 +718,7 @@ static void fsl_elbc_ctrl_init(void) int board_nand_init(struct nand_chip *nand) { struct fsl_elbc_mtd *priv; - uint32_t br, or; + uint32_t br = 0, or = 0; if (!elbc_ctrl) { fsl_elbc_ctrl_init(); @@ -737,11 +737,13 @@ int board_nand_init(struct nand_chip *nand) * if we could pass more than one datum to the NAND driver... */ for (priv->bank = 0; priv->bank < MAX_BANKS; priv->bank++) { + phys_addr_t base_addr = virt_to_phys(nand->IO_ADDR_R); + br = in_be32(&elbc_ctrl->regs->bank[priv->bank].br); or = in_be32(&elbc_ctrl->regs->bank[priv->bank].or); if ((br & BR_V) && (br & BR_MSEL) == BR_MS_FCM && - (br & or & BR_BA) == (phys_addr_t)nand->IO_ADDR_R) + (br & or & BR_BA) == BR_PHYS_ADDR(base_addr)) break; } -- cgit v1.1 From 9e1fa628bdb64745811cdd26c4f953846c076180 Mon Sep 17 00:00:00 2001 From: Jean-Christophe PLAGNIOL-VILLARD Date: Sun, 11 Jan 2009 16:35:15 +0100 Subject: sh: serial: coding style cleanup Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD Signed-off-by: Nobuhiro Iwamatsu --- drivers/serial/serial_sh.c | 35 ++++++++++++++++++----------------- 1 file changed, 18 insertions(+), 17 deletions(-) (limited to 'drivers') diff --git a/drivers/serial/serial_sh.c b/drivers/serial/serial_sh.c index 1d76a19..e47ec2e 100644 --- a/drivers/serial/serial_sh.c +++ b/drivers/serial/serial_sh.c @@ -49,7 +49,7 @@ # define SCFRDR (vu_char *)(SCIF_BASE + 0x24) #else # define SCFTDR (vu_char *)(SCIF_BASE + 0xC) -# define SCFSR (vu_short *)(SCIF_BASE + 0x10) +# define SCFSR (vu_short *)(SCIF_BASE + 0x10) # define SCFRDR (vu_char *)(SCIF_BASE + 0x14) #endif @@ -64,7 +64,7 @@ #elif defined(CONFIG_CPU_SH7763) # if defined(CONFIG_CONS_SCIF2) # define SCSPTR (vu_short *)(SCIF_BASE + 0x20) -# define SCLSR (vu_short *)(SCIF_BASE + 0x24) +# define SCLSR (vu_short *)(SCIF_BASE + 0x24) # define LSR_ORER 1 # define FIFOLEVEL_MASK 0x1F # else @@ -90,7 +90,7 @@ defined(CONFIG_CPU_SH7722) || \ defined(CONFIG_CPU_SH7203) # define SCSPTR (vu_short *)(SCIF_BASE + 0x20) -# define SCLSR (vu_short *)(SCIF_BASE + 0x24) +# define SCLSR (vu_short *)(SCIF_BASE + 0x24) # define LSR_ORER 1 # define FIFOLEVEL_MASK 0x1F #elif defined(CONFIG_CPU_SH7720) @@ -106,31 +106,32 @@ /* SCBRR register value setting */ #if defined(CONFIG_CPU_SH7720) -# define SCBRR_VALUE(bps, clk) (((clk*2)+16*bps)/(32*bps)-1) +# define SCBRR_VALUE(bps, clk) (((clk * 2) + 16 * bps) / (32 * bps) - 1) #elif defined(CONFIG_CPU_SH7723) && defined(CONFIG_SCIF_A) /* SH7723 SCIFA use bus clock. So clock *2 */ -# define SCBRR_VALUE(bps, clk) (((clk*2*2)+16*bps)/(32*bps)-1) +# define SCBRR_VALUE(bps, clk) (((clk * 2 * 2) + 16 * bps) / (32 * bps) - 1) #else /* Generic SuperH */ -# define SCBRR_VALUE(bps, clk) ((clk+16*bps)/(32*bps)-1) +# define SCBRR_VALUE(bps, clk) ((clk + 16 * bps) / (32 * bps) - 1) #endif -#define SCR_RE (1 << 4) -#define SCR_TE (1 << 5) +#define SCR_RE (1 << 4) +#define SCR_TE (1 << 5) #define FCR_RFRST (1 << 1) /* RFCL */ #define FCR_TFRST (1 << 2) /* TFCL */ -#define FSR_DR (1 << 0) -#define FSR_RDF (1 << 1) -#define FSR_FER (1 << 3) -#define FSR_BRK (1 << 4) -#define FSR_FER (1 << 3) -#define FSR_TEND (1 << 6) -#define FSR_ER (1 << 7) +#define FSR_DR (1 << 0) +#define FSR_RDF (1 << 1) +#define FSR_FER (1 << 3) +#define FSR_BRK (1 << 4) +#define FSR_FER (1 << 3) +#define FSR_TEND (1 << 6) +#define FSR_ER (1 << 7) /*----------------------------------------------------------------------*/ void serial_setbrg(void) { DECLARE_GLOBAL_DATA_PTR; + *SCBRR = SCBRR_VALUE(gd->baudrate, CONFIG_SYS_CLK_FREQ); } @@ -191,8 +192,8 @@ int serial_tstc(void) return serial_rx_fifo_level() ? 1 : 0; } -#define FSR_ERR_CLEAR 0x0063 -#define RDRF_CLEAR 0x00fc +#define FSR_ERR_CLEAR 0x0063 +#define RDRF_CLEAR 0x00fc void handle_error(void) { -- cgit v1.1 From fc83c9273cec6e6e542f4a0ea3b653b7d0513ffa Mon Sep 17 00:00:00 2001 From: Jean-Christophe PLAGNIOL-VILLARD Date: Sun, 11 Jan 2009 16:35:16 +0100 Subject: sh: serial: use readx/writex accessors Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD Signed-off-by: Nobuhiro Iwamatsu --- drivers/serial/serial_sh.c | 46 +++++++++++++++++++++++----------------------- 1 file changed, 23 insertions(+), 23 deletions(-) (limited to 'drivers') diff --git a/drivers/serial/serial_sh.c b/drivers/serial/serial_sh.c index e47ec2e..bfdb2ce 100644 --- a/drivers/serial/serial_sh.c +++ b/drivers/serial/serial_sh.c @@ -18,6 +18,7 @@ */ #include +#include #include #if defined(CONFIG_CONS_SCIF0) @@ -132,17 +133,17 @@ void serial_setbrg(void) { DECLARE_GLOBAL_DATA_PTR; - *SCBRR = SCBRR_VALUE(gd->baudrate, CONFIG_SYS_CLK_FREQ); + writeb(SCBRR_VALUE(gd->baudrate, CONFIG_SYS_CLK_FREQ), SCBRR); } int serial_init(void) { - *SCSCR = (SCR_RE | SCR_TE); - *SCSMR = 0; - *SCSMR = 0; - *SCFCR = (FCR_RFRST | FCR_TFRST); - *SCFCR; - *SCFCR = 0; + writew((SCR_RE | SCR_TE), SCSCR); + writew(0, SCSMR); + writew(0, SCSMR); + writew((FCR_RFRST | FCR_TFRST), SCFCR); + readw(SCFCR); + writew(0, SCFCR); serial_setbrg(); return 0; @@ -151,9 +152,9 @@ int serial_init(void) static int serial_rx_fifo_level(void) { #if defined(SCRFDR) - return (*SCRFDR >> 0) & FIFOLEVEL_MASK; + return (readw(SCRFDR) >> 0) & FIFOLEVEL_MASK; #else - return (*SCFDR >> 0) & FIFOLEVEL_MASK; + return (readw(SCFDR) >> 0) & FIFOLEVEL_MASK; #endif } @@ -162,15 +163,15 @@ void serial_raw_putc(const char c) unsigned int fsr_bits_to_clear; while (1) { - if (*SCFSR & FSR_TEND) { /* Tx fifo is empty */ + if (readw(SCFSR) & FSR_TEND) { /* Tx fifo is empty */ fsr_bits_to_clear = FSR_TEND; break; } } - *SCFTDR = c; + writeb(c, SCFTDR); if (fsr_bits_to_clear != 0) - *SCFSR &= ~fsr_bits_to_clear; + writew(readw(SCFSR) & ~fsr_bits_to_clear, SCFSR); } void serial_putc(const char c) @@ -196,22 +197,21 @@ int serial_tstc(void) #define RDRF_CLEAR 0x00fc void handle_error(void) { - - (void)*SCFSR; - *SCFSR = FSR_ERR_CLEAR; - (void)*SCLSR; - *SCLSR = 0x00; + readw(SCFSR); + writew(FSR_ERR_CLEAR, SCFSR); + readw(SCLSR); + writew(0x00, SCLSR); } int serial_getc_check(void) { unsigned short status; - status = *SCFSR; + status = readw(SCFSR); if (status & (FSR_FER | FSR_ER | FSR_BRK)) handle_error(); - if (*SCLSR & LSR_ORER) + if (readw(SCLSR) & LSR_ORER) handle_error(); return status & (FSR_DR | FSR_RDF); } @@ -224,15 +224,15 @@ int serial_getc(void) while (!serial_getc_check()) ; - ch = *SCFRDR; - status = *SCFSR; + ch = readb(SCFRDR); + status = readw(SCFSR); - *SCFSR = RDRF_CLEAR; + writew(RDRF_CLEAR, SCFSR); if (status & (FSR_FER | FSR_FER | FSR_ER | FSR_BRK)) handle_error(); - if (*SCLSR & LSR_ORER) + if (readw(SCLSR) & LSR_ORER) handle_error(); return ch; -- cgit v1.1 From ef0921d6b05aeb9034158f9bef5323d6da9c925e Mon Sep 17 00:00:00 2001 From: Kyungmin Park Date: Tue, 4 Nov 2008 09:24:07 +0900 Subject: Sync with 2.6.27 Sync with OneNAND kernel codes Signed-off-by: Kyungmin Park --- drivers/mtd/onenand/onenand_base.c | 508 +++++++++++++++++++++++++----------- drivers/mtd/onenand/onenand_bbt.c | 8 +- drivers/mtd/onenand/onenand_uboot.c | 10 +- 3 files changed, 370 insertions(+), 156 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/onenand/onenand_base.c b/drivers/mtd/onenand/onenand_base.c index 9b7bf3a..66214e8 100644 --- a/drivers/mtd/onenand/onenand_base.c +++ b/drivers/mtd/onenand/onenand_base.c @@ -78,20 +78,11 @@ static void onenand_writew(unsigned short value, void __iomem * addr) * * Setup Start Address 1 Register (F100h) */ -static int onenand_block_address(int device, int block) +static int onenand_block_address(struct onenand_chip *this, int block) { - if (device & ONENAND_DEVICE_IS_DDP) { - /* Device Flash Core select, NAND Flash Block Address */ - int dfs = 0, density, mask; - - density = device >> ONENAND_DEVICE_DENSITY_SHIFT; - mask = (1 << (density + 6)); - - if (block & mask) - dfs = 1; - - return (dfs << ONENAND_DDP_SHIFT) | (block & (mask - 1)); - } + /* Device Flash Core select, NAND Flash Block Address */ + if (block & this->density_mask) + return ONENAND_DDP_CHIP1 | (block ^ this->density_mask); return block; } @@ -104,22 +95,13 @@ static int onenand_block_address(int device, int block) * * Setup Start Address 2 Register (F101h) for DDP */ -static int onenand_bufferram_address(int device, int block) +static int onenand_bufferram_address(struct onenand_chip *this, int block) { - if (device & ONENAND_DEVICE_IS_DDP) { - /* Device BufferRAM Select */ - int dbs = 0, density, mask; - - density = device >> ONENAND_DEVICE_DENSITY_SHIFT; - mask = (1 << (density + 6)); - - if (block & mask) - dbs = 1; + /* Device BufferRAM Select */ + if (block & this->density_mask) + return ONENAND_DDP_CHIP1; - return (dbs << ONENAND_DDP_SHIFT); - } - - return 0; + return ONENAND_DDP_CHIP0; } /** @@ -169,6 +151,18 @@ static int onenand_buffer_address(int dataram1, int sectors, int count) } /** + * onenand_get_density - [DEFAULT] Get OneNAND density + * @param dev_id OneNAND device ID + * + * Get OneNAND density from device ID + */ +static inline int onenand_get_density(int dev_id) +{ + int density = dev_id >> ONENAND_DEVICE_DENSITY_SHIFT; + return (density & ONENAND_DEVICE_DENSITY_MASK); +} + +/** * onenand_command - [DEFAULT] Send command to OneNAND device * @param mtd MTD device structure * @param cmd the command to be sent @@ -192,6 +186,7 @@ static int onenand_command(struct mtd_info *mtd, int cmd, loff_t addr, case ONENAND_CMD_UNLOCK: case ONENAND_CMD_LOCK: case ONENAND_CMD_LOCK_TIGHT: + case ONENAND_CMD_UNLOCK_ALL: block = -1; page = -1; break; @@ -212,7 +207,7 @@ static int onenand_command(struct mtd_info *mtd, int cmd, loff_t addr, /* NOTE: The setting order of the registers is very important! */ if (cmd == ONENAND_CMD_BUFFERRAM) { /* Select DataRAM for DDP */ - value = onenand_bufferram_address(this->device_id, block); + value = onenand_bufferram_address(this, block); this->write_word(value, this->base + ONENAND_REG_START_ADDRESS2); @@ -224,9 +219,14 @@ static int onenand_command(struct mtd_info *mtd, int cmd, loff_t addr, if (block != -1) { /* Write 'DFS, FBA' of Flash */ - value = onenand_block_address(this->device_id, block); + value = onenand_block_address(this, block); this->write_word(value, this->base + ONENAND_REG_START_ADDRESS1); + + /* Write 'DFS, FBA' of Flash */ + value = onenand_bufferram_address(this, block); + this->write_word(value, + this->base + ONENAND_REG_START_ADDRESS2); } if (page != -1) { @@ -252,15 +252,6 @@ static int onenand_command(struct mtd_info *mtd, int cmd, loff_t addr, /* Write 'BSA, BSC' of DataRAM */ value = onenand_buffer_address(dataram, sectors, count); this->write_word(value, this->base + ONENAND_REG_START_BUFFER); - - if (readcmd) { - /* Select DataRAM for DDP */ - value = - onenand_bufferram_address(this->device_id, block); - this->write_word(value, - this->base + - ONENAND_REG_START_ADDRESS2); - } } /* Interrupt clear */ @@ -296,14 +287,11 @@ static int onenand_wait(struct mtd_info *mtd, int state) ctrl = this->read_word(this->base + ONENAND_REG_CTRL_STATUS); if (ctrl & ONENAND_CTRL_ERROR) { - MTDDEBUG (MTD_DEBUG_LEVEL0, - "onenand_wait: controller error = 0x%04x\n", ctrl); - return -EAGAIN; - } + printk("onenand_wait: controller error = 0x%04x\n", ctrl); + if (ctrl & ONENAND_CTRL_LOCK) + printk("onenand_wait: it's locked error = 0x%04x\n", + ctrl); - if (ctrl & ONENAND_CTRL_LOCK) { - MTDDEBUG (MTD_DEBUG_LEVEL0, - "onenand_wait: it's locked error = 0x%04x\n", ctrl); return -EIO; } @@ -351,7 +339,7 @@ static inline int onenand_bufferram_offset(struct mtd_info *mtd, int area) * * Read the BufferRAM area */ -static int onenand_read_bufferram(struct mtd_info *mtd, int area, +static int onenand_read_bufferram(struct mtd_info *mtd, loff_t addr, int area, unsigned char *buffer, int offset, size_t count) { @@ -376,7 +364,7 @@ static int onenand_read_bufferram(struct mtd_info *mtd, int area, * * Read the BufferRAM area with Sync. Burst Mode */ -static int onenand_sync_read_bufferram(struct mtd_info *mtd, int area, +static int onenand_sync_read_bufferram(struct mtd_info *mtd, loff_t addr, int area, unsigned char *buffer, int offset, size_t count) { @@ -405,7 +393,7 @@ static int onenand_sync_read_bufferram(struct mtd_info *mtd, int area, * * Write the BufferRAM area */ -static int onenand_write_bufferram(struct mtd_info *mtd, int area, +static int onenand_write_bufferram(struct mtd_info *mtd, loff_t addr, int area, const unsigned char *buffer, int offset, size_t count) { @@ -431,21 +419,39 @@ static int onenand_write_bufferram(struct mtd_info *mtd, int area, static int onenand_check_bufferram(struct mtd_info *mtd, loff_t addr) { struct onenand_chip *this = mtd->priv; - int block, page; - int i; + int blockpage, found = 0; + unsigned int i; - block = (int)(addr >> this->erase_shift); - page = (int)(addr >> this->page_shift); - page &= this->page_mask; +#ifdef CONFIG_S3C64XX + return 0; +#endif - i = ONENAND_CURRENT_BUFFERRAM(this); + if (ONENAND_IS_2PLANE(this)) + blockpage = onenand_get_2x_blockpage(mtd, addr); + else + blockpage = (int) (addr >> this->page_shift); /* Is there valid data? */ - if (this->bufferram[i].block == block && - this->bufferram[i].page == page && this->bufferram[i].valid) - return 1; + i = ONENAND_CURRENT_BUFFERRAM(this); + if (this->bufferram[i].blockpage == blockpage) + found = 1; + else { + /* Check another BufferRAM */ + i = ONENAND_NEXT_BUFFERRAM(this); + if (this->bufferram[i].blockpage == blockpage) { + ONENAND_SET_NEXT_BUFFERRAM(this); + found = 1; + } + } - return 0; + if (found && ONENAND_IS_DDP(this)) { + /* Select DataRAM for DDP */ + int block = (int) (addr >> this->erase_shift); + int value = onenand_bufferram_address(this, block); + this->write_word(value, this->base + ONENAND_REG_START_ADDRESS2); + } + + return found; } /** @@ -460,25 +466,25 @@ static int onenand_update_bufferram(struct mtd_info *mtd, loff_t addr, int valid) { struct onenand_chip *this = mtd->priv; - int block, page; - int i; + int blockpage; + unsigned int i; - block = (int)(addr >> this->erase_shift); - page = (int)(addr >> this->page_shift); - page &= this->page_mask; + if (ONENAND_IS_2PLANE(this)) + blockpage = onenand_get_2x_blockpage(mtd, addr); + else + blockpage = (int)(addr >> this->page_shift); - /* Invalidate BufferRAM */ - for (i = 0; i < MAX_BUFFERRAM; i++) { - if (this->bufferram[i].block == block && - this->bufferram[i].page == page) - this->bufferram[i].valid = 0; - } + /* Invalidate another BufferRAM */ + i = ONENAND_NEXT_BUFFERRAM(this); + if (this->bufferram[i].blockpage == blockpage) + this->bufferram[i].blockpage = -1; /* Update BufferRAM */ i = ONENAND_CURRENT_BUFFERRAM(this); - this->bufferram[i].block = block; - this->bufferram[i].page = page; - this->bufferram[i].valid = valid; + if (valid) + this->bufferram[i].blockpage = blockpage; + else + this->bufferram[i].blockpage = -1; return 0; } @@ -500,10 +506,10 @@ static void onenand_invalidate_bufferram(struct mtd_info *mtd, loff_t addr, /* Invalidate BufferRAM */ for (i = 0; i < MAX_BUFFERRAM; i++) { - loff_t buf_addr = this->bufferram[i].block << this->erase_shift; + loff_t buf_addr = this->bufferram[i].blockpage << this->page_shift; if (buf_addr >= addr && buf_addr < end_addr) - this->bufferram[i].valid = 0; + this->bufferram[i].blockpage = -1; } } @@ -556,7 +562,7 @@ static int onenand_transfer_auto_oob(struct mtd_info *mtd, uint8_t *buf, readend += free->offset - lastgap; lastgap = free->offset + free->length; } - this->read_bufferram(mtd, ONENAND_SPARERAM, oob_buf, 0, mtd->oobsize); + this->read_bufferram(mtd, 0, ONENAND_SPARERAM, oob_buf, 0, mtd->oobsize); free = this->ecclayout->oobfree; for (i = 0; i < MTD_MAX_OOBFREE_ENTRIES && free->length; i++, free++) { int free_end = free->offset + free->length; @@ -594,9 +600,7 @@ static int onenand_read_ops_nolock(struct mtd_info *mtd, loff_t from, int ret = 0, boundary = 0; int writesize = this->writesize; - MTDDEBUG(MTD_DEBUG_LEVEL3, - "onenand_read_ops_nolock: from = 0x%08x, len = %i\n", - (unsigned int) from, (int) len); + MTDDEBUG(MTD_DEBUG_LEVEL3, "onenand_read_ops_nolock: from = 0x%08x, len = %i\n", (unsigned int) from, (int) len); if (ops->mode == MTD_OOB_AUTO) oobsize = this->ecclayout->oobavail; @@ -620,6 +624,7 @@ static int onenand_read_ops_nolock(struct mtd_info *mtd, loff_t from, /* Do first load to bufferRAM */ if (read < len) { if (!onenand_check_bufferram(mtd, from)) { + this->main_buf = buf; this->command(mtd, ONENAND_CMD_READ, from, writesize); ret = this->wait(mtd, FL_READING); onenand_update_bufferram(mtd, from, !ret); @@ -637,6 +642,7 @@ static int onenand_read_ops_nolock(struct mtd_info *mtd, loff_t from, /* If there is more to load then start next load */ from += thislen; if (read + thislen < len) { + this->main_buf = buf + thislen; this->command(mtd, ONENAND_CMD_READ, from, writesize); /* * Chip boundary handling in DDP @@ -653,7 +659,7 @@ static int onenand_read_ops_nolock(struct mtd_info *mtd, loff_t from, } /* While load is going, read from last bufferRAM */ - this->read_bufferram(mtd, ONENAND_DATARAM, buf, column, thislen); + this->read_bufferram(mtd, from - thislen, ONENAND_DATARAM, buf, column, thislen); /* Read oob area if needed */ if (oobbuf) { @@ -663,7 +669,7 @@ static int onenand_read_ops_nolock(struct mtd_info *mtd, loff_t from, if (ops->mode == MTD_OOB_AUTO) onenand_transfer_auto_oob(mtd, oobbuf, oobcolumn, thisooblen); else - this->read_bufferram(mtd, ONENAND_SPARERAM, oobbuf, oobcolumn, thisooblen); + this->read_bufferram(mtd, 0, ONENAND_SPARERAM, oobbuf, oobcolumn, thisooblen); oobread += thisooblen; oobbuf += thisooblen; oobcolumn = 0; @@ -726,9 +732,7 @@ static int onenand_read_oob_nolock(struct mtd_info *mtd, loff_t from, from += ops->ooboffs; - MTDDEBUG(MTD_DEBUG_LEVEL3, - "onenand_read_oob_nolock: from = 0x%08x, len = %i\n", - (unsigned int) from, (int) len); + MTDDEBUG(MTD_DEBUG_LEVEL3, "onenand_read_oob_nolock: from = 0x%08x, len = %i\n", (unsigned int) from, (int) len); /* Initialize return length value */ ops->oobretlen = 0; @@ -759,6 +763,7 @@ static int onenand_read_oob_nolock(struct mtd_info *mtd, loff_t from, thislen = oobsize - column; thislen = min_t(int, thislen, len); + this->spare_buf = buf; this->command(mtd, ONENAND_CMD_READOOB, from, mtd->oobsize); onenand_update_bufferram(mtd, from, 0); @@ -772,7 +777,7 @@ static int onenand_read_oob_nolock(struct mtd_info *mtd, loff_t from, if (mode == MTD_OOB_AUTO) onenand_transfer_auto_oob(mtd, buf, column, thislen); else - this->read_bufferram(mtd, ONENAND_SPARERAM, buf, column, thislen); + this->read_bufferram(mtd, 0, ONENAND_SPARERAM, buf, column, thislen); read += thislen; @@ -886,12 +891,6 @@ static int onenand_bbt_wait(struct mtd_info *mtd, int state) interrupt = this->read_word(this->base + ONENAND_REG_INTERRUPT); ctrl = this->read_word(this->base + ONENAND_REG_CTRL_STATUS); - /* Initial bad block case: 0x2400 or 0x0400 */ - if (ctrl & ONENAND_CTRL_ERROR) { - printk(KERN_DEBUG "onenand_bbt_wait: controller error = 0x%04x\n", ctrl); - return ONENAND_BBT_READ_ERROR; - } - if (interrupt & ONENAND_INT_READ) { int ecc = this->read_word(this->base + ONENAND_REG_ECC_STATUS); if (ecc & ONENAND_ECC_2BIT_ALL) @@ -902,6 +901,12 @@ static int onenand_bbt_wait(struct mtd_info *mtd, int state) return ONENAND_BBT_READ_FATAL_ERROR; } + /* Initial bad block case: 0x2400 or 0x0400 */ + if (ctrl & ONENAND_CTRL_ERROR) { + printk(KERN_DEBUG "onenand_bbt_wait: controller error = 0x%04x\n", ctrl); + return ONENAND_BBT_READ_ERROR; + } + return 0; } @@ -922,9 +927,7 @@ int onenand_bbt_read_oob(struct mtd_info *mtd, loff_t from, size_t len = ops->ooblen; u_char *buf = ops->oobbuf; - MTDDEBUG(MTD_DEBUG_LEVEL3, - "onenand_bbt_read_oob: from = 0x%08x, len = %zi\n", - (unsigned int) from, len); + MTDDEBUG(MTD_DEBUG_LEVEL3, "onenand_bbt_read_oob: from = 0x%08x, len = %zi\n", (unsigned int) from, len); /* Initialize return value */ ops->oobretlen = 0; @@ -945,15 +948,16 @@ int onenand_bbt_read_oob(struct mtd_info *mtd, loff_t from, thislen = mtd->oobsize - column; thislen = min_t(int, thislen, len); + this->spare_buf = buf; this->command(mtd, ONENAND_CMD_READOOB, from, mtd->oobsize); onenand_update_bufferram(mtd, from, 0); - ret = onenand_bbt_wait(mtd, FL_READING); + ret = this->bbt_wait(mtd, FL_READING); if (ret) break; - this->read_bufferram(mtd, ONENAND_SPARERAM, buf, column, thislen); + this->read_spareram(mtd, 0, ONENAND_SPARERAM, buf, column, thislen); read += thislen; if (read == len) break; @@ -995,7 +999,7 @@ static int onenand_verify_oob(struct mtd_info *mtd, const u_char *buf, loff_t to if (status) return status; - this->read_bufferram(mtd, ONENAND_SPARERAM, oob_buf, 0, mtd->oobsize); + this->read_bufferram(mtd, 0, ONENAND_SPARERAM, oob_buf, 0, mtd->oobsize); for (i = 0; i < mtd->oobsize; i++) if (buf[i] != 0xFF && buf[i] != oob_buf[i]) return -EBADMSG; @@ -1115,9 +1119,7 @@ static int onenand_write_ops_nolock(struct mtd_info *mtd, loff_t to, u_char *oobbuf; int ret = 0; - MTDDEBUG(MTD_DEBUG_LEVEL3, - "onenand_write_ops_nolock: to = 0x%08x, len = %i\n", - (unsigned int) to, (int) len); + MTDDEBUG(MTD_DEBUG_LEVEL3, "onenand_write_ops_nolock: to = 0x%08x, len = %i\n", (unsigned int) to, (int) len); /* Initialize retlen, in case of early exit */ ops->retlen = 0; @@ -1161,7 +1163,7 @@ static int onenand_write_ops_nolock(struct mtd_info *mtd, loff_t to, wbuf = this->page_buf; } - this->write_bufferram(mtd, ONENAND_DATARAM, wbuf, 0, mtd->writesize); + this->write_bufferram(mtd, to, ONENAND_DATARAM, wbuf, 0, mtd->writesize); if (oob) { oobbuf = this->oob_buf; @@ -1180,7 +1182,7 @@ static int onenand_write_ops_nolock(struct mtd_info *mtd, loff_t to, } else oobbuf = (u_char *) ffchars; - this->write_bufferram(mtd, ONENAND_SPARERAM, oobbuf, 0, mtd->oobsize); + this->write_bufferram(mtd, 0, ONENAND_SPARERAM, oobbuf, 0, mtd->oobsize); this->command(mtd, ONENAND_CMD_PROG, to, mtd->writesize); @@ -1244,9 +1246,7 @@ static int onenand_write_oob_nolock(struct mtd_info *mtd, loff_t to, to += ops->ooboffs; - MTDDEBUG(MTD_DEBUG_LEVEL3, - "onenand_write_oob_nolock: to = 0x%08x, len = %i\n", - (unsigned int) to, (int) len); + MTDDEBUG(MTD_DEBUG_LEVEL3, "onenand_write_oob_nolock: to = 0x%08x, len = %i\n", (unsigned int) to, (int) len); /* Initialize retlen, in case of early exit */ ops->oobretlen = 0; @@ -1293,7 +1293,7 @@ static int onenand_write_oob_nolock(struct mtd_info *mtd, loff_t to, onenand_fill_auto_oob(mtd, oobbuf, buf, column, thislen); else memcpy(oobbuf + column, buf, thislen); - this->write_bufferram(mtd, ONENAND_SPARERAM, oobbuf, 0, mtd->oobsize); + this->write_bufferram(mtd, 0, ONENAND_SPARERAM, oobbuf, 0, mtd->oobsize); this->command(mtd, ONENAND_CMD_PROGOOB, to, mtd->oobsize); @@ -1466,7 +1466,14 @@ int onenand_erase(struct mtd_info *mtd, struct erase_info *instr) while (len) { - /* TODO Check badblock */ + /* Check if we have a bad block, we do not erase bad blocks */ + if (instr->priv == 0 && onenand_block_isbad_nolock(mtd, addr, 0)) { + printk(KERN_WARNING "onenand_erase: attempt to erase" + " a bad block at addr 0x%08x\n", + (unsigned int) addr); + instr->state = MTD_ERASE_FAILED; + goto erase_exit; + } this->command(mtd, ONENAND_CMD_ERASE, addr, block_size); @@ -1482,8 +1489,16 @@ int onenand_erase(struct mtd_info *mtd, struct erase_info *instr) MTDDEBUG (MTD_DEBUG_LEVEL0, "onenand_erase: " "Failed erase, block %d\n", (unsigned)(addr >> this->erase_shift)); + if (ret == -EPERM) + printk("onenand_erase: " + "Device is write protected!!!\n"); + else + printk("onenand_erase: " + "Failed erase, block %d\n", + (unsigned)(addr >> this->erase_shift)); instr->state = MTD_ERASE_FAILED; instr->fail_addr = addr; + goto erase_exit; } @@ -1493,7 +1508,7 @@ int onenand_erase(struct mtd_info *mtd, struct erase_info *instr) instr->state = MTD_ERASE_DONE; - erase_exit: +erase_exit: ret = instr->state == MTD_ERASE_DONE ? 0 : -EIO; /* Do call back function */ @@ -1569,23 +1584,30 @@ int onenand_block_markbad(struct mtd_info *mtd, loff_t ofs) } /** - * onenand_unlock - [MTD Interface] Unlock block(s) - * @param mtd MTD device structure - * @param ofs offset relative to mtd start - * @param len number of bytes to unlock + * onenand_do_lock_cmd - [OneNAND Interface] Lock or unlock block(s) + * @param mtd MTD device structure + * @param ofs offset relative to mtd start + * @param len number of bytes to lock or unlock + * @param cmd lock or unlock command * - * Unlock one or more blocks + * Lock or unlock one or more blocks */ -int onenand_unlock(struct mtd_info *mtd, loff_t ofs, size_t len) +static int onenand_do_lock_cmd(struct mtd_info *mtd, loff_t ofs, size_t len, int cmd) { struct onenand_chip *this = mtd->priv; int start, end, block, value, status; + int wp_status_mask; start = ofs >> this->erase_shift; end = len >> this->erase_shift; + if (cmd == ONENAND_CMD_LOCK) + wp_status_mask = ONENAND_WP_LS; + else + wp_status_mask = ONENAND_WP_US; + /* Continuous lock scheme */ - if (this->options & ONENAND_CONT_LOCK) { + if (this->options & ONENAND_HAS_CONT_LOCK) { /* Set start block address */ this->write_word(start, this->base + ONENAND_REG_START_BLOCK_ADDRESS); @@ -1593,7 +1615,7 @@ int onenand_unlock(struct mtd_info *mtd, loff_t ofs, size_t len) this->write_word(end - 1, this->base + ONENAND_REG_END_BLOCK_ADDRESS); /* Write unlock command */ - this->command(mtd, ONENAND_CMD_UNLOCK, 0, 0); + this->command(mtd, cmd, 0, 0); /* There's no return value */ this->wait(mtd, FL_UNLOCKING); @@ -1612,7 +1634,14 @@ int onenand_unlock(struct mtd_info *mtd, loff_t ofs, size_t len) } /* Block lock scheme */ - for (block = start; block < end; block++) { + for (block = start; block < start + end; block++) { + /* Set block address */ + value = onenand_block_address(this, block); + this->write_word(value, this->base + ONENAND_REG_START_ADDRESS1); + /* Select DataRAM for DDP */ + value = onenand_bufferram_address(this, block); + this->write_word(value, this->base + ONENAND_REG_START_ADDRESS2); + /* Set start block address */ this->write_word(block, this->base + ONENAND_REG_START_BLOCK_ADDRESS); @@ -1627,11 +1656,6 @@ int onenand_unlock(struct mtd_info *mtd, loff_t ofs, size_t len) & ONENAND_CTRL_ONGO) continue; - /* Set block address for read block status */ - value = onenand_block_address(this->device_id, block); - this->write_word(value, - this->base + ONENAND_REG_START_ADDRESS1); - /* Check lock status */ status = this->read_word(this->base + ONENAND_REG_WP_STATUS); if (!(status & ONENAND_WP_US)) @@ -1643,31 +1667,196 @@ int onenand_unlock(struct mtd_info *mtd, loff_t ofs, size_t len) } /** + * onenand_lock - [MTD Interface] Lock block(s) + * @param mtd MTD device structure + * @param ofs offset relative to mtd start + * @param len number of bytes to unlock + * + * Lock one or more blocks + */ +static int onenand_lock(struct mtd_info *mtd, loff_t ofs, size_t len) +{ + int ret; + + onenand_get_device(mtd, FL_LOCKING); + ret = onenand_do_lock_cmd(mtd, ofs, len, ONENAND_CMD_LOCK); + onenand_release_device(mtd); + return ret; +} + +/** + * onenand_unlock - [MTD Interface] Unlock block(s) + * @param mtd MTD device structure + * @param ofs offset relative to mtd start + * @param len number of bytes to unlock + * + * Unlock one or more blocks + */ +static int onenand_unlock(struct mtd_info *mtd, loff_t ofs, size_t len) +{ + int ret; + + onenand_get_device(mtd, FL_LOCKING); + ret = onenand_do_lock_cmd(mtd, ofs, len, ONENAND_CMD_UNLOCK); + onenand_release_device(mtd); + return ret; +} + +/** + * onenand_check_lock_status - [OneNAND Interface] Check lock status + * @param this onenand chip data structure + * + * Check lock status + */ +static int onenand_check_lock_status(struct onenand_chip *this) +{ + unsigned int value, block, status; + unsigned int end; + + end = this->chipsize >> this->erase_shift; + for (block = 0; block < end; block++) { + /* Set block address */ + value = onenand_block_address(this, block); + this->write_word(value, this->base + ONENAND_REG_START_ADDRESS1); + /* Select DataRAM for DDP */ + value = onenand_bufferram_address(this, block); + this->write_word(value, this->base + ONENAND_REG_START_ADDRESS2); + /* Set start block address */ + this->write_word(block, this->base + ONENAND_REG_START_BLOCK_ADDRESS); + + /* Check lock status */ + status = this->read_word(this->base + ONENAND_REG_WP_STATUS); + if (!(status & ONENAND_WP_US)) { + printk(KERN_ERR "block = %d, wp status = 0x%x\n", block, status); + return 0; + } + } + + return 1; +} + +/** + * onenand_unlock_all - [OneNAND Interface] unlock all blocks + * @param mtd MTD device structure + * + * Unlock all blocks + */ +static void onenand_unlock_all(struct mtd_info *mtd) +{ + struct onenand_chip *this = mtd->priv; + loff_t ofs = 0; + size_t len = this->chipsize; + + if (this->options & ONENAND_HAS_UNLOCK_ALL) { + /* Set start block address */ + this->write_word(0, this->base + ONENAND_REG_START_BLOCK_ADDRESS); + /* Write unlock command */ + this->command(mtd, ONENAND_CMD_UNLOCK_ALL, 0, 0); + + /* There's no return value */ + this->wait(mtd, FL_LOCKING); + + /* Sanity check */ + while (this->read_word(this->base + ONENAND_REG_CTRL_STATUS) + & ONENAND_CTRL_ONGO) + continue; + + return; + + /* Check lock status */ + if (onenand_check_lock_status(this)) + return; + + /* Workaround for all block unlock in DDP */ + if (ONENAND_IS_DDP(this)) { + /* All blocks on another chip */ + ofs = this->chipsize >> 1; + len = this->chipsize >> 1; + } + } + + onenand_do_lock_cmd(mtd, ofs, len, ONENAND_CMD_UNLOCK); +} + + +/** + * onenand_check_features - Check and set OneNAND features + * @param mtd MTD data structure + * + * Check and set OneNAND features + * - lock scheme + * - two plane + */ +static void onenand_check_features(struct mtd_info *mtd) +{ + struct onenand_chip *this = mtd->priv; + unsigned int density, process; + + /* Lock scheme depends on density and process */ + density = onenand_get_density(this->device_id); + process = this->version_id >> ONENAND_VERSION_PROCESS_SHIFT; + + /* Lock scheme */ + switch (density) { + case ONENAND_DEVICE_DENSITY_4Gb: + this->options |= ONENAND_HAS_2PLANE; + + case ONENAND_DEVICE_DENSITY_2Gb: + /* 2Gb DDP don't have 2 plane */ + if (!ONENAND_IS_DDP(this)) + this->options |= ONENAND_HAS_2PLANE; + this->options |= ONENAND_HAS_UNLOCK_ALL; + + case ONENAND_DEVICE_DENSITY_1Gb: + /* A-Die has all block unlock */ + if (process) + this->options |= ONENAND_HAS_UNLOCK_ALL; + break; + + default: + /* Some OneNAND has continuous lock scheme */ + if (!process) + this->options |= ONENAND_HAS_CONT_LOCK; + break; + } + + if (this->options & ONENAND_HAS_CONT_LOCK) + printk(KERN_DEBUG "Lock scheme is Continuous Lock\n"); + if (this->options & ONENAND_HAS_UNLOCK_ALL) + printk(KERN_DEBUG "Chip support all block unlock\n"); + if (this->options & ONENAND_HAS_2PLANE) + printk(KERN_DEBUG "Chip has 2 plane\n"); +} + +/** * onenand_print_device_info - Print device ID * @param device device ID * * Print device ID */ -char * onenand_print_device_info(int device) +char *onenand_print_device_info(int device, int version) { int vcc, demuxed, ddp, density; char *dev_info = malloc(80); + char *p = dev_info; vcc = device & ONENAND_DEVICE_VCC_MASK; demuxed = device & ONENAND_DEVICE_IS_DEMUX; ddp = device & ONENAND_DEVICE_IS_DDP; density = device >> ONENAND_DEVICE_DENSITY_SHIFT; - sprintf(dev_info, "%sOneNAND%s %dMB %sV 16-bit (0x%02x)", + p += sprintf(dev_info, "%sOneNAND%s %dMB %sV 16-bit (0x%02x)", demuxed ? "" : "Muxed ", ddp ? "(DDP)" : "", (16 << density), vcc ? "2.65/3.3" : "1.8", device); + sprintf(p, "\nOneNAND version = 0x%04x", version); + printk("%s\n", dev_info); + return dev_info; } static const struct onenand_manufacturers onenand_manuf_ids[] = { {ONENAND_MFR_SAMSUNG, "Samsung"}, - {ONENAND_MFR_UNKNOWN, "Unknown"} }; /** @@ -1678,19 +1867,24 @@ static const struct onenand_manufacturers onenand_manuf_ids[] = { */ static int onenand_check_maf(int manuf) { + int size = ARRAY_SIZE(onenand_manuf_ids); + char *name; int i; - for (i = 0; onenand_manuf_ids[i].id; i++) { + for (i = 0; size; i++) if (manuf == onenand_manuf_ids[i].id) break; - } + + if (i < size) + name = onenand_manuf_ids[i].name; + else + name = "Unknown"; #ifdef ONENAND_DEBUG - printk(KERN_DEBUG "OneNAND Manufacturer: %s (0x%0x)\n", - onenand_manuf_ids[i].name, manuf); + printk(KERN_DEBUG "OneNAND Manufacturer: %s (0x%0x)\n", name, manuf); #endif - return (i != ONENAND_MFR_UNKNOWN); + return i == size; } /** @@ -1703,9 +1897,14 @@ static int onenand_check_maf(int manuf) static int onenand_probe(struct mtd_info *mtd) { struct onenand_chip *this = mtd->priv; - int bram_maf_id, bram_dev_id, maf_id, dev_id; - int version_id; + int bram_maf_id, bram_dev_id, maf_id, dev_id, ver_id; int density; + int syscfg; + + /* Save system configuration 1 */ + syscfg = this->read_word(this->base + ONENAND_REG_SYS_CFG1); + /* Clear Sync. Burst Read mode to read BootRAM */ + this->write_word((syscfg & ~ONENAND_SYS_CFG1_SYNC_READ), this->base + ONENAND_REG_SYS_CFG1); /* Send the command for reading device ID from BootRAM */ this->write_word(ONENAND_CMD_READID, this->base + ONENAND_BOOTRAM); @@ -1714,19 +1913,23 @@ static int onenand_probe(struct mtd_info *mtd) bram_maf_id = this->read_word(this->base + ONENAND_BOOTRAM + 0x0); bram_dev_id = this->read_word(this->base + ONENAND_BOOTRAM + 0x2); - /* Check manufacturer ID */ - if (onenand_check_maf(bram_maf_id)) - return -ENXIO; - /* Reset OneNAND to read default register values */ this->write_word(ONENAND_CMD_RESET, this->base + ONENAND_BOOTRAM); /* Wait reset */ this->wait(mtd, FL_RESETING); + /* Restore system configuration 1 */ + this->write_word(syscfg, this->base + ONENAND_REG_SYS_CFG1); + + /* Check manufacturer ID */ + if (onenand_check_maf(bram_maf_id)) + return -ENXIO; + /* Read manufacturer and device IDs from Register */ maf_id = this->read_word(this->base + ONENAND_REG_MANUFACTURER_ID); dev_id = this->read_word(this->base + ONENAND_REG_DEVICE_ID); + ver_id = this->read_word(this->base + ONENAND_REG_VERSION_ID); /* Check OneNAND device */ if (maf_id != bram_maf_id || dev_id != bram_dev_id) @@ -1739,11 +1942,16 @@ static int onenand_probe(struct mtd_info *mtd) } /* Flash device information */ - mtd->name = onenand_print_device_info(dev_id); + mtd->name = onenand_print_device_info(dev_id, ver_id); this->device_id = dev_id; - density = dev_id >> ONENAND_DEVICE_DENSITY_SHIFT; + density = onenand_get_density(dev_id); this->chipsize = (16 << density) << 20; + /* Set density mask. it is used for DDP */ + if (ONENAND_IS_DDP(this)) + this->density_mask = (1 << (density + 6)); + else + this->density_mask = 0; /* OneNAND page size & block size */ /* The data buffer size is equal to page size */ @@ -1764,18 +1972,8 @@ static int onenand_probe(struct mtd_info *mtd) mtd->size = this->chipsize; - /* Version ID */ - version_id = this->read_word(this->base + ONENAND_REG_VERSION_ID); -#ifdef ONENAND_DEBUG - printk(KERN_DEBUG "OneNAND version = 0x%04x\n", version_id); -#endif - - /* Lock scheme */ - if (density <= ONENAND_DEVICE_DENSITY_512Mb && - !(version_id >> ONENAND_VERSION_PROCESS_SHIFT)) { - printk(KERN_INFO "Lock scheme is Continues Lock\n"); - this->options |= ONENAND_CONT_LOCK; - } + /* Check OneNAND features */ + onenand_check_features(mtd); mtd->flags = MTD_CAP_NANDFLASH; mtd->erase = onenand_erase; @@ -1813,12 +2011,19 @@ int onenand_scan(struct mtd_info *mtd, int maxchips) this->command = onenand_command; if (!this->wait) this->wait = onenand_wait; + if (!this->bbt_wait) + this->bbt_wait = onenand_bbt_wait; if (!this->read_bufferram) this->read_bufferram = onenand_read_bufferram; + if (!this->read_spareram) + this->read_spareram = onenand_read_bufferram; if (!this->write_bufferram) this->write_bufferram = onenand_write_bufferram; + if (!this->scan_bbt) + this->scan_bbt = onenand_default_bbt; + if (onenand_probe(mtd)) return -ENXIO; @@ -1850,9 +2055,10 @@ int onenand_scan(struct mtd_info *mtd, int maxchips) this->options |= ONENAND_OOBBUF_ALLOC; } - onenand_unlock(mtd, 0, mtd->size); + /* Unlock whole block */ + onenand_unlock_all(mtd); - return onenand_default_bbt(mtd); + return this->scan_bbt(mtd); } /** diff --git a/drivers/mtd/onenand/onenand_bbt.c b/drivers/mtd/onenand/onenand_bbt.c index f6092b9..d538f95 100644 --- a/drivers/mtd/onenand/onenand_bbt.c +++ b/drivers/mtd/onenand/onenand_bbt.c @@ -3,7 +3,7 @@ * * Bad Block Table support for the OneNAND driver * - * Copyright(c) 2005-2007 Samsung Electronics + * Copyright(c) 2005-2008 Samsung Electronics * Kyungmin Park * * TODO: @@ -54,7 +54,7 @@ static int check_short_pattern(uint8_t * buf, int len, int paglen, * @param buf temporary buffer * @param bd descriptor for the good/bad block search pattern * @param chip create the table for a specific chip, -1 read all chips. - * Applies only if NAND_BBT_PERCHIP option is set + * Applies only if NAND_BBT_PERCHIP option is set * * Create a bad block table by scanning the device * for the given good/bad block identify pattern @@ -156,8 +156,8 @@ static int onenand_isbad_bbt(struct mtd_info *mtd, loff_t offs, int allowbbt) res = (bbm->bbt[block >> 3] >> (block & 0x06)) & 0x03; MTDDEBUG (MTD_DEBUG_LEVEL2, - "onenand_isbad_bbt: bbt info for offs 0x%08x: (block %d) 0x%02x\n", - (unsigned int)offs, block >> 1, res); + "onenand_isbad_bbt: bbt info for offs 0x%08x: (block %d) 0x%02x\n", + (unsigned int)offs, block >> 1, res); switch ((int)res) { case 0x00: diff --git a/drivers/mtd/onenand/onenand_uboot.c b/drivers/mtd/onenand/onenand_uboot.c index 08082f3..4541b22 100644 --- a/drivers/mtd/onenand/onenand_uboot.c +++ b/drivers/mtd/onenand/onenand_uboot.c @@ -26,9 +26,17 @@ void onenand_init(void) memset(&onenand_mtd, 0, sizeof(struct mtd_info)); memset(&onenand_chip, 0, sizeof(struct onenand_chip)); - onenand_chip.base = (void *) CONFIG_SYS_ONENAND_BASE; onenand_mtd.priv = &onenand_chip; +#ifdef CONFIG_USE_ONENAND_BOARD_INIT + /* + * It's used for some board init required + */ + onenand_board_init(&onenand_mtd); +#else + onenand_chip.base = (void *) CONFIG_SYS_ONENAND_BASE; +#endif + onenand_scan(&onenand_mtd, 1); puts("OneNAND: "); -- cgit v1.1 From 4fca3310d611cc0f51d7295ef3557afbdbd91dc3 Mon Sep 17 00:00:00 2001 From: Stefan Roese Date: Tue, 11 Nov 2008 10:28:53 +0100 Subject: OneNAND: Fix compiler warnings Signed-off-by: Stefan Roese --- drivers/mtd/onenand/onenand_base.c | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) (limited to 'drivers') diff --git a/drivers/mtd/onenand/onenand_base.c b/drivers/mtd/onenand/onenand_base.c index 66214e8..8d004d3 100644 --- a/drivers/mtd/onenand/onenand_base.c +++ b/drivers/mtd/onenand/onenand_base.c @@ -409,6 +409,30 @@ static int onenand_write_bufferram(struct mtd_info *mtd, loff_t addr, int area, } /** + * onenand_get_2x_blockpage - [GENERIC] Get blockpage at 2x program mode + * @param mtd MTD data structure + * @param addr address to check + * @return blockpage address + * + * Get blockpage address at 2x program mode + */ +static int onenand_get_2x_blockpage(struct mtd_info *mtd, loff_t addr) +{ + struct onenand_chip *this = mtd->priv; + int blockpage, block, page; + + /* Calculate the even block number */ + block = (int) (addr >> this->erase_shift) & ~1; + /* Is it the odd plane? */ + if (addr & this->writesize) + block++; + page = (int) (addr >> (this->page_shift + 1)) & this->page_mask; + blockpage = (block << 7) | page; + + return blockpage; +} + +/** * onenand_check_bufferram - [GENERIC] Check BufferRAM information * @param mtd MTD data structure * @param addr address to check @@ -1666,6 +1690,7 @@ static int onenand_do_lock_cmd(struct mtd_info *mtd, loff_t ofs, size_t len, int return 0; } +#ifdef ONENAND_LINUX /** * onenand_lock - [MTD Interface] Lock block(s) * @param mtd MTD device structure @@ -1701,6 +1726,7 @@ static int onenand_unlock(struct mtd_info *mtd, loff_t ofs, size_t len) onenand_release_device(mtd); return ret; } +#endif /** * onenand_check_lock_status - [OneNAND Interface] Check lock status -- cgit v1.1 From 8cf11f3aa78673730e9ecbbe4b75213b53f212c8 Mon Sep 17 00:00:00 2001 From: Stefan Roese Date: Tue, 11 Nov 2008 10:29:09 +0100 Subject: OneNAND: Save version_id in onenand_chip struct The version (ver_id) was not stored in the onenand_chip structure and because of this the continuous locking scheme could be enabled on some chips. Signed-off-by: Stefan Roese --- drivers/mtd/onenand/onenand_base.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/mtd/onenand/onenand_base.c b/drivers/mtd/onenand/onenand_base.c index 8d004d3..f62b1aa 100644 --- a/drivers/mtd/onenand/onenand_base.c +++ b/drivers/mtd/onenand/onenand_base.c @@ -1970,6 +1970,7 @@ static int onenand_probe(struct mtd_info *mtd) /* Flash device information */ mtd->name = onenand_print_device_info(dev_id, ver_id); this->device_id = dev_id; + this->version_id = ver_id; density = onenand_get_density(dev_id); this->chipsize = (16 << density) << 20; -- cgit v1.1 From 1714f51a2009baaecf3d4f6e3bd8c4e93a8d3f23 Mon Sep 17 00:00:00 2001 From: Kyungmin Park Date: Thu, 13 Nov 2008 15:14:33 +0900 Subject: Add markbad function Add missing markbad function If not, it's hang when it entered the mtd->mark_bad(). Signed-off-by: Kyungmin Park --- drivers/mtd/onenand/onenand_base.c | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) (limited to 'drivers') diff --git a/drivers/mtd/onenand/onenand_base.c b/drivers/mtd/onenand/onenand_base.c index f62b1aa..dcc969f 100644 --- a/drivers/mtd/onenand/onenand_base.c +++ b/drivers/mtd/onenand/onenand_base.c @@ -1584,6 +1584,37 @@ int onenand_block_isbad(struct mtd_info *mtd, loff_t ofs) } /** + * onenand_default_block_markbad - [DEFAULT] mark a block bad + * @param mtd MTD device structure + * @param ofs offset from device start + * + * This is the default implementation, which can be overridden by + * a hardware specific driver. + */ +static int onenand_default_block_markbad(struct mtd_info *mtd, loff_t ofs) +{ + struct onenand_chip *this = mtd->priv; + struct bbm_info *bbm = this->bbm; + u_char buf[2] = {0, 0}; + struct mtd_oob_ops ops = { + .mode = MTD_OOB_PLACE, + .ooblen = 2, + .oobbuf = buf, + .ooboffs = 0, + }; + int block; + + /* Get block number */ + block = ((int) ofs) >> bbm->bbt_erase_shift; + if (bbm->bbt) + bbm->bbt[block >> 2] |= 0x01 << ((block & 0x03) << 1); + + /* We write two bytes, so we dont have to mess with 16 bit access */ + ofs += mtd->oobsize + (bbm->badblockpos & ~0x01); + return onenand_write_oob_nolock(mtd, ofs, &ops); +} + +/** * onenand_block_markbad - [MTD Interface] Mark the block at the given offset as bad * @param mtd MTD device structure * @param ofs offset relative to mtd start @@ -2048,6 +2079,8 @@ int onenand_scan(struct mtd_info *mtd, int maxchips) if (!this->write_bufferram) this->write_bufferram = onenand_write_bufferram; + if (!this->block_markbad) + this->block_markbad = onenand_default_block_markbad; if (!this->scan_bbt) this->scan_bbt = onenand_default_bbt; -- cgit v1.1 From 1ae39862044ebb1e682234b51f94421e3f871d6a Mon Sep 17 00:00:00 2001 From: Stefan Roese Date: Tue, 2 Dec 2008 11:06:47 +0100 Subject: OneNAND: Additional sync with 2.6.27 - Add subpage write support - Add onenand_oob_64/32 ecclayout This has been missing and without it UBI has some incompatibilies issues with the current (>= 2.6.27) Linux kernel version. vid_hdr_offset is placed differently (2048 instead of 512) without this fix. Signed-off-by: Stefan Roese Signed-off-by: Scott Wood --- drivers/mtd/onenand/onenand_base.c | 72 +++++++++++++++++++++++++++++++++++++- 1 file changed, 71 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mtd/onenand/onenand_base.c b/drivers/mtd/onenand/onenand_base.c index dcc969f..d482437 100644 --- a/drivers/mtd/onenand/onenand_base.c +++ b/drivers/mtd/onenand/onenand_base.c @@ -36,6 +36,35 @@ static inline void *memcpy_16(void *dst, const void *src, unsigned int len) return ret; } +/** + * onenand_oob_64 - oob info for large (2KB) page + */ +static struct nand_ecclayout onenand_oob_64 = { + .eccbytes = 20, + .eccpos = { + 8, 9, 10, 11, 12, + 24, 25, 26, 27, 28, + 40, 41, 42, 43, 44, + 56, 57, 58, 59, 60, + }, + .oobfree = { + {2, 3}, {14, 2}, {18, 3}, {30, 2}, + {34, 3}, {46, 2}, {50, 3}, {62, 2} + } +}; + +/** + * onenand_oob_32 - oob info for middle (1KB) page + */ +static struct nand_ecclayout onenand_oob_32 = { + .eccbytes = 10, + .eccpos = { + 8, 9, 10, 11, 12, + 24, 25, 26, 27, 28, + }, + .oobfree = { {2, 3}, {14, 2}, {18, 3}, {30, 2} } +}; + static const unsigned char ffchars[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 16 */ @@ -1079,7 +1108,7 @@ static int onenand_verify(struct mtd_info *mtd, const u_char *buf, loff_t addr, #define onenand_verify_oob(...) (0) #endif -#define NOTALIGNED(x) ((x & (mtd->writesize - 1)) != 0) +#define NOTALIGNED(x) ((x & (this->subpagesize - 1)) != 0) /** * onenand_fill_auto_oob - [Internal] oob auto-placement transfer @@ -2058,6 +2087,7 @@ static int onenand_probe(struct mtd_info *mtd) */ int onenand_scan(struct mtd_info *mtd, int maxchips) { + int i; struct onenand_chip *this = mtd->priv; if (!this->read_word) @@ -2115,6 +2145,46 @@ int onenand_scan(struct mtd_info *mtd, int maxchips) this->options |= ONENAND_OOBBUF_ALLOC; } + this->state = FL_READY; + + /* + * Allow subpage writes up to oobsize. + */ + switch (mtd->oobsize) { + case 64: + this->ecclayout = &onenand_oob_64; + mtd->subpage_sft = 2; + break; + + case 32: + this->ecclayout = &onenand_oob_32; + mtd->subpage_sft = 1; + break; + + default: + printk(KERN_WARNING "No OOB scheme defined for oobsize %d\n", + mtd->oobsize); + mtd->subpage_sft = 0; + /* To prevent kernel oops */ + this->ecclayout = &onenand_oob_32; + break; + } + + this->subpagesize = mtd->writesize >> mtd->subpage_sft; + + /* + * The number of bytes available for a client to place data into + * the out of band area + */ + this->ecclayout->oobavail = 0; + for (i = 0; i < MTD_MAX_OOBFREE_ENTRIES && + this->ecclayout->oobfree[i].length; i++) + this->ecclayout->oobavail += + this->ecclayout->oobfree[i].length; + mtd->oobavail = this->ecclayout->oobavail; + + mtd->ecclayout = this->ecclayout; + /* Unlock whole block */ onenand_unlock_all(mtd); -- cgit v1.1 From 69fb8be4fc07162fdf6edf04bdc7233b0e9a920e Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Sat, 6 Dec 2008 02:40:55 -0500 Subject: NAND: move board_nand_init to nand.h Rather than putting the function prototype for board_nand_init() in the one place where it gets called, put it into nand.h so that every place that also defines it gets the prototype. Otherwise, errors can go silently unnoticed such as using the wrong return value (void rather than int) when defining the function. Signed-off-by: Mike Frysinger Signed-off-by: Scott Wood --- drivers/mtd/nand/nand.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/nand.c b/drivers/mtd/nand/nand.c index eeb19ff..cf92617 100644 --- a/drivers/mtd/nand/nand.c +++ b/drivers/mtd/nand/nand.c @@ -36,8 +36,6 @@ static ulong base_address[CONFIG_SYS_MAX_NAND_DEVICE] = CONFIG_SYS_NAND_BASE_LIS static const char default_nand_name[] = "nand"; -extern int board_nand_init(struct nand_chip *nand); - static void nand_init_chip(struct mtd_info *mtd, struct nand_chip *nand, ulong base_addr) { -- cgit v1.1 From 50657c273278f74378e1ac39b41d612b92fdffa0 Mon Sep 17 00:00:00 2001 From: Nishanth Menon Date: Sat, 13 Dec 2008 09:43:06 -0600 Subject: NAND: Enable nand lock, unlock feature Enable nand lock, unlock and status of lock feature. Not every device and platform requires this, hence, it is under define for CONFIG_CMD_NAND_LOCK_UNLOCK Nand unlock and status operate on block boundary instead of page boundary. Details in: http://www.micron.com/products/partdetail?part=MT29C2G24MAKLAJG-6%20IT Intial solution provided by Vikram Pandita Includes preliminary suggestions from Scott Wood Signed-off-by: Nishanth Menon Signed-off-by: Scott Wood --- drivers/mtd/nand/nand_util.c | 79 ++++++++++++++++++++++++-------------------- 1 file changed, 43 insertions(+), 36 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/nand_util.c b/drivers/mtd/nand/nand_util.c index d86c987..77da53e 100644 --- a/drivers/mtd/nand/nand_util.c +++ b/drivers/mtd/nand/nand_util.c @@ -238,7 +238,8 @@ static struct nand_ecclayout autoplace_ecclayout = { #endif /* XXX U-BOOT XXX */ -#if 0 +#ifdef CONFIG_CMD_NAND_LOCK_UNLOCK + /****************************************************************************** * Support for locking / unlocking operations of some NAND devices *****************************************************************************/ @@ -253,7 +254,7 @@ static struct nand_ecclayout autoplace_ecclayout = { * nand_lock: Set all pages of NAND flash chip to the LOCK or LOCK-TIGHT * state * - * @param meminfo nand mtd instance + * @param mtd nand mtd instance * @param tight bring device in lock tight mode * * @return 0 on success, -1 in case of error @@ -270,21 +271,21 @@ static struct nand_ecclayout autoplace_ecclayout = { * calls will fail. It is only posible to leave lock-tight state by * an hardware signal (low pulse on _WP pin) or by power down. */ -int nand_lock(nand_info_t *meminfo, int tight) +int nand_lock(struct mtd_info *mtd, int tight) { int ret = 0; int status; - struct nand_chip *this = meminfo->priv; + struct nand_chip *chip = mtd->priv; /* select the NAND device */ - this->select_chip(meminfo, 0); + chip->select_chip(mtd, 0); - this->cmdfunc(meminfo, + chip->cmdfunc(mtd, (tight ? NAND_CMD_LOCK_TIGHT : NAND_CMD_LOCK), -1, -1); /* call wait ready function */ - status = this->waitfunc(meminfo, this, FL_WRITING); + status = chip->waitfunc(mtd, chip); /* see if device thinks it succeeded */ if (status & 0x01) { @@ -292,7 +293,7 @@ int nand_lock(nand_info_t *meminfo, int tight) } /* de-select the NAND device */ - this->select_chip(meminfo, -1); + chip->select_chip(mtd, -1); return ret; } @@ -300,7 +301,7 @@ int nand_lock(nand_info_t *meminfo, int tight) * nand_get_lock_status: - query current lock state from one page of NAND * flash * - * @param meminfo nand mtd instance + * @param mtd nand mtd instance * @param offset page address to query (muss be page aligned!) * * @return -1 in case of error @@ -311,19 +312,19 @@ int nand_lock(nand_info_t *meminfo, int tight) * NAND_LOCK_STATUS_UNLOCK: page unlocked * */ -int nand_get_lock_status(nand_info_t *meminfo, ulong offset) +int nand_get_lock_status(struct mtd_info *mtd, ulong offset) { int ret = 0; int chipnr; int page; - struct nand_chip *this = meminfo->priv; + struct nand_chip *chip = mtd->priv; /* select the NAND device */ - chipnr = (int)(offset >> this->chip_shift); - this->select_chip(meminfo, chipnr); + chipnr = (int)(offset >> chip->chip_shift); + chip->select_chip(mtd, chipnr); - if ((offset & (meminfo->writesize - 1)) != 0) { + if ((offset & (mtd->writesize - 1)) != 0) { printf ("nand_get_lock_status: " "Start address must be beginning of " "nand page!\n"); @@ -332,16 +333,16 @@ int nand_get_lock_status(nand_info_t *meminfo, ulong offset) } /* check the Lock Status */ - page = (int)(offset >> this->page_shift); - this->cmdfunc(meminfo, NAND_CMD_LOCK_STATUS, -1, page & this->pagemask); + page = (int)(offset >> chip->page_shift); + chip->cmdfunc(mtd, NAND_CMD_LOCK_STATUS, -1, page & chip->pagemask); - ret = this->read_byte(meminfo) & (NAND_LOCK_STATUS_TIGHT + ret = chip->read_byte(mtd) & (NAND_LOCK_STATUS_TIGHT | NAND_LOCK_STATUS_LOCK | NAND_LOCK_STATUS_UNLOCK); out: /* de-select the NAND device */ - this->select_chip(meminfo, -1); + chip->select_chip(mtd, -1); return ret; } @@ -349,59 +350,65 @@ int nand_get_lock_status(nand_info_t *meminfo, ulong offset) * nand_unlock: - Unlock area of NAND pages * only one consecutive area can be unlocked at one time! * - * @param meminfo nand mtd instance + * @param mtd nand mtd instance * @param start start byte address * @param length number of bytes to unlock (must be a multiple of * page size nand->writesize) * * @return 0 on success, -1 in case of error */ -int nand_unlock(nand_info_t *meminfo, ulong start, ulong length) +int nand_unlock(struct mtd_info *mtd, ulong start, ulong length) { int ret = 0; int chipnr; int status; int page; - struct nand_chip *this = meminfo->priv; + struct nand_chip *chip = mtd->priv; printf ("nand_unlock: start: %08x, length: %d!\n", (int)start, (int)length); /* select the NAND device */ - chipnr = (int)(start >> this->chip_shift); - this->select_chip(meminfo, chipnr); + chipnr = (int)(start >> chip->chip_shift); + chip->select_chip(mtd, chipnr); /* check the WP bit */ - this->cmdfunc(meminfo, NAND_CMD_STATUS, -1, -1); - if ((this->read_byte(meminfo) & 0x80) == 0) { + chip->cmdfunc(mtd, NAND_CMD_STATUS, -1, -1); + if (!(chip->read_byte(mtd) & NAND_STATUS_WP)) { printf ("nand_unlock: Device is write protected!\n"); ret = -1; goto out; } - if ((start & (meminfo->writesize - 1)) != 0) { + if ((start & (mtd->erasesize - 1)) != 0) { printf ("nand_unlock: Start address must be beginning of " - "nand page!\n"); + "nand block!\n"); ret = -1; goto out; } - if (length == 0 || (length & (meminfo->writesize - 1)) != 0) { - printf ("nand_unlock: Length must be a multiple of nand page " - "size!\n"); + if (length == 0 || (length & (mtd->erasesize - 1)) != 0) { + printf ("nand_unlock: Length must be a multiple of nand block " + "size %08x!\n", mtd->erasesize); ret = -1; goto out; } + /* + * Set length so that the last address is set to the + * starting address of the last block + */ + length -= mtd->erasesize; + /* submit address of first page to unlock */ - page = (int)(start >> this->page_shift); - this->cmdfunc(meminfo, NAND_CMD_UNLOCK1, -1, page & this->pagemask); + page = (int)(start >> chip->page_shift); + chip->cmdfunc(mtd, NAND_CMD_UNLOCK1, -1, page & chip->pagemask); /* submit ADDRESS of LAST page to unlock */ - page += (int)(length >> this->page_shift) - 1; - this->cmdfunc(meminfo, NAND_CMD_UNLOCK2, -1, page & this->pagemask); + page += (int)(length >> chip->page_shift); + chip->cmdfunc(mtd, NAND_CMD_UNLOCK2, -1, page & chip->pagemask); /* call wait ready function */ - status = this->waitfunc(meminfo, this, FL_WRITING); + status = chip->waitfunc(mtd, chip); /* see if device thinks it succeeded */ if (status & 0x01) { /* there was an error */ @@ -411,7 +418,7 @@ int nand_unlock(nand_info_t *meminfo, ulong start, ulong length) out: /* de-select the NAND device */ - this->select_chip(meminfo, -1); + chip->select_chip(mtd, -1); return ret; } #endif -- cgit v1.1 From 6c869637fef31e66380f0ea1d49690a2e26ec0d7 Mon Sep 17 00:00:00 2001 From: Wolfgang Grandegger Date: Fri, 16 Jan 2009 18:55:54 +0100 Subject: NAND: rename NAND_MAX_CHIPS to CONFIG_SYS_NAND_MAX_CHIPS This patch renames NAND_MAX_CHIPS to CONFIG_SYS_NAND_MAX_CHIPS and changes the default from 8 to 1 for the legacy and the new MTD NAND layer. This allows to remove all NAND_MAX_CHIPS definitions in the board config files because none of the boards use multi chip support (NAND_MAX_CHIPS > 1) so far. The bamboo and the DU440 define #define NAND_MAX_CHIPS CONFIG_SYS_MAX_NAND_DEVICE but that's bogus and did not work anyhow. Signed-off-by: Wolfgang Grandegger Signed-off-by: Scott Wood --- drivers/mtd/nand/nand_base.c | 2 +- drivers/mtd/nand_legacy/nand_legacy.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index 94a65d4..ef37f97 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -2144,7 +2144,7 @@ int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr, { int page, len, status, pages_per_block, ret, chipnr; struct nand_chip *chip = mtd->priv; - int rewrite_bbt[NAND_MAX_CHIPS]={0}; + int rewrite_bbt[CONFIG_SYS_NAND_MAX_CHIPS]={0}; unsigned int bbt_masked_page = 0xffffffff; MTDDEBUG (MTD_DEBUG_LEVEL3, "nand_erase: start = 0x%08x, len = %i\n", diff --git a/drivers/mtd/nand_legacy/nand_legacy.c b/drivers/mtd/nand_legacy/nand_legacy.c index 407e901..441780a 100644 --- a/drivers/mtd/nand_legacy/nand_legacy.c +++ b/drivers/mtd/nand_legacy/nand_legacy.c @@ -457,7 +457,7 @@ static void NanD_ScanChips(struct nand_chip *nand) { int floor, chip; int numchips[NAND_MAX_FLOORS]; - int maxchips = NAND_MAX_CHIPS; + int maxchips = CONFIG_SYS_NAND_MAX_CHIPS; int ret = 1; nand->numchips = 0; -- cgit v1.1 From d4bade8d77aa20e2846fa4accff0e7fa7961a134 Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Sun, 18 Jan 2009 19:46:06 -0500 Subject: nand: fixup printf modifiers to match types used Signed-off-by: Mike Frysinger Signed-off-by: Scott Wood --- drivers/mtd/nand/nand_util.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/nand_util.c b/drivers/mtd/nand/nand_util.c index 77da53e..6ba52b3 100644 --- a/drivers/mtd/nand/nand_util.c +++ b/drivers/mtd/nand/nand_util.c @@ -495,7 +495,7 @@ int nand_write_skip_bad(nand_info_t *nand, size_t offset, size_t *length, if (len_incl_bad == *length) { rval = nand_write (nand, offset, length, buffer); if (rval != 0) - printf ("NAND write to offset %x failed %d\n", + printf ("NAND write to offset %zx failed %d\n", offset, rval); return rval; @@ -506,7 +506,7 @@ int nand_write_skip_bad(nand_info_t *nand, size_t offset, size_t *length, size_t write_size; if (nand_block_isbad (nand, offset & ~(nand->erasesize - 1))) { - printf ("Skip bad block 0x%08x\n", + printf ("Skip bad block 0x%08zx\n", offset & ~(nand->erasesize - 1)); offset += nand->erasesize - block_offset; continue; @@ -519,7 +519,7 @@ int nand_write_skip_bad(nand_info_t *nand, size_t offset, size_t *length, rval = nand_write (nand, offset, &write_size, p_buffer); if (rval != 0) { - printf ("NAND write to offset %x failed %d\n", + printf ("NAND write to offset %zx failed %d\n", offset, rval); *length -= left_to_write; return rval; @@ -565,7 +565,7 @@ int nand_read_skip_bad(nand_info_t *nand, size_t offset, size_t *length, if (len_incl_bad == *length) { rval = nand_read (nand, offset, length, buffer); if (rval != 0) - printf ("NAND read from offset %x failed %d\n", + printf ("NAND read from offset %zx failed %d\n", offset, rval); return rval; @@ -576,7 +576,7 @@ int nand_read_skip_bad(nand_info_t *nand, size_t offset, size_t *length, size_t read_length; if (nand_block_isbad (nand, offset & ~(nand->erasesize - 1))) { - printf ("Skipping bad block 0x%08x\n", + printf ("Skipping bad block 0x%08zx\n", offset & ~(nand->erasesize - 1)); offset += nand->erasesize - block_offset; continue; @@ -589,7 +589,7 @@ int nand_read_skip_bad(nand_info_t *nand, size_t offset, size_t *length, rval = nand_read (nand, offset, &read_length, p_buffer); if (rval != 0) { - printf ("NAND read from offset %x failed %d\n", + printf ("NAND read from offset %zx failed %d\n", offset, rval); *length -= left_to_read; return rval; -- cgit v1.1 From 94f9279f7bbdc01bbc7cf85aedf9b545943b94c3 Mon Sep 17 00:00:00 2001 From: Niklaus Giger Date: Mon, 8 Dec 2008 17:24:08 +0100 Subject: Added legacy flash ST Micro M29W040B --- drivers/mtd/jedec_flash.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) (limited to 'drivers') diff --git a/drivers/mtd/jedec_flash.c b/drivers/mtd/jedec_flash.c index 226e1e4..2d99d4d 100644 --- a/drivers/mtd/jedec_flash.c +++ b/drivers/mtd/jedec_flash.c @@ -215,6 +215,20 @@ static const struct amd_flash_info jedec_table[] = { ERASEINFO(0x01000,128), } }, + { + .mfr_id = STM_MANUFACT, + .dev_id = STM_ID_M29W040B, + .name = "ST Micro M29W040B", + .uaddr = { + [0] = MTD_UADDR_0x0555_0x02AA /* x8 */ + }, + .DevSize = SIZE_512KiB, + .CmdSet = P_ID_AMD_STD, + .NumEraseRegions= 1, + .regions = { + ERASEINFO(0x10000,8), + } + }, #endif #ifdef CONFIG_SYS_FLASH_LEGACY_512Kx16 { -- cgit v1.1 From 97cae3a4c68d856374ccc70fd2c5f8714cc94f7d Mon Sep 17 00:00:00 2001 From: Stefan Roese Date: Mon, 15 Dec 2008 15:40:12 +0100 Subject: serial: Rename driver vcth to vct to support other board variants Moved driver vcth.c to vct.c to better reflect the VCT board series. This driver is now used by the VCT platforms: vct_premium vct_platinum vct_platinumsvc Signed-off-by: Stefan Roese --- drivers/serial/Makefile | 2 +- drivers/serial/vct.c | 125 ++++++++++++++++++++++++++++++++++++++++++++++++ drivers/serial/vcth.c | 121 ---------------------------------------------- 3 files changed, 126 insertions(+), 122 deletions(-) create mode 100755 drivers/serial/vct.c delete mode 100755 drivers/serial/vcth.c (limited to 'drivers') diff --git a/drivers/serial/Makefile b/drivers/serial/Makefile index 17235ff..c7a1882 100644 --- a/drivers/serial/Makefile +++ b/drivers/serial/Makefile @@ -38,7 +38,7 @@ COBJS-$(CONFIG_PL011_SERIAL) += serial_pl01x.o COBJS-$(CONFIG_XILINX_UARTLITE) += serial_xuartlite.o COBJS-$(CONFIG_SCIF_CONSOLE) += serial_sh.o COBJS-$(CONFIG_USB_TTY) += usbtty.o -COBJS-$(CONFIG_VCTH_SERIAL) += vcth.o +COBJS-$(CONFIG_VCT_SERIAL) += vct.o COBJS := $(sort $(COBJS-y)) SRCS := $(COBJS:.o=.c) diff --git a/drivers/serial/vct.c b/drivers/serial/vct.c new file mode 100755 index 0000000..556c114 --- /dev/null +++ b/drivers/serial/vct.c @@ -0,0 +1,125 @@ +/* + * (C) Copyright 2008 Stefan Roese , DENX Software Engineering + * + * 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 +#include +#include + +#ifdef CONFIG_VCT_PLATINUMAVC +#define UART_1_BASE 0xBDC30000 +#else +#define UART_1_BASE 0xBF89C000 +#endif + +#define UART_RBR_OFF 0x00 /* receiver buffer reg */ +#define UART_THR_OFF 0x00 /* transmit holding reg */ +#define UART_DLL_OFF 0x00 /* divisor latch low reg */ +#define UART_IER_OFF 0x04 /* interrupt enable reg */ +#define UART_DLH_OFF 0x04 /* receiver buffer reg */ +#define UART_FCR_OFF 0x08 /* fifo control register */ +#define UART_LCR_OFF 0x0c /* line control register */ +#define UART_MCR_OFF 0x10 /* modem control register */ +#define UART_LSR_OFF 0x14 /* line status register */ +#define UART_MSR_OFF 0x18 /* modem status register */ +#define UART_SCR_OFF 0x1c /* scratch pad register */ + +#define UART_RCV_DATA_RDY 0x01 /* Data Received */ +#define UART_XMT_HOLD_EMPTY 0x20 +#define UART_TRANSMIT_EMPTY 0x40 + +/* 7 bit on line control reg. enalbing rw to dll and dlh */ +#define UART_LCR_DLAB 0x0080 + +#define UART___9600_BDR 0x84 +#define UART__19200_BDR 0x42 +#define UART_115200_BDR 0x08 + +#define UART_DIS_ALL_INTER 0x00 /* disable all interrupts */ + +#define UART_5DATA_BITS 0x0000 /* 5 [bits] 1.5 bits 2 */ +#define UART_6DATA_BITS 0x0001 /* 6 [bits] 1 bits 2 */ +#define UART_7DATA_BITS 0x0002 /* 7 [bits] 1 bits 2 */ +#define UART_8DATA_BITS 0x0003 /* 8 [bits] 1 bits 2 */ + +static void vct_uart_set_baud_rate(u32 address, u32 dh, u32 dl) +{ + u32 val = __raw_readl(UART_1_BASE + UART_LCR_OFF); + + /* set 7 bit on 1 */ + val |= UART_LCR_DLAB; + __raw_writel(val, UART_1_BASE + UART_LCR_OFF); + + __raw_writel(dl, UART_1_BASE + UART_DLL_OFF); + __raw_writel(dh, UART_1_BASE + UART_DLH_OFF); + + /* set 7 bit on 0 */ + val &= ~UART_LCR_DLAB; + __raw_writel(val, UART_1_BASE + UART_LCR_OFF); + + return; +} + +int serial_init(void) +{ + __raw_writel(UART_DIS_ALL_INTER, UART_1_BASE + UART_IER_OFF); + vct_uart_set_baud_rate(UART_1_BASE, 0, UART_115200_BDR); + __raw_writel(UART_8DATA_BITS, UART_1_BASE + UART_LCR_OFF); + + return 0; +} + +void serial_setbrg(void) +{ + /* + * Baudrate change not supported currently, fixed to 115200 baud + */ +} + +void serial_putc(const char c) +{ + if (c == '\n') + serial_putc('\r'); + + while (!(UART_XMT_HOLD_EMPTY & __raw_readl(UART_1_BASE + UART_LSR_OFF))) + ; + + __raw_writel(c, UART_1_BASE + UART_THR_OFF); +} + +void serial_puts(const char *s) +{ + while (*s) + serial_putc(*s++); +} + +int serial_getc(void) +{ + while (!(UART_RCV_DATA_RDY & __raw_readl(UART_1_BASE + UART_LSR_OFF))) + ; + + return __raw_readl(UART_1_BASE + UART_RBR_OFF) & 0xff; +} + +int serial_tstc(void) +{ + if (!(UART_RCV_DATA_RDY & __raw_readl(UART_1_BASE + UART_LSR_OFF))) + return 0; + + return 1; +} diff --git a/drivers/serial/vcth.c b/drivers/serial/vcth.c deleted file mode 100755 index 2c847d0..0000000 --- a/drivers/serial/vcth.c +++ /dev/null @@ -1,121 +0,0 @@ -/* - * (C) Copyright 2008 Stefan Roese , DENX Software Engineering - * - * 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 -#include -#include - -#define UART_1_BASE 0xBF89C000 - -#define UART_RBR_OFF 0x00 /* receiver buffer reg */ -#define UART_THR_OFF 0x00 /* transmit holding reg */ -#define UART_DLL_OFF 0x00 /* divisor latch low reg */ -#define UART_IER_OFF 0x04 /* interrupt enable reg */ -#define UART_DLH_OFF 0x04 /* receiver buffer reg */ -#define UART_FCR_OFF 0x08 /* fifo control register */ -#define UART_LCR_OFF 0x0c /* line control register */ -#define UART_MCR_OFF 0x10 /* modem control register */ -#define UART_LSR_OFF 0x14 /* line status register */ -#define UART_MSR_OFF 0x18 /* modem status register */ -#define UART_SCR_OFF 0x1c /* scratch pad register */ - -#define UART_RCV_DATA_RDY 0x01 /* Data Received */ -#define UART_XMT_HOLD_EMPTY 0x20 -#define UART_TRANSMIT_EMPTY 0x40 - -/* 7 bit on line control reg. enalbing rw to dll and dlh */ -#define UART_LCR_DLAB 0x0080 - -#define UART___9600_BDR 0x84 -#define UART__19200_BDR 0x42 -#define UART_115200_BDR 0x08 - -#define UART_DIS_ALL_INTER 0x00 /* disable all interrupts */ - -#define UART_5DATA_BITS 0x0000 /* 5 [bits] 1.5 bits 2 */ -#define UART_6DATA_BITS 0x0001 /* 6 [bits] 1 bits 2 */ -#define UART_7DATA_BITS 0x0002 /* 7 [bits] 1 bits 2 */ -#define UART_8DATA_BITS 0x0003 /* 8 [bits] 1 bits 2 */ - -static void vcth_uart_set_baud_rate(u32 address, u32 dh, u32 dl) -{ - u32 val = __raw_readl(UART_1_BASE + UART_LCR_OFF); - - /* set 7 bit on 1 */ - val |= UART_LCR_DLAB; - __raw_writel(val, UART_1_BASE + UART_LCR_OFF); - - __raw_writel(dl, UART_1_BASE + UART_DLL_OFF); - __raw_writel(dh, UART_1_BASE + UART_DLH_OFF); - - /* set 7 bit on 0 */ - val &= ~UART_LCR_DLAB; - __raw_writel(val, UART_1_BASE + UART_LCR_OFF); - - return; -} - -int serial_init(void) -{ - __raw_writel(UART_DIS_ALL_INTER, UART_1_BASE + UART_IER_OFF); - vcth_uart_set_baud_rate(UART_1_BASE, 0, UART_115200_BDR); - __raw_writel(UART_8DATA_BITS, UART_1_BASE + UART_LCR_OFF); - - return 0; -} - -void serial_setbrg(void) -{ - /* - * Baudrate change not supported currently, fixed to 115200 baud - */ -} - -void serial_putc(const char c) -{ - if (c == '\n') - serial_putc('\r'); - - while (!(UART_XMT_HOLD_EMPTY & __raw_readl(UART_1_BASE + UART_LSR_OFF))) - ; - - __raw_writel(c, UART_1_BASE + UART_THR_OFF); -} - -void serial_puts(const char *s) -{ - while (*s) - serial_putc(*s++); -} - -int serial_getc(void) -{ - while (!(UART_RCV_DATA_RDY & __raw_readl(UART_1_BASE + UART_LSR_OFF))) - ; - - return __raw_readl(UART_1_BASE + UART_RBR_OFF) & 0xff; -} - -int serial_tstc(void) -{ - if (!(UART_RCV_DATA_RDY & __raw_readl(UART_1_BASE + UART_LSR_OFF))) - return 0; - - return 1; -} -- cgit v1.1 From a7c9310457e85b4598abe5b304108edf11332e2f Mon Sep 17 00:00:00 2001 From: Peter Tyser Date: Wed, 17 Dec 2008 16:36:22 -0600 Subject: Add support for Maxim's DS4510 I2C device Initial support for the DS4510, a CPU supervisor with integrated EEPROM, SRAM, and 4 programmable non-volatile GPIO pins. The CONFIG_DS4510 define enables support for the device while the CONFIG_CMD_DS4510 define enables the ds4510 command. The additional CONFIG_DS4510_INFO, CONFIG_DS4510_MEM, and CONFIG_DS4510_RST defines add additional sub-commands to the ds4510 command when defined. Signed-off-by: Peter Tyser --- drivers/misc/Makefile | 1 + drivers/misc/ds4510.c | 424 ++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 425 insertions(+) create mode 100644 drivers/misc/ds4510.c (limited to 'drivers') diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index 01e0f39..ea2bf87 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -26,6 +26,7 @@ include $(TOPDIR)/config.mk LIB := $(obj)libmisc.a COBJS-$(CONFIG_ALI152X) += ali512x.o +COBJS-$(CONFIG_DS4510) += ds4510.o COBJS-$(CONFIG_FSL_LAW) += fsl_law.o COBJS-$(CONFIG_NS87308) += ns87308.o COBJS-$(CONFIG_STATUS_LED) += status_led.o diff --git a/drivers/misc/ds4510.c b/drivers/misc/ds4510.c new file mode 100644 index 0000000..4cd2fc2 --- /dev/null +++ b/drivers/misc/ds4510.c @@ -0,0 +1,424 @@ +/* + * Copyright 2008 Extreme Engineering Solutions, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * Version 2 as published by the Free Software Foundation. + * + * 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 + */ + +/* + * Driver for DS4510, a CPU supervisor with integrated EEPROM, SRAM, + * and 4 programmable non-volatile GPIO pins. + */ + +#include +#include +#include +#include + +/* Default to an address that hopefully won't corrupt other i2c devices */ +#ifndef CONFIG_SYS_I2C_DS4510_ADDR +#define CONFIG_SYS_I2C_DS4510_ADDR (~0) +#endif + +enum { + DS4510_CMD_INFO, + DS4510_CMD_DEVICE, + DS4510_CMD_NV, + DS4510_CMD_RSTDELAY, + DS4510_CMD_OUTPUT, + DS4510_CMD_INPUT, + DS4510_CMD_PULLUP, + DS4510_CMD_EEPROM, + DS4510_CMD_SEEPROM, + DS4510_CMD_SRAM, +}; + +/* + * Write to DS4510, taking page boundaries into account + */ +int ds4510_mem_write(uint8_t chip, int offset, uint8_t *buf, int count) +{ + int wrlen; + int i = 0; + + do { + wrlen = DS4510_EEPROM_PAGE_SIZE - + DS4510_EEPROM_PAGE_OFFSET(offset); + if (count < wrlen) + wrlen = count; + if (i2c_write(chip, offset, 1, &buf[i], wrlen)) + return -1; + + /* + * This delay isn't needed for SRAM writes but shouldn't delay + * things too much, so do it unconditionally for simplicity + */ + udelay(DS4510_EEPROM_PAGE_WRITE_DELAY_MS * 1000); + count -= wrlen; + offset += wrlen; + i += wrlen; + } while (count > 0); + + return 0; +} + +/* + * General read from DS4510 + */ +int ds4510_mem_read(uint8_t chip, int offset, uint8_t *buf, int count) +{ + return i2c_read(chip, offset, 1, buf, count); +} + +/* + * Write SEE bit in config register. + * nv = 0 - Writes to SEEPROM registers behave like EEPROM + * nv = 1 - Writes to SEEPROM registers behave like SRAM + */ +int ds4510_see_write(uint8_t chip, uint8_t nv) +{ + uint8_t data; + + if (i2c_read(chip, DS4510_CFG, 1, &data, 1)) + return -1; + + if (nv) /* Treat SEEPROM bits as EEPROM */ + data &= ~DS4510_CFG_SEE; + else /* Treat SEEPROM bits as SRAM */ + data |= DS4510_CFG_SEE; + + return ds4510_mem_write(chip, DS4510_CFG, &data, 1); +} + +/* + * Write de-assertion of reset signal delay + */ +int ds4510_rstdelay_write(uint8_t chip, uint8_t delay) +{ + uint8_t data; + + if (i2c_read(chip, DS4510_RSTDELAY, 1, &data, 1)) + return -1; + + data &= ~DS4510_RSTDELAY_MASK; + data |= delay & DS4510_RSTDELAY_MASK; + + return ds4510_mem_write(chip, DS4510_RSTDELAY, &data, 1); +} + +/* + * Write pullup characteristics of IO pins + */ +int ds4510_pullup_write(uint8_t chip, uint8_t val) +{ + val &= DS4510_IO_MASK; + + return ds4510_mem_write(chip, DS4510_PULLUP, (uint8_t *)&val, 1); +} + +/* + * Read pullup characteristics of IO pins + */ +int ds4510_pullup_read(uint8_t chip) +{ + uint8_t val; + + if (i2c_read(chip, DS4510_PULLUP, 1, &val, 1)) + return -1; + + return val & DS4510_IO_MASK; +} + +/* + * Write drive level of IO pins + */ +int ds4510_gpio_write(uint8_t chip, uint8_t val) +{ + uint8_t data; + int i; + + for (i = 0; i < DS4510_NUM_IO; i++) { + if (i2c_read(chip, DS4510_IO0 - i, 1, &data, 1)) + return -1; + + if (val & (0x1 << i)) + data |= 0x1; + else + data &= ~0x1; + + if (ds4510_mem_write(chip, DS4510_IO0 - i, &data, 1)) + return -1; + } + + return 0; +} + +/* + * Read drive level of IO pins + */ +int ds4510_gpio_read(uint8_t chip) +{ + uint8_t data; + int val = 0; + int i; + + for (i = 0; i < DS4510_NUM_IO; i++) { + if (i2c_read(chip, DS4510_IO0 - i, 1, &data, 1)) + return -1; + + if (data & 1) + val |= (1 << i); + } + + return val; +} + +/* + * Read physical level of IO pins + */ +int ds4510_gpio_read_val(uint8_t chip) +{ + uint8_t val; + + if (i2c_read(chip, DS4510_IO_STATUS, 1, &val, 1)) + return -1; + + return val & DS4510_IO_MASK; +} + +#ifdef CONFIG_CMD_DS4510 +#ifdef CONFIG_CMD_DS4510_INFO +/* + * Display DS4510 information + */ +static int ds4510_info(uint8_t chip) +{ + int i; + int tmp; + uint8_t data; + + printf("DS4510 @ 0x%x:\n\n", chip); + + if (i2c_read(chip, DS4510_RSTDELAY, 1, &data, 1)) + return -1; + printf("rstdelay = 0x%x\n\n", data & DS4510_RSTDELAY_MASK); + + if (i2c_read(chip, DS4510_CFG, 1, &data, 1)) + return -1; + printf("config = 0x%x\n", data); + printf(" /ready = %d\n", data & DS4510_CFG_READY ? 1 : 0); + printf(" trip pt = %d\n", data & DS4510_CFG_TRIP_POINT ? 1 : 0); + printf(" rst sts = %d\n", data & DS4510_CFG_RESET ? 1 : 0); + printf(" /see = %d\n", data & DS4510_CFG_SEE ? 1 : 0); + printf(" swrst = %d\n\n", data & DS4510_CFG_SWRST ? 1 : 0); + + printf("gpio pins: 3210\n"); + printf("---------------\n"); + printf("pullup "); + + tmp = ds4510_pullup_read(chip); + if (tmp == -1) + return tmp; + for (i = DS4510_NUM_IO - 1; i >= 0; i--) + printf("%d", (tmp & (1 << i)) ? 1 : 0); + printf("\n"); + + printf("driven "); + tmp = ds4510_gpio_read(chip); + if (tmp == -1) + return -1; + for (i = DS4510_NUM_IO - 1; i >= 0; i--) + printf("%d", (tmp & (1 << i)) ? 1 : 0); + printf("\n"); + + printf("read "); + tmp = ds4510_gpio_read_val(chip); + if (tmp == -1) + return -1; + for (i = DS4510_NUM_IO - 1; i >= 0; i--) + printf("%d", (tmp & (1 << i)) ? 1 : 0); + printf("\n"); + + return 0; +} +#endif /* CONFIG_CMD_DS4510_INFO */ + +cmd_tbl_t cmd_ds4510[] = { + U_BOOT_CMD_MKENT(device, 3, 0, (void *)DS4510_CMD_DEVICE, "", ""), + U_BOOT_CMD_MKENT(nv, 3, 0, (void *)DS4510_CMD_NV, "", ""), + U_BOOT_CMD_MKENT(output, 4, 0, (void *)DS4510_CMD_OUTPUT, "", ""), + U_BOOT_CMD_MKENT(input, 3, 0, (void *)DS4510_CMD_INPUT, "", ""), + U_BOOT_CMD_MKENT(pullup, 4, 0, (void *)DS4510_CMD_PULLUP, "", ""), +#ifdef CONFIG_CMD_DS4510_INFO + U_BOOT_CMD_MKENT(info, 2, 0, (void *)DS4510_CMD_INFO, "", ""), +#endif +#ifdef CONFIG_CMD_DS4510_RST + U_BOOT_CMD_MKENT(rstdelay, 3, 0, (void *)DS4510_CMD_RSTDELAY, "", ""), +#endif +#ifdef CONFIG_CMD_DS4510_MEM + U_BOOT_CMD_MKENT(eeprom, 6, 0, (void *)DS4510_CMD_EEPROM, "", ""), + U_BOOT_CMD_MKENT(seeprom, 6, 0, (void *)DS4510_CMD_SEEPROM, "", ""), + U_BOOT_CMD_MKENT(sram, 6, 0, (void *)DS4510_CMD_SRAM, "", ""), +#endif +}; + +int do_ds4510(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) +{ + static uint8_t chip = CONFIG_SYS_I2C_DS4510_ADDR; + cmd_tbl_t *c; + ulong ul_arg2 = 0; + ulong ul_arg3 = 0; + int tmp; +#ifdef CONFIG_CMD_DS4510_MEM + ulong addr; + ulong off; + ulong cnt; + int end; + int (*rw_func)(uint8_t, int, uint8_t *, int); +#endif + + c = find_cmd_tbl(argv[1], cmd_ds4510, ARRAY_SIZE(cmd_ds4510)); + + /* All commands but "device" require 'maxargs' arguments */ + if (!c || !((argc == (c->maxargs)) || + (((int)c->cmd == DS4510_CMD_DEVICE) && + (argc == (c->maxargs - 1))))) { + printf("Usage:\n%s\n", cmdtp->usage); + return 1; + } + + /* arg2 used as chip addr and pin number */ + if (argc > 2) + ul_arg2 = simple_strtoul(argv[2], NULL, 16); + + /* arg3 used as output/pullup value */ + if (argc > 3) + ul_arg3 = simple_strtoul(argv[3], NULL, 16); + + switch ((int)c->cmd) { + case DS4510_CMD_DEVICE: + if (argc == 3) + chip = ul_arg2; + printf("Current device address: 0x%x\n", chip); + return 0; + case DS4510_CMD_NV: + return ds4510_see_write(chip, ul_arg2); + case DS4510_CMD_OUTPUT: + tmp = ds4510_gpio_read(chip); + if (tmp == -1) + return -1; + if (ul_arg3) + tmp |= (1 << ul_arg2); + else + tmp &= ~(1 << ul_arg2); + return ds4510_gpio_write(chip, tmp); + case DS4510_CMD_INPUT: + tmp = ds4510_gpio_read_val(chip); + if (tmp == -1) + return -1; + return (tmp & (1 << ul_arg2)) != 0; + case DS4510_CMD_PULLUP: + tmp = ds4510_pullup_read(chip); + if (tmp == -1) + return -1; + if (ul_arg3) + tmp |= (1 << ul_arg2); + else + tmp &= ~(1 << ul_arg2); + return ds4510_pullup_write(chip, tmp); +#ifdef CONFIG_CMD_DS4510_INFO + case DS4510_CMD_INFO: + return ds4510_info(chip); +#endif +#ifdef CONFIG_CMD_DS4510_RST + case DS4510_CMD_RSTDELAY: + return ds4510_rstdelay_write(chip, ul_arg2); +#endif +#ifdef CONFIG_CMD_DS4510_MEM + case DS4510_CMD_EEPROM: + end = DS4510_EEPROM + DS4510_EEPROM_SIZE; + off = DS4510_EEPROM; + break; + case DS4510_CMD_SEEPROM: + end = DS4510_SEEPROM + DS4510_SEEPROM_SIZE; + off = DS4510_SEEPROM; + break; + case DS4510_CMD_SRAM: + end = DS4510_SRAM + DS4510_SRAM_SIZE; + off = DS4510_SRAM; + break; +#endif + default: + /* We should never get here... */ + return 1; + } + +#ifdef CONFIG_CMD_DS4510_MEM + /* Only eeprom, seeprom, and sram commands should make it here */ + if (strcmp(argv[2], "read") == 0) { + rw_func = ds4510_mem_read; + } else if (strcmp(argv[2], "write") == 0) { + rw_func = ds4510_mem_write; + } else { + printf("Usage:\n%s\n", cmdtp->usage); + return 1; + } + + addr = simple_strtoul(argv[3], NULL, 16); + off += simple_strtoul(argv[4], NULL, 16); + cnt = simple_strtoul(argv[5], NULL, 16); + + if ((off + cnt) > end) { + printf("ERROR: invalid len\n"); + return -1; + } + + return rw_func(chip, off, (uint8_t *)addr, cnt); +#endif +} + +U_BOOT_CMD( + ds4510, 6, 1, do_ds4510, + "ds4510 - ds4510 eeprom/seeprom/sram/gpio access\n", + "device [dev]\n" + " - show or set current device address\n" +#ifdef CONFIG_CMD_DS4510_INFO + "ds4510 info\n" + " - display ds4510 info\n" +#endif + "ds4510 output pin 0|1\n" + " - set pin low or high-Z\n" + "ds4510 input pin\n" + " - read value of pin\n" + "ds4510 pullup pin 0|1\n" + " - disable/enable pullup on specified pin\n" + "ds4510 nv 0|1\n" + " - make gpio and seeprom writes volatile/non-volatile\n" +#ifdef CONFIG_CMD_DS4510_RST + "ds4510 rstdelay 0-3\n" + " - set reset output delay\n" +#endif +#ifdef CONFIG_CMD_DS4510_MEM + "ds4510 eeprom read addr off cnt\n" + "ds4510 eeprom write addr off cnt\n" + " - read/write 'cnt' bytes at EEPROM offset 'off'\n" + "ds4510 seeprom read addr off cnt\n" + "ds4510 seeprom write addr off cnt\n" + " - read/write 'cnt' bytes at SRAM-shadowed EEPROM offset 'off'\n" + "ds4510 sram read addr off cnt\n" + "ds4510 sram write addr off cnt\n" + " - read/write 'cnt' bytes at SRAM offset 'off'\n" +#endif +); +#endif /* CONFIG_CMD_DS4510 */ -- cgit v1.1 From 68f8718df2ed4c2f43031407ccf6cfa81125dddc Mon Sep 17 00:00:00 2001 From: Brad Bozarth Date: Thu, 1 Jan 2009 22:45:47 -0500 Subject: spi flash: fix crash due to spi flash miscommunication Higher spi flash layers expect to be given back a pointer that was malloced so that it can free the result, but the lower layers return a pointer that is in the middle of the malloced memory. Reorder the members of the lower spi structures so that things work out. Signed-off-by: Brad Bozarth Signed-off-by: Mike Frysinger Acked-by: Haavard Skinnemoen --- drivers/mtd/spi/atmel.c | 3 ++- drivers/mtd/spi/stmicro.c | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/spi/atmel.c b/drivers/mtd/spi/atmel.c index 10fcf0c..a5f51ca 100644 --- a/drivers/mtd/spi/atmel.c +++ b/drivers/mtd/spi/atmel.c @@ -39,9 +39,10 @@ struct atmel_spi_flash_params { const char *name; }; +/* spi_flash needs to be first so upper layers can free() it */ struct atmel_spi_flash { - const struct atmel_spi_flash_params *params; struct spi_flash flash; + const struct atmel_spi_flash_params *params; }; static inline struct atmel_spi_flash * diff --git a/drivers/mtd/spi/stmicro.c b/drivers/mtd/spi/stmicro.c index 86324e4..e7dda91 100644 --- a/drivers/mtd/spi/stmicro.c +++ b/drivers/mtd/spi/stmicro.c @@ -64,9 +64,10 @@ struct stmicro_spi_flash_params { const char *name; }; +/* spi_flash needs to be first so upper layers can free() it */ struct stmicro_spi_flash { - const struct stmicro_spi_flash_params *params; struct spi_flash flash; + const struct stmicro_spi_flash_params *params; }; static inline struct stmicro_spi_flash *to_stmicro_spi_flash(struct spi_flash -- cgit v1.1