diff options
author | Ben Warren <biggerbadderben@gmail.com> | 2009-01-24 20:44:56 -0800 |
---|---|---|
committer | Ben Warren <biggerbadderben@gmail.com> | 2009-01-24 20:44:56 -0800 |
commit | ef29884b2708a6cce3b77f4ccaeea193d4e02c22 (patch) | |
tree | 2f6a28872ab9f5de9fec7ac878b8801f5f536eec /drivers | |
parent | 4cd8ed40615a7d741ef2f09ee53779ec6907b8a6 (diff) | |
parent | 8f86a3636ef88427f880610638e80991adc41896 (diff) | |
download | u-boot-imx-ef29884b2708a6cce3b77f4ccaeea193d4e02c22.zip u-boot-imx-ef29884b2708a6cce3b77f4ccaeea193d4e02c22.tar.gz u-boot-imx-ef29884b2708a6cce3b77f4ccaeea193d4e02c22.tar.bz2 |
Merge git://git.denx.de/u-boot into u-boot
Diffstat (limited to 'drivers')
27 files changed, 1371 insertions, 297 deletions
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 <common.h> +#include <i2c.h> +#include <pca953x.h> + +/* 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 */ 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..a27de5a 100644 --- a/drivers/i2c/soft_i2c.c +++ b/drivers/i2c/soft_i2c.c @@ -434,23 +434,3 @@ int i2c_write(uchar chip, uint addr, int alen, uchar *buffer, int len) send_stop(); 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); -} 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 <common.h> +#include <i2c.h> +#include <command.h> +#include <ds4510.h> + +/* 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 */ 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 { 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 <linux/mtd/compat.h> /* 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++) { 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; } 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) { diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index ba05b76..ef37f97 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) @@ -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/nand_util.c b/drivers/mtd/nand/nand_util.c index d86c987..6ba52b3 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 @@ -488,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; @@ -499,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; @@ -512,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; @@ -558,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; @@ -569,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; @@ -582,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; 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; diff --git a/drivers/mtd/onenand/onenand_base.c b/drivers/mtd/onenand/onenand_base.c index 9b7bf3a..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 */ @@ -78,20 +107,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 +124,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 +180,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 +215,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 +236,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 +248,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 +281,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 +316,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 +368,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 +393,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 +422,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) { @@ -421,6 +438,30 @@ static int onenand_write_bufferram(struct mtd_info *mtd, 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 @@ -431,21 +472,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 +519,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 +559,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 +615,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 +653,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 +677,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 +695,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 +712,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 +722,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 +785,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 +816,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 +830,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 +944,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 +954,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 +980,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 +1001,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 +1052,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; @@ -1051,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 @@ -1115,9 +1172,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 +1216,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 +1235,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 +1299,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 +1346,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 +1519,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 +1542,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 +1561,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 */ @@ -1545,6 +1613,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 @@ -1569,23 +1668,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 +1699,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 +1718,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 +1740,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)) @@ -1642,32 +1750,199 @@ int onenand_unlock(struct mtd_info *mtd, loff_t ofs, size_t len) return 0; } +#ifdef ONENAND_LINUX +/** + * 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; +} +#endif + +/** + * 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 +1953,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 +1983,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 +1999,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 +2028,17 @@ 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; + this->version_id = ver_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 +2059,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; @@ -1802,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) @@ -1813,12 +2099,21 @@ 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->block_markbad) + this->block_markbad = onenand_default_block_markbad; + if (!this->scan_bbt) + this->scan_bbt = onenand_default_bbt; + if (onenand_probe(mtd)) return -ENXIO; @@ -1850,9 +2145,50 @@ int onenand_scan(struct mtd_info *mtd, int maxchips) this->options |= ONENAND_OOBBUF_ALLOC; } - onenand_unlock(mtd, 0, mtd->size); + 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); - 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 <kyungmin.park@samsung.com> * * 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: "); 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 b8b835a..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 @@ -137,7 +138,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; } diff --git a/drivers/mtd/ubi/build.c b/drivers/mtd/ubi/build.c index 17cabb2..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); @@ -1059,6 +1060,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); 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)) 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 <pci.h> #include <asm/immap_fsl_pci.h> +/* 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 <libfdt.h> #include <fdt_support.h> 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); 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/serial_sh.c b/drivers/serial/serial_sh.c index f30532b..bfdb2ce 100644 --- a/drivers/serial/serial_sh.c +++ b/drivers/serial/serial_sh.c @@ -18,6 +18,7 @@ */ #include <common.h> +#include <asm/io.h> #include <asm/processor.h> #if defined(CONFIG_CONS_SCIF0) @@ -49,7 +50,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 +65,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,11 +91,11 @@ 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) -# define SCLSR (vu_short *)(SCIF_BASE + 0x24) +# define SCLSR SCFSR # define LSR_ORER 0x0200 # define FIFOLEVEL_MASK 0x1F #elif defined(CONFIG_CPU_SH7710) || \ @@ -106,42 +107,43 @@ /* 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); + + 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; @@ -150,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 } @@ -161,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) @@ -191,26 +193,25 @@ 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) { - - (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); } @@ -223,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; diff --git a/drivers/serial/vcth.c b/drivers/serial/vct.c index 2c847d0..556c114 100755 --- a/drivers/serial/vcth.c +++ b/drivers/serial/vct.c @@ -21,7 +21,11 @@ #include <common.h> #include <asm/io.h> +#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 */ @@ -53,7 +57,7 @@ #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) +static void vct_uart_set_baud_rate(u32 address, u32 dh, u32 dl) { u32 val = __raw_readl(UART_1_BASE + UART_LCR_OFF); @@ -74,7 +78,7 @@ static void vcth_uart_set_baud_rate(u32 address, u32 dh, u32 dl) 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); + 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; |