diff options
97 files changed, 11274 insertions, 2339 deletions
diff --git a/.gitignore b/.gitignore index 89e96f566d9..e69de29bb2d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,48 +0,0 @@ -# -# NOTE! Don't add files that are generated in specific -# subdirectories here. Add them in the ".gitignore" file -# in that subdirectory instead. -# -# Normal rules -# - -*.rej -*.orig -*.a -*.o -*~ -*.patch - -# -# Top-level generic files -# - -/System.map -/u-boot -/u-boot.hex -/u-boot.map -/u-boot.bin -/u-boot.srec -/u-boot.ldr -/u-boot.ldr.hex -/u-boot.ldr.srec - -# -# Generated files -# - -*.depend -/LOG -/errlog -/reloc_off - -# stgit generated dirs -patches-* -.stgit-edit.txt - -# quilt's files -patches -series - -# cscope files -cscope.* @@ -141,7 +141,7 @@ ifeq ($(ARCH),ppc) CROSS_COMPILE = ppc_8xx- endif ifeq ($(ARCH),arm) -CROSS_COMPILE = arm-linux- +CROSS_COMPILE = arm_v5t_le- endif ifeq ($(ARCH),i386) CROSS_COMPILE = i386-linux- @@ -224,6 +224,7 @@ LIBS += drivers/mtd/libmtd.a LIBS += drivers/mtd/nand/libnand.a LIBS += drivers/mtd/nand_legacy/libnand_legacy.a LIBS += drivers/mtd/onenand/libonenand.a +LIBS += drivers/mtd/spi/libspi_flash.a LIBS += drivers/net/libnet.a LIBS += drivers/net/sk98lin/libsk98lin.a LIBS += drivers/pci/libpci.a @@ -390,6 +391,7 @@ TAG_SUBDIRS += drivers/mtd TAG_SUBDIRS += drivers/mtd/nand TAG_SUBDIRS += drivers/mtd/nand_legacy TAG_SUBDIRS += drivers/mtd/onenand +TAG_SUBDIRS += drivers/mtd/spi TAG_SUBDIRS += drivers/net TAG_SUBDIRS += drivers/net/sk98lin TAG_SUBDIRS += drivers/pci @@ -2411,6 +2413,12 @@ davinci_schmoogie_config : unconfig davinci_sonata_config : unconfig @$(MKCONFIG) $(@:_config=) arm arm926ejs sonata davinci davinci +# TRAB default configuration: 8 MB Flash, 32 MB RAM +xtract_da8xx = $(subst da830_omapl137,da8xx_evm,$(subst _config,,$1)) + +da830_omapl137_config : unconfig + @$(MKCONFIG) -a $(call xtract_da8xx,$@) arm arm926ejs da8xx-evm da8xx da8xx + xtract_omap1610xxx = $(subst _cs0boot,,$(subst _cs3boot,,$(subst _cs_autoboot,,$(subst _config,,$1)))) omap1610inn_config \ diff --git a/board/amcc/taihu/taihu.c b/board/amcc/taihu/taihu.c index eedde597b81..891b4d92498 100644 --- a/board/amcc/taihu/taihu.c +++ b/board/amcc/taihu/taihu.c @@ -165,16 +165,20 @@ unsigned char spi_read(void) return (unsigned char)gpio_read_in_bit(SPI_DIN_GPIO15); } -void taihu_spi_chipsel(int cs) +int spi_cs_is_valid(unsigned int bus, unsigned int cs) { - gpio_write_bit(SPI_CS_GPIO0, cs); + return bus == 0 && cs == 0; } -spi_chipsel_type spi_chipsel[]= { - taihu_spi_chipsel -}; +void spi_cs_activate(struct spi_slave *slave) +{ + gpio_write_bit(SPI_CS_GPIO0, 1); +} -int spi_chipsel_cnt = sizeof(spi_chipsel) / sizeof(spi_chipsel[0]); +void spi_cs_deactivate(struct spi_slave *slave) +{ + gpio_write_bit(SPI_CS_GPIO0, 0); +} #ifdef CONFIG_PCI static unsigned char int_lines[32] = { diff --git a/board/bf533-ezkit/.gitignore b/board/bf533-ezkit/.gitignore index 945f3245496..e69de29bb2d 100644 --- a/board/bf533-ezkit/.gitignore +++ b/board/bf533-ezkit/.gitignore @@ -1 +0,0 @@ -/u-boot.lds diff --git a/board/bf533-stamp/.gitignore b/board/bf533-stamp/.gitignore index 945f3245496..e69de29bb2d 100644 --- a/board/bf533-stamp/.gitignore +++ b/board/bf533-stamp/.gitignore @@ -1 +0,0 @@ -/u-boot.lds diff --git a/board/bf537-stamp/.gitignore b/board/bf537-stamp/.gitignore index 945f3245496..e69de29bb2d 100644 --- a/board/bf537-stamp/.gitignore +++ b/board/bf537-stamp/.gitignore @@ -1 +0,0 @@ -/u-boot.lds diff --git a/board/bf561-ezkit/.gitignore b/board/bf561-ezkit/.gitignore index 945f3245496..e69de29bb2d 100644 --- a/board/bf561-ezkit/.gitignore +++ b/board/bf561-ezkit/.gitignore @@ -1 +0,0 @@ -/u-boot.lds diff --git a/board/da8xx/da8xx-evm/Makefile b/board/da8xx/da8xx-evm/Makefile new file mode 100644 index 00000000000..fa0013811d4 --- /dev/null +++ b/board/da8xx/da8xx-evm/Makefile @@ -0,0 +1,52 @@ +# +# (C) Copyright 2000, 2001, 2002 +# Wolfgang Denk, DENX Software Engineering, wd@denx.de. +# +# Copyright (C) 2007 Sergey Kubushyn <ksi@koi8.net> +# +# 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)lib$(BOARD).a + +COBJS := dv_board.o +SOBJS := board_init.o + +SRCS := $(SOBJS:.o=.S) $(COBJS:.o=.c) +OBJS := $(addprefix $(obj),$(COBJS)) +SOBJS := $(addprefix $(obj),$(SOBJS)) + +$(LIB): $(obj).depend $(OBJS) $(SOBJS) + $(AR) $(ARFLAGS) $@ $(OBJS) $(SOBJS) + +clean: + rm -f $(SOBJS) $(OBJS) + +distclean: clean + rm -f $(LIB) core *.bak *~ .depend + +######################################################################### +# This is for $(obj).depend target +include $(SRCTREE)/rules.mk + +sinclude $(obj).depend + +######################################################################### diff --git a/board/da8xx/da8xx-evm/board_init.S b/board/da8xx/da8xx-evm/board_init.S new file mode 100644 index 00000000000..22d8adc18ca --- /dev/null +++ b/board/da8xx/da8xx-evm/board_init.S @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2007 Sergey Kubushyn <ksi@koi8.net> + * + * Board-specific low level initialization code. Called at the very end + * of cpu/arm926ejs/davinci/lowlevel_init.S. Just returns if there is no + * initialization required. + * + * 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 <config.h> + +.globl dv_board_init +dv_board_init: + + mov pc, lr diff --git a/board/da8xx/da8xx-evm/config.mk b/board/da8xx/da8xx-evm/config.mk new file mode 100644 index 00000000000..56de37a08fb --- /dev/null +++ b/board/da8xx/da8xx-evm/config.mk @@ -0,0 +1,30 @@ +# +# (C) Copyright 2002 +# Gary Jennejohn, DENX Software Engineering, <gj@denx.de> +# David Mueller, ELSOFT AG, <d.mueller@elsoft.ch> +# +# (C) Copyright 2003 +# Texas Instruments, <www.ti.com> +# Swaminathan <swami.iyer@ti.com> +# +# Copyright (C) 2007 Sergey Kubushyn <ksi@koi8.net> +# +# (C) Copyright 2008 +# Sekhar Nori, Texas Instruments, Inc. <nsekhar@ti.com> +# +# Texas Instruments DA8xx EVM board (ARM925EJS) cpu +# see http://www.ti.com/ for more information on Texas Instruments +# +# DA8xx EVM has 1 bank of 64 MB SDRAM (2 16Meg x16 chips). +# Physical Address: +# C000'0000 to C400'0000 +# +# Linux-Kernel is expected to be at C000'8000, entry C000'8000 +# (mem base + reserved) +# +# we load ourself to C108 '0000 +# +# + +#Provide at least 16MB spacing between us and the Linux Kernel image +TEXT_BASE = 0xC1080000 diff --git a/board/da8xx/da8xx-evm/dv_board.c b/board/da8xx/da8xx-evm/dv_board.c new file mode 100644 index 00000000000..481e1de7520 --- /dev/null +++ b/board/da8xx/da8xx-evm/dv_board.c @@ -0,0 +1,316 @@ +/* + * Copyright (C) 2008 Sekhar Nori, Texas Instruments, Inc. <nsekhar@ti.com> + * + * Modified for DA8xx EVM. + * + * Copyright (C) 2007 Sergey Kubushyn <ksi@koi8.net> + * + * Parts are shamelessly stolen from various TI sources, original copyright + * follows: + * ----------------------------------------------------------------- + * + * Copyright (C) 2004 Texas Instruments. + * + * ---------------------------------------------------------------------------- + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * ---------------------------------------------------------------------------- + */ + +#include <common.h> +#include <i2c.h> +#include <asm/arch/hardware.h> +#include <asm/arch/emac_defs.h> +#include <asm/io.h> + +#define MACH_TYPE_DA8XX_EVM 1781 + +DECLARE_GLOBAL_DATA_PTR; + +extern void timer_init(void); +extern int eth_hw_init(void); + +/* Works on Always On power domain only (no PD argument) */ +void lpsc_on(unsigned int id) +{ + dv_reg_p mdstat, mdctl, ptstat, ptcmd; + + if (id >= 64) + return; + + if(id < 32) { + mdstat = REG_P(PSC0_MDSTAT + (id * 4)); + mdctl = REG_P(PSC0_MDCTL + (id * 4)); + ptstat = REG_P(PSC0_PTSTAT); + ptcmd = REG_P(PSC0_PTCMD); + } else { + id -= 32; + mdstat = REG_P(PSC1_MDSTAT + (id * 4)); + mdctl = REG_P(PSC1_MDCTL + (id * 4)); + ptstat = REG_P(PSC1_PTSTAT); + ptcmd = REG_P(PSC1_PTCMD); + } + + while (*ptstat & 0x01) {;} + + if ((*mdstat & 0x1f) == 0x03) + return; /* Already on and enabled */ + + *mdctl |= 0x03; + + /* Special treatment for some modules as for sprue14 p.7.4.2 */ + /* TBD: Confirm if such cases exist for Primus */ + if (0) + *mdctl |= 0x200; + + *ptcmd = 0x01; + + while (*ptstat & 0x01) {;} + while ((*mdstat & 0x1f) != 0x03) {;} /* Probably an overkill... */ +} + +int board_init(void) +{ + + dv_reg_p intc; + + /*-------------------------------------------------------* + * Mask all IRQs by clearing the global enable and setting + * the enable clear for all the 90 interrupts. This code is + * also included in low level init. Including it here in case + * low level init is skipped. Not removing it from low level + * init in case some of the low level init code generates + * interrupts... Not expected... but you never know... + *-------------------------------------------------------*/ + +#ifndef CONFIG_USE_IRQ + intc = REG_P(INTC_GLB_EN); + intc[0] = 0; + + intc = REG_P(INTC_HINT_EN); + intc[0] = 0; + intc[1] = 0; + intc[2] = 0; + + intc = REG_P(INTC_EN_CLR0); + intc[0] = 0xFFFFFFFF; + intc[1] = 0xFFFFFFFF; + intc[2] = 0xFFFFFFFF; +#endif + + /* arch number of the board */ + gd->bd->bi_arch_number = MACH_TYPE_DA8XX_EVM; + + /* address of boot parameters */ + gd->bd->bi_boot_params = LINUX_BOOT_PARAM_ADDR; + + /* Power on required peripherals + * ARM does not have acess by default to PSC0 and PSC1 + * assuming here that the DSP bootloader has set the IOPU + * such that PSC access is available to ARM + */ + lpsc_on(DAVINCI_LPSC_AEMIF); /* NAND, NOR */ + lpsc_on(DAVINCI_LPSC_SPI0); /* Serial Flash */ + lpsc_on(DAVINCI_LPSC_EMAC); /* image download */ + lpsc_on(DAVINCI_LPSC_UART2); /* console */ + lpsc_on(DAVINCI_LPSC_GPIO); + + /* Pin Muxing support */ + + /* write the kick registers to unlock the PINMUX registers */ + REG(KICK0) = 0x83e70b13; /* Kick0 unlock */ + REG(KICK1) = 0x95a4f1e0; /* Kick1 unlock */ + + /* setup the SUSPSRC for ARM to control emulation suspend */ + REG(SUSPSRC) &= ~( (1 << 27) /* Timer0 */ + | (1 << 21) /* SPI0 */ + | (1 << 20) /* UART2 */ + | (1 << 5) /* EMAC */ + | (1 << 16) /* I2C0 */ + ); + +#ifdef CONFIG_USE_PINMUX + +#ifdef CONFIG_SPI_FLASH + /* SPI0 */ + REG(PINMUX7) &= 0x00000FFF; + REG(PINMUX7) |= 0x11111000; +#endif + +#ifdef CONFIG_DRIVER_TI_EMAC + /* RMII clock is sourced externally */ + REG(PINMUX9) &= 0xFF0FFFFF; + REG(PINMUX10) &= 0x0000000F; + REG(PINMUX10) |= 0x22222220; + REG(PINMUX11) &= 0xFFFFFF00; + REG(PINMUX11) |= 0x00000022; +#endif + + /* Async EMIF */ +#if defined(CFG_USE_NAND) || defined(CFG_USE_NOR) + REG(PINMUX13) &= 0x00FFFFFF; + REG(PINMUX13) |= 0x11000000; + REG(PINMUX14) = 0x11111111; + REG(PINMUX15) = 0x11111111; + REG(PINMUX16) = 0x11111111; + REG(PINMUX17) = 0x11111111; + REG(PINMUX18) = 0x11111111; + REG(PINMUX19) &= 0xFFFFFFF0; + REG(PINMUX19) |= 0x1; +#endif + + /* UART Muxing and enabling */ + REG(PINMUX8) &= 0x0FFFFFFF; + REG(PINMUX8) |= 0x20000000; + + REG(PINMUX9) &= 0xFFFFFFF0; + REG(PINMUX9) |= 0x00000002; + + /* I2C muxing */ + REG(PINMUX8) &= 0xFFF00FFF; + REG(PINMUX8) |= 0x00022000; + +#endif + + /* write the kick registers to lock the PINMUX registers */ + REG(KICK0) = 0x0; /* Kick0 lock */ + REG(KICK1) = 0x0; /* Kick1 lock */ + + REG(DAVINCI_UART2_BASE + 0x30) = 0xE001; + + + return(0); +} + +int misc_init_r (void) +{ + u_int8_t tmp[20], buf[10]; + int i; + + printf ("ARM Clock : %d Hz\n", clk_get(DAVINCI_ARM_CLKID)); + + /* Set Ethernet MAC address from EEPROM */ + if (i2c_read(CFG_I2C_EEPROM_ADDR, 0x7f00, CFG_I2C_EEPROM_ADDR_LEN, buf, 6)) { + printf("\nEEPROM @ 0x%02x read FAILED!!!\n", CFG_I2C_EEPROM_ADDR); + } else { + tmp[0] = 0xff; + for (i = 0; i < 6; i++) + tmp[0] &= buf[i]; + + if ((tmp[0] != 0xff) && (getenv("ethaddr") == NULL)) { + sprintf((char *)&tmp[0], "%02x:%02x:%02x:%02x:%02x:%02x", + buf[0], buf[1], buf[2], buf[3], buf[4], buf[5]); + setenv("ethaddr", (char *)&tmp[0]); + } + } + + tmp[0] = 0x01; + tmp[1] = 0x23; + if(i2c_write(0x5f, 0, 0, tmp, 2)) { + printf("Ethernet switch start failed!\n"); + } + + if (!eth_hw_init()) { + printf("Error: Ethernet init failed!\n"); + } + + return(0); +} + +int dram_init(void) +{ + gd->bd->bi_dram[0].start = PHYS_SDRAM_1; + gd->bd->bi_dram[0].size = PHYS_SDRAM_1_SIZE; + + return(0); +} + +#if defined(CFG_USE_NOR) +static u8 nor_read8(void *addr) +{ + u32 temp = (u32) addr; + + temp &= 0x00FFFFFF; + temp >>= 13; + temp |= 0x62000000; + *(unsigned char*) temp = 0; + + return __raw_readb(addr); +} + +static u16 nor_read16(void *addr) +{ + u32 temp = (u32) addr; + + temp &= 0x00FFFFFF; + temp >>= 13; + temp |= 0x62000000; + *(unsigned char*) temp = 0; + + return __raw_readw(addr); +} + +static u32 nor_read32(void *addr) +{ + u32 temp = (u32) addr; + + temp &= 0x00FFFFFF; + temp >>= 13; + temp |= 0x62000000; + *(unsigned char*) temp = 0; + + return __raw_readl(addr); +} + +static void nor_write8(u8 value, void *addr) +{ + u32 temp = (u32) addr; + temp &= 0x00FFFFFF; + temp >>= 13; + temp |= 0x62000000; + *(unsigned char*) temp = 0; + __raw_writeb(value, addr); +} + +static void nor_write16(u8 value, void *addr) +{ + u32 temp = (u32) addr; + temp &= 0x00FFFFFF; + temp >>= 13; + temp |= 0x62000000; + *(unsigned char*) temp = 0; + __raw_writew(value, addr); +} + +static void nor_write32(u8 value, void *addr) +{ + u32 temp = (u32) addr; + temp &= 0x00FFFFFF; + temp >>= 13; + temp |= 0x62000000; + *(unsigned char*) temp = 0; + __raw_writel(value, addr); +} + +void board_flash_set_access(ulong bank_base, int banknum, flash_info_t* info) +{ + info->read8 = nor_read8; + info->read16 = nor_read16; + info->read32 = nor_read32; + + info->write8 = nor_write8; + info->write16 = nor_write16; + info->write32 = nor_write32; +} +#endif diff --git a/board/da8xx/da8xx-evm/u-boot.lds b/board/da8xx/da8xx-evm/u-boot.lds new file mode 100644 index 00000000000..a4fcd1a9bb4 --- /dev/null +++ b/board/da8xx/da8xx-evm/u-boot.lds @@ -0,0 +1,52 @@ +/* + * (C) Copyright 2002 + * Gary Jennejohn, DENX Software Engineering, <gj@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 + */ + +OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm") +OUTPUT_ARCH(arm) +ENTRY(_start) +SECTIONS +{ + . = 0x00000000; + . = ALIGN(4); + .text : + { + cpu/arm926ejs/start.o (.text) + *(.text) + } + . = ALIGN(4); + .rodata : { *(.rodata) } + . = ALIGN(4); + .data : { *(.data) } + . = ALIGN(4); + .got : { *(.got) } + + . = .; + __u_boot_cmd_start = .; + .u_boot_cmd : { *(.u_boot_cmd) } + __u_boot_cmd_end = .; + + . = ALIGN(4); + __bss_start = .; + .bss (NOLOAD) : { *(.bss) } + _end = .; +} diff --git a/board/freescale/mpc8349emds/mpc8349emds.c b/board/freescale/mpc8349emds/mpc8349emds.c index 6c825969d38..e18e68e8cec 100644 --- a/board/freescale/mpc8349emds/mpc8349emds.c +++ b/board/freescale/mpc8349emds/mpc8349emds.c @@ -257,25 +257,24 @@ void sdram_init(void) #define SPI_CS_MASK 0x80000000 -void spi_eeprom_chipsel(int cs) +int spi_cs_is_valid(unsigned int bus, unsigned int cs) +{ + return bus == 0 && cs == 0; +} + +void spi_cs_activate(struct spi_slave *slave) { volatile gpio83xx_t *iopd = &((immap_t *)CFG_IMMR)->gpio[0]; - if (cs) - iopd->dat &= ~SPI_CS_MASK; - else - iopd->dat |= SPI_CS_MASK; + iopd->dat &= ~SPI_CS_MASK; } -/* - * The SPI command uses this table of functions for controlling the SPI - * chip selects. - */ -spi_chipsel_type spi_chipsel[] = { - spi_eeprom_chipsel, -}; -int spi_chipsel_cnt = sizeof(spi_chipsel) / sizeof(spi_chipsel[0]); +void spi_cs_deactivate(struct spi_slave *slave) +{ + volatile gpio83xx_t *iopd = &((immap_t *)CFG_IMMR)->gpio[0]; + iopd->dat |= SPI_CS_MASK; +} #endif /* CONFIG_HARD_SPI */ #if defined(CONFIG_OF_BOARD_SETUP) diff --git a/board/sacsng/sacsng.c b/board/sacsng/sacsng.c index 25209e05464..e85a0fc4dbe 100644 --- a/board/sacsng/sacsng.c +++ b/board/sacsng/sacsng.c @@ -842,37 +842,30 @@ void show_boot_progress (int status) #define SPI_ADC_CS_MASK 0x00000800 #define SPI_DAC_CS_MASK 0x00001000 -void spi_adc_chipsel(int cs) +static const u32 cs_mask[] = { + SPI_ADC_CS_MASK, + SPI_DAC_CS_MASK, +}; + +int spi_cs_is_valid(unsigned int bus, unsigned int cs) +{ + return bus == 0 && cs < sizeof(cs_mask) / sizeof(cs_mask[0]); +} + +void spi_cs_activate(struct spi_slave *slave) { volatile ioport_t *iopd = ioport_addr((immap_t *)CFG_IMMR, 3 /* port D */); - if(cs) - iopd->pdat &= ~SPI_ADC_CS_MASK; /* activate the chip select */ - else - iopd->pdat |= SPI_ADC_CS_MASK; /* deactivate the chip select */ + iopd->pdat &= ~cs_mask[slave->cs]; } -void spi_dac_chipsel(int cs) +void spi_cs_deactivate(struct spi_slave *slave) { volatile ioport_t *iopd = ioport_addr((immap_t *)CFG_IMMR, 3 /* port D */); - if(cs) - iopd->pdat &= ~SPI_DAC_CS_MASK; /* activate the chip select */ - else - iopd->pdat |= SPI_DAC_CS_MASK; /* deactivate the chip select */ + iopd->pdat |= cs_mask[slave->cs]; } -/* - * The SPI command uses this table of functions for controlling the SPI - * chip selects: it calls the appropriate function to control the SPI - * chip selects. - */ -spi_chipsel_type spi_chipsel[] = { - spi_adc_chipsel, - spi_dac_chipsel -}; -int spi_chipsel_cnt = sizeof(spi_chipsel) / sizeof(spi_chipsel[0]); - #endif #endif /* CONFIG_MISC_INIT_R */ diff --git a/board/ssv/adnpesc1/adnpesc1.c b/board/ssv/adnpesc1/adnpesc1.c index 2ec3a728d74..3ee8ba588dc 100644 --- a/board/ssv/adnpesc1/adnpesc1.c +++ b/board/ssv/adnpesc1/adnpesc1.c @@ -69,25 +69,24 @@ long int initdram (int board_type) #define SPI_RTC_CS_MASK 0x00000001 -void spi_rtc_chipsel(int cs) +int spi_cs_is_valid(unsigned int bus, unsigned int cs) +{ + return bus == 0 && cs == 0; +} + +void spi_cs_activate(struct spi_slave *slave) { nios_spi_t *spi = (nios_spi_t *)CFG_NIOS_SPIBASE; - if (cs) - spi->slaveselect = SPI_RTC_CS_MASK; /* activate (1) */ - else - spi->slaveselect = 0; /* deactivate (0) */ + spi->slaveselect = SPI_RTC_CS_MASK; /* activate (1) */ } -/* - * The SPI command uses this table of functions for controlling the SPI - * chip selects: it calls the appropriate function to control the SPI - * chip selects. - */ -spi_chipsel_type spi_chipsel[] = { - spi_rtc_chipsel -}; -int spi_chipsel_cnt = sizeof(spi_chipsel) / sizeof(spi_chipsel[0]); +void spi_cs_deactivate(struct spi_slave *slave) +{ + nios_spi_t *spi = (nios_spi_t *)CFG_NIOS_SPIBASE; + + spi->slaveselect = 0; /* deactivate (0) */ +} #endif diff --git a/common/Makefile b/common/Makefile index 96787992272..b425795e928 100644 --- a/common/Makefile +++ b/common/Makefile @@ -113,6 +113,7 @@ COBJS-y += env_dataflash.o COBJS-y += env_flash.o COBJS-y += env_eeprom.o COBJS-y += env_onenand.o +COBJS-y += env_sf.o COBJS-y += env_nvram.o COBJS-y += env_nowhere.o COBJS-y += exports.o @@ -143,6 +144,7 @@ COBJS-y += xyzModem.o COBJS-y += cmd_mac.o COBJS-$(CONFIG_CMD_MFSL) += cmd_mfsl.o COBJS-$(CONFIG_MP) += cmd_mp.o +COBJS-$(CONFIG_CMD_SF) += cmd_sf.o COBJS := $(COBJS-y) SRCS := $(AOBJS:.o=.S) $(COBJS:.o=.c) diff --git a/common/cmd_df.c b/common/cmd_df.c new file mode 100644 index 00000000000..5f650442c01 --- /dev/null +++ b/common/cmd_df.c @@ -0,0 +1,37 @@ +/* + * Command for accessing DataFlash. + * + * Copyright (C) 2008 Atmel Corporation + */ +#include <common.h> +#include <df.h> + +static int do_df(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) +{ + const char *cmd; + + /* need at least two arguments */ + if (argc < 2) + goto usage; + + cmd = argv[1]; + + if (strcmp(cmd, "init") == 0) { + df_init(0, 0, 1000000); + return 0; + } + + if (strcmp(cmd, "info") == 0) { + df_show_info(); + return 0; + } + +usage: + printf("Usage:\n%s\n", cmdtp->usage); + return 1; +} + +U_BOOT_CMD( + sf, 2, 1, do_serial_flash, + "sf - Serial flash sub-system\n", + "probe [bus:]cs - init flash device on given SPI bus and CS\n") diff --git a/common/cmd_eeprom.c b/common/cmd_eeprom.c index e5000e9ff39..a16d991d973 100644 --- a/common/cmd_eeprom.c +++ b/common/cmd_eeprom.c @@ -82,9 +82,7 @@ int do_eeprom ( cmd_tbl_t * cmdtp, int flag, int argc, char *argv[]) ulong cnt = simple_strtoul (argv[4], NULL, 16); #endif /* CFG_I2C_MULTI_EEPROMS */ -# ifndef CONFIG_SPI eeprom_init (); -# endif /* !CONFIG_SPI */ if (strcmp (argv[1], "read") == 0) { int rcode; diff --git a/common/cmd_mem.c b/common/cmd_mem.c index 51aa71fca84..1252927b9c4 100644 --- a/common/cmd_mem.c +++ b/common/cmd_mem.c @@ -94,9 +94,13 @@ static ulong base_address = 0; int do_mem_md ( cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) { ulong addr, length; -#if defined(CONFIG_HAS_DATAFLASH) +#if defined(CONFIG_HAS_DATAFLASH) || !defined(CFG_NO_FLASH) ulong nbytes, linebytes; #endif +#ifndef CFG_NO_FLASH + flash_info_t *info; +#endif + int size; int rc = 0; @@ -177,11 +181,51 @@ int do_mem_md ( cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) # endif { - /* Print the lines. */ - print_buffer(addr, (void*)addr, size, length, DISP_LINE_LEN/size); - addr += size*length; - } +#ifndef CFG_NO_FLASH + if(info = addr2info(addr)) { + + char linebuf[DISP_LINE_LEN]; + + nbytes = length * size; + do { + char linebuf[DISP_LINE_LEN]; + void *dest = linebuf; + void *src = addr; + int count = linebytes = ((nbytes > DISP_LINE_LEN) ? DISP_LINE_LEN : nbytes); + + nbytes -= linebytes; + + while (count > 0) { + + if (size == 4) + *((ulong *)dest) = info->read32(src); + else if (size == 2) + *((ushort *)dest) = info->read16(src); + else + *((u_char *)dest) = info->read8(src); + src += size; + dest += size; + count -= size; + } + + print_buffer(addr, linebuf, size, linebytes/size, DISP_LINE_LEN/size); + addr += size*length; + + if (ctrlc()) { + rc = 1; + break; + } + + } while (nbytes > 0); + } else +#endif + { + /* Print the lines. */ + print_buffer(addr, (void*)addr, size, length, DISP_LINE_LEN/size); + addr += size*length; + } #endif + } dp_last_addr = addr; dp_last_length = length; @@ -390,6 +434,10 @@ int do_mem_cp ( cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) { ulong addr, dest, count; int size; +#ifndef CFG_NO_FLASH + flash_info_t *info; +#endif + if (argc != 4) { printf ("Usage:\n%s\n", cmdtp->usage); @@ -433,6 +481,31 @@ int do_mem_cp ( cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) puts ("done\n"); return 0; } + + /* check if we are copying from Flash */ + if( ((info = addr2info(addr)) != NULL) +#ifdef CONFIG_HAS_DATAFLASH + && (!addr_dataflash(dest)) +#endif + ) { + + puts ("Copy from Flash... "); + + while (count > 0) { + if (size == 4) + *((ulong *)dest) = info->read32(addr); + else if (size == 2) + *((ushort *)dest) = info->read16(addr); + else + *((u_char *)dest) = info->read8(addr); + addr += size; + dest += size; + count -= size; + } + + puts ("done\n"); + return 0; + } #endif #if defined(CONFIG_CMD_MMC) diff --git a/common/cmd_nvedit.c b/common/cmd_nvedit.c index 9c5d1fcb905..97424bb72da 100644 --- a/common/cmd_nvedit.c +++ b/common/cmd_nvedit.c @@ -58,8 +58,9 @@ DECLARE_GLOBAL_DATA_PTR; !defined(CFG_ENV_IS_IN_DATAFLASH) && \ !defined(CFG_ENV_IS_IN_NAND) && \ !defined(CFG_ENV_IS_IN_ONENAND) && \ + !defined(CFG_ENV_IS_IN_SPI_FLASH) && \ !defined(CFG_ENV_IS_NOWHERE) -# error Define one of CFG_ENV_IS_IN_{NVRAM|EEPROM|FLASH|DATAFLASH|ONENAND|NOWHERE} +# error Define one of CFG_ENV_IS_IN_{NVRAM|EEPROM|FLASH|DATAFLASH|ONENAND|SPI_FLASH|NOWHERE} #endif #define XMK_STR(x) #x @@ -540,6 +541,7 @@ int getenv_r (char *name, char *buf, unsigned len) #if ((defined(CFG_ENV_IS_IN_NVRAM) || defined(CFG_ENV_IS_IN_EEPROM) \ || (defined(CONFIG_CMD_ENV) && defined(CONFIG_CMD_FLASH)) \ || (defined(CONFIG_CMD_ENV) && defined(CONFIG_CMD_NAND)) \ + || (defined(CONFIG_CMD_ENV) && defined(CONFIG_CMD_SF)) \ || (defined(CONFIG_CMD_ENV) && defined(CONFIG_CMD_ONENAND))) \ && !defined(CFG_ENV_IS_NOWHERE)) int do_saveenv (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) @@ -596,6 +598,7 @@ U_BOOT_CMD( #if ((defined(CFG_ENV_IS_IN_NVRAM) || defined(CFG_ENV_IS_IN_EEPROM) \ || (defined(CONFIG_CMD_ENV) && defined(CONFIG_CMD_FLASH)) \ || (defined(CONFIG_CMD_ENV) && defined(CONFIG_CMD_NAND)) \ + || (defined(CONFIG_CMD_ENV) && defined(CONFIG_CMD_SF)) \ || (defined(CONFIG_CMD_ENV) && defined(CONFIG_CMD_ONENAND))) \ && !defined(CFG_ENV_IS_NOWHERE)) U_BOOT_CMD( diff --git a/common/cmd_sf.c b/common/cmd_sf.c new file mode 100644 index 00000000000..5d6db2d2832 --- /dev/null +++ b/common/cmd_sf.c @@ -0,0 +1,197 @@ +/* + * Command for accessing SPI flash. + * + * Copyright (C) 2008 Atmel Corporation + */ +#include <common.h> +#include <spi_flash.h> + +#include <asm/io.h> + +#ifndef CONFIG_SF_DEFAULT_SPEED +# define CONFIG_SF_DEFAULT_SPEED 1000000 +#endif +#ifndef CONFIG_SF_DEFAULT_MODE +# define CONFIG_SF_DEFAULT_MODE SPI_MODE_3 +#endif + +static struct spi_flash *flash; + +static int do_spi_flash_probe(int argc, char *argv[]) +{ + unsigned int bus = 0; + unsigned int cs; + unsigned int speed = CONFIG_SF_DEFAULT_SPEED; + unsigned int mode = CONFIG_SF_DEFAULT_MODE; + char *endp; + struct spi_flash *new; + + if (argc < 2) + goto usage; + + if(flash) { + printf("SPI flash already probed\n"); + goto probe_done; + } + + cs = simple_strtoul(argv[1], &endp, 0); + if (*argv[1] == 0 || (*endp != 0 && *endp != ':')) + goto usage; + if (*endp == ':') { + if (endp[1] == 0) + goto usage; + + bus = cs; + cs = simple_strtoul(endp + 1, &endp, 0); + if (*endp != 0) + goto usage; + } + + if (argc >= 3) { + speed = simple_strtoul(argv[2], &endp, 0); + if (*argv[2] == 0 || *endp != 0) + goto usage; + } + if (argc >= 4) { + mode = simple_strtoul(argv[3], &endp, 0); + if (*argv[3] == 0 || *endp != 0) + goto usage; + } + + new = spi_flash_probe(bus, cs, speed, mode); + if (!new) { + printf("Failed to initialize SPI flash at %u:%u\n", bus, cs); + return 1; + } + + if (flash) + spi_flash_free(flash); + flash = new; + +probe_done: + printf("%u KiB %s at %u:%u is now current device\n", + flash->size >> 10, flash->name, bus, cs); + + return 0; + +usage: + puts("Usage: sf probe [bus:]cs [hz] [mode]\n"); + return 1; +} + +static int do_spi_flash_read_write(int argc, char *argv[]) +{ + unsigned long addr; + unsigned long offset; + unsigned long len; + void *buf; + char *endp; + int ret; + + if (argc < 4) + goto usage; + + addr = simple_strtoul(argv[1], &endp, 16); + if (*argv[1] == 0 || *endp != 0) + goto usage; + offset = simple_strtoul(argv[2], &endp, 16); + if (*argv[2] == 0 || *endp != 0) + goto usage; + len = simple_strtoul(argv[3], &endp, 16); + if (*argv[3] == 0 || *endp != 0) + goto usage; + + buf = map_physmem(addr, len, MAP_WRBACK); + if (!buf) { + puts("Failed to map physical memory\n"); + return 1; + } + + if (strcmp(argv[0], "read") == 0) + ret = spi_flash_read(flash, offset, len, buf); + else + ret = spi_flash_write(flash, offset, len, buf); + + unmap_physmem(buf, len); + + if (ret) { + printf("SPI flash %s failed\n", argv[0]); + return 1; + } + + return 0; + +usage: + printf("Usage: sf %s addr offset len\n", argv[0]); + return 1; +} + +static int do_spi_flash_erase(int argc, char *argv[]) +{ + unsigned long offset; + unsigned long len; + char *endp; + int ret; + + if (argc < 3) + goto usage; + + offset = simple_strtoul(argv[1], &endp, 16); + if (*argv[1] == 0 || *endp != 0) + goto usage; + len = simple_strtoul(argv[2], &endp, 16); + if (*argv[2] == 0 || *endp != 0) + goto usage; + + ret = spi_flash_erase(flash, offset, len); + if (ret) { + printf("SPI flash %s failed\n", argv[0]); + return 1; + } + + return 0; + +usage: + puts("Usage: sf erase offset len\n"); + return 1; +} + +static int do_spi_flash(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) +{ + const char *cmd; + + /* need at least two arguments */ + if (argc < 2) + goto usage; + + cmd = argv[1]; + + if (strcmp(cmd, "probe") == 0) + return do_spi_flash_probe(argc - 1, argv + 1); + + /* The remaining commands require a selected device */ + if (!flash) { + puts("No SPI flash selected. Please run `sf probe'\n"); + return 1; + } + + if (strcmp(cmd, "read") == 0 || strcmp(cmd, "write") == 0) + return do_spi_flash_read_write(argc - 1, argv + 1); + if (strcmp(cmd, "erase") == 0) + return do_spi_flash_erase(argc - 1, argv + 1); + +usage: + printf("Usage:\n%s\n", cmdtp->usage); + return 1; +} + +U_BOOT_CMD( + sf, 5, 1, do_spi_flash, + "sf - SPI flash sub-system\n", + "probe [bus:]cs [hz] [mode] - init flash device on given SPI bus\n" + " and chip select\n" + "sf read addr offset len - read `len' bytes starting at\n" + " `offset' to memory at `addr'\n" + "sf write addr offset len - write `len' bytes from memory\n" + " at `addr' to flash at `offset'\n" + "sf erase offset len - erase `len' bytes from `offset'\n"); diff --git a/common/cmd_spi.c b/common/cmd_spi.c index 76044221416..40ee7e7dd3c 100644 --- a/common/cmd_spi.c +++ b/common/cmd_spi.c @@ -37,20 +37,20 @@ # define MAX_SPI_BYTES 32 /* Maximum number of bytes we can handle */ #endif -/* - * External table of chip select functions (see the appropriate board - * support for the actual definition of the table). - */ -extern spi_chipsel_type spi_chipsel[]; -extern int spi_chipsel_cnt; +#ifndef CONFIG_DEFAULT_SPI_BUS +# define CONFIG_DEFAULT_SPI_BUS 0 +#endif +#ifndef CONFIG_DEFAULT_SPI_MODE +# define CONFIG_DEFAULT_SPI_MODE SPI_MODE_0 +#endif /* * Values from last command. */ -static int device; -static int bitlen; -static uchar dout[MAX_SPI_BYTES]; -static uchar din[MAX_SPI_BYTES]; +static unsigned int device; +static int bitlen; +static uchar dout[MAX_SPI_BYTES]; +static uchar din[MAX_SPI_BYTES]; /* * SPI read/write @@ -65,6 +65,7 @@ static uchar din[MAX_SPI_BYTES]; int do_spi (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) { + struct spi_slave *slave; char *cp = 0; uchar tmp; int j; @@ -101,19 +102,24 @@ int do_spi (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) } } - if ((device < 0) || (device >= spi_chipsel_cnt)) { - printf("Invalid device %d, giving up.\n", device); - return 1; - } if ((bitlen < 0) || (bitlen > (MAX_SPI_BYTES * 8))) { printf("Invalid bitlen %d, giving up.\n", bitlen); return 1; } - debug ("spi_chipsel[%d] = %08X\n", - device, (uint)spi_chipsel[device]); + /* FIXME: Make these parameters run-time configurable */ + slave = spi_setup_slave(CONFIG_DEFAULT_SPI_BUS, device, 1000000, + CONFIG_DEFAULT_SPI_MODE); + if (!slave) { + printf("Invalid device %d, giving up.\n", device); + return 1; + } + + debug ("spi chipsel = %08X\n", device); - if(spi_xfer(spi_chipsel[device], bitlen, dout, din) != 0) { + spi_claim_bus(slave); + if(spi_xfer(slave, bitlen, dout, din, + SPI_XFER_BEGIN | SPI_XFER_END) != 0) { printf("Error with the SPI transaction.\n"); rcode = 1; } else { @@ -123,6 +129,8 @@ int do_spi (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) } printf("\n"); } + spi_release_bus(slave); + spi_free_slave(slave); return rcode; } diff --git a/common/cmd_usb.c b/common/cmd_usb.c index 23413b51035..e23b0596e9c 100644 --- a/common/cmd_usb.c +++ b/common/cmd_usb.c @@ -183,13 +183,13 @@ void usb_display_conf_desc(struct usb_config_descriptor *config,struct usb_devic void usb_display_if_desc(struct usb_interface_descriptor *ifdesc,struct usb_device *dev) { - printf(" Interface: %d\n",ifdesc->bInterfaceNumber); - printf(" - Alternate Setting %d, Endpoints: %d\n",ifdesc->bAlternateSetting,ifdesc->bNumEndpoints); - printf(" - Class "); + printf(" Interface: %d\n",ifdesc->bInterfaceNumber); + printf(" - Alternate Setting %d, Endpoints: %d\n",ifdesc->bAlternateSetting,ifdesc->bNumEndpoints); + printf(" - Class "); usb_display_class_sub(ifdesc->bInterfaceClass,ifdesc->bInterfaceSubClass,ifdesc->bInterfaceProtocol); printf("\n"); if (ifdesc->iInterface) { - printf(" - "); + printf(" - "); usb_display_string(dev,ifdesc->iInterface); printf("\n"); } @@ -197,7 +197,7 @@ void usb_display_if_desc(struct usb_interface_descriptor *ifdesc,struct usb_devi void usb_display_ep_desc(struct usb_endpoint_descriptor *epdesc) { - printf(" - Endpoint %d %s ",epdesc->bEndpointAddress & 0xf,(epdesc->bEndpointAddress & 0x80) ? "In" : "Out"); + printf(" - Endpoint %d %s ",epdesc->bEndpointAddress & 0xf,(epdesc->bEndpointAddress & 0x80) ? "In" : "Out"); switch((epdesc->bmAttributes & 0x03)) { case 0: printf("Control"); break; @@ -276,7 +276,8 @@ void usb_show_tree_graph(struct usb_device *dev,char *pre) pre[index++]= has_child ? '|' : ' '; pre[index]=0; printf(" %s (%s, %dmA)\n",usb_get_class_desc(dev->config.if_desc[0].bInterfaceClass), - dev->slow ? "1.5MBit/s" : "12MBit/s",dev->config.MaxPower * 2); + ((dev->slow==0) && (dev->high==1)) ? "480Mbit/s" : (((dev->slow==0) && (dev->high==0)) ? "12MBit/s" : "1.5MBit/s"), + dev->config.MaxPower * 2); if (strlen(dev->mf) || strlen(dev->prod) || strlen(dev->serial)) @@ -370,7 +371,7 @@ int do_usbboot (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) printf("error reading partinfo...try to boot raw\n"); } if ((strncmp((char *)info.type, BOOT_PART_TYPE, sizeof(info.type)) != 0) && - (strncmp((char *)info.type, BOOT_PART_COMP, sizeof(info.type)) != 0)) { + (strncmp((char *)info.type, BOOT_PART_COMP, sizeof(info.type)) != 0)) { printf ("\n** Invalid partition type \"%.32s\"" " (expect \"" BOOT_PART_TYPE "\")\n", info.type); @@ -423,7 +424,7 @@ int do_usbboot (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) cnt -= 1; if (stor_dev->block_read (dev, info.start+1, cnt, - (ulong *)(addr+info.blksz)) != cnt) { + (ulong *)(addr+info.blksz)) != cnt) { printf ("\n** Read error on %d:%d\n", dev, part); return 1; } @@ -475,7 +476,7 @@ int do_usb (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) #ifdef CONFIG_USB_STORAGE /* try to recognize storage devices immediately */ if (i >= 0) - usb_stor_curr_dev = usb_stor_scan(1); + usb_stor_curr_dev = usb_stor_scan(1); #endif return 0; } @@ -627,7 +628,7 @@ int do_usb (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) #ifdef CONFIG_USB_STORAGE U_BOOT_CMD( usb, 5, 1, do_usb, - "usb - USB sub-system\n", + "usb - USB sub-system\n", "reset - reset (rescan) USB controller\n" "usb stop [f] - stop USB [f]=force stop\n" "usb tree - show USB device tree\n" @@ -636,7 +637,7 @@ U_BOOT_CMD( "usb dev [dev] - show or set current USB storage device\n" "usb part [dev] - print partition table of one or all USB storage devices\n" "usb read addr blk# cnt - read `cnt' blocks starting at block `blk#'\n" - " to memory address `addr'\n" + " to memory address `addr'\n" ); @@ -649,9 +650,9 @@ U_BOOT_CMD( #else U_BOOT_CMD( usb, 5, 1, do_usb, - "usb - USB sub-system\n", + "usb - USB sub-system\n", "reset - reset (rescan) USB controller\n" - "usb tree - show USB device tree\n" + "usb tree - show USB device tree\n" "usb info [dev] - show available USB devices\n" ); #endif diff --git a/common/env_common.c b/common/env_common.c index a49481244e2..9dc2c4ab4ea 100644 --- a/common/env_common.c +++ b/common/env_common.c @@ -134,7 +134,8 @@ uchar default_environment[] = { "\0" }; -#if defined(CFG_ENV_IS_IN_NAND) /* Environment is in Nand Flash */ +#if defined(CFG_ENV_IS_IN_NAND) /* Environment is in Nand Flash */ \ + || defined(CFG_ENV_IS_IN_SPI_FLASH) || defined(CFG_ENV_IS_IN_FLASH) int default_environment_size = sizeof(default_environment); #endif diff --git a/common/env_flash.c b/common/env_flash.c index a92160ddfb3..b0994d19291 100644 --- a/common/env_flash.c +++ b/common/env_flash.c @@ -88,6 +88,13 @@ static ulong end_addr_new = CFG_ENV_ADDR_REDUND + CFG_ENV_SECT_SIZE - 1; extern uchar default_environment[]; extern int default_environment_size; +static env_t tmp_env; + +/* local functions */ +#if !defined(ENV_IS_EMBEDDED) +static void use_default(void); +#endif + uchar env_get_char_spec (int index) { @@ -248,15 +255,9 @@ Done: #else /* ! CFG_ENV_ADDR_REDUND */ int env_init(void) -{ - if (crc32(0, env_ptr->data, ENV_SIZE) == env_ptr->crc) { - gd->env_addr = (ulong)&(env_ptr->data); - gd->env_valid = 1; - return(0); - } - +{ gd->env_addr = (ulong)&default_environment[0]; - gd->env_valid = 0; + gd->env_valid = 1; return (0); } @@ -336,6 +337,28 @@ int saveenv(void) void env_relocate_spec (void) { + + flash_info_t *info; + int count = CFG_ENV_SIZE; + u_char *src = (u_char*) flash_addr, *dst = (u_char*)env_ptr; + + if(!(info = addr2info(flash_addr))) { + return; + } + + while (count--) { + *dst++ = info->read8(src++); + } + + if (crc32(0, env_ptr->data, ENV_SIZE) == env_ptr->crc) { + gd->env_addr = (ulong)&(env_ptr->data); + gd->env_valid = 1; + return(0); + } else { + return use_default(); + } + + #if !defined(ENV_IS_EMBEDDED) || defined(CFG_ENV_ADDR_REDUND) #ifdef CFG_ENV_ADDR_REDUND if (gd->env_addr != (ulong)&(flash_addr->data)) { @@ -384,4 +407,23 @@ void env_relocate_spec (void) #endif /* ! ENV_IS_EMBEDDED || CFG_ENV_ADDR_REDUND */ } +#if !defined(ENV_IS_EMBEDDED) +static void use_default() +{ + puts ("*** Warning - bad CRC or FLASH, using default environment\n\n"); + + if (default_environment_size > CFG_ENV_SIZE){ + puts ("*** Error - default environment is too large\n\n"); + return; + } + + memset (env_ptr, 0, sizeof(env_t)); + memcpy (env_ptr->data, + default_environment, + default_environment_size); + env_ptr->crc = crc32(0, env_ptr->data, ENV_SIZE); + gd->env_valid = 1; +} +#endif + #endif /* CFG_ENV_IS_IN_FLASH */ diff --git a/common/env_sf.c b/common/env_sf.c new file mode 100644 index 00000000000..d641a9a73ca --- /dev/null +++ b/common/env_sf.c @@ -0,0 +1,131 @@ +/* + * (C) Copyright 2000-2002 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * (C) Copyright 2001 Sysgo Real-Time Solutions, GmbH <www.elinos.com> + * Andreas Heppel <aheppel@sysgo.de> + * + * (C) Copyright 2008 Atmel Corporation + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ +#include <common.h> + +#ifdef CFG_ENV_IS_IN_SPI_FLASH + +#include <environment.h> +#include <spi_flash.h> + +#ifndef CFG_ENV_SPI_BUS +# define CFG_ENV_SPI_BUS 0 +#endif +#ifndef CFG_ENV_SPI_CS +# define CFG_ENV_SPI_CS 0 +#endif +#ifndef CFG_ENV_SPI_MAX_HZ +# define CFG_ENV_SPI_MAX_HZ 1000000 +#endif +#ifndef CFG_ENV_SPI_MODE +# define CFG_ENV_SPI_MODE SPI_MODE_3 +#endif + +DECLARE_GLOBAL_DATA_PTR; + +/* references to names in env_common.c */ +extern uchar default_environment[]; +extern int default_environment_size; + +char * env_name_spec = "SPI Flash"; +env_t *env_ptr; + +static struct spi_flash *env_flash; + +uchar env_get_char_spec(int index) +{ + return *((uchar *)(gd->env_addr + index)); +} + +int saveenv(void) +{ + if (!env_flash) { + puts("Environment SPI flash not initialized\n"); + return 1; + } + + puts("Erasing SPI flash..."); + if (spi_flash_erase(env_flash, CFG_ENV_OFFSET, CFG_ENV_SIZE)) + return 1; + + puts("Writing to SPI flash..."); + if (spi_flash_write(env_flash, CFG_ENV_OFFSET, CFG_ENV_SIZE, env_ptr)) + return 1; + + puts("done\n"); + return 0; +} + +void env_relocate_spec(void) +{ + int ret; + + env_flash = spi_flash_probe(CFG_ENV_SPI_BUS, CFG_ENV_SPI_CS, + CFG_ENV_SPI_MAX_HZ, CFG_ENV_SPI_MODE); + if (!env_flash) + goto err_probe; + + ret = spi_flash_read(env_flash, CFG_ENV_OFFSET, CFG_ENV_SIZE, env_ptr); + if (ret) + goto err_read; + + if (crc32(0, env_ptr->data, ENV_SIZE) != env_ptr->crc) + goto err_crc; + + gd->env_valid = 1; + + return; + +err_read: + spi_flash_free(env_flash); + env_flash = NULL; +err_probe: +err_crc: + puts("*** Warning - bad CRC, using default environment\n\n"); + + if (default_environment_size > CFG_ENV_SIZE) { + gd->env_valid = 0; + puts("*** Error - default environment is too large\n\n"); + return; + } + + memset(env_ptr, 0, sizeof(env_t)); + memcpy(env_ptr->data, default_environment, default_environment_size); + env_ptr->crc = crc32(0, env_ptr->data, ENV_SIZE); + gd->env_valid = 1; +} + +int env_init(void) +{ + /* SPI flash isn't usable before relocation */ + gd->env_addr = (ulong)&default_environment[0]; + gd->env_valid = 1; + + return 0; +} + +#endif /* CFG_ENV_IS_IN_SPI_FLASH */ diff --git a/common/soft_spi.c b/common/soft_spi.c index e4250616c28..c13165030db 100644 --- a/common/soft_spi.c +++ b/common/soft_spi.c @@ -29,6 +29,8 @@ #if defined(CONFIG_SOFT_SPI) +#include <malloc.h> + /*----------------------------------------------------------------------- * Definitions */ @@ -39,6 +41,15 @@ #define PRINTD(fmt,args...) #endif +struct soft_spi_slave { + struct spi_slave slave; + unsigned int mode; +}; + +static inline struct soft_spi_slave *to_soft_spi(struct spi_slave *slave) +{ + return container_of(slave, struct soft_spi_slave, slave); +} /*=====================================================================*/ /* Public Functions */ @@ -56,6 +67,57 @@ void spi_init (void) #endif } +struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs, + unsigned int max_hz, unsigned int mode) +{ + struct soft_spi_slave *ss; + + if (!spi_cs_is_valid(bus, cs)) + return NULL; + + ss = malloc(sizeof(struct soft_spi_slave)); + if (!ss) + return NULL; + + ss->slave.bus = bus; + ss->slave.cs = cs; + ss->mode = mode; + + /* TODO: Use max_hz to limit the SCK rate */ + + return &ss->slave; +} + +void spi_free_slave(struct spi_slave *slave) +{ + struct soft_spi_slave *ss = to_soft_spi(slave); + + free(ss); +} + +int spi_claim_bus(struct spi_slave *slave) +{ +#ifdef CFG_IMMR + volatile immap_t *immr = (immap_t *)CFG_IMMR; +#endif + struct soft_spi_slave *ss = to_soft_spi(slave); + + /* + * Make sure the SPI clock is in idle state as defined for + * this slave. + */ + if (ss->mode & SPI_CPOL) + SPI_SCL(1); + else + SPI_SCL(0); + + return 0; +} + +void spi_release_bus(struct spi_slave *slave) +{ + /* Nothing to do */ +} /*----------------------------------------------------------------------- * SPI transfer @@ -68,50 +130,54 @@ void spi_init (void) * and "din" can point to the same memory location, in which case the * input data overwrites the output data (since both are buffered by * temporary variables, this is OK). - * - * If the chipsel() function is not NULL, it is called with a parameter - * of '1' (chip select active) at the start of the transfer and again with - * a parameter of '0' at the end of the transfer. - * - * If the chipsel() function _is_ NULL, it the responsibility of the - * caller to make the appropriate chip select active before calling - * spi_xfer() and making it inactive after spi_xfer() returns. */ -int spi_xfer(spi_chipsel_type chipsel, int bitlen, uchar *dout, uchar *din) +int spi_xfer(struct spi_slave *slave, unsigned int bitlen, + const void *dout, void *din, unsigned long flags) { #ifdef CFG_IMMR volatile immap_t *immr = (immap_t *)CFG_IMMR; #endif - uchar tmpdin = 0; - uchar tmpdout = 0; - int j; + struct soft_spi_slave *ss = to_soft_spi(slave); + uchar tmpdin = 0; + uchar tmpdout = 0; + const u8 *txd = dout; + u8 *rxd = din; + int cpol = ss->mode & SPI_CPOL; + int cpha = ss->mode & SPI_CPHA; + unsigned int j; - PRINTD("spi_xfer: chipsel %08X dout %08X din %08X bitlen %d\n", - (int)chipsel, *(uint *)dout, *(uint *)din, bitlen); + PRINTD("spi_xfer: slave %u:%u dout %08X din %08X bitlen %u\n", + slave->bus, slave->cs, *(uint *)txd, *(uint *)rxd, bitlen); - if(chipsel != NULL) { - (*chipsel)(1); /* select the target chip */ - } + if (flags & SPI_XFER_BEGIN) + spi_cs_activate(slave); for(j = 0; j < bitlen; j++) { /* * Check if it is time to work on a new byte. */ if((j % 8) == 0) { - tmpdout = *dout++; + tmpdout = *txd++; if(j != 0) { - *din++ = tmpdin; + *rxd++ = tmpdin; } tmpdin = 0; } - SPI_SCL(0); + + if (!cpha) + SPI_SCL(!cpol); SPI_SDA(tmpdout & 0x80); SPI_DELAY; - SPI_SCL(1); + if (cpha) + SPI_SCL(!cpol); + else + SPI_SCL(cpol); + tmpdin <<= 1; + tmpdin |= SPI_READ; + tmpdout <<= 1; SPI_DELAY; - tmpdin <<= 1; - tmpdin |= SPI_READ; - tmpdout <<= 1; + if (cpha) + SPI_SCL(cpol); } /* * If the number of bits isn't a multiple of 8, shift the last @@ -120,14 +186,10 @@ int spi_xfer(spi_chipsel_type chipsel, int bitlen, uchar *dout, uchar *din) */ if((bitlen % 8) != 0) tmpdin <<= 8 - (bitlen % 8); - *din++ = tmpdin; - - SPI_SCL(0); /* SPI wants the clock left low for idle */ + *rxd++ = tmpdin; - if(chipsel != NULL) { - (*chipsel)(0); /* deselect the target chip */ - - } + if (flags & SPI_XFER_END) + spi_cs_deactivate(slave); return(0); } diff --git a/common/usb.c b/common/usb.c index 4df01eabe51..ff972cba140 100644 --- a/common/usb.c +++ b/common/usb.c @@ -10,7 +10,7 @@ * (C) Copyright Randy Dunlap 2000 * (C) Copyright David Brownell 2000 (kernel hotplug, usb_device_id) * (C) Copyright Yggdrasil Computing, Inc. 2000 - * (usb_device_id matching changes by Adam J. Richter) + * (usb_device_id matching changes by Adam J. Richter) * * Adapted for U-Boot: * (C) Copyright 2001 Denis Peter, MPL AG Switzerland @@ -59,7 +59,7 @@ #undef USB_DEBUG #ifdef USB_DEBUG -#define USB_PRINTF(fmt,args...) printf (fmt ,##args) +#define USB_PRINTF(fmt,args...) printf (fmt ,##args) #else #define USB_PRINTF(fmt,args...) #endif @@ -180,7 +180,7 @@ int usb_control_msg(struct usb_device *dev, unsigned int pipe, setup_packet.value = swap_16(value); setup_packet.index = swap_16(index); setup_packet.length = swap_16(size); - USB_PRINTF("usb_control_msg: request: 0x%X, requesttype: 0x%X\nvalue 0x%X index 0x%X length 0x%X\n", + USB_PRINTF("usb_control_msg: request: 0x%X, requesttype: 0x%X\nvalue 0x%X index 0x%X length 0x%X\n", request,requesttype,value,index,size); dev->status=USB_ST_NOT_PROC; /*not yet processed */ @@ -241,40 +241,59 @@ int usb_maxpacket(struct usb_device *dev,unsigned long pipe) return(dev->epmaxpacketin[((pipe>>15) & 0xf)]); } +/* The routine usb_set_maxpacket_ep() is extracted from the loop of routine + * usb_set_maxpacket(), because the optimizer of GCC 4.x chokes on this routine + * when it is inlined in 1 single routine. What happens is that the register r3 + * is used as loop-count 'i', but gets overwritten later on. + * This is clearly a compiler bug, but it is easier to workaround it here than + * to update the compiler (Occurs with at least several GCC 4.{1,2},x + * CodeSourcery compilers like e.g. 2007q3, 2008q1, 2008q3 lite editions on ARM) + */ +static void __attribute__((noinline)) +usb_set_maxpacket_ep(struct usb_device *dev, struct usb_endpoint_descriptor *ep) +{ + int b; + + b = ep->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK; + + if ((ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == + USB_ENDPOINT_XFER_CONTROL) { + /* Control => bidirectional */ + dev->epmaxpacketout[b] = ep->wMaxPacketSize; + dev->epmaxpacketin [b] = ep->wMaxPacketSize; + USB_PRINTF("##Control EP epmaxpacketout/in[%d] = %d\n", + b, dev->epmaxpacketin[b]); + } else { + if ((ep->bEndpointAddress & 0x80) == 0) { + /* OUT Endpoint */ + if (ep->wMaxPacketSize > dev->epmaxpacketout[b]) { + dev->epmaxpacketout[b] = ep->wMaxPacketSize; + USB_PRINTF("##EP epmaxpacketout[%d] = %d\n", + b, dev->epmaxpacketout[b]); + } + } else { + /* IN Endpoint */ + if (ep->wMaxPacketSize > dev->epmaxpacketin[b]) { + dev->epmaxpacketin[b] = ep->wMaxPacketSize; + USB_PRINTF("##EP epmaxpacketin[%d] = %d\n", + b, dev->epmaxpacketin[b]); + } + } /* if out */ + } /* if control */ +} + /* * set the max packed value of all endpoints in the given configuration */ int usb_set_maxpacket(struct usb_device *dev) { - int i,ii,b; - struct usb_endpoint_descriptor *ep; + int i, ii; - for(i=0; i<dev->config.bNumInterfaces;i++) { - for(ii=0; ii<dev->config.if_desc[i].bNumEndpoints; ii++) { - ep=&dev->config.if_desc[i].ep_desc[ii]; - b=ep->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK; + for (i = 0; i < dev->config.bNumInterfaces; i++) + for (ii = 0; ii < dev->config.if_desc[i].bNumEndpoints; ii++) + usb_set_maxpacket_ep(dev, + &dev->config.if_desc[i].ep_desc[ii]); - if((ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)==USB_ENDPOINT_XFER_CONTROL) { /* Control => bidirectional */ - dev->epmaxpacketout[b] = ep->wMaxPacketSize; - dev->epmaxpacketin [b] = ep->wMaxPacketSize; - USB_PRINTF("##Control EP epmaxpacketout/in[%d] = %d\n",b,dev->epmaxpacketin[b]); - } - else { - if ((ep->bEndpointAddress & 0x80)==0) { /* OUT Endpoint */ - if(ep->wMaxPacketSize > dev->epmaxpacketout[b]) { - dev->epmaxpacketout[b] = ep->wMaxPacketSize; - USB_PRINTF("##EP epmaxpacketout[%d] = %d\n",b,dev->epmaxpacketout[b]); - } - } - else { /* IN Endpoint */ - if(ep->wMaxPacketSize > dev->epmaxpacketin[b]) { - dev->epmaxpacketin[b] = ep->wMaxPacketSize; - USB_PRINTF("##EP epmaxpacketin[%d] = %d\n",b,dev->epmaxpacketin[b]); - } - } /* if out */ - } /* if control */ - } /* for each endpoint */ - } return 0; } @@ -356,6 +375,7 @@ int usb_parse_config(struct usb_device *dev, unsigned char *buffer, int cfgno) * endp: endpoint number in bits 0-3; * direction flag in bit 7 (1 = IN, 0 = OUT) */ + int usb_clear_halt(struct usb_device *dev, int pipe) { int result; @@ -387,7 +407,7 @@ int usb_clear_halt(struct usb_device *dev, int pipe) int usb_get_descriptor(struct usb_device *dev, unsigned char type, unsigned char index, void *buf, int size) { int res; - res = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), + res = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), USB_REQ_GET_DESCRIPTOR, USB_DIR_IN, (type << 8) + index, 0, buf, size, USB_CNTL_TIMEOUT); @@ -399,7 +419,7 @@ int usb_get_descriptor(struct usb_device *dev, unsigned char type, unsigned char */ int usb_get_configuration_no(struct usb_device *dev,unsigned char *buffer,int cfgno) { - int result; + int result; unsigned int tmp; struct usb_config_descriptor *config; @@ -470,8 +490,8 @@ int usb_set_interface(struct usb_device *dev, int interface, int alternate) return 0; if ((ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), - USB_REQ_SET_INTERFACE, USB_RECIP_INTERFACE, alternate, - interface, NULL, 0, USB_CNTL_TIMEOUT * 5)) < 0) + USB_REQ_SET_INTERFACE, USB_RECIP_INTERFACE, alternate, + interface, NULL, 0, USB_CNTL_TIMEOUT * 5)) < 0) return ret; return 0; @@ -651,7 +671,7 @@ int usb_string(struct usb_device *dev, int index, char *buf, size_t size) if (err < 0) return err; - size--; /* leave room for trailing NULL char in output buffer */ + size--; /* leave room for trailing NULL char in output buffer */ for (idx = 0, u = 2; u < err; u += 2) { if (idx >= size) break; @@ -719,7 +739,7 @@ int usb_new_device(struct usb_device *dev) unsigned char tmpbuf[USB_BUFSIZ]; dev->descriptor.bMaxPacketSize0 = 8; /* Start off at 8 bytes */ - dev->maxpacketsize = 0; /* Default to 8 byte max packet size */ + dev->maxpacketsize = 0; /* Default to 8 byte max packet size */ dev->epmaxpacketin [0] = 8; dev->epmaxpacketout[0] = 8; @@ -740,7 +760,7 @@ int usb_new_device(struct usb_device *dev) struct usb_device *parent = dev->parent; unsigned short portstatus; - /* send 64-byte GET-DEVICE-DESCRIPTOR request. Since the descriptor is + /* send 64-byte GET-DEVICE-DESCRIPTOR request. Since the descriptor is * only 18 bytes long, this will terminate with a short packet. But if * the maxpacket size is 8 or 16 the device may be waiting to transmit * some more. */ @@ -773,7 +793,7 @@ int usb_new_device(struct usb_device *dev) /* reset the port for the second time */ err = hub_port_reset(dev->parent, port, &portstatus); if (err < 0) { - printf("\n Couldn't reset port %i\n", port); + printf("\n Couldn't reset port %i\n", port); return 1; } } @@ -781,7 +801,7 @@ int usb_new_device(struct usb_device *dev) /* and this is the old and known way of initializing devices */ err = usb_get_descriptor(dev, USB_DT_DEVICE, 0, &dev->descriptor, 8); if (err < 8) { - printf("\n USB device not responding, giving up (status=%lX)\n",dev->status); + printf("\n USB device not responding, giving up (status=%lX)\n",dev->status); return 1; } #endif @@ -799,7 +819,7 @@ int usb_new_device(struct usb_device *dev) err = usb_set_address(dev); /* set address */ if (err < 0) { - printf("\n USB device not accepting new address (error=%lX)\n", dev->status); + printf("\n USB device not accepting new address (error=%lX)\n", dev->status); return 1; } @@ -841,7 +861,7 @@ int usb_new_device(struct usb_device *dev) if (dev->descriptor.iSerialNumber) usb_string(dev, dev->descriptor.iSerialNumber, dev->serial, sizeof(dev->serial)); USB_PRINTF("Manufacturer %s\n", dev->mf); - USB_PRINTF("Product %s\n", dev->prod); + USB_PRINTF("Product %s\n", dev->prod); USB_PRINTF("SerialNumber %s\n", dev->serial); /* now prode if the device is a hub */ usb_hub_probe(dev,0); @@ -880,7 +900,7 @@ void usb_scan_devices(void) #undef USB_HUB_DEBUG #ifdef USB_HUB_DEBUG -#define USB_HUB_PRINTF(fmt,args...) printf (fmt ,##args) +#define USB_HUB_PRINTF(fmt,args...) printf (fmt ,##args) #else #define USB_HUB_PRINTF(fmt,args...) #endif @@ -988,7 +1008,7 @@ static int hub_port_reset(struct usb_device *dev, int port, (portstatus & USB_PORT_STAT_CONNECTION) ? 1 : 0, (portstatus & USB_PORT_STAT_ENABLE) ? 1 : 0); if ((portchange & USB_PORT_STAT_C_CONNECTION) || - !(portstatus & USB_PORT_STAT_CONNECTION)) + !(portstatus & USB_PORT_STAT_CONNECTION)) return -1; if (portstatus & USB_PORT_STAT_ENABLE) { @@ -1034,7 +1054,7 @@ void usb_hub_port_connect_change(struct usb_device *dev, int port) /* Disconnect any existing devices under this port */ if (((!(portstatus & USB_PORT_STAT_CONNECTION)) && - (!(portstatus & USB_PORT_STAT_ENABLE)))|| (dev->children[port])) { + (!(portstatus & USB_PORT_STAT_ENABLE)))|| (dev->children[port])) { USB_HUB_PRINTF("usb_disconnect(&hub->children[port]);\n"); /* Return now if nothing is connected */ if (!(portstatus & USB_PORT_STAT_CONNECTION)) @@ -1053,6 +1073,7 @@ void usb_hub_port_connect_change(struct usb_device *dev, int port) /* Allocate a new device struct for it */ usb=usb_alloc_new_device(); usb->slow = (portstatus & USB_PORT_STAT_LOW_SPEED) ? 1 : 0; + usb->high = (portstatus & USB_PORT_STAT_HIGH_SPEED) ? 1 : 0; dev->children[port] = usb; usb->parent=dev; @@ -1142,7 +1163,7 @@ int usb_hub_configure(struct usb_device *dev) case 0x10: case 0x18: USB_HUB_PRINTF("no over-current protection\n"); - break; + break; } USB_HUB_PRINTF("power on to power good time: %dms\n", descriptor->bPwrOn2PwrGood * 2); USB_HUB_PRINTF("hub controller current requirement: %dmA\n", descriptor->bHubContrCurrent); @@ -1178,7 +1199,7 @@ int usb_hub_configure(struct usb_device *dev) portstatus = swap_16(portsts.wPortStatus); portchange = swap_16(portsts.wPortChange); USB_HUB_PRINTF("Port %d Status %X Change %X\n",i+1,portstatus,portchange); - if (portchange & USB_PORT_STAT_C_CONNECTION) { + if ( (portchange & USB_PORT_STAT_C_CONNECTION) || (portstatus & USB_PORT_STAT_CONNECTION)) { USB_HUB_PRINTF("port %d connection change\n", i + 1); usb_hub_port_connect_change(dev, i); } @@ -1198,7 +1219,7 @@ int usb_hub_configure(struct usb_device *dev) } if (portstatus & USB_PORT_STAT_SUSPEND) { USB_HUB_PRINTF("port %d suspend change\n", i + 1); - usb_clear_port_feature(dev, i + 1, USB_PORT_FEAT_SUSPEND); + usb_clear_port_feature(dev, i + 1, USB_PORT_FEAT_SUSPEND); } if (portchange & USB_PORT_STAT_C_OVERCURRENT) { @@ -1227,9 +1248,9 @@ int usb_hub_probe(struct usb_device *dev, int ifnum) if (iface->bInterfaceClass != USB_CLASS_HUB) return 0; /* Some hubs have a subclass of 1, which AFAICT according to the */ - /* specs is not defined, but it works */ + /* specs is not defined, but it works */ if ((iface->bInterfaceSubClass != 0) && - (iface->bInterfaceSubClass != 1)) + (iface->bInterfaceSubClass != 1)) return 0; /* Multiple endpoints? What kind of mutant ninja-hub is this? */ if (iface->bNumEndpoints != 1) diff --git a/common/usb_storage.c b/common/usb_storage.c index 7c08f957752..ee1178eac8f 100644 --- a/common/usb_storage.c +++ b/common/usb_storage.c @@ -26,7 +26,7 @@ * * 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 + * 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 @@ -65,8 +65,8 @@ #undef BBB_COMDAT_TRACE #undef BBB_XPORT_TRACE -#ifdef USB_STOR_DEBUG -#define USB_STOR_PRINTF(fmt,args...) printf (fmt ,##args) +#ifdef USB_STOR_DEBUG +#define USB_STOR_PRINTF(fmt,args...) printf (fmt ,##args) #else #define USB_STOR_PRINTF(fmt,args...) #endif @@ -76,10 +76,10 @@ * transfer for each command code -- a 1 indicates input */ unsigned char us_direction[256/8] = { - 0x28, 0x81, 0x14, 0x14, 0x20, 0x01, 0x90, 0x77, - 0x0C, 0x20, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + 0x28, 0x81, 0x14, 0x14, 0x20, 0x01, 0x90, 0x77, + 0x0C, 0x20, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; #define US_DIRECTION(x) ((us_direction[x>>3] >> (x & 7)) & 1) @@ -90,43 +90,43 @@ static ccb usb_ccb; * CBI style */ -#define US_CBI_ADSC 0 +#define US_CBI_ADSC 0 /* * BULK only */ -#define US_BBB_RESET 0xff -#define US_BBB_GET_MAX_LUN 0xfe +#define US_BBB_RESET 0xff +#define US_BBB_GET_MAX_LUN 0xfe /* Command Block Wrapper */ typedef struct { - __u32 dCBWSignature; -# define CBWSIGNATURE 0x43425355 - __u32 dCBWTag; - __u32 dCBWDataTransferLength; - __u8 bCBWFlags; -# define CBWFLAGS_OUT 0x00 -# define CBWFLAGS_IN 0x80 - __u8 bCBWLUN; - __u8 bCDBLength; -# define CBWCDBLENGTH 16 - __u8 CBWCDB[CBWCDBLENGTH]; + __u32 dCBWSignature; +# define CBWSIGNATURE 0x43425355 + __u32 dCBWTag; + __u32 dCBWDataTransferLength; + __u8 bCBWFlags; +# define CBWFLAGS_OUT 0x00 +# define CBWFLAGS_IN 0x80 + __u8 bCBWLUN; + __u8 bCDBLength; +# define CBWCDBLENGTH 16 + __u8 CBWCDB[CBWCDBLENGTH]; } umass_bbb_cbw_t; -#define UMASS_BBB_CBW_SIZE 31 +#define UMASS_BBB_CBW_SIZE 31 static __u32 CBWTag = 0; /* Command Status Wrapper */ typedef struct { - __u32 dCSWSignature; -# define CSWSIGNATURE 0x53425355 - __u32 dCSWTag; - __u32 dCSWDataResidue; - __u8 bCSWStatus; -# define CSWSTATUS_GOOD 0x0 -# define CSWSTATUS_FAILED 0x1 -# define CSWSTATUS_PHASE 0x2 + __u32 dCSWSignature; +# define CSWSIGNATURE 0x53425355 + __u32 dCSWTag; + __u32 dCSWDataResidue; + __u8 bCSWStatus; +# define CSWSTATUS_GOOD 0x0 +# define CSWSTATUS_FAILED 0x1 +# define CSWSTATUS_PHASE 0x2 } umass_bbb_csw_t; -#define UMASS_BBB_CSW_SIZE 13 +#define UMASS_BBB_CSW_SIZE 13 #define USB_MAX_STOR_DEV 5 static int usb_max_devs = 0; /* number of highest available usb device */ @@ -138,31 +138,31 @@ typedef int (*trans_cmnd)(ccb*, struct us_data*); typedef int (*trans_reset)(struct us_data*); struct us_data { - struct usb_device *pusb_dev; /* this usb_device */ - unsigned int flags; /* from filter initially */ - unsigned char ifnum; /* interface number */ - unsigned char ep_in; /* in endpoint */ - unsigned char ep_out; /* out ....... */ - unsigned char ep_int; /* interrupt . */ - unsigned char subclass; /* as in overview */ - unsigned char protocol; /* .............. */ - unsigned char attention_done; /* force attn on first cmd */ - unsigned short ip_data; /* interrupt data */ - int action; /* what to do */ - int ip_wanted; /* needed */ - int *irq_handle; /* for USB int requests */ - unsigned int irqpipe; /* pipe for release_irq */ - unsigned char irqmaxp; /* max packed for irq Pipe */ - unsigned char irqinterval; /* Intervall for IRQ Pipe */ - ccb *srb; /* current srb */ - trans_reset transport_reset; /* reset routine */ - trans_cmnd transport; /* transport routine */ + struct usb_device *pusb_dev; /* this usb_device */ + unsigned int flags; /* from filter initially */ + unsigned char ifnum; /* interface number */ + unsigned char ep_in; /* in endpoint */ + unsigned char ep_out; /* out ....... */ + unsigned char ep_int; /* interrupt . */ + unsigned char subclass; /* as in overview */ + unsigned char protocol; /* .............. */ + unsigned char attention_done; /* force attn on first cmd */ + unsigned short ip_data; /* interrupt data */ + int action; /* what to do */ + int ip_wanted; /* needed */ + int *irq_handle; /* for USB int requests */ + unsigned int irqpipe; /* pipe for release_irq */ + unsigned char irqmaxp; /* max packed for irq Pipe */ + unsigned char irqinterval; /* Intervall for IRQ Pipe */ + ccb *srb; /* current srb */ + trans_reset transport_reset; /* reset routine */ + trans_cmnd transport; /* transport routine */ }; static struct us_data usb_stor[USB_MAX_STOR_DEV]; -#define USB_STOR_TRANSPORT_GOOD 0 +#define USB_STOR_TRANSPORT_GOOD 0 #define USB_STOR_TRANSPORT_FAILED -1 #define USB_STOR_TRANSPORT_ERROR -2 @@ -175,13 +175,13 @@ void uhci_show_temp_int_td(void); block_dev_desc_t *usb_stor_get_dev(int index) { - return (index < USB_MAX_STOR_DEV) ? &usb_dev_desc[index] : NULL; + return (index < USB_MAX_STOR_DEV) ? &usb_dev_desc[index] : NULL; } void usb_show_progress(void) { - printf("."); + printf("."); } /********************************************************************************* @@ -190,18 +190,18 @@ void usb_show_progress(void) */ int usb_stor_info(void) { - int i; - - if (usb_max_devs > 0) { - for (i = 0; i < usb_max_devs; i++) { - printf (" Device %d: ", i); - dev_print(&usb_dev_desc[i]); - } - return 0; - } - - printf("No storage devices, perhaps not 'usb start'ed..?\n"); - return 1; + int i; + + if (usb_max_devs > 0) { + for (i = 0; i < usb_max_devs; i++) { + printf (" Device %d: ", i); + dev_print(&usb_dev_desc[i]); + } + return 0; + } + + printf("No storage devices, perhaps not 'usb start'ed..?\n"); + return 1; } /********************************************************************************* @@ -211,86 +211,86 @@ int usb_stor_info(void) */ int usb_stor_scan(int mode) { - unsigned char i; - struct usb_device *dev; - - /* GJ */ - memset(usb_stor_buf, 0, sizeof(usb_stor_buf)); - - if(mode==1) { - printf(" scanning bus for storage devices... "); - } - usb_disable_asynch(1); /* asynch transfer not allowed */ - - for(i=0;i<USB_MAX_STOR_DEV;i++) { - memset(&usb_dev_desc[i],0,sizeof(block_dev_desc_t)); - usb_dev_desc[i].target=0xff; - usb_dev_desc[i].if_type=IF_TYPE_USB; - usb_dev_desc[i].dev=i; - usb_dev_desc[i].part_type=PART_TYPE_UNKNOWN; - usb_dev_desc[i].block_read=usb_stor_read; - } - - usb_max_devs=0; - for(i=0;i<USB_MAX_DEVICE;i++) { - dev=usb_get_dev_index(i); /* get device */ - USB_STOR_PRINTF("i=%d\n",i); - if(dev==NULL) { - break; /* no more devices avaiable */ - } - if(usb_storage_probe(dev,0,&usb_stor[usb_max_devs])) { /* ok, it is a storage devices */ - /* get info and fill it in */ - if(usb_stor_get_info(dev, &usb_stor[usb_max_devs], &usb_dev_desc[usb_max_devs])) - usb_max_devs++; - } /* if storage device */ - if(usb_max_devs==USB_MAX_STOR_DEV) { - printf("max USB Storage Device reached: %d stopping\n",usb_max_devs); - break; - } - } /* for */ - - usb_disable_asynch(0); /* asynch transfer allowed */ - printf("%d Storage Device(s) found\n", usb_max_devs); - if(usb_max_devs>0) - return 0; - else - return-1; + unsigned char i; + struct usb_device *dev; + + /* GJ */ + memset(usb_stor_buf, 0, sizeof(usb_stor_buf)); + + if(mode==1) { + printf(" scanning bus for storage devices... "); + } + usb_disable_asynch(1); /* asynch transfer not allowed */ + + for(i=0;i<USB_MAX_STOR_DEV;i++) { + memset(&usb_dev_desc[i],0,sizeof(block_dev_desc_t)); + usb_dev_desc[i].target=0xff; + usb_dev_desc[i].if_type=IF_TYPE_USB; + usb_dev_desc[i].dev=i; + usb_dev_desc[i].part_type=PART_TYPE_UNKNOWN; + usb_dev_desc[i].block_read=usb_stor_read; + } + + usb_max_devs=0; + for(i=0;i<USB_MAX_DEVICE;i++) { + dev=usb_get_dev_index(i); /* get device */ + USB_STOR_PRINTF("i=%d\n",i); + if(dev==NULL) { + break; /* no more devices avaiable */ + } + if(usb_storage_probe(dev,0,&usb_stor[usb_max_devs])) { /* ok, it is a storage devices */ + /* get info and fill it in */ + if(usb_stor_get_info(dev, &usb_stor[usb_max_devs], &usb_dev_desc[usb_max_devs])) + usb_max_devs++; + } /* if storage device */ + if(usb_max_devs==USB_MAX_STOR_DEV) { + printf("max USB Storage Device reached: %d stopping\n",usb_max_devs); + break; + } + } /* for */ + + usb_disable_asynch(0); /* asynch transfer allowed */ + printf("%d Storage Device(s) found\n", usb_max_devs); + if(usb_max_devs>0) + return 0; + else + return-1; } static int usb_stor_irq(struct usb_device *dev) { - struct us_data *us; - us=(struct us_data *)dev->privptr; + struct us_data *us; + us=(struct us_data *)dev->privptr; - if(us->ip_wanted) { - us->ip_wanted=0; - } - return 0; + if(us->ip_wanted) { + us->ip_wanted=0; + } + return 0; } -#ifdef USB_STOR_DEBUG +#ifdef USB_STOR_DEBUG static void usb_show_srb(ccb * pccb) { - int i; - printf("SRB: len %d datalen 0x%lX\n ",pccb->cmdlen,pccb->datalen); - for(i=0;i<12;i++) { - printf("%02X ",pccb->cmd[i]); - } - printf("\n"); + int i; + printf("SRB: len %d datalen 0x%lX\n ",pccb->cmdlen,pccb->datalen); + for(i=0;i<12;i++) { + printf("%02X ",pccb->cmd[i]); + } + printf("\n"); } static void display_int_status(unsigned long tmp) { - printf("Status: %s %s %s %s %s %s %s\n", - (tmp & USB_ST_ACTIVE) ? "Active" : "", - (tmp & USB_ST_STALLED) ? "Stalled" : "", - (tmp & USB_ST_BUF_ERR) ? "Buffer Error" : "", - (tmp & USB_ST_BABBLE_DET) ? "Babble Det" : "", - (tmp & USB_ST_NAK_REC) ? "NAKed" : "", - (tmp & USB_ST_CRC_ERR) ? "CRC Error" : "", - (tmp & USB_ST_BIT_ERR) ? "Bitstuff Error" : ""); + printf("Status: %s %s %s %s %s %s %s\n", + (tmp & USB_ST_ACTIVE) ? "Active" : "", + (tmp & USB_ST_STALLED) ? "Stalled" : "", + (tmp & USB_ST_BUF_ERR) ? "Buffer Error" : "", + (tmp & USB_ST_BABBLE_DET) ? "Babble Det" : "", + (tmp & USB_ST_NAK_REC) ? "NAKed" : "", + (tmp & USB_ST_CRC_ERR) ? "CRC Error" : "", + (tmp & USB_ST_BIT_ERR) ? "Bitstuff Error" : ""); } #endif /*********************************************************************** @@ -299,121 +299,125 @@ static void display_int_status(unsigned long tmp) static int us_one_transfer(struct us_data *us, int pipe, char *buf, int length) { - int max_size; - int this_xfer; - int result; - int partial; - int maxtry; - int stat; - - /* determine the maximum packet size for these transfers */ - max_size = usb_maxpacket(us->pusb_dev, pipe) * 16; - - /* while we have data left to transfer */ - while (length) { - - /* calculate how long this will be -- maximum or a remainder */ - this_xfer = length > max_size ? max_size : length; - length -= this_xfer; - - /* setup the retry counter */ - maxtry = 10; - - /* set up the transfer loop */ - do { - /* transfer the data */ - USB_STOR_PRINTF("Bulk xfer 0x%x(%d) try #%d\n", - (unsigned int)buf, this_xfer, 11 - maxtry); - result = usb_bulk_msg(us->pusb_dev, pipe, buf, - this_xfer, &partial, USB_CNTL_TIMEOUT*5); - USB_STOR_PRINTF("bulk_msg returned %d xferred %d/%d\n", - result, partial, this_xfer); - if(us->pusb_dev->status!=0) { - /* if we stall, we need to clear it before we go on */ + int max_size; + int this_xfer; + int result; + int partial; + int maxtry; + int stat; + + /* determine the maximum packet size for these transfers */ + max_size = usb_maxpacket(us->pusb_dev, pipe) * 16; + + /* while we have data left to transfer */ + while (length) { + + /* calculate how long this will be -- maximum or a remainder */ + this_xfer = length > max_size ? max_size : length; + length -= this_xfer; + + /* setup the retry counter */ + maxtry = 10; + + /* set up the transfer loop */ + do { + /* transfer the data */ + USB_STOR_PRINTF("Bulk xfer 0x%x(%d) try #%d\n", + (unsigned int)buf, this_xfer, 11 - maxtry); + result = usb_bulk_msg(us->pusb_dev, pipe, buf, + this_xfer, &partial, USB_CNTL_TIMEOUT*5); + USB_STOR_PRINTF("bulk_msg returned %d xferred %d/%d\n", + result, partial, this_xfer); + if(us->pusb_dev->status!=0) { + /* if we stall, we need to clear it before we go on */ #ifdef USB_STOR_DEBUG - display_int_status(us->pusb_dev->status); + display_int_status(us->pusb_dev->status); #endif - if (us->pusb_dev->status & USB_ST_STALLED) { - USB_STOR_PRINTF("stalled ->clearing endpoint halt for pipe 0x%x\n", pipe); - stat = us->pusb_dev->status; - usb_clear_halt(us->pusb_dev, pipe); - us->pusb_dev->status=stat; - if(this_xfer == partial) { - USB_STOR_PRINTF("bulk transferred with error %X, but data ok\n",us->pusb_dev->status); - return 0; - } - else - return result; - } - if (us->pusb_dev->status & USB_ST_NAK_REC) { - USB_STOR_PRINTF("Device NAKed bulk_msg\n"); - return result; - } - if(this_xfer == partial) { - USB_STOR_PRINTF("bulk transferred with error %d, but data ok\n",us->pusb_dev->status); - return 0; - } - /* if our try counter reaches 0, bail out */ - USB_STOR_PRINTF("bulk transferred with error %d, data %d\n",us->pusb_dev->status,partial); - if (!maxtry--) - return result; - } - /* update to show what data was transferred */ - this_xfer -= partial; - buf += partial; - /* continue until this transfer is done */ - } while ( this_xfer ); - } - - /* if we get here, we're done and successful */ - return 0; + if (us->pusb_dev->status & USB_ST_STALLED) { + USB_STOR_PRINTF("stalled ->clearing endpoint halt for pipe 0x%x\n", pipe); + stat = us->pusb_dev->status; + usb_clear_halt(us->pusb_dev, pipe); + us->pusb_dev->status=stat; + if(this_xfer == partial) { + USB_STOR_PRINTF("bulk transferred with error %X, but data ok\n",us->pusb_dev->status); + return 0; + } + else + return result; + } + if (us->pusb_dev->status & USB_ST_NAK_REC) { + USB_STOR_PRINTF("Device NAKed bulk_msg\n"); + return result; + } + if(this_xfer == partial) { + USB_STOR_PRINTF("bulk transferred with error %d, but data ok\n",us->pusb_dev->status); + return 0; + } + /* if our try counter reaches 0, bail out */ + USB_STOR_PRINTF("bulk transferred with error %d, data %d\n",us->pusb_dev->status,partial); + if (!maxtry--) + return result; + } + /* update to show what data was transferred */ + this_xfer -= partial; + buf += partial; + /* continue until this transfer is done */ + } while ( this_xfer ); + } + + /* if we get here, we're done and successful */ + return 0; } static int usb_stor_BBB_reset(struct us_data *us) { - int result; - unsigned int pipe; - - /* - * Reset recovery (5.3.4 in Universal Serial Bus Mass Storage Class) - * - * For Reset Recovery the host shall issue in the following order: - * a) a Bulk-Only Mass Storage Reset - * b) a Clear Feature HALT to the Bulk-In endpoint - * c) a Clear Feature HALT to the Bulk-Out endpoint - * - * This is done in 3 steps. - * - * If the reset doesn't succeed, the device should be port reset. - * - * This comment stolen from FreeBSD's /sys/dev/usb/umass.c. - */ - USB_STOR_PRINTF("BBB_reset\n"); - result = usb_control_msg(us->pusb_dev, usb_sndctrlpipe(us->pusb_dev,0), - US_BBB_RESET, USB_TYPE_CLASS | USB_RECIP_INTERFACE, - 0, us->ifnum, 0, 0, USB_CNTL_TIMEOUT*5); - - if((result < 0) && (us->pusb_dev->status & USB_ST_STALLED)) - { - USB_STOR_PRINTF("RESET:stall\n"); - return -1; - } - - /* long wait for reset */ - wait_ms(150); - USB_STOR_PRINTF("BBB_reset result %d: status %X reset\n",result,us->pusb_dev->status); - pipe = usb_rcvbulkpipe(us->pusb_dev, us->ep_in); - result = usb_clear_halt(us->pusb_dev, pipe); - /* long wait for reset */ - wait_ms(150); - USB_STOR_PRINTF("BBB_reset result %d: status %X clearing IN endpoint\n",result,us->pusb_dev->status); - /* long wait for reset */ - pipe = usb_sndbulkpipe(us->pusb_dev, us->ep_out); - result = usb_clear_halt(us->pusb_dev, pipe); - wait_ms(150); - USB_STOR_PRINTF("BBB_reset result %d: status %X clearing OUT endpoint\n",result,us->pusb_dev->status); - USB_STOR_PRINTF("BBB_reset done\n"); - return 0; + int result; + unsigned int pipe; + + /* + * Reset recovery (5.3.4 in Universal Serial Bus Mass Storage Class) + * + * For Reset Recovery the host shall issue in the following order: + * a) a Bulk-Only Mass Storage Reset + * b) a Clear Feature HALT to the Bulk-In endpoint + * c) a Clear Feature HALT to the Bulk-Out endpoint + * + * This is done in 3 steps. + * + * If the reset doesn't succeed, the device should be port reset. + * + * This comment stolen from FreeBSD's /sys/dev/usb/umass.c. + */ + USB_STOR_PRINTF("BBB_reset\n"); + result = usb_control_msg(us->pusb_dev, usb_sndctrlpipe(us->pusb_dev,0), + US_BBB_RESET, USB_TYPE_CLASS | USB_RECIP_INTERFACE, + 0, us->ifnum, 0, 0, USB_CNTL_TIMEOUT*5); + + if((result < 0) && (us->pusb_dev->status & USB_ST_STALLED)) + { + USB_STOR_PRINTF("RESET:stall\n"); + return -1; + } + + /* If there is any error, return */ + if ( ( result < 0 ) && ( us->pusb_dev->status != 0 ) ) + return( -1 ); + + /* long wait for reset */ + wait_ms(150); + USB_STOR_PRINTF("BBB_reset result %d: status %X reset\n",result,us->pusb_dev->status); + pipe = usb_rcvbulkpipe(us->pusb_dev, us->ep_in); + result = usb_clear_halt(us->pusb_dev, pipe); + /* long wait for reset */ + wait_ms(150); + USB_STOR_PRINTF("BBB_reset result %d: status %X clearing IN endpoint\n",result,us->pusb_dev->status); + /* long wait for reset */ + pipe = usb_sndbulkpipe(us->pusb_dev, us->ep_out); + result = usb_clear_halt(us->pusb_dev, pipe); + wait_ms(150); + USB_STOR_PRINTF("BBB_reset result %d: status %X clearing OUT endpoint\n",result,us->pusb_dev->status); + USB_STOR_PRINTF("BBB_reset done\n"); + return 0; } /* FIXME: this reset function doesn't really reset the port, and it @@ -422,25 +426,25 @@ static int usb_stor_BBB_reset(struct us_data *us) */ static int usb_stor_CB_reset(struct us_data *us) { - unsigned char cmd[12]; - int result; - - USB_STOR_PRINTF("CB_reset\n"); - memset(cmd, 0xFF, sizeof(cmd)); - cmd[0] = SCSI_SEND_DIAG; - cmd[1] = 4; - result = usb_control_msg(us->pusb_dev, usb_sndctrlpipe(us->pusb_dev,0), - US_CBI_ADSC, USB_TYPE_CLASS | USB_RECIP_INTERFACE, - 0, us->ifnum, cmd, sizeof(cmd), USB_CNTL_TIMEOUT*5); - - /* long wait for reset */ - wait_ms(1500); - USB_STOR_PRINTF("CB_reset result %d: status %X clearing endpoint halt\n",result,us->pusb_dev->status); - usb_clear_halt(us->pusb_dev, usb_rcvbulkpipe(us->pusb_dev, us->ep_in)); - usb_clear_halt(us->pusb_dev, usb_rcvbulkpipe(us->pusb_dev, us->ep_out)); - - USB_STOR_PRINTF("CB_reset done\n"); - return 0; + unsigned char cmd[12]; + int result; + + USB_STOR_PRINTF("CB_reset\n"); + memset(cmd, 0xFF, sizeof(cmd)); + cmd[0] = SCSI_SEND_DIAG; + cmd[1] = 4; + result = usb_control_msg(us->pusb_dev, usb_sndctrlpipe(us->pusb_dev,0), + US_CBI_ADSC, USB_TYPE_CLASS | USB_RECIP_INTERFACE, + 0, us->ifnum, cmd, sizeof(cmd), USB_CNTL_TIMEOUT*5); + + /* long wait for reset */ + wait_ms(1500); + USB_STOR_PRINTF("CB_reset result %d: status %X clearing endpoint halt\n",result,us->pusb_dev->status); + usb_clear_halt(us->pusb_dev, usb_rcvbulkpipe(us->pusb_dev, us->ep_in)); + usb_clear_halt(us->pusb_dev, usb_rcvbulkpipe(us->pusb_dev, us->ep_out)); + + USB_STOR_PRINTF("CB_reset done\n"); + return 0; } /* @@ -449,44 +453,44 @@ static int usb_stor_CB_reset(struct us_data *us) */ int usb_stor_BBB_comdat(ccb *srb, struct us_data *us) { - int result; - int actlen; - int dir_in; - unsigned int pipe; - umass_bbb_cbw_t cbw; + int result; + int actlen; + int dir_in; + unsigned int pipe; + umass_bbb_cbw_t cbw; - dir_in = US_DIRECTION(srb->cmd[0]); + dir_in = US_DIRECTION(srb->cmd[0]); #ifdef BBB_COMDAT_TRACE - printf("dir %d lun %d cmdlen %d cmd %p datalen %d pdata %p\n", dir_in, srb->lun, srb->cmdlen, srb->cmd, srb->datalen, srb->pdata); - if (srb->cmdlen) { - for(result = 0;result < srb->cmdlen;result++) - printf("cmd[%d] %#x ", result, srb->cmd[result]); - printf("\n"); - } + printf("dir %d lun %d cmdlen %d cmd %p datalen %d pdata %p\n", dir_in, srb->lun, srb->cmdlen, srb->cmd, srb->datalen, srb->pdata); + if (srb->cmdlen) { + for(result = 0;result < srb->cmdlen;result++) + printf("cmd[%d] %#x ", result, srb->cmd[result]); + printf("\n"); + } #endif - /* sanity checks */ - if (!(srb->cmdlen <= CBWCDBLENGTH)) { - USB_STOR_PRINTF("usb_stor_BBB_comdat:cmdlen too large\n"); - return -1; - } - - /* always OUT to the ep */ - pipe = usb_sndbulkpipe(us->pusb_dev, us->ep_out); - - cbw.dCBWSignature = swap_32(CBWSIGNATURE); - cbw.dCBWTag = swap_32(CBWTag++); - cbw.dCBWDataTransferLength = swap_32(srb->datalen); - cbw.bCBWFlags = (dir_in? CBWFLAGS_IN : CBWFLAGS_OUT); - cbw.bCBWLUN = srb->lun; - cbw.bCDBLength = srb->cmdlen; - /* copy the command data into the CBW command data buffer */ - /* DST SRC LEN!!! */ - memcpy(cbw.CBWCDB, srb->cmd, srb->cmdlen); - result = usb_bulk_msg(us->pusb_dev, pipe, &cbw, UMASS_BBB_CBW_SIZE, &actlen, USB_CNTL_TIMEOUT*5); - if (result < 0) - USB_STOR_PRINTF("usb_stor_BBB_comdat:usb_bulk_msg error\n"); - return result; + /* sanity checks */ + if (!(srb->cmdlen <= CBWCDBLENGTH)) { + USB_STOR_PRINTF("usb_stor_BBB_comdat:cmdlen too large\n"); + return -1; + } + + /* always OUT to the ep */ + pipe = usb_sndbulkpipe(us->pusb_dev, us->ep_out); + + cbw.dCBWSignature = swap_32(CBWSIGNATURE); + cbw.dCBWTag = swap_32(CBWTag++); + cbw.dCBWDataTransferLength = swap_32(srb->datalen); + cbw.bCBWFlags = (dir_in? CBWFLAGS_IN : CBWFLAGS_OUT); + cbw.bCBWLUN = srb->lun; + cbw.bCDBLength = srb->cmdlen; + /* copy the command data into the CBW command data buffer */ + /* DST SRC LEN!!! */ + memcpy(cbw.CBWCDB, srb->cmd, srb->cmdlen); + result = usb_bulk_msg(us->pusb_dev, pipe, &cbw, UMASS_BBB_CBW_SIZE, &actlen, USB_CNTL_TIMEOUT*5); + if (result < 0) + USB_STOR_PRINTF("usb_stor_BBB_comdat:usb_bulk_msg error\n"); + return result; } /* FIXME: we also need a CBI_command which sets up the completion @@ -494,100 +498,100 @@ int usb_stor_BBB_comdat(ccb *srb, struct us_data *us) */ int usb_stor_CB_comdat(ccb *srb, struct us_data *us) { - int result = 0; - int dir_in,retry; - unsigned int pipe; - unsigned long status; - - retry=5; - dir_in=US_DIRECTION(srb->cmd[0]); - - if(dir_in) - pipe=usb_rcvbulkpipe(us->pusb_dev, us->ep_in); - else - pipe=usb_sndbulkpipe(us->pusb_dev, us->ep_out); - while(retry--) { - USB_STOR_PRINTF("CBI gets a command: Try %d\n",5-retry); + int result = 0; + int dir_in,retry; + unsigned int pipe; + unsigned long status; + + retry=5; + dir_in=US_DIRECTION(srb->cmd[0]); + + if(dir_in) + pipe=usb_rcvbulkpipe(us->pusb_dev, us->ep_in); + else + pipe=usb_sndbulkpipe(us->pusb_dev, us->ep_out); + while(retry--) { + USB_STOR_PRINTF("CBI gets a command: Try %d\n",5-retry); #ifdef USB_STOR_DEBUG - usb_show_srb(srb); + usb_show_srb(srb); #endif - /* let's send the command via the control pipe */ - result = usb_control_msg(us->pusb_dev, usb_sndctrlpipe(us->pusb_dev,0), - US_CBI_ADSC, USB_TYPE_CLASS | USB_RECIP_INTERFACE, - 0, us->ifnum, - srb->cmd, srb->cmdlen, USB_CNTL_TIMEOUT*5); - USB_STOR_PRINTF("CB_transport: control msg returned %d, status %X\n",result,us->pusb_dev->status); - /* check the return code for the command */ - if (result < 0) { - if(us->pusb_dev->status & USB_ST_STALLED) { - status=us->pusb_dev->status; - USB_STOR_PRINTF(" stall during command found, clear pipe\n"); - usb_clear_halt(us->pusb_dev, usb_sndctrlpipe(us->pusb_dev,0)); - us->pusb_dev->status=status; - } - USB_STOR_PRINTF(" error during command %02X Stat = %X\n",srb->cmd[0],us->pusb_dev->status); - return result; - } - /* transfer the data payload for this command, if one exists*/ - - USB_STOR_PRINTF("CB_transport: control msg returned %d, direction is %s to go 0x%lx\n",result,dir_in ? "IN" : "OUT",srb->datalen); - if (srb->datalen) { - result = us_one_transfer(us, pipe, (char *)srb->pdata,srb->datalen); - USB_STOR_PRINTF("CBI attempted to transfer data, result is %d status %lX, len %d\n", result,us->pusb_dev->status,us->pusb_dev->act_len); - if(!(us->pusb_dev->status & USB_ST_NAK_REC)) - break; - } /* if (srb->datalen) */ - else - break; - } - /* return result */ - - return result; + /* let's send the command via the control pipe */ + result = usb_control_msg(us->pusb_dev, usb_sndctrlpipe(us->pusb_dev,0), + US_CBI_ADSC, USB_TYPE_CLASS | USB_RECIP_INTERFACE, + 0, us->ifnum, + srb->cmd, srb->cmdlen, USB_CNTL_TIMEOUT*5); + USB_STOR_PRINTF("CB_transport: control msg returned %d, status %X\n",result,us->pusb_dev->status); + /* check the return code for the command */ + if (result < 0) { + if(us->pusb_dev->status & USB_ST_STALLED) { + status=us->pusb_dev->status; + USB_STOR_PRINTF(" stall during command found, clear pipe\n"); + usb_clear_halt(us->pusb_dev, usb_sndctrlpipe(us->pusb_dev,0)); + us->pusb_dev->status=status; + } + USB_STOR_PRINTF(" error during command %02X Stat = %X\n",srb->cmd[0],us->pusb_dev->status); + return result; + } + /* transfer the data payload for this command, if one exists*/ + + USB_STOR_PRINTF("CB_transport: control msg returned %d, direction is %s to go 0x%lx\n",result,dir_in ? "IN" : "OUT",srb->datalen); + if (srb->datalen) { + result = us_one_transfer(us, pipe, (char *)srb->pdata,srb->datalen); + USB_STOR_PRINTF("CBI attempted to transfer data, result is %d status %lX, len %d\n", result,us->pusb_dev->status,us->pusb_dev->act_len); + if(!(us->pusb_dev->status & USB_ST_NAK_REC)) + break; + } /* if (srb->datalen) */ + else + break; + } + /* return result */ + + return result; } int usb_stor_CBI_get_status (ccb * srb, struct us_data *us) { - int timeout; - - us->ip_wanted = 1; - submit_int_msg (us->pusb_dev, us->irqpipe, - (void *) &us->ip_data, us->irqmaxp, us->irqinterval); - timeout = 1000; - while (timeout--) { - if ((volatile int *) us->ip_wanted == 0) - break; - wait_ms (10); - } - if (us->ip_wanted) { - printf (" Did not get interrupt on CBI\n"); - us->ip_wanted = 0; - return USB_STOR_TRANSPORT_ERROR; - } - USB_STOR_PRINTF - ("Got interrupt data 0x%x, transfered %d status 0x%lX\n", - us->ip_data, us->pusb_dev->irq_act_len, - us->pusb_dev->irq_status); - /* UFI gives us ASC and ASCQ, like a request sense */ - if (us->subclass == US_SC_UFI) { - if (srb->cmd[0] == SCSI_REQ_SENSE || - srb->cmd[0] == SCSI_INQUIRY) - return USB_STOR_TRANSPORT_GOOD; /* Good */ - else if (us->ip_data) - return USB_STOR_TRANSPORT_FAILED; - else - return USB_STOR_TRANSPORT_GOOD; - } - /* otherwise, we interpret the data normally */ - switch (us->ip_data) { - case 0x0001: - return USB_STOR_TRANSPORT_GOOD; - case 0x0002: - return USB_STOR_TRANSPORT_FAILED; - default: - return USB_STOR_TRANSPORT_ERROR; - } /* switch */ - return USB_STOR_TRANSPORT_ERROR; + int timeout; + + us->ip_wanted = 1; + submit_int_msg (us->pusb_dev, us->irqpipe, + (void *) &us->ip_data, us->irqmaxp, us->irqinterval); + timeout = 1000; + while (timeout--) { + if ((volatile int *) us->ip_wanted == 0) + break; + wait_ms (10); + } + if (us->ip_wanted) { + printf (" Did not get interrupt on CBI\n"); + us->ip_wanted = 0; + return USB_STOR_TRANSPORT_ERROR; + } + USB_STOR_PRINTF + ("Got interrupt data 0x%x, transfered %d status 0x%lX\n", + us->ip_data, us->pusb_dev->irq_act_len, + us->pusb_dev->irq_status); + /* UFI gives us ASC and ASCQ, like a request sense */ + if (us->subclass == US_SC_UFI) { + if (srb->cmd[0] == SCSI_REQ_SENSE || + srb->cmd[0] == SCSI_INQUIRY) + return USB_STOR_TRANSPORT_GOOD; /* Good */ + else if (us->ip_data) + return USB_STOR_TRANSPORT_FAILED; + else + return USB_STOR_TRANSPORT_GOOD; + } + /* otherwise, we interpret the data normally */ + switch (us->ip_data) { + case 0x0001: + return USB_STOR_TRANSPORT_GOOD; + case 0x0002: + return USB_STOR_TRANSPORT_FAILED; + default: + return USB_STOR_TRANSPORT_ERROR; + } /* switch */ + return USB_STOR_TRANSPORT_ERROR; } #define USB_TRANSPORT_UNKNOWN_RETRY 5 @@ -596,327 +600,327 @@ int usb_stor_CBI_get_status (ccb * srb, struct us_data *us) /* clear a stall on an endpoint - special for BBB devices */ int usb_stor_BBB_clear_endpt_stall(struct us_data *us, __u8 endpt) { - int result; + int result; - /* ENDPOINT_HALT = 0, so set value to 0 */ - result = usb_control_msg(us->pusb_dev, usb_sndctrlpipe(us->pusb_dev,0), - USB_REQ_CLEAR_FEATURE, USB_RECIP_ENDPOINT, - 0, endpt, 0, 0, USB_CNTL_TIMEOUT*5); - return result; + /* ENDPOINT_HALT = 0, so set value to 0 */ + result = usb_control_msg(us->pusb_dev, usb_sndctrlpipe(us->pusb_dev,0), + USB_REQ_CLEAR_FEATURE, USB_RECIP_ENDPOINT, + 0, endpt, 0, 0, USB_CNTL_TIMEOUT*5); + return result; } int usb_stor_BBB_transport(ccb *srb, struct us_data *us) { - int result, retry; - int dir_in; - int actlen, data_actlen; - unsigned int pipe, pipein, pipeout; - umass_bbb_csw_t csw; + int result, retry; + int dir_in; + int actlen, data_actlen; + unsigned int pipe, pipein, pipeout; + umass_bbb_csw_t csw; #ifdef BBB_XPORT_TRACE - unsigned char *ptr; - int index; + unsigned char *ptr; + int index; #endif - dir_in = US_DIRECTION(srb->cmd[0]); - - /* COMMAND phase */ - USB_STOR_PRINTF("COMMAND phase\n"); - result = usb_stor_BBB_comdat(srb, us); - if (result < 0) { - USB_STOR_PRINTF("failed to send CBW status %ld\n", - us->pusb_dev->status); - usb_stor_BBB_reset(us); - return USB_STOR_TRANSPORT_FAILED; - } - wait_ms(5); - pipein = usb_rcvbulkpipe(us->pusb_dev, us->ep_in); - pipeout = usb_sndbulkpipe(us->pusb_dev, us->ep_out); - /* DATA phase + error handling */ - data_actlen = 0; - /* no data, go immediately to the STATUS phase */ - if (srb->datalen == 0) - goto st; - USB_STOR_PRINTF("DATA phase\n"); - if (dir_in) - pipe = pipein; - else - pipe = pipeout; - result = usb_bulk_msg(us->pusb_dev, pipe, srb->pdata, srb->datalen, &data_actlen, USB_CNTL_TIMEOUT*5); - /* special handling of STALL in DATA phase */ - if((result < 0) && (us->pusb_dev->status & USB_ST_STALLED)) { - USB_STOR_PRINTF("DATA:stall\n"); - /* clear the STALL on the endpoint */ - result = usb_stor_BBB_clear_endpt_stall(us, dir_in? us->ep_in : us->ep_out); - if (result >= 0) - /* continue on to STATUS phase */ - goto st; - } - if (result < 0) { - USB_STOR_PRINTF("usb_bulk_msg error status %ld\n", - us->pusb_dev->status); - usb_stor_BBB_reset(us); - return USB_STOR_TRANSPORT_FAILED; - } + dir_in = US_DIRECTION(srb->cmd[0]); + + /* COMMAND phase */ + USB_STOR_PRINTF("COMMAND phase\n"); + result = usb_stor_BBB_comdat(srb, us); + if (result < 0) { + USB_STOR_PRINTF("failed to send CBW status %ld\n", + us->pusb_dev->status); + usb_stor_BBB_reset(us); + return USB_STOR_TRANSPORT_FAILED; + } + wait_ms(5); + pipein = usb_rcvbulkpipe(us->pusb_dev, us->ep_in); + pipeout = usb_sndbulkpipe(us->pusb_dev, us->ep_out); + /* DATA phase + error handling */ + data_actlen = 0; + /* no data, go immediately to the STATUS phase */ + if (srb->datalen == 0) + goto st; + USB_STOR_PRINTF("DATA phase\n"); + if (dir_in) + pipe = pipein; + else + pipe = pipeout; + result = usb_bulk_msg(us->pusb_dev, pipe, srb->pdata, srb->datalen, &data_actlen, USB_CNTL_TIMEOUT*5); + /* special handling of STALL in DATA phase */ + if((result < 0) && (us->pusb_dev->status & USB_ST_STALLED)) { + USB_STOR_PRINTF("DATA:stall\n"); + /* clear the STALL on the endpoint */ + result = usb_stor_BBB_clear_endpt_stall(us, dir_in? us->ep_in : us->ep_out); + if (result >= 0) + /* continue on to STATUS phase */ + goto st; + } + if (result < 0) { + USB_STOR_PRINTF("usb_bulk_msg error status %ld\n", + us->pusb_dev->status); + usb_stor_BBB_reset(us); + return USB_STOR_TRANSPORT_FAILED; + } #ifdef BBB_XPORT_TRACE - for (index = 0; index < data_actlen; index++) - printf("pdata[%d] %#x ", index, srb->pdata[index]); - printf("\n"); + for (index = 0; index < data_actlen; index++) + printf("pdata[%d] %#x ", index, srb->pdata[index]); + printf("\n"); #endif - /* STATUS phase + error handling */ + /* STATUS phase + error handling */ st: - retry = 0; + retry = 0; again: - USB_STOR_PRINTF("STATUS phase\n"); - result = usb_bulk_msg(us->pusb_dev, pipein, &csw, UMASS_BBB_CSW_SIZE, - &actlen, USB_CNTL_TIMEOUT*5); - - /* special handling of STALL in STATUS phase */ - if((result < 0) && (retry < 1) && (us->pusb_dev->status & USB_ST_STALLED)) { - USB_STOR_PRINTF("STATUS:stall\n"); - /* clear the STALL on the endpoint */ - result = usb_stor_BBB_clear_endpt_stall(us, us->ep_in); - if (result >= 0 && (retry++ < 1)) - /* do a retry */ - goto again; - } - if (result < 0) { - USB_STOR_PRINTF("usb_bulk_msg error status %ld\n", - us->pusb_dev->status); - usb_stor_BBB_reset(us); - return USB_STOR_TRANSPORT_FAILED; - } + USB_STOR_PRINTF("STATUS phase\n"); + result = usb_bulk_msg(us->pusb_dev, pipein, &csw, UMASS_BBB_CSW_SIZE, + &actlen, USB_CNTL_TIMEOUT*5); + + /* special handling of STALL in STATUS phase */ + if((result < 0) && (retry < 1) && (us->pusb_dev->status & USB_ST_STALLED)) { + USB_STOR_PRINTF("STATUS:stall\n"); + /* clear the STALL on the endpoint */ + result = usb_stor_BBB_clear_endpt_stall(us, us->ep_in); + if (result >= 0 && (retry++ < 1)) + /* do a retry */ + goto again; + } + if (result < 0) { + USB_STOR_PRINTF("usb_bulk_msg error status %ld\n", + us->pusb_dev->status); + usb_stor_BBB_reset(us); + return USB_STOR_TRANSPORT_FAILED; + } #ifdef BBB_XPORT_TRACE - ptr = (unsigned char *)&csw; - for (index = 0; index < UMASS_BBB_CSW_SIZE; index++) - printf("ptr[%d] %#x ", index, ptr[index]); - printf("\n"); + ptr = (unsigned char *)&csw; + for (index = 0; index < UMASS_BBB_CSW_SIZE; index++) + printf("ptr[%d] %#x ", index, ptr[index]); + printf("\n"); #endif - /* misuse pipe to get the residue */ - pipe = swap_32(csw.dCSWDataResidue); - if (pipe == 0 && srb->datalen != 0 && srb->datalen - data_actlen != 0) - pipe = srb->datalen - data_actlen; - if (CSWSIGNATURE != swap_32(csw.dCSWSignature)) { - USB_STOR_PRINTF("!CSWSIGNATURE\n"); - usb_stor_BBB_reset(us); - return USB_STOR_TRANSPORT_FAILED; - } else if ((CBWTag - 1) != swap_32(csw.dCSWTag)) { - USB_STOR_PRINTF("!Tag\n"); - usb_stor_BBB_reset(us); - return USB_STOR_TRANSPORT_FAILED; - } else if (csw.bCSWStatus > CSWSTATUS_PHASE) { - USB_STOR_PRINTF(">PHASE\n"); - usb_stor_BBB_reset(us); - return USB_STOR_TRANSPORT_FAILED; - } else if (csw.bCSWStatus == CSWSTATUS_PHASE) { - USB_STOR_PRINTF("=PHASE\n"); - usb_stor_BBB_reset(us); - return USB_STOR_TRANSPORT_FAILED; - } else if (data_actlen > srb->datalen) { - USB_STOR_PRINTF("transferred %dB instead of %dB\n", - data_actlen, srb->datalen); - return USB_STOR_TRANSPORT_FAILED; - } else if (csw.bCSWStatus == CSWSTATUS_FAILED) { - USB_STOR_PRINTF("FAILED\n"); - return USB_STOR_TRANSPORT_FAILED; - } - - return result; + /* misuse pipe to get the residue */ + pipe = swap_32(csw.dCSWDataResidue); + if (pipe == 0 && srb->datalen != 0 && srb->datalen - data_actlen != 0) + pipe = srb->datalen - data_actlen; + if (CSWSIGNATURE != swap_32(csw.dCSWSignature)) { + USB_STOR_PRINTF("!CSWSIGNATURE\n"); + usb_stor_BBB_reset(us); + return USB_STOR_TRANSPORT_FAILED; + } else if ((CBWTag - 1) != swap_32(csw.dCSWTag)) { + USB_STOR_PRINTF("!Tag\n"); + usb_stor_BBB_reset(us); + return USB_STOR_TRANSPORT_FAILED; + } else if (csw.bCSWStatus > CSWSTATUS_PHASE) { + USB_STOR_PRINTF(">PHASE\n"); + usb_stor_BBB_reset(us); + return USB_STOR_TRANSPORT_FAILED; + } else if (csw.bCSWStatus == CSWSTATUS_PHASE) { + USB_STOR_PRINTF("=PHASE\n"); + usb_stor_BBB_reset(us); + return USB_STOR_TRANSPORT_FAILED; + } else if (data_actlen > srb->datalen) { + USB_STOR_PRINTF("transferred %dB instead of %dB\n", + data_actlen, srb->datalen); + return USB_STOR_TRANSPORT_FAILED; + } else if (csw.bCSWStatus == CSWSTATUS_FAILED) { + USB_STOR_PRINTF("FAILED\n"); + return USB_STOR_TRANSPORT_FAILED; + } + + return result; } int usb_stor_CB_transport(ccb *srb, struct us_data *us) { - int result,status; - ccb *psrb; - ccb reqsrb; - int retry,notready; - - psrb=&reqsrb; - status=USB_STOR_TRANSPORT_GOOD; - retry=0; - notready=0; - /* issue the command */ + int result,status; + ccb *psrb; + ccb reqsrb; + int retry,notready; + + psrb=&reqsrb; + status=USB_STOR_TRANSPORT_GOOD; + retry=0; + notready=0; + /* issue the command */ do_retry: - result=usb_stor_CB_comdat(srb,us); - USB_STOR_PRINTF("command / Data returned %d, status %X\n",result,us->pusb_dev->status); - /* if this is an CBI Protocol, get IRQ */ - if(us->protocol==US_PR_CBI) { - status=usb_stor_CBI_get_status(srb,us); - /* if the status is error, report it */ - if(status==USB_STOR_TRANSPORT_ERROR) { - USB_STOR_PRINTF(" USB CBI Command Error\n"); - return status; - } - srb->sense_buf[12]=(unsigned char)(us->ip_data>>8); - srb->sense_buf[13]=(unsigned char)(us->ip_data&0xff); - if(!us->ip_data) { - /* if the status is good, report it */ - if(status==USB_STOR_TRANSPORT_GOOD) { - USB_STOR_PRINTF(" USB CBI Command Good\n"); - return status; - } - } - } - /* do we have to issue an auto request? */ - /* HERE we have to check the result */ - if((result<0) && !(us->pusb_dev->status & USB_ST_STALLED)) { - USB_STOR_PRINTF("ERROR %X\n",us->pusb_dev->status); - us->transport_reset(us); - return USB_STOR_TRANSPORT_ERROR; - } - if((us->protocol==US_PR_CBI) && - ((srb->cmd[0]==SCSI_REQ_SENSE) || - (srb->cmd[0]==SCSI_INQUIRY))) { /* do not issue an autorequest after request sense */ - USB_STOR_PRINTF("No auto request and good\n"); - return USB_STOR_TRANSPORT_GOOD; - } - /* issue an request_sense */ - memset(&psrb->cmd[0],0,12); - psrb->cmd[0]=SCSI_REQ_SENSE; - psrb->cmd[1]=srb->lun<<5; - psrb->cmd[4]=18; - psrb->datalen=18; - psrb->pdata=&srb->sense_buf[0]; - psrb->cmdlen=12; - /* issue the command */ - result=usb_stor_CB_comdat(psrb,us); - USB_STOR_PRINTF("auto request returned %d\n",result); - /* if this is an CBI Protocol, get IRQ */ - if(us->protocol==US_PR_CBI) { - status=usb_stor_CBI_get_status(psrb,us); - } - if((result<0)&&!(us->pusb_dev->status & USB_ST_STALLED)) { - USB_STOR_PRINTF(" AUTO REQUEST ERROR %d\n",us->pusb_dev->status); - return USB_STOR_TRANSPORT_ERROR; - } - USB_STOR_PRINTF("autorequest returned 0x%02X 0x%02X 0x%02X 0x%02X\n",srb->sense_buf[0],srb->sense_buf[2],srb->sense_buf[12],srb->sense_buf[13]); - /* Check the auto request result */ - if((srb->sense_buf[2]==0) && - (srb->sense_buf[12]==0) && - (srb->sense_buf[13]==0)) /* ok, no sense */ - return USB_STOR_TRANSPORT_GOOD; - /* Check the auto request result */ - switch(srb->sense_buf[2]) { - case 0x01: /* Recovered Error */ - return USB_STOR_TRANSPORT_GOOD; - break; - case 0x02: /* Not Ready */ - if(notready++ > USB_TRANSPORT_NOT_READY_RETRY) { - printf("cmd 0x%02X returned 0x%02X 0x%02X 0x%02X 0x%02X (NOT READY)\n", - srb->cmd[0],srb->sense_buf[0],srb->sense_buf[2],srb->sense_buf[12],srb->sense_buf[13]); - return USB_STOR_TRANSPORT_FAILED; - } else { - wait_ms(100); - goto do_retry; - } - break; - default: - if(retry++ > USB_TRANSPORT_UNKNOWN_RETRY) { - printf("cmd 0x%02X returned 0x%02X 0x%02X 0x%02X 0x%02X\n", - srb->cmd[0],srb->sense_buf[0],srb->sense_buf[2],srb->sense_buf[12],srb->sense_buf[13]); - return USB_STOR_TRANSPORT_FAILED; - } else { - goto do_retry; - } - break; - } - return USB_STOR_TRANSPORT_FAILED; + result=usb_stor_CB_comdat(srb,us); + USB_STOR_PRINTF("command / Data returned %d, status %X\n",result,us->pusb_dev->status); + /* if this is an CBI Protocol, get IRQ */ + if(us->protocol==US_PR_CBI) { + status=usb_stor_CBI_get_status(srb,us); + /* if the status is error, report it */ + if(status==USB_STOR_TRANSPORT_ERROR) { + USB_STOR_PRINTF(" USB CBI Command Error\n"); + return status; + } + srb->sense_buf[12]=(unsigned char)(us->ip_data>>8); + srb->sense_buf[13]=(unsigned char)(us->ip_data&0xff); + if(!us->ip_data) { + /* if the status is good, report it */ + if(status==USB_STOR_TRANSPORT_GOOD) { + USB_STOR_PRINTF(" USB CBI Command Good\n"); + return status; + } + } + } + /* do we have to issue an auto request? */ + /* HERE we have to check the result */ + if((result<0) && !(us->pusb_dev->status & USB_ST_STALLED)) { + USB_STOR_PRINTF("ERROR %X\n",us->pusb_dev->status); + us->transport_reset(us); + return USB_STOR_TRANSPORT_ERROR; + } + if((us->protocol==US_PR_CBI) && + ((srb->cmd[0]==SCSI_REQ_SENSE) || + (srb->cmd[0]==SCSI_INQUIRY))) { /* do not issue an autorequest after request sense */ + USB_STOR_PRINTF("No auto request and good\n"); + return USB_STOR_TRANSPORT_GOOD; + } + /* issue an request_sense */ + memset(&psrb->cmd[0],0,12); + psrb->cmd[0]=SCSI_REQ_SENSE; + psrb->cmd[1]=srb->lun<<5; + psrb->cmd[4]=18; + psrb->datalen=18; + psrb->pdata=&srb->sense_buf[0]; + psrb->cmdlen=12; + /* issue the command */ + result=usb_stor_CB_comdat(psrb,us); + USB_STOR_PRINTF("auto request returned %d\n",result); + /* if this is an CBI Protocol, get IRQ */ + if(us->protocol==US_PR_CBI) { + status=usb_stor_CBI_get_status(psrb,us); + } + if((result<0)&&!(us->pusb_dev->status & USB_ST_STALLED)) { + USB_STOR_PRINTF(" AUTO REQUEST ERROR %d\n",us->pusb_dev->status); + return USB_STOR_TRANSPORT_ERROR; + } + USB_STOR_PRINTF("autorequest returned 0x%02X 0x%02X 0x%02X 0x%02X\n",srb->sense_buf[0],srb->sense_buf[2],srb->sense_buf[12],srb->sense_buf[13]); + /* Check the auto request result */ + if((srb->sense_buf[2]==0) && + (srb->sense_buf[12]==0) && + (srb->sense_buf[13]==0)) /* ok, no sense */ + return USB_STOR_TRANSPORT_GOOD; + /* Check the auto request result */ + switch(srb->sense_buf[2]) { + case 0x01: /* Recovered Error */ + return USB_STOR_TRANSPORT_GOOD; + break; + case 0x02: /* Not Ready */ + if(notready++ > USB_TRANSPORT_NOT_READY_RETRY) { + printf("cmd 0x%02X returned 0x%02X 0x%02X 0x%02X 0x%02X (NOT READY)\n", + srb->cmd[0],srb->sense_buf[0],srb->sense_buf[2],srb->sense_buf[12],srb->sense_buf[13]); + return USB_STOR_TRANSPORT_FAILED; + } else { + wait_ms(100); + goto do_retry; + } + break; + default: + if(retry++ > USB_TRANSPORT_UNKNOWN_RETRY) { + printf("cmd 0x%02X returned 0x%02X 0x%02X 0x%02X 0x%02X\n", + srb->cmd[0],srb->sense_buf[0],srb->sense_buf[2],srb->sense_buf[12],srb->sense_buf[13]); + return USB_STOR_TRANSPORT_FAILED; + } else { + goto do_retry; + } + break; + } + return USB_STOR_TRANSPORT_FAILED; } static int usb_inquiry(ccb *srb,struct us_data *ss) { - int retry,i; - retry=5; - do { - memset(&srb->cmd[0],0,12); - srb->cmd[0]=SCSI_INQUIRY; - srb->cmd[1]=srb->lun<<5; - srb->cmd[4]=36; - srb->datalen=36; - srb->cmdlen=12; - i=ss->transport(srb,ss); - USB_STOR_PRINTF("inquiry returns %d\n",i); - if(i==0) - break; - } while(retry--); - - if(!retry) { - printf("error in inquiry\n"); - return -1; - } - return 0; + int retry,i; + retry=5; + do { + memset(&srb->cmd[0],0,12); + srb->cmd[0]=SCSI_INQUIRY; + srb->cmd[1]=srb->lun<<5; + srb->cmd[4]=36; + srb->datalen=36; + srb->cmdlen=12; + i=ss->transport(srb,ss); + USB_STOR_PRINTF("inquiry returns %d\n",i); + if(i==0) + break; + } while(retry--); + + if(!retry) { + printf("error in inquiry\n"); + return -1; + } + return 0; } static int usb_request_sense(ccb *srb,struct us_data *ss) { - char *ptr; - - ptr=(char *)srb->pdata; - memset(&srb->cmd[0],0,12); - srb->cmd[0]=SCSI_REQ_SENSE; - srb->cmd[1]=srb->lun<<5; - srb->cmd[4]=18; - srb->datalen=18; - srb->pdata=&srb->sense_buf[0]; - srb->cmdlen=12; - ss->transport(srb,ss); - USB_STOR_PRINTF("Request Sense returned %02X %02X %02X\n",srb->sense_buf[2],srb->sense_buf[12],srb->sense_buf[13]); - srb->pdata=(uchar *)ptr; - return 0; + char *ptr; + + ptr=(char *)srb->pdata; + memset(&srb->cmd[0],0,12); + srb->cmd[0]=SCSI_REQ_SENSE; + srb->cmd[1]=srb->lun<<5; + srb->cmd[4]=18; + srb->datalen=18; + srb->pdata=&srb->sense_buf[0]; + srb->cmdlen=12; + ss->transport(srb,ss); + USB_STOR_PRINTF("Request Sense returned %02X %02X %02X\n",srb->sense_buf[2],srb->sense_buf[12],srb->sense_buf[13]); + srb->pdata=(uchar *)ptr; + return 0; } static int usb_test_unit_ready(ccb *srb,struct us_data *ss) { - int retries = 10; - - do { - memset(&srb->cmd[0],0,12); - srb->cmd[0]=SCSI_TST_U_RDY; - srb->cmd[1]=srb->lun<<5; - srb->datalen=0; - srb->cmdlen=12; - if(ss->transport(srb,ss)==USB_STOR_TRANSPORT_GOOD) { - return 0; - } - usb_request_sense (srb, ss); - wait_ms (100); - } while(retries--); - - return -1; + int retries = 10; + + do { + memset(&srb->cmd[0],0,12); + srb->cmd[0]=SCSI_TST_U_RDY; + srb->cmd[1]=srb->lun<<5; + srb->datalen=0; + srb->cmdlen=12; + if(ss->transport(srb,ss)==USB_STOR_TRANSPORT_GOOD) { + return 0; + } + usb_request_sense (srb, ss); + wait_ms (100); + } while(retries--); + + return -1; } static int usb_read_capacity(ccb *srb,struct us_data *ss) { - int retry; - retry = 3; /* retries */ - do { - memset(&srb->cmd[0],0,12); - srb->cmd[0]=SCSI_RD_CAPAC; - srb->cmd[1]=srb->lun<<5; - srb->datalen=8; - srb->cmdlen=12; - if(ss->transport(srb,ss)==USB_STOR_TRANSPORT_GOOD) { - return 0; - } - } while(retry--); - - return -1; + int retry; + retry = 3; /* retries */ + do { + memset(&srb->cmd[0],0,12); + srb->cmd[0]=SCSI_RD_CAPAC; + srb->cmd[1]=srb->lun<<5; + srb->datalen=8; + srb->cmdlen=12; + if(ss->transport(srb,ss)==USB_STOR_TRANSPORT_GOOD) { + return 0; + } + } while(retry--); + + return -1; } static int usb_read_10(ccb *srb,struct us_data *ss, unsigned long start, unsigned short blocks) { - memset(&srb->cmd[0],0,12); - srb->cmd[0]=SCSI_READ10; - srb->cmd[1]=srb->lun<<5; - srb->cmd[2]=((unsigned char) (start>>24))&0xff; - srb->cmd[3]=((unsigned char) (start>>16))&0xff; - srb->cmd[4]=((unsigned char) (start>>8))&0xff; - srb->cmd[5]=((unsigned char) (start))&0xff; - srb->cmd[7]=((unsigned char) (blocks>>8))&0xff; - srb->cmd[8]=(unsigned char) blocks & 0xff; - srb->cmdlen=12; - USB_STOR_PRINTF("read10: start %lx blocks %x\n",start,blocks); - return ss->transport(srb,ss); + memset(&srb->cmd[0],0,12); + srb->cmd[0]=SCSI_READ10; + srb->cmd[1]=srb->lun<<5; + srb->cmd[2]=((unsigned char) (start>>24))&0xff; + srb->cmd[3]=((unsigned char) (start>>16))&0xff; + srb->cmd[4]=((unsigned char) (start>>8))&0xff; + srb->cmd[5]=((unsigned char) (start))&0xff; + srb->cmd[7]=((unsigned char) (blocks>>8))&0xff; + srb->cmd[8]=(unsigned char) blocks & 0xff; + srb->cmdlen=12; + USB_STOR_PRINTF("read10: start %lx blocks %x\n",start,blocks); + return ss->transport(srb,ss); } @@ -931,14 +935,14 @@ static int usb_read_10(ccb *srb,struct us_data *ss, unsigned long start, unsigne * block_dev_desc_t in include/part.h. */ static void usb_bin_fixup(struct usb_device_descriptor descriptor, - unsigned char vendor[], - unsigned char product[]) { - const unsigned char max_vendor_len = 40; - const unsigned char max_product_len = 20; - if (descriptor.idVendor == 0x0424 && descriptor.idProduct == 0x223a) { - strncpy ((char *)vendor, "SMSC", max_vendor_len); - strncpy ((char *)product, "Flash Media Cntrller", max_product_len); - } + unsigned char vendor[], + unsigned char product[]) { + const unsigned char max_vendor_len = 40; + const unsigned char max_product_len = 20; + if (descriptor.idVendor == 0x0424 && descriptor.idProduct == 0x223a) { + strncpy ((char *)vendor, "SMSC", max_vendor_len); + strncpy ((char *)product, "Flash Media Cntrller", max_product_len); + } } #endif /* CONFIG_USB_BIN_FIXUP */ @@ -946,309 +950,309 @@ static void usb_bin_fixup(struct usb_device_descriptor descriptor, unsigned long usb_stor_read(int device, unsigned long blknr, unsigned long blkcnt, void *buffer) { - unsigned long start,blks, buf_addr; - unsigned short smallblks; - struct usb_device *dev; - int retry,i; - ccb *srb = &usb_ccb; - - if (blkcnt == 0) - return 0; - - device &= 0xff; - /* Setup device - */ - USB_STOR_PRINTF("\nusb_read: dev %d \n",device); - dev=NULL; - for(i=0;i<USB_MAX_DEVICE;i++) { - dev=usb_get_dev_index(i); - if(dev==NULL) { - return 0; - } - if(dev->devnum==usb_dev_desc[device].target) - break; - } - - usb_disable_asynch(1); /* asynch transfer not allowed */ - srb->lun=usb_dev_desc[device].lun; - buf_addr=(unsigned long)buffer; - start=blknr; - blks=blkcnt; - if(usb_test_unit_ready(srb,(struct us_data *)dev->privptr)) { - printf("Device NOT ready\n Request Sense returned %02X %02X %02X\n", - srb->sense_buf[2],srb->sense_buf[12],srb->sense_buf[13]); - return 0; - } - USB_STOR_PRINTF("\nusb_read: dev %d startblk %lx, blccnt %lx buffer %lx\n",device,start,blks, buf_addr); - do { - retry=2; - srb->pdata=(unsigned char *)buf_addr; - if(blks>USB_MAX_READ_BLK) { - smallblks=USB_MAX_READ_BLK; - } else { - smallblks=(unsigned short) blks; - } + unsigned long start,blks, buf_addr; + unsigned short smallblks; + struct usb_device *dev; + int retry,i; + ccb *srb = &usb_ccb; + + if (blkcnt == 0) + return 0; + + device &= 0xff; + /* Setup device + */ + USB_STOR_PRINTF("\nusb_read: dev %d \n",device); + dev=NULL; + for(i=0;i<USB_MAX_DEVICE;i++) { + dev=usb_get_dev_index(i); + if(dev==NULL) { + return 0; + } + if(dev->devnum==usb_dev_desc[device].target) + break; + } + + usb_disable_asynch(1); /* asynch transfer not allowed */ + srb->lun=usb_dev_desc[device].lun; + buf_addr=(unsigned long)buffer; + start=blknr; + blks=blkcnt; + if(usb_test_unit_ready(srb,(struct us_data *)dev->privptr)) { + printf("Device NOT ready\n Request Sense returned %02X %02X %02X\n", + srb->sense_buf[2],srb->sense_buf[12],srb->sense_buf[13]); + return 0; + } + USB_STOR_PRINTF("\nusb_read: dev %d startblk %lx, blccnt %lx buffer %lx\n",device,start,blks, buf_addr); + do { + retry=2; + srb->pdata=(unsigned char *)buf_addr; + if(blks>USB_MAX_READ_BLK) { + smallblks=USB_MAX_READ_BLK; + } else { + smallblks=(unsigned short) blks; + } retry_it: - if(smallblks==USB_MAX_READ_BLK) - usb_show_progress(); - srb->datalen=usb_dev_desc[device].blksz * smallblks; - srb->pdata=(unsigned char *)buf_addr; - if(usb_read_10(srb,(struct us_data *)dev->privptr, start, smallblks)) { - USB_STOR_PRINTF("Read ERROR\n"); - usb_request_sense(srb,(struct us_data *)dev->privptr); - if(retry--) - goto retry_it; - blkcnt-=blks; - break; - } - start+=smallblks; - blks-=smallblks; - buf_addr+=srb->datalen; - } while(blks!=0); - USB_STOR_PRINTF("usb_read: end startblk %lx, blccnt %x buffer %lx\n",start,smallblks,buf_addr); - usb_disable_asynch(0); /* asynch transfer allowed */ - if(blkcnt>=USB_MAX_READ_BLK) - printf("\n"); - return(blkcnt); + if(smallblks==USB_MAX_READ_BLK) + usb_show_progress(); + srb->datalen=usb_dev_desc[device].blksz * smallblks; + srb->pdata=(unsigned char *)buf_addr; + if(usb_read_10(srb,(struct us_data *)dev->privptr, start, smallblks)) { + USB_STOR_PRINTF("Read ERROR\n"); + usb_request_sense(srb,(struct us_data *)dev->privptr); + if(retry--) + goto retry_it; + blkcnt-=blks; + break; + } + start+=smallblks; + blks-=smallblks; + buf_addr+=srb->datalen; + } while(blks!=0); + USB_STOR_PRINTF("usb_read: end startblk %lx, blccnt %x buffer %lx\n",start,smallblks,buf_addr); + usb_disable_asynch(0); /* asynch transfer allowed */ + if(blkcnt>=USB_MAX_READ_BLK) + printf("\n"); + return(blkcnt); } /* Probe to see if a new device is actually a Storage device */ int usb_storage_probe(struct usb_device *dev, unsigned int ifnum,struct us_data *ss) { - struct usb_interface_descriptor *iface; - int i; - unsigned int flags = 0; + struct usb_interface_descriptor *iface; + int i; + unsigned int flags = 0; - int protocol = 0; - int subclass = 0; + int protocol = 0; + int subclass = 0; - /* let's examine the device now */ - iface = &dev->config.if_desc[ifnum]; + /* let's examine the device now */ + iface = &dev->config.if_desc[ifnum]; #if 0 - /* this is the place to patch some storage devices */ - USB_STOR_PRINTF("iVendor %X iProduct %X\n",dev->descriptor.idVendor,dev->descriptor.idProduct); - if ((dev->descriptor.idVendor) == 0x066b && (dev->descriptor.idProduct) == 0x0103) { - USB_STOR_PRINTF("patched for E-USB\n"); - protocol = US_PR_CB; - subclass = US_SC_UFI; /* an assumption */ - } + /* this is the place to patch some storage devices */ + USB_STOR_PRINTF("iVendor %X iProduct %X\n",dev->descriptor.idVendor,dev->descriptor.idProduct); + if ((dev->descriptor.idVendor) == 0x066b && (dev->descriptor.idProduct) == 0x0103) { + USB_STOR_PRINTF("patched for E-USB\n"); + protocol = US_PR_CB; + subclass = US_SC_UFI; /* an assumption */ + } #endif - if (dev->descriptor.bDeviceClass != 0 || - iface->bInterfaceClass != USB_CLASS_MASS_STORAGE || - iface->bInterfaceSubClass < US_SC_MIN || - iface->bInterfaceSubClass > US_SC_MAX) { - /* if it's not a mass storage, we go no further */ - return 0; - } - - memset(ss, 0, sizeof(struct us_data)); - - /* At this point, we know we've got a live one */ - USB_STOR_PRINTF("\n\nUSB Mass Storage device detected\n"); - - /* Initialize the us_data structure with some useful info */ - ss->flags = flags; - ss->ifnum = ifnum; - ss->pusb_dev = dev; - ss->attention_done = 0; - - /* If the device has subclass and protocol, then use that. Otherwise, - * take data from the specific interface. - */ - if (subclass) { - ss->subclass = subclass; - ss->protocol = protocol; - } else { - ss->subclass = iface->bInterfaceSubClass; - ss->protocol = iface->bInterfaceProtocol; - } - - /* set the handler pointers based on the protocol */ - USB_STOR_PRINTF("Transport: "); - switch (ss->protocol) { - case US_PR_CB: - USB_STOR_PRINTF("Control/Bulk\n"); - ss->transport = usb_stor_CB_transport; - ss->transport_reset = usb_stor_CB_reset; - break; - - case US_PR_CBI: - USB_STOR_PRINTF("Control/Bulk/Interrupt\n"); - ss->transport = usb_stor_CB_transport; - ss->transport_reset = usb_stor_CB_reset; - break; - case US_PR_BULK: - USB_STOR_PRINTF("Bulk/Bulk/Bulk\n"); - ss->transport = usb_stor_BBB_transport; - ss->transport_reset = usb_stor_BBB_reset; - break; - default: - printf("USB Storage Transport unknown / not yet implemented\n"); - return 0; - break; - } - - /* - * We are expecting a minimum of 2 endpoints - in and out (bulk). - * An optional interrupt is OK (necessary for CBI protocol). - * We will ignore any others. - */ - for (i = 0; i < iface->bNumEndpoints; i++) { - /* is it an BULK endpoint? */ - if ((iface->ep_desc[i].bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) - == USB_ENDPOINT_XFER_BULK) { - if (iface->ep_desc[i].bEndpointAddress & USB_DIR_IN) - ss->ep_in = iface->ep_desc[i].bEndpointAddress & - USB_ENDPOINT_NUMBER_MASK; - else - ss->ep_out = iface->ep_desc[i].bEndpointAddress & - USB_ENDPOINT_NUMBER_MASK; - } - - /* is it an interrupt endpoint? */ - if ((iface->ep_desc[i].bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) - == USB_ENDPOINT_XFER_INT) { - ss->ep_int = iface->ep_desc[i].bEndpointAddress & - USB_ENDPOINT_NUMBER_MASK; - ss->irqinterval = iface->ep_desc[i].bInterval; - } - } - USB_STOR_PRINTF("Endpoints In %d Out %d Int %d\n", - ss->ep_in, ss->ep_out, ss->ep_int); - - /* Do some basic sanity checks, and bail if we find a problem */ - if (usb_set_interface(dev, iface->bInterfaceNumber, 0) || - !ss->ep_in || !ss->ep_out || - (ss->protocol == US_PR_CBI && ss->ep_int == 0)) { - USB_STOR_PRINTF("Problems with device\n"); - return 0; - } - /* set class specific stuff */ - /* We only handle certain protocols. Currently, these are - * the only ones. - * The SFF8070 accepts the requests used in u-boot - */ - if (ss->subclass != US_SC_UFI && ss->subclass != US_SC_SCSI && - ss->subclass != US_SC_8070) { - printf("Sorry, protocol %d not yet supported.\n",ss->subclass); - return 0; - } - if(ss->ep_int) { /* we had found an interrupt endpoint, prepare irq pipe */ - /* set up the IRQ pipe and handler */ - - ss->irqinterval = (ss->irqinterval > 0) ? ss->irqinterval : 255; - ss->irqpipe = usb_rcvintpipe(ss->pusb_dev, ss->ep_int); - ss->irqmaxp = usb_maxpacket(dev, ss->irqpipe); - dev->irq_handle=usb_stor_irq; - } - dev->privptr=(void *)ss; - return 1; + if (dev->descriptor.bDeviceClass != 0 || + iface->bInterfaceClass != USB_CLASS_MASS_STORAGE || + iface->bInterfaceSubClass < US_SC_MIN || + iface->bInterfaceSubClass > US_SC_MAX) { + /* if it's not a mass storage, we go no further */ + return 0; + } + + memset(ss, 0, sizeof(struct us_data)); + + /* At this point, we know we've got a live one */ + USB_STOR_PRINTF("\n\nUSB Mass Storage device detected\n"); + + /* Initialize the us_data structure with some useful info */ + ss->flags = flags; + ss->ifnum = ifnum; + ss->pusb_dev = dev; + ss->attention_done = 0; + + /* If the device has subclass and protocol, then use that. Otherwise, + * take data from the specific interface. + */ + if (subclass) { + ss->subclass = subclass; + ss->protocol = protocol; + } else { + ss->subclass = iface->bInterfaceSubClass; + ss->protocol = iface->bInterfaceProtocol; + } + + /* set the handler pointers based on the protocol */ + USB_STOR_PRINTF("Transport: "); + switch (ss->protocol) { + case US_PR_CB: + USB_STOR_PRINTF("Control/Bulk\n"); + ss->transport = usb_stor_CB_transport; + ss->transport_reset = usb_stor_CB_reset; + break; + + case US_PR_CBI: + USB_STOR_PRINTF("Control/Bulk/Interrupt\n"); + ss->transport = usb_stor_CB_transport; + ss->transport_reset = usb_stor_CB_reset; + break; + case US_PR_BULK: + USB_STOR_PRINTF("Bulk/Bulk/Bulk\n"); + ss->transport = usb_stor_BBB_transport; + ss->transport_reset = usb_stor_BBB_reset; + break; + default: + printf("USB Storage Transport unknown / not yet implemented\n"); + return 0; + break; + } + + /* + * We are expecting a minimum of 2 endpoints - in and out (bulk). + * An optional interrupt is OK (necessary for CBI protocol). + * We will ignore any others. + */ + for (i = 0; i < iface->bNumEndpoints; i++) { + /* is it an BULK endpoint? */ + if ((iface->ep_desc[i].bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) + == USB_ENDPOINT_XFER_BULK) { + if (iface->ep_desc[i].bEndpointAddress & USB_DIR_IN) + ss->ep_in = iface->ep_desc[i].bEndpointAddress & + USB_ENDPOINT_NUMBER_MASK; + else + ss->ep_out = iface->ep_desc[i].bEndpointAddress & + USB_ENDPOINT_NUMBER_MASK; + } + + /* is it an interrupt endpoint? */ + if ((iface->ep_desc[i].bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) + == USB_ENDPOINT_XFER_INT) { + ss->ep_int = iface->ep_desc[i].bEndpointAddress & + USB_ENDPOINT_NUMBER_MASK; + ss->irqinterval = iface->ep_desc[i].bInterval; + } + } + USB_STOR_PRINTF("Endpoints In %d Out %d Int %d\n", + ss->ep_in, ss->ep_out, ss->ep_int); + + /* Do some basic sanity checks, and bail if we find a problem */ + if (usb_set_interface(dev, iface->bInterfaceNumber, 0) || + !ss->ep_in || !ss->ep_out || + (ss->protocol == US_PR_CBI && ss->ep_int == 0)) { + USB_STOR_PRINTF("Problems with device\n"); + return 0; + } + /* set class specific stuff */ + /* We only handle certain protocols. Currently, these are + * the only ones. + * The SFF8070 accepts the requests used in u-boot + */ + if (ss->subclass != US_SC_UFI && ss->subclass != US_SC_SCSI && + ss->subclass != US_SC_8070) { + printf("Sorry, protocol %d not yet supported.\n",ss->subclass); + return 0; + } + if(ss->ep_int) { /* we had found an interrupt endpoint, prepare irq pipe */ + /* set up the IRQ pipe and handler */ + + ss->irqinterval = (ss->irqinterval > 0) ? ss->irqinterval : 255; + ss->irqpipe = usb_rcvintpipe(ss->pusb_dev, ss->ep_int); + ss->irqmaxp = usb_maxpacket(dev, ss->irqpipe); + dev->irq_handle=usb_stor_irq; + } + dev->privptr=(void *)ss; + return 1; } int usb_stor_get_info(struct usb_device *dev,struct us_data *ss,block_dev_desc_t *dev_desc) { - unsigned char perq,modi; - unsigned long cap[2]; - unsigned long *capacity,*blksz; - ccb *pccb = &usb_ccb; - - /* for some reasons a couple of devices would not survive this reset */ - if ( - /* Sony USM256E */ - (dev->descriptor.idVendor == 0x054c && - dev->descriptor.idProduct == 0x019e) - - || - /* USB007 Mini-USB2 Flash Drive */ - (dev->descriptor.idVendor == 0x066f && - dev->descriptor.idProduct == 0x2010) - || - /* SanDisk Corporation Cruzer Micro 20044318410546613953 */ - (dev->descriptor.idVendor == 0x0781 && - dev->descriptor.idProduct == 0x5151) - ) - USB_STOR_PRINTF("usb_stor_get_info: skipping RESET..\n"); - else - ss->transport_reset(ss); - - pccb->pdata = usb_stor_buf; - - dev_desc->target = dev->devnum; - pccb->lun = dev_desc->lun; - USB_STOR_PRINTF(" address %d\n",dev_desc->target); - - if(usb_inquiry(pccb,ss)) - return -1; - - perq = usb_stor_buf[0]; - modi = usb_stor_buf[1]; - if((perq & 0x1f) == 0x1f) { - return 0; /* skip unknown devices */ - } - if((modi&0x80) == 0x80) {/* drive is removable */ - dev_desc->removable = 1; - } - memcpy(&dev_desc->vendor[0], &usb_stor_buf[8], 8); - memcpy(&dev_desc->product[0], &usb_stor_buf[16], 16); - memcpy(&dev_desc->revision[0], &usb_stor_buf[32], 4); - dev_desc->vendor[8] = 0; - dev_desc->product[16] = 0; - dev_desc->revision[4] = 0; + unsigned char perq,modi; + unsigned long cap[2]; + unsigned long *capacity,*blksz; + ccb *pccb = &usb_ccb; + + /* for some reasons a couple of devices would not survive this reset */ + if ( + /* Sony USM256E */ + (dev->descriptor.idVendor == 0x054c && + dev->descriptor.idProduct == 0x019e) + + || + /* USB007 Mini-USB2 Flash Drive */ + (dev->descriptor.idVendor == 0x066f && + dev->descriptor.idProduct == 0x2010) + || + /* SanDisk Corporation Cruzer Micro 20044318410546613953 */ + (dev->descriptor.idVendor == 0x0781 && + dev->descriptor.idProduct == 0x5151) + ) + USB_STOR_PRINTF("usb_stor_get_info: skipping RESET..\n"); + else + ss->transport_reset(ss); + + pccb->pdata = usb_stor_buf; + + dev_desc->target = dev->devnum; + pccb->lun = dev_desc->lun; + USB_STOR_PRINTF(" address %d\n",dev_desc->target); + + if(usb_inquiry(pccb,ss)) + return -1; + + perq = usb_stor_buf[0]; + modi = usb_stor_buf[1]; + if((perq & 0x1f) == 0x1f) { + return 0; /* skip unknown devices */ + } + if((modi&0x80) == 0x80) {/* drive is removable */ + dev_desc->removable = 1; + } + memcpy(&dev_desc->vendor[0], &usb_stor_buf[8], 8); + memcpy(&dev_desc->product[0], &usb_stor_buf[16], 16); + memcpy(&dev_desc->revision[0], &usb_stor_buf[32], 4); + dev_desc->vendor[8] = 0; + dev_desc->product[16] = 0; + dev_desc->revision[4] = 0; #ifdef CONFIG_USB_BIN_FIXUP - usb_bin_fixup(dev->descriptor, (uchar *)dev_desc->vendor, (uchar *)dev_desc->product); + usb_bin_fixup(dev->descriptor, (uchar *)dev_desc->vendor, (uchar *)dev_desc->product); #endif /* CONFIG_USB_BIN_FIXUP */ - USB_STOR_PRINTF("ISO Vers %X, Response Data %X\n",usb_stor_buf[2],usb_stor_buf[3]); - if(usb_test_unit_ready(pccb,ss)) { - printf("Device NOT ready\n Request Sense returned %02X %02X %02X\n",pccb->sense_buf[2],pccb->sense_buf[12],pccb->sense_buf[13]); - if(dev_desc->removable == 1) { - dev_desc->type = perq; - return 1; - } - else - return 0; - } - pccb->pdata = (unsigned char *)&cap[0]; - memset(pccb->pdata,0,8); - if(usb_read_capacity(pccb,ss) != 0) { - printf("READ_CAP ERROR\n"); - cap[0] = 2880; - cap[1] = 0x200; - } - USB_STOR_PRINTF("Read Capacity returns: 0x%lx, 0x%lx\n",cap[0],cap[1]); + USB_STOR_PRINTF("ISO Vers %X, Response Data %X\n",usb_stor_buf[2],usb_stor_buf[3]); + if(usb_test_unit_ready(pccb,ss)) { + printf("Device NOT ready\n Request Sense returned %02X %02X %02X\n",pccb->sense_buf[2],pccb->sense_buf[12],pccb->sense_buf[13]); + if(dev_desc->removable == 1) { + dev_desc->type = perq; + return 1; + } + else + return 0; + } + pccb->pdata = (unsigned char *)&cap[0]; + memset(pccb->pdata,0,8); + if(usb_read_capacity(pccb,ss) != 0) { + printf("READ_CAP ERROR\n"); + cap[0] = 2880; + cap[1] = 0x200; + } + USB_STOR_PRINTF("Read Capacity returns: 0x%lx, 0x%lx\n",cap[0],cap[1]); #if 0 - if(cap[0]>(0x200000 * 10)) /* greater than 10 GByte */ - cap[0]>>=16; + if(cap[0]>(0x200000 * 10)) /* greater than 10 GByte */ + cap[0]>>=16; #endif #ifdef LITTLEENDIAN - cap[0] = ((unsigned long)( - (((unsigned long)(cap[0]) & (unsigned long)0x000000ffUL) << 24) | - (((unsigned long)(cap[0]) & (unsigned long)0x0000ff00UL) << 8) | - (((unsigned long)(cap[0]) & (unsigned long)0x00ff0000UL) >> 8) | - (((unsigned long)(cap[0]) & (unsigned long)0xff000000UL) >> 24) )); - cap[1] = ((unsigned long)( - (((unsigned long)(cap[1]) & (unsigned long)0x000000ffUL) << 24) | - (((unsigned long)(cap[1]) & (unsigned long)0x0000ff00UL) << 8) | - (((unsigned long)(cap[1]) & (unsigned long)0x00ff0000UL) >> 8) | - (((unsigned long)(cap[1]) & (unsigned long)0xff000000UL) >> 24) )); + cap[0] = ((unsigned long)( + (((unsigned long)(cap[0]) & (unsigned long)0x000000ffUL) << 24) | + (((unsigned long)(cap[0]) & (unsigned long)0x0000ff00UL) << 8) | + (((unsigned long)(cap[0]) & (unsigned long)0x00ff0000UL) >> 8) | + (((unsigned long)(cap[0]) & (unsigned long)0xff000000UL) >> 24) )); + cap[1] = ((unsigned long)( + (((unsigned long)(cap[1]) & (unsigned long)0x000000ffUL) << 24) | + (((unsigned long)(cap[1]) & (unsigned long)0x0000ff00UL) << 8) | + (((unsigned long)(cap[1]) & (unsigned long)0x00ff0000UL) >> 8) | + (((unsigned long)(cap[1]) & (unsigned long)0xff000000UL) >> 24) )); #endif - /* this assumes bigendian! */ - cap[0] += 1; - capacity = &cap[0]; - blksz = &cap[1]; - USB_STOR_PRINTF("Capacity = 0x%lx, blocksz = 0x%lx\n",*capacity,*blksz); - dev_desc->lba = *capacity; - dev_desc->blksz = *blksz; - dev_desc->type = perq; - USB_STOR_PRINTF(" address %d\n",dev_desc->target); - USB_STOR_PRINTF("partype: %d\n",dev_desc->part_type); - - init_part(dev_desc); - - USB_STOR_PRINTF("partype: %d\n",dev_desc->part_type); - return 1; + /* this assumes bigendian! */ + cap[0] += 1; + capacity = &cap[0]; + blksz = &cap[1]; + USB_STOR_PRINTF("Capacity = 0x%lx, blocksz = 0x%lx\n",*capacity,*blksz); + dev_desc->lba = *capacity; + dev_desc->blksz = *blksz; + dev_desc->type = perq; + USB_STOR_PRINTF(" address %d\n",dev_desc->target); + USB_STOR_PRINTF("partype: %d\n",dev_desc->part_type); + + init_part(dev_desc); + + USB_STOR_PRINTF("partype: %d\n",dev_desc->part_type); + return 1; } #endif /* CONFIG_USB_STORAGE */ diff --git a/cpu/arm926ejs/da8xx/Makefile b/cpu/arm926ejs/da8xx/Makefile new file mode 100644 index 00000000000..49fa3111ef4 --- /dev/null +++ b/cpu/arm926ejs/da8xx/Makefile @@ -0,0 +1,49 @@ +# +# (C) Copyright 2000-2006 +# Wolfgang Denk, DENX Software Engineering, wd@denx.de. +# +# Copyright (C) 2007 Sergey Kubushyn <ksi@koi8.net> +# +# 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)lib$(SOC).a + +COBJS = timer.o ether.o nand.o clock.o i2c.o +SOBJS = lowlevel_init.o reset.o + +SRCS := $(START:.o=.S) $(SOBJS:.o=.S) $(COBJS:.o=.c) +OBJS := $(addprefix $(obj),$(COBJS) $(SOBJS)) +START := $(addprefix $(obj),$(START)) + +all: $(obj).depend $(LIB) + +$(LIB): $(OBJS) + $(AR) $(ARFLAGS) $@ $(OBJS) + +######################################################################### + +# defines $(obj).depend target +include $(SRCTREE)/rules.mk + +sinclude $(obj).depend + +######################################################################### diff --git a/cpu/arm926ejs/da8xx/clock.c b/cpu/arm926ejs/da8xx/clock.c new file mode 100644 index 00000000000..7cb979bc005 --- /dev/null +++ b/cpu/arm926ejs/da8xx/clock.c @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2008 Sekhar Nori, Texas Instruments, Inc. <nsekhar@ti.com> + * + * DA8xx clock module + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * ---------------------------------------------------------------------------- + */ + +#include <common.h> +#include <asm/arch/hardware.h> + +dv_reg_p sysdiv[9] = { + PLL0_DIV1, PLL0_DIV2, PLL0_DIV3, PLL0_DIV4, PLL0_DIV5, PLL0_DIV6, + PLL0_DIV7, PLL0_DIV8, PLL0_DIV9 }; + +int clk_get(unsigned int id) +{ + int pre_div = (REG(PLL0_PREDIV) & 0xff) + 1; + int pllm = REG(PLL0_PLLM) + 1; + int post_div = (REG(PLL0_POSTDIV) & 0xff) + 1; + int pll_out = CFG_OSCIN_FREQ; + + if(id == DAVINCI_AUXCLK_CLKID) + goto out; + + /* Lets keep this simple. Combining operations can result in + * unexpected approximations + */ + pll_out /= pre_div; + pll_out *= pllm; + + if(id == DAVINCI_PLLM_CLKID) + goto out; + + pll_out /= post_div; + + if(id == DAVINCI_PLLC_CLKID) + goto out; + + pll_out /= (REG(sysdiv[id - 1]) & 0xff) + 1; + +out: + return pll_out; +} diff --git a/cpu/arm926ejs/da8xx/ether.c b/cpu/arm926ejs/da8xx/ether.c new file mode 100644 index 00000000000..f128196bb96 --- /dev/null +++ b/cpu/arm926ejs/da8xx/ether.c @@ -0,0 +1,667 @@ +/* + * Ethernet driver for TI TMS320DM644x (DaVinci) chips. + * + * Copyright (C) 2007 Sergey Kubushyn <ksi@koi8.net> + * + * Parts shamelessly stolen from TI's dm644x_emac.c. Original copyright + * follows: + * + * ---------------------------------------------------------------------------- + * + * dm644x_emac.c + * + * TI DaVinci (DM644X) EMAC peripheral driver source for DV-EVM + * + * Copyright (C) 2005 Texas Instruments. + * + * ---------------------------------------------------------------------------- + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * ---------------------------------------------------------------------------- + + * Modifications: + * ver. 1.0: Sep 2005, Anant Gole - Created EMAC version for uBoot. + * ver 1.1: Nov 2005, Anant Gole - Extended the RX logic for multiple descriptors + * + */ +#include <common.h> +#include <command.h> +#include <net.h> +#include <miiphy.h> +#include <asm/arch/emac_defs.h> + +#ifdef CONFIG_DRIVER_TI_EMAC + +#ifdef CONFIG_CMD_NET + +unsigned int emac_dbg = 0; +#define debug_emac(fmt,args...) if (emac_dbg) printf(fmt,##args) + +/* Internal static functions */ +static int dm644x_eth_hw_init (void); +static int dm644x_eth_open (void); +static int dm644x_eth_close (void); +static int dm644x_eth_send_packet (volatile void *packet, int length); +static int dm644x_eth_rcv_packet (void); +static void dm644x_eth_mdio_enable(void); + +static int gen_init_phy(int phy_addr); +static int gen_is_phy_connected(int phy_addr); +static int gen_get_link_speed(int phy_addr); +static int gen_auto_negotiate(int phy_addr); + +/* Wrappers exported to the U-Boot proper */ +int eth_hw_init(void) +{ + return(dm644x_eth_hw_init()); +} + +int eth_init(bd_t * bd) +{ + return(dm644x_eth_open()); +} + +void eth_halt(void) +{ + dm644x_eth_close(); +} + +int eth_send(volatile void *packet, int length) +{ + return(dm644x_eth_send_packet(packet, length)); +} + +int eth_rx(void) +{ + return(dm644x_eth_rcv_packet()); +} + +void eth_mdio_enable(void) +{ + dm644x_eth_mdio_enable(); +} +/* End of wrappers */ + +/* dm644x_eth_mac_addr[0] goes out on the wire first */ + +static u_int8_t dm644x_eth_mac_addr[] = { 0x00, 0xff, 0xff, 0xff, 0xff, 0x00 }; + +/* + * This function must be called before emac_open() if you want to override + * the default mac address. + */ +void dm644x_eth_set_mac_addr(const u_int8_t *addr) +{ + int i; + + for (i = 0; i < sizeof (dm644x_eth_mac_addr); i++) { + dm644x_eth_mac_addr[i] = addr[i]; + } +} + +/* EMAC Addresses */ +static volatile emac_regs *adap_emac = (emac_regs *)EMAC_BASE_ADDR; +static volatile ewrap_regs *adap_ewrap = (ewrap_regs *)EMAC_WRAPPER_BASE_ADDR; +static volatile mdio_regs *adap_mdio = (mdio_regs *)EMAC_MDIO_BASE_ADDR; + +/* EMAC descriptors */ +static volatile emac_desc *emac_rx_desc = (emac_desc *)(EMAC_WRAPPER_RAM_ADDR + EMAC_RX_DESC_BASE); +static volatile emac_desc *emac_tx_desc = (emac_desc *)(EMAC_WRAPPER_RAM_ADDR + EMAC_TX_DESC_BASE); +static volatile emac_desc *emac_rx_active_head = 0; +static volatile emac_desc *emac_rx_active_tail = 0; +static int emac_rx_queue_active = 0; + +/* Receive packet buffers */ +static unsigned char emac_rx_buffers[EMAC_MAX_RX_BUFFERS * (EMAC_MAX_ETHERNET_PKT_SIZE + EMAC_PKT_ALIGN)]; + +/* PHY address for a discovered PHY (0xff - not found) */ +static volatile u_int8_t active_phy_addr = 0xff; + +static int no_phy_init (int phy_addr) { return(1); } +static int no_phy_is_connected (int phy_addr) { return(1); } +static int no_phy_get_link_speed (int phy_addr) { return(1); } +static int no_phy_auto_negotiate (int phy_addr) { return(1); } +phy_t phy = { + .init = no_phy_init, + .is_phy_connected = no_phy_is_connected, + .get_link_speed = no_phy_get_link_speed, + .auto_negotiate = no_phy_auto_negotiate +}; + +static void dm644x_eth_mdio_enable(void) +{ + u_int32_t clkdiv; + + clkdiv = (EMAC_MDIO_BUS_FREQ / EMAC_MDIO_CLOCK_FREQ) - 1; + + adap_mdio->CONTROL = (clkdiv & 0xff) | + MDIO_CONTROL_ENABLE | + MDIO_CONTROL_FAULT | + MDIO_CONTROL_FAULT_ENABLE; + + while (adap_mdio->CONTROL & MDIO_CONTROL_IDLE) {;} +} + +/* + * Tries to find an active connected PHY. Returns 1 if address if found. + * If no active PHY found returns 0. If more than one active PHY (switch) + * returns 2 + * Sets active_phy_addr variable when returns 1. + */ +static int dm644x_eth_phy_detect(void) +{ + u_int32_t phy_act_state; + int i; + + active_phy_addr = 0xff; + + if ((phy_act_state = adap_mdio->ALIVE) == 0) + return(0); /* No active PHYs */ + + debug_emac("dm644x_eth_phy_detect(), ALIVE = 0x%08x\n", phy_act_state); + + for (i = 0; i < 32; i++) { + if (phy_act_state & (1 << i)) { + if (phy_act_state & ~(1 << i)) + return(2); /* More than one PHY */ + else { + active_phy_addr = i; + return(1); + } + } + } + + return(0); /* Just to make GCC happy */ +} + + +/* Read a PHY register via MDIO inteface. Returns 1 on success, 0 otherwise */ +int dm644x_eth_phy_read(u_int8_t phy_addr, u_int8_t reg_num, u_int16_t *data) +{ + int tmp; + + while (adap_mdio->USERACCESS0 & MDIO_USERACCESS0_GO) {;} + + adap_mdio->USERACCESS0 = MDIO_USERACCESS0_GO | + MDIO_USERACCESS0_WRITE_READ | + ((reg_num & 0x1f) << 21) | + ((phy_addr & 0x1f) << 16); + + /* Wait for command to complete */ + while ((tmp = adap_mdio->USERACCESS0) & MDIO_USERACCESS0_GO) {;} + + if (tmp & MDIO_USERACCESS0_ACK) { + *data = tmp & 0xffff; + return(1); + } + + *data = -1; + return(0); +} + +/* Write to a PHY register via MDIO inteface. Blocks until operation is complete. */ +int dm644x_eth_phy_write(u_int8_t phy_addr, u_int8_t reg_num, u_int16_t data) +{ + + while (adap_mdio->USERACCESS0 & MDIO_USERACCESS0_GO) {;} + + adap_mdio->USERACCESS0 = MDIO_USERACCESS0_GO | + MDIO_USERACCESS0_WRITE_WRITE | + ((reg_num & 0x1f) << 21) | + ((phy_addr & 0x1f) << 16) | + (data & 0xffff); + + /* Wait for command to complete */ + while (adap_mdio->USERACCESS0 & MDIO_USERACCESS0_GO) {;} + + return(1); +} + +/* PHY functions for a generic PHY */ +static int gen_init_phy(int phy_addr) +{ + int ret = 1; + + if (gen_get_link_speed(phy_addr)) { + /* Try another time */ + ret = gen_get_link_speed(phy_addr); + } + + return(ret); +} + +static int gen_is_phy_connected(int phy_addr) +{ + u_int16_t dummy; + + return(dm644x_eth_phy_read(phy_addr, PHY_PHYIDR1, &dummy)); +} + +static int gen_get_link_speed(int phy_addr) +{ + u_int16_t tmp; + + if (dm644x_eth_phy_read(phy_addr, MII_STATUS_REG, &tmp) && (tmp & 0x04)) + return(1); + + return(0); +} + +static int gen_auto_negotiate(int phy_addr) +{ + u_int16_t tmp; + + if (!dm644x_eth_phy_read(phy_addr, PHY_BMCR, &tmp)) + return(0); + + /* Restart Auto_negotiation */ + tmp |= PHY_BMCR_AUTON; + dm644x_eth_phy_write(phy_addr, PHY_BMCR, tmp); + + /*check AutoNegotiate complete */ + udelay (10000); + if (!dm644x_eth_phy_read(phy_addr, PHY_BMSR, &tmp)) + return(0); + + if (!(tmp & PHY_BMSR_AUTN_COMP)) + return(0); + + return(gen_get_link_speed(phy_addr)); +} +/* End of generic PHY functions */ + + +#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII) +static int dm644x_mii_phy_read(char *devname, unsigned char addr, unsigned char reg, unsigned short *value) +{ + return(dm644x_eth_phy_read(addr, reg, value) ? 0 : 1); +} + +static int dm644x_mii_phy_write(char *devname, unsigned char addr, unsigned char reg, unsigned short value) +{ + return(dm644x_eth_phy_write(addr, reg, value) ? 0 : 1); +} + +int dm644x_eth_miiphy_initialize(bd_t *bis) +{ + miiphy_register(phy.name, dm644x_mii_phy_read, dm644x_mii_phy_write); + + return(1); +} +#endif + +/* + * This function initializes the emac hardware. It does NOT initialize + * EMAC modules power or pin multiplexors, that is done by board_init() + * much earlier in bootup process. Returns 1 on success, 0 otherwise. + */ +static int dm644x_eth_hw_init(void) +{ + u_int32_t phy_id; + u_int16_t tmp; + int i, ret; + + /* The RMII clock can be sources internally through the SYSCLK7 + * or can come externally through a dedicated pin. This selection is + * controlled by PinMux9[21]. PinMux registers are off-limits for ARM. + * In short, we just assume there is a 50MHz RMII clock available. + */ + + dm644x_eth_mdio_enable(); + + for (i = 0; i < 256; i++) { + if (adap_mdio->ALIVE) + break; + udelay(1000); + } + + if (i >= 256) { + printf("No ETH PHY detected!!!\n"); + return(0); + } + + /* Find if a PHY is connected and get it's address */ + ret = dm644x_eth_phy_detect(); + + if (ret == 2) { + printf("More than one PHY detected.\n"); + return(1); + } else if(ret == 0) + return(0); + + /* Get PHY ID and initialize phy_ops for a detected PHY */ + if (!dm644x_eth_phy_read(active_phy_addr, PHY_PHYIDR1, &tmp)) { + active_phy_addr = 0xff; + return(0); + } + + phy_id = (tmp << 16) & 0xffff0000; + + if (!dm644x_eth_phy_read(active_phy_addr, PHY_PHYIDR2, &tmp)) { + active_phy_addr = 0xff; + return(0); + } + + phy_id |= tmp & 0x0000ffff; + + switch (phy_id) { + default: + sprintf(phy.name, "GENERIC @ 0x%02x", active_phy_addr); + phy.init = gen_init_phy; + phy.is_phy_connected = gen_is_phy_connected; + phy.get_link_speed = gen_get_link_speed; + phy.auto_negotiate = gen_auto_negotiate; + } + + return(1); +} + + +/* Eth device open */ +static int dm644x_eth_open(void) +{ + dv_reg_p addr; + u_int32_t clkdiv, cnt; + volatile emac_desc *rx_desc; + int i; + + debug_emac("+ emac_open\n"); + + /* Reset EMAC module and disable interrupts in wrapper */ + adap_emac->SOFTRESET = 1; + while (adap_emac->SOFTRESET != 0) {;} + adap_ewrap->SOFTRESET = 1; + while (adap_ewrap->SOFTRESET != 0) {;} + + adap_ewrap->C0RXEN = adap_ewrap->C1RXEN = adap_ewrap->C2RXEN = 0; + adap_ewrap->C0TXEN = adap_ewrap->C1TXEN = adap_ewrap->C2TXEN = 0; + adap_ewrap->C0MISCEN = adap_ewrap->C1MISCEN = adap_ewrap->C2MISCEN = 0; + + rx_desc = emac_rx_desc; + + adap_emac->TXCONTROL = 0x01; + adap_emac->RXCONTROL = 0x01; + + /* Set MAC Addresses & Init multicast Hash to 0 (disable any multicast receive) */ + /* Using channel 0 only - other channels are disabled */ + for (i = 0; i < 8; i++) { + adap_emac->MACINDEX = i; + adap_emac->MACADDRHI = + (dm644x_eth_mac_addr[3] << 24) | /* bits 23-16 */ + (dm644x_eth_mac_addr[2] << 16) | /* bits 31-24 */ + (dm644x_eth_mac_addr[1] << 8) | /* bits 39-32 */ + (dm644x_eth_mac_addr[0]); /* bits 47-40 */ + adap_emac->MACADDRLO = + (dm644x_eth_mac_addr[5] << 8) | /* bits 8-0*/ + (dm644x_eth_mac_addr[4]) | (1 << 19) | (1 << 20); /* bits 8-0 */ + } + + adap_emac->MACHASH1 = 0; + adap_emac->MACHASH2 = 0; + + /* Set source MAC address - REQUIRED for pause frames */ + adap_emac->MACSRCADDRHI = + (dm644x_eth_mac_addr[3] << 24) | /* bits 23-16 */ + (dm644x_eth_mac_addr[2] << 16) | /* bits 31-24 */ + (dm644x_eth_mac_addr[1] << 8) | /* bits 39-32 */ + (dm644x_eth_mac_addr[0]); /* bits 47-40 */ + adap_emac->MACSRCADDRLO = + (dm644x_eth_mac_addr[5] << 8) | /* bits 8-0 */ + (dm644x_eth_mac_addr[4]); /* bits 15-8 */ + + /* Set DMA 8 TX / 8 RX Head pointers to 0 */ + addr = &adap_emac->TX0HDP; + for(cnt = 0; cnt < 16; cnt++) + *addr++ = 0; + + addr = &adap_emac->TX0CP; + for(cnt = 0; cnt < 16; cnt++) + *addr++ = 0; + + /* Clear Statistics (do this before setting MacControl register) */ + addr = &adap_emac->RXGOODFRAMES; + for(cnt = 0; cnt < EMAC_NUM_STATS; cnt++) + *addr++ = 0; + + /* No multicast addressing */ + adap_emac->MACHASH1 = 0; + adap_emac->MACHASH2 = 0; + + /* Create RX queue and set receive process in place */ + emac_rx_active_head = emac_rx_desc; + for (cnt = 0; cnt < EMAC_MAX_RX_BUFFERS; cnt++) { + rx_desc->next = (u_int32_t)(rx_desc + 1); + rx_desc->buffer = &emac_rx_buffers[cnt * (EMAC_MAX_ETHERNET_PKT_SIZE + EMAC_PKT_ALIGN)]; + rx_desc->buff_off_len = EMAC_MAX_ETHERNET_PKT_SIZE; + rx_desc->pkt_flag_len = EMAC_CPPI_OWNERSHIP_BIT; + rx_desc++; + } + + /* Set the last descriptor's "next" parameter to 0 to end the RX desc list */ + rx_desc--; + rx_desc->next = 0; + emac_rx_active_tail = rx_desc; + emac_rx_queue_active = 1; + + /* Enable TX/RX */ + adap_emac->RXMAXLEN = EMAC_MAX_ETHERNET_PKT_SIZE; + adap_emac->RXBUFFEROFFSET = 0; + + /* No fancy configs - Use this for promiscous for debug - EMAC_RXMBPENABLE_RXCAFEN_ENABLE */ + adap_emac->RXMBPENABLE = EMAC_RXMBPENABLE_RXBROADEN; + + /* Enable ch 0 only */ + adap_emac->RXUNICASTSET = 0x01; + + /* Enable MII interface and Full duplex mode */ + adap_emac->MACCONTROL = (EMAC_MACCONTROL_MIIEN_ENABLE | EMAC_MACCONTROL_FULLDUPLEX_ENABLE) | EMAC_MACCONTROL_RMIISPEED_100; + + /* Init MDIO & get link state */ + clkdiv = (EMAC_MDIO_BUS_FREQ / EMAC_MDIO_CLOCK_FREQ) - 1; + adap_mdio->CONTROL = ((clkdiv & 0xff) | MDIO_CONTROL_ENABLE | MDIO_CONTROL_FAULT); + + if (!phy.get_link_speed(active_phy_addr)) + return(0); + + /* Start receive process */ + adap_emac->RX0HDP = (u_int32_t)emac_rx_desc; + + debug_emac("- emac_open\n"); + + return(1); +} + +/* EMAC Channel Teardown */ +static void dm644x_eth_ch_teardown(int ch) +{ + dv_reg dly = 0xff; + dv_reg cnt; + + debug_emac("+ emac_ch_teardown\n"); + + if (ch == EMAC_CH_TX) { + /* Init TX channel teardown */ + adap_emac->TXTEARDOWN = 1; + for(cnt = 0; cnt != 0xfffffffc; cnt = adap_emac->TX0CP) { + /* Wait here for Tx teardown completion interrupt to occur + * Note: A task delay can be called here to pend rather than + * occupying CPU cycles - anyway it has been found that teardown + * takes very few cpu cycles and does not affect functionality */ + dly--; + udelay(1); + if (dly == 0) + break; + } + adap_emac->TX0CP = cnt; + adap_emac->TX0HDP = 0; + } else { + /* Init RX channel teardown */ + adap_emac->RXTEARDOWN = 1; + for(cnt = 0; cnt != 0xfffffffc; cnt = adap_emac->RX0CP) { + /* Wait here for Rx teardown completion interrupt to occur + * Note: A task delay can be called here to pend rather than + * occupying CPU cycles - anyway it has been found that teardown + * takes very few cpu cycles and does not affect functionality */ + dly--; + udelay(1); + if (dly == 0) + break; + } + adap_emac->RX0CP = cnt; + adap_emac->RX0HDP = 0; + } + + debug_emac("- emac_ch_teardown\n"); +} + +/* Eth device close */ +static int dm644x_eth_close(void) +{ + debug_emac("+ emac_close\n"); + + dm644x_eth_ch_teardown(EMAC_CH_TX); /* TX Channel teardown */ + dm644x_eth_ch_teardown(EMAC_CH_RX); /* RX Channel teardown */ + + /* Reset EMAC module and disable interrupts in wrapper */ + adap_emac->SOFTRESET = 1; + adap_ewrap->SOFTRESET = 1; + + adap_ewrap->C0RXEN = adap_ewrap->C1RXEN = adap_ewrap->C2RXEN = 0; + adap_ewrap->C0TXEN = adap_ewrap->C1TXEN = adap_ewrap->C2TXEN = 0; + adap_ewrap->C0MISCEN = adap_ewrap->C1MISCEN = adap_ewrap->C2MISCEN = 0; + + debug_emac("- emac_close\n"); + return(1); +} + +static int tx_send_loop = 0; + +/* + * This function sends a single packet on the network and returns + * positive number (number of bytes transmitted) or negative for error + */ +static int dm644x_eth_send_packet(volatile void *packet, int length) +{ + int ret_status = -1; + tx_send_loop = 0; + + /* Return error if no link */ + if (!phy.get_link_speed(active_phy_addr)) + { + printf("WARN: emac_send_packet: No link\n"); + return (ret_status); + } + + /* Check packet size and if < EMAC_MIN_ETHERNET_PKT_SIZE, pad it up */ + if (length < EMAC_MIN_ETHERNET_PKT_SIZE) + { + length = EMAC_MIN_ETHERNET_PKT_SIZE; + } + + /* Populate the TX descriptor */ + emac_tx_desc->next = 0; + emac_tx_desc->buffer = (u_int8_t *)packet; + emac_tx_desc->buff_off_len = (length & 0xffff); + emac_tx_desc->pkt_flag_len = ((length & 0xffff) | + EMAC_CPPI_SOP_BIT | + EMAC_CPPI_OWNERSHIP_BIT | + EMAC_CPPI_EOP_BIT); + /* Send the packet */ + adap_emac->TX0HDP = (unsigned int)emac_tx_desc; + + /* Wait for packet to complete or link down */ + while (1) { + if (!phy.get_link_speed(active_phy_addr)) { + dm644x_eth_ch_teardown(EMAC_CH_TX); + return (ret_status); + } + if (adap_emac->TXINTSTATRAW & 0x01) { + ret_status = length; + break; + } + tx_send_loop++; + } + + return(ret_status); +} + +/* + * This function handles receipt of a packet from the network + */ +static int dm644x_eth_rcv_packet(void) +{ + volatile emac_desc *rx_curr_desc; + volatile emac_desc *curr_desc; + volatile emac_desc *tail_desc; + int status, ret = -1; + + rx_curr_desc = emac_rx_active_head; + status = rx_curr_desc->pkt_flag_len; + if ((rx_curr_desc) && ((status & EMAC_CPPI_OWNERSHIP_BIT) == 0)) { + if (status & EMAC_CPPI_RX_ERROR_FRAME) { + /* Error in packet - discard it and requeue desc */ + printf("WARN: emac_rcv_pkt: Error in packet\n"); + } else { + NetReceive(rx_curr_desc->buffer, (rx_curr_desc->buff_off_len & 0xffff)); + ret = rx_curr_desc->buff_off_len & 0xffff; + } + + /* Ack received packet descriptor */ + adap_emac->RX0CP = (unsigned int)rx_curr_desc; + curr_desc = rx_curr_desc; + emac_rx_active_head = (volatile emac_desc *)rx_curr_desc->next; + + if (status & EMAC_CPPI_EOQ_BIT) { + if (emac_rx_active_head) { + adap_emac->RX0HDP = (unsigned int)emac_rx_active_head; + } else { + emac_rx_queue_active = 0; + printf("INFO:emac_rcv_packet: RX Queue not active\n"); + } + } + + /* Recycle RX descriptor */ + rx_curr_desc->buff_off_len = EMAC_MAX_ETHERNET_PKT_SIZE; + rx_curr_desc->pkt_flag_len = EMAC_CPPI_OWNERSHIP_BIT; + rx_curr_desc->next = 0; + + if (emac_rx_active_head == 0) { + printf("INFO: emac_rcv_pkt: active queue head = 0\n"); + emac_rx_active_head = curr_desc; + emac_rx_active_tail = curr_desc; + if (emac_rx_queue_active != 0) { + adap_emac->RX0HDP = (unsigned int)emac_rx_active_head; + printf("INFO: emac_rcv_pkt: active queue head = 0, HDP fired\n"); + emac_rx_queue_active = 1; + } + } else { + tail_desc = emac_rx_active_tail; + emac_rx_active_tail = curr_desc; + tail_desc->next = (unsigned int)curr_desc; + status = tail_desc->pkt_flag_len; + if (status & EMAC_CPPI_EOQ_BIT) { + adap_emac->RX0HDP = (unsigned int)curr_desc; + status &= ~EMAC_CPPI_EOQ_BIT; + tail_desc->pkt_flag_len = status; + } + } + return(ret); + } + return(0); +} + +#endif /* CONFIG_CMD_NET */ + +#endif /* CONFIG_DRIVER_TI_EMAC */ diff --git a/cpu/arm926ejs/da8xx/i2c.c b/cpu/arm926ejs/da8xx/i2c.c new file mode 100644 index 00000000000..4a7938a10de --- /dev/null +++ b/cpu/arm926ejs/da8xx/i2c.c @@ -0,0 +1,355 @@ +/* + * TI DaVinci (TMS320DM644x) I2C driver. + * + * Copyright (C) 2007 Sergey Kubushyn <ksi@koi8.net> + * + * -------------------------------------------------------- + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include <common.h> + +#ifdef CONFIG_DRIVER_DAVINCI_I2C + +#include <i2c.h> +#include <asm/arch/hardware.h> +#include <asm/arch/i2c_defs.h> + +#define CHECK_NACK() \ + do {\ + if (tmp & (I2C_TIMEOUT | I2C_STAT_NACK)) {\ + REG(I2C_CON) = 0;\ + return(1);\ + }\ + } while (0) + + +static int wait_for_bus(void) +{ + int stat, timeout; + + REG(I2C_STAT) = 0xffff; + + for (timeout = 0; timeout < 10; timeout++) { + if (!((stat = REG(I2C_STAT)) & I2C_STAT_BB)) { + REG(I2C_STAT) = 0xffff; + return(0); + } + + REG(I2C_STAT) = stat; + udelay(50000); + } + + REG(I2C_STAT) = 0xffff; + return(1); +} + + +static int poll_i2c_irq(int mask) +{ + int stat, timeout; + + for (timeout = 0; timeout < 10; timeout++) { + udelay(1000); + stat = REG(I2C_STAT); + if (stat & mask) { + return(stat); + } + } + + REG(I2C_STAT) = 0xffff; + return(stat | I2C_TIMEOUT); +} + + +void flush_rx(void) +{ + int dummy; + + while (1) { + if (!(REG(I2C_STAT) & I2C_STAT_RRDY)) + break; + + dummy = REG(I2C_DRR); + REG(I2C_STAT) = I2C_STAT_RRDY; + udelay(1000); + } +} + + +void i2c_init(int speed, int slaveadd) +{ + u_int32_t div, psc; + + if (REG(I2C_CON) & I2C_CON_EN) { + REG(I2C_CON) = 0; + udelay (50000); + } + + /* Get 1MHz into I2C internal */ + psc = CFG_HZ_CLOCK/1000000; + + div = CFG_HZ_CLOCK / (psc * speed); /* SCLL + SCLH */ + + REG(I2C_PSC) = psc - 1; /* 27MHz / (2 + 1) = 9MHz */ + REG(I2C_SCLL) = (div * 50) / 100; /* 50% Duty */ + REG(I2C_SCLH) = div - REG(I2C_SCLL); + + REG(I2C_OA) = slaveadd; + REG(I2C_CNT) = 0; + + /* Interrupts must be enabled or I2C module won't work */ + REG(I2C_IE) = I2C_IE_SCD_IE | I2C_IE_XRDY_IE | + I2C_IE_RRDY_IE | I2C_IE_ARDY_IE | I2C_IE_NACK_IE; + + /* Now enable I2C controller (get it out of reset) */ + REG(I2C_CON) = I2C_CON_EN; + + udelay(1000); +} + + +int i2c_probe(u_int8_t chip) +{ + int rc = 1; + + if (chip == REG(I2C_OA)) { + return(rc); + } + + REG(I2C_CON) = 0; + if (wait_for_bus()) {return(1);} + + /* try to read one byte from current (or only) address */ + REG(I2C_CNT) = 1; + REG(I2C_SA) = chip; + REG(I2C_CON) = (I2C_CON_EN | I2C_CON_MST | I2C_CON_STT | I2C_CON_STP | I2C_CON_FREE); + udelay (50000); + + if (!(REG(I2C_STAT) & I2C_STAT_NACK)) { + rc = 0; + flush_rx(); + REG(I2C_STAT) = 0xffff; + } else { + REG(I2C_STAT) = 0xffff; + REG(I2C_CON) |= I2C_CON_STP; + udelay(20000); + if (wait_for_bus()) {return(1);} + } + + flush_rx(); + REG(I2C_STAT) = 0xffff; + REG(I2C_CNT) = 0; + return(rc); +} + + +int i2c_read(u_int8_t chip, u_int32_t addr, int alen, u_int8_t *buf, int len) +{ + u_int32_t tmp; + int i; + + if ((alen < 0) || (alen > 2)) { + printf("%s(): bogus address length %x\n", __FUNCTION__, alen); + return(1); + } + + if (wait_for_bus()) {return(1);} + + if (alen != 0) { + /* Start address phase */ + tmp = I2C_CON_EN | I2C_CON_MST | I2C_CON_STT | I2C_CON_TRX | + I2C_CON_FREE; + REG(I2C_CNT) = alen; + REG(I2C_SA) = chip; + REG(I2C_CON) = tmp; + + tmp = poll_i2c_irq(I2C_STAT_XRDY | I2C_STAT_NACK); + + CHECK_NACK(); + + switch (alen) { + case 2: + /* Send address MSByte */ + if (tmp & I2C_STAT_XRDY) { + REG(I2C_DXR) = (addr >> 8) & 0xff; + } else { + REG(I2C_CON) = 0; + return(1); + } + + tmp = poll_i2c_irq(I2C_STAT_XRDY | I2C_STAT_NACK); + + CHECK_NACK(); + /* No break, fall through */ + case 1: + /* Send address LSByte */ + if (tmp & I2C_STAT_XRDY) { + REG(I2C_DXR) = addr & 0xff; + } else { + REG(I2C_CON) = 0; + return(1); + } + + tmp = poll_i2c_irq(I2C_STAT_XRDY | I2C_STAT_NACK | I2C_STAT_ARDY); + + CHECK_NACK(); + + if (!(tmp & I2C_STAT_ARDY)) { + REG(I2C_CON) = 0; + return(1); + } + } + } + + /* Address phase is over, now read 'len' bytes and stop */ + tmp = I2C_CON_EN | I2C_CON_MST | I2C_CON_STT | I2C_CON_STP | I2C_CON_FREE; + REG(I2C_CNT) = len & 0xffff; + REG(I2C_SA) = chip; + REG(I2C_CON) = tmp; + + for (i = 0; i < len; i++) { + tmp = poll_i2c_irq(I2C_STAT_RRDY | I2C_STAT_NACK | I2C_STAT_ROVR); + + CHECK_NACK(); + + if (tmp & I2C_STAT_RRDY) { + buf[i] = REG(I2C_DRR); + } else { + REG(I2C_CON) = 0; + return(1); + } + } + + tmp = poll_i2c_irq(I2C_STAT_SCD | I2C_STAT_NACK); + + CHECK_NACK(); + + if (!(tmp & I2C_STAT_SCD)) { + REG(I2C_CON) = 0; + return(1); + } + + flush_rx(); + REG(I2C_STAT) = 0xffff; + REG(I2C_CNT) = 0; + REG(I2C_CON) = 0; + + return(0); +} + + +int i2c_write(u_int8_t chip, u_int32_t addr, int alen, u_int8_t *buf, int len) +{ + u_int32_t tmp; + int i; + + if ((alen < 0) || (alen > 2)) { + printf("%s(): bogus address length %x\n", __FUNCTION__, alen); + return(1); + } + if (len < 0) { + printf("%s(): bogus length %x\n", __FUNCTION__, len); + return(1); + } + + if (wait_for_bus()) {return(1);} + + /* Start address phase */ + tmp = I2C_CON_EN | I2C_CON_MST | I2C_CON_STT | I2C_CON_TRX | I2C_CON_STP; + REG(I2C_CNT) = (alen == 0) ? len & 0xffff : (len & 0xffff) + alen; + REG(I2C_SA) = chip; + REG(I2C_CON) = tmp; + + switch (alen) { + case 2: + /* Send address MSByte */ + tmp = poll_i2c_irq(I2C_STAT_XRDY | I2C_STAT_NACK); + + CHECK_NACK(); + + if (tmp & I2C_STAT_XRDY) { + REG(I2C_DXR) = (addr >> 8) & 0xff; + } else { + REG(I2C_CON) = 0; + return(1); + } + /* No break, fall through */ + case 1: + /* Send address LSByte */ + tmp = poll_i2c_irq(I2C_STAT_XRDY | I2C_STAT_NACK); + + CHECK_NACK(); + + if (tmp & I2C_STAT_XRDY) { + REG(I2C_DXR) = addr & 0xff; + } else { + REG(I2C_CON) = 0; + return(1); + } + } + + for (i = 0; i < len; i++) { + tmp = poll_i2c_irq(I2C_STAT_XRDY | I2C_STAT_NACK); + + CHECK_NACK(); + + if (tmp & I2C_STAT_XRDY) { + REG(I2C_DXR) = buf[i]; + } else { + return(1); + } + } + + tmp = poll_i2c_irq(I2C_STAT_SCD | I2C_STAT_NACK); + + CHECK_NACK(); + + if (!(tmp & I2C_STAT_SCD)) { + REG(I2C_CON) = 0; + return(1); + } + + flush_rx(); + REG(I2C_STAT) = 0xffff; + REG(I2C_CNT) = 0; + REG(I2C_CON) = 0; + + return(0); +} + + +u_int8_t i2c_reg_read(u_int8_t chip, u_int8_t reg) +{ + u_int8_t tmp; + + i2c_read(chip, reg, 1, &tmp, 1); + return(tmp); +} + + +void i2c_reg_write(u_int8_t chip, u_int8_t reg, u_int8_t val) +{ + u_int8_t tmp; + + i2c_write(chip, reg, 1, &tmp, 1); +} + +#endif /* CONFIG_DRIVER_DAVINCI_I2C */ diff --git a/cpu/arm926ejs/da8xx/lowlevel_init.S b/cpu/arm926ejs/da8xx/lowlevel_init.S new file mode 100644 index 00000000000..53f801a6222 --- /dev/null +++ b/cpu/arm926ejs/da8xx/lowlevel_init.S @@ -0,0 +1,73 @@ +/* + * Low-level board setup code for TI DA8xx SoC based boards. + * + * Copyright (C) 2008 Texas Instruments, Inc <www.ti.com> + * Sekhar Nori <nsekhar@ti.com> + * + * Based on TI DaVinci low level init code. Original copyrights follow. + * + * Copyright (C) 2007 Sergey Kubushyn <ksi@koi8.net> + * + * Partially based on TI sources, original copyrights follow: + */ + +/* + * Board specific setup info + * + * (C) Copyright 2003 + * Texas Instruments, <www.ti.com> + * Kshitij Gupta <Kshitij@ti.com> + * + * Modified for OMAP 1610 H2 board by Nishant Kamat, Jan 2004 + * + * Modified for OMAP 5912 OSK board by Rishi Bhattacharya, Apr 2004 + * See file CREDITS for list of people who contributed to this + * project. + * + * Modified for DV-EVM board by Rishi Bhattacharya, Apr 2005 + * See file CREDITS for list of people who contributed to this + * project. + * + * Modified for DV-EVM board by Swaminathan S, Nov 2005 + * 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 <config.h> +#include <asm/arch/hardware.h> + +.globl lowlevel_init +lowlevel_init: + + /* + * Call board-specific lowlevel init. + * That MUST be present and THAT returns + * back to arch calling code with "mov pc, lr." + */ + b dv_board_init + nop + +.ltorg + +INTC_GLB_EN_ADDR: + .word INTC_GLB_EN +INTC_EN_CLR0_ADDR: + .word INTC_EN_CLR0 +INTC_HINT_EN_ADDR: + .word INTC_HINT_EN + diff --git a/cpu/arm926ejs/da8xx/nand.c b/cpu/arm926ejs/da8xx/nand.c new file mode 100644 index 00000000000..05049d59f14 --- /dev/null +++ b/cpu/arm926ejs/da8xx/nand.c @@ -0,0 +1,468 @@ +/* + * NAND driver for TI DaVinci based boards. + * + * Copyright (C) 2007 Sergey Kubushyn <ksi@koi8.net> + * + * Based on Linux DaVinci NAND driver by TI. Original copyright follows: + */ + +/* + * + * linux/drivers/mtd/nand/nand_dm355.c + * + * NAND Flash Driver + * + * Copyright (C) 2006 Texas Instruments. + * + * ---------------------------------------------------------------------------- + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * ---------------------------------------------------------------------------- + * + * Overview: + * This is a device driver for the NAND flash device found on the + * DaVinci board which utilizes the Samsung k9k2g08 part. + * + Modifications: + ver. 1.0: Feb 2005, Vinod/Sudhakar + March 2008, Sandeep + - + * + */ + +#include <common.h> + +#ifdef CONFIG_CMD_NAND +#if !defined(CFG_NAND_LEGACY) + +#include <asm/arch/hardware.h> +#include <nand.h> +#include <asm/arch/nand_defs.h> +#include <asm/arch/emif_defs.h> + +#define CSL_EMIF_1_REGS (0x68000000) +#define NAND4BITECCLOAD (CSL_EMIF_1_REGS + 0xBC) +#define NAND4BITECC1 (CSL_EMIF_1_REGS + 0xC0) +#define NAND4BITECC2 (CSL_EMIF_1_REGS + 0xC4) +#define NAND4BITECC3 (CSL_EMIF_1_REGS + 0xC8) +#define NAND4BITECC4 (CSL_EMIF_1_REGS + 0xCC) +#define NANDERRADD1 (CSL_EMIF_1_REGS + 0xD0) +#define NANDERRADD2 (CSL_EMIF_1_REGS + 0xD4) +#define NANDERRVAL1 (CSL_EMIF_1_REGS + 0xD8) +#define NANDERRVAL2 (CSL_EMIF_1_REGS + 0xDC) + +/* Definitions for 4-bit hardware ECC */ +#define NAND_4BITECC_MASK 0x03FF03FF +#define EMIF_NANDFSR_ECC_STATE_MASK 0x00000F00 +#define ECC_STATE_NO_ERR 0x0 +#define ECC_STATE_TOO_MANY_ERRS 0x1 +#define ECC_STATE_ERR_CORR_COMP_P 0x2 +#define ECC_STATE_ERR_CORR_COMP_N 0x3 +#define ECC_MAX_CORRECTABLE_ERRORS 0x4 + +extern struct nand_chip nand_dev_desc[CFG_MAX_NAND_DEVICE]; + +static void nand_dm350evm_hwcontrol(struct mtd_info *mtd, int cmd) +{ + struct nand_chip *this = mtd->priv; + u_int32_t IO_ADDR_W = (u_int32_t)this->IO_ADDR_W; + u_int32_t IO_ADDR_R = (u_int32_t)this->IO_ADDR_R; + + IO_ADDR_W &= ~(MASK_ALE|MASK_CLE); + + switch (cmd) { + case NAND_CTL_SETCLE: + IO_ADDR_W |= MASK_CLE; + break; + case NAND_CTL_SETALE: + IO_ADDR_W |= MASK_ALE; + break; + } + + this->IO_ADDR_W = (void *)IO_ADDR_W; +} + +/* + * Instead of placing the spare data at the end of the page, the 4-bit ECC + * hardware generator requires that the page be subdivided into 4 subpages, + * each with its own spare data area. This structure defines the format of + * each of these subpages. + */ +static struct page_layout_item nand_dm355_hw10_512_layout[] = { + {.type = ITEM_TYPE_DATA,.length = 512}, + {.type = ITEM_TYPE_OOB,.length = 6,}, + {.type = ITEM_TYPE_ECC,.length = 10,}, + {.type = 0,.length = 0,}, +}; + +static struct nand_oobinfo nand_dm355_hw10_512_oobinfo = { + .useecc = MTD_NANDECC_AUTOPLACE, + /* + * We actually have 40 bytes of ECC per page, but the nand_oobinfo + * structure definition limits us to a maximum of 32 bytes. This + * doesn't matter, because out page_layout_item structure definition + * determines where our ECC actually goes in the flash page. + */ + .eccbytes = 32, + .eccpos = {6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, + 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, + 54, 55, + }, + .oobfree = {{0, 6}, {16, 6}, {32, 6}, {48, 6}}, +}; + + + +static int nand_dm355_hw10_512_block_markbad(struct mtd_info *mtd, loff_t ofs) +{ + struct nand_chip *this = mtd->priv; + int block; + + /* Get block number */ + block = ((int)ofs) >> this->bbt_erase_shift; + if (this->bbt) + this->bbt[block >> 2] |= 0x01 << ((block & 0x03) << 1); + + /* Do we have a flash based bad block table ? */ + if (this->options & NAND_USE_FLASH_BBT) + return nand_update_bbt(mtd, ofs); + + return 0; +} + +static void nand_dm355_4bit_enable_hwecc(struct mtd_info *mtd, int mode) +{ + struct nand_chip *this = mtd->priv; + emifregs emif_addr = (emifregs)CSL_EMIF_1_REGS; + u32 val; + + switch (mode) { + case NAND_ECC_WRITE: + case NAND_ECC_READ: + /* + * Start a new ECC calculation for reading or writing 512 bytes + * of data. + */ + val = (emif_addr->NANDFCR & ~(3 << 4)); + val |= (1 << 4) | (1 << 12); + emif_addr->NANDFCR = val; + break; + case NAND_ECC_WRITEOOB: + case NAND_ECC_READOOB: + /* + * Terminate ECC calculation by performing a dummy read of an + * ECC register. Our hardware ECC generator supports including + * the OOB in the ECC calculation, but the NAND core code + * doesn't really support that. We will only calculate the ECC + * on the data; errors in the non-ECC bytes in the OOB will not + * be detected or corrected. + */ + val = emif_addr->NANDF1ECC; + break; + case NAND_ECC_WRITESYN: + case NAND_ECC_READSYN: + /* + * Our ECC calculation has already been terminated, so no need + * to do anything here. + */ + break; + default: + break; + } +} + +static u32 nand_dm355_4bit_readecc(struct mtd_info *mtd, unsigned int ecc[4]) +{ + emifregs emif_addr = (emifregs)CSL_EMIF_1_REGS; + + ecc[0] = (*(dv_reg_p) NAND4BITECC1) & NAND_4BITECC_MASK; + ecc[1] = (*(dv_reg_p) NAND4BITECC2) & NAND_4BITECC_MASK; + ecc[2] = (*(dv_reg_p) NAND4BITECC3) & NAND_4BITECC_MASK; + ecc[3] = (*(dv_reg_p) NAND4BITECC4) & NAND_4BITECC_MASK; + + return 0; +} + +static int nand_dm355_4bit_calculate_ecc(struct mtd_info *mtd, + const u_char * dat, + u_char * ecc_code) +{ + unsigned int hw_4ecc[4] = { 0, 0, 0, 0 }; + unsigned int const1 = 0, const2 = 0; + unsigned char count1 = 0; + + /* + * Since the NAND_HWECC_SYNDROME option is enabled, this routine is + * only called just after the data and oob have been written. The + * ECC value calculated by the hardware ECC generator is available + * for us to read. + */ + nand_dm355_4bit_readecc(mtd, hw_4ecc); + + /*Convert 10 bit ecc value to 8 bit */ + for (count1 = 0; count1 < 2; count1++) { + const2 = count1 * 5; + const1 = count1 * 2; + + /* Take first 8 bits from val1 (count1=0) or val5 (count1=1) */ + ecc_code[const2] = hw_4ecc[const1] & 0xFF; + + /* + * Take 2 bits as LSB bits from val1 (count1=0) or val5 + * (count1=1) and 6 bits from val2 (count1=0) or val5 (count1=1) + */ + ecc_code[const2 + 1] = + ((hw_4ecc[const1] >> 8) & 0x3) | ((hw_4ecc[const1] >> 14) & + 0xFC); + + /* + * Take 4 bits from val2 (count1=0) or val5 (count1=1) and + * 4 bits from val3 (count1=0) or val6 (count1=1) + */ + ecc_code[const2 + 2] = + ((hw_4ecc[const1] >> 22) & 0xF) | + ((hw_4ecc[const1 + 1] << 4) & 0xF0); + + /* + * Take 6 bits from val3(count1=0) or val6 (count1=1) and + * 2 bits from val4 (count1=0) or val7 (count1=1) + */ + ecc_code[const2 + 3] = + ((hw_4ecc[const1 + 1] >> 4) & 0x3F) | + ((hw_4ecc[const1 + 1] >> 10) & 0xC0); + + /* Take 8 bits from val4 (count1=0) or val7 (count1=1) */ + ecc_code[const2 + 4] = (hw_4ecc[const1 + 1] >> 18) & 0xFF; + } + + return 0; +} + +static int nand_dm355_4bit_compare_ecc(struct mtd_info *mtd, u8 * read_ecc, /* read from NAND */ + u8 * page_data) +{ + struct nand_chip *this = mtd->priv; + struct nand_dm355_info *info = this->priv; + unsigned short ecc_10bit[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; + int i; + unsigned int hw_4ecc[4] = { 0, 0, 0, 0 }, iserror = 0; + unsigned short *pspare = NULL, *pspare1 = NULL; + unsigned int numErrors, errorAddress, errorValue; + emifregs emif_addr = (emifregs)CSL_EMIF_1_REGS; + u32 val; + + /* + * Check for an ECC where all bytes are 0xFF. If this is the case, we + * will assume we are looking at an erased page and we should ignore the + * ECC. + */ + for (i = 0; i < 10; i++) { + if (read_ecc[i] != 0xFF) + break; + } + if (i == 10) + return 0; + + /* Convert 8 bit in to 10 bit */ + pspare = (unsigned short *)&read_ecc[2]; + pspare1 = (unsigned short *)&read_ecc[0]; + /* Take 10 bits from 0th and 1st bytes */ + ecc_10bit[0] = (*pspare1) & 0x3FF; /* 10 */ + /* Take 6 bits from 1st byte and 4 bits from 2nd byte */ + ecc_10bit[1] = (((*pspare1) >> 10) & 0x3F) + | (((pspare[0]) << 6) & 0x3C0); /* 6 + 4 */ + /* Take 4 bits form 2nd bytes and 6 bits from 3rd bytes */ + ecc_10bit[2] = ((pspare[0]) >> 4) & 0x3FF; /* 10 */ + /*Take 2 bits from 3rd byte and 8 bits from 4th byte */ + ecc_10bit[3] = (((pspare[0]) >> 14) & 0x3) + | ((((pspare[1])) << 2) & 0x3FC); /* 2 + 8 */ + /* Take 8 bits from 5th byte and 2 bits from 6th byte */ + ecc_10bit[4] = ((pspare[1]) >> 8) + | ((((pspare[2])) << 8) & 0x300); /* 8 + 2 */ + /* Take 6 bits from 6th byte and 4 bits from 7th byte */ + ecc_10bit[5] = (pspare[2] >> 2) & 0x3FF; /* 10 */ + /* Take 4 bits from 7th byte and 6 bits from 8th byte */ + ecc_10bit[6] = (((pspare[2]) >> 12) & 0xF) + | ((((pspare[3])) << 4) & 0x3F0); /* 4 + 6 */ + /*Take 2 bits from 8th byte and 8 bits from 9th byte */ + ecc_10bit[7] = ((pspare[3]) >> 6) & 0x3FF; /* 10 */ + + /* + * Write the parity values in the NAND Flash 4-bit ECC Load register. + * Write each parity value one at a time starting from 4bit_ecc_val8 + * to 4bit_ecc_val1. + */ + for (i = 7; i >= 0; i--) + { + *(dv_reg_p)NAND4BITECCLOAD = ecc_10bit[i]; + } + + /* + * Perform a dummy read to the EMIF Revision Code and Status register. + * This is required to ensure time for syndrome calculation after + * writing the ECC values in previous step. + */ + val = emif_addr->ERCSR; + + /* + * Read the syndrome from the NAND Flash 4-Bit ECC 1-4 registers. + * A syndrome value of 0 means no bit errors. If the syndrome is + * non-zero then go further otherwise return. + */ + nand_dm355_4bit_readecc(mtd, hw_4ecc); + + if (hw_4ecc[0] == ECC_STATE_NO_ERR && hw_4ecc[1] == ECC_STATE_NO_ERR && + hw_4ecc[2] == ECC_STATE_NO_ERR && hw_4ecc[3] == ECC_STATE_NO_ERR) + return 0; + + /* + * Clear any previous address calculation by doing a dummy read of an + * error address register. + */ + val = *(dv_reg_p)NANDERRADD1; + + /* + * Set the addr_calc_st bit(bit no 13) in the NAND Flash Control + * register to 1. + */ + + emif_addr->NANDFCR |= (1 << 13); + + /* + * Wait for the corr_state field (bits 8 to 11)in the + * NAND Flash Status register to be equal to 0x0, 0x1, 0x2, or 0x3. + */ + do { + iserror = emif_addr->NANDFSR & 0xC00; + } while (iserror); + + iserror = emif_addr->NANDFSR; + iserror &= EMIF_NANDFSR_ECC_STATE_MASK; + iserror = iserror >> 8; + + + if (iserror == ECC_STATE_NO_ERR) + return 0; + else if (iserror == ECC_STATE_TOO_MANY_ERRS) + { + printf("too many erros to be corrected!\n"); + return -1; + } + +#if 1 + numErrors = ((emif_addr->NANDFSR >> 16) & 0x3) + 1; + + /* Read the error address, error value and correct */ + for (i = 0; i < numErrors; i++) { + if (i > 1) { + errorAddress = + ((*(dv_reg_p)(NANDERRADD2) >> + (16 * (i & 1))) & 0x3FF); + errorAddress = ((512 + 7) - errorAddress); + errorValue = + ((*(dv_reg_p)(NANDERRVAL2) >> + (16 * (i & 1))) & 0xFF); + } else { + errorAddress = + ((*(dv_reg_p)(NANDERRADD1) >> + (16 * (i & 1))) & 0x3FF); + errorAddress = ((512 + 7) - errorAddress); + errorValue = + ((*(dv_reg_p)(NANDERRVAL1) >> + (16 * (i & 1))) & 0xFF); + } + /* xor the corrupt data with error value */ + if (errorAddress < 512) + page_data[errorAddress] ^= errorValue; + } +#else + numErrors = ((emif_addr->NANDFSR >> 16) & 0x3); + // bit 9:0 + errorAddress = 519 - (*(dv_reg_p)NANDERRADD1 & (0x3FF)); + errorValue = (*(dv_reg_p)NANDERRVAL1) & (0x3FF); + page_data[errorAddress] ^= (char)errorValue; + + if(numErrors == 0) + return numErrors; + else { + // bit 25:16 + errorAddress = 519 - ( (*(dv_reg_p)NANDERRADD1 & (0x3FF0000))>>16 ); + errorValue = (*(dv_reg_p)NANDERRVAL1) & (0x3FF); + page_data[errorAddress] ^= (char)errorValue; + + if(numErrors == 1) + return numErrors; + else { + // bit 9:0 + errorAddress = 519 - (*(dv_reg_p)NANDERRADD2 & (0x3FF)); + errorValue = (*(dv_reg_p)NANDERRVAL2) & (0x3FF); + page_data[errorAddress] ^= (char)errorValue; + + if (numErrors == 2) + return numErrors; + else { + // bit 25:16 + errorAddress = 519 - ( (*(dv_reg_p)NANDERRADD2 & (0x3FF0000))>>16 ); + errorValue = (*(dv_reg_p)NANDERRVAL2) & (0x3FF); + page_data[errorAddress] ^= (char)errorValue; + } + } + } +#endif + + return numErrors; +} + +static int nand_dm355_4bit_correct_data(struct mtd_info *mtd, u_char * dat, + u_char * read_ecc, u_char * calc_ecc) +{ + int r = 0; + + /* + * dat points to 512 bytes of data. read_ecc points to the start of the + * oob area for this subpage, so the ecc values start at offset 6. + * The calc_ecc pointer is not needed since our caclulated ECC is + * already latched in the hardware ECC generator. + */ +#if 1 + r = nand_dm355_4bit_compare_ecc(mtd, read_ecc + 6, dat); +#endif + + return r; +} +int board_nand_init(struct nand_chip *nand) +{ + nand->chip_delay = 0; + nand->eccmode = NAND_ECC_HW10_512; + nand->options = NAND_HWECC_SYNDROME | NAND_USE_FLASH_BBT; + nand->autooob = &nand_dm355_hw10_512_oobinfo; + nand->layout = nand_dm355_hw10_512_layout; + nand->calculate_ecc = nand_dm355_4bit_calculate_ecc; + nand->correct_data = nand_dm355_4bit_correct_data; + nand->enable_hwecc = nand_dm355_4bit_enable_hwecc; + nand->block_markbad = nand_dm355_hw10_512_block_markbad; + + /* Set address of hardware control function */ + nand->hwcontrol = nand_dm350evm_hwcontrol; + + + return 0; +} + +#else +#error "U-Boot legacy NAND support not available for DaVinci chips" +#endif +#endif /* CFG_USE_NAND */ diff --git a/cpu/arm926ejs/da8xx/reset.S b/cpu/arm926ejs/da8xx/reset.S new file mode 100644 index 00000000000..a687d44035c --- /dev/null +++ b/cpu/arm926ejs/da8xx/reset.S @@ -0,0 +1,77 @@ +/* + * Processor reset using WDT for TI TMS320DM644x SoC. + * + * Copyright (C) 2007 Sergey Kubushyn <ksi@koi8.net> + * + * ----------------------------------------------------- + * + * 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 + */ + +.globl reset_cpu +reset_cpu: + ldr r0, WDT_TGCR + mov r1, $0x08 + str r1, [r0] + ldr r1, [r0] + orr r1, r1, $0x03 + str r1, [r0] + mov r1, $0 + ldr r0, WDT_TIM12 + str r1, [r0] + ldr r0, WDT_TIM34 + str r1, [r0] + ldr r0, WDT_PRD12 + str r1, [r0] + ldr r0, WDT_PRD34 + str r1, [r0] + ldr r0, WDT_TCR + ldr r1, [r0] + orr r1, r1, $0x40 + str r1, [r0] + ldr r0, WDT_WDTCR + ldr r1, [r0] + orr r1, r1, $0x4000 + str r1, [r0] + ldr r1, WDTCR_VAL1 + str r1, [r0] + ldr r1, WDTCR_VAL2 + str r1, [r0] + nop + nop + nop + nop +reset_cpu_loop: + b reset_cpu_loop + +WDT_TGCR: + .word 0x01c21c24 +WDT_TIM12: + .word 0x01c21c10 +WDT_TIM34: + .word 0x01c21c14 +WDT_PRD12: + .word 0x01c21c18 +WDT_PRD34: + .word 0x01c21c1c +WDT_TCR: + .word 0x01c21c20 +WDT_WDTCR: + .word 0x01c21c28 +WDTCR_VAL1: + .word 0xa5c64000 +WDTCR_VAL2: + .word 0xda7e4000 diff --git a/cpu/arm926ejs/da8xx/timer.c b/cpu/arm926ejs/da8xx/timer.c new file mode 100644 index 00000000000..6c670f0b756 --- /dev/null +++ b/cpu/arm926ejs/da8xx/timer.c @@ -0,0 +1,148 @@ +/* + * (C) Copyright 2003 + * Texas Instruments <www.ti.com> + * + * (C) Copyright 2002 + * Sysgo Real-Time Solutions, GmbH <www.elinos.com> + * Marius Groeger <mgroeger@sysgo.de> + * + * (C) Copyright 2002 + * Sysgo Real-Time Solutions, GmbH <www.elinos.com> + * Alex Zuepke <azu@sysgo.de> + * + * (C) Copyright 2002-2004 + * Gary Jennejohn, DENX Software Engineering, <gj@denx.de> + * + * (C) Copyright 2004 + * Philippe Robin, ARM Ltd. <philippe.robin@arm.com> + * + * Copyright (C) 2007 Sergey Kubushyn <ksi@koi8.net> + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include <common.h> +#include <arm926ejs.h> + +typedef volatile struct { + u_int32_t pid12; + u_int32_t emumgt; + u_int32_t na1; + u_int32_t na2; + u_int32_t tim12; + u_int32_t tim34; + u_int32_t prd12; + u_int32_t prd34; + u_int32_t tcr; + u_int32_t tgcr; + u_int32_t wdtcr; +} davinci_timer; + +davinci_timer *timer = (davinci_timer *)CFG_TIMERBASE; + +#define TIMER_LOAD_VAL (CFG_HZ_CLOCK / CFG_HZ) +#define TIM_CLK_DIV 16 + +static ulong timestamp; +static ulong lastinc; + +int timer_init(void) +{ + /* We are using timer34 in unchained 32-bit mode, full speed */ + timer->tcr = 0x0; + timer->tgcr = 0x0; + timer->tgcr = 0x06 | ((TIM_CLK_DIV - 1) << 8); + timer->tim34 = 0x0; + timer->prd34 = TIMER_LOAD_VAL; + lastinc = 0; + timestamp = 0; + timer->tcr = 2 << 22; + + return(0); +} + +void reset_timer(void) +{ + timer->tcr = 0x0; + timer->tim34 = 0; + lastinc = 0; + timestamp = 0; + timer->tcr = 2 << 22; +} + +static ulong get_timer_raw(void) +{ + ulong now = timer->tim34; + + if (now >= lastinc) { + /* normal mode */ + timestamp += now - lastinc; + } else { + /* overflow ... */ + timestamp += now + TIMER_LOAD_VAL - lastinc; + } + lastinc = now; + return timestamp; +} + +ulong get_timer(ulong base) +{ + return((get_timer_raw() / (TIMER_LOAD_VAL / TIM_CLK_DIV)) - base); +} + +void set_timer(ulong t) +{ + timestamp = t; +} + +void udelay(unsigned long usec) +{ + ulong tmo; + ulong endtime; + signed long diff; + + tmo = CFG_HZ_CLOCK / 1000; + tmo *= usec; + tmo /= (1000 * TIM_CLK_DIV); + + endtime = get_timer_raw() + tmo; + + do { + ulong now = get_timer_raw(); + diff = endtime - now; + } while (diff >= 0); +} + +/* + * This function is derived from PowerPC code (read timebase as long long). + * On ARM it just returns the timer value. + */ +unsigned long long get_ticks(void) +{ + return(get_timer(0)); +} + +/* + * This function is derived from PowerPC code (timebase clock frequency). + * On ARM it returns the number of timer ticks per second. + */ +ulong get_tbclk(void) +{ + return CFG_HZ; +} diff --git a/cpu/at32ap/at32ap700x/gpio.c b/cpu/at32ap/at32ap700x/gpio.c index 859124a91f6..3da35d4fe23 100644 --- a/cpu/at32ap/at32ap700x/gpio.c +++ b/cpu/at32ap/at32ap700x/gpio.c @@ -21,8 +21,11 @@ */ #include <common.h> +#include <asm/io.h> + #include <asm/arch/chip-features.h> #include <asm/arch/gpio.h> +#include <asm/arch/memory-map.h> /* * Lots of small functions here. We depend on --gc-sections getting @@ -142,3 +145,43 @@ void gpio_enable_mmci(void) gpio_select_periph_A(GPIO_PIN_PA15, 0); /* DATA3 */ } #endif + +#ifdef AT32AP700x_CHIP_HAS_SPI +void gpio_enable_spi0(unsigned long cs_mask) +{ + u32 pa_mask = 0; + + gpio_select_periph_A(GPIO_PIN_PA0, 0); /* MISO */ + gpio_select_periph_A(GPIO_PIN_PA1, 0); /* MOSI */ + gpio_select_periph_A(GPIO_PIN_PA2, 0); /* SCK */ + + if (cs_mask & (1 << 0)) + pa_mask |= 1 << 3; /* NPCS0 */ + if (cs_mask & (1 << 1)) + pa_mask |= 1 << 4; /* NPCS1 */ + if (cs_mask & (1 << 2)) + pa_mask |= 1 << 5; /* NPCS2 */ + if (cs_mask & (1 << 3)) + pa_mask |= 1 << 20; /* NPCS3 */ + + __raw_writel(pa_mask, PIOA_BASE + 0x00); + __raw_writel(pa_mask, PIOA_BASE + 0x30); + __raw_writel(pa_mask, PIOA_BASE + 0x10); +} + +void gpio_enable_spi1(unsigned long cs_mask) +{ + gpio_select_periph_B(GPIO_PIN_PA0, 0); /* MISO */ + gpio_select_periph_B(GPIO_PIN_PB1, 0); /* MOSI */ + gpio_select_periph_B(GPIO_PIN_PB5, 0); /* SCK */ + + if (cs_mask & (1 << 0)) + gpio_select_periph_B(GPIO_PIN_PB2, 0); /* NPCS0 */ + if (cs_mask & (1 << 1)) + gpio_select_periph_B(GPIO_PIN_PB3, 0); /* NPCS1 */ + if (cs_mask & (1 << 2)) + gpio_select_periph_B(GPIO_PIN_PB4, 0); /* NPCS2 */ + if (cs_mask & (1 << 3)) + gpio_select_periph_A(GPIO_PIN_PA27, 0); /* NPCS3 */ +} +#endif diff --git a/cpu/blackfin/.gitignore b/cpu/blackfin/.gitignore index 0ec9d5672ed..e69de29bb2d 100644 --- a/cpu/blackfin/.gitignore +++ b/cpu/blackfin/.gitignore @@ -1 +0,0 @@ -bootrom-asm-offsets.[chs] diff --git a/cpu/nios/spi.c b/cpu/nios/spi.c index f37146b7939..6408180147a 100644 --- a/cpu/nios/spi.c +++ b/cpu/nios/spi.c @@ -63,10 +63,10 @@ static char quickhex (int i) return hex_digit[i]; } -static void memdump (void *pv, int num) +static void memdump (const void *pv, int num) { int i; - unsigned char *pc = (unsigned char *) pv; + const unsigned char *pc = (const unsigned char *) pv; for (i = 0; i < num; i++) printf ("%c%c ", quickhex (pc[i] >> 4), quickhex (pc[i] & 0x0f)); @@ -83,26 +83,64 @@ static void memdump (void *pv, int num) #endif /* DEBUG */ +struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs, + unsigned int max_hz, unsigned int mode) +{ + struct spi_slave *slave; + + if (!spi_cs_is_valid(bus, cs)) + return NULL; + + slave = malloc(sizeof(struct spi_slave)); + if (!slave) + return NULL; + + slave->bus = bus; + slave->cs = cs; + + /* TODO: Add support for different modes and speeds */ + + return slave; +} + +void spi_free_slave(struct spi_slave *slave) +{ + free(slave); +} + +int spi_claim_bus(struct spi_slave *slave) +{ + return 0; +} + +void spi_release_bus(struct spi_slave *slave) +{ + +} + /* * SPI transfer: * * See include/spi.h and http://www.altera.com/literature/ds/ds_nios_spi.pdf * for more informations. */ -int spi_xfer(spi_chipsel_type chipsel, int bitlen, uchar *dout, uchar *din) +int spi_xfer(struct spi_slave *slave, int bitlen, const void *dout, + void *din, unsigned long flags) { + const u8 *txd = dout; + u8 *rxd = din; int j; - DPRINT(("spi_xfer: chipsel %08X dout %08X din %08X bitlen %d\n", - (int)chipsel, *(uint *)dout, *(uint *)din, bitlen)); + DPRINT(("spi_xfer: slave %u:%u dout %08X din %08X bitlen %d\n", + slave->bus, slave->cs, *(uint *)dout, *(uint *)din, bitlen)); - memdump((void*)dout, (bitlen + 7) / 8); + memdump(dout, (bitlen + 7) / 8); - if(chipsel != NULL) { - chipsel(1); /* select the target chip */ - } + if (flags & SPI_XFER_BEGIN) + spi_cs_activate(slave); - if (bitlen > CFG_NIOS_SPIBITS) { /* leave chip select active */ + if (!(flags & SPI_XFER_END) || bitlen > CFG_NIOS_SPIBITS) { + /* leave chip select active */ spi->control |= NIOS_SPI_SSO; } @@ -114,11 +152,11 @@ int spi_xfer(spi_chipsel_type chipsel, int bitlen, uchar *dout, uchar *din) while ((spi->status & NIOS_SPI_TRDY) == 0) ; - spi->txdata = (unsigned)(dout[j]); + spi->txdata = (unsigned)(txd[j]); while ((spi->status & NIOS_SPI_RRDY) == 0) ; - din[j] = (unsigned char)(spi->rxdata & 0xff); + rxd[j] = (unsigned char)(spi->rxdata & 0xff); #elif (CFG_NIOS_SPIBITS == 16) j++, j++) { @@ -126,15 +164,15 @@ int spi_xfer(spi_chipsel_type chipsel, int bitlen, uchar *dout, uchar *din) while ((spi->status & NIOS_SPI_TRDY) == 0) ; if ((j+1) < ((bitlen + 7) / 8)) - spi->txdata = (unsigned)((dout[j] << 8) | dout[j+1]); + spi->txdata = (unsigned)((txd[j] << 8) | txd[j+1]); else - spi->txdata = (unsigned)(dout[j] << 8); + spi->txdata = (unsigned)(txd[j] << 8); while ((spi->status & NIOS_SPI_RRDY) == 0) ; - din[j] = (unsigned char)((spi->rxdata >> 8) & 0xff); + rxd[j] = (unsigned char)((spi->rxdata >> 8) & 0xff); if ((j+1) < ((bitlen + 7) / 8)) - din[j+1] = (unsigned char)(spi->rxdata & 0xff); + rxd[j+1] = (unsigned char)(spi->rxdata & 0xff); #else #error "*** unsupported value of CFG_NIOS_SPIBITS ***" @@ -142,15 +180,14 @@ int spi_xfer(spi_chipsel_type chipsel, int bitlen, uchar *dout, uchar *din) } - if (bitlen > CFG_NIOS_SPIBITS) { + if (bitlen > CFG_NIOS_SPIBITS && (flags & SPI_XFER_END)) { spi->control &= ~NIOS_SPI_SSO; } - if(chipsel != NULL) { - chipsel(0); /* deselect the target chip */ - } + if (flags & SPI_XFER_END) + spi_cs_deactivate(slave); - memdump((void*)din, (bitlen + 7) / 8); + memdump(din, (bitlen + 7) / 8); return 0; } diff --git a/disk/part.c b/disk/part.c index 316e2547399..fe90643206b 100644 --- a/disk/part.c +++ b/disk/part.c @@ -25,21 +25,22 @@ #include <command.h> #include <ide.h> #include <part.h> +#include <config_cmd_default.h> #undef PART_DEBUG #ifdef PART_DEBUG -#define PRINTF(fmt,args...) printf (fmt ,##args) +#define PRINTF(fmt,args...) printf (fmt ,##args) #else #define PRINTF(fmt,args...) #endif #if (defined(CONFIG_CMD_IDE) || \ - defined(CONFIG_CMD_SATA) || \ - defined(CONFIG_CMD_SCSI) || \ - defined(CONFIG_CMD_USB) || \ - defined(CONFIG_MMC) || \ - defined(CONFIG_SYSTEMACE) ) + defined(CONFIG_CMD_SATA) || \ + defined(CONFIG_CMD_SCSI) || \ + defined(CONFIG_CMD_USB) || \ + defined(CONFIG_MMC) || \ + defined(CONFIG_SYSTEMACE) ) struct block_drvr { char *name; @@ -91,11 +92,11 @@ block_dev_desc_t *get_dev(char* ifname, int dev) #endif #if (defined(CONFIG_CMD_IDE) || \ - defined(CONFIG_CMD_SATA) || \ - defined(CONFIG_CMD_SCSI) || \ - defined(CONFIG_CMD_USB) || \ - defined(CONFIG_MMC) || \ - defined(CONFIG_SYSTEMACE) ) + defined(CONFIG_CMD_SATA) || \ + defined(CONFIG_CMD_SCSI) || \ + defined(CONFIG_CMD_USB) || \ + defined(CONFIG_MMC) || \ + defined(CONFIG_SYSTEMACE) ) /* ------------------------------------------------------------------------- */ /* @@ -109,7 +110,7 @@ void dev_print (block_dev_desc_t *dev_desc) lbaint_t lba512; #endif - switch (dev_desc->type) { + switch (dev_desc->if_type) { case IF_TYPE_SCSI: printf ("(%d:%d) Vendor: %s Prod.: %s Rev: %s\n", dev_desc->target,dev_desc->lun, @@ -124,12 +125,18 @@ void dev_print (block_dev_desc_t *dev_desc) dev_desc->revision, dev_desc->product); break; + case IF_TYPE_USB: + printf ("Vendor: %s Rev: %s Prod: %s\n", + dev_desc->vendor, + dev_desc->revision, + dev_desc->product); + break; case DEV_TYPE_UNKNOWN: default: puts ("not available\n"); return; } - puts (" Type: "); + puts (" Type: "); if (dev_desc->removable) puts ("Removable "); switch (dev_desc->type & 0x1F) { @@ -159,46 +166,46 @@ void dev_print (block_dev_desc_t *dev_desc) lba512 = (lba * (dev_desc->blksz/512)); mb = (10 * lba512) / 2048; /* 2048 = (1024 * 1024) / 512 MB */ /* round to 1 digit */ - mb_quot = mb / 10; + mb_quot = mb / 10; mb_rem = mb - (10 * mb_quot); gb = mb / 1024; - gb_quot = gb / 10; + gb_quot = gb / 10; gb_rem = gb - (10 * gb_quot); #ifdef CONFIG_LBA48 if (dev_desc->lba48) - printf (" Supports 48-bit addressing\n"); + printf (" Supports 48-bit addressing\n"); #endif #if defined(CFG_64BIT_LBA) && defined(CFG_64BIT_VSPRINTF) - printf (" Capacity: %ld.%ld MB = %ld.%ld GB (%qd x %ld)\n", + printf (" Capacity: %ld.%ld MB = %ld.%ld GB (%qd x %ld)\n", mb_quot, mb_rem, gb_quot, gb_rem, lba, dev_desc->blksz); #else - printf (" Capacity: %ld.%ld MB = %ld.%ld GB (%ld x %ld)\n", + printf (" Capacity: %ld.%ld MB = %ld.%ld GB (%ld x %ld)\n", mb_quot, mb_rem, gb_quot, gb_rem, (ulong)lba, dev_desc->blksz); #endif } else { - puts (" Capacity: not available\n"); + puts (" Capacity: not available\n"); } } #endif #if (defined(CONFIG_CMD_IDE) || \ - defined(CONFIG_CMD_SATA) || \ - defined(CONFIG_CMD_SCSI) || \ - defined(CONFIG_CMD_USB) || \ - defined(CONFIG_MMC) || \ - defined(CONFIG_SYSTEMACE) ) + defined(CONFIG_CMD_SATA) || \ + defined(CONFIG_CMD_SCSI) || \ + defined(CONFIG_CMD_USB) || \ + defined(CONFIG_MMC) || \ + defined(CONFIG_SYSTEMACE) ) #if defined(CONFIG_MAC_PARTITION) || \ - defined(CONFIG_DOS_PARTITION) || \ - defined(CONFIG_ISO_PARTITION) || \ - defined(CONFIG_AMIGA_PARTITION) + defined(CONFIG_DOS_PARTITION) || \ + defined(CONFIG_ISO_PARTITION) || \ + defined(CONFIG_AMIGA_PARTITION) void init_part (block_dev_desc_t * dev_desc) { @@ -225,8 +232,8 @@ void init_part (block_dev_desc_t * dev_desc) #ifdef CONFIG_AMIGA_PARTITION if (test_part_amiga(dev_desc) == 0) { - dev_desc->part_type = PART_TYPE_AMIGA; - return; + dev_desc->part_type = PART_TYPE_AMIGA; + return; } #endif } @@ -265,12 +272,12 @@ int get_partition_info (block_dev_desc_t *dev_desc, int part #ifdef CONFIG_AMIGA_PARTITION case PART_TYPE_AMIGA: - if (get_partition_info_amiga(dev_desc, part, info) == 0) - { + if (get_partition_info_amiga(dev_desc, part, info) == 0) + { PRINTF ("## Valid Amiga partition found ##\n"); return (0); - } - break; + } + break; #endif default: break; @@ -337,10 +344,10 @@ void print_part (block_dev_desc_t * dev_desc) #ifdef CONFIG_AMIGA_PARTITION case PART_TYPE_AMIGA: - PRINTF ("## Testing for a valid Amiga partition ##\n"); - print_part_header ("AMIGA", dev_desc); - print_part_amiga (dev_desc); - return; + PRINTF ("## Testing for a valid Amiga partition ##\n"); + print_part_header ("AMIGA", dev_desc); + print_part_amiga (dev_desc); + return; #endif } puts ("## Unknown partition table\n"); diff --git a/disk/part_dos.c b/disk/part_dos.c index 4d778ec5b24..0bc8ba72043 100644 --- a/disk/part_dos.c +++ b/disk/part_dos.c @@ -36,28 +36,28 @@ #include "part_dos.h" #if (defined(CONFIG_CMD_IDE) || \ - defined(CONFIG_CMD_SATA) || \ - defined(CONFIG_CMD_SCSI) || \ - defined(CONFIG_CMD_USB) || \ - defined(CONFIG_MMC) || \ - defined(CONFIG_SYSTEMACE) ) && defined(CONFIG_DOS_PARTITION) + defined(CONFIG_CMD_SATA) || \ + defined(CONFIG_CMD_SCSI) || \ + defined(CONFIG_CMD_USB) || \ + defined(CONFIG_MMC) || \ + defined(CONFIG_SYSTEMACE) ) && defined(CONFIG_DOS_PARTITION) /* Convert char[4] in little endian format to the host format integer */ static inline int le32_to_int(unsigned char *le32) { - return ((le32[3] << 24) + - (le32[2] << 16) + - (le32[1] << 8) + - le32[0] + return ((le32[3] << 24) + + (le32[2] << 16) + + (le32[1] << 8) + + le32[0] ); } static inline int is_extended(int part_type) { - return (part_type == 0x5 || - part_type == 0xf || - part_type == 0x85); + return (part_type == 0x5 || + part_type == 0xf || + part_type == 0x85); } static void print_one_part (dos_partition_t *p, int ext_part_sector, int part_num) @@ -73,12 +73,12 @@ static void print_one_part (dos_partition_t *p, int ext_part_sector, int part_nu static int test_block_type(unsigned char *buffer) { if((buffer[DOS_PART_MAGIC_OFFSET + 0] != 0x55) || - (buffer[DOS_PART_MAGIC_OFFSET + 1] != 0xaa) ) { + (buffer[DOS_PART_MAGIC_OFFSET + 1] != 0xaa) ) { return (-1); } /* no DOS Signature at all */ if(strncmp((char *)&buffer[DOS_PBR_FSTYPE_OFFSET],"FAT",3)==0) return DOS_PBR; /* is PBR */ - return DOS_MBR; /* Is MBR */ + return DOS_MBR; /* Is MBR */ } @@ -87,14 +87,14 @@ int test_part_dos (block_dev_desc_t *dev_desc) unsigned char buffer[DEFAULT_SECTOR_SIZE]; if ((dev_desc->block_read(dev_desc->dev, 0, 1, (ulong *) buffer) != 1) || - (buffer[DOS_PART_MAGIC_OFFSET + 0] != 0x55) || - (buffer[DOS_PART_MAGIC_OFFSET + 1] != 0xaa) ) { + (buffer[DOS_PART_MAGIC_OFFSET + 0] != 0x55) || + (buffer[DOS_PART_MAGIC_OFFSET + 1] != 0xaa) ) { return (-1); } return (0); } -/* Print a partition that is relative to its Extended partition table +/* Print a partition that is relative to its Extended partition table */ static void print_partition_extended (block_dev_desc_t *dev_desc, int ext_part_sector, int relative, int part_num) @@ -116,7 +116,7 @@ static void print_partition_extended (block_dev_desc_t *dev_desc, int ext_part_s return; } if(i==DOS_PBR) { - printf (" 1\t\t 0\t%10ld\t%2x\n", + printf (" 1\t\t 0\t%10ld\t%2x\n", dev_desc->lba, buffer[DOS_PBR_MEDIA_TYPE_OFFSET]); return; } @@ -129,13 +129,13 @@ static void print_partition_extended (block_dev_desc_t *dev_desc, int ext_part_s */ if ((pt->sys_ind != 0) && - (ext_part_sector == 0 || !is_extended (pt->sys_ind)) ) { + (ext_part_sector == 0 || !is_extended (pt->sys_ind)) ) { print_one_part (pt, ext_part_sector, part_num); } /* Reverse engr the fdisk part# assignment rule! */ if ((ext_part_sector == 0) || - (pt->sys_ind != 0 && !is_extended (pt->sys_ind)) ) { + (pt->sys_ind != 0 && !is_extended (pt->sys_ind)) ) { part_num++; } } @@ -147,7 +147,7 @@ static void print_partition_extended (block_dev_desc_t *dev_desc, int ext_part_s int lba_start = le32_to_int (pt->start4) + relative; print_partition_extended (dev_desc, lba_start, - ext_part_sector == 0 ? lba_start + ext_part_sector == 0 ? lba_start : relative, part_num); } @@ -157,7 +157,7 @@ static void print_partition_extended (block_dev_desc_t *dev_desc, int ext_part_s } -/* Print a partition that is relative to its Extended partition table +/* Print a partition that is relative to its Extended partition table */ static int get_partition_info_extended (block_dev_desc_t *dev_desc, int ext_part_sector, int relative, int part_num, @@ -180,6 +180,9 @@ static int get_partition_info_extended (block_dev_desc_t *dev_desc, int ext_part return -1; } + if (((buffer[0] == 0xEB) && (buffer[2] == 0x90)) || (buffer[0] == 0xE9)) + return(-1); + /* Print all primary/logical partitions */ pt = (dos_partition_t *) (buffer + DOS_PART_TBL_OFFSET); for (i = 0; i < 4; i++, pt++) { @@ -188,11 +191,11 @@ static int get_partition_info_extended (block_dev_desc_t *dev_desc, int ext_part * are not in the MBR */ if ((pt->sys_ind != 0) && - (part_num == which_part) && - (is_extended(pt->sys_ind) == 0)) { + (part_num == which_part) && + (is_extended(pt->sys_ind) == 0)) { info->blksz = 512; info->start = ext_part_sector + le32_to_int (pt->start4); - info->size = le32_to_int (pt->size4); + info->size = le32_to_int (pt->size4); switch(dev_desc->if_type) { case IF_TYPE_IDE: case IF_TYPE_SATA: @@ -219,7 +222,7 @@ static int get_partition_info_extended (block_dev_desc_t *dev_desc, int ext_part /* Reverse engr the fdisk part# assignment rule! */ if ((ext_part_sector == 0) || - (pt->sys_ind != 0 && !is_extended (pt->sys_ind)) ) { + (pt->sys_ind != 0 && !is_extended (pt->sys_ind)) ) { part_num++; } } @@ -240,7 +243,7 @@ static int get_partition_info_extended (block_dev_desc_t *dev_desc, int ext_part void print_part_dos (block_dev_desc_t *dev_desc) { - printf ("Partition Start Sector Num Sectors Type\n"); + printf ("Partition Start Sector Num Sectors Type\n"); print_partition_extended (dev_desc, 0, 0, 1); } diff --git a/drivers/mtd/cfi_flash.c b/drivers/mtd/cfi_flash.c index 68ab55f8a5f..aaca81b01da 100644 --- a/drivers/mtd/cfi_flash.c +++ b/drivers/mtd/cfi_flash.c @@ -32,7 +32,7 @@ */ /* The DEBUG define must be before common to enable debugging */ -/* #define DEBUG */ +/* #define DEBUG */ #include <common.h> #include <asm/processor.h> @@ -162,6 +162,10 @@ static ulong bank_base[CFG_MAX_FLASH_BANKS] = CFG_FLASH_BANKS_LIST; flash_info_t flash_info[CFG_MAX_FLASH_BANKS]; /* FLASH chips info */ #endif +#ifdef CFG_FLASH_SPL_ACCESS +void board_flash_set_access(ulong bank_base, int banknum, flash_info_t* flash_info); +#endif + /* * Check if chip width is defined. If not, start detecting with 8bit. */ @@ -358,9 +362,9 @@ static inline uchar flash_read_uchar (flash_info_t * info, uint offset) cp = flash_map (info, 0, offset); #if defined(__LITTLE_ENDIAN) || defined(CFG_WRITE_SWAPPED_DATA) - retval = flash_read8(cp); + retval = info->read8(cp); #else - retval = flash_read8(cp + info->portwidth - 1); + retval = info->read8(cp + info->portwidth - 1); #endif flash_unmap (info, 0, offset, cp); return retval; @@ -374,7 +378,7 @@ static inline ushort flash_read_word (flash_info_t * info, uint offset) ushort *addr, retval; addr = flash_map (info, 0, offset); - retval = flash_read16 (addr); + retval = info->read16 (addr); flash_unmap (info, 0, offset, addr); return retval; } @@ -399,19 +403,19 @@ static ulong flash_read_long (flash_info_t * info, flash_sect_t sect, debug ("long addr is at %p info->portwidth = %d\n", addr, info->portwidth); for (x = 0; x < 4 * info->portwidth; x++) { - debug ("addr[%x] = 0x%x\n", x, flash_read8(addr + x)); + debug ("addr[%x] = 0x%x\n", x, info->read8(addr + x)); } #endif #if defined(__LITTLE_ENDIAN) || defined(CFG_WRITE_SWAPPED_DATA) - retval = ((flash_read8(addr) << 16) | - (flash_read8(addr + info->portwidth) << 24) | - (flash_read8(addr + 2 * info->portwidth)) | - (flash_read8(addr + 3 * info->portwidth) << 8)); + retval = ((info->read8(addr) << 16) | + (info->read8(addr + info->portwidth) << 24) | + (info->read8(addr + 2 * info->portwidth)) | + (info->read8(addr + 3 * info->portwidth) << 8)); #else - retval = ((flash_read8(addr + 2 * info->portwidth - 1) << 24) | - (flash_read8(addr + info->portwidth - 1) << 16) | - (flash_read8(addr + 4 * info->portwidth - 1) << 8) | - (flash_read8(addr + 3 * info->portwidth - 1))); + retval = ((info->read8(addr + 2 * info->portwidth - 1) << 24) | + (info->read8(addr + info->portwidth - 1) << 16) | + (info->read8(addr + 4 * info->portwidth - 1) << 8) | + (info->read8(addr + 3 * info->portwidth - 1))); #endif flash_unmap(info, sect, offset, addr); @@ -434,19 +438,19 @@ static void flash_write_cmd (flash_info_t * info, flash_sect_t sect, case FLASH_CFI_8BIT: debug ("fwc addr %p cmd %x %x 8bit x %d bit\n", addr, cmd, cword.c, info->chipwidth << CFI_FLASH_SHIFT_WIDTH); - flash_write8(cword.c, addr); + info->write8(cword.c, addr); break; case FLASH_CFI_16BIT: debug ("fwc addr %p cmd %x %4.4x 16bit x %d bit\n", addr, cmd, cword.w, info->chipwidth << CFI_FLASH_SHIFT_WIDTH); - flash_write16(cword.w, addr); + info->write16(cword.w, addr); break; case FLASH_CFI_32BIT: debug ("fwc addr %p cmd %x %8.8lx 32bit x %d bit\n", addr, cmd, cword.l, info->chipwidth << CFI_FLASH_SHIFT_WIDTH); - flash_write32(cword.l, addr); + info->write32(cword.l, addr); break; case FLASH_CFI_64BIT: #ifdef DEBUG @@ -460,7 +464,7 @@ static void flash_write_cmd (flash_info_t * info, flash_sect_t sect, info->chipwidth << CFI_FLASH_SHIFT_WIDTH); } #endif - flash_write64(cword.ll, addr); + info->write64(cword.ll, addr); break; } @@ -491,16 +495,16 @@ static int flash_isequal (flash_info_t * info, flash_sect_t sect, debug ("is= cmd %x(%c) addr %p ", cmd, cmd, addr); switch (info->portwidth) { case FLASH_CFI_8BIT: - debug ("is= %x %x\n", flash_read8(addr), cword.c); - retval = (flash_read8(addr) == cword.c); + debug ("is= %x %x\n", info->read8(addr), cword.c); + retval = (info->read8(addr) == cword.c); break; case FLASH_CFI_16BIT: - debug ("is= %4.4x %4.4x\n", flash_read16(addr), cword.w); - retval = (flash_read16(addr) == cword.w); + debug ("is= %4.4x %4.4x\n", info->read16(addr), cword.w); + retval = (info->read16(addr) == cword.w); break; case FLASH_CFI_32BIT: - debug ("is= %8.8lx %8.8lx\n", flash_read32(addr), cword.l); - retval = (flash_read32(addr) == cword.l); + debug ("is= %8.8lx %8.8lx\n", info->read32(addr), cword.l); + retval = (info->read32(addr) == cword.l); break; case FLASH_CFI_64BIT: #ifdef DEBUG @@ -508,12 +512,12 @@ static int flash_isequal (flash_info_t * info, flash_sect_t sect, char str1[20]; char str2[20]; - print_longlong (str1, flash_read64(addr)); + print_longlong (str1, info->read64(addr)); print_longlong (str2, cword.ll); debug ("is= %s %s\n", str1, str2); } #endif - retval = (flash_read64(addr) == cword.ll); + retval = (info->read64(addr) == cword.ll); break; default: retval = 0; @@ -537,16 +541,16 @@ static int flash_isset (flash_info_t * info, flash_sect_t sect, flash_make_cmd (info, cmd, &cword); switch (info->portwidth) { case FLASH_CFI_8BIT: - retval = ((flash_read8(addr) & cword.c) == cword.c); + retval = ((info->read8(addr) & cword.c) == cword.c); break; case FLASH_CFI_16BIT: - retval = ((flash_read16(addr) & cword.w) == cword.w); + retval = ((info->read16(addr) & cword.w) == cword.w); break; case FLASH_CFI_32BIT: - retval = ((flash_read32(addr) & cword.l) == cword.l); + retval = ((info->read32(addr) & cword.l) == cword.l); break; case FLASH_CFI_64BIT: - retval = ((flash_read64(addr) & cword.ll) == cword.ll); + retval = ((info->read64(addr) & cword.ll) == cword.ll); break; default: retval = 0; @@ -570,20 +574,20 @@ static int flash_toggle (flash_info_t * info, flash_sect_t sect, flash_make_cmd (info, cmd, &cword); switch (info->portwidth) { case FLASH_CFI_8BIT: - retval = ((flash_read8(addr) & cword.c) != - (flash_read8(addr) & cword.c)); + retval = ((info->read8(addr) & cword.c) != + (info->read8(addr) & cword.c)); break; case FLASH_CFI_16BIT: - retval = ((flash_read16(addr) & cword.w) != - (flash_read16(addr) & cword.w)); + retval = ((info->read16(addr) & cword.w) != + (info->read16(addr) & cword.w)); break; case FLASH_CFI_32BIT: - retval = ((flash_read32(addr) & cword.l) != - (flash_read32(addr) & cword.l)); + retval = ((info->read32(addr) & cword.l) != + (info->read32(addr) & cword.l)); break; case FLASH_CFI_64BIT: - retval = ((flash_read64(addr) & cword.ll) != - (flash_read64(addr) & cword.ll)); + retval = ((info->read64(addr) & cword.ll) != + (info->read64(addr) & cword.ll)); break; default: retval = 0; @@ -768,16 +772,16 @@ static int flash_write_cfiword (flash_info_t * info, ulong dest, /* Check if Flash is (sufficiently) erased */ switch (info->portwidth) { case FLASH_CFI_8BIT: - flag = ((flash_read8(dstaddr) & cword.c) == cword.c); + flag = ((info->read8(dstaddr) & cword.c) == cword.c); break; case FLASH_CFI_16BIT: - flag = ((flash_read16(dstaddr) & cword.w) == cword.w); + flag = ((info->read16(dstaddr) & cword.w) == cword.w); break; case FLASH_CFI_32BIT: - flag = ((flash_read32(dstaddr) & cword.l) == cword.l); + flag = ((info->read32(dstaddr) & cword.l) == cword.l); break; case FLASH_CFI_64BIT: - flag = ((flash_read64(dstaddr) & cword.ll) == cword.ll); + flag = ((info->read64(dstaddr) & cword.ll) == cword.ll); break; default: flag = 0; @@ -809,16 +813,16 @@ static int flash_write_cfiword (flash_info_t * info, ulong dest, switch (info->portwidth) { case FLASH_CFI_8BIT: - flash_write8(cword.c, dstaddr); + info->write8(cword.c, dstaddr); break; case FLASH_CFI_16BIT: - flash_write16(cword.w, dstaddr); + info->write16(cword.w, dstaddr); break; case FLASH_CFI_32BIT: - flash_write32(cword.l, dstaddr); + info->write32(cword.l, dstaddr); break; case FLASH_CFI_64BIT: - flash_write64(cword.ll, dstaddr); + info->write64(cword.ll, dstaddr); break; } @@ -870,23 +874,23 @@ static int flash_write_cfibuffer (flash_info_t * info, ulong dest, uchar * cp, while ((cnt-- > 0) && (flag == 0)) { switch (info->portwidth) { case FLASH_CFI_8BIT: - flag = ((flash_read8(dst2) & flash_read8(src)) == - flash_read8(src)); + flag = ((info->read8(dst2) & info->read8(src)) == + info->read8(src)); src += 1, dst2 += 1; break; case FLASH_CFI_16BIT: - flag = ((flash_read16(dst2) & flash_read16(src)) == - flash_read16(src)); + flag = ((info->read16(dst2) & info->read16(src)) == + info->read16(src)); src += 2, dst2 += 2; break; case FLASH_CFI_32BIT: - flag = ((flash_read32(dst2) & flash_read32(src)) == - flash_read32(src)); + flag = ((info->read32(dst2) & info->read32(src)) == + info->read32(src)); src += 4, dst2 += 4; break; case FLASH_CFI_64BIT: - flag = ((flash_read64(dst2) & flash_read64(src)) == - flash_read64(src)); + flag = ((info->read64(dst2) & info->read64(src)) == + info->read64(src)); src += 8, dst2 += 8; break; } @@ -915,19 +919,19 @@ static int flash_write_cfibuffer (flash_info_t * info, ulong dest, uchar * cp, while (cnt-- > 0) { switch (info->portwidth) { case FLASH_CFI_8BIT: - flash_write8(flash_read8(src), dst); + info->write8(info->read8(src), dst); src += 1, dst += 1; break; case FLASH_CFI_16BIT: - flash_write16(flash_read16(src), dst); + info->write16(info->read16(src), dst); src += 2, dst += 2; break; case FLASH_CFI_32BIT: - flash_write32(flash_read32(src), dst); + info->write32(info->read32(src), dst); src += 4, dst += 4; break; case FLASH_CFI_64BIT: - flash_write64(flash_read64(src), dst); + info->write64(info->read64(src), dst); src += 8, dst += 8; break; default: @@ -958,25 +962,25 @@ static int flash_write_cfibuffer (flash_info_t * info, ulong dest, uchar * cp, switch (info->portwidth) { case FLASH_CFI_8BIT: while (cnt-- > 0) { - flash_write8(flash_read8(src), dst); + info->write8(info->read8(src), dst); src += 1, dst += 1; } break; case FLASH_CFI_16BIT: while (cnt-- > 0) { - flash_write16(flash_read16(src), dst); + info->write16(info->read16(src), dst); src += 2, dst += 2; } break; case FLASH_CFI_32BIT: while (cnt-- > 0) { - flash_write32(flash_read32(src), dst); + info->write32(info->read32(src), dst); src += 4, dst += 4; } break; case FLASH_CFI_64BIT: while (cnt-- > 0) { - flash_write64(flash_read64(src), dst); + info->write64(info->read64(src), dst); src += 8, dst += 8; } break; @@ -1240,14 +1244,14 @@ int write_buff (flash_info_t * info, uchar * src, ulong addr, ulong cnt) cword.l = 0; p = map_physmem(wp, info->portwidth, MAP_NOCACHE); for (i = 0; i < aln; ++i) - flash_add_byte (info, &cword, flash_read8(p + i)); + flash_add_byte (info, &cword, info->read8(p + i)); for (; (i < info->portwidth) && (cnt > 0); i++) { flash_add_byte (info, &cword, *src++); cnt--; } for (; (cnt == 0) && (i < info->portwidth); ++i) - flash_add_byte (info, &cword, flash_read8(p + i)); + flash_add_byte (info, &cword, info->read8(p + i)); rc = flash_write_cfiword (info, wp, cword); unmap_physmem(p, info->portwidth); @@ -1315,7 +1319,7 @@ int write_buff (flash_info_t * info, uchar * src, ulong addr, ulong cnt) --cnt; } for (; i < info->portwidth; ++i) - flash_add_byte (info, &cword, flash_read8(p + i)); + flash_add_byte (info, &cword, info->read8(p + i)); unmap_physmem(p, info->portwidth); return flash_write_cfiword (info, wp, cword); @@ -1888,6 +1892,29 @@ unsigned long flash_init (void) for (i = 0; i < CFG_MAX_FLASH_BANKS; ++i) { flash_info[i].flash_id = FLASH_UNKNOWN; + /* flash read and write routines board specific attention */ +#ifdef CFG_FLASH_SPL_ACCESS + board_flash_set_access(bank_base[i], i, &flash_info[i]); +#endif + + if(!flash_info[i].write8) + flash_info[i].write8 = flash_write8; + if(!flash_info[i].write16) + flash_info[i].write16 = flash_write16; + if(!flash_info[i].write32) + flash_info[i].write32 = flash_write32; + if(!flash_info[i].write64) + flash_info[i].write64 = flash_write64; + + if(!flash_info[i].read8) + flash_info[i].read8 = flash_read8; + if(!flash_info[i].read16) + flash_info[i].read16 = flash_read16; + if(!flash_info[i].read32) + flash_info[i].read32 = flash_read32; + if(!flash_info[i].read64) + flash_info[i].read64 = flash_read64; + if (!flash_detect_legacy (bank_base[i], i)) flash_get_size (bank_base[i], i); size += flash_info[i].size; @@ -1947,6 +1974,7 @@ unsigned long flash_init (void) } } #endif /* CFG_FLASH_PROTECTION */ + } /* Monitor protection ON by default */ diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index 2da1d4621c8..1a9cd65473c 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -5,14 +5,14 @@ * This is the generic MTD driver for NAND flash devices. It should be * capable of working with almost all NAND chips currently available. * Basic support for AG-AND chips is provided. - * + * * Additional technical information is available on * http://www.linux-mtd.infradead.org/tech/nand.html - * + * * Copyright (C) 2000 Steven J. Hill (sjhill@realitydiluted.com) * 2002 Thomas Gleixner (tglx@linutronix.de) * - * 02-08-2004 tglx: support for strange chips, which cannot auto increment + * 02-08-2004 tglx: support for strange chips, which cannot auto increment * pages on read / read_oob * * 03-17-2004 tglx: Check ready before auto increment check. Simon Bayes @@ -21,16 +21,38 @@ * Make reads over block boundaries work too * * 04-14-2004 tglx: first working version for 2k page size chips - * + * * 05-19-2004 tglx: Basic support for Renesas AG-AND chips * * 09-24-2004 tglx: add support for hardware controllers (e.g. ECC) shared * among multiple independend devices. Suggestions and initial patch * from Ben Dooks <ben-mtd@fluff.org> * - * Credits: - * David Woodhouse for adding multichip support + * 12-05-2004 dmarlin: add workaround for Renesas AG-AND chips "disturb" issue. + * Basically, any block not rewritten may lose data when surrounding blocks + * are rewritten many times. JFFS2 ensures this doesn't happen for blocks + * it uses, but the Bad Block Table(s) may not be rewritten. To ensure they + * do not lose data, force them to be rewritten when some of the surrounding + * blocks are erased. Rather than tracking a specific nearby block (which + * could itself go bad), use a page address 'mask' to select several blocks + * in the same area, and rewrite the BBT when any of them are erased. + * + * 01-03-2005 dmarlin: added support for the device recovery command sequence for Renesas + * AG-AND chips. If there was a sudden loss of power during an erase operation, + * a "device recovery" operation must be performed when power is restored + * to ensure correct operation. + * + * 01-20-2005 dmarlin: added support for optional hardware specific callback routine to + * perform extra error status checks on erase and write failures. This required + * adding a wrapper function for nand_read_ecc. + * + * 08-20-2005 vwool: suspend/resume added + * + * 11-01-2005: vwool: NAND page layouts introduces for HW ECC handling * + * Credits: + * David Woodhouse for adding multichip support + * * Aleph One Ltd. and Toby Churchill Ltd. for supporting the * rework for 2K page size chips * @@ -41,7 +63,7 @@ * The AG-AND chips have nice features for speed improvement, * which are not supported yet. Read / program 4 pages in one go. * - * $Id: nand_base.c,v 1.126 2004/12/13 11:22:25 lavinen Exp $ + * $Id: nand_base.c,v 1.145 2005/05/31 20:32:53 gleixner Exp $ * * 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 @@ -107,23 +129,15 @@ static struct nand_oobinfo nand_oob_64 = { .useecc = MTD_NANDECC_AUTOPLACE, .eccbytes = 24, .eccpos = { - 40, 41, 42, 43, 44, 45, 46, 47, - 48, 49, 50, 51, 52, 53, 54, 55, + 40, 41, 42, 43, 44, 45, 46, 47, + 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63}, .oobfree = { {2, 38} } }; -/* This is used for padding purposes in nand_write_oob */ -static u_char ffchars[] = { - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, -}; +/* This is used for padding purposes in nand_write_oob/nand_write_oob_hwecc */ +#define FFCHARS_SIZE 2048 +static u_char ffchars[FFCHARS_SIZE]; /* * NAND low-level MTD interface functions @@ -154,19 +168,19 @@ static void nand_sync (struct mtd_info *mtd); static int nand_write_page (struct mtd_info *mtd, struct nand_chip *this, int page, u_char *oob_buf, struct nand_oobinfo *oobsel, int mode); #ifdef CONFIG_MTD_NAND_VERIFY_WRITE -static int nand_verify_pages (struct mtd_info *mtd, struct nand_chip *this, int page, int numpages, +static int nand_verify_pages (struct mtd_info *mtd, struct nand_chip *this, int page, int numpages, u_char *oob_buf, struct nand_oobinfo *oobsel, int chipnr, int oobmode); #else #define nand_verify_pages(...) (0) #endif - + static void nand_get_device (struct nand_chip *this, struct mtd_info *mtd, int new_state); /** * nand_release_device - [GENERIC] release chip * @mtd: MTD device structure - * - * Deselect, release chip lock and wake up anyone waiting on the device + * + * Deselect, release chip lock and wake up anyone waiting on the device */ /* XXX U-BOOT XXX */ #if 0 @@ -176,11 +190,20 @@ static void nand_release_device (struct mtd_info *mtd) /* De-select the NAND device */ this->select_chip(mtd, -1); - /* Do we have a hardware controller ? */ + if (this->controller) { + /* Release the controller and the chip */ spin_lock(&this->controller->lock); this->controller->active = NULL; + this->state = FL_READY; + wake_up(&this->controller->wq); spin_unlock(&this->controller->lock); + } else { + /* Release the chip */ + spin_lock(&this->chip_lock); + this->state = FL_READY; + wake_up(&this->wq); + spin_unlock(&this->chip_lock); } /* Release the chip */ spin_lock (&this->chip_lock); @@ -225,7 +248,7 @@ static void nand_write_byte(struct mtd_info *mtd, u_char byte) * nand_read_byte16 - [DEFAULT] read one byte endianess aware from the chip * @mtd: MTD device structure * - * Default read function for 16bit buswith with + * Default read function for 16bit buswith with * endianess conversion */ static u_char nand_read_byte16(struct mtd_info *mtd) @@ -252,7 +275,7 @@ static void nand_write_byte16(struct mtd_info *mtd, u_char byte) * nand_read_word - [DEFAULT] read one word from the chip * @mtd: MTD device structure * - * Default read function for 16bit buswith without + * Default read function for 16bit buswith without * endianess conversion */ static u16 nand_read_word(struct mtd_info *mtd) @@ -266,7 +289,7 @@ static u16 nand_read_word(struct mtd_info *mtd) * @mtd: MTD device structure * @word: data word to write * - * Default write function for 16bit buswith without + * Default write function for 16bit buswith without * endianess conversion */ static void nand_write_word(struct mtd_info *mtd, u16 word) @@ -287,7 +310,7 @@ static void nand_select_chip(struct mtd_info *mtd, int chip) struct nand_chip *this = mtd->priv; switch(chip) { case -1: - this->hwcontrol(mtd, NAND_CTL_CLRNCE); + this->hwcontrol(mtd, NAND_CTL_CLRNCE); break; case 0: this->hwcontrol(mtd, NAND_CTL_SETNCE); @@ -316,7 +339,7 @@ static void nand_write_buf(struct mtd_info *mtd, const u_char *buf, int len) } /** - * nand_read_buf - [DEFAULT] read chip data into buffer + * nand_read_buf - [DEFAULT] read chip data into buffer * @mtd: MTD device structure * @buf: buffer to store date * @len: number of bytes to read @@ -333,7 +356,7 @@ static void nand_read_buf(struct mtd_info *mtd, u_char *buf, int len) } /** - * nand_verify_buf - [DEFAULT] Verify chip data against buffer + * nand_verify_buf - [DEFAULT] Verify chip data against buffer * @mtd: MTD device structure * @buf: buffer containing the data to compare * @len: number of bytes to compare @@ -366,14 +389,14 @@ static void nand_write_buf16(struct mtd_info *mtd, const u_char *buf, int len) struct nand_chip *this = mtd->priv; u16 *p = (u16 *) buf; len >>= 1; - + for (i=0; i<len; i++) writew(p[i], this->IO_ADDR_W); - + } /** - * nand_read_buf16 - [DEFAULT] read chip data into buffer + * nand_read_buf16 - [DEFAULT] read chip data into buffer * @mtd: MTD device structure * @buf: buffer to store date * @len: number of bytes to read @@ -392,7 +415,7 @@ static void nand_read_buf16(struct mtd_info *mtd, u_char *buf, int len) } /** - * nand_verify_buf16 - [DEFAULT] Verify chip data against buffer + * nand_verify_buf16 - [DEFAULT] Verify chip data against buffer * @mtd: MTD device structure * @buf: buffer containing the data to compare * @len: number of bytes to compare @@ -419,17 +442,16 @@ static int nand_verify_buf16(struct mtd_info *mtd, const u_char *buf, int len) * @ofs: offset from device start * @getchip: 0, if the chip is already selected * - * Check, if the block is bad. + * Check, if the block is bad. */ static int nand_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip) { int page, chipnr, res = 0; struct nand_chip *this = mtd->priv; u16 bad; - - page = (int)(ofs >> this->page_shift) & this->pagemask; - + if (getchip) { + page = (int)(ofs >> this->page_shift); chipnr = (int)(ofs >> this->chip_shift); /* Grab the lock and see if the device is available */ @@ -437,25 +459,26 @@ static int nand_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip) /* Select the NAND device */ this->select_chip(mtd, chipnr); - } + } else + page = (int) ofs; if (this->options & NAND_BUSWIDTH_16) { - this->cmdfunc (mtd, NAND_CMD_READOOB, this->badblockpos & 0xFE, page); + this->cmdfunc (mtd, NAND_CMD_READOOB, this->badblockpos & 0xFE, page & this->pagemask); bad = cpu_to_le16(this->read_word(mtd)); if (this->badblockpos & 0x1) - bad >>= 1; + bad >>= 8; if ((bad & 0xFF) != 0xff) res = 1; } else { - this->cmdfunc (mtd, NAND_CMD_READOOB, this->badblockpos, page); + this->cmdfunc (mtd, NAND_CMD_READOOB, this->badblockpos, page & this->pagemask); if (this->read_byte(mtd) != 0xff) res = 1; } - + if (getchip) { /* Deselect and wake up anyone waiting on the device */ nand_release_device(mtd); - } + } return res; } @@ -474,33 +497,34 @@ static int nand_default_block_markbad(struct mtd_info *mtd, loff_t ofs) u_char buf[2] = {0, 0}; size_t retlen; int block; - + /* Get block number */ block = ((int) ofs) >> this->bbt_erase_shift; - this->bbt[block >> 2] |= 0x01 << ((block & 0x03) << 1); + if (this->bbt) + this->bbt[block >> 2] |= 0x01 << ((block & 0x03) << 1); /* Do we have a flash based bad block table ? */ if (this->options & NAND_USE_FLASH_BBT) return nand_update_bbt (mtd, ofs); - + /* We write two bytes, so we dont have to mess with 16 bit access */ ofs += mtd->oobsize + (this->badblockpos & ~0x01); return nand_write_oob (mtd, ofs , 2, &retlen, buf); } -/** +/** * nand_check_wp - [GENERIC] check if the chip is write protected * @mtd: MTD device structure - * Check, if the device is write protected + * Check, if the device is write protected * - * The function expects, that the device is already selected + * The function expects, that the device is already selected */ static int nand_check_wp (struct mtd_info *mtd) { struct nand_chip *this = mtd->priv; /* Check the WP bit */ this->cmdfunc (mtd, NAND_CMD_STATUS, -1, -1); - return (this->read_byte(mtd) & 0x80) ? 0 : 1; + return (this->read_byte(mtd) & NAND_STATUS_WP) ? 0 : 1; } /** @@ -516,10 +540,10 @@ static int nand_check_wp (struct mtd_info *mtd) static int nand_block_checkbad (struct mtd_info *mtd, loff_t ofs, int getchip, int allowbbt) { struct nand_chip *this = mtd->priv; - + if (!this->bbt) return this->block_bad(mtd, ofs, getchip); - + /* Return info from the table */ return nand_isbad_bbt (mtd, ofs, allowbbt); } @@ -584,13 +608,13 @@ static void nand_command (struct mtd_info *mtd, unsigned command, int column, in /* Latch in address */ this->hwcontrol(mtd, NAND_CTL_CLRALE); } - - /* - * program and erase have their own busy handlers + + /* + * program and erase have their own busy handlers * status and sequential in needs no delay */ switch (command) { - + case NAND_CMD_PAGEPROG: case NAND_CMD_ERASE1: case NAND_CMD_ERASE2: @@ -599,27 +623,26 @@ static void nand_command (struct mtd_info *mtd, unsigned command, int column, in return; case NAND_CMD_RESET: - if (this->dev_ready) + if (this->dev_ready) break; udelay(this->chip_delay); this->hwcontrol(mtd, NAND_CTL_SETCLE); this->write_byte(mtd, NAND_CMD_STATUS); this->hwcontrol(mtd, NAND_CTL_CLRCLE); - while ( !(this->read_byte(mtd) & 0x40)); + while ( !(this->read_byte(mtd) & NAND_STATUS_READY)); return; - /* This applies to read commands */ + /* This applies to read commands */ default: - /* + /* * If we don't have access to the busy pin, we apply the given * command delay */ if (!this->dev_ready) { udelay (this->chip_delay); return; - } + } } - /* Apply this short delay always to ensure that we do wait tWB in * any case on any machine. */ ndelay (100); @@ -648,12 +671,12 @@ static void nand_command_lp (struct mtd_info *mtd, unsigned command, int column, column += mtd->oobblock; command = NAND_CMD_READ0; } - - + + /* Begin command latch cycle */ this->hwcontrol(mtd, NAND_CTL_SETCLE); /* Write out the command to the device. */ - this->write_byte(mtd, command); + this->write_byte(mtd, (command & 0xff)); /* End command latch cycle */ this->hwcontrol(mtd, NAND_CTL_CLRCLE); @@ -667,7 +690,7 @@ static void nand_command_lp (struct mtd_info *mtd, unsigned command, int column, column >>= 1; this->write_byte(mtd, column & 0xff); this->write_byte(mtd, column >> 8); - } + } if (page_addr != -1) { this->write_byte(mtd, (unsigned char) (page_addr & 0xff)); this->write_byte(mtd, (unsigned char) ((page_addr >> 8) & 0xff)); @@ -678,30 +701,41 @@ static void nand_command_lp (struct mtd_info *mtd, unsigned command, int column, /* Latch in address */ this->hwcontrol(mtd, NAND_CTL_CLRALE); } - - /* - * program and erase have their own busy handlers - * status and sequential in needs no delay - */ + + /* + * program and erase have their own busy handlers + * status, sequential in, and deplete1 need no delay + */ switch (command) { - + case NAND_CMD_CACHEDPROG: case NAND_CMD_PAGEPROG: case NAND_CMD_ERASE1: case NAND_CMD_ERASE2: case NAND_CMD_SEQIN: case NAND_CMD_STATUS: + case NAND_CMD_DEPLETE1: return; + /* + * read error status commands require only a short delay + */ + case NAND_CMD_STATUS_ERROR: + case NAND_CMD_STATUS_ERROR0: + case NAND_CMD_STATUS_ERROR1: + case NAND_CMD_STATUS_ERROR2: + case NAND_CMD_STATUS_ERROR3: + udelay(this->chip_delay); + return; case NAND_CMD_RESET: - if (this->dev_ready) + if (this->dev_ready) break; udelay(this->chip_delay); this->hwcontrol(mtd, NAND_CTL_SETCLE); this->write_byte(mtd, NAND_CMD_STATUS); this->hwcontrol(mtd, NAND_CTL_CLRCLE); - while ( !(this->read_byte(mtd) & 0x40)); + while ( !(this->read_byte(mtd) & NAND_STATUS_READY)); return; case NAND_CMD_READ0: @@ -712,23 +746,23 @@ static void nand_command_lp (struct mtd_info *mtd, unsigned command, int column, /* End command latch cycle */ this->hwcontrol(mtd, NAND_CTL_CLRCLE); /* Fall through into ready check */ - - /* This applies to read commands */ + + /* This applies to read commands */ default: - /* + /* * If we don't have access to the busy pin, we apply the given * command delay */ if (!this->dev_ready) { udelay (this->chip_delay); return; - } + } } /* Apply this short delay always to ensure that we do wait tWB in * any case on any machine. */ ndelay (100); - /* wait until command is processed */ + while (!this->dev_ready(mtd)); } @@ -736,7 +770,7 @@ static void nand_command_lp (struct mtd_info *mtd, unsigned command, int column, * nand_get_device - [GENERIC] Get chip for selected access * @this: the nand chip descriptor * @mtd: MTD device structure - * @new_state: the state which is requested + * @new_state: the state which is requested * * Get the device and lock it for exclusive access */ @@ -744,37 +778,38 @@ static void nand_command_lp (struct mtd_info *mtd, unsigned command, int column, #if 0 static void nand_get_device (struct nand_chip *this, struct mtd_info *mtd, int new_state) { - struct nand_chip *active = this; - + struct nand_chip *active; + spinlock_t *lock; + wait_queue_head_t *wq; DECLARE_WAITQUEUE (wait, current); - /* - * Grab the lock and see if the device is available - */ + lock = (this->controller) ? &this->controller->lock : &this->chip_lock; + wq = (this->controller) ? &this->controller->wq : &this->wq; retry: + active = this; + spin_lock(lock); + /* Hardware controller shared among independend devices */ if (this->controller) { - spin_lock (&this->controller->lock); if (this->controller->active) active = this->controller->active; else this->controller->active = this; - spin_unlock (&this->controller->lock); } - - if (active == this) { - spin_lock (&this->chip_lock); - if (this->state == FL_READY) { - this->state = new_state; - spin_unlock (&this->chip_lock); - return; - } + if (active == this && this->state == FL_READY) { + this->state = new_state; + spin_unlock(lock); + return 0; + } + if (new_state == FL_PM_SUSPENDED) { + spin_unlock(lock); + return (this->state == FL_PM_SUSPENDED) ? 0 : -EAGAIN; } - set_current_state (TASK_UNINTERRUPTIBLE); - add_wait_queue (&active->wq, &wait); - spin_unlock (&active->chip_lock); - schedule (); - remove_wait_queue (&active->wq, &wait); + set_current_state(TASK_UNINTERRUPTIBLE); + add_wait_queue(wq, &wait); + spin_unlock(lock); + schedule(); + remove_wait_queue(wq, &wait); goto retry; } #else @@ -788,7 +823,7 @@ static void nand_get_device (struct nand_chip *this, struct mtd_info *mtd, int n * @state: state to select the max. timeout value * * Wait for command done. This applies to erase and program only - * Erase can take up to 400ms and program up to 20ms according to + * Erase can take up to 400ms and program up to 20ms according to * general NAND and SmartMedia specs * */ @@ -796,9 +831,10 @@ static void nand_get_device (struct nand_chip *this, struct mtd_info *mtd, int n #if 0 static int nand_wait(struct mtd_info *mtd, struct nand_chip *this, int state) { + unsigned long timeo = jiffies; int status; - + if (state == FL_ERASING) timeo += (HZ * 400) / 1000; else @@ -810,37 +846,42 @@ static int nand_wait(struct mtd_info *mtd, struct nand_chip *this, int state) if ((state == FL_ERASING) && (this->options & NAND_IS_AND)) this->cmdfunc (mtd, NAND_CMD_STATUS_MULTI, -1, -1); - else + else this->cmdfunc (mtd, NAND_CMD_STATUS, -1, -1); - while (time_before(jiffies, timeo)) { + while (time_before(jiffies, timeo)) { /* Check, if we were interrupted */ if (this->state != state) return 0; if (this->dev_ready) { if (this->dev_ready(mtd)) - break; + break; } else { if (this->read_byte(mtd) & NAND_STATUS_READY) break; } - yield (); + cond_resched(); } status = (int) this->read_byte(mtd); return status; - - return 0; } #else static int nand_wait(struct mtd_info *mtd, struct nand_chip *this, int state) { unsigned long timeo; - +#if 0 if (state == FL_ERASING) timeo = (CFG_HZ * 400) / 1000; else timeo = (CFG_HZ * 20) / 1000; +#endif + + if (state == FL_ERASING) + timeo = (CFG_HZ_CLOCK * 400) / 1000; + else + timeo = (CFG_HZ_CLOCK * 20) / 1000; + if ((state == FL_ERASING) && (this->options & NAND_IS_AND)) this->cmdfunc(mtd, NAND_CMD_STATUS_MULTI, -1, -1); @@ -887,19 +928,19 @@ static int nand_wait(struct mtd_info *mtd, struct nand_chip *this, int state) * * Cached programming is not supported yet. */ -static int nand_write_page (struct mtd_info *mtd, struct nand_chip *this, int page, +static int nand_write_page (struct mtd_info *mtd, struct nand_chip *this, int page, u_char *oob_buf, struct nand_oobinfo *oobsel, int cached) { - int i, status; - u_char ecc_code[32]; + int i, oobidx, status; + u_char ecc_code[40]; int eccmode = oobsel->useecc ? this->eccmode : NAND_ECC_NONE; - uint *oob_config = oobsel->eccpos; + int *oob_config = oobsel->eccpos; int datidx = 0, eccidx = 0, eccsteps = this->eccsteps; int eccbytes = 0; - + /* FIXME: Enable cached programming */ cached = 0; - + /* Send command to begin auto page programming */ this->cmdfunc (mtd, NAND_CMD_SEQIN, 0x00, page); @@ -908,9 +949,44 @@ static int nand_write_page (struct mtd_info *mtd, struct nand_chip *this, int pa /* No ecc, write all */ case NAND_ECC_NONE: printk (KERN_WARNING "Writing data without ECC to NAND-FLASH is not recommended\n"); - this->write_buf(mtd, this->data_poi, mtd->oobblock); - break; + if (!this->layout) { + this->write_buf(mtd, this->data_poi, mtd->oobblock); + this->write_buf(mtd, oob_buf, mtd->oobsize); + break; + } + /* + * Since we have a page layout, we must observe the layout to + * position data and oob correctly even though we aren't + * calculating ECC. + */ + for (oobidx = 0; eccsteps; eccsteps--) { + int j = 0; + for (; this->layout[j].length; j++) { + int len = this->layout[j].length; + int oidx = oobidx; + switch (this->layout[j].type) { + case ITEM_TYPE_DATA: + this->write_buf(mtd, &this->data_poi[datidx], this->layout[j].length); + datidx += len; + break; + case ITEM_TYPE_ECC: + case ITEM_TYPE_OOB: + if (this->options & NAND_BUSWIDTH_16) { + if (oidx & 1) { + oidx--; + len++; + } + if (len & 1) + len--; + } + this->write_buf(mtd, &oob_buf[oidx], len); + oobidx += len; + break; + } + } + } + break; /* Software ecc 3/256, write all */ case NAND_ECC_SOFT: for (; eccsteps; eccsteps--) { @@ -920,49 +996,106 @@ static int nand_write_page (struct mtd_info *mtd, struct nand_chip *this, int pa datidx += this->eccsize; } this->write_buf(mtd, this->data_poi, mtd->oobblock); + this->write_buf(mtd, oob_buf, mtd->oobsize); break; default: eccbytes = this->eccbytes; - for (; eccsteps; eccsteps--) { - /* enable hardware ecc logic for write */ - this->enable_hwecc(mtd, NAND_ECC_WRITE); - this->write_buf(mtd, &this->data_poi[datidx], this->eccsize); - this->calculate_ecc(mtd, &this->data_poi[datidx], ecc_code); - for (i = 0; i < eccbytes; i++, eccidx++) - oob_buf[oob_config[eccidx]] = ecc_code[i]; - /* If the hardware ecc provides syndromes then - * the ecc code must be written immediately after - * the data bytes (words) */ + + if (! this->layout) { + for (; eccsteps; eccsteps--) { + /* enable hardware ecc logic for write */ + this->enable_hwecc(mtd, NAND_ECC_WRITE); + this->write_buf(mtd, &this->data_poi[datidx], this->eccsize); + this->calculate_ecc(mtd, &this->data_poi[datidx], ecc_code); + for (i = 0; i < eccbytes; i++, eccidx++) + oob_buf[oob_config[eccidx]] = ecc_code[i]; + /* If the hardware ecc provides syndromes then + * the ecc code must be written immidiately after + * the data bytes (words) */ + if (this->options & NAND_HWECC_SYNDROME) + this->write_buf(mtd, ecc_code, eccbytes); + datidx += this->eccsize; + } + if (this->options & NAND_HWECC_SYNDROME) - this->write_buf(mtd, ecc_code, eccbytes); - datidx += this->eccsize; + this->write_buf(mtd, &oob_buf[oobsel->eccbytes], mtd->oobsize - + oobsel->eccbytes); + else + this->write_buf(mtd, oob_buf, mtd->oobsize); + + + break; + } + + for (oobidx = 0; eccsteps; eccsteps--) { + int j = 0, last_datidx = datidx, last_oobidx; + for (; this->layout[j].length; j++) { + int len = this->layout[j].length; + int oidx = oobidx; + switch (this->layout[j].type) { + case ITEM_TYPE_DATA: + this->enable_hwecc(mtd, NAND_ECC_WRITE); + this->write_buf(mtd, &this->data_poi[datidx], this->layout[j].length); + datidx += len; + break; + case ITEM_TYPE_ECC: + this->enable_hwecc(mtd, NAND_ECC_WRITESYN); + this->calculate_ecc(mtd, &this->data_poi[last_datidx], &ecc_code[eccidx]); + for (last_oobidx = oobidx; oobidx < last_oobidx + len; oobidx++, eccidx++) + oob_buf[oobidx] = ecc_code[eccidx]; + if (this->options & NAND_BUSWIDTH_16) { + if (oidx & 1) { + oidx--; + len++; + } + if (len & 1) + len--; + } + this->write_buf(mtd, &oob_buf[oidx], len); + break; + case ITEM_TYPE_OOB: + this->enable_hwecc(mtd, NAND_ECC_WRITEOOB); + if (this->options & NAND_BUSWIDTH_16) { + if (oidx & 1) { + oidx--; + len++; + } + if (len & 1) + len--; + } + this->write_buf(mtd, &oob_buf[oidx], len); + oobidx += len; + break; + } + } + } break; } - - /* Write out OOB data */ - if (this->options & NAND_HWECC_SYNDROME) - this->write_buf(mtd, &oob_buf[oobsel->eccbytes], mtd->oobsize - oobsel->eccbytes); - else - this->write_buf(mtd, oob_buf, mtd->oobsize); - + /* Send command to actually program the data */ this->cmdfunc (mtd, cached ? NAND_CMD_CACHEDPROG : NAND_CMD_PAGEPROG, -1, -1); if (!cached) { /* call wait ready function */ status = this->waitfunc (mtd, this, FL_WRITING); + + /* See if operation failed and additional status checks are available */ + if ((status & NAND_STATUS_FAIL) && (this->errstat)) { + status = this->errstat(mtd, this, FL_WRITING, status, page); + } + /* See if device thinks it succeeded */ - if (status & 0x01) { + if (status & NAND_STATUS_FAIL) { DEBUG (MTD_DEBUG_LEVEL0, "%s: " "Failed write, page 0x%08x, ", __FUNCTION__, page); return -EIO; } } else { /* FIXME: Implement cached programming ! */ /* wait until cache is ready*/ - /* status = this->waitfunc (mtd, this, FL_CACHEDRPG); */ + // status = this->waitfunc (mtd, this, FL_CACHEDRPG); } - return 0; + return 0; } #ifdef CONFIG_MTD_NAND_VERIFY_WRITE @@ -978,19 +1111,19 @@ static int nand_write_page (struct mtd_info *mtd, struct nand_chip *this, int pa * @oobmode: 1 = full buffer verify, 0 = ecc only * * The NAND device assumes that it is always writing to a cleanly erased page. - * Hence, it performs its internal write verification only on bits that + * Hence, it performs its internal write verification only on bits that * transitioned from 1 to 0. The device does NOT verify the whole page on a - * byte by byte basis. It is possible that the page was not completely erased - * or the page is becoming unusable due to wear. The read with ECC would catch - * the error later when the ECC page check fails, but we would rather catch + * byte by byte basis. It is possible that the page was not completely erased + * or the page is becoming unusable due to wear. The read with ECC would catch + * the error later when the ECC page check fails, but we would rather catch * it early in the page write stage. Better to write no data than invalid data. */ -static int nand_verify_pages (struct mtd_info *mtd, struct nand_chip *this, int page, int numpages, +static int nand_verify_pages (struct mtd_info *mtd, struct nand_chip *this, int page, int numpages, u_char *oob_buf, struct nand_oobinfo *oobsel, int chipnr, int oobmode) { int i, j, datidx = 0, oobofs = 0, res = -EIO; int eccsteps = this->eccsteps; - int hweccbytes; + int hweccbytes; u_char oobdata[64]; hweccbytes = (this->options & NAND_HWECC_SYNDROME) ? (oobsel->eccbytes / eccsteps) : 0; @@ -1030,7 +1163,7 @@ static int nand_verify_pages (struct mtd_info *mtd, struct nand_chip *this, int if (oobsel->useecc != MTD_NANDECC_OFF && !hweccbytes) { int ecccnt = oobsel->eccbytes; - + for (i = 0; i < ecccnt; i++) { int idx = oobsel->eccpos[i]; if (oobdata[idx] != oob_buf[oobofs + idx] ) { @@ -1040,20 +1173,20 @@ static int nand_verify_pages (struct mtd_info *mtd, struct nand_chip *this, int goto out; } } - } + } } oobofs += mtd->oobsize - hweccbytes * eccsteps; page++; numpages--; - /* Apply delay or wait for ready/busy pin + /* Apply delay or wait for ready/busy pin * Do this before the AUTOINCR check, so no problems * arise if a chip which does auto increment * is marked as NOAUTOINCR by the board driver. * Do this also before returning, so the chip is * ready for the next command. */ - if (!this->dev_ready) + if (!this->dev_ready) udelay (this->chip_delay); else while (!this->dev_ready(mtd)); @@ -1061,40 +1194,41 @@ static int nand_verify_pages (struct mtd_info *mtd, struct nand_chip *this, int /* All done, return happy */ if (!numpages) return 0; - - - /* Check, if the chip supports auto page increment */ + + + /* Check, if the chip supports auto page increment */ if (!NAND_CANAUTOINCR(this)) this->cmdfunc (mtd, NAND_CMD_READ0, 0x00, page); } - /* + /* * Terminate the read command. We come here in case of an error * So we must issue a reset command. */ -out: +out: this->cmdfunc (mtd, NAND_CMD_RESET, -1, -1); return res; } #endif /** - * nand_read - [MTD Interface] MTD compability function for nand_read_ecc + * nand_read - [MTD Interface] MTD compability function for nand_do_read_ecc * @mtd: MTD device structure * @from: offset to read from * @len: number of bytes to read * @retlen: pointer to variable to store the number of read bytes * @buf: the databuffer to put data * - * This function simply calls nand_read_ecc with oob buffer and oobsel = NULL -*/ + * This function simply calls nand_do_read_ecc with oob buffer and oobsel = NULL + * and flags = 0xff + */ static int nand_read (struct mtd_info *mtd, loff_t from, size_t len, size_t * retlen, u_char * buf) { - return nand_read_ecc (mtd, from, len, retlen, buf, NULL, NULL); + return nand_do_read_ecc (mtd, from, len, retlen, buf, NULL, &mtd->oobinfo, 0xff); } /** - * nand_read_ecc - [MTD Interface] Read data with ECC + * nand_read_ecc - [MTD Interface] MTD compability function for nand_do_read_ecc * @mtd: MTD device structure * @from: offset to read from * @len: number of bytes to read @@ -1103,20 +1237,47 @@ static int nand_read (struct mtd_info *mtd, loff_t from, size_t len, size_t * re * @oob_buf: filesystem supplied oob data buffer * @oobsel: oob selection structure * - * NAND read with ECC + * This function simply calls nand_do_read_ecc with flags = 0xff */ static int nand_read_ecc (struct mtd_info *mtd, loff_t from, size_t len, size_t * retlen, u_char * buf, u_char * oob_buf, struct nand_oobinfo *oobsel) { + /* use userspace supplied oobinfo, if zero */ + if (oobsel == NULL) + oobsel = &mtd->oobinfo; + return nand_do_read_ecc(mtd, from, len, retlen, buf, oob_buf, oobsel, 0xff); +} + + +/** + * nand_do_read_ecc - [MTD Interface] Read data with ECC + * @mtd: MTD device structure + * @from: offset to read from + * @len: number of bytes to read + * @retlen: pointer to variable to store the number of read bytes + * @buf: the databuffer to put data + * @oob_buf: filesystem supplied oob data buffer (can be NULL) + * @oobsel: oob selection structure + * @flags: flag to indicate if nand_get_device/nand_release_device should be preformed + * and how many corrected error bits are acceptable: + * bits 0..7 - number of tolerable errors + * bit 8 - 0 == do not get/release chip, 1 == get/release chip + * + * NAND read with ECC + */ +int nand_do_read_ecc (struct mtd_info *mtd, loff_t from, size_t len, + size_t * retlen, u_char * buf, u_char * oob_buf, + struct nand_oobinfo *oobsel, int flags) +{ + int i, j, col, realpage, page, end, ecc, chipnr, sndcmd = 1; - int read = 0, oob = 0, ecc_status = 0, ecc_failed = 0; + int read = 0, oob = 0, oobidx, ecc_status = 0, ecc_failed = 0, eccidx; struct nand_chip *this = mtd->priv; u_char *data_poi, *oob_data = oob_buf; u_char ecc_calc[32]; u_char ecc_code[32]; - int eccmode, eccsteps; - unsigned *oob_config; - int datidx; + int eccmode, eccsteps; + int *oob_config, datidx; int blockcheck = (1 << (this->phys_erase_shift - this->page_shift)) - 1; int eccbytes; int compareecc = 1; @@ -1133,16 +1294,13 @@ static int nand_read_ecc (struct mtd_info *mtd, loff_t from, size_t len, } /* Grab the lock and see if the device is available */ - nand_get_device (this, mtd ,FL_READING); - - /* use userspace supplied oobinfo, if zero */ - if (oobsel == NULL) - oobsel = &mtd->oobinfo; + if (flags & NAND_GET_DEVICE) + nand_get_device (this, mtd, FL_READING); /* Autoplace of oob data ? Use the default placement scheme */ if (oobsel->useecc == MTD_NANDECC_AUTOPLACE) oobsel = this->autooob; - + eccmode = oobsel->useecc ? this->eccmode : NAND_ECC_NONE; oob_config = oobsel->eccpos; @@ -1160,28 +1318,28 @@ static int nand_read_ecc (struct mtd_info *mtd, loff_t from, size_t len, end = mtd->oobblock; ecc = this->eccsize; eccbytes = this->eccbytes; - + if ((eccmode == NAND_ECC_NONE) || (this->options & NAND_HWECC_SYNDROME)) compareecc = 0; oobreadlen = mtd->oobsize; - if (this->options & NAND_HWECC_SYNDROME) + if (this->options & NAND_HWECC_SYNDROME) oobreadlen -= oobsel->eccbytes; /* Loop until all data read */ while (read < len) { - + int aligned = (!col && (len - read) >= end); - /* + /* * If the read is not page aligned, we have to read into data buffer * due to ecc, else we read into return buffer direct */ if (aligned) data_poi = &buf[read]; - else + else data_poi = this->data_buf; - - /* Check, if we have this page in the buffer + + /* Check, if we have this page in the buffer * * FIXME: Make it work when we must provide oob data too, * check the usage of data_buf oob field @@ -1197,7 +1355,7 @@ static int nand_read_ecc (struct mtd_info *mtd, loff_t from, size_t len, if (sndcmd) { this->cmdfunc (mtd, NAND_CMD_READ0, 0x00, page); sndcmd = 0; - } + } /* get oob area, if we have no oob buffer from fs-driver */ if (!oob_buf || oobsel->useecc == MTD_NANDECC_AUTOPLACE || @@ -1205,7 +1363,7 @@ static int nand_read_ecc (struct mtd_info *mtd, loff_t from, size_t len, oob_data = &this->data_buf[end]; eccsteps = this->eccsteps; - + switch (eccmode) { case NAND_ECC_NONE: { /* No ECC, Read in a page */ /* XXX U-BOOT XXX */ @@ -1218,50 +1376,151 @@ static int nand_read_ecc (struct mtd_info *mtd, loff_t from, size_t len, #else puts("Reading data from NAND FLASH without ECC is not recommended\n"); #endif - this->read_buf(mtd, data_poi, end); + if (!this->layout) { + this->read_buf(mtd, data_poi, end); + break; + } + + /* + * Since we have a page layout, we must observe the + * layout to position data and oob correctly even though + * we aren't calculating ECC. + */ + for (oobidx = 0, datidx = 0; eccsteps; eccsteps--) { + for (j = 0; this->layout[j].length; j++) { + int len = this->layout[j].length; + int oidx = oobidx; + switch (this->layout[j].type) { + case ITEM_TYPE_DATA: + DEBUG (MTD_DEBUG_LEVEL3, "%s: reading %d bytes of data\n", __FUNCTION__, this->layout[j].length); + this->read_buf(mtd, &data_poi[datidx], len); + datidx += this->layout[j].length; + break; + case ITEM_TYPE_ECC: + case ITEM_TYPE_OOB: + DEBUG (MTD_DEBUG_LEVEL3, "%s: reading %d oob bytes\n", __FUNCTION__, this->layout[j].length); + if (this->options & NAND_BUSWIDTH_16) { + if (oidx & 1) { + oidx--; + len++; + } + if (len & 1) + len--; + } + this->read_buf(mtd, &oob_data[oidx], len); + oobidx += this->layout[j].length; + break; + } + } + } break; } - case NAND_ECC_SOFT: /* Software ECC 3/256: Read in a page + oob data */ this->read_buf(mtd, data_poi, end); - for (i = 0, datidx = 0; eccsteps; eccsteps--, i+=3, datidx += ecc) + for (i = 0, datidx = 0; eccsteps; eccsteps--, i+=3, datidx += ecc) this->calculate_ecc(mtd, &data_poi[datidx], &ecc_calc[i]); - break; + this->read_buf(mtd, &oob_data[mtd->oobsize - oobreadlen], oobreadlen); + break; default: - for (i = 0, datidx = 0; eccsteps; eccsteps--, i+=eccbytes, datidx += ecc) { - this->enable_hwecc(mtd, NAND_ECC_READ); - this->read_buf(mtd, &data_poi[datidx], ecc); - - /* HW ecc with syndrome calculation must read the - * syndrome from flash immidiately after the data */ - if (!compareecc) { - /* Some hw ecc generators need to know when the - * syndrome is read from flash */ - this->enable_hwecc(mtd, NAND_ECC_READSYN); - this->read_buf(mtd, &oob_data[i], eccbytes); - /* We calc error correction directly, it checks the hw - * generator for an error, reads back the syndrome and - * does the error correction on the fly */ - if (this->correct_data(mtd, &data_poi[datidx], &oob_data[i], &ecc_code[i]) == -1) { - DEBUG (MTD_DEBUG_LEVEL0, "nand_read_ecc: " - "Failed ECC read, page 0x%08x on chip %d\n", page, chipnr); - ecc_failed++; + if (! this->layout) { + for (i = 0, datidx = 0; eccsteps; eccsteps--, i+=eccbytes, datidx += ecc) { + this->enable_hwecc(mtd, NAND_ECC_READ); + this->read_buf(mtd, &data_poi[datidx], ecc); + + /* HW ecc with syndrome calculation must read the + * syndrome from flash immidiately after the data */ + if (!compareecc) { + /* Some hw ecc generators need to know when the + * syndrome is read from flash */ + this->enable_hwecc(mtd, NAND_ECC_READSYN); + this->read_buf(mtd, &oob_data[i], eccbytes); + /* We calc error correction directly, it checks the hw + * generator for an error, reads back the syndrome and + * does the error correction on the fly */ + ecc_status = this->correct_data(mtd, &data_poi[datidx], &oob_data[i], &ecc_code[i]); + if ((ecc_status == -1) || (ecc_status > (flags & 0xff))) { + DEBUG (MTD_DEBUG_LEVEL0, "nand_read_ecc: " + "Failed ECC read, page 0x%08x on chip %d\n", page, chipnr); + ecc_failed++; + } + } else { + this->calculate_ecc(mtd, &data_poi[datidx], &ecc_calc[i]); + } + } + + this->read_buf(mtd, &oob_data[mtd->oobsize - oobreadlen], oobreadlen); + + break; + } + + for (oobidx = 0, datidx = 0, eccidx = 0; eccsteps; eccsteps--) { + int last_datidx = datidx, last_oobidx = oobidx; + for (j = 0; this->layout[j].length; j++) { + int len = this->layout[j].length; + int oidx = oobidx; + switch (this->layout[j].type) { + case ITEM_TYPE_DATA: + DEBUG (MTD_DEBUG_LEVEL3, "%s: reading %d bytes of data\n", __FUNCTION__, this->layout[j].length); + this->enable_hwecc(mtd, NAND_ECC_READ); + this->read_buf(mtd, &data_poi[datidx], len); + datidx += this->layout[j].length; + break; + + case ITEM_TYPE_ECC: + DEBUG (MTD_DEBUG_LEVEL3, "%s: reading %d ecc bytes\n", __FUNCTION__, this->layout[j].length); + /* let the particular driver decide whether to read ECC */ + this->enable_hwecc(mtd, NAND_ECC_READSYN); + if (this->options & NAND_BUSWIDTH_16) { + if (oidx & 1) { + oidx--; + len++; + } + if (len & 1) + len--; + } + + this->read_buf(mtd, &oob_data[oidx], len); + if (!compareecc) { + /* We calc error correction directly, it checks the hw + * generator for an error, reads back the syndrome and + * does the error correction on the fly */ + ecc_status = this->correct_data(mtd, &data_poi[last_datidx], &oob_data[last_oobidx], &ecc_code[eccidx]); + if ((ecc_status == -1) || (ecc_status > (flags & 0xff))) { + DEBUG (MTD_DEBUG_LEVEL0, "nand_read_ecc: " + "Failed ECC read, page 0x%08x on chip %d\n", page, chipnr); + ecc_failed++; + } + } else + this->calculate_ecc(mtd, &data_poi[last_datidx], &ecc_calc[eccidx]); + oobidx += this->layout[j].length; + eccidx += this->layout[j].length; + break; + case ITEM_TYPE_OOB: + DEBUG (MTD_DEBUG_LEVEL3, "%s: reading %d free oob bytes\n", __FUNCTION__, this->layout[j].length); + this->enable_hwecc(mtd, NAND_ECC_READOOB); + if (this->options & NAND_BUSWIDTH_16) { + if (oidx & 1) { + oidx--; + len++; + } + if (len & 1) + len--; + } + + this->read_buf(mtd, &oob_data[oidx], len); + oobidx += this->layout[j].length; + break; } - } else { - this->calculate_ecc(mtd, &data_poi[datidx], &ecc_calc[i]); } } - break; + break; } - /* read oobdata */ - this->read_buf(mtd, &oob_data[mtd->oobsize - oobreadlen], oobreadlen); - /* Skip ECC check, if not requested (ECC_NONE or HW_ECC with syndromes) */ if (!compareecc) - goto readoob; - + goto readoob; + /* Pick the ECC bytes out of the oob data */ for (j = 0; j < oobsel->eccbytes; j++) ecc_code[j] = oob_data[oob_config[j]]; @@ -1269,24 +1528,24 @@ static int nand_read_ecc (struct mtd_info *mtd, loff_t from, size_t len, /* correct data, if neccecary */ for (i = 0, j = 0, datidx = 0; i < this->eccsteps; i++, datidx += ecc) { ecc_status = this->correct_data(mtd, &data_poi[datidx], &ecc_code[j], &ecc_calc[j]); - + /* Get next chunk of ecc bytes */ j += eccbytes; - - /* Check, if we have a fs supplied oob-buffer, + + /* Check, if we have a fs supplied oob-buffer, * This is the legacy mode. Used by YAFFS1 * Should go away some day */ - if (oob_buf && oobsel->useecc == MTD_NANDECC_PLACE) { + if (oob_buf && oobsel->useecc == MTD_NANDECC_PLACE) { int *p = (int *)(&oob_data[mtd->oobsize]); p[i] = ecc_status; } - - if (ecc_status == -1) { + + if ((ecc_status == -1) || (ecc_status > (flags & 0xff))) { DEBUG (MTD_DEBUG_LEVEL0, "nand_read_ecc: " "Failed ECC read, page 0x%08x\n", page); ecc_failed++; } - } + } readoob: /* check, if we have a fs supplied oob-buffer */ @@ -1296,13 +1555,12 @@ static int nand_read_ecc (struct mtd_info *mtd, loff_t from, size_t len, case MTD_NANDECC_AUTOPLACE: case MTD_NANDECC_AUTOPL_USR: /* Walk through the autoplace chunks */ - for (i = 0, j = 0; j < mtd->oobavail; i++) { + for (i = 0; oobsel->oobfree[i][1]; i++) { int from = oobsel->oobfree[i][0]; int num = oobsel->oobfree[i][1]; - memcpy(&oob_buf[oob+j], &oob_data[from], num); - j+= num; + memcpy(&oob_buf[oob], &oob_data[from], num); + oob += num; } - oob += mtd->oobavail; break; case MTD_NANDECC_PLACE: /* YAFFS1 legacy mode */ @@ -1313,25 +1571,25 @@ static int nand_read_ecc (struct mtd_info *mtd, loff_t from, size_t len, } readdata: /* Partial page read, transfer data into fs buffer */ - if (!aligned) { + if (!aligned) { for (j = col; j < end && read < len; j++) buf[read++] = data_poi[j]; - this->pagebuf = realpage; - } else + this->pagebuf = realpage; + } else read += mtd->oobblock; - /* Apply delay or wait for ready/busy pin + /* Apply delay or wait for ready/busy pin * Do this before the AUTOINCR check, so no problems * arise if a chip which does auto increment * is marked as NOAUTOINCR by the board driver. */ - if (!this->dev_ready) + if (!this->dev_ready) udelay (this->chip_delay); else - while (!this->dev_ready(mtd)); - + while (!this->dev_ready(mtd)); + if (read == len) - break; + break; /* For subsequent reads align to page boundary. */ col = 0; @@ -1345,15 +1603,16 @@ static int nand_read_ecc (struct mtd_info *mtd, loff_t from, size_t len, this->select_chip(mtd, -1); this->select_chip(mtd, chipnr); } - /* Check, if the chip supports auto page increment - * or if we have hit a block boundary. - */ + /* Check, if the chip supports auto page increment + * or if we have hit a block boundary. + */ if (!NAND_CANAUTOINCR(this) || !(page & blockcheck)) - sndcmd = 1; + sndcmd = 1; } /* Deselect and wake up anyone waiting on the device */ - nand_release_device(mtd); + if (flags & NAND_GET_DEVICE) + nand_release_device(mtd); /* * Return success, if no ECC failures, else -EBADMSG @@ -1385,7 +1644,7 @@ static int nand_read_oob (struct mtd_info *mtd, loff_t from, size_t len, size_t /* Shift to get page */ page = (int)(from >> this->page_shift); chipnr = (int)(from >> this->chip_shift); - + /* Mask to get column */ col = from & (mtd->oobsize - 1); @@ -1407,7 +1666,7 @@ static int nand_read_oob (struct mtd_info *mtd, loff_t from, size_t len, size_t /* Send the read command */ this->cmdfunc (mtd, NAND_CMD_READOOB, col, page & this->pagemask); - /* + /* * Read the data, if we read more than one page * oob data, let the device transfer the data ! */ @@ -1417,16 +1676,16 @@ static int nand_read_oob (struct mtd_info *mtd, loff_t from, size_t len, size_t thislen = min_t(int, thislen, len); this->read_buf(mtd, &buf[i], thislen); i += thislen; - - /* Apply delay or wait for ready/busy pin + + /* Apply delay or wait for ready/busy pin * Do this before the AUTOINCR check, so no problems * arise if a chip which does auto increment * is marked as NOAUTOINCR by the board driver. */ - if (!this->dev_ready) + if (!this->dev_ready) udelay (this->chip_delay); else - while (!this->dev_ready(mtd)); + while (!this->dev_ready(mtd)); /* Read more ? */ if (i < len) { @@ -1439,17 +1698,166 @@ static int nand_read_oob (struct mtd_info *mtd, loff_t from, size_t len, size_t this->select_chip(mtd, -1); this->select_chip(mtd, chipnr); } - - /* Check, if the chip supports auto page increment - * or if we have hit a block boundary. - */ + + /* Check, if the chip supports auto page increment + * or if we have hit a block boundary. + */ if (!NAND_CANAUTOINCR(this) || !(page & blockcheck)) { /* For subsequent page reads set offset to 0 */ - this->cmdfunc (mtd, NAND_CMD_READOOB, 0x0, page & this->pagemask); + this->cmdfunc (mtd, NAND_CMD_READOOB, 0x0, page & this->pagemask); + } + } + } + + /* Deselect and wake up anyone waiting on the device */ + nand_release_device(mtd); + + /* Return happy */ + *retlen = len; + return 0; +} + +/** + * nand_read_oob_hwecc - [MTD Interface] NAND read out-of-band (HW ECC) + * @mtd: MTD device structure + * @from: offset to read from + * @len: number of bytes to read + * @retlen: pointer to variable to store the number of read bytes + * @oob_buf: the databuffer to put data + * + * NAND read out-of-band data from the spare area + * W/o assumptions that are valid only for software ECC + */ +static int nand_read_oob_hwecc (struct mtd_info *mtd, loff_t from, size_t len, size_t * retlen, u_char * oob_buf) +{ + int i, col, page, chipnr, nleft; + struct nand_chip *this = mtd->priv; + + DEBUG (MTD_DEBUG_LEVEL3, "%s: from = 0x%08x, len = %i\n", __FUNCTION__, + (unsigned int) from, (int) len); + + /* Shift to get page */ + page = (int)(from >> this->page_shift); + chipnr = (int)(from >> this->chip_shift); + + /* Mask to get column */ + col = from & (mtd->oobsize - 1); + + /* Initialize return length value */ + *retlen = 0; + + /* Do not allow reads past end of device */ + if ((from + len) > mtd->size) { + DEBUG (MTD_DEBUG_LEVEL0, "%s: Attempt read beyond end of device\n", + __FUNCTION__); + *retlen = 0; + return -EINVAL; + } + + /* Grab the lock and see if the device is available */ + nand_get_device (this, mtd , FL_READING); + + /* Select the NAND device */ + this->select_chip(mtd, chipnr); + + /* + * Read the data, if we read more than one page + * oob data, let the device transfer the data ! + */ + i = 0; + nleft = len; + while (i < len) { + int ooboff, pageoff, eccsteps; + + eccsteps = this->eccsteps; + for (ooboff = 0, pageoff = 0; eccsteps; eccsteps--) { + int j, first, last, thislen; + /* + * In the following we assume that each item (data, ECC, + * and OOB) in the layout has an even length such as + * would be required for a 16-bit-wide NAND. This + * assumption allows us to handle 16-bit-wide chips with + * no special cases versus 8-bit-wide chips. + */ + for (j = 0; this->layout[j].length; j++) { + thislen = this->layout[j].length; + /* are we done yet? */ + if (i == len) + goto finished; + switch (this->layout[j].type) { + case ITEM_TYPE_DATA: + pageoff += thislen; + continue; + case ITEM_TYPE_ECC: + case ITEM_TYPE_OOB: + /* + * Calculate the intersection of the oob + * data with this layout item. + */ + first = max(ooboff, col); + last = min(ooboff + thislen, + col + nleft); + if (first >= last) { + /* no intersection */ + break; + } + this->cmdfunc(mtd, NAND_CMD_READ0, + pageoff + + ((first - ooboff) & ~1), + page & this->pagemask); + /* handle an odd offset */ + if (first & 1) { + oob_buf[i++] = cpu_to_le16( + this->read_word(mtd)) + >> 8; + ++first; + } + if (last - first > 1) { + int n = ((last - first) & ~1); + /* read an even number of oob bytes */ + this->read_buf(mtd, oob_buf + i, n); + i += n; + first += n; + } + /* handle an odd length */ + if (last - first == 1) { + oob_buf[i++] = cpu_to_le16( + this->read_word(mtd)) + & 0xff; + ++first; + } + break; + } + pageoff += thislen; + ooboff += thislen; + } + } + + /* + * Apply delay or wait for ready/busy pin in case the chip is + * auto-incrementing to the next page. + */ + if (!this->dev_ready) + udelay (this->chip_delay); + else + while (!this->dev_ready(mtd)); + + /* Read more ? */ + if (i < len) { + page++; + col = 0; + nleft = len - i; + + /* Check, if we cross a chip boundary */ + if (!(page & this->pagemask)) { + chipnr++; + this->select_chip(mtd, -1); + this->select_chip(mtd, chipnr); } } } +finished: /* Deselect and wake up anyone waiting on the device */ nand_release_device(mtd); @@ -1458,6 +1866,7 @@ static int nand_read_oob (struct mtd_info *mtd, loff_t from, size_t len, size_t return 0; } + /** * nand_read_raw - [GENERIC] Read raw data including oob into buffer * @mtd: MTD device structure @@ -1488,27 +1897,61 @@ int nand_read_raw (struct mtd_info *mtd, uint8_t *buf, loff_t from, size_t len, nand_get_device (this, mtd , FL_READING); this->select_chip (mtd, chip); - + /* Add requested oob length */ len += ooblen; - + while (len) { if (sndcmd) this->cmdfunc (mtd, NAND_CMD_READ0, 0, page & this->pagemask); - sndcmd = 0; + sndcmd = 0; + + if (!this->layout) + this->read_buf(mtd, &buf[cnt], pagesize); + else { + int oobidx, datidx, eccsteps, j; + uint8_t *datbuf, *oobbuf; - this->read_buf (mtd, &buf[cnt], pagesize); + /* + * Since we have a page layout, we must observe the + * layout to position data and oob correctly. + */ + datbuf = &buf[cnt]; + oobbuf = &datbuf[mtd->oobblock]; + eccsteps = this->eccsteps; + for (oobidx = 0, datidx = 0; eccsteps; eccsteps--) { + for (j = 0; this->layout[j].length; j++) { + int thislen = this->layout[j].length; + + switch (this->layout[j].type) { + case ITEM_TYPE_DATA: + this->read_buf(mtd, + &datbuf[datidx], + thislen); + datidx += thislen; + break; + case ITEM_TYPE_ECC: + case ITEM_TYPE_OOB: + this->read_buf(mtd, + &oobbuf[oobidx], + thislen); + oobidx += thislen; + break; + } + } + } + } len -= pagesize; cnt += pagesize; page++; - - if (!this->dev_ready) + + if (!this->dev_ready) udelay (this->chip_delay); else - while (!this->dev_ready(mtd)); - - /* Check, if the chip supports auto page increment */ + while (!this->dev_ready(mtd)); + + /* Check, if the chip supports auto page increment */ if (!NAND_CANAUTOINCR(this) || !(page & blockcheck)) sndcmd = 1; } @@ -1519,8 +1962,8 @@ int nand_read_raw (struct mtd_info *mtd, uint8_t *buf, loff_t from, size_t len, } -/** - * nand_prepare_oobbuf - [GENERIC] Prepare the out of band buffer +/** + * nand_prepare_oobbuf - [GENERIC] Prepare the out of band buffer * @mtd: MTD device structure * @fsbuf: buffer given by fs driver * @oobsel: out of band selection structre @@ -1549,20 +1992,20 @@ static u_char * nand_prepare_oobbuf (struct mtd_info *mtd, u_char *fsbuf, struct int i, len, ofs; /* Zero copy fs supplied buffer */ - if (fsbuf && !autoplace) + if (fsbuf && !autoplace) return fsbuf; /* Check, if the buffer must be filled with ff again */ - if (this->oobdirty) { - memset (this->oob_buf, 0xff, + if (this->oobdirty) { + memset (this->oob_buf, 0xff, mtd->oobsize << (this->phys_erase_shift - this->page_shift)); this->oobdirty = 0; - } - + } + /* If we have no autoplacement or no fs buffer use the internal one */ if (!autoplace || !fsbuf) return this->oob_buf; - + /* Walk through the pages and place the data */ this->oobdirty = 1; ofs = 0; @@ -1574,7 +2017,7 @@ static u_char * nand_prepare_oobbuf (struct mtd_info *mtd, u_char *fsbuf, struct len += num; fsbuf += num; } - ofs += mtd->oobavail; + ofs += mtd->oobsize; } return this->oob_buf; } @@ -1596,7 +2039,7 @@ static int nand_write (struct mtd_info *mtd, loff_t to, size_t len, size_t * ret { return (nand_write_ecc (mtd, to, len, retlen, buf, NULL, NULL)); } - + /** * nand_write_ecc - [MTD Interface] NAND write with ECC * @mtd: MTD device structure @@ -1629,7 +2072,7 @@ static int nand_write_ecc (struct mtd_info *mtd, loff_t to, size_t len, return -EINVAL; } - /* reject writes, which are not page aligned */ + /* reject writes, which are not page aligned */ if (NOTALIGNED (to) || NOTALIGNED(len)) { printk (KERN_NOTICE "nand_write_ecc: Attempt to write not page aligned data\n"); return -EINVAL; @@ -1644,20 +2087,18 @@ static int nand_write_ecc (struct mtd_info *mtd, loff_t to, size_t len, this->select_chip(mtd, chipnr); /* Check, if it is write protected */ - if (nand_check_wp(mtd)) { - printk (KERN_NOTICE "nand_write_ecc: Device is write protected\n"); + if (nand_check_wp(mtd)) goto out; - } /* if oobsel is NULL, use chip defaults */ - if (oobsel == NULL) - oobsel = &mtd->oobinfo; - + if (oobsel == NULL) + oobsel = &mtd->oobinfo; + /* Autoplace of oob data ? Use the default placement scheme */ if (oobsel->useecc == MTD_NANDECC_AUTOPLACE) { oobsel = this->autooob; autoplace = 1; - } + } if (oobsel->useecc == MTD_NANDECC_AUTOPL_USR) autoplace = 1; @@ -1665,9 +2106,9 @@ static int nand_write_ecc (struct mtd_info *mtd, loff_t to, size_t len, totalpages = len >> this->page_shift; page = (int) (to >> this->page_shift); /* Invalidate the page cache, if we write to the cached page */ - if (page <= this->pagebuf && this->pagebuf < (page + totalpages)) + if (page <= this->pagebuf && this->pagebuf < (page + totalpages)) this->pagebuf = -1; - + /* Set it relative to chip */ page &= this->pagemask; startpage = page; @@ -1689,14 +2130,14 @@ static int nand_write_ecc (struct mtd_info *mtd, loff_t to, size_t len, if (ret) { DEBUG (MTD_DEBUG_LEVEL0, "nand_write_ecc: write_page failed %d\n", ret); goto out; - } + } /* Next oob page */ oob += mtd->oobsize; /* Update written bytes count */ written += mtd->oobblock; - if (written == len) + if (written == len) goto cmp; - + /* Increment page address */ page++; @@ -1707,15 +2148,14 @@ static int nand_write_ecc (struct mtd_info *mtd, loff_t to, size_t len, if (!(page & (ppblock - 1))){ int ofs; this->data_poi = bufstart; - ret = nand_verify_pages (mtd, this, startpage, + ret = nand_verify_pages (mtd, this, startpage, page - startpage, oobbuf, oobsel, chipnr, (eccbuf != NULL)); if (ret) { DEBUG (MTD_DEBUG_LEVEL0, "nand_write_ecc: verify_pages failed %d\n", ret); goto out; - } + } *retlen = written; - bufstart = (u_char*) &buf[written]; ofs = autoplace ? mtd->oobavail : mtd->oobsize; if (eccbuf) @@ -1724,10 +2164,9 @@ static int nand_write_ecc (struct mtd_info *mtd, loff_t to, size_t len, numpages = min (totalpages, ppblock); page &= this->pagemask; startpage = page; - oob = 0; - this->oobdirty = 1; - oobbuf = nand_prepare_oobbuf (mtd, eccbuf, oobsel, + oobbuf = nand_prepare_oobbuf (mtd, eccbuf, oobsel, autoplace, numpages); + oob = 0; /* Check, if we cross a chip boundary */ if (!page) { chipnr++; @@ -1743,7 +2182,7 @@ cmp: oobbuf, oobsel, chipnr, (eccbuf != NULL)); if (!ret) *retlen = written; - else + else DEBUG (MTD_DEBUG_LEVEL0, "nand_write_ecc: verify_pages failed %d\n", ret); out: @@ -1803,7 +2242,7 @@ static int nand_write_oob (struct mtd_info *mtd, loff_t to, size_t len, size_t * /* Check, if it is write protected */ if (nand_check_wp(mtd)) goto out; - + /* Invalidate the page cache, if we write to the cached page */ if (page == this->pagebuf) this->pagebuf = -1; @@ -1829,7 +2268,7 @@ static int nand_write_oob (struct mtd_info *mtd, loff_t to, size_t len, size_t * status = this->waitfunc (mtd, this, FL_WRITING); /* See if device thinks it succeeded */ - if (status & 0x01) { + if (status & NAND_STATUS_FAIL) { DEBUG (MTD_DEBUG_LEVEL0, "nand_write_oob: " "Failed write, page 0x%08x\n", page); ret = -EIO; goto out; @@ -1855,8 +2294,164 @@ out: return ret; } -/* XXX U-BOOT XXX */ -#if 0 +/** + * nand_write_oob_hwecc - [MTD Interface] NAND write out-of-band + * @mtd: MTD device structure + * @to: offset to write to + * @len: number of bytes to write + * @retlen: pointer to variable to store the number of written bytes + * @oob_buf: the data to write + * + * NAND write out-of-band + * W/o assumptions that are valid only for software ECC + */ +static int nand_write_oob_hwecc (struct mtd_info *mtd, loff_t to, size_t len, size_t * retlen, const u_char * oob_buf) +{ + int column, page, status, ret = -EIO, chipnr, eccsteps; + int ooblen, oc; + struct nand_chip *this = mtd->priv; + + DEBUG (MTD_DEBUG_LEVEL3, "%s: to = 0x%08x, len = %i\n", __FUNCTION__, (unsigned int) to, (int) len); + + /* Shift to get page */ + page = (int) (to >> this->page_shift); + chipnr = (int) (to >> this->chip_shift); + + /* Mask to get column */ + column = to & (mtd->oobsize - 1); + + /* Initialize return length value */ + *retlen = 0; + + /* Do not allow write past end of page */ + if ((column + len) > mtd->oobsize) { + DEBUG (MTD_DEBUG_LEVEL0, "%s: Attempt to write past end of page\n", __FUNCTION__); + return -EINVAL; + } + + /* Grab the lock and see if the device is available */ + nand_get_device (this, mtd, FL_WRITING); + + /* Select the NAND device */ + this->select_chip(mtd, chipnr); + + /* Reset the chip. Some chips (like the Toshiba TC5832DC found + in one of my DiskOnChip 2000 test units) will clear the whole + data page too if we don't do this. I have no clue why, but + I seem to have 'fixed' it in the doc2000 driver in + August 1999. dwmw2. */ + this->cmdfunc(mtd, NAND_CMD_RESET, -1, -1); + + /* Check, if it is write protected */ + if (nand_check_wp(mtd)) + goto out; + + /* Invalidate the page cache, if we write to the cached page */ + if (page == this->pagebuf) + this->pagebuf = -1; + + /* Write out desired data */ + this->cmdfunc (mtd, NAND_CMD_SEQIN, 0, page & this->pagemask); + + eccsteps = this->eccsteps; + + for (ooblen = 0, oc = 0; eccsteps; eccsteps--) { + int j, first, last, thislen; + /* + * In the following we assume that each item (data, ECC, + * and OOB) in the layout has an even length such as would be + * required for a 16-bit-wide NAND. This assumption allows us + * to handle 16-bit-wide chips with no special cases versus + * 8-bit-wide chips. + */ + for (j = 0; this->layout[j].length; j++) { + /* are we done yet? */ + if ((oc == len) && !NAND_MUST_PAD(this)) + goto finish; + thislen = this->layout[j].length; + switch (this->layout[j].type) { + case ITEM_TYPE_DATA: + this->write_buf(mtd, ffchars, thislen); + continue; + case ITEM_TYPE_ECC: + case ITEM_TYPE_OOB: + /* + * Calculate the intersection of the oob data + * with this layout item. + */ + first = max(ooblen, column); + last = min(ooblen + thislen, column + (int)len); + if (first >= last) { + /* no intersection */ + this->write_buf(mtd, ffchars, thislen); + break; + } + /* pre-pad */ + if (first > ooblen + 1) { + /* write an even number of FFs */ + this->write_buf(mtd, ffchars, + ((first - ooblen) & ~1)); + } + /* handle an odd offset */ + if (first & 1) { + this->write_word(mtd, + cpu_to_le16((oob_buf[oc++] << 8) + | 0xff)); + ++first; + } + if (last - first > 1) { + int n = ((last - first) & ~1); + /* write an even number of oob bytes */ + this->write_buf(mtd, oob_buf + oc, n); + oc += n; + first += n; + } + /* handle an odd length */ + if (last - first == 1) { + this->write_word(mtd, + cpu_to_le16(0xff00 + | oob_buf[oc++])); + ++first; + } + /* post-pad */ + if (((last + 1) & ~1) < ooblen + thislen) { + this->write_buf(mtd, ffchars, + ooblen + thislen + - ((last + 1) & ~1)); + } + break; + } + ooblen += thislen; + } + } + +finish: + /* Send command to program the OOB data */ + this->cmdfunc (mtd, NAND_CMD_PAGEPROG, -1, -1); + + status = this->waitfunc (mtd, this, FL_WRITING); + + /* See if device thinks it succeeded */ + if (status & NAND_STATUS_FAIL) { + DEBUG (MTD_DEBUG_LEVEL0, "%s: Failed write, page 0x%08x\n", __FUNCTION__, page); + ret = -EIO; + goto out; + } + /* Return happy */ + *retlen = len; + +#ifdef CONFIG_MTD_NAND_VERIFY_WRITE +#warning "Verify for OOB data in HW ECC case is NOT YET implemented" +#endif + ret = 0; + +out: + /* Deselect and wake up anyone waiting on the device */ + nand_release_device(mtd); + + return ret; +} + /** * nand_writev - [MTD Interface] compabilty function for nand_writev_ecc * @mtd: MTD device structure @@ -1867,10 +2462,11 @@ out: * * NAND write with kvec. This just calls the ecc function */ -static int nand_writev (struct mtd_info *mtd, const struct kvec *vecs, unsigned long count, +#if 0 +static int nand_writev (struct mtd_info *mtd, const struct kvec *vecs, unsigned long count, loff_t to, size_t * retlen) { - return (nand_writev_ecc (mtd, vecs, count, to, retlen, NULL, NULL)); + return (nand_writev_ecc (mtd, vecs, count, to, retlen, NULL, NULL)); } /** @@ -1885,7 +2481,7 @@ static int nand_writev (struct mtd_info *mtd, const struct kvec *vecs, unsigned * * NAND write with iovec with ecc */ -static int nand_writev_ecc (struct mtd_info *mtd, const struct kvec *vecs, unsigned long count, +static int nand_writev_ecc (struct mtd_info *mtd, const struct kvec *vecs, unsigned long count, loff_t to, size_t * retlen, u_char *eccbuf, struct nand_oobinfo *oobsel) { int i, page, len, total_len, ret = -EIO, written = 0, chipnr; @@ -1911,7 +2507,7 @@ static int nand_writev_ecc (struct mtd_info *mtd, const struct kvec *vecs, unsig return -EINVAL; } - /* reject writes, which are not page aligned */ + /* reject writes, which are not page aligned */ if (NOTALIGNED (to) || NOTALIGNED(total_len)) { printk (KERN_NOTICE "nand_write_ecc: Attempt to write not page aligned data\n"); return -EINVAL; @@ -1930,21 +2526,21 @@ static int nand_writev_ecc (struct mtd_info *mtd, const struct kvec *vecs, unsig goto out; /* if oobsel is NULL, use chip defaults */ - if (oobsel == NULL) - oobsel = &mtd->oobinfo; + if (oobsel == NULL) + oobsel = &mtd->oobinfo; /* Autoplace of oob data ? Use the default placement scheme */ if (oobsel->useecc == MTD_NANDECC_AUTOPLACE) { oobsel = this->autooob; autoplace = 1; - } + } if (oobsel->useecc == MTD_NANDECC_AUTOPL_USR) autoplace = 1; /* Setup start page */ page = (int) (to >> this->page_shift); /* Invalidate the page cache, if we write to the cached page */ - if (page <= this->pagebuf && this->pagebuf < ((to + total_len) >> this->page_shift)) + if (page <= this->pagebuf && this->pagebuf < ((to + total_len) >> this->page_shift)) this->pagebuf = -1; startpage = page & this->pagemask; @@ -1968,10 +2564,10 @@ static int nand_writev_ecc (struct mtd_info *mtd, const struct kvec *vecs, unsig oob = 0; for (i = 1; i <= numpages; i++) { /* Write one page. If this is the last page to write - * then use the real pageprogram command, else select + * then use the real pageprogram command, else select * cached programming if supported by the chip. */ - ret = nand_write_page (mtd, this, page & this->pagemask, + ret = nand_write_page (mtd, this, page & this->pagemask, &oobbuf[oob], oobsel, i != numpages); if (ret) goto out; @@ -1987,12 +2583,12 @@ static int nand_writev_ecc (struct mtd_info *mtd, const struct kvec *vecs, unsig count--; } } else { - /* We must use the internal buffer, read data out of each + /* We must use the internal buffer, read data out of each * tuple until we have a full page to write */ int cnt = 0; while (cnt < mtd->oobblock) { - if (vecs->iov_base != NULL && vecs->iov_len) + if (vecs->iov_base != NULL && vecs->iov_len) this->data_buf[cnt++] = ((u_char *) vecs->iov_base)[len++]; /* Check, if we have to switch to the next tuple */ if (len >= (int) vecs->iov_len) { @@ -2001,10 +2597,10 @@ static int nand_writev_ecc (struct mtd_info *mtd, const struct kvec *vecs, unsig count--; } } - this->pagebuf = page; - this->data_poi = this->data_buf; + this->pagebuf = page; + this->data_poi = this->data_buf; bufstart = this->data_poi; - numpages = 1; + numpages = 1; oobbuf = nand_prepare_oobbuf (mtd, NULL, oobsel, autoplace, numpages); ret = nand_write_page (mtd, this, page & this->pagemask, oobbuf, oobsel, 0); @@ -2017,7 +2613,7 @@ static int nand_writev_ecc (struct mtd_info *mtd, const struct kvec *vecs, unsig ret = nand_verify_pages (mtd, this, startpage, numpages, oobbuf, oobsel, chipnr, 0); if (ret) goto out; - + written += mtd->oobblock * numpages; /* All done ? */ if (!count) @@ -2086,7 +2682,8 @@ static int nand_erase (struct mtd_info *mtd, struct erase_info *instr) { return nand_erase_nand (mtd, instr, 0); } - + +#define BBT_PAGE_MASK 0xffffff3f /** * nand_erase_intern - [NAND Interface] erase block(s) * @mtd: MTD device structure @@ -2099,6 +2696,10 @@ int nand_erase_nand (struct mtd_info *mtd, struct erase_info *instr, int allowbb { int page, len, status, pages_per_block, ret, chipnr; struct nand_chip *this = mtd->priv; + int rewrite_bbt[NAND_MAX_CHIPS]={0}; /* flags to indicate the page, if bbt needs to be rewritten. */ + unsigned int bbt_masked_page; /* bbt mask to compare to page being erased. */ + /* It is used to see if the current page is in the same */ + /* 256 block group and the same bank as the bbt. */ DEBUG (MTD_DEBUG_LEVEL3, "nand_erase: start = 0x%08x, len = %i\n", (unsigned int) instr->addr, (unsigned int) instr->len); @@ -2144,37 +2745,56 @@ int nand_erase_nand (struct mtd_info *mtd, struct erase_info *instr, int allowbb goto erase_exit; } + /* if BBT requires refresh, set the BBT page mask to see if the BBT should be rewritten */ + if (this->options & BBT_AUTO_REFRESH) { + bbt_masked_page = this->bbt_td->pages[chipnr] & BBT_PAGE_MASK; + } else { + bbt_masked_page = 0xffffffff; /* should not match anything */ + } + /* Loop through the pages */ len = instr->len; instr->state = MTD_ERASING; while (len) { -#ifndef NAND_ALLOW_ERASE_ALL /* Check if we have a bad block, we do not erase bad blocks ! */ if (nand_block_checkbad(mtd, ((loff_t) page) << this->page_shift, 0, allowbbt)) { printk (KERN_WARNING "nand_erase: attempt to erase a bad block at page 0x%08x\n", page); instr->state = MTD_ERASE_FAILED; goto erase_exit; } -#endif - /* Invalidate the page cache, if we erase the block which contains + + /* Invalidate the page cache, if we erase the block which contains the current cached page */ if (page <= this->pagebuf && this->pagebuf < (page + pages_per_block)) this->pagebuf = -1; this->erase_cmd (mtd, page & this->pagemask); - + status = this->waitfunc (mtd, this, FL_ERASING); + /* See if operation failed and additional status checks are available */ + if ((status & NAND_STATUS_FAIL) && (this->errstat)) { + status = this->errstat(mtd, this, FL_ERASING, status, page); + } + /* See if block erase succeeded */ - if (status & 0x01) { + if (status & NAND_STATUS_FAIL) { DEBUG (MTD_DEBUG_LEVEL0, "nand_erase: " "Failed erase, page 0x%08x\n", page); instr->state = MTD_ERASE_FAILED; instr->fail_addr = (page << this->page_shift); goto erase_exit; } + /* if BBT requires refresh, set the BBT rewrite flag to the page being erased */ + if (this->options & BBT_AUTO_REFRESH) { + if (((page & BBT_PAGE_MASK) == bbt_masked_page) && + (page != this->bbt_td->pages[chipnr])) { + rewrite_bbt[chipnr] = (page << this->page_shift); + } + } + /* Increment page address and decrement length */ len -= (1 << this->phys_erase_shift); page += pages_per_block; @@ -2184,6 +2804,12 @@ int nand_erase_nand (struct mtd_info *mtd, struct erase_info *instr, int allowbb chipnr++; this->select_chip(mtd, -1); this->select_chip(mtd, chipnr); + /* if BBT requires refresh and BBT-PERCHIP, + * set the BBT page mask to see if this BBT should be rewritten */ + if ((this->options & BBT_AUTO_REFRESH) && (this->bbt_td->options & NAND_BBT_PERCHIP)) { + bbt_masked_page = this->bbt_td->pages[chipnr] & BBT_PAGE_MASK; + } + } } instr->state = MTD_ERASE_DONE; @@ -2198,6 +2824,18 @@ erase_exit: /* Deselect and wake up anyone waiting on the device */ nand_release_device(mtd); + /* if BBT requires refresh and erase was successful, rewrite any selected bad block tables */ + if ((this->options & BBT_AUTO_REFRESH) && (!ret)) { + for (chipnr = 0; chipnr < this->numchips; chipnr++) { + if (rewrite_bbt[chipnr]) { + /* update the BBT for chip */ + DEBUG (MTD_DEBUG_LEVEL0, "nand_erase_nand: nand_update_bbt (%d:0x%0x 0x%0x)\n", + chipnr, rewrite_bbt[chipnr], this->bbt_td->pages[chipnr]); + nand_update_bbt (mtd, rewrite_bbt[chipnr]); + } + } + } + /* Return more or less happy */ return ret; } @@ -2229,9 +2867,9 @@ static void nand_sync (struct mtd_info *mtd) static int nand_block_isbad (struct mtd_info *mtd, loff_t ofs) { /* Check for invalid offset */ - if (ofs > mtd->size) + if (ofs > mtd->size) return -EINVAL; - + return nand_block_checkbad (mtd, ofs, 1, 0); } @@ -2245,12 +2883,12 @@ static int nand_block_markbad (struct mtd_info *mtd, loff_t ofs) struct nand_chip *this = mtd->priv; int ret; - if ((ret = nand_block_isbad(mtd, ofs))) { - /* If it was bad already, return success and do nothing. */ + if ((ret = nand_block_isbad(mtd, ofs))) { + /* If it was bad already, return success and do nothing. */ if (ret > 0) return 0; - return ret; - } + return ret; + } return this->block_markbad(mtd, ofs); } @@ -2269,9 +2907,9 @@ static int nand_block_markbad (struct mtd_info *mtd, loff_t ofs) */ int nand_scan (struct mtd_info *mtd, int maxchips) { - int i, j, nand_maf_id, nand_dev_id, busw; + int i, nand_maf_id, nand_dev_id, busw, maf_id; struct nand_chip *this = mtd->priv; - + /* Get buswidth to select the correct functions*/ busw = this->options & NAND_BUSWIDTH_16; @@ -2310,9 +2948,13 @@ int nand_scan (struct mtd_info *mtd, int maxchips) if (!this->scan_bbt) this->scan_bbt = nand_default_bbt; + /* 'ff' the ffchars */ + memset(ffchars, 0xff, FFCHARS_SIZE); + /* Select the device */ this->select_chip(mtd, 0); + this->cmdfunc (mtd, NAND_CMD_RESET, -1, -1); /* Send the command for reading device ID */ this->cmdfunc (mtd, NAND_CMD_READID, 0x00, -1); @@ -2320,15 +2962,18 @@ int nand_scan (struct mtd_info *mtd, int maxchips) nand_maf_id = this->read_byte(mtd); nand_dev_id = this->read_byte(mtd); + printf("NAND Manufacturer id: %x\n", nand_maf_id); + printf("NAND Device id: %x\n", nand_dev_id); + /* Print and store flash device information */ for (i = 0; nand_flash_ids[i].name != NULL; i++) { - - if (nand_dev_id != nand_flash_ids[i].id) + + if (nand_dev_id != nand_flash_ids[i].id) continue; if (!mtd->name) mtd->name = nand_flash_ids[i].name; this->chipsize = nand_flash_ids[i].chipsize << 20; - + /* New devices have all the information in additional id bytes */ if (!nand_flash_ids[i].pagesize) { int extid; @@ -2340,14 +2985,14 @@ int nand_scan (struct mtd_info *mtd, int maxchips) mtd->oobblock = 1024 << (extid & 0x3); extid >>= 2; /* Calc oobsize */ - mtd->oobsize = (8 << (extid & 0x01)) * (mtd->oobblock / 512); + mtd->oobsize = (8 << (extid & 0x03)) * (mtd->oobblock / 512); extid >>= 2; /* Calc blocksize. Blocksize is multiples of 64KiB */ mtd->erasesize = (64 * 1024) << (extid & 0x03); extid >>= 2; /* Get buswidth information */ busw = (extid & 0x01) ? NAND_BUSWIDTH_16 : 0; - + } else { /* Old devices have this data hardcoded in the * device id table */ @@ -2357,27 +3002,33 @@ int nand_scan (struct mtd_info *mtd, int maxchips) busw = nand_flash_ids[i].options & NAND_BUSWIDTH_16; } + /* Try to identify manufacturer */ + for (maf_id = 0; nand_manuf_ids[maf_id].id != 0x0; maf_id++) { + if (nand_manuf_ids[maf_id].id == nand_maf_id) + break; + } + /* Check, if buswidth is correct. Hardware drivers should set * this correct ! */ if (busw != (this->options & NAND_BUSWIDTH_16)) { printk (KERN_INFO "NAND device: Manufacturer ID:" - " 0x%02x, Chip ID: 0x%02x (%s %s)\n", nand_maf_id, nand_dev_id, - nand_manuf_ids[i].name , mtd->name); - printk (KERN_WARNING - "NAND bus width %d instead %d bit\n", + " 0x%02x, Chip ID: 0x%02x (%s %s)\n", nand_maf_id, nand_dev_id, + nand_manuf_ids[maf_id].name , mtd->name); + printk (KERN_WARNING + "NAND bus width %d instead %d bit\n", (this->options & NAND_BUSWIDTH_16) ? 16 : 8, busw ? 16 : 8); this->select_chip(mtd, -1); - return 1; + return 1; } - - /* Calculate the address shift from the page size */ + + /* Calculate the address shift from the page size */ this->page_shift = ffs(mtd->oobblock) - 1; this->bbt_erase_shift = this->phys_erase_shift = ffs(mtd->erasesize) - 1; this->chip_shift = ffs(this->chipsize) - 1; /* Set the bad block position */ - this->badblockpos = mtd->oobblock > 512 ? + this->badblockpos = mtd->oobblock > 512 ? NAND_LARGE_BADBLOCK_POS : NAND_SMALL_BADBLOCK_POS; /* Get chip options, preserve non chip based options */ @@ -2387,10 +3038,10 @@ int nand_scan (struct mtd_info *mtd, int maxchips) this->options |= NAND_NO_AUTOINCR; /* Check if this is a not a samsung device. Do not clear the options * for chips which are not having an extended id. - */ + */ if (nand_maf_id != NAND_MFR_SAMSUNG && !nand_flash_ids[i].pagesize) this->options &= ~NAND_SAMSUNG_LP_OPTIONS; - + /* Check for AND chips with 4 page planes */ if (this->options & NAND_4PAGE_ARRAY) this->erase_cmd = multi_erase_cmd; @@ -2400,19 +3051,15 @@ int nand_scan (struct mtd_info *mtd, int maxchips) /* Do not replace user supplied command function ! */ if (mtd->oobblock > 512 && this->cmdfunc == nand_command) this->cmdfunc = nand_command_lp; - - /* Try to identify manufacturer */ - for (j = 0; nand_manuf_ids[j].id != 0x0; j++) { - if (nand_manuf_ids[j].id == nand_maf_id) - break; - } + + printk (KERN_INFO "NAND device: Manufacturer ID:" + " 0x%02x, Chip ID: 0x%02x (%s %s)\n", nand_maf_id, nand_dev_id, + nand_manuf_ids[maf_id].name , nand_flash_ids[i].name); break; } if (!nand_flash_ids[i].name) { -#ifndef CFG_NAND_QUIET_TEST printk (KERN_WARNING "No NAND device found!!!\n"); -#endif this->select_chip(mtd, -1); return 1; } @@ -2430,7 +3077,7 @@ int nand_scan (struct mtd_info *mtd, int maxchips) } if (i > 1) printk(KERN_INFO "%d NAND chips detected\n", i); - + /* Allocate buffers, if neccecary */ if (!this->oob_buf) { size_t len; @@ -2442,7 +3089,7 @@ int nand_scan (struct mtd_info *mtd, int maxchips) } this->options |= NAND_OOBBUF_ALLOC; } - + if (!this->data_buf) { size_t len; len = mtd->oobblock + mtd->oobsize; @@ -2469,7 +3116,7 @@ int nand_scan (struct mtd_info *mtd, int maxchips) if (!this->autooob) { /* Select the appropriate default oob placement scheme for * placement agnostic filesystems */ - switch (mtd->oobsize) { + switch (mtd->oobsize) { case 8: this->autooob = &nand_oob_8; break; @@ -2482,22 +3129,22 @@ int nand_scan (struct mtd_info *mtd, int maxchips) default: printk (KERN_WARNING "No oob scheme defined for oobsize %d\n", mtd->oobsize); -/* BUG(); */ + BUG(); } } - + /* The number of bytes available for the filesystem to place fs dependend * oob data */ mtd->oobavail = 0; - for (i=0; this->autooob->oobfree[i][1]; i++) + for (i = 0; this->autooob->oobfree[i][1]; i++) mtd->oobavail += this->autooob->oobfree[i][1]; - /* + /* * check ECC mode, default to software * if 3byte/512byte hardware ECC is selected and we have 256 byte pagesize - * fallback to software ECC + * fallback to software ECC */ - this->eccsize = 256; /* set default eccsize */ + this->eccsize = 256; /* set default eccsize */ this->eccbytes = 3; switch (this->eccmode) { @@ -2512,56 +3159,59 @@ int nand_scan (struct mtd_info *mtd, int maxchips) this->eccsize = 2048; break; - case NAND_ECC_HW3_512: - case NAND_ECC_HW6_512: - case NAND_ECC_HW8_512: + case NAND_ECC_HW3_512: + case NAND_ECC_HW6_512: + case NAND_ECC_HW8_512: + case NAND_ECC_HW10_512: if (mtd->oobblock == 256) { printk (KERN_WARNING "512 byte HW ECC not possible on 256 Byte pagesize, fallback to SW ECC \n"); this->eccmode = NAND_ECC_SOFT; this->calculate_ecc = nand_calculate_ecc; this->correct_data = nand_correct_data; - } else + } else this->eccsize = 512; /* set eccsize to 512 */ break; - + case NAND_ECC_HW3_256: break; - - case NAND_ECC_NONE: + + case NAND_ECC_NONE: printk (KERN_WARNING "NAND_ECC_NONE selected by board driver. This is not recommended !!\n"); this->eccmode = NAND_ECC_NONE; break; - case NAND_ECC_SOFT: + case NAND_ECC_SOFT: this->calculate_ecc = nand_calculate_ecc; this->correct_data = nand_correct_data; break; default: printk (KERN_WARNING "Invalid NAND_ECC_MODE %d\n", this->eccmode); -/* BUG(); */ - } + BUG(); + } - /* Check hardware ecc function availability and adjust number of ecc bytes per + /* Check hardware ecc function availability and adjust number of ecc bytes per * calculation step */ switch (this->eccmode) { case NAND_ECC_HW12_2048: - this->eccbytes += 4; - case NAND_ECC_HW8_512: this->eccbytes += 2; - case NAND_ECC_HW6_512: + case NAND_ECC_HW10_512: + this->eccbytes += 2; + case NAND_ECC_HW8_512: + this->eccbytes += 2; + case NAND_ECC_HW6_512: this->eccbytes += 3; - case NAND_ECC_HW3_512: + case NAND_ECC_HW3_512: case NAND_ECC_HW3_256: if (this->calculate_ecc && this->correct_data && this->enable_hwecc) break; printk (KERN_WARNING "No ECC functions supplied, Hardware ECC not possible\n"); -/* BUG(); */ + BUG(); } - + mtd->eccsize = this->eccsize; - + /* Set the number of read / write steps for one page to ensure ECC generation */ switch (this->eccmode) { case NAND_ECC_HW12_2048: @@ -2570,17 +3220,20 @@ int nand_scan (struct mtd_info *mtd, int maxchips) case NAND_ECC_HW3_512: case NAND_ECC_HW6_512: case NAND_ECC_HW8_512: + case NAND_ECC_HW10_512: this->eccsteps = mtd->oobblock / 512; break; case NAND_ECC_HW3_256: - case NAND_ECC_SOFT: + case NAND_ECC_SOFT: this->eccsteps = mtd->oobblock / 256; break; - - case NAND_ECC_NONE: + + case NAND_ECC_NONE: this->eccsteps = 1; break; } + + mtd->eccsize = this->eccsize; /* XXX U-BOOT XXX */ #if 0 @@ -2607,9 +3260,15 @@ int nand_scan (struct mtd_info *mtd, int maxchips) mtd->write = nand_write; mtd->read_ecc = nand_read_ecc; mtd->write_ecc = nand_write_ecc; - mtd->read_oob = nand_read_oob; - mtd->write_oob = nand_write_oob; -/* XXX U-BOOT XXX */ + + if ((this->eccmode != NAND_ECC_NONE && this->eccmode != NAND_ECC_SOFT) + && this->layout) { + mtd->read_oob = nand_read_oob_hwecc; + mtd->write_oob = nand_write_oob_hwecc; + } else { + mtd->read_oob = nand_read_oob; + mtd->write_oob = nand_write_oob; + } #if 0 mtd->readv = NULL; mtd->writev = nand_writev; @@ -2632,14 +3291,18 @@ int nand_scan (struct mtd_info *mtd, int maxchips) #if 0 mtd->owner = THIS_MODULE; #endif + /* Check, if we should skip the bad block table scan */ + if (this->options & NAND_SKIP_BBTSCAN) + return 0; + /* Build bad block table */ return this->scan_bbt (mtd); } /** - * nand_release - [NAND Interface] Free resources held by the NAND device + * nand_release - [NAND Interface] Free resources held by the NAND device * @mtd: MTD device structure - */ +*/ void nand_release (struct mtd_info *mtd) { struct nand_chip *this = mtd->priv; diff --git a/drivers/mtd/nand/nand_bbt.c b/drivers/mtd/nand/nand_bbt.c index 19a9bc2a5b6..4f683150bcf 100644 --- a/drivers/mtd/nand/nand_bbt.c +++ b/drivers/mtd/nand/nand_bbt.c @@ -564,7 +564,9 @@ write: return res; } + udelay(100000); res = mtd->write_ecc (mtd, to, len, &retlen, buf, &buf[len], &oobinfo); + if (res < 0) { printk (KERN_WARNING "nand_bbt: Error while writing bad block table %d\n", res); return res; @@ -812,7 +814,7 @@ int nand_scan_bbt (struct mtd_info *mtd, struct nand_bbt_descr *bd) len = (1 << this->bbt_erase_shift); len += (len >> this->page_shift) * mtd->oobsize; buf = kmalloc (len, GFP_KERNEL); - if (!buf) { + if(!buf) { printk (KERN_ERR "nand_bbt: Out of memory\n"); kfree (this->bbt); this->bbt = NULL; @@ -929,7 +931,7 @@ static struct nand_bbt_descr smallpage_flashbased = { }; static struct nand_bbt_descr largepage_flashbased = { - .options = NAND_BBT_SCANEMPTY | NAND_BBT_SCANALLPAGES, + .options = 0, /* NAND_BBT_SCANEMPTY | NAND_BBT_SCANALLPAGES,*/ .offs = 0, .len = 2, .pattern = scan_ff_pattern @@ -952,9 +954,9 @@ static uint8_t mirror_pattern[] = {'1', 't', 'b', 'B' }; static struct nand_bbt_descr bbt_main_descr = { .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE | NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP, - .offs = 8, + .offs = 2, .len = 4, - .veroffs = 12, + .veroffs = 16, .maxblocks = 4, .pattern = bbt_pattern }; @@ -962,9 +964,9 @@ static struct nand_bbt_descr bbt_main_descr = { static struct nand_bbt_descr bbt_mirror_descr = { .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE | NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP, - .offs = 8, + .offs = 2, .len = 4, - .veroffs = 12, + .veroffs = 16, .maxblocks = 4, .pattern = mirror_pattern }; diff --git a/drivers/mtd/nand/nand_ecc.c b/drivers/mtd/nand/nand_ecc.c index 4c532b0794e..a8871aea023 100644 --- a/drivers/mtd/nand/nand_ecc.c +++ b/drivers/mtd/nand/nand_ecc.c @@ -40,13 +40,6 @@ #if defined(CONFIG_CMD_NAND) && !defined(CFG_NAND_LEGACY) #include<linux/mtd/mtd.h> - -/* - * NAND-SPL has no sofware ECC for now, so don't include nand_calculate_ecc(), - * only nand_correct_data() is needed - */ - -#ifndef CONFIG_NAND_SPL /* * Pre-calculated 256-way 1 byte column parity */ @@ -69,75 +62,90 @@ static const u_char nand_ecc_precalc_table[] = { 0x00, 0x55, 0x56, 0x03, 0x59, 0x0c, 0x0f, 0x5a, 0x5a, 0x0f, 0x0c, 0x59, 0x03, 0x56, 0x55, 0x00 }; + +/** + * nand_trans_result - [GENERIC] create non-inverted ECC + * @reg2: line parity reg 2 + * @reg3: line parity reg 3 + * @ecc_code: ecc + * + * Creates non-inverted ECC code from line parity + */ +static void nand_trans_result(u_char reg2, u_char reg3, + u_char *ecc_code) +{ + u_char a, b, i, tmp1, tmp2; + + /* Initialize variables */ + a = b = 0x80; + tmp1 = tmp2 = 0; + + /* Calculate first ECC byte */ + for (i = 0; i < 4; i++) { + if (reg3 & a) /* LP15,13,11,9 --> ecc_code[0] */ + tmp1 |= b; + b >>= 1; + if (reg2 & a) /* LP14,12,10,8 --> ecc_code[0] */ + tmp1 |= b; + b >>= 1; + a >>= 1; + } + + /* Calculate second ECC byte */ + b = 0x80; + for (i = 0; i < 4; i++) { + if (reg3 & a) /* LP7,5,3,1 --> ecc_code[1] */ + tmp2 |= b; + b >>= 1; + if (reg2 & a) /* LP6,4,2,0 --> ecc_code[1] */ + tmp2 |= b; + b >>= 1; + a >>= 1; + } + + /* Store two of the ECC bytes */ + ecc_code[0] = tmp1; + ecc_code[1] = tmp2; +} + /** - * nand_calculate_ecc - [NAND Interface] Calculate 3-byte ECC for 256-byte block + * nand_calculate_ecc - [NAND Interface] Calculate 3 byte ECC code for 256 byte block * @mtd: MTD block structure * @dat: raw data * @ecc_code: buffer for ECC */ -int nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat, - u_char *ecc_code) +int nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat, u_char *ecc_code) { - uint8_t idx, reg1, reg2, reg3, tmp1, tmp2; - int i; + u_char idx, reg1, reg2, reg3; + int j; /* Initialize variables */ reg1 = reg2 = reg3 = 0; + ecc_code[0] = ecc_code[1] = ecc_code[2] = 0; /* Build up column parity */ - for(i = 0; i < 256; i++) { + for(j = 0; j < 256; j++) { + /* Get CP0 - CP5 from table */ - idx = nand_ecc_precalc_table[*dat++]; + idx = nand_ecc_precalc_table[dat[j]]; reg1 ^= (idx & 0x3f); /* All bit XOR = 1 ? */ if (idx & 0x40) { - reg3 ^= (uint8_t) i; - reg2 ^= ~((uint8_t) i); + reg3 ^= (u_char) j; + reg2 ^= ~((u_char) j); } } /* Create non-inverted ECC code from line parity */ - tmp1 = (reg3 & 0x80) >> 0; /* B7 -> B7 */ - tmp1 |= (reg2 & 0x80) >> 1; /* B7 -> B6 */ - tmp1 |= (reg3 & 0x40) >> 1; /* B6 -> B5 */ - tmp1 |= (reg2 & 0x40) >> 2; /* B6 -> B4 */ - tmp1 |= (reg3 & 0x20) >> 2; /* B5 -> B3 */ - tmp1 |= (reg2 & 0x20) >> 3; /* B5 -> B2 */ - tmp1 |= (reg3 & 0x10) >> 3; /* B4 -> B1 */ - tmp1 |= (reg2 & 0x10) >> 4; /* B4 -> B0 */ - - tmp2 = (reg3 & 0x08) << 4; /* B3 -> B7 */ - tmp2 |= (reg2 & 0x08) << 3; /* B3 -> B6 */ - tmp2 |= (reg3 & 0x04) << 3; /* B2 -> B5 */ - tmp2 |= (reg2 & 0x04) << 2; /* B2 -> B4 */ - tmp2 |= (reg3 & 0x02) << 2; /* B1 -> B3 */ - tmp2 |= (reg2 & 0x02) << 1; /* B1 -> B2 */ - tmp2 |= (reg3 & 0x01) << 1; /* B0 -> B1 */ - tmp2 |= (reg2 & 0x01) << 0; /* B7 -> B0 */ + nand_trans_result(reg2, reg3, ecc_code); /* Calculate final ECC code */ -#ifdef CONFIG_MTD_NAND_ECC_SMC - ecc_code[0] = ~tmp2; - ecc_code[1] = ~tmp1; -#else - ecc_code[0] = ~tmp1; - ecc_code[1] = ~tmp2; -#endif + ecc_code[0] = ~ecc_code[0]; + ecc_code[1] = ~ecc_code[1]; ecc_code[2] = ((~reg1) << 2) | 0x03; - return 0; } -#endif /* CONFIG_NAND_SPL */ - -static inline int countbits(uint32_t byte) -{ - int res = 0; - - for (;byte; byte >>= 1) - res += byte & 0x01; - return res; -} /** * nand_correct_data - [NAND Interface] Detect and correct bit error(s) @@ -148,53 +156,89 @@ static inline int countbits(uint32_t byte) * * Detect and correct a 1 bit error for 256 byte block */ -int nand_correct_data(struct mtd_info *mtd, u_char *dat, - u_char *read_ecc, u_char *calc_ecc) +int nand_correct_data(struct mtd_info *mtd, u_char *dat, u_char *read_ecc, u_char *calc_ecc) { - uint8_t s0, s1, s2; - -#ifdef CONFIG_MTD_NAND_ECC_SMC - s0 = calc_ecc[0] ^ read_ecc[0]; - s1 = calc_ecc[1] ^ read_ecc[1]; - s2 = calc_ecc[2] ^ read_ecc[2]; -#else - s1 = calc_ecc[0] ^ read_ecc[0]; - s0 = calc_ecc[1] ^ read_ecc[1]; - s2 = calc_ecc[2] ^ read_ecc[2]; -#endif - if ((s0 | s1 | s2) == 0) - return 0; - - /* Check for a single bit error */ - if( ((s0 ^ (s0 >> 1)) & 0x55) == 0x55 && - ((s1 ^ (s1 >> 1)) & 0x55) == 0x55 && - ((s2 ^ (s2 >> 1)) & 0x54) == 0x54) { + u_char a, b, c, d1, d2, d3, add, bit, i; - uint32_t byteoffs, bitnum; + /* Do error detection */ + d1 = calc_ecc[0] ^ read_ecc[0]; + d2 = calc_ecc[1] ^ read_ecc[1]; + d3 = calc_ecc[2] ^ read_ecc[2]; - byteoffs = (s1 << 0) & 0x80; - byteoffs |= (s1 << 1) & 0x40; - byteoffs |= (s1 << 2) & 0x20; - byteoffs |= (s1 << 3) & 0x10; - - byteoffs |= (s0 >> 4) & 0x08; - byteoffs |= (s0 >> 3) & 0x04; - byteoffs |= (s0 >> 2) & 0x02; - byteoffs |= (s0 >> 1) & 0x01; - - bitnum = (s2 >> 5) & 0x04; - bitnum |= (s2 >> 4) & 0x02; - bitnum |= (s2 >> 3) & 0x01; - - dat[byteoffs] ^= (1 << bitnum); - - return 1; + if ((d1 | d2 | d3) == 0) { + /* No errors */ + return 0; + } + else { + a = (d1 ^ (d1 >> 1)) & 0x55; + b = (d2 ^ (d2 >> 1)) & 0x55; + c = (d3 ^ (d3 >> 1)) & 0x54; + + /* Found and will correct single bit error in the data */ + if ((a == 0x55) && (b == 0x55) && (c == 0x54)) { + c = 0x80; + add = 0; + a = 0x80; + for (i=0; i<4; i++) { + if (d1 & c) + add |= a; + c >>= 2; + a >>= 1; + } + c = 0x80; + for (i=0; i<4; i++) { + if (d2 & c) + add |= a; + c >>= 2; + a >>= 1; + } + bit = 0; + b = 0x04; + c = 0x80; + for (i=0; i<3; i++) { + if (d3 & c) + bit |= b; + c >>= 2; + b >>= 1; + } + b = 0x01; + a = dat[add]; + a ^= (b << bit); + dat[add] = a; + return 1; + } else { + i = 0; + while (d1) { + if (d1 & 0x01) + ++i; + d1 >>= 1; + } + while (d2) { + if (d2 & 0x01) + ++i; + d2 >>= 1; + } + while (d3) { + if (d3 & 0x01) + ++i; + d3 >>= 1; + } + if (i == 1) { + /* ECC Code Error Correction */ + read_ecc[0] = calc_ecc[0]; + read_ecc[1] = calc_ecc[1]; + read_ecc[2] = calc_ecc[2]; + return 2; + } + else { + /* Uncorrectable Error */ + return -1; + } + } } - if(countbits(s0 | ((uint32_t)s1 << 8) | ((uint32_t)s2 <<16)) == 1) - return 1; - + /* Should never happen */ return -1; } -#endif +#endif /* CONFIG_COMMANDS & CFG_CMD_NAND */ diff --git a/drivers/mtd/nand/nand_ids.c b/drivers/mtd/nand/nand_ids.c index 524b6b19a7e..e493002ccd0 100644 --- a/drivers/mtd/nand/nand_ids.c +++ b/drivers/mtd/nand/nand_ids.c @@ -61,15 +61,26 @@ struct nand_flash_dev nand_flash_ids[] = { {"NAND 64MiB 3,3V 16-bit", 0x56, 512, 64, 0x4000, NAND_BUSWIDTH_16}, {"NAND 128MiB 1,8V 8-bit", 0x78, 512, 128, 0x4000, 0}, + {"NAND 128MiB 1,8V 8-bit", 0x39, 512, 128, 0x4000, 0}, {"NAND 128MiB 3,3V 8-bit", 0x79, 512, 128, 0x4000, 0}, {"NAND 128MiB 1,8V 16-bit", 0x72, 512, 128, 0x4000, NAND_BUSWIDTH_16}, + {"NAND 128MiB 1,8V 16-bit", 0x49, 512, 128, 0x4000, NAND_BUSWIDTH_16}, {"NAND 128MiB 3,3V 16-bit", 0x74, 512, 128, 0x4000, NAND_BUSWIDTH_16}, + {"NAND 128MiB 3,3V 16-bit", 0x59, 512, 128, 0x4000, NAND_BUSWIDTH_16}, {"NAND 256MiB 3,3V 8-bit", 0x71, 512, 256, 0x4000, 0}, + {"NAND 512MiB 3,3V 8-bit", 0xDC, 0, 512, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_NO_AUTOINCR}, /* These are the new chips with large page size. The pagesize * and the erasesize is determined from the extended id bytes */ + /*512 Megabit */ + {"NAND 64MiB 1,8V 8-bit", 0xA2, 0, 64, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_NO_AUTOINCR}, + {"NAND 64MiB 3,3V 8-bit", 0xF2, 0, 64, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_NO_AUTOINCR}, + {"NAND 64MiB 1,8V 16-bit", 0xB2, 0, 64, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_BUSWIDTH_16 | NAND_NO_AUTOINCR}, + {"NAND 64MiB 3,3V 16-bit", 0xC2, 0, 64, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_BUSWIDTH_16 | NAND_NO_AUTOINCR}, + + /* 1 Gigabit */ {"NAND 128MiB 1,8V 8-bit", 0xA1, 0, 128, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_NO_AUTOINCR}, {"NAND 128MiB 3,3V 8-bit", 0xF1, 0, 128, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_NO_AUTOINCR}, @@ -121,6 +132,7 @@ struct nand_manufacturers nand_manuf_ids[] = { {NAND_MFR_NATIONAL, "National"}, {NAND_MFR_RENESAS, "Renesas"}, {NAND_MFR_STMICRO, "ST Micro"}, + {NAND_MFR_HYNIX, "Hynix"}, {NAND_MFR_MICRON, "Micron"}, {0x0, "Unknown"} }; diff --git a/drivers/mtd/spi/Makefile b/drivers/mtd/spi/Makefile new file mode 100644 index 00000000000..5941235d8ac --- /dev/null +++ b/drivers/mtd/spi/Makefile @@ -0,0 +1,49 @@ +# +# (C) Copyright 2006 +# 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)libspi_flash.a + +COBJS-$(CONFIG_SPI_FLASH) += spi_flash.o +COBJS-$(CONFIG_SPI_FLASH_ATMEL) += atmel.o +COBJS-$(CONFIG_SPI_FLASH_STMICRO) += stmicro.o +COBJS-$(CONFIG_SPI_FLASH_WINBOND) += winbond.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/mtd/spi/atmel.c b/drivers/mtd/spi/atmel.c new file mode 100644 index 00000000000..fb7a4a939b0 --- /dev/null +++ b/drivers/mtd/spi/atmel.c @@ -0,0 +1,362 @@ +/* + * Atmel SPI DataFlash support + * + * Copyright (C) 2008 Atmel Corporation + */ +#define DEBUG +#include <common.h> +#include <malloc.h> +#include <spi_flash.h> + +#include "spi_flash_internal.h" + +/* AT45-specific commands */ +#define CMD_AT45_READ_STATUS 0xd7 +#define CMD_AT45_ERASE_PAGE 0x81 +#define CMD_AT45_LOAD_PROG_BUF1 0x82 +#define CMD_AT45_LOAD_BUF1 0x84 +#define CMD_AT45_LOAD_PROG_BUF2 0x85 +#define CMD_AT45_LOAD_BUF2 0x87 +#define CMD_AT45_PROG_BUF1 0x88 +#define CMD_AT45_PROG_BUF2 0x89 + +/* AT45 status register bits */ +#define AT45_STATUS_P2_PAGE_SIZE (1 << 0) +#define AT45_STATUS_READY (1 << 7) + +/* DataFlash family IDs, as obtained from the second idcode byte */ +#define DF_FAMILY_AT26F 0 +#define DF_FAMILY_AT45 1 +#define DF_FAMILY_AT26DF 2 /* AT25DF and AT26DF */ + +struct atmel_spi_flash_params { + u8 idcode1; + /* Log2 of page size in power-of-two mode */ + u8 l2_page_size; + u8 pages_per_block; + u8 blocks_per_sector; + u8 nr_sectors; + const char *name; +}; + +struct atmel_spi_flash { + const struct atmel_spi_flash_params *params; + struct spi_flash flash; +}; + +static inline struct atmel_spi_flash * +to_atmel_spi_flash(struct spi_flash *flash) +{ + return container_of(flash, struct atmel_spi_flash, flash); +} + +static const struct atmel_spi_flash_params atmel_spi_flash_table[] = { + { + .idcode1 = 0x28, + .l2_page_size = 10, + .pages_per_block = 8, + .blocks_per_sector = 32, + .nr_sectors = 32, + .name = "AT45DB642D", + }, +}; + +static int at45_wait_ready(struct spi_flash *flash, unsigned long timeout) +{ + struct spi_slave *spi = flash->spi; + unsigned long timebase; + int ret; + u8 cmd = CMD_AT45_READ_STATUS; + u8 status; + + timebase = get_timer(0); + + ret = spi_xfer(spi, 8, &cmd, NULL, SPI_XFER_BEGIN); + if (ret) + return -1; + + do { + ret = spi_xfer(spi, 8, NULL, &status, 0); + if (ret) + return -1; + + if (status & AT45_STATUS_READY) + break; + } while (get_timer(timebase) < timeout); + + /* Deactivate CS */ + spi_xfer(spi, 0, NULL, NULL, SPI_XFER_END); + + if (status & AT45_STATUS_READY) + return 0; + + /* Timed out */ + return -1; +} + +/* + * Assemble the address part of a command for AT45 devices in + * non-power-of-two page size mode. + */ +static void at45_build_address(struct atmel_spi_flash *asf, u8 *cmd, u32 offset) +{ + unsigned long page_addr; + unsigned long byte_addr; + unsigned long page_size; + unsigned int page_shift; + + /* + * The "extra" space per page is the power-of-two page size + * divided by 32. + */ + page_shift = asf->params->l2_page_size; + page_size = (1 << page_shift) + (1 << (page_shift - 5)); + page_shift++; + page_addr = offset / page_size; + byte_addr = offset % page_size; + + cmd[0] = page_addr >> (16 - page_shift); + cmd[1] = page_addr << (page_shift - 8) | (byte_addr >> 8); + cmd[2] = byte_addr; +} + +static int dataflash_read_fast_p2(struct spi_flash *flash, + u32 offset, size_t len, void *buf) +{ + u8 cmd[5]; + + cmd[0] = CMD_READ_ARRAY_FAST; + cmd[1] = offset >> 16; + cmd[2] = offset >> 8; + cmd[3] = offset; + cmd[4] = 0x00; + + return spi_flash_read_common(flash, cmd, sizeof(cmd), buf, len); +} + +static int dataflash_read_fast_at45(struct spi_flash *flash, + u32 offset, size_t len, void *buf) +{ + struct atmel_spi_flash *asf = to_atmel_spi_flash(flash); + u8 cmd[5]; + + cmd[0] = CMD_READ_ARRAY_FAST; + at45_build_address(asf, cmd + 1, offset); + cmd[4] = 0x00; + + return spi_flash_read_common(flash, cmd, sizeof(cmd), buf, len); +} + +static int dataflash_write_at45(struct spi_flash *flash, + u32 offset, size_t len, const void *buf) +{ + struct atmel_spi_flash *asf = to_atmel_spi_flash(flash); + unsigned long page_addr; + unsigned long byte_addr; + unsigned long page_size; + unsigned int page_shift; + size_t chunk_len; + size_t actual; + int ret; + u8 cmd[4]; + + page_shift = asf->params->l2_page_size; + page_size = (1 << page_shift) + (1 << (page_shift - 5)); + page_shift++; + page_addr = offset / page_size; + byte_addr = offset % page_size; + + ret = spi_claim_bus(flash->spi); + if (ret) { + debug("SF: Unable to claim SPI bus\n"); + return ret; + } + + for (actual = 0; actual < len; actual += chunk_len) { + chunk_len = min(len - actual, page_size - byte_addr); + + /* Use the same address bits for both commands */ + cmd[0] = CMD_AT45_LOAD_BUF1; + cmd[1] = page_addr >> (16 - page_shift); + cmd[2] = page_addr << (page_shift - 8) | (byte_addr >> 8); + cmd[3] = byte_addr; + + ret = spi_flash_cmd_write(flash->spi, cmd, 4, + buf + actual, chunk_len); + if (ret < 0) { + debug("SF: Loading AT45 buffer failed\n"); + goto out; + } + + cmd[0] = CMD_AT45_PROG_BUF1; + ret = spi_flash_cmd_write(flash->spi, cmd, 4, NULL, 0); + if (ret < 0) { + debug("SF: AT45 page programming failed\n"); + goto out; + } + + ret = at45_wait_ready(flash, SPI_FLASH_PROG_TIMEOUT); + if (ret < 0) { + debug("SF: AT45 page programming timed out\n"); + goto out; + } + + page_addr++; + byte_addr = 0; + } + + debug("SF: AT45: Successfully programmed %u bytes @ 0x%x\n", + len, offset); + ret = 0; + +out: + spi_release_bus(flash->spi); + return ret; +} + +int dataflash_erase_at45(struct spi_flash *flash, u32 offset, size_t len) +{ + struct atmel_spi_flash *asf = to_atmel_spi_flash(flash); + unsigned long page_addr; + unsigned long page_size; + unsigned int page_shift; + size_t actual; + int ret; + u8 cmd[4]; + + /* + * TODO: This function currently uses page erase only. We can + * probably speed things up by using block and/or sector erase + * when possible. + */ + + page_shift = asf->params->l2_page_size; + page_size = (1 << page_shift) + (1 << (page_shift - 5)); + page_shift++; + page_addr = offset / page_size; + + if (offset % page_size || len % page_size) { + debug("SF: Erase offset/length not multiple of page size\n"); + return -1; + } + + cmd[0] = CMD_AT45_ERASE_PAGE; + cmd[3] = 0x00; + + ret = spi_claim_bus(flash->spi); + if (ret) { + debug("SF: Unable to claim SPI bus\n"); + return ret; + } + + for (actual = 0; actual < len; actual += page_size) { + cmd[1] = page_addr >> (16 - page_shift); + cmd[2] = page_addr << (page_shift - 8); + + ret = spi_flash_cmd_write(flash->spi, cmd, 4, NULL, 0); + if (ret < 0) { + debug("SF: AT45 page erase failed\n"); + goto out; + } + + ret = at45_wait_ready(flash, SPI_FLASH_PAGE_ERASE_TIMEOUT); + if (ret < 0) { + debug("SF: AT45 page erase timed out\n"); + goto out; + } + + page_addr++; + } + + debug("SF: AT45: Successfully erased %u bytes @ 0x%x\n", + len, offset); + ret = 0; + +out: + spi_release_bus(flash->spi); + return ret; +} + +struct spi_flash *spi_flash_probe_atmel(struct spi_slave *spi, u8 *idcode) +{ + const struct atmel_spi_flash_params *params; + unsigned long page_size; + unsigned int family; + struct atmel_spi_flash *asf; + unsigned int i; + int ret; + u8 status; + + for (i = 0; i < ARRAY_SIZE(atmel_spi_flash_table); i++) { + params = &atmel_spi_flash_table[i]; + if (params->idcode1 == idcode[1]) + break; + } + + if (i == ARRAY_SIZE(atmel_spi_flash_table)) { + debug("SF: Unsupported DataFlash ID %02x\n", + idcode[1]); + return NULL; + } + + asf = malloc(sizeof(struct atmel_spi_flash)); + if (!asf) { + debug("SF: Failed to allocate memory\n"); + return NULL; + } + + asf->params = params; + asf->flash.spi = spi; + asf->flash.name = params->name; + + /* Assuming power-of-two page size initially. */ + page_size = 1 << params->l2_page_size; + + family = idcode[1] >> 5; + + switch (family) { + case DF_FAMILY_AT45: + /* + * AT45 chips have configurable page size. The status + * register indicates which configuration is active. + */ + ret = spi_flash_cmd(spi, CMD_AT45_READ_STATUS, &status, 1); + if (ret) + goto err; + + debug("SF: AT45 status register: %02x\n", status); + + if (!(status & AT45_STATUS_P2_PAGE_SIZE)) { + asf->flash.read = dataflash_read_fast_at45; + asf->flash.write = dataflash_write_at45; + asf->flash.erase = dataflash_erase_at45; + page_size += 1 << (params->l2_page_size - 5); + } else { + asf->flash.read = dataflash_read_fast_p2; + } + + break; + + case DF_FAMILY_AT26F: + case DF_FAMILY_AT26DF: + asf->flash.read = dataflash_read_fast_p2; + break; + + default: + debug("SF: Unsupported DataFlash family %u\n", family); + goto err; + } + + asf->flash.size = page_size * params->pages_per_block + * params->blocks_per_sector + * params->nr_sectors; + + debug("SF: Detected %s with page size %u, total %u bytes\n", + params->name, page_size, asf->flash.size); + + return &asf->flash; + +err: + free(asf); + return NULL; +} diff --git a/drivers/mtd/spi/spi_flash.c b/drivers/mtd/spi/spi_flash.c new file mode 100644 index 00000000000..6a3ec89f555 --- /dev/null +++ b/drivers/mtd/spi/spi_flash.c @@ -0,0 +1,172 @@ +/* + * SPI flash interface + * + * Copyright (C) 2008 Atmel Corporation + */ +#include <common.h> +#include <malloc.h> +#include <spi.h> +#include <spi_flash.h> + +#include "spi_flash_internal.h" + +int spi_flash_cmd(struct spi_slave *spi, u8 cmd, void *response, size_t len) +{ + unsigned long flags = SPI_XFER_BEGIN; + int ret; + + if (len == 0) + flags |= SPI_XFER_END; + + ret = spi_xfer(spi, 8, &cmd, NULL, flags); + if (ret) { + debug("SF: Failed to send command %02x: %d\n", cmd, ret); + return ret; + } + + if (len) { + ret = spi_xfer(spi, len * 8, NULL, response, SPI_XFER_END); + if (ret) + debug("SF: Failed to read response (%zu bytes): %d\n", + len, ret); + } + + return ret; +} + +int spi_flash_cmd_read(struct spi_slave *spi, const u8 *cmd, + size_t cmd_len, void *data, size_t data_len) +{ + unsigned long flags = SPI_XFER_BEGIN; + int ret; + + if (data_len == 0) + flags |= SPI_XFER_END; + + ret = spi_xfer(spi, cmd_len * 8, cmd, NULL, flags); + if (ret) { + debug("SF: Failed to send read command (%zu bytes): %d\n", + cmd_len, ret); + } else if (data_len != 0) { + ret = spi_xfer(spi, data_len * 8, NULL, data, SPI_XFER_END); + if (ret) + debug("SF: Failed to read %zu bytes of data: %d\n", + data_len, ret); + } + + return ret; +} + +int spi_flash_cmd_write(struct spi_slave *spi, const u8 *cmd, size_t cmd_len, + const void *data, size_t data_len) +{ + unsigned long flags = SPI_XFER_BEGIN; + int ret; + + if (data_len == 0) + flags |= SPI_XFER_END; + + ret = spi_xfer(spi, cmd_len * 8, cmd, NULL, flags); + if (ret) { + debug("SF: Failed to send read command (%zu bytes): %d\n", + cmd_len, ret); + } else if (data_len != 0) { + ret = spi_xfer(spi, data_len * 8, data, NULL, SPI_XFER_END); + if (ret) + debug("SF: Failed to read %zu bytes of data: %d\n", + data_len, ret); + } + + return ret; +} + + +int spi_flash_read_common(struct spi_flash *flash, const u8 *cmd, + size_t cmd_len, void *data, size_t data_len) +{ + struct spi_slave *spi = flash->spi; + int ret; + + spi_claim_bus(spi); + ret = spi_flash_cmd_read(spi, cmd, cmd_len, data, data_len); + spi_release_bus(spi); + + return ret; +} + +struct spi_flash *spi_flash_probe(unsigned int bus, unsigned int cs, + unsigned int max_hz, unsigned int spi_mode) +{ + struct spi_slave *spi; + struct spi_flash *flash; + int ret; + u8 idcode[3]; + + spi = spi_setup_slave(bus, cs, max_hz, spi_mode); + if (!spi) { + debug("SF: Failed to set up slave\n"); + return NULL; + } + + ret = spi_claim_bus(spi); + if (ret) { + debug("SF: Failed to claim SPI bus: %d\n", ret); + goto err_claim_bus; + } + + /* Read the ID codes */ + ret = spi_flash_cmd(spi, CMD_READ_ID, &idcode, sizeof(idcode)); + if (ret) + goto err_read_id; + + debug("SF: Got idcode %02x %02x %02x\n", idcode[0], + idcode[1], idcode[2]); + + switch (idcode[0]) { +#ifdef CONFIG_SPI_FLASH_SPANSION + case 0x01: + flash = spi_flash_probe_spansion(spi, idcode); + break; +#endif +#ifdef CONFIG_SPI_FLASH_ATMEL + case 0x1F: + flash = spi_flash_probe_atmel(spi, idcode); + break; +#endif +#ifdef CONFIG_SPI_FLASH_WINBOND + case 0xef: + flash = spi_flash_probe_winbond(spi, idcode); + break; +#endif +#ifdef CONFIG_SPI_FLASH_STMICRO + case 0x00: + case 0xff: + flash = spi_flash_probe_stmicro(spi, idcode); + break; +#endif + default: + debug("SF: Unsupported manufacturer %02X\n", idcode[0]); + flash = NULL; + break; + } + + if (!flash) + goto err_manufacturer_probe; + + spi_release_bus(spi); + + return flash; + +err_manufacturer_probe: +err_read_id: + spi_release_bus(spi); +err_claim_bus: + spi_free_slave(spi); + return NULL; +} + +void spi_flash_free(struct spi_flash *flash) +{ + spi_free_slave(flash->spi); + free(flash); +} diff --git a/drivers/mtd/spi/spi_flash_internal.h b/drivers/mtd/spi/spi_flash_internal.h new file mode 100644 index 00000000000..1eacb5c7487 --- /dev/null +++ b/drivers/mtd/spi/spi_flash_internal.h @@ -0,0 +1,47 @@ +/* + * SPI flash internal definitions + * + * Copyright (C) 2008 Atmel Corporation + */ + +/* Common parameters */ +#define SPI_FLASH_PROG_TIMEOUT ((10 * CFG_HZ) / 1000) +#define SPI_FLASH_PAGE_ERASE_TIMEOUT ((50 * CFG_HZ) / 1000) +#define SPI_FLASH_SECTOR_ERASE_TIMEOUT (10 * CFG_HZ) + +/* Common commands */ +#define CMD_READ_ID 0x9f + +#define CMD_READ_ARRAY_SLOW 0x03 +#define CMD_READ_ARRAY_FAST 0x0b +#define CMD_READ_ARRAY_LEGACY 0xe8 + +/* Send a single-byte command to the device and read the response */ +int spi_flash_cmd(struct spi_slave *spi, u8 cmd, void *response, size_t len); + +/* + * Send a multi-byte command to the device and read the response. Used + * for flash array reads, etc. + */ +int spi_flash_cmd_read(struct spi_slave *spi, const u8 *cmd, + size_t cmd_len, void *data, size_t data_len); + +/* + * Send a multi-byte command to the device followed by (optional) + * data. Used for programming the flash array, etc. + */ +int spi_flash_cmd_write(struct spi_slave *spi, const u8 *cmd, size_t cmd_len, + const void *data, size_t data_len); + +/* + * Same as spi_flash_cmd_read() except it also claims/releases the SPI + * bus. Used as common part of the ->read() operation. + */ +int spi_flash_read_common(struct spi_flash *flash, const u8 *cmd, + size_t cmd_len, void *data, size_t data_len); + +/* Manufacturer-specific probe functions */ +struct spi_flash *spi_flash_probe_spansion(struct spi_slave *spi, u8 *idcode); +struct spi_flash *spi_flash_probe_atmel(struct spi_slave *spi, u8 *idcode); +struct spi_flash *spi_flash_probe_stmicro(struct spi_slave *spi, u8 *idcode); +struct spi_flash *spi_flash_probe_winbond(struct spi_slave *spi, u8 *idcode); diff --git a/drivers/mtd/spi/stmicro.c b/drivers/mtd/spi/stmicro.c new file mode 100644 index 00000000000..b8b835a3ffe --- /dev/null +++ b/drivers/mtd/spi/stmicro.c @@ -0,0 +1,356 @@ +/* + * (C) Copyright 2000-2002 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * Copyright 2008, Network Appliance Inc. + * Jason McMullan <mcmullan@netapp.com> + * + * Copyright (C) 2004-2007 Freescale Semiconductor, Inc. + * TsiChung Liew (Tsi-Chung.Liew@freescale.com) + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include <common.h> +#include <malloc.h> +#include <spi_flash.h> + +#include "spi_flash_internal.h" + +/* M25Pxx-specific commands */ +#define CMD_M25PXX_WREN 0x06 /* Write Enable */ +#define CMD_M25PXX_WRDI 0x04 /* Write Disable */ +#define CMD_M25PXX_RDSR 0x05 /* Read Status Register */ +#define CMD_M25PXX_WRSR 0x01 /* Write Status Register */ +#define CMD_M25PXX_READ 0x03 /* Read Data Bytes */ +#define CMD_M25PXX_FAST_READ 0x0b /* Read Data Bytes at Higher Speed */ +#define CMD_M25PXX_PP 0x02 /* Page Program */ +#define CMD_M25PXX_SE 0xd8 /* Sector Erase */ +#define CMD_M25PXX_BE 0xc7 /* Bulk Erase */ +#define CMD_M25PXX_DP 0xb9 /* Deep Power-down */ +#define CMD_M25PXX_RES 0xab /* Release from DP, and Read Signature */ + +#define STM_ID_M25P16 0x15 +#define STM_ID_M25P20 0x12 +#define STM_ID_M25P32 0x16 +#define STM_ID_M25P40 0x13 +#define STM_ID_M25P64 0x17 +#define STM_ID_M25P80 0x14 +#define STM_ID_M25P128 0x18 + +#define STMICRO_SR_WIP (1 << 0) /* Write-in-Progress */ + +struct stmicro_spi_flash_params { + u8 idcode1; + u16 page_size; + u16 pages_per_sector; + u16 nr_sectors; + const char *name; +}; + +struct stmicro_spi_flash { + const struct stmicro_spi_flash_params *params; + struct spi_flash flash; +}; + +static inline struct stmicro_spi_flash *to_stmicro_spi_flash(struct spi_flash + *flash) +{ + return container_of(flash, struct stmicro_spi_flash, flash); +} + +static const struct stmicro_spi_flash_params stmicro_spi_flash_table[] = { + { + .idcode1 = STM_ID_M25P16, + .page_size = 256, + .pages_per_sector = 256, + .nr_sectors = 32, + .name = "M25P16", + }, + { + .idcode1 = STM_ID_M25P20, + .page_size = 256, + .pages_per_sector = 256, + .nr_sectors = 4, + .name = "M25P20", + }, + { + .idcode1 = STM_ID_M25P32, + .page_size = 256, + .pages_per_sector = 256, + .nr_sectors = 64, + .name = "M25P32", + }, + { + .idcode1 = STM_ID_M25P40, + .page_size = 256, + .pages_per_sector = 256, + .nr_sectors = 8, + .name = "M25P40", + }, + { + .idcode1 = STM_ID_M25P64, + .page_size = 256, + .pages_per_sector = 256, + .nr_sectors = 128, + .name = "M25P64", + }, + { + .idcode1 = STM_ID_M25P80, + .page_size = 256, + .pages_per_sector = 256, + .nr_sectors = 16, + .name = "M25P80", + }, + { + .idcode1 = STM_ID_M25P128, + .page_size = 256, + .pages_per_sector = 1024, + .nr_sectors = 64, + .name = "M25P128", + }, +}; + +static int stmicro_wait_ready(struct spi_flash *flash, unsigned long timeout) +{ + struct spi_slave *spi = flash->spi; + unsigned long timebase; + int ret; + u8 status; + u8 cmd[4] = { CMD_M25PXX_RDSR, 0xff, 0xff, 0xff }; + + ret = spi_xfer(spi, 32, &cmd[0], NULL, SPI_XFER_BEGIN); + if (ret) { + debug("SF: Failed to send command %02x: %d\n", cmd, ret); + return ret; + } + + timebase = get_timer(0); + do { + ret = spi_xfer(spi, 8, NULL, &status, 0); + if (ret) + return -1; + + if ((status & STMICRO_SR_WIP) == 0) + break; + + } while (get_timer(timebase) < timeout); + + spi_xfer(spi, 0, NULL, NULL, SPI_XFER_END); + + if ((status & STMICRO_SR_WIP) == 0) + return 0; + + /* Timed out */ + return -1; +} + +static int stmicro_read_fast(struct spi_flash *flash, + u32 offset, size_t len, void *buf) +{ + struct stmicro_spi_flash *stm = to_stmicro_spi_flash(flash); + unsigned long page_addr; + unsigned long page_size; + u8 cmd[5]; + + page_size = stm->params->page_size; + page_addr = offset / page_size; + + cmd[0] = CMD_READ_ARRAY_FAST; + cmd[1] = page_addr >> 8; + cmd[2] = page_addr; + cmd[3] = offset % page_size; + cmd[4] = 0x00; + + return spi_flash_read_common(flash, cmd, sizeof(cmd), buf, len); +} + +static int stmicro_write(struct spi_flash *flash, + u32 offset, size_t len, const void *buf) +{ + struct stmicro_spi_flash *stm = to_stmicro_spi_flash(flash); + unsigned long page_addr; + unsigned long byte_addr; + unsigned long page_size; + size_t chunk_len; + size_t actual; + int ret; + u8 cmd[4]; + + page_size = stm->params->page_size; + page_addr = offset / page_size; + byte_addr = offset % page_size; + + ret = spi_claim_bus(flash->spi); + if (ret) { + debug("SF: Unable to claim SPI bus\n"); + return ret; + } + + ret = 0; + for (actual = 0; actual < len; actual += chunk_len) { + chunk_len = min(len - actual, page_size - byte_addr); + + cmd[0] = CMD_M25PXX_PP; + cmd[1] = page_addr >> 8; + cmd[2] = page_addr; + cmd[3] = byte_addr; + + debug + ("PP: 0x%p => cmd = { 0x%02x 0x%02x%02x%02x } chunk_len = %d\n", + buf + actual, cmd[0], cmd[1], cmd[2], cmd[3], chunk_len); + + ret = spi_flash_cmd(flash->spi, CMD_M25PXX_WREN, NULL, 0); + if (ret < 0) { + debug("SF: Enabling Write failed\n"); + break; + } + + ret = spi_flash_cmd_write(flash->spi, cmd, 4, + buf + actual, chunk_len); + if (ret < 0) { + debug("SF: STMicro Page Program failed\n"); + break; + } + + ret = stmicro_wait_ready(flash, SPI_FLASH_PROG_TIMEOUT); + if (ret < 0) { + debug("SF: STMicro page programming timed out\n"); + break; + } + + page_addr++; + byte_addr = 0; + } + + debug("SF: STMicro: Successfully programmed %u bytes @ 0x%x\n", + len, offset); + + spi_release_bus(flash->spi); + return ret; +} + +int stmicro_erase(struct spi_flash *flash, u32 offset, size_t len) +{ + struct stmicro_spi_flash *stm = to_stmicro_spi_flash(flash); + unsigned long sector_size; + size_t actual; + int ret; + u8 cmd[4]; + + /* + * This function currently uses sector erase only. + * probably speed things up by using bulk erase + * when possible. + */ + + sector_size = stm->params->page_size * stm->params->pages_per_sector; + + if (offset % sector_size || len % sector_size) { + debug("SF: Erase offset/length not multiple of sector size\n"); + return -1; + } + + len /= sector_size; + cmd[0] = CMD_M25PXX_SE; + cmd[2] = 0x00; + cmd[3] = 0x00; + + ret = spi_claim_bus(flash->spi); + if (ret) { + debug("SF: Unable to claim SPI bus\n"); + return ret; + } + + ret = 0; + for (actual = 0; actual < len; actual++) { + cmd[1] = (offset / sector_size) + actual; + + ret = spi_flash_cmd(flash->spi, CMD_M25PXX_WREN, NULL, 0); + if (ret < 0) { + debug("SF: Enabling Write failed\n"); + break; + } + + ret = spi_flash_cmd_write(flash->spi, cmd, 4, NULL, 0); + if (ret < 0) { + debug("SF: STMicro page erase failed\n"); + break; + } + + /* Up to 2 seconds */ + ret = stmicro_wait_ready(flash, 2 * CONFIG_SYS_HZ); + if (ret < 0) { + debug("SF: STMicro page erase timed out\n"); + break; + } + } + + debug("SF: STMicro: Successfully erased %u bytes @ 0x%x\n", + len * sector_size, offset); + + spi_release_bus(flash->spi); + return ret; +} + +struct spi_flash *spi_flash_probe_stmicro(struct spi_slave *spi, u8 * idcode) +{ + const struct stmicro_spi_flash_params *params; + struct stmicro_spi_flash *stm; + unsigned int i; + int ret; + u8 id[3]; + + ret = spi_flash_cmd(spi, CMD_READ_ID, id, sizeof(id)); + if (ret) + return NULL; + + for (i = 0; i < ARRAY_SIZE(stmicro_spi_flash_table); i++) { + params = &stmicro_spi_flash_table[i]; + if (params->idcode1 == idcode[2]) { + break; + } + } + + if (i == ARRAY_SIZE(stmicro_spi_flash_table)) { + debug("SF: Unsupported STMicro ID %02x\n", id[1]); + return NULL; + } + + stm = malloc(sizeof(struct stmicro_spi_flash)); + if (!stm) { + debug("SF: Failed to allocate memory\n"); + return NULL; + } + + stm->params = params; + stm->flash.spi = spi; + stm->flash.name = params->name; + + stm->flash.write = stmicro_write; + stm->flash.erase = stmicro_erase; + stm->flash.read = stmicro_read_fast; + stm->flash.size = params->page_size * params->pages_per_sector + * params->nr_sectors; + + debug("SF: Detected %s with page size %u, total %u bytes\n", + params->name, params->page_size, stm->flash.size); + + return &stm->flash; +} diff --git a/drivers/mtd/spi/winbond.c b/drivers/mtd/spi/winbond.c new file mode 100644 index 00000000000..5fa4ce056f1 --- /dev/null +++ b/drivers/mtd/spi/winbond.c @@ -0,0 +1,334 @@ +/* + * (C) Copyright 2000-2002 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * Copyright 2008, Texas Instrumemnts Inc. + * Modified to suppport Winbond flash. + * + * Copyright 2008, Network Appliance Inc. + * Jason McMullan <mcmullan@netapp.com> + * + * Copyright (C) 2004-2007 Freescale Semiconductor, Inc. + * TsiChung Liew (Tsi-Chung.Liew@freescale.com) + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include <common.h> +#include <malloc.h> +#include <spi_flash.h> + +#include "spi_flash_internal.h" + +/* W25 specific commands. Derived from section 12.2 of + * http://www.winbond-usa.com/products/Nexflash/pdfs/datasheets/W25X16_32_64h.pdf + */ +#define CMD_W25_WREN 0x06 /* Write Enable */ +#define CMD_W25_WRDI 0x04 /* Write Disable */ +#define CMD_W25_RDSR 0x05 /* Read Status Register */ +#define CMD_W25_WRSR 0x01 /* Write Status Register */ +#define CMD_W25_READ 0x03 /* Read Data Bytes */ +#define CMD_W25_FAST_READ 0x0b /* Read Data Bytes at Higher Speed */ +#define CMD_W25_PP 0x02 /* Page Program */ +#define CMD_W25_SE 0x20 /* Sector Erase */ +#define CMD_W25_BE 0xd8 /* Bulk Erase */ +#define CMD_W25_DP 0xb9 /* Deep Power-down */ +#define CMD_W25_RES 0xab /* Release from DP, and Read Signature */ + +#define WINBOND_ID_W25X16 0x3015 +#define WINBOND_ID_W25X32 0x3016 +#define WINBOND_ID_W25X64 0x3017 + +#define WINBOND_SR_WIP (1 << 0) /* Write-in-Progress */ + +struct winbond_spi_flash_params { + u16 idcode; + u16 page_size; + u16 pages_per_sector; + u16 nr_sectors; + const char *name; +}; + +struct winbond_spi_flash { + const struct winbond_spi_flash_params *params; + struct spi_flash flash; +}; + +static inline struct winbond_spi_flash *to_winbond_spi_flash(struct spi_flash + *flash) +{ + return container_of(flash, struct winbond_spi_flash, flash); +} + +/* W25 specific flash parameters. Derived from chapter 1 of + * http://www.winbond-usa.com/products/Nexflash/pdfs/datasheets/W25X16_32_64h.pdf + */ +static const struct winbond_spi_flash_params winbond_spi_flash_table[] = { + { + .idcode = WINBOND_ID_W25X32, + .page_size = 256, + .pages_per_sector = 16, + .nr_sectors = 1024, + .name = "W25X32", + }, + { + .idcode = WINBOND_ID_W25X16, + .page_size = 256, + .pages_per_sector = 16, + .nr_sectors = 512, + .name = "W25X16", + }, + { + .idcode = WINBOND_ID_W25X64, + .page_size = 256, + .pages_per_sector = 16, + .nr_sectors = 2048, + .name = "W25X64", + }, + +}; + +static int winbond_wait_ready(struct spi_flash *flash, unsigned long timeout) +{ + struct spi_slave *spi = flash->spi; + unsigned long timebase; + int ret; + u8 status; + u8 cmd[4] = { CMD_W25_RDSR, 0xff, 0xff, 0xff }; + + ret = spi_xfer(spi, 32, &cmd[0], NULL, SPI_XFER_BEGIN); + if (ret) { + debug("SF: Failed to send command %02x: %d\n", cmd, ret); + return ret; + } + + timebase = get_timer(0); + do { + ret = spi_xfer(spi, 8, NULL, &status, 0); + if (ret) + return -1; + + if ((status & WINBOND_SR_WIP) == 0) + break; + + } while (get_timer(timebase) < timeout); + + spi_xfer(spi, 0, NULL, NULL, SPI_XFER_END); + + if ((status & WINBOND_SR_WIP) == 0) + return 0; + + /* Timed out */ + return -1; +} + +static int winbond_read_fast(struct spi_flash *flash, + u32 offset, size_t len, void *buf) +{ + struct winbond_spi_flash *win = to_winbond_spi_flash(flash); + u8 cmd[5]; + int i, j; + + cmd[0] = CMD_READ_ARRAY_FAST; + for (i = 0, j = 1; i < 24; i += 8) + cmd[j++] = ((offset >> (16 - i)) & 0xFF); + cmd[4] = 0x00; + + return spi_flash_read_common(flash, cmd, sizeof(cmd), buf, len); +} + +static int winbond_write(struct spi_flash *flash, + u32 offset, size_t len, const void *buf) +{ + struct winbond_spi_flash *win = to_winbond_spi_flash(flash); + unsigned long page_addr; + unsigned long byte_addr; + unsigned long page_size; + size_t chunk_len; + size_t actual; + int ret, i, j; + u8 cmd[4]; + + page_size = win->params->page_size; + page_addr = offset / page_size; + byte_addr = offset % page_size; + + ret = spi_claim_bus(flash->spi); + if (ret) { + debug("SF: Unable to claim SPI bus\n"); + return ret; + } + + ret = 0; + for (actual = 0; actual < len; actual += chunk_len) { + chunk_len = min(len - actual, page_size - byte_addr); + + cmd[0] = CMD_W25_PP; + for (i = 0, j = 1; i < 24; i += 8) + cmd[j++] = ((offset >> (16 - i)) & 0xFF); + + debug + ("PP: 0x%p => cmd = { 0x%02x 0x%02x%02x%02x } chunk_len = %d\n", + buf + actual, cmd[0], cmd[1], cmd[2], cmd[3], chunk_len); + + ret = spi_flash_cmd(flash->spi, CMD_W25_WREN, NULL, 0); + if (ret < 0) { + debug("SF: Enabling Write failed\n"); + break; + } + + ret = spi_flash_cmd_write(flash->spi, cmd, 4, + buf + actual, chunk_len); + if (ret < 0) { + debug("SF: Winbond Page Program failed\n"); + break; + } + + ret = winbond_wait_ready(flash, SPI_FLASH_PROG_TIMEOUT); + if (ret < 0) { + debug("SF: Winbond page programming timed out\n"); + break; + } + + page_addr++; + offset += chunk_len; + byte_addr = 0; + } + + debug("SF: Winbond: Successfully programmed %u bytes @ 0x%x\n", + len, offset); + + spi_release_bus(flash->spi); + return ret; +} + +int winbond_erase(struct spi_flash *flash, u32 offset, size_t len) +{ + struct winbond_spi_flash *win = to_winbond_spi_flash(flash); + unsigned long sector_size; + size_t actual; + int ret, i , j; + u8 cmd[4]; + + /* + * This function currently uses sector erase only. + * probably speed things up by using bulk erase + * when possible. + */ + + sector_size = win->params->page_size * win->params->pages_per_sector; + + if (offset % sector_size || len % sector_size) { + debug("SF: Erase offset/length not multiple of sector size\n"); + return -1; + } + + len /= sector_size; + cmd[0] = CMD_W25_SE; + + ret = spi_claim_bus(flash->spi); + if (ret) { + debug("SF: Unable to claim SPI bus\n"); + return ret; + } + + ret = 0; + for (actual = 0; actual < len; actual++) { + + for (i = 0, j = 1; i < 24; i += 8) + cmd[j++] = ((offset >> (16 - i)) & 0xFF); + + debug + ("SE: cmd = { 0x%02x 0x%02x%02x%02x }\n", + cmd[0], cmd[1], cmd[2], cmd[3]); + + ret = spi_flash_cmd(flash->spi, CMD_W25_WREN, NULL, 0); + if (ret < 0) { + debug("SF: Enabling Write failed\n"); + break; + } + + ret = spi_flash_cmd_write(flash->spi, cmd, 4, NULL, 0); + if (ret < 0) { + debug("SF: Winbond page erase failed\n"); + break; + } + + /* Up to 2 seconds */ + ret = winbond_wait_ready(flash, 2 * CFG_HZ); + if (ret < 0) { + debug("SF: Winbond page erase timed out\n"); + break; + } + + offset += sector_size; + } + + debug("SF: Winbond: Successfully erased %u bytes @ 0x%x\n", + len * sector_size, offset); + + spi_release_bus(flash->spi); + return ret; +} + +struct spi_flash *spi_flash_probe_winbond(struct spi_slave *spi, u8 * idcode) +{ + const struct winbond_spi_flash_params *params; + struct winbond_spi_flash *win; + unsigned int i; + int ret; + u8 id[3]; + u16 idmatch = ((idcode[1] << 8) | idcode[2]); + + ret = spi_flash_cmd(spi, CMD_READ_ID, id, sizeof(id)); + if (ret) + return NULL; + + for (i = 0; i < ARRAY_SIZE(winbond_spi_flash_table); i++) { + params = &winbond_spi_flash_table[i]; + if (params->idcode == idmatch) + break; + } + + if (i == ARRAY_SIZE(winbond_spi_flash_table)) { + debug("SF: Unsupported Winbond ID %02x\n", idmatch); + return NULL; + } + + win = malloc(sizeof(struct winbond_spi_flash)); + if (!win) { + debug("SF: Failed to allocate memory\n"); + return NULL; + } + + win->params = params; + win->flash.spi = spi; + win->flash.name = params->name; + + win->flash.write = winbond_write; + win->flash.erase = winbond_erase; + win->flash.read = winbond_read_fast; + win->flash.size = params->page_size * params->pages_per_sector + * params->nr_sectors; + + debug("SF: Detected %s with page size %u, total %u bytes\n", + params->name, params->page_size, win->flash.size); + + return &win->flash; +} diff --git a/drivers/rtc/ds1306.c b/drivers/rtc/ds1306.c index 1c8ac7f2927..29854fc7c4c 100644 --- a/drivers/rtc/ds1306.c +++ b/drivers/rtc/ds1306.c @@ -62,13 +62,6 @@ #define RTC_USER_RAM_BASE 0x20 -/* - * External table of chip select functions (see the appropriate board - * support for the actual definition of the table). - */ -extern spi_chipsel_type spi_chipsel[]; -extern int spi_chipsel_cnt; - static unsigned int bin2bcd (unsigned int n); static unsigned char bcd2bin (unsigned char c); @@ -305,11 +298,29 @@ void rtc_reset (void) static unsigned char rtc_read (unsigned char reg); static void rtc_write (unsigned char reg, unsigned char val); +static struct spi_slave *slave; + /* read clock time from DS1306 and return it in *tmp */ int rtc_get (struct rtc_time *tmp) { unsigned char sec, min, hour, mday, wday, mon, year; + /* + * Assuming Vcc = 2.0V (lowest speed) + * + * REVISIT: If we add an rtc_init() function we can do this + * step just once. + */ + if (!slave) { + slave = spi_setup_slave(0, CFG_SPI_RTC_DEVID, 600000, + SPI_MODE_3 | SPI_CS_HIGH); + if (!slave) + return; + } + + if (spi_claim_bus(slave)) + return; + sec = rtc_read (RTC_SECONDS); min = rtc_read (RTC_MINUTES); hour = rtc_read (RTC_HOURS); @@ -318,6 +329,8 @@ int rtc_get (struct rtc_time *tmp) mon = rtc_read (RTC_MONTH); year = rtc_read (RTC_YEAR); + spi_release_bus(slave); + debug ("Get RTC year: %02x mon: %02x mday: %02x wday: %02x " "hr: %02x min: %02x sec: %02x\n", year, mon, mday, wday, hour, min, sec); @@ -360,6 +373,17 @@ int rtc_get (struct rtc_time *tmp) /* set clock time from *tmp in DS1306 RTC */ void rtc_set (struct rtc_time *tmp) { + /* Assuming Vcc = 2.0V (lowest speed) */ + if (!slave) { + slave = spi_setup_slave(0, CFG_SPI_RTC_DEVID, 600000, + SPI_MODE_3 | SPI_CS_HIGH); + if (!slave) + return; + } + + if (spi_claim_bus(slave)) + return; + debug ("Set DATE: %4d-%02d-%02d (wday=%d) TIME: %2d:%02d:%02d\n", tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_wday, tmp->tm_hour, tmp->tm_min, tmp->tm_sec); @@ -371,6 +395,8 @@ void rtc_set (struct rtc_time *tmp) rtc_write (RTC_DATE_OF_MONTH, bin2bcd (tmp->tm_mday)); rtc_write (RTC_MONTH, bin2bcd (tmp->tm_mon)); rtc_write (RTC_YEAR, bin2bcd (tmp->tm_year - 2000)); + + spi_release_bus(slave); } /* ------------------------------------------------------------------------- */ @@ -378,6 +404,17 @@ void rtc_set (struct rtc_time *tmp) /* reset the DS1306 */ void rtc_reset (void) { + /* Assuming Vcc = 2.0V (lowest speed) */ + if (!slave) { + slave = spi_setup_slave(0, CFG_SPI_RTC_DEVID, 600000, + SPI_MODE_3 | SPI_CS_HIGH); + if (!slave) + return; + } + + if (spi_claim_bus(slave)) + return; + /* clear the control register */ rtc_write (RTC_CONTROL, 0x00); /* 1st step: reset WP */ rtc_write (RTC_CONTROL, 0x00); /* 2nd step: reset 1Hz, AIE1, AIE0 */ @@ -391,22 +428,18 @@ void rtc_reset (void) rtc_write (RTC_HOURS_ALARM1, 0x00); rtc_write (RTC_DAY_OF_WEEK_ALARM0, 0x00); rtc_write (RTC_DAY_OF_WEEK_ALARM1, 0x00); + + spi_release_bus(slave); } /* ------------------------------------------------------------------------- */ static unsigned char rtc_read (unsigned char reg) { - unsigned char dout[2]; /* SPI Output Data Bytes */ - unsigned char din[2]; /* SPI Input Data Bytes */ - - dout[0] = reg; + int ret; - if (spi_xfer (spi_chipsel[CFG_SPI_RTC_DEVID], 16, dout, din) != 0) { - return 0; - } else { - return din[1]; - } + ret = spi_w8r8(slave, reg); + return ret < 0 ? 0 : ret; } /* ------------------------------------------------------------------------- */ @@ -419,7 +452,7 @@ static void rtc_write (unsigned char reg, unsigned char val) dout[0] = 0x80 | reg; dout[1] = val; - spi_xfer (spi_chipsel[CFG_SPI_RTC_DEVID], 16, dout, din); + spi_xfer (slave, 16, dout, din, SPI_XFER_BEGIN | SPI_XFER_END); } #endif /* end of code exclusion (see #ifdef CONFIG_SXNI855T above) */ diff --git a/drivers/rtc/mc13783-rtc.c b/drivers/rtc/mc13783-rtc.c index 35b1b8b254d..b6e15014bb6 100644 --- a/drivers/rtc/mc13783-rtc.c +++ b/drivers/rtc/mc13783-rtc.c @@ -24,34 +24,50 @@ #include <rtc.h> #include <spi.h> +static struct spi_slave *slave; + int rtc_get(struct rtc_time *rtc) { u32 day1, day2, time; u32 reg; int err, tim, i = 0; - spi_select(1, 0, SPI_MODE_2 | SPI_CS_HIGH); + if (!slave) { + /* FIXME: Verify the max SCK rate */ + slave = spi_setup_slave(1, 0, 1000000, + SPI_MODE_2 | SPI_CS_HIGH); + if (!slave) + return -1; + } + + if (spi_claim_bus(slave)) + return -1; do { reg = 0x2c000000; - err = spi_xfer(0, 32, (uchar *)®, (uchar *)&day1); + err = spi_xfer(slave, 32, (uchar *)®, (uchar *)&day1, + SPI_XFER_BEGIN | SPI_XFER_END); if (err) return err; reg = 0x28000000; - err = spi_xfer(0, 32, (uchar *)®, (uchar *)&time); + err = spi_xfer(slave, 32, (uchar *)®, (uchar *)&time, + SPI_XFER_BEGIN | SPI_XFER_END); if (err) return err; reg = 0x2c000000; - err = spi_xfer(0, 32, (uchar *)®, (uchar *)&day2); + err = spi_xfer(slave, 32, (uchar *)®, (uchar *)&day2, + SPI_XFER_BEGIN | SPI_XFER_END); if (err) return err; } while (day1 != day2 && i++ < 3); + spi_release_bus(slave); + tim = day1 * 86400 + time; to_tm(tim, rtc); @@ -65,16 +81,31 @@ void rtc_set(struct rtc_time *rtc) { u32 time, day, reg; + if (!slave) { + /* FIXME: Verify the max SCK rate */ + slave = spi_setup_slave(1, 0, 1000000, + SPI_MODE_2 | SPI_CS_HIGH); + if (!slave) + return; + } + time = mktime(rtc->tm_year, rtc->tm_mon, rtc->tm_mday, rtc->tm_hour, rtc->tm_min, rtc->tm_sec); day = time / 86400; time %= 86400; + if (spi_claim_bus(slave)) + return; + reg = 0x2c000000 | day | 0x80000000; - spi_xfer(0, 32, (uchar *)®, (uchar *)&day); + spi_xfer(slave, 32, (uchar *)®, (uchar *)&day, + SPI_XFER_BEGIN | SPI_XFER_END); reg = 0x28000000 | time | 0x80000000; - spi_xfer(0, 32, (uchar *)®, (uchar *)&time); + spi_xfer(slave, 32, (uchar *)®, (uchar *)&time, + SPI_XFER_BEGIN | SPI_XFER_END); + + spi_release_bus(slave); } void rtc_reset(void) diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile index bc8a1041210..a917ba5c1d6 100644 --- a/drivers/spi/Makefile +++ b/drivers/spi/Makefile @@ -26,7 +26,9 @@ include $(TOPDIR)/config.mk LIB := $(obj)libspi.a COBJS-y += mpc8xxx_spi.o +COBJS-$(CONFIG_ATMEL_SPI) += atmel_spi.o COBJS-$(CONFIG_MXC_SPI) += mxc_spi.o +COBJS-$(CONFIG_DAVINCI_SPI) += davinci_spi.o COBJS := $(COBJS-y) SRCS := $(COBJS:.o=.c) diff --git a/drivers/spi/atmel_spi.c b/drivers/spi/atmel_spi.c new file mode 100644 index 00000000000..317c0b41b6f --- /dev/null +++ b/drivers/spi/atmel_spi.c @@ -0,0 +1,210 @@ +/* + * Copyright (C) 2007 Atmel Corporation + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ +#include <common.h> +#include <spi.h> +#include <malloc.h> + +#include <asm/io.h> + +#include <asm/arch/clk.h> +#include <asm/arch/memory-map.h> + +#include "atmel_spi.h" + +void spi_init() +{ + +} + +struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs, + unsigned int max_hz, unsigned int mode) +{ + struct atmel_spi_slave *as; + unsigned int scbr; + u32 csrx; + void *regs; + + if (cs > 3 || !spi_cs_is_valid(bus, cs)) + return NULL; + + switch (bus) { + case 0: + regs = (void *)SPI0_BASE; + break; +#ifdef SPI1_BASE + case 1: + regs = (void *)SPI1_BASE; + break; +#endif +#ifdef SPI2_BASE + case 2: + regs = (void *)SPI2_BASE; + break; +#endif +#ifdef SPI3_BASE + case 3: + regs = (void *)SPI3_BASE; + break; +#endif + default: + return NULL; + } + + + scbr = (get_spi_clk_rate(bus) + max_hz - 1) / max_hz; + if (scbr > ATMEL_SPI_CSRx_SCBR_MAX) + /* Too low max SCK rate */ + return NULL; + if (scbr < 1) + scbr = 1; + + csrx = ATMEL_SPI_CSRx_SCBR(scbr); + csrx |= ATMEL_SPI_CSRx_BITS(ATMEL_SPI_BITS_8); + if (!(mode & SPI_CPHA)) + csrx |= ATMEL_SPI_CSRx_NCPHA; + if (mode & SPI_CPOL) + csrx |= ATMEL_SPI_CSRx_CPOL; + + as = malloc(sizeof(struct atmel_spi_slave)); + if (!as) + return NULL; + + as->slave.bus = bus; + as->slave.cs = cs; + as->regs = regs; + as->mr = ATMEL_SPI_MR_MSTR | ATMEL_SPI_MR_MODFDIS + | ATMEL_SPI_MR_PCS(~(1 << cs) & 0xf); + spi_writel(as, CSR(cs), csrx); + + return &as->slave; +} + +void spi_free_slave(struct spi_slave *slave) +{ + struct atmel_spi_slave *as = to_atmel_spi(slave); + + free(as); +} + +int spi_claim_bus(struct spi_slave *slave) +{ + struct atmel_spi_slave *as = to_atmel_spi(slave); + + /* Enable the SPI hardware */ + spi_writel(as, CR, ATMEL_SPI_CR_SPIEN); + + /* + * Select the slave. This should set SCK to the correct + * initial state, etc. + */ + spi_writel(as, MR, as->mr); + + return 0; +} + +void spi_release_bus(struct spi_slave *slave) +{ + struct atmel_spi_slave *as = to_atmel_spi(slave); + + /* Disable the SPI hardware */ + spi_writel(as, CR, ATMEL_SPI_CR_SPIDIS); +} + +int spi_xfer(struct spi_slave *slave, unsigned int bitlen, + const void *dout, void *din, unsigned long flags) +{ + struct atmel_spi_slave *as = to_atmel_spi(slave); + unsigned int len_tx; + unsigned int len_rx; + unsigned int len; + int ret; + u32 status; + const u8 *txp = dout; + u8 *rxp = din; + u8 value; + + ret = 0; + if (bitlen == 0) + /* Finish any previously submitted transfers */ + goto out; + + /* + * TODO: The controller can do non-multiple-of-8 bit + * transfers, but this driver currently doesn't support it. + * + * It's also not clear how such transfers are supposed to be + * represented as a stream of bytes...this is a limitation of + * the current SPI interface. + */ + if (bitlen % 8) { + /* Errors always terminate an ongoing transfer */ + flags |= SPI_XFER_END; + goto out; + } + + len = bitlen / 8; + + /* + * The controller can do automatic CS control, but it is + * somewhat quirky, and it doesn't really buy us much anyway + * in the context of U-Boot. + */ + if (flags & SPI_XFER_BEGIN) + spi_cs_activate(slave); + + for (len_tx = 0, len_rx = 0; len_rx < len; ) { + status = spi_readl(as, SR); + + if (status & ATMEL_SPI_SR_OVRES) + return -1; + + if (len_tx < len && (status & ATMEL_SPI_SR_TDRE)) { + if (txp) + value = *txp++; + else + value = 0; + spi_writel(as, TDR, value); + len_tx++; + } + if (status & ATMEL_SPI_SR_RDRF) { + value = spi_readl(as, RDR); + if (rxp) + *rxp++ = value; + len_rx++; + } + } + +out: + if (flags & SPI_XFER_END) { + /* + * Wait until the transfer is completely done before + * we deactivate CS. + */ + do { + status = spi_readl(as, SR); + } while (!(status & ATMEL_SPI_SR_TXEMPTY)); + + spi_cs_deactivate(slave); + } + + return 0; +} diff --git a/drivers/spi/atmel_spi.h b/drivers/spi/atmel_spi.h new file mode 100644 index 00000000000..2baf9c76ef2 --- /dev/null +++ b/drivers/spi/atmel_spi.h @@ -0,0 +1,95 @@ +/* + * Register definitions for the DaVinci SPI Controller + */ + +/* Register offsets */ +#define DAVINCI_SPI_CR 0x0000 +#define ATMEL_SPI_MR 0x0004 +#define ATMEL_SPI_RDR 0x0008 +#define ATMEL_SPI_TDR 0x000c +#define ATMEL_SPI_SR 0x0010 +#define ATMEL_SPI_IER 0x0014 +#define ATMEL_SPI_IDR 0x0018 +#define ATMEL_SPI_IMR 0x001c +#define ATMEL_SPI_CSR(x) (0x0030 + 4 * (x)) +#define ATMEL_SPI_VERSION 0x00fc + +/* Bits in CR */ +#define ATMEL_SPI_CR_SPIEN (1 << 0) +#define ATMEL_SPI_CR_SPIDIS (1 << 1) +#define ATMEL_SPI_CR_SWRST (1 << 7) +#define ATMEL_SPI_CR_LASTXFER (1 << 24) + +/* Bits in MR */ +#define ATMEL_SPI_MR_MSTR (1 << 0) +#define ATMEL_SPI_MR_PS (1 << 1) +#define ATMEL_SPI_MR_PCSDEC (1 << 2) +#define ATMEL_SPI_MR_FDIV (1 << 3) +#define ATMEL_SPI_MR_MODFDIS (1 << 4) +#define ATMEL_SPI_MR_LLB (1 << 7) +#define ATMEL_SPI_MR_PCS(x) (((x) & 15) << 16) +#define ATMEL_SPI_MR_DLYBCS(x) ((x) << 24) + +/* Bits in RDR */ +#define ATMEL_SPI_RDR_RD(x) (x) +#define ATMEL_SPI_RDR_PCS(x) ((x) << 16) + +/* Bits in TDR */ +#define ATMEL_SPI_TDR_TD(x) (x) +#define ATMEL_SPI_TDR_PCS(x) ((x) << 16) +#define ATMEL_SPI_TDR_LASTXFER (1 << 24) + +/* Bits in SR/IER/IDR/IMR */ +#define ATMEL_SPI_SR_RDRF (1 << 0) +#define ATMEL_SPI_SR_TDRE (1 << 1) +#define ATMEL_SPI_SR_MODF (1 << 2) +#define ATMEL_SPI_SR_OVRES (1 << 3) +#define ATMEL_SPI_SR_ENDRX (1 << 4) +#define ATMEL_SPI_SR_ENDTX (1 << 5) +#define ATMEL_SPI_SR_RXBUFF (1 << 6) +#define ATMEL_SPI_SR_TXBUFE (1 << 7) +#define ATMEL_SPI_SR_NSSR (1 << 8) +#define ATMEL_SPI_SR_TXEMPTY (1 << 9) +#define ATMEL_SPI_SR_SPIENS (1 << 16) + +/* Bits in CSRx */ +#define ATMEL_SPI_CSRx_CPOL (1 << 0) +#define ATMEL_SPI_CSRx_NCPHA (1 << 1) +#define ATMEL_SPI_CSRx_CSAAT (1 << 3) +#define ATMEL_SPI_CSRx_BITS(x) ((x) << 4) +#define ATMEL_SPI_CSRx_SCBR(x) ((x) << 8) +#define ATMEL_SPI_CSRx_SCBR_MAX 0xff +#define ATMEL_SPI_CSRx_DLYBS(x) ((x) << 16) +#define ATMEL_SPI_CSRx_DLYBCT(x) ((x) << 24) + +/* Bits in VERSION */ +#define ATMEL_SPI_VERSION_REV(x) ((x) << 0) +#define ATMEL_SPI_VERSION_MFN(x) ((x) << 16) + +/* Constants for CSRx:BITS */ +#define ATMEL_SPI_BITS_8 0 +#define ATMEL_SPI_BITS_9 1 +#define ATMEL_SPI_BITS_10 2 +#define ATMEL_SPI_BITS_11 3 +#define ATMEL_SPI_BITS_12 4 +#define ATMEL_SPI_BITS_13 5 +#define ATMEL_SPI_BITS_14 6 +#define ATMEL_SPI_BITS_15 7 +#define ATMEL_SPI_BITS_16 8 + +struct atmel_spi_slave { + struct spi_slave slave; + void *regs; + u32 mr; +}; + +static inline struct atmel_spi_slave *to_atmel_spi(struct spi_slave *slave) +{ + return container_of(slave, struct atmel_spi_slave, slave); +} + +/* Register access macros */ +#define spi_readl(as, reg) \ + readl(as->regs + ATMEL_SPI_##reg) +#define spi_writel(as, reg, value) \ + writel(value, as->regs + ATMEL_SPI_##reg) diff --git a/drivers/spi/davinci_spi.c b/drivers/spi/davinci_spi.c new file mode 100644 index 00000000000..ed895212bd0 --- /dev/null +++ b/drivers/spi/davinci_spi.c @@ -0,0 +1,284 @@ +/* + * Copyright (C) 2008 Sekhar Nori, Texas Instruments, Inc <www.ti.com> + * + * Driver for SPI controller on DaVinci. Based on atmel_spi.c + * by Atmel Corporation + * + * Copyright (C) 2007 Atmel Corporation + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ +#include <common.h> +#include <spi.h> +#include <malloc.h> + +#include <asm/io.h> + +#include <asm/arch/hardware.h> + +#include "davinci_spi.h" + +static unsigned int data1_reg_val; + + +void spi_init() +{ + /* do nothing */ + +} + +struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs, + unsigned int max_hz, unsigned int mode) +{ + struct davinci_spi_slave *ds; + void *regs; + unsigned int fmt0; + + ds = malloc(sizeof(struct davinci_spi_slave)); + if (!ds) + return NULL; + + ds->slave.bus = bus; + ds->slave.cs = cs; + ds->regs = CFG_SPI_BASE; + ds->freq = max_hz; + + return &ds->slave; +} + +void spi_free_slave(struct spi_slave *slave) +{ + struct davinci_spi_slave *ds = to_davinci_spi(slave); + + free(ds); +} + +int spi_claim_bus(struct spi_slave *slave) +{ + struct davinci_spi_slave *ds = to_davinci_spi(slave); + unsigned int scalar; + + /* Enable the SPI hardware */ + spi_writel(ds, GCR0, 0); + udelay(1000); + spi_writel(ds, GCR0, 1); + + /* Set master mode, powered up and not activated */ + spi_writel(ds, GCR1, 0x3); + + /* CS, CLK, SIMO and SOMI are functional pins */ + spi_writel(ds, PC0, (1 << 0) | (1 << 9) | (1 << 10) | (1 << 11)); + + /* setup format */ + scalar = ((CFG_SPI_CLK / ds->freq) - 1 ) & 0xFF; + + spi_writel(ds, FMT0, 8 | /* character length */ + (scalar << 8) | + (1 << 16) | /* clock signal delayed by half clk cycle */ + (0 << 17) | /* clock low in idle state - Mode 0 */ + (0 << 20)); /* MSB shifted out first */ + + /* hold cs active at end of transfer until explicitly de-asserted */ + data1_reg_val = (1 << 28) | (slave->cs << 16); + spi_writel(ds, DAT1, data1_reg_val); + + /* including a minor delay. No science here. Should be good even with + * no delay + */ + spi_writel(ds, DELAY, (50 << 24) | (50 << 16)); + + /* default chip select register */ + spi_writel(ds, DEF, 1); + + /* no interrupts */ + spi_writel(ds, INT0, 0); + spi_writel(ds, LVL, 0); + + /* enable SPI */ + spi_writel(ds, GCR1, spi_readl(ds, GCR1) | (1 << 24)); + + return 0; +} + +void spi_release_bus(struct spi_slave *slave) +{ + struct davinci_spi_slave *ds = to_davinci_spi(slave); + + /* Disable the SPI hardware */ + spi_writel(ds, GCR0, 0); +} + +int spi_xfer(struct spi_slave *slave, unsigned int bitlen, + const void *dout, void *din, unsigned long flags) +{ + struct davinci_spi_slave *ds = to_davinci_spi(slave); + unsigned int len_tx; + unsigned int len_rx; + unsigned int len; + int ret, i; + u32 status; + const u8 *txp = dout; + u8 *rxp = din; + u8 value, dummy = 0; + + ret = 0; + + if (bitlen == 0) + /* Finish any previously submitted transfers */ + goto out; + + /* + * It's not clear how non-8-bit-aligned transfers are supposed to be + * represented as a stream of bytes...this is a limitation of + * the current SPI interface - here we terminate on receiving such a + * transfer request. + */ + if (bitlen % 8) { + /* Errors always terminate an ongoing transfer */ + flags |= SPI_XFER_END; + goto out; + } + + len = bitlen / 8; + + /* do an empty read to clear the current contents */ + spi_readl(ds, BUF); + + /* keep writing and reading 1 byte until done */ + for (i = 0; i < len; i++) { + + /* wait till TXFULL is asserted */ + while(spi_readl(ds, BUF) & (1 << 29)); + + /* write the data */ + data1_reg_val &= ~0xFFFF; + if(txp) { + data1_reg_val |= *txp & 0xFF; + txp++; + } + + /* write to DAT1 is required to keep the serial transfer going */ + /* we just terminate when we reach the end */ + if((i == (len -1)) && (flags & SPI_XFER_END)) { + spi_writel(ds, DAT1, data1_reg_val & ~(1 << 28)); /* clear CS hold */ + } else { + spi_writel(ds, DAT1, data1_reg_val); + } + + + /* read the data - wait for data availability */ + while(spi_readl(ds, BUF) & (1 << 31)); + + if(rxp) { + *rxp = spi_readl(ds, BUF) & 0xFF; + rxp++; + } else { + spi_readl(ds, BUF); /* simply drop the read character */ + } + + } + + return 0; + +out: + if (flags & SPI_XFER_END) { + spi_writel(ds, DAT1, data1_reg_val & ~(1 << 28)); + } + + return 0; +} + + +#ifdef CONFIG_CMD_EEPROM + +/* ------------------------------------------------------------------------ * + * SPI ROM Definitions * + * ------------------------------------------------------------------------ */ +#define SPIROM_SIZE 0x00008000 +#define SPIROM_BASE 0x00000000 +#define SPIROM_PAGESIZE 32 +#define SPIROM_PAGEMASK 0xffffffc0 + +/* ------------------------------------------------------------------------ * + * SPI ROM Commands * + * ------------------------------------------------------------------------ */ +#define SPIROM_CMD_WRSR 0x01 +#define SPIROM_CMD_WRITE 0x02 +#define SPIROM_CMD_READ 0x03 +#define SPIROM_CMD_WRDI 0x04 +#define SPIROM_CMD_RDSR 0x05 +#define SPIROM_CMD_WREN 0x06 + +static struct spi_slave *slave; + +void spi_init_f(void) +{ + slave = spi_setup_slave(0, 0, 1*1024*1024, 0); + spi_claim_bus(slave); +} + +static char spirombuf[3]; + +/* ------------------------------------------------------------------------ * + * spirom_status( ) * + * ------------------------------------------------------------------------ */ +static unsigned char spi_get_status( ) +{ + /* Issue read status command */ + spirombuf[0] = SPIROM_CMD_RDSR; + spirombuf[1] = 0; + + spi_xfer(slave, (2)*8, spirombuf, spirombuf, SPI_XFER_BEGIN | SPI_XFER_END); + + return spirombuf[1]; +} + +ssize_t spi_write(uchar *addr, int alen, uchar *buffer, int len) +{ + + spirombuf[0] = SPIROM_CMD_WREN; + spi_xfer(slave, 1*8, spirombuf, NULL, SPI_XFER_BEGIN | SPI_XFER_END); + + /* Create command block for program operation */ + spirombuf[0] = SPIROM_CMD_WRITE; + spirombuf[1] = addr[0]; + spirombuf[2] = addr[1]; + + spi_xfer(slave, 3 * 8, spirombuf, NULL, SPI_XFER_BEGIN); + spi_xfer(slave, len * 8, buffer, NULL, SPI_XFER_END); + + /* Wait while busy */ + while( (spi_get_status( ) & 0x01 ) ); + + return len; +} + +ssize_t spi_read(uchar *addr, int alen, uchar *buffer, int len) +{ + spirombuf[0] = 0x3; + spirombuf[1] = addr[0]; + spirombuf[2] = addr[1]; + + spi_xfer(slave, 3*8, spirombuf, NULL, SPI_XFER_BEGIN); + spi_xfer(slave, len*8, NULL, buffer, SPI_XFER_END); + + return len; +} + +#endif diff --git a/drivers/spi/davinci_spi.h b/drivers/spi/davinci_spi.h new file mode 100644 index 00000000000..0f2b0877baa --- /dev/null +++ b/drivers/spi/davinci_spi.h @@ -0,0 +1,46 @@ +/* + * Register definitions for the DaVinci SPI Controller + */ + +/* Register offsets */ +#define DAVINCI_SPI_GCR0 0x0000 +#define DAVINCI_SPI_GCR1 0x0004 +#define DAVINCI_SPI_INT0 0x0008 +#define DAVINCI_SPI_LVL 0x000c +#define DAVINCI_SPI_FLG 0x0010 +#define DAVINCI_SPI_PC0 0x0014 +#define DAVINCI_SPI_PC1 0x0018 +#define DAVINCI_SPI_PC2 0x001c +#define DAVINCI_SPI_PC3 0x0020 +#define DAVINCI_SPI_PC4 0x0024 +#define DAVINCI_SPI_PC5 0x0028 +#define DAVINCI_SPI_DAT0 0x0038 +#define DAVINCI_SPI_DAT1 0x003c +#define DAVINCI_SPI_BUF 0x0040 +#define DAVINCI_SPI_EMU 0x0044 +#define DAVINCI_SPI_DELAY 0x0048 +#define DAVINCI_SPI_DEF 0x004c +#define DAVINCI_SPI_FMT0 0x0050 +#define DAVINCI_SPI_FMT1 0x0054 +#define DAVINCI_SPI_FMT2 0x0058 +#define DAVINCI_SPI_FMT3 0x005c +#define DAVINCI_SPI_INTVEC0 0x0060 +#define DAVINCI_SPI_INTVEC1 0x0064 + +struct davinci_spi_slave { + struct spi_slave slave; + void *regs; + u32 mr; + unsigned int freq; +}; + +static inline struct davinci_spi_slave *to_davinci_spi(struct spi_slave *slave) +{ + return container_of(slave, struct davinci_spi_slave, slave); +} + +#define spi_readl(as, reg) \ + readl(CFG_SPI_BASE + DAVINCI_SPI_##reg) +#define spi_writel(as, reg, value) \ + writel(value, CFG_SPI_BASE + DAVINCI_SPI_##reg) + diff --git a/drivers/spi/mpc8xxx_spi.c b/drivers/spi/mpc8xxx_spi.c index 2fe838c45d5..136fb50052f 100644 --- a/drivers/spi/mpc8xxx_spi.c +++ b/drivers/spi/mpc8xxx_spi.c @@ -24,6 +24,7 @@ #include <common.h> #if defined(CONFIG_MPC8XXX_SPI) && defined(CONFIG_HARD_SPI) +#include <malloc.h> #include <spi.h> #include <asm/mpc8xxx_spi.h> @@ -37,6 +38,34 @@ #define SPI_TIMEOUT 1000 +struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs, + unsigned int max_hz, unsigned int mode) +{ + struct spi_slave *slave; + + if (!spi_cs_is_valid(bus, cs)) + return NULL; + + slave = malloc(sizeof(struct spi_slave)); + if (!slave) + return NULL; + + slave->bus = bus; + slave->cs = cs; + + /* + * TODO: Some of the code in spi_init() should probably move + * here, or into spi_claim_bus() below. + */ + + return slave; +} + +void spi_free_slave(struct spi_slave *slave) +{ + free(slave); +} + void spi_init(void) { volatile spi8xxx_t *spi = &((immap_t *) (CFG_IMMR))->spi; @@ -53,7 +82,18 @@ void spi_init(void) spi->com = 0; /* LST bit doesn't do anything, so disregard */ } -int spi_xfer(spi_chipsel_type chipsel, int bitlen, uchar *dout, uchar *din) +int spi_claim_bus(struct spi_slave *slave) +{ + return 0; +} + +void spi_release_bus(struct spi_slave *slave) +{ + +} + +int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout, + void *din, unsigned long flags) { volatile spi8xxx_t *spi = &((immap_t *) (CFG_IMMR))->spi; unsigned int tmpdout, tmpdin, event; @@ -61,11 +101,11 @@ int spi_xfer(spi_chipsel_type chipsel, int bitlen, uchar *dout, uchar *din) int tm, isRead = 0; unsigned char charSize = 32; - debug("spi_xfer: chipsel %08X dout %08X din %08X bitlen %d\n", - (int)chipsel, *(uint *) dout, *(uint *) din, bitlen); + debug("spi_xfer: slave %u:%u dout %08X din %08X bitlen %u\n", + slave->bus, slave->cs, *(uint *) dout, *(uint *) din, bitlen); - if (chipsel != NULL) - (*chipsel) (1); /* select the target chip */ + if (flags & SPI_XFER_BEGIN) + spi_cs_activate(slave); spi->event = 0xffffffff; /* Clear all SPI events */ @@ -135,8 +175,8 @@ int spi_xfer(spi_chipsel_type chipsel, int bitlen, uchar *dout, uchar *din) debug("*** spi_xfer: transfer ended. Value=%08x\n", tmpdin); } - if (chipsel != NULL) - (*chipsel) (0); /* deselect the target chip */ + if (flags & SPI_XFER_END) + spi_cs_deactivate(slave); return 0; } diff --git a/drivers/spi/mxc_spi.c b/drivers/spi/mxc_spi.c index b2e3ab9b676..e0809593d10 100644 --- a/drivers/spi/mxc_spi.c +++ b/drivers/spi/mxc_spi.c @@ -19,6 +19,7 @@ */ #include <common.h> +#include <malloc.h> #include <spi.h> #include <asm/io.h> @@ -61,17 +62,18 @@ static unsigned long spi_bases[] = { 0x53f84000, }; -static unsigned long spi_base; - #endif -spi_chipsel_type spi_chipsel[] = { - (spi_chipsel_type)0, - (spi_chipsel_type)1, - (spi_chipsel_type)2, - (spi_chipsel_type)3, +struct mxc_spi_slave { + struct spi_slave slave; + unsigned long base; + u32 ctrl_reg; }; -int spi_chipsel_cnt = sizeof(spi_chipsel) / sizeof(spi_chipsel[0]); + +static inline struct mxc_spi_slave *to_mxc_spi_slave(struct spi_slave *slave) +{ + return container_of(slave, struct mxc_spi_slave, slave); +} static inline u32 reg_read(unsigned long addr) { @@ -83,30 +85,31 @@ static inline void reg_write(unsigned long addr, u32 val) *(volatile unsigned long*)addr = val; } -static u32 spi_xchg_single(u32 data, int bitlen) +static u32 spi_xchg_single(struct spi_slave *slave, u32 data, int bitlen) { - - unsigned int cfg_reg = reg_read(spi_base + MXC_CSPICTRL); + struct mxc_spi_slave *mxcs = to_mxc_spi_slave(slave); + unsigned int cfg_reg = reg_read(mxcs->base + MXC_CSPICTRL); if (MXC_CSPICTRL_BITCOUNT(bitlen - 1) != (cfg_reg & MXC_CSPICTRL_BITCOUNT(31))) { cfg_reg = (cfg_reg & ~MXC_CSPICTRL_BITCOUNT(31)) | MXC_CSPICTRL_BITCOUNT(bitlen - 1); - reg_write(spi_base + MXC_CSPICTRL, cfg_reg); + reg_write(mxcs->base + MXC_CSPICTRL, cfg_reg); } - reg_write(spi_base + MXC_CSPITXDATA, data); + reg_write(mxcs->base + MXC_CSPITXDATA, data); cfg_reg |= MXC_CSPICTRL_XCH; - reg_write(spi_base + MXC_CSPICTRL, cfg_reg); + reg_write(mxcs->base + MXC_CSPICTRL, cfg_reg); - while (reg_read(spi_base + MXC_CSPICTRL) & MXC_CSPICTRL_XCH) + while (reg_read(mxcs->base + MXC_CSPICTRL) & MXC_CSPICTRL_XCH) ; - return reg_read(spi_base + MXC_CSPIRXDATA); + return reg_read(mxcs->base + MXC_CSPIRXDATA); } -int spi_xfer(spi_chipsel_type chipsel, int bitlen, uchar *dout, uchar *din) +int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout, + void *din, unsigned long flags) { int n_blks = (bitlen + 31) / 32; u32 *out_l, *in_l; @@ -117,13 +120,10 @@ int spi_xfer(spi_chipsel_type chipsel, int bitlen, uchar *dout, uchar *din) return 1; } - if (!spi_base) - spi_select(CONFIG_MXC_SPI_IFACE, (int)chipsel, SPI_MODE_2 | SPI_CS_HIGH); - for (i = 0, in_l = (u32 *)din, out_l = (u32 *)dout; i < n_blks; i++, in_l++, out_l++, bitlen -= 32) - *in_l = spi_xchg_single(*out_l, bitlen); + *in_l = spi_xchg_single(slave, *out_l, bitlen); return 0; } @@ -132,17 +132,17 @@ void spi_init(void) { } -int spi_select(unsigned int bus, unsigned int dev, unsigned long mode) +struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs, + unsigned int max_hz, unsigned int mode) { unsigned int ctrl_reg; + struct mxc_spi_slave *mxcs; if (bus >= sizeof(spi_bases) / sizeof(spi_bases[0]) || - dev > 3) - return 1; - - spi_base = spi_bases[bus]; + cs > 3) + return NULL; - ctrl_reg = MXC_CSPICTRL_CHIPSELECT(dev) | + ctrl_reg = MXC_CSPICTRL_CHIPSELECT(cs) | MXC_CSPICTRL_BITCOUNT(31) | MXC_CSPICTRL_DATARATE(7) | /* FIXME: calculate data rate */ MXC_CSPICTRL_EN | @@ -155,12 +155,38 @@ int spi_select(unsigned int bus, unsigned int dev, unsigned long mode) if (mode & SPI_CS_HIGH) ctrl_reg |= MXC_CSPICTRL_SSPOL; - reg_write(spi_base + MXC_CSPIRESET, 1); + mxcs = malloc(sizeof(struct mxc_spi_slave)); + if (!mxcs) + return NULL; + + mxcs->slave.bus = bus; + mxcs->slave.cs = cs; + mxcs->base = spi_bases[bus]; + mxcs->ctrl_reg = ctrl_reg; + + return &mxcs->slave; +} + +void spi_free_slave(struct spi_slave *slave) +{ + free(slave); +} + +int spi_claim_bus(struct spi_slave *slave) +{ + struct mxc_spi_slave *mxcs = to_mxc_spi_slave(slave); + + reg_write(mxcs->base + MXC_CSPIRESET, 1); udelay(1); - reg_write(spi_base + MXC_CSPICTRL, ctrl_reg); - reg_write(spi_base + MXC_CSPIPERIOD, + reg_write(mxcs->base + MXC_CSPICTRL, mxcs->ctrl_reg); + reg_write(mxcs->base + MXC_CSPIPERIOD, MXC_CSPIPERIOD_32KHZ); - reg_write(spi_base + MXC_CSPIINT, 0); + reg_write(mxcs->base + MXC_CSPIINT, 0); return 0; } + +void spi_release_bus(struct spi_slave *slave) +{ + /* TODO: Shut the controller down */ +} diff --git a/drivers/spi/spirom.c b/drivers/spi/spirom.c new file mode 100644 index 00000000000..87c93668ed3 --- /dev/null +++ b/drivers/spi/spirom.c @@ -0,0 +1,212 @@ +/* + * Copyright 2007 b7 Spectrum Digital Incorporated. + * All rights reserved. Property of Spectrum Digital Incorporated. + */ + +/* + * SPI ROM interface + * + */ + +#include "spirom.h" + +static Uint8 spirombuf[SPIROM_PAGESIZE + 5]; +static Uint8 statusbuf[8]; +static Uint32 spidat1; + +/* ------------------------------------------------------------------------ * + * * + * _wait( delay ) * + * Wait in a software loop for 'x' delay * + * * + * ------------------------------------------------------------------------ */ +void DAVINCIHD_wait( Uint32 delay ) +{ + volatile Uint32 i; + for ( i = 0 ; i < delay ; i++ ){ }; +} + + +/* ------------------------------------------------------------------------ * + * spirom_init( ) * + * ------------------------------------------------------------------------ */ +void spirom_init( ) +{ + /* Reset SPI */ + SPI_SPIGCR0 = 0; + _wait( 1000 ); + + /* Release SPI */ + SPI_SPIGCR0 = 1; + + /* SPI 4-Pin Mode setup */ + SPI_SPIGCR1 = 0 + | ( 0 << 24 ) + | ( 0 << 16 ) + | ( 1 << 1 ) + | ( 1 << 0 ); + + SPI_SPIPC0 = 0 + | ( 1 << 11 ) // DI + | ( 1 << 10 ) // DO + | ( 1 << 9 ) // CLK + | ( 1 << 1 ) // EN1 + | ( 1 << 0 ); // EN0 + + SPI_SPIFMT0 = 0 + | ( 0 << 20 ) // SHIFTDIR + | ( 0 << 17 ) // Polarity + | ( 1 << 16 ) // Phase + | ( 50 << 8 ) // Prescale + | ( 8 << 0 ); // Char Len + + spidat1 = 0 + | ( 1 << 28 ) // CSHOLD + | ( 0 << 24 ) // Format [0] + | ( 2 << 16 ) // CSNR [only CS0 enbled] + | ( 0 << 0 ); // + + SPI_SPIDAT1 = spidat1; + + SPI_SPIDELAY = 0 + | ( 8 << 24 ) // C2TDELAY + | ( 8 << 16 ); // T2CDELAY + + SPI_SPIDEF = 0 + | ( 1 << 1 ) // EN1 inactive high + | ( 1 << 0 ); // EN0 inactive high + + SPI_SPIINT = 0 + | ( 0 << 16 ) // + | ( 0 << 8 ) // + | ( 0 << 6 ) // + | ( 1 << 4 ); // + + SPI_SPILVL = 0 + | ( 0 << 8 ) // EN0 + | ( 0 << 6 ) // EN0 + | ( 0 << 4 ); // EN0 + + + /* Enable SPI */ + SPI_SPIGCR1 |= ( 1 << 24 ); +} + +/* ------------------------------------------------------------------------ * + * spirom_cycle( buf, len ) * + * * + * Execute a SPI spirom data transfer cycle. Each byte in buf is shifted * + * out and replaced with data coming back from the spirom. * + * ------------------------------------------------------------------------ */ +void spirom_cycle( Uint8 *buf, Uint16 len ) +{ + Uint16 i; + + /* Clear any old data */ + SPI_SPIBUF; + + /* SPIROM access cycle */ + for ( i = 0 ; i <= len ; i++ ) + { + /* Wait for transmit ready */ + while ( SPI_SPIBUF & 0x10000000 ); + + if ( i == len ) + SPI_SPIDAT1 = ( spidat1 & 0x0ffcffff ) | buf[i]; + else + SPI_SPIDAT1 = spidat1 | buf[i]; + + /* Wait for receive data ready */ + while ( SPI_SPIBUF & 0x80000000 ); + + /* Read 1 byte */ + buf[i] = SPI_SPIBUF; + } +} + +/* ------------------------------------------------------------------------ * + * spirom_status( ) * + * ------------------------------------------------------------------------ */ +Uint8 spirom_status( ) +{ + /* Issue read status command */ + statusbuf[0] = SPIROM_CMD_RDSR; + statusbuf[1] = 0; + + spirom_cycle( statusbuf, 2 ); + + return statusbuf[1]; +} + +/* ------------------------------------------------------------------------ * + * spirom_read( src, dst, length ) * + * ------------------------------------------------------------------------ */ +void spirom_read( Uint16 src, Uint32 dst, Uint32 length ) +{ + Int32 i; + Uint8 *psrc, *pdst; + + // Setup command + spirombuf[0] = SPIROM_CMD_READ; + spirombuf[1] = ( src >> 8 ); + spirombuf[2] = ( src >> 0 ); + + // Execute spirom read cycle + spirom_cycle( spirombuf, length + 3 ); + + // Copy returned data + pdst = ( Uint8 * )dst; + psrc = spirombuf + 3; + for ( i = 0 ; i < length ; i++ ) + *pdst++ = *psrc++; +} + +/* ------------------------------------------------------------------------ * + * spirom_write( src, dst, length ) * + * ------------------------------------------------------------------------ */ +void spirom_write( Uint32 src, Uint16 dst, Uint32 length ) +{ + Int32 i; + Int32 bytes_left; + Int32 bytes_to_program; + Uint8 *psrc; + + /* Establish source */ + psrc = ( Uint8 * )src; + bytes_left = length; + + while ( bytes_left > 0 ) + { + bytes_to_program = bytes_left; + + /* Most to program is SPIROM_CMD_BLOCKSIZE */ + if ( bytes_to_program > SPIROM_PAGESIZE ) + bytes_to_program = SPIROM_PAGESIZE; + + /* Make sure you don't run off the end of a block */ + if ( ( dst & SPIROM_PAGEMASK ) != ( ( dst + bytes_to_program ) & SPIROM_PAGEMASK ) ) + bytes_to_program -= ( dst + bytes_to_program ) - ( ( dst + bytes_to_program ) & SPIROM_PAGEMASK ); + + /* Issue WPEN */ + spirombuf[0] = SPIROM_CMD_WREN; + spirom_cycle( spirombuf, 0 ); + + /* Create command block for program operation */ + spirombuf[0] = SPIROM_CMD_WRITE; + spirombuf[1] = ( Uint8 )( dst >> 8 ); + spirombuf[2] = ( Uint8 )( dst ); + + for ( i = 0 ; i < bytes_to_program ; i++ ) + spirombuf[3+i] = *psrc++; + + /* Execute write command */ + spirom_cycle( spirombuf, bytes_to_program + 2 ); + + /* Wait while busy */ + while( ( spirom_status( ) & 0x01 ) ); + + /* Get ready for next iteration */ + bytes_left -= bytes_to_program; + dst += bytes_to_program; + } +} diff --git a/drivers/spi/spirom.h b/drivers/spi/spirom.h new file mode 100644 index 00000000000..2dfe3bc32f7 --- /dev/null +++ b/drivers/spi/spirom.h @@ -0,0 +1,77 @@ +/* + * Copyright 2007 by Spectrum Digital Incorporated. + * All rights reserved. Property of Spectrum Digital Incorporated. + */ + +/* + * SPI ROM header file + * + */ + +#ifndef SPIROM_ +#define SPIROM_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "davincihd.h" + +/* ------------------------------------------------------------------------ * + * SPI ROM Definitions * + * ------------------------------------------------------------------------ */ +#define SPIROM_SIZE 0x00008000 +#define SPIROM_BASE 0x00000000 +#define SPIROM_PAGESIZE 32 +#define SPIROM_PAGEMASK 0xffffffc0 + +/* ------------------------------------------------------------------------ * + * SPI ROM Commands * + * ------------------------------------------------------------------------ */ +#define SPIROM_CMD_WRSR 0x01 +#define SPIROM_CMD_WRITE 0x02 +#define SPIROM_CMD_READ 0x03 +#define SPIROM_CMD_WRDI 0x04 +#define SPIROM_CMD_RDSR 0x05 +#define SPIROM_CMD_WREN 0x06 + +/* ------------------------------------------------------------------------ * + * SPI Controller * + * ------------------------------------------------------------------------ */ +#define SPI_BASE 0x01c66800 +#define SPI_SPIGCR0 *( volatile Uint32* )( SPI_BASE + 0x0 ) +#define SPI_SPIGCR1 *( volatile Uint32* )( SPI_BASE + 0x4 ) +#define SPI_SPIINT *( volatile Uint32* )( SPI_BASE + 0x8 ) +#define SPI_SPILVL *( volatile Uint32* )( SPI_BASE + 0xc ) +#define SPI_SPIFLG *( volatile Uint32* )( SPI_BASE + 0x10 ) +#define SPI_SPIPC0 *( volatile Uint32* )( SPI_BASE + 0x14 ) +#define SPI_SPIPC2 *( volatile Uint32* )( SPI_BASE + 0x1c ) +#define SPI_SPIDAT1_TOP *( volatile Uint16* )( SPI_BASE + 0x3c ) +#define SPI_SPIDAT1 *( volatile Uint32* )( SPI_BASE + 0x3c ) +#define SPI_SPIDAT1_PTR16 *( volatile Uint16* )( SPI_BASE + 0x3e ) +#define SPI_SPIDAT1_PTR8 *( volatile Uint8* ) ( SPI_BASE + 0x3f ) +#define SPI_SPIBUF *( volatile Uint32* )( SPI_BASE + 0x40 ) +#define SPI_SPIBUF_PTR16 *( volatile Uint16* )( SPI_BASE + 0x42 ) +#define SPI_SPIBUF_PTR8 *( volatile Uint8* ) ( SPI_BASE + 0x43 ) +#define SPI_SPIEMU *( volatile Uint32* )( SPI_BASE + 0x44 ) +#define SPI_SPIDELAY *( volatile Uint32* )( SPI_BASE + 0x48 ) +#define SPI_SPIDEF *( volatile Uint32* )( SPI_BASE + 0x4c ) +#define SPI_SPIFMT0 *( volatile Uint32* )( SPI_BASE + 0x50 ) +#define SPI_SPIFMT1 *( volatile Uint32* )( SPI_BASE + 0x54 ) +#define SPI_SPIFMT2 *( volatile Uint32* )( SPI_BASE + 0x58 ) +#define SPI_SPIFMT3 *( volatile Uint32* )( SPI_BASE + 0x5c ) +#define SPI_INTVEC0 *( volatile Uint32* )( SPI_BASE + 0x60 ) +#define SPI_INTVEC1 *( volatile Uint32* )( SPI_BASE + 0x64 ) + +/* ------------------------------------------------------------------------ * + * Prototype * + * ------------------------------------------------------------------------ */ +void spirom_init( ); +void spirom_read( Uint16 src, Uint32 dst, Uint32 length ); +void spirom_write( Uint32 src, Uint16 dst, Uint32 length ); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/drivers/usb/Makefile b/drivers/usb/Makefile index f8ea167b12c..013a78dda9b 100644 --- a/drivers/usb/Makefile +++ b/drivers/usb/Makefile @@ -12,7 +12,7 @@ # # 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 +# 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 @@ -23,7 +23,7 @@ include $(TOPDIR)/config.mk -LIB := $(obj)libusb.a +LIB := $(obj)libusb.a COBJS-y += isp116x-hcd.o COBJS-y += sl811_usb.o @@ -32,14 +32,16 @@ COBJS-y += usbdcore.o COBJS-y += usbdcore_ep0.o COBJS-y += usbdcore_mpc8xx.o COBJS-y += usbdcore_omap1510.o +COBJS-y += da8xx_usb.o +COBJS-y += musbhdrc.o -COBJS := $(COBJS-y) -SRCS := $(COBJS:.o=.c) -OBJS := $(addprefix $(obj),$(COBJS)) +COBJS := $(COBJS-y) +SRCS := $(COBJS:.o=.c) +OBJS := $(addprefix $(obj),$(COBJS)) -all: $(LIB) +all: $(LIB) -$(LIB): $(obj).depend $(OBJS) +$(LIB): $(obj).depend $(OBJS) $(AR) $(ARFLAGS) $@ $(OBJS) ######################################################################### diff --git a/drivers/usb/da8xx_usb.c b/drivers/usb/da8xx_usb.c new file mode 100644 index 00000000000..5dd5f123936 --- /dev/null +++ b/drivers/usb/da8xx_usb.c @@ -0,0 +1,213 @@ +/* + * TI's DA8xx platform specific usb wrapper functions. + * + * Copyright (c) 2004 Texas Instruments + * + * This package is free software; you can redistribute it and/or + * modify it under the terms of the license found in the file + * named COPYING that should have accompanied this file. + * + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + * Author: Thomas Abraham t-abraham@ti.com, Texas Instruments + * + * Copyright (c) 2003 Wolfgang Denk, wd@denx.de + * + */ + +#include <common.h> + +#ifdef CONFIG_USB_DA8XX + +#include "da8xx_usb.h" + +/* extern functions */ +extern void lpsc_on(unsigned int id); + +/* Timeout for DA8xx usb module */ +#define DA8XX_USB_TIMEOUT 0x3FFFF + + +/* This function writes to a 32-bit register of platform usb wrapper */ +inline void pusb_writel( u32 offset , u32 value ) +{ + *(volatile u32*)(DA8XX_USB0_BASE+offset) = value; +} + +/* This function reads a 32-bit register of platform usb wrapper */ +inline u32 pusb_readl(u32 offset) +{ + return(*(volatile u32*)(DA8XX_USB0_BASE+offset)); +} + +/* This function writes to a 16-bit register of platform musb core */ +inline void musb_writew(u32 offset, u16 value) +{ + *(volatile u16*)(MENTOR_USB0_BASE+offset) = value; +} + +/* This function writes to a 8-bit register of platform musb core */ +inline void musb_writeb(u32 offset, u8 value) +{ + *(volatile u8*)(MENTOR_USB0_BASE+offset) = value; +} + +/* This function reads a 16-bit register of platform usb wrapper */ +inline u16 musb_readw(u32 offset) +{ + return(*(volatile u16*)(MENTOR_USB0_BASE + offset)); +} + +/* This function reads a 8-bit register of platform usb wrapper */ +inline u8 musb_readb(u32 offset) +{ + return(*(volatile u8*)(MENTOR_USB0_BASE+offset)); +} + +/* + * This function enables VBUS by driving the GPIO Bank4 Pin 15 high. + */ +static void enable_vbus(void) +{ + u32 value; + + /* configure GPIO bank4 pin 15 in output direction */ + value = *(volatile u32 *)GPIO_BANK4_REG_DIR_ADDR; + value &= ~0x8000; + *(volatile u32 *)GPIO_BANK4_REG_DIR_ADDR = value; + + /* set GPIO bank4 pin 15 high to drive VBUS */ + value = *(volatile u32 *)GPIO_BANK4_REG_SET_ADDR; + value |= 0x8000; + *(volatile u32 *)GPIO_BANK4_REG_SET_ADDR = value; +} + +/* + * Enable the usb0 phy. This initialization procedure is explained in + * the DA8xx USB user guide document. + */ +static u8 phy_on( void ) +{ + u32 timeout; + u8 result = 1; + + /* write access keys */ + *(volatile u32 *)(KICK0) = 0x83e70b13; + *(volatile u32 *)(KICK1) = 0x95a4f1e0; + + +#ifdef CONFIG_USE_PINMUX + + /* set PINMUX[7:4] = 1 */ + *(volatile u32 *)(PINMUX9) |= ( 1 << 4 ); + *(volatile u32 *)(PINMUX9) &= 0xFFFFFF7F; + +#endif + + /* reset the usb controller */ + pusb_writel( DA8XX_USB_CTRL_REG , 0x1 ); + udelay( 5000 ); + + /* enable and then disable the usb phy reset */ + *(volatile u32*)CFGCHIP2 |= 0x00008000; + udelay( 5000 ); + *(volatile u32*)CFGCHIP2 &= 0xFFFF7FFF; + udelay( 5000 ); + + /* configure phy (refer to da8xx usb user guide use case section) */ + *(volatile u32*)CFGCHIP2 &= 0xFFFF9FFF; + *(volatile u32*)CFGCHIP2 &= 0xFFFFFBFF; + *(volatile u32*)CFGCHIP2 &= 0xFFFFFDFF; + *(volatile u32*)CFGCHIP2 |= 0x00000100; + *(volatile u32*)CFGCHIP2 |= 0x00000020; + *(volatile u32*)CFGCHIP2 |= 0x00000010; + *(volatile u32*)CFGCHIP2 |= 0x00000002; + *(volatile u32*)CFGCHIP2 &= 0xFFFFE7FF; + *(volatile u32*)CFGCHIP2 |= 0x00000800; + + *(volatile u32*)CFGCHIP2 &= 0xFFFF9FFF; + *(volatile u32*)CFGCHIP2 |= 0x00002000; + *(volatile u32*)CFGCHIP2 |= 0x00000040; + + /* wait until the usb phy pll locks */ + timeout = DA8XX_USB_TIMEOUT; + do { + timeout--; + if (timeout == 0) + break; + } + while(((*(volatile u32*)CFGCHIP2) & 0x00020000) == 0); + + /* disable register access by writing invalid keys */ + *(volatile u32 *)(0x01C14038) = 0x0; + *(volatile u32 *)(0x01C1403C) = 0x0; + + if (timeout == 0) + result = 0; + + return(result); +} + +/* + * Disable the usb phy + */ +static void phy_off(void) +{ + /* write access keys */ + *(volatile u32 *)(KICK0) = 0; + *(volatile u32 *)(KICK1) = 0; + + /* powerdown the on-chip PHY and its oscillator */ + *(volatile u32*)(CFGCHIP2) = 0x8600; +} + + +/* + * This function performs DA8xx platform specific initialization for usb0. + */ +int musb_platform_init(void) +{ + u32 revision; + + /* enable psc for usb2.0 */ + lpsc_on(33); + + /* enable usb vbus */ + enable_vbus(); + + /* start the on-chip usb phy and its pll */ + if (phy_on() == 0) + return(-1); + + /* reset the controller */ + pusb_writel(DA8XX_USB_CTRL_REG, 0x1); + udelay(5000); + + /* Returns zero if e.g. not clocked */ + revision = pusb_readl(DA8XX_USB_VERSION_REG); + if (revision == 0) + return(-1); + + /* Disable all interrupts */ + pusb_writel(DA8XX_USB_INT_MASK_SET_REG, 0x01FF1F1F); + return(0); +} + + +/* + * This function performs DA8xx platform specific deinitialization for usb0. + */ +void musb_platform_deinit(void) +{ + /* Turn of the phy */ + phy_off(); + + /* flush any interrupts */ + pusb_writel(DA8XX_USB_INT_MASK_CLR_REG, DA8XX_USB_USBINT_MASK|DA8XX_USB_TXINT_MASK|DA8XX_USB_RXINT_MASK); + pusb_writel(DA8XX_USB_EOI_REG, 0); +} + +#endif /* CONFIG_USB_DA8XX */ + diff --git a/drivers/usb/da8xx_usb.h b/drivers/usb/da8xx_usb.h new file mode 100644 index 00000000000..ffc0be39b18 --- /dev/null +++ b/drivers/usb/da8xx_usb.h @@ -0,0 +1,73 @@ +/* + * TI's DA8xx platform specific usb wrapper functions. + * + * Copyright (c) 2004 Texas Instruments + * + * This package is free software; you can redistribute it and/or + * modify it under the terms of the license found in the file + * named COPYING that should have accompanied this file. + * + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + * Author: Thomas Abraham t-abraham@ti.com, Texas Instruments + * + * Copyright (c) 2003 Wolfgang Denk, wd@denx.de + * + */ + +#ifndef __DA8XX_MUSB_H__ +#define __DA8XX_MUSB_H__ + +#include "musbhdrc.h" + +/* Base address of da8xx usb0 wrapper */ +#define DA8XX_USB0_BASE 0x01E00000 + +/* Base address of da8xx musb core */ +#define MENTOR_USB0_BASE (DA8XX_USB0_BASE+0x400) + +/* For now include usb OTG module registers here */ +#define DA8XX_USB_VERSION_REG 0x00 +#define DA8XX_USB_CTRL_REG 0x04 +#define DA8XX_USB_STAT_REG 0x08 +#define DA8XX_MODE_TGCR_REG 0x10 /* Mode reg RNDIS */ +#define DA8XX_AUTOREQ_REG 0x14 +#define DA8XX_SRP_FIXTIME_REG 0x18 /* SRP Fixtime reg */ +#define DA8XX_TEARDOWN_REG 0x1C /* TearDown Register*/ +#define DA8XX_USB_INT_SOURCE_REG 0x20 +#define DA8XX_USB_INT_SET_REG 0x24 +#define DA8XX_USB_INT_SRC_CLR_REG 0x28 +#define DA8XX_USB_INT_MASK_REG 0x2c +#define DA8XX_USB_INT_MASK_SET_REG 0x30 +#define DA8XX_USB_INT_MASK_CLR_REG 0x34 +#define DA8XX_USB_INT_SRC_MASKED_REG 0x38 +#define DA8XX_USB_EOI_REG 0x3c +#define DA8XX_USB_EOI_INTVEC 0x40 +#define DA8XX_GRNDIS_EP1SIZE_REG 0x50 +#define DA8XX_GRNDIS_EP2SIZE_REG 0x54 +#define DA8XX_GRNDIS_EP3SIZE_REG 0x58 +#define DA8XX_GRNDIS_EP4SIZE_REG 0x5C + + +#define DA8XX_USB_TX_ENDPTS_MASK 0x1f /* ep0 + 4 tx */ +#define DA8XX_USB_RX_ENDPTS_MASK 0x1e /* 4 rx */ + +#define DA8XX_USB_USBINT_SHIFT 16 +#define DA8XX_USB_TXINT_SHIFT 0 +#define DA8XX_USB_RXINT_SHIFT 8 + +#define DA8XX_INTR_DRVVBUS 0x0100 + +#define DA8XX_USB_USBINT_MASK 0x01ff0000 /* 8 Mentor, DRVVBUS */ +#define DA8XX_USB_TXINT_MASK \ + (DA8XX_USB_TX_ENDPTS_MASK << DA8XX_USB_TXINT_SHIFT) +#define DA8XX_USB_RXINT_MASK \ + (DA8XX_USB_RX_ENDPTS_MASK << DA8XX_USB_RXINT_SHIFT) + +#define MGC_BUSCTL_OFFSET(_bEnd, _bOffset) \ + (0x80 + (8*(_bEnd)) + (_bOffset)) + +#endif /* __DA8XX_MUSB_H__ */ + diff --git a/drivers/usb/musbhdrc.c b/drivers/usb/musbhdrc.c new file mode 100644 index 00000000000..ff907f9afe3 --- /dev/null +++ b/drivers/usb/musbhdrc.c @@ -0,0 +1,885 @@ +/* + * Mentor USB Core host controller driver. + * + * Copyright (c) 2004 Texas Instruments + * + * This package is free software; you can redistribute it and/or + * modify it under the terms of the license found in the file + * named COPYING that should have accompanied this file. + * + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + * Author: Thomas Abraham t-abraham@ti.com, Texas Instruments + * + * Copyright (c) 2003 Wolfgang Denk, wd@denx.de + * + */ + +#include <common.h> + +/* Include usb hcd code if usb support is included in u-boot */ +#ifdef CONFIG_MUSB + +#include <usb.h> +#include "musbhdrc.h" + +/* extern functions */ +extern int musb_platform_init(void); +extern void musb_platform_deinit(void); +extern inline void musb_writew(u32 offset, u16 value); +extern inline void musb_writeb(u32 offset, u8 value); +extern inline u16 musb_readw(u32 offset); +extern inline u8 musb_readb(u32 offset); + +/* The controller driver polls for changes in the state. This defines a timeout + for cases where the states do not change so the appropriate error can be + returned. */ +#define MUSB_USB_TIMEOUT 0x3FFFFF + +/* This defines the endpoint number used for control transfers */ +#define MUSB_CONTROL_EP 0 + +/* This defines the endpoint number used for bulk transfer */ +#define MUSB_BULK_EP 1 + +/* Determine the operating speed of MUSB core */ +#define musb_ishighspeed() \ + ((musb_readb(MGC_O_HDRC_POWER) & MGC_M_POWER_HSMODE) >> 4) + +/* speed negotiated with the connected device */ +static u8 musb_speed; + +/* + * This function configures all the endpoint FIFOs. Endpoint 1 is used for bulk + * transfers and so the fifo size of EP1 Tx and Rx is set to 512 bytes. The + * other endpoints 2,3 & 4 are configured for default fifo size of 64 bytes but + * these endpoints are not used. + */ +void musb_configure_ep(void) +{ + /* Select Endpoint 1 for bulk transfer */ + musb_writeb(MGC_O_HDRC_INDEX, 1); + + /* Configure FIFO for endpoint 1 */ + musb_writeb(MGC_O_HDRC_TXFIFOSZ, 0x06); + musb_writeb(MGC_O_HDRC_RXFIFOSZ, 0x06); + musb_writew(MGC_O_HDRC_TXFIFOADD, 0x08); + musb_writew(MGC_O_HDRC_RXFIFOADD, 0x48); + + /* Select Endpoint 2 for bulk transfer */ + musb_writeb(MGC_O_HDRC_INDEX, 2); + + /* Configure FIFO for endpoint 2 */ + musb_writeb(MGC_O_HDRC_TXFIFOSZ, 0x03); + musb_writeb(MGC_O_HDRC_RXFIFOSZ, 0x03); + musb_writew(MGC_O_HDRC_TXFIFOADD, 0x88); + musb_writew(MGC_O_HDRC_RXFIFOADD, 0x90); + + /* Select Endpoint 3 for bulk transfer */ + musb_writeb(MGC_O_HDRC_INDEX, 3 ); + + /* Configure FIFO for endpoint 2 */ + musb_writeb(MGC_O_HDRC_TXFIFOSZ, 0x03); + musb_writeb(MGC_O_HDRC_RXFIFOSZ, 0x03); + musb_writew(MGC_O_HDRC_TXFIFOADD, 0x98); + musb_writew(MGC_O_HDRC_RXFIFOADD, 0xA0); + + /* Select Endpoint 3 for bulk transfer */ + musb_writeb(MGC_O_HDRC_INDEX, 4 ); + + /* Configure FIFO for endpoint 2 */ + musb_writeb(MGC_O_HDRC_TXFIFOSZ, 0x03); + musb_writeb(MGC_O_HDRC_RXFIFOSZ, 0x03); + musb_writew(MGC_O_HDRC_TXFIFOADD, 0xA8); + musb_writew(MGC_O_HDRC_RXFIFOADD, 0xB0); +} + +/* + * program the HDRC to start (enable interrupts, dma, etc.) + */ +void musb_start( void ) +{ + u8 devctl; + + /* disable all interrupts */ + musb_writew(MGC_O_HDRC_INTRTXE, 0x0000); + musb_writew(MGC_O_HDRC_INTRRXE, 0x0000); + musb_writeb(MGC_O_HDRC_INTRUSBE, 0x00); + musb_writeb(MGC_O_HDRC_TESTMODE, 0); + + /* put into basic highspeed mode and start session */ + musb_writeb(MGC_O_HDRC_POWER, (MGC_M_POWER_HSENAB)); + devctl = musb_readb(MGC_O_HDRC_DEVCTL); + devctl |= MGC_M_DEVCTL_SESSION; + musb_writeb(MGC_O_HDRC_DEVCTL, devctl); +} + +/* + * This function writes data to endpoint fifo + */ +static void write_fifo(u8 ep, u32 length, void *fifo_data) +{ + u32 address; + u8 *data = (u8*)fifo_data; + + /* select the endpoint index */ + musb_writeb(MGC_O_HDRC_INDEX, ep); + address = MUSB_FIFO_OFFSET(ep)+0x20; + + /* write the data to the fifo */ + while(length) { + musb_writeb(address, *data); + data++; + length--; + } +} + +/* + * This function reads data from endpoint fifo + */ +static void read_fifo(u8 ep, u32 length, void *fifo_data) +{ + u32 address; + u8 *data = (u8*)fifo_data; + + /* select the endpoint index */ + musb_writeb(MGC_O_HDRC_INDEX, ep); + address = MUSB_FIFO_OFFSET(ep)+0x20; + + /* read the data to the fifo */ + while(length) { + *data = musb_readb(address); + data++; + length--; + } +} + +/* + * This function performs all intializations required for setting up the + * bulk endpoint. + */ +static void setup_bulk_ep(u8 bulkep) +{ + u16 csr; + + /* select bulk endpoint */ + musb_writeb(MGC_O_HDRC_INDEX, bulkep); + + /* clear the data toggle bit of bluk endpoint */ + csr = musb_readw(MGC_INDEXED_OFFSET(MGC_O_HDRC_TXCSR)); + csr = csr | MGC_M_TXCSR_CLRDATATOG; + musb_writew(MGC_INDEXED_OFFSET(MGC_O_HDRC_TXCSR), csr); + + csr = musb_readw(MGC_INDEXED_OFFSET(MGC_O_HDRC_RXCSR)); + csr = csr | MGC_M_RXCSR_CLRDATATOG; + musb_writew(MGC_INDEXED_OFFSET(MGC_O_HDRC_RXCSR), csr); + + /* also, flush the Tx and Rx FIFO of endpoint 1 */ + if ((musb_readb(MGC_INDEXED_OFFSET(MGC_O_HDRC_TXCSR)) & MGC_M_TXCSR_TXPKTRDY) == MGC_M_TXCSR_TXPKTRDY) { + csr = musb_readw(MGC_INDEXED_OFFSET(MGC_O_HDRC_TXCSR)); + csr = csr | MGC_M_TXCSR_FLUSHFIFO; + musb_writew(MGC_INDEXED_OFFSET(MGC_O_HDRC_TXCSR), csr); + } + + if ((musb_readb(MGC_INDEXED_OFFSET(MGC_O_HDRC_RXCSR)) & MGC_M_RXCSR_RXPKTRDY) == MGC_M_RXCSR_RXPKTRDY) { + csr = musb_readw(MGC_INDEXED_OFFSET(MGC_O_HDRC_RXCSR)); + csr = csr | MGC_M_RXCSR_FLUSHFIFO; + musb_writew(MGC_INDEXED_OFFSET(MGC_O_HDRC_RXCSR), csr); + } +} + +/* + * This function checks if RxStall has occured on the endpoint. If a RxStall has + * occured, the RxStall is cleared and 1 is returned. If RxStall has not occured, + * 0 is returned. + */ +static u8 check_stall(u8 ep, u8 dir_out) +{ + u16 csr; + + /* For endpoint 0 */ + if (ep == 0) { + csr = musb_readw(MGC_INDEXED_OFFSET(MGC_O_HDRC_CSR0)); + if ((csr & MGC_M_CSR0_H_RXSTALL ) == MGC_M_CSR0_H_RXSTALL) { + csr = csr & ~(MGC_M_CSR0_H_RXSTALL|MGC_M_CSR0_H_STATUSPKT|MGC_M_CSR0_RXPKTRDY); + musb_writew(MGC_INDEXED_OFFSET(MGC_O_HDRC_CSR0), csr); + return(1); + } + } else { /* For non-ep0 */ + if (dir_out == 1) { /* is it tx ep */ + csr = musb_readw(MGC_INDEXED_OFFSET(MGC_O_HDRC_TXCSR)); + if ((csr & MGC_M_TXCSR_H_RXSTALL) == MGC_M_TXCSR_H_RXSTALL) { + csr = csr & ~(MGC_M_CSR0_H_RXSTALL|MGC_M_CSR0_H_STATUSPKT|MGC_M_CSR0_RXPKTRDY); + musb_writew(MGC_INDEXED_OFFSET(MGC_O_HDRC_CSR0), csr); + return(1); + } + } else { /* is it rx ep */ + csr = musb_readw(MGC_INDEXED_OFFSET(MGC_O_HDRC_RXCSR)); + if ((csr & MGC_M_RXCSR_H_RXSTALL) == MGC_M_RXCSR_H_RXSTALL) { + csr = csr & ~(MGC_M_CSR0_H_RXSTALL|MGC_M_CSR0_H_STATUSPKT|MGC_M_CSR0_RXPKTRDY); + musb_writew(MGC_INDEXED_OFFSET(MGC_O_HDRC_CSR0), csr); + return(1); + } + } + } + + /* There is no RxStall at the endpoint */ + return(0); +} + + +/* + * waits until ep0 is ready. + */ +static int wait_until_ep0_ready(struct usb_device *dev, u32 bit_mask) +{ + u32 timeout; + + timeout = MUSB_USB_TIMEOUT; + do { + /* is there a stall */ + if (check_stall(MUSB_CONTROL_EP, 0)) { + dev->status = USB_ST_STALLED; + return( -2 ); + } + + switch(bit_mask) { + case MGC_M_CSR0_TXPKTRDY: + /* check if TXPKTRDY bit is cleared */ + if ((musb_readw( MGC_INDEXED_OFFSET(MGC_O_HDRC_CSR0)) & MGC_M_CSR0_TXPKTRDY) != MGC_M_CSR0_TXPKTRDY) + return(0); + break; + + case MGC_M_CSR0_RXPKTRDY: + /* check if RXPKTRDY bit is set */ + if ((musb_readw(MGC_INDEXED_OFFSET(MGC_O_HDRC_CSR0)) & MGC_M_CSR0_RXPKTRDY) == MGC_M_CSR0_RXPKTRDY) + return(0); + break; + + case MGC_M_CSR0_H_REQPKT: + /* check if the request has been sent */ + if ((musb_readw( MGC_INDEXED_OFFSET(MGC_O_HDRC_CSR0)) & MGC_M_CSR0_H_REQPKT) != MGC_M_CSR0_H_REQPKT) + return(0); + break; + } + timeout--; + } + while(timeout > 0); + + /* timed-out */ + dev->status = USB_ST_CRC_ERR; + return(-1); +} + +/* + * This function performs the setup phase of the control transfer + */ +static int ctrlreq_setup_phase(struct usb_device *dev, struct devrequest *setup) +{ + int result = -1; + u16 csr; + + /* write the control request to ep0 fifo */ + write_fifo(MUSB_CONTROL_EP, sizeof(struct devrequest), (void*)setup); + + /* enable transfer of setup packet */ + csr = musb_readw(MGC_INDEXED_OFFSET(MGC_O_HDRC_CSR0)); + csr = csr | (MGC_M_CSR0_TXPKTRDY|MGC_M_CSR0_H_SETUPPKT); + musb_writew(MGC_INDEXED_OFFSET(MGC_O_HDRC_CSR0), csr); + + /* wait until the setup packet is transmitted */ + result = wait_until_ep0_ready(dev, MGC_M_CSR0_TXPKTRDY); + dev->act_len = 0; + + /* control transfer setup phase completes */ + return(result); +} + +/* + * This function handles the control transfer in data phase + */ +static int ctrlreq_in_data_phase(struct usb_device *dev, u32 len, void *buffer) +{ + u16 csr; + u32 rxlen = 0; + u32 nextlen = 0; + u8 maxpktsize = ( 1 << dev->maxpacketsize ) * 8; + u8* rxbuff = (u8*)buffer; + u8 rxedlength; + int result; + + do { + /* Determine the next read length */ + nextlen = (( len-rxlen) > maxpktsize) ? maxpktsize:(len-rxlen); + + /* Set the ReqPkt bit */ + csr = musb_readw(MGC_INDEXED_OFFSET(MGC_O_HDRC_CSR0)); + csr = csr | MGC_M_CSR0_H_REQPKT; + musb_writew(MGC_INDEXED_OFFSET(MGC_O_HDRC_CSR0), csr); + + result = wait_until_ep0_ready(dev, MGC_M_CSR0_RXPKTRDY); + if (result < 0) + return(result); + + /* Actual number of bytes received by usb */ + rxedlength = musb_readb(MGC_INDEXED_OFFSET(MGC_O_HDRC_COUNT0)); + + /* Read the data from the RxFIFO */ + read_fifo(MUSB_CONTROL_EP, rxedlength, &rxbuff[rxlen]); + + /* Clear the RxPktRdy Bit */ + csr = musb_readw(MGC_INDEXED_OFFSET(MGC_O_HDRC_CSR0)); + csr = csr & (~MGC_M_CSR0_RXPKTRDY); + musb_writew(MGC_INDEXED_OFFSET(MGC_O_HDRC_CSR0), csr); + + if (rxedlength != nextlen) { + dev->act_len += rxedlength; + break; + } + + rxlen = rxlen + nextlen; + dev->act_len = rxlen; + } + while(rxlen < len); + + /* done reading the data */ + return(0); +} + +/* + * This function handles the control transfer out data phase + */ +static int ctrlreq_out_data_phase(struct usb_device *dev, u32 len, void *buffer) +{ + u16 csr; + u32 txlen = 0; + u32 nextlen = 0; + u8 maxpktsize = ( 1 << dev->maxpacketsize ) * 8; + u8* txbuff = (u8*)buffer; + int result; + + do { + /* Determine the next write length */ + nextlen = ((len-txlen) > maxpktsize) ? maxpktsize:(len-txlen); + + /* Load the data to send in FIFO */ + write_fifo(MUSB_CONTROL_EP, txlen, &txbuff[txlen]); + + /* Set TXPKTRDY bit */ + csr = musb_readw(MGC_INDEXED_OFFSET(MGC_O_HDRC_CSR0)); + csr = csr | (MGC_M_CSR0_H_DIS_PING|MGC_M_CSR0_TXPKTRDY); + musb_writew(MGC_INDEXED_OFFSET(MGC_O_HDRC_CSR0), csr); + + result = wait_until_ep0_ready(dev, MGC_M_CSR0_TXPKTRDY); + if ( result < 0 ) + return(result); + + txlen = txlen + nextlen; + dev->act_len = txlen; + } + while(txlen < len); + + /* done writing the data */ + return(0); +} + + +/* + * This function handles the control transfer out status phase + */ +static int ctrlreq_out_status_phase(struct usb_device *dev) +{ + u16 csr; + int result; + + /* Set the StatusPkt bit */ + csr = musb_readw(MGC_INDEXED_OFFSET(MGC_O_HDRC_CSR0)); + csr = csr | (MGC_M_CSR0_H_DIS_PING|MGC_M_CSR0_TXPKTRDY|MGC_M_CSR0_H_STATUSPKT); + musb_writew(MGC_INDEXED_OFFSET(MGC_O_HDRC_CSR0), csr); + + /* Wait until TXPKTRDY bit is cleared */ + result = wait_until_ep0_ready(dev, MGC_M_CSR0_TXPKTRDY); + return(result); +} + + +/* + * This function handles the control transfer in status phase + */ +static int ctrlreq_in_status_phase(struct usb_device *dev) +{ + u16 csr; + int result; + + /* Set the StatusPkt bit and ReqPkt bit */ + csr = musb_readw(MGC_INDEXED_OFFSET(MGC_O_HDRC_CSR0)); + csr = csr | (MGC_M_CSR0_H_DIS_PING|MGC_M_CSR0_H_REQPKT|MGC_M_CSR0_H_STATUSPKT); + musb_writew(MGC_INDEXED_OFFSET(MGC_O_HDRC_CSR0), csr); + + result = wait_until_ep0_ready(dev, MGC_M_CSR0_H_REQPKT); + if (result < 0) + return(result); + + /* clear StatusPkt bit and RxPktRdy bit */ + csr = musb_readw(MGC_INDEXED_OFFSET(MGC_O_HDRC_CSR0)); + csr = csr & (~((MGC_M_CSR0_RXPKTRDY|MGC_M_CSR0_H_STATUSPKT))); + musb_writew(MGC_INDEXED_OFFSET(MGC_O_HDRC_CSR0), csr); + + return(0); +} + + +/* + * determines the speed of the device (High/Full/Slow) + */ +static u8 get_dev_speed(struct usb_device *dev) +{ + if (dev->high == 1) + return(MGC_TYPE_SPEED_HIGH); + else + if (dev->slow == 1) + return(MGC_TYPE_SPEED_LOW); + else + return(MGC_TYPE_SPEED_FULL); +} + +/* + * configure the hub address and the port address. + */ +static void config_hub_port(struct usb_device *dev, u8 ep) +{ + u8 chid; + u8 hub; + + /* Find out the nearest parent which is high speed */ + while(dev->parent->parent != NULL) { + if (get_dev_speed(dev->parent) != MGC_TYPE_SPEED_HIGH) + dev = dev->parent; + else + break; + } + + /* determine the port address at that hub */ + hub = dev->parent->devnum; + for (chid = 0; chid < USB_MAXCHILDREN; chid++) + if (dev->parent->children[chid] == dev) + break; + + /* configure the hub address and the port address */ + musb_writeb(MGC_BUSCTL_OFFSET(ep, MGC_O_HDRC_TXHUBADDR), hub ); + musb_writeb(MGC_BUSCTL_OFFSET(ep, MGC_O_HDRC_TXHUBPORT), (chid+1) ); + musb_writeb(MGC_BUSCTL_OFFSET(ep, MGC_O_HDRC_RXHUBADDR), hub ); + musb_writeb(MGC_BUSCTL_OFFSET(ep, MGC_O_HDRC_RXHUBPORT), (chid+1) ); +} + +/* + * do a control transfer + */ +int submit_control_msg( struct usb_device *dev , unsigned long pipe , void *buffer , + int len , struct devrequest *setup ) +{ + int devnum = usb_pipedevice(pipe); + int ep = usb_pipeendpoint(pipe); + u16 csr; + u16 wIntrTxE; + u8 devspeed; + + /* select control endpoint */ + musb_writeb(MGC_O_HDRC_INDEX, MUSB_CONTROL_EP); + csr = musb_readw(MGC_INDEXED_OFFSET(MGC_O_HDRC_CSR0)); + + /* disable interrupt in case we flush */ + wIntrTxE = musb_readw(MGC_INDEXED_OFFSET(MGC_O_HDRC_INTRTXE)); + musb_writew(MGC_INDEXED_OFFSET(MGC_O_HDRC_INTRTXE), (wIntrTxE & ~(1 << ep))); + + /* endpoint 0: just flush */ + musb_writew(MGC_INDEXED_OFFSET(MGC_O_HDRC_CSR0), (csr|MGC_M_CSR0_FLUSHFIFO)); + musb_writew(MGC_INDEXED_OFFSET(MGC_O_HDRC_CSR0), (csr|MGC_M_CSR0_FLUSHFIFO)); + + /* target addr and (for multipoint) hub addr/port */ + musb_writeb(MGC_BUSCTL_OFFSET(MUSB_CONTROL_EP, MGC_O_HDRC_TXFUNCADDR), devnum); + musb_writeb(MGC_BUSCTL_OFFSET(MUSB_CONTROL_EP, MGC_O_HDRC_RXFUNCADDR), devnum); + + + /* configure the hub address and the port number as required */ + if (( musb_ishighspeed()) && (dev->parent != NULL)) { + devspeed = get_dev_speed(dev); + if (devspeed != MGC_TYPE_SPEED_HIGH) { + config_hub_port(dev, MUSB_CONTROL_EP); + musb_writeb(MGC_INDEXED_OFFSET(MGC_O_HDRC_TYPE0), devspeed << 6); + } + } else { + musb_writeb(MGC_INDEXED_OFFSET(MGC_O_HDRC_TYPE0), musb_speed << 6); + musb_writeb(MGC_BUSCTL_OFFSET(MUSB_CONTROL_EP, MGC_O_HDRC_TXHUBADDR), 0); + musb_writeb(MGC_BUSCTL_OFFSET(MUSB_CONTROL_EP, MGC_O_HDRC_TXHUBPORT), 0); + musb_writeb(MGC_BUSCTL_OFFSET(MUSB_CONTROL_EP, MGC_O_HDRC_RXHUBADDR), 0); + musb_writeb(MGC_BUSCTL_OFFSET(MUSB_CONTROL_EP, MGC_O_HDRC_RXHUBPORT), 0); + } + + /* Control transfer setup phase */ + if (ctrlreq_setup_phase(dev, setup) < 0) + return(-1); + + if ((setup->request == 0x06) || /* GET_DESCRIPTOR */ + (setup->request == 0x08) || /* GET_CONFIGURATION */ + (setup->request == 0x0A) || /* GET_INTERFACE */ + (setup->request == 0x00)) { /* GET_STATUS */ + /* control transfer in-data-phase */ + if (ctrlreq_in_data_phase(dev, len, buffer) < 0) + return(-1); + + /* control transfer out-status-phase */ + if (ctrlreq_out_status_phase(dev) < 0) + return(-1); + } else { + if ((setup->request == 0x05) || /* SET_ADDRESS */ + (setup->request == 0x09) || /* SET_CONFIGURATION */ + (setup->request == 0x03) || /* SET_FEATURE */ + (setup->request == 0x03) || /* SET_FEATURE */ + (setup->request == 0x0B) || /* SET_INTERFACE */ + (setup->request == 0x01) || /* CLEAR_FEATURE */ + (setup->request == 0xFF)) { /* USB Mass Stroage Reset */ + + /* control transfer in status phase */ + if (ctrlreq_in_status_phase(dev) < 0) + return(-1); + } else { + if (setup->request == 0x07) { /* SET_DESCRIPTOR */ + /* control transfer out data phase */ + if (ctrlreq_out_data_phase(dev, len, buffer) < 0) + return(-1); + + /* control transfer in status phase */ + if ( ctrlreq_in_status_phase(dev) < 0 ) + return(-1); + } else { + /* unhandled control transfer */ + return(-1); + } + } + } + + /* end of control transfer */ + dev->status = 0; + dev->act_len = len; + return len; +} + +/* + * do a bulk transfer + */ +int submit_bulk_msg(struct usb_device *dev, unsigned long pipe, void *buffer, int len) +{ + int dir_out = usb_pipeout(pipe); + int ep = usb_pipeendpoint(pipe); + int devnum = usb_pipedevice(pipe); + u8 type; + u16 csr; + u32 txLen = 0; + u32 nextLen = 0; + u8 devspeed; + u32 timeout; + + /* select bulk endpoint */ + musb_writeb(MGC_O_HDRC_INDEX, MUSB_BULK_EP); + + /* write the address of the device */ + if ( dir_out == 1 ) + musb_writeb(MGC_BUSCTL_OFFSET(MUSB_BULK_EP, MGC_O_HDRC_TXFUNCADDR), devnum); + else + musb_writeb(MGC_BUSCTL_OFFSET(MUSB_BULK_EP, MGC_O_HDRC_RXFUNCADDR), devnum); + + /* configure the hub address and the port number as required */ + if ((musb_ishighspeed()) && (dev->parent != NULL)) { + devspeed = get_dev_speed(dev); + if (devspeed != MGC_TYPE_SPEED_HIGH) { + /* MUSB is in high speed and the destination device is full speed device. + So configure the hub address and port address registers. */ + config_hub_port(dev, MUSB_BULK_EP); + } + } else { + if (dir_out == 1) { + musb_writeb(MGC_BUSCTL_OFFSET(MUSB_BULK_EP, MGC_O_HDRC_TXHUBADDR), 0); + musb_writeb(MGC_BUSCTL_OFFSET(MUSB_BULK_EP, MGC_O_HDRC_TXHUBPORT), 0); + } else { + musb_writeb(MGC_BUSCTL_OFFSET(MUSB_BULK_EP, MGC_O_HDRC_RXHUBADDR), 0); + musb_writeb(MGC_BUSCTL_OFFSET(MUSB_BULK_EP, MGC_O_HDRC_RXHUBPORT), 0); + } + devspeed = musb_speed; + } + + if (dir_out == 1) { /* bulk-out transfer */ + /* Write the old data toggle value */ + if (usb_gettoggle(dev, ep, dir_out) == 0) { + csr = musb_readw(MGC_INDEXED_OFFSET(MGC_O_HDRC_TXCSR)); + csr = MGC_M_TXCSR_CLRDATATOG; + musb_writew(MGC_INDEXED_OFFSET(MGC_O_HDRC_TXCSR), csr); + } else { + csr = musb_readw(MGC_INDEXED_OFFSET(MGC_O_HDRC_TXCSR)); + csr = csr | MGC_M_TXCSR_H_WR_DATATOGGLE; + musb_writew(MGC_INDEXED_OFFSET(MGC_O_HDRC_TXCSR), csr); + + csr = csr | (usb_gettoggle(dev, ep, dir_out)<<8); + musb_writew(MGC_INDEXED_OFFSET(MGC_O_HDRC_TXCSR), csr); + } + + /* Program the TxType register */ + type = (devspeed << MGC_S_TYPE_SPEED) | + (0x2 << MGC_S_TYPE_PROTO) | + (ep & 0xF); + musb_writeb(MGC_INDEXED_OFFSET(MGC_O_HDRC_TXTYPE), type); + + /* Write maximum packet size to the TxMaxp register */ + musb_writew(MGC_INDEXED_OFFSET(MGC_O_HDRC_TXMAXP), dev->epmaxpacketout[ep]); + + while(txLen < len) { + nextLen = ((len-txLen) < dev->epmaxpacketout[ep]) ? (len-txLen):dev->epmaxpacketout[ep]; + + /* Write the data to the FIFO */ + write_fifo(1, nextLen, (void*)(((u8*)buffer)+txLen)); + + /* Set the TxPktRdy bit */ + csr = musb_readw(MGC_INDEXED_OFFSET(MGC_O_HDRC_TXCSR)); + csr = csr | MGC_M_TXCSR_TXPKTRDY; + musb_writew(MGC_INDEXED_OFFSET(MGC_O_HDRC_TXCSR), csr); + + /* Wait until the TxPktRdy bit is cleared */ + timeout = MUSB_USB_TIMEOUT; + do { + csr = musb_readw(MGC_INDEXED_OFFSET(MGC_O_HDRC_TXCSR)); + if ((csr & MGC_M_TXCSR_H_RXSTALL) == MGC_M_TXCSR_H_RXSTALL) { + musb_writew(MGC_INDEXED_OFFSET(MGC_O_HDRC_TXCSR), csr & (~(MGC_M_TXCSR_H_RXSTALL))); + + /* Keep a copy of the data toggle bit */ + usb_settoggle(dev, ep, dir_out, (musb_readw(MGC_INDEXED_OFFSET(MGC_O_HDRC_TXCSR)) >> 8) & 0x01); + + dev->status = USB_ST_STALLED; + dev->act_len = txLen; + return(0); + } + + if ((csr & MGC_M_TXCSR_H_ERROR) == MGC_M_TXCSR_H_ERROR) { + /* keep a copy of the data toggle bit */ + usb_settoggle(dev, ep, dir_out, (musb_readw(MGC_INDEXED_OFFSET(MGC_O_HDRC_TXCSR)) >> 8) & 0x01); + dev->status = USB_ST_CRC_ERR; + dev->act_len = txLen; + return(0); + } + + /* maintain a timeout */ + if (timeout-- == 0) { + /* keep a copy of the data toggle bit */ + usb_settoggle(dev, ep, dir_out, (musb_readw(MGC_INDEXED_OFFSET(MGC_O_HDRC_TXCSR)) >> 8) & 0x01); + dev->status = USB_ST_CRC_ERR; + dev->act_len = txLen; + + /* clear the TxPktRdy bit */ + csr = musb_readw(MGC_INDEXED_OFFSET(MGC_O_HDRC_TXCSR)); + csr = csr & (~MGC_M_TXCSR_TXPKTRDY); + musb_writew(MGC_INDEXED_OFFSET(MGC_O_HDRC_TXCSR), csr); + return(0); + } + } + while((csr & MGC_M_TXCSR_TXPKTRDY) == MGC_M_TXCSR_TXPKTRDY); + + txLen = txLen + nextLen; + #if 0 + if ((txLen == len) && (nextLen == dev->epmaxpacketout[ep])) { + /* Set the TxPktRdy bit */ + csr = musb_readw(MGC_INDEXED_OFFSET(MGC_O_HDRC_TXCSR)); + csr = csr | MGC_M_TXCSR_TXPKTRDY; + musb_writew(MGC_INDEXED_OFFSET(MGC_O_HDRC_TXCSR), csr); + + /* Wait until the TxPktRdy bit is cleared */ + while(( musb_readw(MGC_INDEXED_OFFSET(MGC_O_HDRC_TXCSR) & MGC_M_TXCSR_TXPKTRDY)) == MGC_M_TXCSR_TXPKTRDY); + } + #endif + } + + /* Keep a copy of the data toggle bit */ + usb_settoggle(dev, ep, dir_out, (musb_readw(MGC_INDEXED_OFFSET(MGC_O_HDRC_TXCSR)) >> 8) & 0x01); + } else { /* bulk-in transfer */ + /* Write the old data toggle value */ + if (usb_gettoggle(dev, ep, dir_out) == 0) { + csr = musb_readw(MGC_INDEXED_OFFSET(MGC_O_HDRC_RXCSR)); + csr = MGC_M_RXCSR_CLRDATATOG; + musb_writew(MGC_INDEXED_OFFSET(MGC_O_HDRC_RXCSR), csr); + } else { + csr = musb_readw(MGC_INDEXED_OFFSET(MGC_O_HDRC_RXCSR)); + csr = csr | MGC_M_RXCSR_H_WR_DATATOGGLE; + musb_writew(MGC_INDEXED_OFFSET(MGC_O_HDRC_RXCSR), csr); + + csr = csr | (usb_gettoggle(dev, ep, dir_out)<<9); + musb_writew(MGC_INDEXED_OFFSET(MGC_O_HDRC_RXCSR), csr); + } + + /* Program the RxType register */ + type = (devspeed << MGC_S_TYPE_SPEED) | + (0x2 << MGC_S_TYPE_PROTO) | + (ep & 0xF); + musb_writeb(MGC_INDEXED_OFFSET(MGC_O_HDRC_RXTYPE), type); + + /* Write the maximum packet size to the RxMaxp register */ + musb_writew(MGC_INDEXED_OFFSET(MGC_O_HDRC_RXMAXP), dev->epmaxpacketin[ep]); + + while(txLen < len) { + nextLen = ((len-txLen) < dev->epmaxpacketin[ep]) ? (len-txLen):dev->epmaxpacketin[ep]; + + /* Set the ReqPkt bit */ + csr = musb_readw(MGC_INDEXED_OFFSET(MGC_O_HDRC_RXCSR)); + csr = csr | MGC_M_RXCSR_H_REQPKT; + musb_writew(MGC_INDEXED_OFFSET(MGC_O_HDRC_RXCSR), csr); + + /* Wait until the RxPktRdy bit is cleared */ + timeout = MUSB_USB_TIMEOUT; + do { + csr = musb_readw(MGC_INDEXED_OFFSET(MGC_O_HDRC_RXCSR)); + if ((csr & MGC_M_RXCSR_H_RXSTALL) == MGC_M_RXCSR_H_RXSTALL) { + /* Keep a copy of the data toggle bit */ + usb_settoggle(dev, ep, dir_out, (musb_readw( MGC_INDEXED_OFFSET(MGC_O_HDRC_RXCSR) ) >> 9) & 0x01); + + musb_writew(MGC_INDEXED_OFFSET(MGC_O_HDRC_RXCSR), csr & (~(MGC_M_RXCSR_H_RXSTALL))); + dev->status = USB_ST_STALLED; + dev->act_len = txLen; + return(0); + } + + if ((csr & MGC_M_RXCSR_H_ERROR) == MGC_M_RXCSR_H_ERROR) { + /* Keep a copy of the data toggle bit */ + usb_settoggle(dev, ep, dir_out, (musb_readw( MGC_INDEXED_OFFSET(MGC_O_HDRC_RXCSR) ) >> 9) & 0x01); + dev->status = USB_ST_CRC_ERR; + dev->act_len = txLen; + return(0); + } + + if (timeout-- == 0) { + /* Keep a copy of the data toggle bit */ + usb_settoggle(dev, ep, dir_out, (musb_readw( MGC_INDEXED_OFFSET(MGC_O_HDRC_RXCSR) ) >> 9) & 0x01); + dev->status = USB_ST_CRC_ERR; + dev->act_len = txLen; + + /* clear the ReqPkt bit */ + csr = musb_readw(MGC_INDEXED_OFFSET(MGC_O_HDRC_RXCSR)); + csr = csr & (~MGC_M_RXCSR_H_REQPKT); + musb_writew(MGC_INDEXED_OFFSET(MGC_O_HDRC_RXCSR), csr); + return(0); + } + } + while((csr & MGC_M_RXCSR_RXPKTRDY) != MGC_M_RXCSR_RXPKTRDY); + + /* Read the data from the FIFO */ + read_fifo(1, nextLen, (void*)(((u8*)buffer) + txLen)); + + /* Clear the RxPktRdy bit */ + csr = musb_readw(MGC_INDEXED_OFFSET(MGC_O_HDRC_RXCSR)); + csr = csr & ~(MGC_M_RXCSR_RXPKTRDY); + musb_writew(MGC_INDEXED_OFFSET(MGC_O_HDRC_RXCSR), csr); + + txLen = txLen + nextLen; + } + + /* Keep a copy of the data toggle bit */ + usb_settoggle(dev, ep, dir_out, (musb_readw( MGC_INDEXED_OFFSET(MGC_O_HDRC_RXCSR) ) >> 9) & 0x01); + } + + /* bulk transfer is complete */ + dev->status = 0; + dev->act_len = len; + return 0; +} + +/* + * This function initializes the usb controller module. + */ +int usb_lowlevel_init(void) +{ + u8 power; + u32 timeout; + + if (musb_platform_init() == -1) + return(-1); + + /* Configure all the endpoint FIFO's and start usb controller */ + musb_configure_ep(); + musb_start(); + + /* Wait until musb is enabled in host mode with a timeout. No hot + plug support. So there should be a usb device connected. */ + timeout = MUSB_USB_TIMEOUT*0x10; + do { + /* wait until the musb core moves into host mode */ + if (( musb_readb(MGC_O_HDRC_DEVCTL) & MGC_M_DEVCTL_HM) == MGC_M_DEVCTL_HM) + break; + + /* maintain a timeout */ + timeout--; + } + while( timeout > 0 ); + + /* if musb core is not in host mode, then return */ + if (timeout == 0) + return( -1 ); + + /* start usb bus reset */ + power = musb_readb(MGC_O_HDRC_POWER); + power = power | MGC_M_POWER_RESET; + musb_writeb(MGC_O_HDRC_POWER, power); + + /* After initiating a usb reset, wait for about 20ms to 30ms */ + udelay(30000); + + /* stop usb bus reset */ + power = musb_readb(MGC_O_HDRC_POWER); + power = power & (~MGC_M_POWER_RESET); + musb_writeb(MGC_O_HDRC_POWER, power); + + /* Determine if the connected device is a high/full/low speed device */ + if ((musb_readb(MGC_O_HDRC_POWER) & MGC_M_POWER_HSMODE) == MGC_M_POWER_HSMODE) { + /* High speed device is connected */ + musb_speed = MGC_TYPE_SPEED_HIGH; + } else { + if ((musb_readb(MGC_O_HDRC_DEVCTL) & MGC_M_DEVCTL_FSDEV) == MGC_M_DEVCTL_FSDEV) { + /* Full speed device is connected */ + musb_speed = MGC_TYPE_SPEED_FULL; + } else { + /* Low speed device is connected */ + musb_speed = MGC_TYPE_SPEED_LOW; + } + } + + /* setup the bulk endpoint */ + setup_bulk_ep(MUSB_BULK_EP); + + /* usb low level intialization is complete */ + return(0); +} + +/* + * This function stops the operation of the davinci usb module. + */ +int usb_lowlevel_stop(void) +{ + /* Reset the USB module */ + musb_platform_deinit(); + musb_writeb(MGC_O_HDRC_DEVCTL, 0); + + /* All done */ + return 0; +} + +/* + * This function supports usb interrupt transfers. Currently, usb interrupt transfers + * are not supported. + */ +int submit_int_msg( struct usb_device *dev, unsigned long pipe , + void *buffer , int len, int interval ) +{ + return(-1); +} + +#endif /* CONFIG_MUSB */ + + + diff --git a/drivers/usb/musbhdrc.h b/drivers/usb/musbhdrc.h new file mode 100644 index 00000000000..fba253e40b1 --- /dev/null +++ b/drivers/usb/musbhdrc.h @@ -0,0 +1,322 @@ +/****************************************************************** + * Copyright 2005 Mentor Graphics Corporation + * Copyright (C) 2005-2006 by Texas Instruments + * + * This file is part of the Inventra Controller Driver for Linux. + * + * The Inventra Controller Driver for Linux 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. + * + * The Inventra Controller Driver for Linux 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 The Inventra Controller Driver for Linux ; if not, + * write to the Free Software Foundation, Inc., 59 Temple Place, + * Suite 330, Boston, MA 02111-1307 USA + * + * ANY DOWNLOAD, USE, REPRODUCTION, MODIFICATION OR DISTRIBUTION + * OF THIS DRIVER INDICATES YOUR COMPLETE AND UNCONDITIONAL ACCEPTANCE + * OF THOSE TERMS.THIS DRIVER IS PROVIDED "AS IS" AND MENTOR GRAPHICS + * MAKES NO WARRANTIES, EXPRESS OR IMPLIED, RELATED TO THIS DRIVER. + * MENTOR GRAPHICS SPECIFICALLY DISCLAIMS ALL IMPLIED WARRANTIES + * OF MERCHANTABILITY; FITNESS FOR A PARTICULAR PURPOSE AND + * NON-INFRINGEMENT. MENTOR GRAPHICS DOES NOT PROVIDE SUPPORT + * SERVICES OR UPDATES FOR THIS DRIVER, EVEN IF YOU ARE A MENTOR + * GRAPHICS SUPPORT CUSTOMER. + ******************************************************************/ + +#ifndef __MUSB_HDRC_DEFS_H__ +#define __MUSB_HDRC_DEFS_H__ + +/* + * HDRC-specific definitions + */ + +#define MGC_MAX_USB_ENDS 4 + +#define MGC_END0_FIFOSIZE 64 /* this is non-configurable */ + +/* + * MUSBMHDRC Register map + */ + +/* Common USB registers */ + +#define MGC_O_HDRC_FADDR 0x00 /* 8-bit */ +#define MGC_O_HDRC_POWER 0x01 /* 8-bit */ + +#define MGC_O_HDRC_INTRTX 0x02 /* 16-bit */ +#define MGC_O_HDRC_INTRRX 0x04 +#define MGC_O_HDRC_INTRTXE 0x06 +#define MGC_O_HDRC_INTRRXE 0x08 +#define MGC_O_HDRC_INTRUSB 0x0A /* 8 bit */ +#define MGC_O_HDRC_INTRUSBE 0x0B /* 8 bit */ +#define MGC_O_HDRC_FRAME 0x0C +#define MGC_O_HDRC_INDEX 0x0E /* 8 bit */ +#define MGC_O_HDRC_TESTMODE 0x0F /* 8 bit */ + +/* Get offset for a given FIFO from musb->pRegs */ +#ifdef CONFIG_USB_TUSB6010 +#define MUSB_FIFO_OFFSET(epnum) (0x200 + ((epnum) * 0x20)) +#else +#define MUSB_FIFO_OFFSET(epnum) (epnum * 4) +#endif + +/* Additional Control Registers */ + +#define MGC_O_HDRC_DEVCTL 0x60 /* 8 bit */ + +/* These are always controlled through the INDEX register */ +#define MGC_O_HDRC_TXFIFOSZ 0x62 /* 8-bit (see masks) */ +#define MGC_O_HDRC_RXFIFOSZ 0x63 /* 8-bit (see masks) */ +#define MGC_O_HDRC_TXFIFOADD 0x64 /* 16-bit offset shifted right 3 */ +#define MGC_O_HDRC_RXFIFOADD 0x66 /* 16-bit offset shifted right 3 */ + +// vctrl/vstatus: optional vendor utmi+phy register at 0x68 +#define MGC_O_HDRC_HWVERS 0x6C /* 8 bit */ + +#define MGC_O_HDRC_EPINFO 0x78 /* 8 bit */ +#define MGC_O_HDRC_RAMINFO 0x79 /* 8 bit */ +#define MGC_O_HDRC_LINKINFO 0x7a /* 8 bit */ +#define MGC_O_HDRC_VPLEN 0x7b /* 8 bit */ +#define MGC_O_HDRC_HS_EOF1 0x7c /* 8 bit */ +#define MGC_O_HDRC_FS_EOF1 0x7d /* 8 bit */ +#define MGC_O_HDRC_LS_EOF1 0x7e /* 8 bit */ + +/* offsets to endpoint registers */ +#define MGC_O_HDRC_TXMAXP 0x00 +#define MGC_O_HDRC_TXCSR 0x02 +#define MGC_O_HDRC_CSR0 MGC_O_HDRC_TXCSR /* re-used for EP0 */ +#define MGC_O_HDRC_RXMAXP 0x04 +#define MGC_O_HDRC_RXCSR 0x06 +#define MGC_O_HDRC_RXCOUNT 0x08 +#define MGC_O_HDRC_COUNT0 MGC_O_HDRC_RXCOUNT /* re-used for EP0 */ +#define MGC_O_HDRC_TXTYPE 0x0A +#define MGC_O_HDRC_TYPE0 MGC_O_HDRC_TXTYPE /* re-used for EP0 */ +#define MGC_O_HDRC_TXINTERVAL 0x0B +#define MGC_O_HDRC_NAKLIMIT0 MGC_O_HDRC_TXINTERVAL /* re-used for EP0 */ +#define MGC_O_HDRC_RXTYPE 0x0C +#define MGC_O_HDRC_RXINTERVAL 0x0D +#define MGC_O_HDRC_FIFOSIZE 0x0F +#define MGC_O_HDRC_CONFIGDATA MGC_O_HDRC_FIFOSIZE /* re-used for EP0 */ + +/* offsets to endpoint registers in indexed model (using INDEX register) */ +#define MGC_INDEXED_OFFSET(_bOffset) \ + (0x10 + (_bOffset)) + +/* offsets to endpoint registers in flat models */ +#define MGC_FLAT_OFFSET(_bEnd, _bOffset) \ + (0x100 + (0x10*(_bEnd)) + (_bOffset)) + +#ifdef CONFIG_USB_TUSB6010 +/* TUSB6010 EP0 configuration register is special */ +#define MGC_TUSB_OFFSET(_bEnd, _bOffset) \ + (0x10 + _bOffset) +#include "tusb6010.h" /* needed "only" for TUSB_EP0_CONF */ +#endif + +/* "bus control"/target registers, for host side multipoint (external hubs) */ +#define MGC_O_HDRC_TXFUNCADDR 0x00 +#define MGC_O_HDRC_TXHUBADDR 0x02 +#define MGC_O_HDRC_TXHUBPORT 0x03 + +#define MGC_O_HDRC_RXFUNCADDR 0x04 +#define MGC_O_HDRC_RXHUBADDR 0x06 +#define MGC_O_HDRC_RXHUBPORT 0x07 + +#define MGC_BUSCTL_OFFSET(_bEnd, _bOffset) \ + (0x80 + (8*(_bEnd)) + (_bOffset)) + +/* + * MUSBHDRC Register bit masks + */ + +/* POWER */ + +#define MGC_M_POWER_ISOUPDATE 0x80 +#define MGC_M_POWER_SOFTCONN 0x40 +#define MGC_M_POWER_HSENAB 0x20 +#define MGC_M_POWER_HSMODE 0x10 +#define MGC_M_POWER_RESET 0x08 +#define MGC_M_POWER_RESUME 0x04 +#define MGC_M_POWER_SUSPENDM 0x02 +#define MGC_M_POWER_ENSUSPEND 0x01 + +/* INTRUSB */ +#define MGC_M_INTR_SUSPEND 0x01 +#define MGC_M_INTR_RESUME 0x02 +#define MGC_M_INTR_RESET 0x04 +#define MGC_M_INTR_BABBLE 0x04 +#define MGC_M_INTR_SOF 0x08 +#define MGC_M_INTR_CONNECT 0x10 +#define MGC_M_INTR_DISCONNECT 0x20 +#define MGC_M_INTR_SESSREQ 0x40 +#define MGC_M_INTR_VBUSERROR 0x80 /* FOR SESSION END */ + +/* DEVCTL */ +#define MGC_M_DEVCTL_BDEVICE 0x80 +#define MGC_M_DEVCTL_FSDEV 0x40 +#define MGC_M_DEVCTL_LSDEV 0x20 +#define MGC_M_DEVCTL_VBUS 0x18 +#define MGC_S_DEVCTL_VBUS 3 +#define MGC_M_DEVCTL_HM 0x04 +#define MGC_M_DEVCTL_HR 0x02 +#define MGC_M_DEVCTL_SESSION 0x01 + +/* TESTMODE */ + +#define MGC_M_TEST_FORCE_HOST 0x80 +#define MGC_M_TEST_FIFO_ACCESS 0x40 +#define MGC_M_TEST_FORCE_FS 0x20 +#define MGC_M_TEST_FORCE_HS 0x10 +#define MGC_M_TEST_PACKET 0x08 +#define MGC_M_TEST_K 0x04 +#define MGC_M_TEST_J 0x02 +#define MGC_M_TEST_SE0_NAK 0x01 + +/* allocate for double-packet buffering (effectively doubles assigned _SIZE) */ +#define MGC_M_FIFOSZ_DPB 0x10 +/* allocation size (8, 16, 32, ... 4096) */ +#define MGC_M_FIFOSZ_SIZE 0x0f + +/* CSR0 */ +#define MGC_M_CSR0_FLUSHFIFO 0x0100 +#define MGC_M_CSR0_TXPKTRDY 0x0002 +#define MGC_M_CSR0_RXPKTRDY 0x0001 + +/* CSR0 in Peripheral mode */ +#define MGC_M_CSR0_P_SVDSETUPEND 0x0080 +#define MGC_M_CSR0_P_SVDRXPKTRDY 0x0040 +#define MGC_M_CSR0_P_SENDSTALL 0x0020 +#define MGC_M_CSR0_P_SETUPEND 0x0010 +#define MGC_M_CSR0_P_DATAEND 0x0008 +#define MGC_M_CSR0_P_SENTSTALL 0x0004 + +/* CSR0 in Host mode */ +#define MGC_M_CSR0_H_DIS_PING 0x0800 +#define MGC_M_CSR0_H_WR_DATATOGGLE 0x0400 /* set to allow setting: */ +#define MGC_M_CSR0_H_DATATOGGLE 0x0200 /* data toggle control */ +#define MGC_M_CSR0_H_NAKTIMEOUT 0x0080 +#define MGC_M_CSR0_H_STATUSPKT 0x0040 +#define MGC_M_CSR0_H_REQPKT 0x0020 +#define MGC_M_CSR0_H_ERROR 0x0010 +#define MGC_M_CSR0_H_SETUPPKT 0x0008 +#define MGC_M_CSR0_H_RXSTALL 0x0004 + +/* CSR0 bits to avoid zeroing (write zero clears, write 1 ignored) */ +#define MGC_M_CSR0_P_WZC_BITS \ + ( MGC_M_CSR0_P_SENTSTALL ) +#define MGC_M_CSR0_H_WZC_BITS \ + ( MGC_M_CSR0_H_NAKTIMEOUT | MGC_M_CSR0_H_RXSTALL \ + | MGC_M_CSR0_RXPKTRDY ) + + +/* TxType/RxType */ +#define MGC_M_TYPE_SPEED 0xc0 +#define MGC_S_TYPE_SPEED 6 +#define MGC_TYPE_SPEED_HIGH 1 +#define MGC_TYPE_SPEED_FULL 2 +#define MGC_TYPE_SPEED_LOW 3 +#define MGC_M_TYPE_PROTO 0x30 /* implicitly zero for ep0 */ +#define MGC_S_TYPE_PROTO 4 +#define MGC_M_TYPE_REMOTE_END 0xf /* implicitly zero for ep0 */ + +/* CONFIGDATA */ + +#define MGC_M_CONFIGDATA_MPRXE 0x80 /* auto bulk pkt combining */ +#define MGC_M_CONFIGDATA_MPTXE 0x40 /* auto bulk pkt splitting */ +#define MGC_M_CONFIGDATA_BIGENDIAN 0x20 +#define MGC_M_CONFIGDATA_HBRXE 0x10 /* HB-ISO for RX */ +#define MGC_M_CONFIGDATA_HBTXE 0x08 /* HB-ISO for TX */ +#define MGC_M_CONFIGDATA_DYNFIFO 0x04 /* dynamic FIFO sizing */ +#define MGC_M_CONFIGDATA_SOFTCONE 0x02 /* SoftConnect */ +#define MGC_M_CONFIGDATA_UTMIDW 0x01 /* data width 0/1 => 8/16bits */ + +/* TXCSR in Peripheral and Host mode */ + +#define MGC_M_TXCSR_AUTOSET 0x8000 +#define MGC_M_TXCSR_MODE 0x2000 +#define MGC_M_TXCSR_DMAENAB 0x1000 +#define MGC_M_TXCSR_FRCDATATOG 0x0800 +#define MGC_M_TXCSR_DMAMODE 0x0400 +#define MGC_M_TXCSR_CLRDATATOG 0x0040 +#define MGC_M_TXCSR_FLUSHFIFO 0x0008 +#define MGC_M_TXCSR_FIFONOTEMPTY 0x0002 +#define MGC_M_TXCSR_TXPKTRDY 0x0001 + +/* TXCSR in Peripheral mode */ + +#define MGC_M_TXCSR_P_ISO 0x4000 +#define MGC_M_TXCSR_P_INCOMPTX 0x0080 +#define MGC_M_TXCSR_P_SENTSTALL 0x0020 +#define MGC_M_TXCSR_P_SENDSTALL 0x0010 +#define MGC_M_TXCSR_P_UNDERRUN 0x0004 + +/* TXCSR in Host mode */ + +#define MGC_M_TXCSR_H_WR_DATATOGGLE 0x0200 +#define MGC_M_TXCSR_H_DATATOGGLE 0x0100 +#define MGC_M_TXCSR_H_NAKTIMEOUT 0x0080 +#define MGC_M_TXCSR_H_RXSTALL 0x0020 +#define MGC_M_TXCSR_H_ERROR 0x0004 + +/* TXCSR bits to avoid zeroing (write zero clears, write 1 ignored) */ +#define MGC_M_TXCSR_P_WZC_BITS \ + ( MGC_M_TXCSR_P_INCOMPTX | MGC_M_TXCSR_P_SENTSTALL \ + | MGC_M_TXCSR_P_UNDERRUN | MGC_M_TXCSR_FIFONOTEMPTY ) +#define MGC_M_TXCSR_H_WZC_BITS \ + ( MGC_M_TXCSR_H_NAKTIMEOUT | MGC_M_TXCSR_H_RXSTALL \ + | MGC_M_TXCSR_H_ERROR | MGC_M_TXCSR_FIFONOTEMPTY ) + + +/* RXCSR in Peripheral and Host mode */ + +#define MGC_M_RXCSR_AUTOCLEAR 0x8000 +#define MGC_M_RXCSR_DMAENAB 0x2000 +#define MGC_M_RXCSR_DISNYET 0x1000 +#define MGC_M_RXCSR_PID_ERR 0x1000 +#define MGC_M_RXCSR_DMAMODE 0x0800 +#define MGC_M_RXCSR_INCOMPRX 0x0100 +#define MGC_M_RXCSR_CLRDATATOG 0x0080 +#define MGC_M_RXCSR_FLUSHFIFO 0x0010 +#define MGC_M_RXCSR_DATAERROR 0x0008 +#define MGC_M_RXCSR_FIFOFULL 0x0002 +#define MGC_M_RXCSR_RXPKTRDY 0x0001 + +/* RXCSR in Peripheral mode */ + +#define MGC_M_RXCSR_P_ISO 0x4000 +#define MGC_M_RXCSR_P_SENTSTALL 0x0040 +#define MGC_M_RXCSR_P_SENDSTALL 0x0020 +#define MGC_M_RXCSR_P_OVERRUN 0x0004 + +/* RXCSR in Host mode */ + +#define MGC_M_RXCSR_H_AUTOREQ 0x4000 +#define MGC_M_RXCSR_H_WR_DATATOGGLE 0x0400 +#define MGC_M_RXCSR_H_DATATOGGLE 0x0200 +#define MGC_M_RXCSR_H_RXSTALL 0x0040 +#define MGC_M_RXCSR_H_REQPKT 0x0020 +#define MGC_M_RXCSR_H_ERROR 0x0004 + +/* RXCSR bits to avoid zeroing (write zero clears, write 1 ignored) */ +#define MGC_M_RXCSR_P_WZC_BITS \ + ( MGC_M_RXCSR_P_SENTSTALL | MGC_M_RXCSR_P_OVERRUN \ + | MGC_M_RXCSR_RXPKTRDY ) +#define MGC_M_RXCSR_H_WZC_BITS \ + ( MGC_M_RXCSR_H_RXSTALL | MGC_M_RXCSR_H_ERROR \ + | MGC_M_RXCSR_DATAERROR | MGC_M_RXCSR_RXPKTRDY ) + + +/* HUBADDR */ +#define MGC_M_HUBADDR_MULTI_TT 0x80 + + +#endif /* __MUSB_HDRC_DEFS_H__ */ + diff --git a/examples/.gitignore b/examples/.gitignore index 806425ff783..e69de29bb2d 100644 --- a/examples/.gitignore +++ b/examples/.gitignore @@ -1,10 +0,0 @@ -/82559_eeprom -/hello_world -/interrupt -/mem_to_mem_idma2intr -/test_burst -/timer -/sched -/smc91111_eeprom -*.bin -*.srec diff --git a/fs/fat/fat.c b/fs/fat/fat.c index 49c78ed79ac..417721296db 100644 --- a/fs/fat/fat.c +++ b/fs/fat/fat.c @@ -45,27 +45,32 @@ downcase(char *str) } } -static block_dev_desc_t *cur_dev = NULL; +static block_dev_desc_t *cur_dev = NULL; static unsigned long part_offset = 0; static int cur_part = 1; -#define DOS_PART_TBL_OFFSET 0x1be +#define DOS_PART_TBL_OFFSET 0x1be #define DOS_PART_MAGIC_OFFSET 0x1fe #define DOS_FS_TYPE_OFFSET 0x36 - +#define DOS_FS_FAT32_TYPE_OFFSET 0x52 int disk_read (__u32 startblock, __u32 getsize, __u8 * bufptr) { + int result; + startblock += part_offset; if (cur_dev == NULL) return -1; if (cur_dev->block_read) { - return cur_dev->block_read (cur_dev->dev + result = cur_dev->block_read (cur_dev->dev , startblock, getsize, (unsigned long *)bufptr); + if ( result != 0 ) + return( result ); + else + return( -1 ); } return -1; } - int fat_register_device(block_dev_desc_t *dev_desc, int part_no) { @@ -86,15 +91,17 @@ fat_register_device(block_dev_desc_t *dev_desc, int part_no) return -1; } #if (defined(CONFIG_CMD_IDE) || \ - defined(CONFIG_CMD_SCSI) || \ - defined(CONFIG_CMD_USB) || \ - defined(CONFIG_MMC) || \ - defined(CONFIG_SYSTEMACE) ) + defined(CONFIG_CMD_SCSI) || \ + defined(CONFIG_CMD_USB) || \ + defined(CONFIG_MMC) || \ + defined(CONFIG_SYSTEMACE) ) + memset (&info, 0, sizeof(info)); /* First we assume, there is a MBR */ if (!get_partition_info (dev_desc, part_no, &info)) { part_offset = info.start; cur_part = part_no; - } else if (!strncmp((char *)&buffer[DOS_FS_TYPE_OFFSET], "FAT", 3)) { + } else if(!strncmp((char *)&buffer[DOS_FS_TYPE_OFFSET],"FAT",3) || + !strncmp((char *)&buffer[DOS_FS_FAT32_TYPE_OFFSET],"FAT32",5)) { /* ok, we assume we are on a PBR only */ cur_part = 1; part_offset = 0; @@ -228,7 +235,7 @@ get_fatent(fsdata *mydata, __u32 entry) __u32 startblock = bufnum * FATBUFBLOCKS; fatlength *= SECTOR_SIZE; /* We want it in bytes now */ - startblock += mydata->fat_sect; /* Offset from start of disk */ + startblock += mydata->fat_sect; /* Offset from start of disk */ if (getsize > fatlength) getsize = fatlength; if (disk_read(startblock, getsize, bufptr) < 0) { @@ -330,7 +337,7 @@ get_cluster(fsdata *mydata, __u32 clustnum, __u8 *buffer, unsigned long size) */ static long get_contents(fsdata *mydata, dir_entry *dentptr, __u8 *buffer, - unsigned long maxsize) + unsigned long maxsize) { unsigned long filesize = FAT2CPU32(dentptr->size), gotsize = 0; unsigned int bytesperclust = mydata->clust_size * SECTOR_SIZE; @@ -438,7 +445,7 @@ slot2str(dir_slot *slotptr, char *l_name, int *idx) __u8 get_vfatname_block[MAX_CLUSTSIZE]; static int get_vfatname(fsdata *mydata, int curclust, __u8 *cluster, - dir_entry *retdent, char *l_name) + dir_entry *retdent, char *l_name) { dir_entry *realdent; dir_slot *slotptr = (dir_slot*) retdent; @@ -526,140 +533,140 @@ static dir_entry *get_dentfromdir (fsdata * mydata, int startsect, char *filename, dir_entry * retdent, int dols) { - __u16 prevcksum = 0xffff; - __u32 curclust = START (retdent); - int files = 0, dirs = 0; + __u16 prevcksum = 0xffff; + __u32 curclust = START (retdent); + int files = 0, dirs = 0; - FAT_DPRINT ("get_dentfromdir: %s\n", filename); - while (1) { + FAT_DPRINT ("get_dentfromdir: %s\n", filename); + while (1) { dir_entry *dentptr; int i; if (get_cluster (mydata, curclust, get_dentfromdir_block, mydata->clust_size * SECTOR_SIZE) != 0) { - FAT_DPRINT ("Error: reading directory block\n"); - return NULL; + FAT_DPRINT ("Error: reading directory block\n"); + return NULL; } dentptr = (dir_entry *) get_dentfromdir_block; for (i = 0; i < DIRENTSPERCLUST; i++) { - char s_name[14], l_name[256]; - - l_name[0] = '\0'; - if (dentptr->name[0] == DELETED_FLAG) { - dentptr++; - continue; - } - if ((dentptr->attr & ATTR_VOLUME)) { + char s_name[14], l_name[256]; + + l_name[0] = '\0'; + if (dentptr->name[0] == DELETED_FLAG) { + dentptr++; + continue; + } + if ((dentptr->attr & ATTR_VOLUME)) { #ifdef CONFIG_SUPPORT_VFAT if ((dentptr->attr & ATTR_VFAT) && - (dentptr->name[0] & LAST_LONG_ENTRY_MASK)) { - prevcksum = ((dir_slot *) dentptr) - ->alias_checksum; - get_vfatname (mydata, curclust, get_dentfromdir_block, + (dentptr->name[0] & LAST_LONG_ENTRY_MASK)) { + prevcksum = ((dir_slot *) dentptr) + ->alias_checksum; + get_vfatname (mydata, curclust, get_dentfromdir_block, dentptr, l_name); - if (dols) { + if (dols) { int isdir = (dentptr->attr & ATTR_DIR); char dirc; int doit = 0; if (isdir) { - dirs++; - dirc = '/'; - doit = 1; + dirs++; + dirc = '/'; + doit = 1; } else { - dirc = ' '; - if (l_name[0] != 0) { + dirc = ' '; + if (l_name[0] != 0) { files++; doit = 1; - } + } } if (doit) { - if (dirc == ' ') { - printf (" %8ld %s%c\n", + if (dirc == ' ') { + printf (" %8ld %s%c\n", (long) FAT2CPU32 (dentptr->size), l_name, dirc); - } else { - printf (" %s%c\n", l_name, dirc); - } + } else { + printf (" %s%c\n", l_name, dirc); + } } dentptr++; continue; - } - FAT_DPRINT ("vfatname: |%s|\n", l_name); + } + FAT_DPRINT ("vfatname: |%s|\n", l_name); } else #endif { - /* Volume label or VFAT entry */ - dentptr++; - continue; + /* Volume label or VFAT entry */ + dentptr++; + continue; + } } - } - if (dentptr->name[0] == 0) { + if (dentptr->name[0] == 0) { if (dols) { - printf ("\n%d file(s), %d dir(s)\n\n", files, dirs); + printf ("\n%d file(s), %d dir(s)\n\n", files, dirs); } FAT_DPRINT ("Dentname == NULL - %d\n", i); return NULL; - } + } #ifdef CONFIG_SUPPORT_VFAT - if (dols && mkcksum (dentptr->name) == prevcksum) { + if (dols && mkcksum (dentptr->name) == prevcksum) { dentptr++; continue; - } + } #endif - get_name (dentptr, s_name); - if (dols) { + get_name (dentptr, s_name); + if (dols) { int isdir = (dentptr->attr & ATTR_DIR); char dirc; int doit = 0; if (isdir) { - dirs++; - dirc = '/'; - doit = 1; + dirs++; + dirc = '/'; + doit = 1; } else { - dirc = ' '; - if (s_name[0] != 0) { + dirc = ' '; + if (s_name[0] != 0) { files++; doit = 1; - } + } } if (doit) { - if (dirc == ' ') { - printf (" %8ld %s%c\n", + if (dirc == ' ') { + printf (" %8ld %s%c\n", (long) FAT2CPU32 (dentptr->size), s_name, dirc); - } else { - printf (" %s%c\n", s_name, dirc); - } + } else { + printf (" %s%c\n", s_name, dirc); + } } dentptr++; continue; - } - if (strcmp (filename, s_name) && strcmp (filename, l_name)) { + } + if (strcmp (filename, s_name) && strcmp (filename, l_name)) { FAT_DPRINT ("Mismatch: |%s|%s|\n", s_name, l_name); dentptr++; continue; - } - memcpy (retdent, dentptr, sizeof (dir_entry)); + } + memcpy (retdent, dentptr, sizeof (dir_entry)); - FAT_DPRINT ("DentName: %s", s_name); - FAT_DPRINT (", start: 0x%x", START (dentptr)); - FAT_DPRINT (", size: 0x%x %s\n", + FAT_DPRINT ("DentName: %s", s_name); + FAT_DPRINT (", start: 0x%x", START (dentptr)); + FAT_DPRINT (", size: 0x%x %s\n", FAT2CPU32 (dentptr->size), (dentptr->attr & ATTR_DIR) ? "(DIR)" : ""); - return retdent; + return retdent; } curclust = get_fatent (mydata, curclust); if (CHECK_CLUST(curclust, mydata->fatsize)) { - FAT_DPRINT ("curclust: 0x%x\n", curclust); - FAT_ERROR ("Invalid FAT entry\n"); - return NULL; + FAT_DPRINT ("curclust: 0x%x\n", curclust); + FAT_ERROR ("Invalid FAT entry\n"); + return NULL; + } } - } - return NULL; + return NULL; } @@ -727,203 +734,203 @@ read_bootsectandvi(boot_sector *bs, volume_info *volinfo, int *fatsize) } -__u8 do_fat_read_block[MAX_CLUSTSIZE]; /* Block buffer */ +__u8 do_fat_read_block[MAX_CLUSTSIZE]; /* Block buffer */ long do_fat_read (const char *filename, void *buffer, unsigned long maxsize, - int dols) + int dols) { #if CONFIG_NIOS /* NIOS CPU cannot access big automatic arrays */ - static + static #endif - char fnamecopy[2048]; - boot_sector bs; - volume_info volinfo; - fsdata datablock; - fsdata *mydata = &datablock; - dir_entry *dentptr; - __u16 prevcksum = 0xffff; - char *subname = ""; - int rootdir_size, cursect; - int idx, isdir = 0; - int files = 0, dirs = 0; - long ret = 0; - int firsttime; - - if (read_bootsectandvi (&bs, &volinfo, &mydata->fatsize)) { + char fnamecopy[2048]; + boot_sector bs; + volume_info volinfo; + fsdata datablock; + fsdata *mydata = &datablock; + dir_entry *dentptr; + __u16 prevcksum = 0xffff; + char *subname = ""; + int rootdir_size, cursect; + int idx, isdir = 0; + int files = 0, dirs = 0; + long ret = 0; + int firsttime; + + if (read_bootsectandvi (&bs, &volinfo, &mydata->fatsize)) { FAT_DPRINT ("Error: reading boot sector\n"); return -1; - } - if (mydata->fatsize == 32) { + } + if (mydata->fatsize == 32) { mydata->fatlength = bs.fat32_length; - } else { + } else { mydata->fatlength = bs.fat_length; - } - mydata->fat_sect = bs.reserved; - cursect = mydata->rootdir_sect - = mydata->fat_sect + mydata->fatlength * bs.fats; - mydata->clust_size = bs.cluster_size; - if (mydata->fatsize == 32) { + } + mydata->fat_sect = bs.reserved; + cursect = mydata->rootdir_sect + = mydata->fat_sect + mydata->fatlength * bs.fats; + mydata->clust_size = bs.cluster_size; + if (mydata->fatsize == 32) { rootdir_size = mydata->clust_size; - mydata->data_begin = mydata->rootdir_sect /* + rootdir_size */ + mydata->data_begin = mydata->rootdir_sect /* + rootdir_size */ - (mydata->clust_size * 2); - } else { + } else { rootdir_size = ((bs.dir_entries[1] * (int) 256 + bs.dir_entries[0]) * sizeof (dir_entry)) / SECTOR_SIZE; mydata->data_begin = mydata->rootdir_sect + rootdir_size - (mydata->clust_size * 2); - } - mydata->fatbufnum = -1; + } + mydata->fatbufnum = -1; - FAT_DPRINT ("FAT%d, fatlength: %d\n", mydata->fatsize, + FAT_DPRINT ("FAT%d, fatlength: %d\n", mydata->fatsize, mydata->fatlength); - FAT_DPRINT ("Rootdir begins at sector: %d, offset: %x, size: %d\n" + FAT_DPRINT ("Rootdir begins at sector: %d, offset: %x, size: %d\n" "Data begins at: %d\n", mydata->rootdir_sect, mydata->rootdir_sect * SECTOR_SIZE, rootdir_size, mydata->data_begin); - FAT_DPRINT ("Cluster size: %d\n", mydata->clust_size); + FAT_DPRINT ("Cluster size: %d\n", mydata->clust_size); - /* "cwd" is always the root... */ - while (ISDIRDELIM (*filename)) + /* "cwd" is always the root... */ + while (ISDIRDELIM (*filename)) filename++; - /* Make a copy of the filename and convert it to lowercase */ - strcpy (fnamecopy, filename); - downcase (fnamecopy); - if (*fnamecopy == '\0') { + /* Make a copy of the filename and convert it to lowercase */ + strcpy (fnamecopy, filename); + downcase (fnamecopy); + if (*fnamecopy == '\0') { if (!dols) - return -1; + return -1; dols = LS_ROOT; - } else if ((idx = dirdelim (fnamecopy)) >= 0) { + } else if ((idx = dirdelim (fnamecopy)) >= 0) { isdir = 1; fnamecopy[idx] = '\0'; subname = fnamecopy + idx + 1; /* Handle multiple delimiters */ while (ISDIRDELIM (*subname)) - subname++; - } else if (dols) { + subname++; + } else if (dols) { isdir = 1; - } + } - while (1) { + while (1) { int i; if (disk_read (cursect, mydata->clust_size, do_fat_read_block) < 0) { - FAT_DPRINT ("Error: reading rootdir block\n"); - return -1; + FAT_DPRINT ("Error: reading rootdir block\n"); + return -1; } dentptr = (dir_entry *) do_fat_read_block; for (i = 0; i < DIRENTSPERBLOCK; i++) { - char s_name[14], l_name[256]; + char s_name[14], l_name[256]; - l_name[0] = '\0'; - if ((dentptr->attr & ATTR_VOLUME)) { + l_name[0] = '\0'; + if ((dentptr->attr & ATTR_VOLUME)) { #ifdef CONFIG_SUPPORT_VFAT if ((dentptr->attr & ATTR_VFAT) && - (dentptr->name[0] & LAST_LONG_ENTRY_MASK)) { - prevcksum = ((dir_slot *) dentptr)->alias_checksum; - get_vfatname (mydata, 0, do_fat_read_block, dentptr, l_name); - if (dols == LS_ROOT) { + (dentptr->name[0] & LAST_LONG_ENTRY_MASK)) { + prevcksum = ((dir_slot *) dentptr)->alias_checksum; + get_vfatname (mydata, 0, do_fat_read_block, dentptr, l_name); + if (dols == LS_ROOT) { int isdir = (dentptr->attr & ATTR_DIR); char dirc; int doit = 0; if (isdir) { - dirs++; - dirc = '/'; - doit = 1; + dirs++; + dirc = '/'; + doit = 1; } else { - dirc = ' '; - if (l_name[0] != 0) { + dirc = ' '; + if (l_name[0] != 0) { files++; doit = 1; - } + } } if (doit) { - if (dirc == ' ') { - printf (" %8ld %s%c\n", + if (dirc == ' ') { + printf (" %8ld %s%c\n", (long) FAT2CPU32 (dentptr->size), l_name, dirc); - } else { - printf (" %s%c\n", l_name, dirc); - } + } else { + printf (" %s%c\n", l_name, dirc); + } } dentptr++; continue; - } - FAT_DPRINT ("Rootvfatname: |%s|\n", l_name); + } + FAT_DPRINT ("Rootvfatname: |%s|\n", l_name); } else #endif { - /* Volume label or VFAT entry */ - dentptr++; - continue; + /* Volume label or VFAT entry */ + dentptr++; + continue; } - } else if (dentptr->name[0] == 0) { + } else if (dentptr->name[0] == 0) { FAT_DPRINT ("RootDentname == NULL - %d\n", i); if (dols == LS_ROOT) { - printf ("\n%d file(s), %d dir(s)\n\n", files, dirs); - return 0; + printf ("\n%d file(s), %d dir(s)\n\n", files, dirs); + return 0; } return -1; - } + } #ifdef CONFIG_SUPPORT_VFAT - else if (dols == LS_ROOT - && mkcksum (dentptr->name) == prevcksum) { + else if (dols == LS_ROOT + && mkcksum (dentptr->name) == prevcksum) { dentptr++; continue; - } + } #endif - get_name (dentptr, s_name); - if (dols == LS_ROOT) { + get_name (dentptr, s_name); + if (dols == LS_ROOT) { int isdir = (dentptr->attr & ATTR_DIR); char dirc; int doit = 0; if (isdir) { - dirc = '/'; - if (s_name[0] != 0) { + dirc = '/'; + if (s_name[0] != 0) { dirs++; doit = 1; - } + } } else { - dirc = ' '; - if (s_name[0] != 0) { + dirc = ' '; + if (s_name[0] != 0) { files++; doit = 1; - } + } } if (doit) { - if (dirc == ' ') { - printf (" %8ld %s%c\n", + if (dirc == ' ') { + printf (" %8ld %s%c\n", (long) FAT2CPU32 (dentptr->size), s_name, dirc); - } else { - printf (" %s%c\n", s_name, dirc); - } + } else { + printf (" %s%c\n", s_name, dirc); + } } dentptr++; continue; - } - if (strcmp (fnamecopy, s_name) && strcmp (fnamecopy, l_name)) { + } + if (strcmp (fnamecopy, s_name) && strcmp (fnamecopy, l_name)) { FAT_DPRINT ("RootMismatch: |%s|%s|\n", s_name, l_name); dentptr++; continue; - } - if (isdir && !(dentptr->attr & ATTR_DIR)) + } + if (isdir && !(dentptr->attr & ATTR_DIR)) return -1; - FAT_DPRINT ("RootName: %s", s_name); - FAT_DPRINT (", start: 0x%x", START (dentptr)); - FAT_DPRINT (", size: 0x%x %s\n", + FAT_DPRINT ("RootName: %s", s_name); + FAT_DPRINT (", start: 0x%x", START (dentptr)); + FAT_DPRINT (", size: 0x%x %s\n", FAT2CPU32 (dentptr->size), isdir ? "(DIR)" : ""); - goto rootdir_done; /* We got a match */ + goto rootdir_done; /* We got a match */ } cursect++; - } + } rootdir_done: - firsttime = 1; - while (isdir) { + firsttime = 1; + while (isdir) { int startsect = mydata->data_begin + START (dentptr) * mydata->clust_size; dir_entry dent; @@ -934,47 +941,47 @@ do_fat_read (const char *filename, void *buffer, unsigned long maxsize, idx = dirdelim (subname); if (idx >= 0) { - subname[idx] = '\0'; - nextname = subname + idx + 1; - /* Handle multiple delimiters */ - while (ISDIRDELIM (*nextname)) + subname[idx] = '\0'; + nextname = subname + idx + 1; + /* Handle multiple delimiters */ + while (ISDIRDELIM (*nextname)) nextname++; - if (dols && *nextname == '\0') + if (dols && *nextname == '\0') firsttime = 0; } else { - if (dols && firsttime) { + if (dols && firsttime) { firsttime = 0; - } else { + } else { isdir = 0; - } + } } if (get_dentfromdir (mydata, startsect, subname, dentptr, - isdir ? 0 : dols) == NULL) { - if (dols && !isdir) + isdir ? 0 : dols) == NULL) { + if (dols && !isdir) return 0; - return -1; + return -1; } if (idx >= 0) { - if (!(dentptr->attr & ATTR_DIR)) + if (!(dentptr->attr & ATTR_DIR)) return -1; - subname = nextname; + subname = nextname; + } } - } - ret = get_contents (mydata, dentptr, buffer, maxsize); - FAT_DPRINT ("Size: %d, got: %ld\n", FAT2CPU32 (dentptr->size), ret); + ret = get_contents (mydata, dentptr, buffer, maxsize); + FAT_DPRINT ("Size: %d, got: %ld\n", FAT2CPU32 (dentptr->size), ret); - return ret; + return ret; } int file_fat_detectfs(void) { - boot_sector bs; - volume_info volinfo; - int fatsize; + boot_sector bs; + volume_info volinfo; + int fatsize; char vol_label[12]; if(cur_dev==NULL) { @@ -982,20 +989,20 @@ file_fat_detectfs(void) return 1; } #if defined(CONFIG_CMD_IDE) || \ - defined(CONFIG_CMD_SCSI) || \ - defined(CONFIG_CMD_USB) || \ - defined(CONFIG_MMC) - printf("Interface: "); + defined(CONFIG_CMD_SCSI) || \ + defined(CONFIG_CMD_USB) || \ + defined(CONFIG_MMC) + printf("Interface: "); switch(cur_dev->if_type) { case IF_TYPE_IDE : printf("IDE"); break; - case IF_TYPE_SCSI : printf("SCSI"); break; + case IF_TYPE_SCSI : printf("SCSI"); break; case IF_TYPE_ATAPI : printf("ATAPI"); break; case IF_TYPE_USB : printf("USB"); break; case IF_TYPE_DOC : printf("DOC"); break; case IF_TYPE_MMC : printf("MMC"); break; default : printf("Unknown"); } - printf("\n Device %d: ",cur_dev->dev); + printf("\n Device %d: ",cur_dev->dev); dev_print(cur_dev); #endif if(read_bootsectandvi(&bs, &volinfo, &fatsize)) { diff --git a/include/.gitignore b/include/.gitignore index ef7dd5fc8a2..e69de29bb2d 100644 --- a/include/.gitignore +++ b/include/.gitignore @@ -1,8 +0,0 @@ -/autoconf.mk* -/asm -/asm-*/arch -/asm-*/proc -/bmp_logo.h -/config.h -/config.mk -/version_autogenerated.h diff --git a/include/asm-arm/arch-at91sam9/hardware.h b/include/asm-arm/arch-at91sam9/hardware.h index d2fe45388b3..fba3908cbdb 100644 --- a/include/asm-arm/arch-at91sam9/hardware.h +++ b/include/asm-arm/arch-at91sam9/hardware.h @@ -42,15 +42,4 @@ #error "Unsupported AT91 processor" #endif -/* - * container_of - cast a member of a structure out to the containing structure - * - * @ptr: the pointer to the member. - * @type: the type of the container struct this is embedded in. - * @member: the name of the member within the struct. - */ -#define container_of(ptr, type, member) ({ \ - const typeof(((type *)0)->member) *__mptr = (ptr); \ - (type *)((char *)__mptr - offsetof(type, member)); }) - #endif diff --git a/include/asm-arm/arch-da8xx/emac_defs.h b/include/asm-arm/arch-da8xx/emac_defs.h new file mode 100644 index 00000000000..6120a595e36 --- /dev/null +++ b/include/asm-arm/arch-da8xx/emac_defs.h @@ -0,0 +1,331 @@ +/* + * Copyright (C) 2007 Sergey Kubushyn <ksi@koi8.net> + * + * Based on: + * + * ---------------------------------------------------------------------------- + * + * dm644x_emac.h + * + * TI DaVinci (DM644X) EMAC peripheral driver header for DV-EVM + * + * Copyright (C) 2005 Texas Instruments. + * + * ---------------------------------------------------------------------------- + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * ---------------------------------------------------------------------------- + + * Modifications: + * ver. 1.0: Sep 2005, TI PSP Team - Created EMAC version for uBoot. + * + */ + +#ifndef _DM644X_EMAC_H_ +#define _DM644X_EMAC_H_ + +#include <asm/arch/hardware.h> + +#define EMAC_BASE_ADDR DAVINCI_EMAC_CNTRL_REGS_BASE +#define EMAC_WRAPPER_BASE_ADDR DAVINCI_EMAC_WRAPPER_CNTRL_REGS_BASE +#define EMAC_WRAPPER_RAM_ADDR DAVINCI_EMAC_WRAPPER_RAM_BASE +#define EMAC_MDIO_BASE_ADDR DAVINCI_MDIO_CNTRL_REGS_BASE + +/* MDIO module input frequency */ +#define EMAC_MDIO_BUS_FREQ clk_get(DAVINCI_MDIO_CLKID) + +/* MDIO clock output frequency */ +#define EMAC_MDIO_CLOCK_FREQ 2000000 /* 2.0 MHz */ + +/* Ethernet Min/Max packet size */ +#define EMAC_MIN_ETHERNET_PKT_SIZE 60 +#define EMAC_MAX_ETHERNET_PKT_SIZE 1518 +#define EMAC_PKT_ALIGN 18 /* 1518 + 18 = 1536 (packet aligned on 32 byte boundry) */ + +/* Number of RX packet buffers + * NOTE: Only 1 buffer supported as of now + */ +#define EMAC_MAX_RX_BUFFERS 10 + + +/*********************************************** + ******** Internally used macros *************** + ***********************************************/ + +#define EMAC_CH_TX 1 +#define EMAC_CH_RX 0 + +/* Each descriptor occupies 4 words, lets start RX desc's at 0 and + * reserve space for 64 descriptors max + */ +#define EMAC_RX_DESC_BASE 0x0 +#define EMAC_TX_DESC_BASE 0x1000 + +/* EMAC Teardown value */ +#define EMAC_TEARDOWN_VALUE 0xfffffffc + +/* MII Status Register */ +#define MII_STATUS_REG 1 + +/* Number of statistics registers */ +#define EMAC_NUM_STATS 36 + + +/* EMAC Descriptor */ +typedef volatile struct _emac_desc +{ + u_int32_t next; /* Pointer to next descriptor in chain */ + u_int8_t *buffer; /* Pointer to data buffer */ + u_int32_t buff_off_len; /* Buffer Offset(MSW) and Length(LSW) */ + u_int32_t pkt_flag_len; /* Packet Flags(MSW) and Length(LSW) */ +} emac_desc; + +/* CPPI bit positions */ +#define EMAC_CPPI_SOP_BIT (0x80000000) +#define EMAC_CPPI_EOP_BIT (0x40000000) +#define EMAC_CPPI_OWNERSHIP_BIT (0x20000000) +#define EMAC_CPPI_EOQ_BIT (0x10000000) +#define EMAC_CPPI_TEARDOWN_COMPLETE_BIT (0x08000000) +#define EMAC_CPPI_PASS_CRC_BIT (0x04000000) + +#define EMAC_CPPI_RX_ERROR_FRAME (0x03fc0000) + +#define EMAC_MACCONTROL_RMIISPEED_100 (1 << 15) +#define EMAC_MACCONTROL_MIIEN_ENABLE (0x20) +#define EMAC_MACCONTROL_FULLDUPLEX_ENABLE (0x1) + +#define EMAC_RXMBPENABLE_RXCAFEN_ENABLE (0x200000) +#define EMAC_RXMBPENABLE_RXBROADEN (0x2000) + + +#define MDIO_CONTROL_IDLE (0x80000000) +#define MDIO_CONTROL_ENABLE (0x40000000) +#define MDIO_CONTROL_FAULT_ENABLE (0x40000) +#define MDIO_CONTROL_FAULT (0x80000) +#define MDIO_USERACCESS0_GO (0x80000000) +#define MDIO_USERACCESS0_WRITE_READ (0x0) +#define MDIO_USERACCESS0_WRITE_WRITE (0x40000000) +#define MDIO_USERACCESS0_ACK (0x20000000) + +/* Ethernet MAC Registers Structure */ +typedef struct { + dv_reg TXIDVER; + dv_reg TXCONTROL; + dv_reg TXTEARDOWN; + u_int8_t RSVD0[4]; + dv_reg RXIDVER; + dv_reg RXCONTROL; + dv_reg RXTEARDOWN; + u_int8_t RSVD1[100]; + dv_reg TXINTSTATRAW; + dv_reg TXINTSTATMASKED; + dv_reg TXINTMASKSET; + dv_reg TXINTMASKCLEAR; + dv_reg MACINVECTOR; + u_int8_t RSVD2[12]; + dv_reg RXINTSTATRAW; + dv_reg RXINTSTATMASKED; + dv_reg RXINTMASKSET; + dv_reg RXINTMASKCLEAR; + dv_reg MACINTSTATRAW; + dv_reg MACINTSTATMASKED; + dv_reg MACINTMASKSET; + dv_reg MACINTMASKCLEAR; + u_int8_t RSVD3[64]; + dv_reg RXMBPENABLE; + dv_reg RXUNICASTSET; + dv_reg RXUNICASTCLEAR; + dv_reg RXMAXLEN; + dv_reg RXBUFFEROFFSET; + dv_reg RXFILTERLOWTHRESH; + u_int8_t RSVD4[8]; + dv_reg RX0FLOWTHRESH; + dv_reg RX1FLOWTHRESH; + dv_reg RX2FLOWTHRESH; + dv_reg RX3FLOWTHRESH; + dv_reg RX4FLOWTHRESH; + dv_reg RX5FLOWTHRESH; + dv_reg RX6FLOWTHRESH; + dv_reg RX7FLOWTHRESH; + dv_reg RX0FREEBUFFER; + dv_reg RX1FREEBUFFER; + dv_reg RX2FREEBUFFER; + dv_reg RX3FREEBUFFER; + dv_reg RX4FREEBUFFER; + dv_reg RX5FREEBUFFER; + dv_reg RX6FREEBUFFER; + dv_reg RX7FREEBUFFER; + dv_reg MACCONTROL; + dv_reg MACSTATUS; + dv_reg EMCONTROL; + dv_reg FIFOCONTROL; + dv_reg MACCONFIG; + dv_reg SOFTRESET; + u_int8_t RSVD5[88]; + dv_reg MACSRCADDRLO; + dv_reg MACSRCADDRHI; + dv_reg MACHASH1; + dv_reg MACHASH2; + dv_reg BOFFTEST; + dv_reg TPACETEST; + dv_reg RXPAUSE; + dv_reg TXPAUSE; + u_int8_t RSVD6[16]; + dv_reg RXGOODFRAMES; + dv_reg RXBCASTFRAMES; + dv_reg RXMCASTFRAMES; + dv_reg RXPAUSEFRAMES; + dv_reg RXCRCERRORS; + dv_reg RXALIGNCODEERRORS; + dv_reg RXOVERSIZED; + dv_reg RXJABBER; + dv_reg RXUNDERSIZED; + dv_reg RXFRAGMENTS; + dv_reg RXFILTERED; + dv_reg RXQOSFILTERED; + dv_reg RXOCTETS; + dv_reg TXGOODFRAMES; + dv_reg TXBCASTFRAMES; + dv_reg TXMCASTFRAMES; + dv_reg TXPAUSEFRAMES; + dv_reg TXDEFERRED; + dv_reg TXCOLLISION; + dv_reg TXSINGLECOLL; + dv_reg TXMULTICOLL; + dv_reg TXEXCESSIVECOLL; + dv_reg TXLATECOLL; + dv_reg TXUNDERRUN; + dv_reg TXCARRIERSENSE; + dv_reg TXOCTETS; + dv_reg FRAME64; + dv_reg FRAME65T127; + dv_reg FRAME128T255; + dv_reg FRAME256T511; + dv_reg FRAME512T1023; + dv_reg FRAME1024TUP; + dv_reg NETOCTETS; + dv_reg RXSOFOVERRUNS; + dv_reg RXMOFOVERRUNS; + dv_reg RXDMAOVERRUNS; + u_int8_t RSVD7[624]; + dv_reg MACADDRLO; + dv_reg MACADDRHI; + dv_reg MACINDEX; + u_int8_t RSVD8[244]; + dv_reg TX0HDP; + dv_reg TX1HDP; + dv_reg TX2HDP; + dv_reg TX3HDP; + dv_reg TX4HDP; + dv_reg TX5HDP; + dv_reg TX6HDP; + dv_reg TX7HDP; + dv_reg RX0HDP; + dv_reg RX1HDP; + dv_reg RX2HDP; + dv_reg RX3HDP; + dv_reg RX4HDP; + dv_reg RX5HDP; + dv_reg RX6HDP; + dv_reg RX7HDP; + dv_reg TX0CP; + dv_reg TX1CP; + dv_reg TX2CP; + dv_reg TX3CP; + dv_reg TX4CP; + dv_reg TX5CP; + dv_reg TX6CP; + dv_reg TX7CP; + dv_reg RX0CP; + dv_reg RX1CP; + dv_reg RX2CP; + dv_reg RX3CP; + dv_reg RX4CP; + dv_reg RX5CP; + dv_reg RX6CP; + dv_reg RX7CP; +} emac_regs; + +/* EMAC Wrapper Registers Structure */ +typedef struct { + dv_reg REV; + dv_reg SOFTRESET; + dv_reg INTCONTROL; + dv_reg C0RXTHRESHEN; + dv_reg C0RXEN; + dv_reg C0TXEN; + dv_reg C0MISCEN; + dv_reg C1RXTHRESHEN; + dv_reg C1RXEN; + dv_reg C1TXEN; + dv_reg C1MISCEN; + dv_reg C2RXTHRESHEN; + dv_reg C2RXEN; + dv_reg C2TXEN; + dv_reg C2MISCEN; + dv_reg C0RXTHRESHSTAT; + dv_reg C0RXSTAT; + dv_reg C0TXSTAT; + dv_reg C0MISCSTAT; + dv_reg C1RXTHRESHSTAT; + dv_reg C1RXSTAT; + dv_reg C1TXSTAT; + dv_reg C1MISCSTAT; + dv_reg C2RXTHRESHSTAT; + dv_reg C2RXSTAT; + dv_reg C2TXSTAT; + dv_reg C2MISCSTAT; + dv_reg C0RXIMAX; + dv_reg C0TXIMAX; + dv_reg C1RXIMAX; + dv_reg C1TXIMAX; + dv_reg C2RXIMAX; + dv_reg C2TXIMAX; +} ewrap_regs; + + +/* EMAC MDIO Registers Structure */ +typedef struct { + dv_reg VERSION; + dv_reg CONTROL; + dv_reg ALIVE; + dv_reg LINK; + dv_reg LINKINTRAW; + dv_reg LINKINTMASKED; + u_int8_t RSVD0[8]; + dv_reg USERINTRAW; + dv_reg USERINTMASKED; + dv_reg USERINTMASKSET; + dv_reg USERINTMASKCLEAR; + u_int8_t RSVD1[80]; + dv_reg USERACCESS0; + dv_reg USERPHYSEL0; + dv_reg USERACCESS1; + dv_reg USERPHYSEL1; +} mdio_regs; + +int dm644x_eth_phy_read(u_int8_t phy_addr, u_int8_t reg_num, u_int16_t *data); +int dm644x_eth_phy_write(u_int8_t phy_addr, u_int8_t reg_num, u_int16_t data); + +typedef struct +{ + char name[64]; + int (*init)(int phy_addr); + int (*is_phy_connected)(int phy_addr); + int (*get_link_speed)(int phy_addr); + int (*auto_negotiate)(int phy_addr); +} phy_t; + +#endif /* _DM644X_EMAC_H_ */ diff --git a/include/asm-arm/arch-da8xx/emif_defs.h b/include/asm-arm/arch-da8xx/emif_defs.h new file mode 100644 index 00000000000..646fc774694 --- /dev/null +++ b/include/asm-arm/arch-da8xx/emif_defs.h @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2007 Sergey Kubushyn <ksi@koi8.net> + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ +#ifndef _EMIF_DEFS_H_ +#define _EMIF_DEFS_H_ + +#include <asm/arch/hardware.h> + +typedef struct { + dv_reg ERCSR; + dv_reg AWCCR; + dv_reg SDBCR; + dv_reg SDRCR; + dv_reg AB1CR; + dv_reg AB2CR; + dv_reg AB3CR; + dv_reg AB4CR; + dv_reg SDTIMR; + dv_reg DDRSR; + dv_reg DDRPHYCR; + dv_reg DDRPHYSR; + dv_reg TOTAR; + dv_reg TOTACTR; + dv_reg DDRPHYID_REV; + dv_reg SDSRETR; + dv_reg EIRR; + dv_reg EIMR; + dv_reg EIMSR; + dv_reg EIMCR; + dv_reg IOCTRLR; + dv_reg IOSTATR; + u_int8_t RSVD0[8]; + dv_reg NANDFCR; + dv_reg NANDFSR; + u_int8_t RSVD1[8]; + dv_reg NANDF1ECC; + dv_reg NANDF2ECC; + dv_reg NANDF3ECC; + dv_reg NANDF4ECC; +} emif_registers; + +typedef emif_registers *emifregs; +#endif diff --git a/include/asm-arm/arch-da8xx/hardware.h b/include/asm-arm/arch-da8xx/hardware.h new file mode 100644 index 00000000000..6791c3b21eb --- /dev/null +++ b/include/asm-arm/arch-da8xx/hardware.h @@ -0,0 +1,207 @@ +/* + * Copyright (C) 2008 Sekhar Nori, Texas Instruments, Inc + * + * Based on hardware.h for DaVinci. Original Copyrights follow. + * + * Sergey Kubushyn <ksi@koi8.net> + * Copyright (C) 2007 Sergey Kubushyn <ksi@koi8.net> + * + * Based on: + * + * ------------------------------------------------------------------------- + * + * linux/include/asm-arm/arch-davinci/hardware.h + * + * Copyright (C) 2006 Texas Instruments. + * + * 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 SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN + * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * 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., + * 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ +#ifndef __ASM_ARCH_HARDWARE_H +#define __ASM_ARCH_HARDWARE_H + +#include <config.h> + +#ifndef __ASSEMBLY__ + +#include <asm/sizes.h> + +#define REG(addr) (*(volatile unsigned int *)(addr)) +#define REG_P(addr) ((volatile unsigned int *)(addr)) + +typedef volatile unsigned int dv_reg; +typedef volatile unsigned int * dv_reg_p; + +#endif + +/* + * Base register addresses + */ +#define DAVINCI_UART0_BASE (0x01c42000) +#define DAVINCI_UART1_BASE (0x01d0c000) +#define DAVINCI_UART2_BASE (0x01d0d000) +#define DAVINCI_I2C0_BASE (0x01c22000) +#define DAVINCI_I2C1_BASE (0x01e28000) +#define DAVINCI_TIMER0_BASE (0x01c20000) +#define DAVINCI_TIMER1_BASE (0x01c21000) +#define DAVINCI_WDOG_BASE (0x01c21000) +#define DAVINCI_PLL_CNTRL0_BASE (0x01c11000) +#define DAVINCI_PSC0_BASE (0x01c10000) +#define DAVINCI_PSC1_BASE (0x01e27000) +#define DAVINCI_SPI0_BASE (0x01c41000) +#define DAVINCI_SPI1_BASE (0x01e12000) +#define DAVINCI_GPIO_BASE (0x01e26000) +#define DAVINCI_EMAC_CNTRL_REGS_BASE (0x01e23000) +#define DAVINCI_EMAC_WRAPPER_CNTRL_REGS_BASE (0x01e22000) +#define DAVINCI_EMAC_WRAPPER_RAM_BASE (0x01e20000) +#define DAVINCI_MDIO_CNTRL_REGS_BASE (0x01e24000) +#define DAVINCI_ASYNC_EMIF_CNTRL_BASE (0x68000000) +#define DAVINCI_ASYNC_EMIF_DATA_CE0_BASE (0x40000000) +#define DAVINCI_ASYNC_EMIF_DATA_CE2_BASE (0x60000000) +#define DAVINCI_ASYNC_EMIF_DATA_CE3_BASE (0x62000000) +#define DAVINCI_ASYNC_EMIF_DATA_CE4_BASE (0x64000000) +#define DAVINCI_ASYNC_EMIF_DATA_CE5_BASE (0x66000000) +#define DAVINCI_DDR_EMIF_CTRL_BASE (0xb0000000) +#define DAVINCI_DDR_EMIF_DATA_BASE (0xc0000000) +#define DAVINCI_INTC_BASE (0xfffee000) +#define DAVINCI_BOOTCFG_BASE (0x01c14000) + +/* Clock IDs */ +#define DAVINCI_PLLM_CLKID (0xFF + 0) +#define DAVINCI_PLLC_CLKID (0xFF + 1) +#define DAVINCI_AUXCLK_CLKID (0xFF + 2) +#define DAVINCI_MDIO_CLKID 4 +#define DAVINCI_SPI0_CLKID 2 +#define DAVINCI_UART2_CLKID 2 +#define DAVINCI_ARM_CLKID 6 + +/* Power and Sleep Controller (PSC) Domains */ +#define DAVINCI_GPSC_ARMDOMAIN 0 +#define DAVINCI_GPSC_DSPDOMAIN 1 + +/* LPSCs in PSC0 */ +#define DAVINCI_LPSC_TPCC 0 +#define DAVINCI_LPSC_TPTC0 1 +#define DAVINCI_LPSC_TPTC1 2 +#define DAVINCI_LPSC_AEMIF 3 +#define DAVINCI_LPSC_SPI0 4 +#define DAVINCI_LPSC_MMC_SD 5 +#define DAVINCI_LPSC_AINTC 6 +#define DAVINCI_LPSC_ARM_RAM_ROM 7 +#define DAVINCI_LPSC_SECCTL_KEYMGR 8 +#define DAVINCI_LPSC_UART0 9 +#define DAVINCI_LPSC_SCR0 10 +#define DAVINCI_LPSC_SCR1 11 +#define DAVINCI_LPSC_SCR2 12 +#define DAVINCI_LPSC_DMAX 13 +#define DAVINCI_LPSC_ARM 14 +#define DAVINCI_LPSC_GEM 15 + +/* for LPSCs in PSC1, 32 + actual id is being used for differentiation */ +#define DAVINCI_LPSC_USB11 (32 + 1) +#define DAVINCI_LPSC_USB20 (32 + 2) +#define DAVINCI_LPSC_GPIO (32 + 3) +#define DAVINCI_LPSC_UHPI (32 + 4) +#define DAVINCI_LPSC_EMAC (32 + 5) +#define DAVINCI_LPSC_DDR_EMIF (32 + 6) +#define DAVINCI_LPSC_McASP0 (32 + 7) +#define DAVINCI_LPSC_McASP1 (32 + 8) +#define DAVINCI_LPSC_McASP2 (32 + 9) +#define DAVINCI_LPSC_SPI1 (32 + 10) +#define DAVINCI_LPSC_I2C1 (32 + 11) +#define DAVINCI_LPSC_UART1 (32 + 12) +#define DAVINCI_LPSC_UART2 (32 + 13) +#define DAVINCI_LPSC_LCDC (32 + 16) +#define DAVINCI_LPSC_ePWM (32 + 17) +#define DAVINCI_LPSC_eCAP (32 + 20) +#define DAVINCI_LPSC_eQEP (32 + 21) +#define DAVINCI_LPSC_SCR_P0 (32 + 22) +#define DAVINCI_LPSC_SCR_P1 (32 + 23) +#define DAVINCI_LPSC_CR_P3 (32 + 26) +#define DAVINCI_LPSC_L3_CBA_RAM (32 + 31) + +/* Some PSC defines */ + +#define PSC0_MDCTL (DAVINCI_PSC0_BASE + 0xa00) +#define PSC0_MDSTAT (DAVINCI_PSC0_BASE + 0x800) +#define PSC0_PTCMD (DAVINCI_PSC0_BASE + 0x120) +#define PSC0_PTSTAT (DAVINCI_PSC0_BASE + 0x128) + +#define PSC1_MDCTL (DAVINCI_PSC1_BASE + 0xa00) +#define PSC1_MDSTAT (DAVINCI_PSC1_BASE + 0x800) +#define PSC1_PTCMD (DAVINCI_PSC1_BASE + 0x120) +#define PSC1_PTSTAT (DAVINCI_PSC1_BASE + 0x128) + +/* Some PLL defines */ +#define PLL0_PLLCTL (DAVINCI_PLL_CNTRL0_BASE + 0x100) +#define PLL0_PLLM (DAVINCI_PLL_CNTRL0_BASE + 0x110) +#define PLL0_PREDIV (DAVINCI_PLL_CNTRL0_BASE + 0x114) +#define PLL0_POSTDIV (DAVINCI_PLL_CNTRL0_BASE + 0x128) +#define PLL0_DIV1 (DAVINCI_PLL_CNTRL0_BASE + 0x118) +#define PLL0_DIV2 (DAVINCI_PLL_CNTRL0_BASE + 0x11c) +#define PLL0_DIV3 (DAVINCI_PLL_CNTRL0_BASE + 0x120) +#define PLL0_DIV4 (DAVINCI_PLL_CNTRL0_BASE + 0x160) +#define PLL0_DIV5 (DAVINCI_PLL_CNTRL0_BASE + 0x164) +#define PLL0_DIV6 (DAVINCI_PLL_CNTRL0_BASE + 0x168) +#define PLL0_DIV7 (DAVINCI_PLL_CNTRL0_BASE + 0x16c) +#define PLL0_DIV8 (DAVINCI_PLL_CNTRL0_BASE + 0x170) +#define PLL0_DIV9 (DAVINCI_PLL_CNTRL0_BASE + 0x114) + +/* Boot config */ +#define KICK0 (DAVINCI_BOOTCFG_BASE + 0x38) +#define KICK1 (DAVINCI_BOOTCFG_BASE + 0x3c) +#define PINMUX0 (DAVINCI_BOOTCFG_BASE + 0x120) +#define PINMUX1 (DAVINCI_BOOTCFG_BASE + 0x124) +#define PINMUX2 (DAVINCI_BOOTCFG_BASE + 0x128) +#define PINMUX3 (DAVINCI_BOOTCFG_BASE + 0x12c) +#define PINMUX4 (DAVINCI_BOOTCFG_BASE + 0x130) +#define PINMUX5 (DAVINCI_BOOTCFG_BASE + 0x134) +#define PINMUX6 (DAVINCI_BOOTCFG_BASE + 0x138) +#define PINMUX7 (DAVINCI_BOOTCFG_BASE + 0x13c) +#define PINMUX8 (DAVINCI_BOOTCFG_BASE + 0x140) +#define PINMUX9 (DAVINCI_BOOTCFG_BASE + 0x144) +#define PINMUX10 (DAVINCI_BOOTCFG_BASE + 0x148) +#define PINMUX11 (DAVINCI_BOOTCFG_BASE + 0x14c) +#define PINMUX12 (DAVINCI_BOOTCFG_BASE + 0x150) +#define PINMUX13 (DAVINCI_BOOTCFG_BASE + 0x154) +#define PINMUX14 (DAVINCI_BOOTCFG_BASE + 0x158) +#define PINMUX15 (DAVINCI_BOOTCFG_BASE + 0x15C) +#define PINMUX16 (DAVINCI_BOOTCFG_BASE + 0x160) +#define PINMUX17 (DAVINCI_BOOTCFG_BASE + 0x164) +#define PINMUX18 (DAVINCI_BOOTCFG_BASE + 0x168) +#define PINMUX19 (DAVINCI_BOOTCFG_BASE + 0x16c) +#define SUSPSRC (DAVINCI_BOOTCFG_BASE + 0x170) +#define CFGCHIP0 (DAVINCI_BOOTCFG_BASE + 0x17c) +#define CFGCHIP2 (DAVINCI_BOOTCFG_BASE + 0x184) + +/* Interrupt controller */ +#define INTC_GLB_EN (DAVINCI_INTC_BASE + 0x10) +#define INTC_HINT_EN (DAVINCI_INTC_BASE + 0x1500) +#define INTC_EN_CLR0 (DAVINCI_INTC_BASE + 0x380) + +/* GPIO */ +#define GPIO_BANK4_ADDR 0x01E26000 +#define GPIO_BANK4_REG_DIR_ADDR ( GPIO_BANK4_ADDR + 0x60 ) +#define GPIO_BANK4_REG_OPDATA_ADDR ( GPIO_BANK4_ADDR + 0x64 ) +#define GPIO_BANK4_REG_SET_ADDR ( GPIO_BANK4_ADDR + 0x68 ) +#define GPIO_BANK4_REG_CLR_ADDR ( GPIO_BANK4_ADDR + 0x6C ) + +#endif /* __ASM_ARCH_HARDWARE_H */ diff --git a/include/asm-arm/arch-da8xx/i2c_defs.h b/include/asm-arm/arch-da8xx/i2c_defs.h new file mode 100644 index 00000000000..714211fca5e --- /dev/null +++ b/include/asm-arm/arch-da8xx/i2c_defs.h @@ -0,0 +1,95 @@ +/* + * (C) Copyright 2004 + * Texas Instruments, <www.ti.com> + * + * Some changes copyright (C) 2007 Sergey Kubushyn <ksi@koi8.net> + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ +#ifndef _DAVINCI_I2C_H_ +#define _DAVINCI_I2C_H_ + +#define I2C_WRITE 0 +#define I2C_READ 1 + +#define I2C_BASE 0x01c22000 + +#define I2C_OA (I2C_BASE + 0x00) +#define I2C_IE (I2C_BASE + 0x04) +#define I2C_STAT (I2C_BASE + 0x08) +#define I2C_SCLL (I2C_BASE + 0x0c) +#define I2C_SCLH (I2C_BASE + 0x10) +#define I2C_CNT (I2C_BASE + 0x14) +#define I2C_DRR (I2C_BASE + 0x18) +#define I2C_SA (I2C_BASE + 0x1c) +#define I2C_DXR (I2C_BASE + 0x20) +#define I2C_CON (I2C_BASE + 0x24) +#define I2C_IV (I2C_BASE + 0x28) +#define I2C_PSC (I2C_BASE + 0x30) + +/* I2C masks */ + +/* I2C Interrupt Enable Register (I2C_IE): */ +#define I2C_IE_SCD_IE (1 << 5) /* Stop condition detect interrupt enable */ +#define I2C_IE_XRDY_IE (1 << 4) /* Transmit data ready interrupt enable */ +#define I2C_IE_RRDY_IE (1 << 3) /* Receive data ready interrupt enable */ +#define I2C_IE_ARDY_IE (1 << 2) /* Register access ready interrupt enable */ +#define I2C_IE_NACK_IE (1 << 1) /* No acknowledgment interrupt enable */ +#define I2C_IE_AL_IE (1 << 0) /* Arbitration lost interrupt enable */ + +/* I2C Status Register (I2C_STAT): */ + +#define I2C_STAT_BB (1 << 12) /* Bus busy */ +#define I2C_STAT_ROVR (1 << 11) /* Receive overrun */ +#define I2C_STAT_XUDF (1 << 10) /* Transmit underflow */ +#define I2C_STAT_AAS (1 << 9) /* Address as slave */ +#define I2C_STAT_SCD (1 << 5) /* Stop condition detect */ +#define I2C_STAT_XRDY (1 << 4) /* Transmit data ready */ +#define I2C_STAT_RRDY (1 << 3) /* Receive data ready */ +#define I2C_STAT_ARDY (1 << 2) /* Register access ready */ +#define I2C_STAT_NACK (1 << 1) /* No acknowledgment interrupt enable */ +#define I2C_STAT_AL (1 << 0) /* Arbitration lost interrupt enable */ + + +/* I2C Interrupt Code Register (I2C_INTCODE): */ + +#define I2C_INTCODE_MASK 7 +#define I2C_INTCODE_NONE 0 +#define I2C_INTCODE_AL 1 /* Arbitration lost */ +#define I2C_INTCODE_NAK 2 /* No acknowledgement/general call */ +#define I2C_INTCODE_ARDY 3 /* Register access ready */ +#define I2C_INTCODE_RRDY 4 /* Rcv data ready */ +#define I2C_INTCODE_XRDY 5 /* Xmit data ready */ +#define I2C_INTCODE_SCD 6 /* Stop condition detect */ + + +/* I2C Configuration Register (I2C_CON): */ + +#define I2C_CON_EN (1 << 5) /* I2C module enable */ +#define I2C_CON_STB (1 << 4) /* Start byte mode (master mode only) */ +#define I2C_CON_MST (1 << 10) /* Master/slave mode */ +#define I2C_CON_TRX (1 << 9) /* Transmitter/receiver mode (master mode only) */ +#define I2C_CON_XA (1 << 8) /* Expand address */ +#define I2C_CON_STP (1 << 11) /* Stop condition (master mode only) */ +#define I2C_CON_STT (1 << 13) /* Start condition (master mode only) */ +#define I2C_CON_FREE (1 << 14) /* Free run on emulation */ + +#define I2C_TIMEOUT 0xffff0000 /* Timeout mask for poll_i2c_irq() */ + +#endif diff --git a/include/asm-arm/arch-da8xx/nand_defs.h b/include/asm-arm/arch-da8xx/nand_defs.h new file mode 100644 index 00000000000..5084bb7f34c --- /dev/null +++ b/include/asm-arm/arch-da8xx/nand_defs.h @@ -0,0 +1,164 @@ +/* + * Copyright (C) 2007 Sergey Kubushyn <ksi@koi8.net> + * + * Parts shamelesly stolen from Linux Kernel source tree. + * + * ------------------------------------------------------------ + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ +#ifndef _NAND_DEFS_H_ +#define _NAND_DEFS_H_ + +#include <asm/arch/hardware.h> + +#define MASK_CLE 0x10 +//#define MASK_ALE 0x0a +#define MASK_ALE 0x08 + + +#define NAND_CE0CLE ((volatile u_int8_t *)(CFG_NAND_BASE + 0x10)) +//#define NAND_CE0ALE ((volatile u_int8_t *)(CFG_NAND_BASE + 0x0a)) +#define NAND_CE0ALE ((volatile u_int8_t *)(CFG_NAND_BASE + 0x08)) +#define NAND_CE0DATA ((volatile u_int8_t *)CFG_NAND_BASE) + +typedef struct { + u_int32_t NRCSR; + u_int32_t AWCCR; + u_int8_t RSVD0[8]; + u_int32_t AB1CR; + u_int32_t AB2CR; + u_int32_t AB3CR; + u_int32_t AB4CR; + u_int8_t RSVD1[32]; + u_int32_t NIRR; + u_int32_t NIMR; + u_int32_t NIMSR; + u_int32_t NIMCR; + u_int8_t RSVD2[16]; + u_int32_t NANDFCR; + u_int32_t NANDFSR; + u_int8_t RSVD3[8]; + u_int32_t NANDF1ECC; + u_int32_t NANDF2ECC; + u_int32_t NANDF3ECC; + u_int32_t NANDF4ECC; + u_int8_t RSVD4[4]; + u_int32_t IODFTECR; + u_int32_t IODFTGCR; + u_int8_t RSVD5[4]; + u_int32_t IODFTMRLR; + u_int32_t IODFTMRMR; + u_int32_t IODFTMRMSBR; + u_int8_t RSVD6[20]; + u_int32_t MODRNR; + u_int8_t RSVD7[76]; + u_int32_t CE0DATA; + u_int32_t CE0ALE; + u_int32_t CE0CLE; + u_int8_t RSVD8[4]; + u_int32_t CE1DATA; + u_int32_t CE1ALE; + u_int32_t CE1CLE; + u_int8_t RSVD9[4]; + u_int32_t CE2DATA; + u_int32_t CE2ALE; + u_int32_t CE2CLE; + u_int8_t RSVD10[4]; + u_int32_t CE3DATA; + u_int32_t CE3ALE; + u_int32_t CE3CLE; +} nand_registers; + +typedef volatile nand_registers *nandregs; + +#define NAND_READ_START 0x00 +#define NAND_READ_END 0x30 +#define NAND_STATUS 0x70 + +#ifdef CFG_NAND_HW_ECC +#define NAND_Ecc_P1e (1 << 0) +#define NAND_Ecc_P2e (1 << 1) +#define NAND_Ecc_P4e (1 << 2) +#define NAND_Ecc_P8e (1 << 3) +#define NAND_Ecc_P16e (1 << 4) +#define NAND_Ecc_P32e (1 << 5) +#define NAND_Ecc_P64e (1 << 6) +#define NAND_Ecc_P128e (1 << 7) +#define NAND_Ecc_P256e (1 << 8) +#define NAND_Ecc_P512e (1 << 9) +#define NAND_Ecc_P1024e (1 << 10) +#define NAND_Ecc_P2048e (1 << 11) + +#define NAND_Ecc_P1o (1 << 16) +#define NAND_Ecc_P2o (1 << 17) +#define NAND_Ecc_P4o (1 << 18) +#define NAND_Ecc_P8o (1 << 19) +#define NAND_Ecc_P16o (1 << 20) +#define NAND_Ecc_P32o (1 << 21) +#define NAND_Ecc_P64o (1 << 22) +#define NAND_Ecc_P128o (1 << 23) +#define NAND_Ecc_P256o (1 << 24) +#define NAND_Ecc_P512o (1 << 25) +#define NAND_Ecc_P1024o (1 << 26) +#define NAND_Ecc_P2048o (1 << 27) + +#define TF(v) (v ? 1 : 0) + +#define P2048e(a) (TF(a & NAND_Ecc_P2048e) << 0) +#define P2048o(a) (TF(a & NAND_Ecc_P2048o) << 1) +#define P1e(a) (TF(a & NAND_Ecc_P1e) << 2) +#define P1o(a) (TF(a & NAND_Ecc_P1o) << 3) +#define P2e(a) (TF(a & NAND_Ecc_P2e) << 4) +#define P2o(a) (TF(a & NAND_Ecc_P2o) << 5) +#define P4e(a) (TF(a & NAND_Ecc_P4e) << 6) +#define P4o(a) (TF(a & NAND_Ecc_P4o) << 7) + +#define P8e(a) (TF(a & NAND_Ecc_P8e) << 0) +#define P8o(a) (TF(a & NAND_Ecc_P8o) << 1) +#define P16e(a) (TF(a & NAND_Ecc_P16e) << 2) +#define P16o(a) (TF(a & NAND_Ecc_P16o) << 3) +#define P32e(a) (TF(a & NAND_Ecc_P32e) << 4) +#define P32o(a) (TF(a & NAND_Ecc_P32o) << 5) +#define P64e(a) (TF(a & NAND_Ecc_P64e) << 6) +#define P64o(a) (TF(a & NAND_Ecc_P64o) << 7) + +#define P128e(a) (TF(a & NAND_Ecc_P128e) << 0) +#define P128o(a) (TF(a & NAND_Ecc_P128o) << 1) +#define P256e(a) (TF(a & NAND_Ecc_P256e) << 2) +#define P256o(a) (TF(a & NAND_Ecc_P256o) << 3) +#define P512e(a) (TF(a & NAND_Ecc_P512e) << 4) +#define P512o(a) (TF(a & NAND_Ecc_P512o) << 5) +#define P1024e(a) (TF(a & NAND_Ecc_P1024e) << 6) +#define P1024o(a) (TF(a & NAND_Ecc_P1024o) << 7) + +#define P8e_s(a) (TF(a & NAND_Ecc_P8e) << 0) +#define P8o_s(a) (TF(a & NAND_Ecc_P8o) << 1) +#define P16e_s(a) (TF(a & NAND_Ecc_P16e) << 2) +#define P16o_s(a) (TF(a & NAND_Ecc_P16o) << 3) +#define P1e_s(a) (TF(a & NAND_Ecc_P1e) << 4) +#define P1o_s(a) (TF(a & NAND_Ecc_P1o) << 5) +#define P2e_s(a) (TF(a & NAND_Ecc_P2e) << 6) +#define P2o_s(a) (TF(a & NAND_Ecc_P2o) << 7) + +#define P4e_s(a) (TF(a & NAND_Ecc_P4e) << 0) +#define P4o_s(a) (TF(a & NAND_Ecc_P4o) << 1) +#endif + +#endif diff --git a/include/asm-avr32/arch-at32ap700x/chip-features.h b/include/asm-avr32/arch-at32ap700x/chip-features.h index 29b1fd663d0..c47107e2a64 100644 --- a/include/asm-avr32/arch-at32ap700x/chip-features.h +++ b/include/asm-avr32/arch-at32ap700x/chip-features.h @@ -25,6 +25,7 @@ /* Currently, all the AP700x chips have these */ #define AT32AP700x_CHIP_HAS_USART #define AT32AP700x_CHIP_HAS_MMCI +#define AT32AP700x_CHIP_HAS_SPI /* Only AP7000 has ethernet interface */ #ifdef CONFIG_AT32AP7000 diff --git a/include/asm-avr32/arch-at32ap700x/clk.h b/include/asm-avr32/arch-at32ap700x/clk.h index 385319aac75..bd6f2e5c7bd 100644 --- a/include/asm-avr32/arch-at32ap700x/clk.h +++ b/include/asm-avr32/arch-at32ap700x/clk.h @@ -74,6 +74,12 @@ static inline unsigned long get_mci_clk_rate(void) return get_pbb_clk_rate(); } #endif +#ifdef AT32AP700x_CHIP_HAS_SPI +static inline unsigned long get_spi_clk_rate(unsigned int dev_id) +{ + return get_pba_clk_rate(); +} +#endif /* Board code may need the SDRAM base clock as a compile-time constant */ #define SDRAMC_BUS_HZ (MAIN_CLK_RATE >> CFG_CLKDIV_HSB) diff --git a/include/asm-avr32/arch-at32ap700x/gpio.h b/include/asm-avr32/arch-at32ap700x/gpio.h index b10a3e4f868..ef20ceaab7c 100644 --- a/include/asm-avr32/arch-at32ap700x/gpio.h +++ b/include/asm-avr32/arch-at32ap700x/gpio.h @@ -216,5 +216,9 @@ void gpio_enable_macb1(void); #ifdef AT32AP700x_CHIP_HAS_MMCI void gpio_enable_mmci(void); #endif +#ifdef AT32AP700x_CHIP_HAS_SPI +void gpio_enable_spi0(unsigned long cs_mask); +void gpio_enable_spi1(unsigned long cs_mask); +#endif #endif /* __ASM_AVR32_ARCH_GPIO_H__ */ diff --git a/include/asm-avr32/u-boot.h b/include/asm-avr32/u-boot.h index 71dfcaf2840..85ef008b727 100644 --- a/include/asm-avr32/u-boot.h +++ b/include/asm-avr32/u-boot.h @@ -42,15 +42,4 @@ typedef struct bd_info { #define bi_memstart bi_dram[0].start #define bi_memsize bi_dram[0].size -/** - * container_of - cast a member of a structure out to the containing structure - * - * @ptr: the pointer to the member. - * @type: the type of the container struct this is embedded in. - * @member: the name of the member within the struct. - */ -#define container_of(ptr, type, member) ({ \ - const typeof( ((type *)0)->member ) *__mptr = (ptr); \ - (type *)( (char *)__mptr - offsetof(type,member) );}) - #endif /* __ASM_U_BOOT_H__ */ diff --git a/include/common.h b/include/common.h index d0f57040ee4..bfd18fe8961 100644 --- a/include/common.h +++ b/include/common.h @@ -106,6 +106,9 @@ typedef volatile unsigned char vu_char; #ifdef CONFIG_BLACKFIN #include <asm/blackfin.h> #endif +#ifdef CONFIG_DA8XX +#include <asm/arch/hardware.h> +#endif #include <part.h> #include <flash.h> @@ -176,6 +179,17 @@ typedef void (interrupt_handler_t)(void *); (__x > __y) ? __x : __y; }) +/** + * container_of - cast a member of a structure out to the containing structure + * @ptr: the pointer to the member. + * @type: the type of the container struct this is embedded in. + * @member: the name of the member within the struct. + * + */ +#define container_of(ptr, type, member) ({ \ + const typeof( ((type *)0)->member ) *__mptr = (ptr); \ + (type *)( (char *)__mptr - offsetof(type,member) );}) + /* * Function Prototypes */ diff --git a/include/configs/da8xx_evm.h b/include/configs/da8xx_evm.h new file mode 100644 index 00000000000..f093710a220 --- /dev/null +++ b/include/configs/da8xx_evm.h @@ -0,0 +1,232 @@ +/* + * Copyright (C) 2008 Texas Instruments, Inc <www.ti.com> + * + * Based on davinci_dvevm.h. Original Copyrights follow: + * + * Copyright (C) 2007 Sergey Kubushyn <ksi@koi8.net> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#ifndef __CONFIG_H +#define __CONFIG_H +#include <asm/sizes.h> + +/*=======*/ +/* Board */ +/*=======*/ +#define CFG_USE_SPIFLASH + +/*===================*/ +/* SoC Configuration */ +/*===================*/ +#define CONFIG_ARM926EJS /* arm926ejs CPU core */ +#define CONFIG_DA8XX /* TI DA8xx SoC */ +#define CONFIG_SYS_CLK_FREQ clk_get(DAVINCI_ARM_CLKID) /* Arm Clock */ +#define CFG_OSCIN_FREQ 24000000 +#define CFG_TIMERBASE DAVINCI_TIMER0_BASE /* use timer 0 */ +#define CFG_HZ_CLOCK clk_get(DAVINCI_AUXCLK_CLKID) /* Timer Input clock freq */ +#define CFG_HZ 1000 +#undef CONFIG_SKIP_LOWLEVEL_INIT /* U-Boot is _always_ loaded by a bootloader */ +#define CONFIG_SKIP_RELOCATE_UBOOT /* to a proper address, init done */ + +/*=============*/ +/* Memory Info */ +/*=============*/ +#define CFG_MALLOC_LEN (0x10000 + 1*1024*1024) /* malloc() len */ +#define CFG_GBL_DATA_SIZE 128 /* reserved for initial data */ +#define PHYS_SDRAM_1 DAVINCI_DDR_EMIF_DATA_BASE /* DDR Start */ +#define PHYS_SDRAM_1_SIZE 0x04000000 /* SDRAM size 64MB */ +#define CFG_MEMTEST_START PHYS_SDRAM_1 /* memtest start address */ +#define CFG_MEMTEST_END (PHYS_SDRAM_1 + 16*1024*1024) /* 16MB RAM test */ +#define CONFIG_NR_DRAM_BANKS 1 /* we have 1 bank of DRAM */ +#define CONFIG_STACKSIZE (256*1024) /* regular stack */ +#define SDRAM_4BANKS_10COLS /* TODO: Update this! */ + +/*====================*/ +/* Serial Driver info */ +/*====================*/ +#define CFG_NS16550 +#define CFG_NS16550_SERIAL +#define CFG_NS16550_REG_SIZE 4 /* NS16550 register size */ +#define CFG_NS16550_COM1 DAVINCI_UART2_BASE /* Base address of UART2 */ +#define CFG_NS16550_CLK clk_get(DAVINCI_UART2_CLKID) /* Input clock to NS16550 */ +#define CONFIG_CONS_INDEX 1 /* use UART0 for console */ +#define CONFIG_BAUDRATE 115200 /* Default baud rate */ +#define CFG_BAUDRATE_TABLE { 9600, 19200, 38400, 57600, 115200 } + +/*===================*/ +/* I2C Configuration */ +/*===================*/ +#define CONFIG_HARD_I2C +#define CONFIG_DRIVER_DAVINCI_I2C +#define CFG_I2C_SPEED 25000 /* 100Kbps won't work, silicon bug */ +#define CFG_I2C_SLAVE 10 /* Bogus, master-only in U-Boot */ + +/*====================================================*/ +/* I2C EEPROM definitions for catalyst 24W256 EEPROM chip */ +/*====================================================*/ +#define CFG_I2C_EEPROM_ADDR_LEN 2 +#define CFG_I2C_EEPROM_ADDR 0x50 +#define CFG_EEPROM_PAGE_WRITE_BITS 6 +#define CFG_EEPROM_PAGE_WRITE_DELAY_MS 20 + +/*==================================*/ +/* Network & Ethernet Configuration */ +/*==================================*/ +#define CONFIG_DRIVER_TI_EMAC +#define CONFIG_MII +#define CONFIG_BOOTP_DEFAULT +#define CONFIG_BOOTP_DNS +#define CONFIG_BOOTP_DNS2 +#define CONFIG_BOOTP_SEND_HOSTNAME +#define CONFIG_NET_RETRY_COUNT 10 + +/*=====================*/ +/* Flash & Environment */ +/*=====================*/ +#ifdef CFG_USE_NAND +#undef CFG_ENV_IS_IN_FLASH +#define CFG_NO_FLASH +#define CFG_ENV_IS_IN_NAND /* U-Boot env in NAND Flash */ +#define CFG_ENV_SIZE SZ_128K +#define CFG_NAND_1BIT_ECC +#define CFG_NAND_CS 3 +#define CFG_NAND_BASE DAVINCI_ASYNC_EMIF_DATA_CE3_BASE +#define CFG_CLE_MASK 0x10 +#define CFG_ALE_MASK 0x8 +#define CFG_NAND_HW_ECC +#define CFG_MAX_NAND_DEVICE 1 /* Max number of NAND devices */ +#define NAND_MAX_CHIPS 1 +#define CFG_ENV_OFFSET 0x0 /* Block 0--not used by bootcode */ +#define DEF_BOOTM "" +#endif + +#ifdef CFG_USE_NOR +#define CFG_ENV_IS_IN_FLASH +#undef CFG_NO_FLASH +#define CFG_FLASH_CFI_DRIVER +#define CFG_FLASH_CFI +#define CFG_MAX_FLASH_BANKS 1 /* max number of flash banks */ +#define CFG_FLASH_SECT_SZ 0x10000 /* 64KB sect size AMD Flash */ +#define CFG_ENV_OFFSET (CFG_FLASH_SECT_SZ*3) +#define CFG_FLASH_BASE DAVINCI_ASYNC_EMIF_DATA_CE2_BASE +#define PHYS_FLASH_SIZE 0x2000000 /* Flash size 32MB */ +#define CFG_MAX_FLASH_SECT (PHYS_FLASH_SIZE/CFG_FLASH_SECT_SZ) +#define CFG_ENV_SECT_SIZE CFG_FLASH_SECT_SZ /* Env sector Size */ +#define CFG_FLASH_SPL_ACCESS +#endif + +#ifdef CFG_USE_SPIFLASH +#undef CFG_ENV_IS_IN_FLASH +#undef CFG_ENV_IS_IN_NAND +#define CFG_ENV_IS_IN_SPI_FLASH +#define CFG_ENV_SIZE SZ_16K +#define CFG_ENV_OFFSET SZ_256K +#define CFG_NO_FLASH +#define CONFIG_SPI +#define CONFIG_SPI_FLASH +#define CONFIG_SPI_FLASH_WINBOND +#define CONFIG_DAVINCI_SPI +#define CFG_SPI_BASE DAVINCI_SPI0_BASE +#define CFG_SPI_CLK clk_get(DAVINCI_SPI0_CLKID) +#define CONFIG_SF_DEFAULT_SPEED 50000000 +#define CFG_ENV_SPI_MAX_HZ CONFIG_SF_DEFAULT_SPEED +#endif + + +/*==============================*/ +/* U-Boot general configuration */ +/*==============================*/ +#undef CONFIG_USE_IRQ /* No IRQ/FIQ in U-Boot */ +#define CONFIG_MISC_INIT_R +#undef CONFIG_BOOTDELAY +#define CONFIG_BOOTFILE "uImage" /* Boot file name */ +#define CFG_PROMPT "U-Boot > " /* Monitor Command Prompt */ +#define CFG_CBSIZE 1024 /* Console I/O Buffer Size */ +#define CFG_PBSIZE (CFG_CBSIZE+sizeof(CFG_PROMPT)+16) /* Print buffer sz */ +#define CFG_MAXARGS 16 /* max number of command args */ +#define CFG_BARGSIZE CFG_CBSIZE /* Boot Argument Buffer Size */ +#define CFG_LOAD_ADDR (CFG_MEMTEST_START + 0x700000) /* default Linux kernel load address */ +#define CONFIG_VERSION_VARIABLE +#define CONFIG_AUTO_COMPLETE /* Won't work with hush so far, may be later */ +#define CFG_HUSH_PARSER +#define CFG_PROMPT_HUSH_PS2 "> " +#define CONFIG_CMDLINE_EDITING +#define CFG_LONGHELP +#define CONFIG_CRC32_VERIFY +#define CONFIG_MX_CYCLIC +#define CONFIG_MUSB /* Enable Mentor USB support */ +#define CONFIG_USB_DA8XX +#define CONFIG_USB_STORAGE +#define CONFIG_USE_PINMUX + +/*===================*/ +/* Linux Information */ +/*===================*/ +#define LINUX_BOOT_PARAM_ADDR (CFG_MEMTEST_START + 0x100) +#define CONFIG_CMDLINE_TAG +#define CONFIG_SETUP_MEMORY_TAGS +#define CONFIG_BOOTARGS "mem=32M console=ttyS2,115200n8 root=/dev/mtdblock/2 rw noinitrd ip=dhcp" +#define CONFIG_BOOTCOMMAND "" +#define CONFIG_BOOTDELAY 3 + +/*=================*/ +/* U-Boot commands */ +/*=================*/ +#include <config_cmd_default.h> +#define CONFIG_CMD_ENV +#define CONFIG_CMD_ASKENV +#define CONFIG_CMD_DHCP +#define CONFIG_CMD_DIAG +#define CONFIG_CMD_MII +#define CONFIG_CMD_PING +#define CONFIG_CMD_SAVES +#define CONFIG_CMD_MEMORY +#undef CONFIG_CMD_BDI +#undef CONFIG_CMD_FPGA +#undef CONFIG_CMD_SETGETDCR +#define CONFIG_CMD_EEPROM + +#ifdef CFG_USE_NAND +#undef CONFIG_CMD_FLASH +#undef CONFIG_CMD_IMLS +#define CONFIG_CMD_NAND +#endif + +#ifdef CFG_USE_SPIFLASH +#undef CONFIG_CMD_IMLS +#undef CONFIG_CMD_FLASH +#define CONFIG_CMD_SF +#endif + +#if !defined(CFG_USE_NAND) && !defined(CFG_USE_NOR) && !defined(CFG_USE_SPIFLASH) +#define CFG_ENV_IS_NOWHERE +#define CFG_NO_FLASH +#define CFG_ENV_SIZE SZ_16K +#undef CONFIG_CMD_IMLS +#undef CONFIG_CMD_FLASH +#undef CONFIG_CMD_ENV +#endif + +#ifdef CONFIG_USB_DA8XX +#define CONFIG_CMD_USB /* inclue support for usb */ +#define CONFIG_CMD_STORAGE /* inclue support for usb */ +#define CONFIG_CMD_FAT /* inclue support for FAT/storage*/ +#define CONFIG_DOS_PARTITION /* inclue support for FAT/storage*/ +#endif + +#endif /* __CONFIG_H */ diff --git a/include/configs/imx31_litekit.h b/include/configs/imx31_litekit.h index 4281d73c90b..ec4ed1eeb67 100644 --- a/include/configs/imx31_litekit.h +++ b/include/configs/imx31_litekit.h @@ -65,7 +65,8 @@ #define CONFIG_HARD_SPI 1 #define CONFIG_MXC_SPI 1 -#define CONFIG_MXC_SPI_IFACE 1 +#define CONFIG_DEFAULT_SPI_BUS 1 +#define CONFIG_DEFAULT_SPI_MODE (SPI_MODE_2 | SPI_CS_HIGH) #define CONFIG_RTC_MC13783 1 diff --git a/include/configs/mx31ads.h b/include/configs/mx31ads.h index 2ea48a6da9a..37ba872a439 100644 --- a/include/configs/mx31ads.h +++ b/include/configs/mx31ads.h @@ -62,7 +62,8 @@ #define CONFIG_HARD_SPI 1 #define CONFIG_MXC_SPI 1 -#define CONFIG_MXC_SPI_IFACE 1 /* Default SPI interface number */ +#define CONFIG_DEFAULT_SPI_BUS 1 +#define CONFIG_DEFAULT_SPI_MODE (SPI_MODE_2 | SPI_CS_HIGH) #define CONFIG_RTC_MC13783 1 diff --git a/include/flash.h b/include/flash.h index 2ed1e20fd22..bd92e59ef54 100644 --- a/include/flash.h +++ b/include/flash.h @@ -26,7 +26,7 @@ #ifndef CFG_NO_FLASH /*----------------------------------------------------------------------- - * FLASH Info: contains chip specific data, per FLASH bank + * FLASH Info: contains chip/board specific data, per FLASH bank */ typedef struct { @@ -56,8 +56,21 @@ typedef struct { ulong addr_unlock2; /* unlock address 2 for AMD flash roms */ const char *name; /* human-readable name */ #endif + + /* board specific write routines */ + void (*write8)(u8 value, void *addr); + void (*write16)(u16 value, void *addr); + void (*write32)(u32 value, void *addr); + void (*write64)(u64 value, void *addr); + + /* board specific read routines */ + u8 (*read8)(void *addr); + u16 (*read16)(void *addr); + u32 (*read32)(void *addr); + u64 (*read64)(void *addr); } flash_info_t; + /* * Values for the width of the port */ diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h index 4cc4a7d1bb4..79d670d349d 100644 --- a/include/linux/mtd/nand.h +++ b/include/linux/mtd/nand.h @@ -109,6 +109,26 @@ extern int nand_read_raw (struct mtd_info *mtd, uint8_t *buf, loff_t from, size_ /* Extended commands for large page devices */ #define NAND_CMD_READSTART 0x30 #define NAND_CMD_CACHEDPROG 0x15 +/* Extended commands for AG-AND device */ +/* + * Note: the command for NAND_CMD_DEPLETE1 is really 0x00 but + * there is no way to distinguish that from NAND_CMD_READ0 + * until the remaining sequence of commands has been completed + * so add a high order bit and mask it off in the command. + */ +#define NAND_CMD_DEPLETE1 0x100 +#define NAND_CMD_DEPLETE2 0x38 +#define NAND_CMD_STATUS_MULTI 0x71 +#define NAND_CMD_STATUS_ERROR 0x72 +/* multi-bank error status (banks 0-3) */ +#define NAND_CMD_STATUS_ERROR0 0x73 +#define NAND_CMD_STATUS_ERROR1 0x74 +#define NAND_CMD_STATUS_ERROR2 0x75 +#define NAND_CMD_STATUS_ERROR3 0x76 +#define NAND_CMD_STATUS_RESET 0x7f +#define NAND_CMD_STATUS_CLEAR 0xff + + /* Status bits */ #define NAND_STATUS_FAIL 0x01 @@ -135,6 +155,18 @@ extern int nand_read_raw (struct mtd_info *mtd, uint8_t *buf, loff_t from, size_ #define NAND_ECC_HW8_512 6 /* Hardware ECC 12 byte ECC per 2048 Byte data */ #define NAND_ECC_HW12_2048 7 +/* Hardware ECC 10 byte ECC per 512 Byte data */ +#define NAND_ECC_HW10_512 8 + +struct page_layout_item { + int length; + enum { + ITEM_TYPE_DATA, + ITEM_TYPE_OOB, + ITEM_TYPE_ECC, + } type; +}; + /* * Constants for Hardware ECC @@ -145,6 +177,14 @@ extern int nand_read_raw (struct mtd_info *mtd, uint8_t *buf, loff_t from, size_ #define NAND_ECC_WRITE 1 /* Enable Hardware ECC before syndrom is read back from flash */ #define NAND_ECC_READSYN 2 +#define NAND_ECC_WRITESYN 3 +#define NAND_ECC_READOOB 4 +#define NAND_ECC_WRITEOOB 5 + +/* Bit mask for flags passed to do_nand_read_ecc */ +#define NAND_GET_DEVICE 0x80 + + /* Option constants for bizarre disfunctionality and real * features @@ -165,6 +205,10 @@ extern int nand_read_raw (struct mtd_info *mtd, uint8_t *buf, loff_t from, size_ /* Chip has a array of 4 pages which can be read without * additional ready /busy waits */ #define NAND_4PAGE_ARRAY 0x00000040 +/* Chip requires that BBT is periodically rewritten to prevent + * bits from adjacent blocks from 'leaking' in altering data. + * This happens with the Renesas AG-AND chips, possibly others. */ +#define BBT_AUTO_REFRESH 0x00000080 /* Options valid for Samsung large page devices */ #define NAND_SAMSUNG_LP_OPTIONS \ @@ -187,6 +231,12 @@ extern int nand_read_raw (struct mtd_info *mtd, uint8_t *buf, loff_t from, size_ * This can only work if we have the ecc bytes directly behind the * data bytes. Applies for DOC and AG-AND Renesas HW Reed Solomon generators */ #define NAND_HWECC_SYNDROME 0x00020000 +/* This option skips the bbt scan during initialization. */ +#define NAND_SKIP_BBTSCAN 0x00040000 +/* This option specifies that a whole NAND page is to be written in + * nand_write_oob. This is needed for some HW ECC generators that need a + * whole page to be written to generate ECC properly */ +#define NAND_COMPLEX_OOB_WRITE 0x00080000 /* Options set by nand scan */ @@ -207,6 +257,7 @@ typedef enum { FL_ERASING, FL_SYNCING, FL_CACHEDPRG, + FL_PM_SUSPENDED, } nand_state_t; /* Keep gcc happy */ @@ -331,12 +382,16 @@ struct nand_chip { int pagemask; int pagebuf; struct nand_oobinfo *autooob; + struct page_layout_item *layout; + int layout_allocated; uint8_t *bbt; struct nand_bbt_descr *bbt_td; struct nand_bbt_descr *bbt_md; struct nand_bbt_descr *badblock_pattern; struct nand_hw_control *controller; void *priv; + int (*errstat)(struct mtd_info *mtd, struct nand_chip *this, int state, int status, int page); + }; /* @@ -348,6 +403,7 @@ struct nand_chip { #define NAND_MFR_NATIONAL 0x8f #define NAND_MFR_RENESAS 0x07 #define NAND_MFR_STMICRO 0x20 +#define NAND_MFR_HYNIX 0xad #define NAND_MFR_MICRON 0x2c /** @@ -459,6 +515,10 @@ extern int nand_update_bbt (struct mtd_info *mtd, loff_t offs); extern int nand_default_bbt (struct mtd_info *mtd); extern int nand_isbad_bbt (struct mtd_info *mtd, loff_t offs, int allowbbt); extern int nand_erase_nand (struct mtd_info *mtd, struct erase_info *instr, int allowbbt); +extern int nand_do_read_ecc (struct mtd_info *mtd, loff_t from, size_t len, + size_t * retlen, u_char * buf, u_char * oob_buf, + struct nand_oobinfo *oobsel, int flags); + /* * Constants for oob configuration diff --git a/include/linux/mtd/nand_ids.h b/include/linux/mtd/nand_ids.h index d9eb9118280..5c58fce5051 100644 --- a/include/linux/mtd/nand_ids.h +++ b/include/linux/mtd/nand_ids.h @@ -53,6 +53,7 @@ static struct nand_flash_dev nand_flash_ids[] = { {"Samsung KM29W16000", NAND_MFR_SAMSUNG, 0xea, 21, 1, 2, 0x1000, 0}, {"Samsung K9F5616Q0C", NAND_MFR_SAMSUNG, 0x45, 25, 0, 2, 0x4000, 1}, {"Samsung K9K1216Q0C", NAND_MFR_SAMSUNG, 0x46, 26, 0, 3, 0x4000, 1}, + {"Samsung K9K1208Q0C", NAND_MFR_SAMSUNG, 0x36, 26, 0, 3, 0x4000, 0}, {"Samsung K9F1G08U0M", NAND_MFR_SAMSUNG, 0xf1, 27, 0, 2, 0, 0}, {NULL,} }; diff --git a/include/nand.h b/include/nand.h index 247d3465dbb..3c0752ea12a 100644 --- a/include/nand.h +++ b/include/nand.h @@ -34,22 +34,22 @@ extern int nand_curr_device; extern nand_info_t nand_info[]; extern void nand_init(void); -static inline int nand_read(nand_info_t *info, off_t ofs, size_t *len, u_char *buf) +static inline int nand_read(nand_info_t *info, ulong ofs, ulong *len, u_char *buf) { return info->read(info, ofs, *len, (size_t *)len, buf); } -static inline int nand_write(nand_info_t *info, off_t ofs, size_t *len, u_char *buf) +static inline int nand_write(nand_info_t *info, ulong ofs, ulong *len, u_char *buf) { return info->write(info, ofs, *len, (size_t *)len, buf); } -static inline int nand_block_isbad(nand_info_t *info, off_t ofs) +static inline int nand_block_isbad(nand_info_t *info, ulong ofs) { return info->block_isbad(info, ofs); } -static inline int nand_erase(nand_info_t *info, off_t off, size_t size) +static inline int nand_erase(nand_info_t *info, ulong off, ulong size) { struct erase_info instr; diff --git a/include/spi.h b/include/spi.h index 3a55a68c4d1..7744c2e36b0 100644 --- a/include/spi.h +++ b/include/spi.h @@ -31,22 +31,87 @@ #define SPI_MODE_1 (0|SPI_CPHA) #define SPI_MODE_2 (SPI_CPOL|0) #define SPI_MODE_3 (SPI_CPOL|SPI_CPHA) -#define SPI_CS_HIGH 0x04 /* chipselect active high? */ +#define SPI_CS_HIGH 0x04 /* CS active high */ #define SPI_LSB_FIRST 0x08 /* per-word bits-on-wire */ #define SPI_3WIRE 0x10 /* SI/SO signals shared */ #define SPI_LOOP 0x20 /* loopback mode */ -/* - * The function call pointer type used to drive the chip select. - */ -typedef void (*spi_chipsel_type)(int cs); +/* SPI transfer flags */ +#define SPI_XFER_BEGIN 0x01 /* Assert CS before transfer */ +#define SPI_XFER_END 0x02 /* Deassert CS after transfer */ +/*----------------------------------------------------------------------- + * Representation of a SPI slave, i.e. what we're communicating with. + * + * Drivers are expected to extend this with controller-specific data. + * + * bus: ID of the bus that the slave is attached to. + * cs: ID of the chip select connected to the slave. + */ +struct spi_slave { + unsigned int bus; + unsigned int cs; +}; /*----------------------------------------------------------------------- * Initialization, must be called once on start up. + * + * TODO: I don't think we really need this. */ void spi_init(void); +/*----------------------------------------------------------------------- + * Set up communications parameters for a SPI slave. + * + * This must be called once for each slave. Note that this function + * usually doesn't touch any actual hardware, it only initializes the + * contents of spi_slave so that the hardware can be easily + * initialized later. + * + * bus: Bus ID of the slave chip. + * cs: Chip select ID of the slave chip on the specified bus. + * max_hz: Maximum SCK rate in Hz. + * mode: Clock polarity, clock phase and other parameters. + * + * Returns: A spi_slave reference that can be used in subsequent SPI + * calls, or NULL if one or more of the parameters are not supported. + */ +struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs, + unsigned int max_hz, unsigned int mode); + +/*----------------------------------------------------------------------- + * Free any memory associated with a SPI slave. + * + * slave: The SPI slave + */ +void spi_free_slave(struct spi_slave *slave); + +/*----------------------------------------------------------------------- + * Claim the bus and prepare it for communication with a given slave. + * + * This must be called before doing any transfers with a SPI slave. It + * will enable and initialize any SPI hardware as necessary, and make + * sure that the SCK line is in the correct idle state. It is not + * allowed to claim the same bus for several slaves without releasing + * the bus in between. + * + * slave: The SPI slave + * + * Returns: 0 if the bus was claimed successfully, or a negative value + * if it wasn't. + */ +int spi_claim_bus(struct spi_slave *slave); + +/*----------------------------------------------------------------------- + * Release the SPI bus + * + * This must be called once for every call to spi_claim_bus() after + * all transfers have finished. It may disable any SPI hardware as + * appropriate. + * + * slave: The SPI slave + */ +void spi_release_bus(struct spi_slave *slave); /*----------------------------------------------------------------------- * SPI transfer @@ -60,28 +125,67 @@ void spi_init(void); * input data overwrites the output data (since both are buffered by * temporary variables, this is OK). * - * If the chipsel() function is not NULL, it is called with a parameter - * of '1' (chip select active) at the start of the transfer and again with - * a parameter of '0' at the end of the transfer. - * - * If the chipsel() function _is_ NULL, it the responsibility of the - * caller to make the appropriate chip select active before calling - * spi_xfer() and making it inactive after spi_xfer() returns. - * * spi_xfer() interface: - * chipsel: Routine to call to set/clear the chip select: - * if chipsel is NULL, it is not used. - * if(cs), make the chip select active (typically '0'). - * if(!cs), make the chip select inactive (typically '1'). - * dout: Pointer to a string of bits to send out. The bits are - * held in a byte array and are sent MSB first. - * din: Pointer to a string of bits that will be filled in. - * bitlen: How many bits to write and read. + * slave: The SPI slave which will be sending/receiving the data. + * bitlen: How many bits to write and read. + * dout: Pointer to a string of bits to send out. The bits are + * held in a byte array and are sent MSB first. + * din: Pointer to a string of bits that will be filled in. + * flags: A bitwise combination of SPI_XFER_* flags. * * Returns: 0 on success, not 0 on failure */ -int spi_xfer(spi_chipsel_type chipsel, int bitlen, uchar *dout, uchar *din); +int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout, + void *din, unsigned long flags); + +/*----------------------------------------------------------------------- + * Determine if a SPI chipselect is valid. + * This function is provided by the board if the low-level SPI driver + * needs it to determine if a given chipselect is actually valid. + * + * Returns: 1 if bus:cs identifies a valid chip on this board, 0 + * otherwise. + */ +int spi_cs_is_valid(unsigned int bus, unsigned int cs); + +/*----------------------------------------------------------------------- + * Activate a SPI chipselect. + * This function is provided by the board code when using a driver + * that can't control its chipselects automatically (e.g. + * common/soft_spi.c). When called, it should activate the chip select + * to the device identified by "slave". + */ +void spi_cs_activate(struct spi_slave *slave); + +/*----------------------------------------------------------------------- + * Deactivate a SPI chipselect. + * This function is provided by the board code when using a driver + * that can't control its chipselects automatically (e.g. + * common/soft_spi.c). When called, it should deactivate the chip + * select to the device identified by "slave". + */ +void spi_cs_deactivate(struct spi_slave *slave); + +/*----------------------------------------------------------------------- + * Write 8 bits, then read 8 bits. + * slave: The SPI slave we're communicating with + * byte: Byte to be written + * + * Returns: The value that was read, or a negative value on error. + * + * TODO: This function probably shouldn't be inlined. + */ +static inline int spi_w8r8(struct spi_slave *slave, unsigned char byte) +{ + unsigned char dout[2]; + unsigned char din[2]; + int ret; + + dout[0] = byte; + dout[1] = 0; -int spi_select(unsigned int bus, unsigned int dev, unsigned long mode); + ret = spi_xfer(slave, 16, dout, din, SPI_XFER_BEGIN | SPI_XFER_END); + return ret < 0 ? ret : din[1]; +} #endif /* _SPI_H_ */ diff --git a/include/spi_flash.h b/include/spi_flash.h new file mode 100644 index 00000000000..de4f174ad52 --- /dev/null +++ b/include/spi_flash.h @@ -0,0 +1,70 @@ +/* + * Interface to SPI flash + * + * Copyright (C) 2008 Atmel Corporation + * + * 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 + * 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 + */ +#ifndef _SPI_FLASH_H_ +#define _SPI_FLASH_H_ + +#include <spi.h> + +struct spi_flash_region { + unsigned int count; + unsigned int size; +}; + +struct spi_flash { + struct spi_slave *spi; + + const char *name; + + u32 size; + + int (*read)(struct spi_flash *flash, u32 offset, + size_t len, void *buf); + int (*write)(struct spi_flash *flash, u32 offset, + size_t len, const void *buf); + int (*erase)(struct spi_flash *flash, u32 offset, + size_t len); +}; + +struct spi_flash *spi_flash_probe(unsigned int bus, unsigned int cs, + unsigned int max_hz, unsigned int spi_mode); +void spi_flash_free(struct spi_flash *flash); + +static inline int spi_flash_read(struct spi_flash *flash, u32 offset, + size_t len, void *buf) +{ + return flash->read(flash, offset, len, buf); +} + +static inline int spi_flash_write(struct spi_flash *flash, u32 offset, + size_t len, const void *buf) +{ + return flash->write(flash, offset, len, buf); +} + +static inline int spi_flash_erase(struct spi_flash *flash, u32 offset, + size_t len) +{ + return flash->erase(flash, offset, len); +} + +#endif /* _SPI_FLASH_H_ */ diff --git a/include/usb.h b/include/usb.h index 5a6ffddec80..f8a4fdaa4de 100644 --- a/include/usb.h +++ b/include/usb.h @@ -12,7 +12,7 @@ * * 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 + * 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 @@ -29,15 +29,15 @@ #include <usb_defs.h> /* Everything is aribtrary */ -#define USB_ALTSETTINGALLOC 4 -#define USB_MAXALTSETTING 128 /* Hard limit */ +#define USB_ALTSETTINGALLOC 4 +#define USB_MAXALTSETTING 128 /* Hard limit */ #define USB_MAX_DEVICE 32 #define USB_MAXCONFIG 8 #define USB_MAXINTERFACES 8 #define USB_MAXENDPOINTS 16 -#define USB_MAXCHILDREN 8 /* This is arbitrary */ -#define USB_MAX_HUB 16 +#define USB_MAXCHILDREN 8 /* This is arbitrary */ +#define USB_MAX_HUB 16 #define USB_CNTL_TIMEOUT 100 /* 100ms timeout */ @@ -131,18 +131,19 @@ struct usb_config_descriptor { struct usb_device { - int devnum; /* Device number on USB bus */ + int devnum; /* Device number on USB bus */ int slow; /* Slow device? */ + int high; /* High speed device? */ char mf[32]; /* manufacturer */ char prod[32]; /* product */ char serial[32]; /* serial number */ int maxpacketsize; /* Maximum packet size; encoded as 0,1,2,3 = 8,16,32,64 */ - unsigned int toggle[2]; /* one bit for each endpoint ([0] = IN, [1] = OUT) */ - unsigned int halted[2]; /* endpoint halts; one bit per endpoint # & direction; */ - /* [0] = IN, [1] = OUT */ + unsigned int toggle[2]; /* one bit for each endpoint ([0] = IN, [1] = OUT) */ + unsigned int halted[2]; /* endpoint halts; one bit per endpoint # & direction; */ + /* [0] = IN, [1] = OUT */ int epmaxpacketin[16]; /* INput endpoint specific maximums */ - int epmaxpacketout[16]; /* OUTput endpoint specific maximums */ + int epmaxpacketout[16]; /* OUTput endpoint specific maximums */ int configno; /* selected config number */ struct usb_device_descriptor descriptor; /* Device Descriptor */ @@ -155,7 +156,7 @@ struct usb_device { int irq_act_len; /* transfered bytes */ void *privptr; /* - * Child devices - if this is a hub device + * Child devices - if this is a hub device * Each instance needs its own set of data structures. */ unsigned long status; @@ -171,7 +172,7 @@ struct usb_device { #if defined(CONFIG_USB_UHCI) || defined(CONFIG_USB_OHCI) || \ defined(CONFIG_USB_OHCI_NEW) || defined (CONFIG_USB_SL811HS) || \ - defined(CONFIG_USB_ISP116X_HCD) + defined(CONFIG_USB_ISP116X_HCD) || defined(CONFIG_USB_DA8XX) int usb_lowlevel_init(void); int usb_lowlevel_stop(void); @@ -184,7 +185,7 @@ void usb_event_poll(void); /* Defines */ #define USB_UHCI_VEND_ID 0x8086 -#define USB_UHCI_DEV_ID 0x7112 +#define USB_UHCI_DEV_ID 0x7112 #else #error USB Lowlevel not defined @@ -243,8 +244,8 @@ int usb_set_interface(struct usb_device *dev, int interface, int alternate); ({ unsigned long x_ = (unsigned long)x; \ (unsigned long)( \ ((x_ & 0x000000FFUL) << 24) | \ - ((x_ & 0x0000FF00UL) << 8) | \ - ((x_ & 0x00FF0000UL) >> 8) | \ + ((x_ & 0x0000FF00UL) << 8) | \ + ((x_ & 0x00FF0000UL) >> 8) | \ ((x_ & 0xFF000000UL) >> 24) ); \ }) @@ -260,13 +261,13 @@ int usb_set_interface(struct usb_device *dev, int interface, int alternate); * Calling this entity a "pipe" is glorifying it. A USB pipe * is something embarrassingly simple: it basically consists * of the following information: - * - device number (7 bits) - * - endpoint number (4 bits) - * - current Data0/1 state (1 bit) - * - direction (1 bit) - * - speed (1 bit) - * - max packet size (2 bits: 8, 16, 32 or 64) - * - pipe type (2 bits: control, interrupt, bulk, isochronous) + * - device number (7 bits) + * - endpoint number (4 bits) + * - current Data0/1 state (1 bit) + * - direction (1 bit) + * - speed (1 bit) + * - max packet size (2 bits: 8, 16, 32 or 64) + * - pipe type (2 bits: control, interrupt, bulk, isochronous) * * That's 18 bits. Really. Nothing more. And the USB people have * documented these eighteen bits as some kind of glorious @@ -275,13 +276,13 @@ int usb_set_interface(struct usb_device *dev, int interface, int alternate); * Let's not fall in that trap. We'll just encode it as a simple * unsigned int. The encoding is: * - * - max size: bits 0-1 (00 = 8, 01 = 16, 10 = 32, 11 = 64) - * - direction: bit 7 (0 = Host-to-Device [Out], 1 = Device-to-Host [In]) - * - device: bits 8-14 - * - endpoint: bits 15-18 - * - Data0/1: bit 19 - * - speed: bit 26 (0 = Full, 1 = Low Speed) - * - pipe type: bits 30-31 (00 = isochronous, 01 = interrupt, 10 = control, 11 = bulk) + * - max size: bits 0-1 (00 = 8, 01 = 16, 10 = 32, 11 = 64) + * - direction: bit 7 (0 = Host-to-Device [Out], 1 = Device-to-Host [In]) + * - device: bits 8-14 + * - endpoint: bits 15-18 + * - Data0/1: bit 19 + * - speed: bit 26 (0 = Full, 1 = Low Speed) + * - pipe type: bits 30-31 (00 = isochronous, 01 = interrupt, 10 = control, 11 = bulk) * * Why? Because it's arbitrary, and whatever encoding we select is really * up to us. This one happens to share a lot of bit positions with the UHCI @@ -301,12 +302,12 @@ int usb_set_interface(struct usb_device *dev, int interface, int alternate); #define usb_rcvbulkpipe(dev,endpoint) ((PIPE_BULK << 30) | create_pipe(dev,endpoint) | USB_DIR_IN) #define usb_sndintpipe(dev,endpoint) ((PIPE_INTERRUPT << 30) | create_pipe(dev,endpoint)) #define usb_rcvintpipe(dev,endpoint) ((PIPE_INTERRUPT << 30) | create_pipe(dev,endpoint) | USB_DIR_IN) -#define usb_snddefctrl(dev) ((PIPE_CONTROL << 30) | default_pipe(dev)) -#define usb_rcvdefctrl(dev) ((PIPE_CONTROL << 30) | default_pipe(dev) | USB_DIR_IN) +#define usb_snddefctrl(dev) ((PIPE_CONTROL << 30) | default_pipe(dev)) +#define usb_rcvdefctrl(dev) ((PIPE_CONTROL << 30) | default_pipe(dev) | USB_DIR_IN) /* The D0/D1 toggle bits */ #define usb_gettoggle(dev, ep, out) (((dev)->toggle[out] >> ep) & 1) -#define usb_dotoggle(dev, ep, out) ((dev)->toggle[out] ^= (1 << ep)) +#define usb_dotoggle(dev, ep, out) ((dev)->toggle[out] ^= (1 << ep)) #define usb_settoggle(dev, ep, out, bit) ((dev)->toggle[out] = ((dev)->toggle[out] & ~(1 << ep)) | ((bit) << ep)) /* Endpoint halt control/status */ diff --git a/include/usb_defs.h b/include/usb_defs.h index 353019fc166..6ad4d084e97 100644 --- a/include/usb_defs.h +++ b/include/usb_defs.h @@ -30,149 +30,149 @@ /* Device and/or Interface Class codes */ #define USB_CLASS_PER_INTERFACE 0 /* for DeviceClass */ -#define USB_CLASS_AUDIO 1 -#define USB_CLASS_COMM 2 -#define USB_CLASS_HID 3 -#define USB_CLASS_PRINTER 7 -#define USB_CLASS_MASS_STORAGE 8 -#define USB_CLASS_HUB 9 -#define USB_CLASS_DATA 10 -#define USB_CLASS_VENDOR_SPEC 0xff +#define USB_CLASS_AUDIO 1 +#define USB_CLASS_COMM 2 +#define USB_CLASS_HID 3 +#define USB_CLASS_PRINTER 7 +#define USB_CLASS_MASS_STORAGE 8 +#define USB_CLASS_HUB 9 +#define USB_CLASS_DATA 10 +#define USB_CLASS_VENDOR_SPEC 0xff /* some HID sub classes */ -#define USB_SUB_HID_NONE 0 -#define USB_SUB_HID_BOOT 1 +#define USB_SUB_HID_NONE 0 +#define USB_SUB_HID_BOOT 1 /* some UID Protocols */ -#define USB_PROT_HID_NONE 0 -#define USB_PROT_HID_KEYBOARD 1 -#define USB_PROT_HID_MOUSE 2 +#define USB_PROT_HID_NONE 0 +#define USB_PROT_HID_KEYBOARD 1 +#define USB_PROT_HID_MOUSE 2 /* Sub STORAGE Classes */ -#define US_SC_RBC 1 /* Typically, flash devices */ -#define US_SC_8020 2 /* CD-ROM */ -#define US_SC_QIC 3 /* QIC-157 Tapes */ -#define US_SC_UFI 4 /* Floppy */ -#define US_SC_8070 5 /* Removable media */ -#define US_SC_SCSI 6 /* Transparent */ -#define US_SC_MIN US_SC_RBC -#define US_SC_MAX US_SC_SCSI +#define US_SC_RBC 1 /* Typically, flash devices */ +#define US_SC_8020 2 /* CD-ROM */ +#define US_SC_QIC 3 /* QIC-157 Tapes */ +#define US_SC_UFI 4 /* Floppy */ +#define US_SC_8070 5 /* Removable media */ +#define US_SC_SCSI 6 /* Transparent */ +#define US_SC_MIN US_SC_RBC +#define US_SC_MAX US_SC_SCSI /* STORAGE Protocols */ -#define US_PR_CB 1 /* Control/Bulk w/o interrupt */ -#define US_PR_CBI 0 /* Control/Bulk/Interrupt */ -#define US_PR_BULK 0x50 /* bulk only */ +#define US_PR_CB 1 /* Control/Bulk w/o interrupt */ +#define US_PR_CBI 0 /* Control/Bulk/Interrupt */ +#define US_PR_BULK 0x50 /* bulk only */ /* USB types */ -#define USB_TYPE_STANDARD (0x00 << 5) -#define USB_TYPE_CLASS (0x01 << 5) -#define USB_TYPE_VENDOR (0x02 << 5) -#define USB_TYPE_RESERVED (0x03 << 5) +#define USB_TYPE_STANDARD (0x00 << 5) +#define USB_TYPE_CLASS (0x01 << 5) +#define USB_TYPE_VENDOR (0x02 << 5) +#define USB_TYPE_RESERVED (0x03 << 5) /* USB recipients */ -#define USB_RECIP_DEVICE 0x00 +#define USB_RECIP_DEVICE 0x00 #define USB_RECIP_INTERFACE 0x01 -#define USB_RECIP_ENDPOINT 0x02 -#define USB_RECIP_OTHER 0x03 +#define USB_RECIP_ENDPOINT 0x02 +#define USB_RECIP_OTHER 0x03 /* USB directions */ -#define USB_DIR_OUT 0 -#define USB_DIR_IN 0x80 +#define USB_DIR_OUT 0 +#define USB_DIR_IN 0x80 /* Descriptor types */ -#define USB_DT_DEVICE 0x01 -#define USB_DT_CONFIG 0x02 -#define USB_DT_STRING 0x03 -#define USB_DT_INTERFACE 0x04 -#define USB_DT_ENDPOINT 0x05 +#define USB_DT_DEVICE 0x01 +#define USB_DT_CONFIG 0x02 +#define USB_DT_STRING 0x03 +#define USB_DT_INTERFACE 0x04 +#define USB_DT_ENDPOINT 0x05 -#define USB_DT_HID (USB_TYPE_CLASS | 0x01) -#define USB_DT_REPORT (USB_TYPE_CLASS | 0x02) -#define USB_DT_PHYSICAL (USB_TYPE_CLASS | 0x03) -#define USB_DT_HUB (USB_TYPE_CLASS | 0x09) +#define USB_DT_HID (USB_TYPE_CLASS | 0x01) +#define USB_DT_REPORT (USB_TYPE_CLASS | 0x02) +#define USB_DT_PHYSICAL (USB_TYPE_CLASS | 0x03) +#define USB_DT_HUB (USB_TYPE_CLASS | 0x09) /* Descriptor sizes per descriptor type */ -#define USB_DT_DEVICE_SIZE 18 -#define USB_DT_CONFIG_SIZE 9 -#define USB_DT_INTERFACE_SIZE 9 -#define USB_DT_ENDPOINT_SIZE 7 -#define USB_DT_ENDPOINT_AUDIO_SIZE 9 /* Audio extension */ -#define USB_DT_HUB_NONVAR_SIZE 7 -#define USB_DT_HID_SIZE 9 +#define USB_DT_DEVICE_SIZE 18 +#define USB_DT_CONFIG_SIZE 9 +#define USB_DT_INTERFACE_SIZE 9 +#define USB_DT_ENDPOINT_SIZE 7 +#define USB_DT_ENDPOINT_AUDIO_SIZE 9 /* Audio extension */ +#define USB_DT_HUB_NONVAR_SIZE 7 +#define USB_DT_HID_SIZE 9 /* Endpoints */ #define USB_ENDPOINT_NUMBER_MASK 0x0f /* in bEndpointAddress */ -#define USB_ENDPOINT_DIR_MASK 0x80 +#define USB_ENDPOINT_DIR_MASK 0x80 -#define USB_ENDPOINT_XFERTYPE_MASK 0x03 /* in bmAttributes */ +#define USB_ENDPOINT_XFERTYPE_MASK 0x03 /* in bmAttributes */ #define USB_ENDPOINT_XFER_CONTROL 0 -#define USB_ENDPOINT_XFER_ISOC 1 -#define USB_ENDPOINT_XFER_BULK 2 -#define USB_ENDPOINT_XFER_INT 3 +#define USB_ENDPOINT_XFER_ISOC 1 +#define USB_ENDPOINT_XFER_BULK 2 +#define USB_ENDPOINT_XFER_INT 3 /* USB Packet IDs (PIDs) */ -#define USB_PID_UNDEF_0 0xf0 -#define USB_PID_OUT 0xe1 -#define USB_PID_ACK 0xd2 -#define USB_PID_DATA0 0xc3 -#define USB_PID_UNDEF_4 0xb4 -#define USB_PID_SOF 0xa5 -#define USB_PID_UNDEF_6 0x96 -#define USB_PID_UNDEF_7 0x87 -#define USB_PID_UNDEF_8 0x78 -#define USB_PID_IN 0x69 -#define USB_PID_NAK 0x5a -#define USB_PID_DATA1 0x4b -#define USB_PID_PREAMBLE 0x3c -#define USB_PID_SETUP 0x2d -#define USB_PID_STALL 0x1e -#define USB_PID_UNDEF_F 0x0f +#define USB_PID_UNDEF_0 0xf0 +#define USB_PID_OUT 0xe1 +#define USB_PID_ACK 0xd2 +#define USB_PID_DATA0 0xc3 +#define USB_PID_UNDEF_4 0xb4 +#define USB_PID_SOF 0xa5 +#define USB_PID_UNDEF_6 0x96 +#define USB_PID_UNDEF_7 0x87 +#define USB_PID_UNDEF_8 0x78 +#define USB_PID_IN 0x69 +#define USB_PID_NAK 0x5a +#define USB_PID_DATA1 0x4b +#define USB_PID_PREAMBLE 0x3c +#define USB_PID_SETUP 0x2d +#define USB_PID_STALL 0x1e +#define USB_PID_UNDEF_F 0x0f /* Standard requests */ -#define USB_REQ_GET_STATUS 0x00 -#define USB_REQ_CLEAR_FEATURE 0x01 -#define USB_REQ_SET_FEATURE 0x03 -#define USB_REQ_SET_ADDRESS 0x05 -#define USB_REQ_GET_DESCRIPTOR 0x06 -#define USB_REQ_SET_DESCRIPTOR 0x07 -#define USB_REQ_GET_CONFIGURATION 0x08 -#define USB_REQ_SET_CONFIGURATION 0x09 -#define USB_REQ_GET_INTERFACE 0x0A -#define USB_REQ_SET_INTERFACE 0x0B -#define USB_REQ_SYNCH_FRAME 0x0C +#define USB_REQ_GET_STATUS 0x00 +#define USB_REQ_CLEAR_FEATURE 0x01 +#define USB_REQ_SET_FEATURE 0x03 +#define USB_REQ_SET_ADDRESS 0x05 +#define USB_REQ_GET_DESCRIPTOR 0x06 +#define USB_REQ_SET_DESCRIPTOR 0x07 +#define USB_REQ_GET_CONFIGURATION 0x08 +#define USB_REQ_SET_CONFIGURATION 0x09 +#define USB_REQ_GET_INTERFACE 0x0A +#define USB_REQ_SET_INTERFACE 0x0B +#define USB_REQ_SYNCH_FRAME 0x0C /* HID requests */ -#define USB_REQ_GET_REPORT 0x01 -#define USB_REQ_GET_IDLE 0x02 -#define USB_REQ_GET_PROTOCOL 0x03 -#define USB_REQ_SET_REPORT 0x09 -#define USB_REQ_SET_IDLE 0x0A -#define USB_REQ_SET_PROTOCOL 0x0B +#define USB_REQ_GET_REPORT 0x01 +#define USB_REQ_GET_IDLE 0x02 +#define USB_REQ_GET_PROTOCOL 0x03 +#define USB_REQ_SET_REPORT 0x09 +#define USB_REQ_SET_IDLE 0x0A +#define USB_REQ_SET_PROTOCOL 0x0B /* "pipe" definitions */ -#define PIPE_ISOCHRONOUS 0 -#define PIPE_INTERRUPT 1 -#define PIPE_CONTROL 2 -#define PIPE_BULK 3 -#define PIPE_DEVEP_MASK 0x0007ff00 +#define PIPE_ISOCHRONOUS 0 +#define PIPE_INTERRUPT 1 +#define PIPE_CONTROL 2 +#define PIPE_BULK 3 +#define PIPE_DEVEP_MASK 0x0007ff00 #define USB_ISOCHRONOUS 0 -#define USB_INTERRUPT 1 -#define USB_CONTROL 2 -#define USB_BULK 3 +#define USB_INTERRUPT 1 +#define USB_CONTROL 2 +#define USB_BULK 3 /* USB-status codes: */ -#define USB_ST_ACTIVE 0x1 /* TD is active */ -#define USB_ST_STALLED 0x2 /* TD is stalled */ -#define USB_ST_BUF_ERR 0x4 /* buffer error */ -#define USB_ST_BABBLE_DET 0x8 /* Babble detected */ -#define USB_ST_NAK_REC 0x10 /* NAK Received*/ -#define USB_ST_CRC_ERR 0x20 /* CRC/timeout Error */ -#define USB_ST_BIT_ERR 0x40 /* Bitstuff error */ -#define USB_ST_NOT_PROC 0x80000000L /* Not yet processed */ +#define USB_ST_ACTIVE 0x1 /* TD is active */ +#define USB_ST_STALLED 0x2 /* TD is stalled */ +#define USB_ST_BUF_ERR 0x4 /* buffer error */ +#define USB_ST_BABBLE_DET 0x8 /* Babble detected */ +#define USB_ST_NAK_REC 0x10 /* NAK Received*/ +#define USB_ST_CRC_ERR 0x20 /* CRC/timeout Error */ +#define USB_ST_BIT_ERR 0x40 /* Bitstuff error */ +#define USB_ST_NOT_PROC 0x80000000L /* Not yet processed */ /************************************************************************* @@ -184,50 +184,51 @@ */ #define USB_RT_HUB (USB_TYPE_CLASS | USB_RECIP_DEVICE) -#define USB_RT_PORT (USB_TYPE_CLASS | USB_RECIP_OTHER) +#define USB_RT_PORT (USB_TYPE_CLASS | USB_RECIP_OTHER) /* * Hub Class feature numbers */ -#define C_HUB_LOCAL_POWER 0 -#define C_HUB_OVER_CURRENT 1 +#define C_HUB_LOCAL_POWER 0 +#define C_HUB_OVER_CURRENT 1 /* * Port feature numbers */ -#define USB_PORT_FEAT_CONNECTION 0 -#define USB_PORT_FEAT_ENABLE 1 -#define USB_PORT_FEAT_SUSPEND 2 -#define USB_PORT_FEAT_OVER_CURRENT 3 -#define USB_PORT_FEAT_RESET 4 -#define USB_PORT_FEAT_POWER 8 -#define USB_PORT_FEAT_LOWSPEED 9 -#define USB_PORT_FEAT_C_CONNECTION 16 -#define USB_PORT_FEAT_C_ENABLE 17 -#define USB_PORT_FEAT_C_SUSPEND 18 +#define USB_PORT_FEAT_CONNECTION 0 +#define USB_PORT_FEAT_ENABLE 1 +#define USB_PORT_FEAT_SUSPEND 2 +#define USB_PORT_FEAT_OVER_CURRENT 3 +#define USB_PORT_FEAT_RESET 4 +#define USB_PORT_FEAT_POWER 8 +#define USB_PORT_FEAT_LOWSPEED 9 +#define USB_PORT_FEAT_C_CONNECTION 16 +#define USB_PORT_FEAT_C_ENABLE 17 +#define USB_PORT_FEAT_C_SUSPEND 18 #define USB_PORT_FEAT_C_OVER_CURRENT 19 -#define USB_PORT_FEAT_C_RESET 20 +#define USB_PORT_FEAT_C_RESET 20 /* wPortStatus bits */ -#define USB_PORT_STAT_CONNECTION 0x0001 -#define USB_PORT_STAT_ENABLE 0x0002 -#define USB_PORT_STAT_SUSPEND 0x0004 -#define USB_PORT_STAT_OVERCURRENT 0x0008 -#define USB_PORT_STAT_RESET 0x0010 -#define USB_PORT_STAT_POWER 0x0100 -#define USB_PORT_STAT_LOW_SPEED 0x0200 +#define USB_PORT_STAT_CONNECTION 0x0001 +#define USB_PORT_STAT_ENABLE 0x0002 +#define USB_PORT_STAT_SUSPEND 0x0004 +#define USB_PORT_STAT_OVERCURRENT 0x0008 +#define USB_PORT_STAT_RESET 0x0010 +#define USB_PORT_STAT_POWER 0x0100 +#define USB_PORT_STAT_LOW_SPEED 0x0200 +#define USB_PORT_STAT_HIGH_SPEED 0x0400 /* wPortChange bits */ -#define USB_PORT_STAT_C_CONNECTION 0x0001 -#define USB_PORT_STAT_C_ENABLE 0x0002 -#define USB_PORT_STAT_C_SUSPEND 0x0004 +#define USB_PORT_STAT_C_CONNECTION 0x0001 +#define USB_PORT_STAT_C_ENABLE 0x0002 +#define USB_PORT_STAT_C_SUSPEND 0x0004 #define USB_PORT_STAT_C_OVERCURRENT 0x0008 -#define USB_PORT_STAT_C_RESET 0x0010 +#define USB_PORT_STAT_C_RESET 0x0010 /* wHubCharacteristics (masks) */ -#define HUB_CHAR_LPSM 0x0003 -#define HUB_CHAR_COMPOUND 0x0004 -#define HUB_CHAR_OCPM 0x0018 +#define HUB_CHAR_LPSM 0x0003 +#define HUB_CHAR_COMPOUND 0x0004 +#define HUB_CHAR_OCPM 0x0018 /* *Hub Status & Hub Change bit masks @@ -238,4 +239,6 @@ #define HUB_CHANGE_LOCAL_POWER 0x0001 #define HUB_CHANGE_OVERCURRENT 0x0002 +#define LITTLEENDIAN + #endif /*_USB_DEFS_H_ */ diff --git a/lib_generic/string.c b/lib_generic/string.c index e0b793abbee..0a9eb453f3b 100644 --- a/lib_generic/string.c +++ b/lib_generic/string.c @@ -470,7 +470,11 @@ void * memmove(void * dest,const void *src,size_t count) { char *tmp, *s; - if (dest <= src) { + if(dest == src) { + goto done; + } + + if (dest < src) { tmp = (char *) dest; s = (char *) src; while (count--) @@ -482,7 +486,7 @@ void * memmove(void * dest,const void *src,size_t count) while (count--) *--tmp = *--s; } - +done: return dest; } #endif diff --git a/net/tftp.c b/net/tftp.c index ea8fea2f7e8..f64710f8a83 100644 --- a/net/tftp.c +++ b/net/tftp.c @@ -72,7 +72,7 @@ extern flash_info_t flash_info[]; * Minus eth.hdrs thats 1468. Can get 2x better throughput with * almost-MTU block sizes. At least try... fall back to 512 if need be. */ -#define TFTP_MTU_BLOCKSIZE 1468 +#define TFTP_MTU_BLOCKSIZE 512 static unsigned short TftpBlkSize=TFTP_BLOCK_SIZE; static unsigned short TftpBlkSizeOption=TFTP_MTU_BLOCKSIZE; diff --git a/tools/.gitignore b/tools/.gitignore index df3500d9653..e69de29bb2d 100644 --- a/tools/.gitignore +++ b/tools/.gitignore @@ -1,18 +0,0 @@ -/bmp_logo -/crc32.c -/envcrc -/environment.c -/gen_eth_addr -/img2srec -/md5.c -/mkimage -/sha1.c -/ubsha1 -/image.c -/fdt.c -/fdt_ro.c -/fdt_rw.c -/fdt_strerror.c -/fdt_wip.c -/libfdt_internal.h -/zlib.h |