diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/input/ps2ser.c | 22 | ||||
-rw-r--r-- | drivers/mmc/bfin_sdh.c | 14 | ||||
-rw-r--r-- | drivers/mtd/spi/Makefile | 2 | ||||
-rw-r--r-- | drivers/mtd/spi/atmel.c | 50 | ||||
-rw-r--r-- | drivers/mtd/spi/spansion.c | 350 | ||||
-rw-r--r-- | drivers/mtd/spi/spi_flash.c | 13 | ||||
-rw-r--r-- | drivers/mtd/spi/spi_flash_internal.h | 10 | ||||
-rw-r--r-- | drivers/mtd/spi/sst.c | 358 | ||||
-rw-r--r-- | drivers/mtd/spi/stmicro.c | 17 | ||||
-rw-r--r-- | drivers/serial/ns16550.c | 39 | ||||
-rw-r--r-- | drivers/spi/bfin_spi.c | 18 |
11 files changed, 833 insertions, 60 deletions
diff --git a/drivers/input/ps2ser.c b/drivers/input/ps2ser.c index 1af3fde..1a5e2d4 100644 --- a/drivers/input/ps2ser.c +++ b/drivers/input/ps2ser.c @@ -1,6 +1,6 @@ /*********************************************************************** * - * (C) Copyright 2004 + * (C) Copyright 2004-2009 * DENX Software Engineering * Wolfgang Denk, wd@denx.de * All rights reserved. @@ -18,9 +18,11 @@ #include <asm/io.h> #include <asm/atomic.h> #include <ps2mult.h> -#if defined(CONFIG_SYS_NS16550) || defined(CONFIG_MPC85xx) -#include <ns16550.h> +/* This is needed for ns16550.h */ +#ifndef CONFIG_SYS_NS16550_REG_SIZE +#define CONFIG_SYS_NS16550_REG_SIZE 1 #endif +#include <ns16550.h> DECLARE_GLOBAL_DATA_PTR; @@ -128,12 +130,12 @@ int ps2ser_init(void) NS16550_t com_port = (NS16550_t)COM_BASE; com_port->ier = 0x00; - com_port->lcr = LCR_BKSE | LCR_8N1; + com_port->lcr = UART_LCR_BKSE | UART_LCR_8N1; com_port->dll = (CONFIG_SYS_NS16550_CLK / 16 / PS2SER_BAUD) & 0xff; com_port->dlm = ((CONFIG_SYS_NS16550_CLK / 16 / PS2SER_BAUD) >> 8) & 0xff; - com_port->lcr = LCR_8N1; - com_port->mcr = (MCR_DTR | MCR_RTS); - com_port->fcr = (FCR_FIFO_EN | FCR_RXSR | FCR_TXSR); + com_port->lcr = UART_LCR_8N1; + com_port->mcr = (UART_MCR_DTR | UART_MCR_RTS); + com_port->fcr = (UART_FCR_FIFO_EN | UART_FCR_RXSR | UART_FCR_TXSR); return (0); } @@ -202,7 +204,7 @@ void ps2ser_putc(int chr) psc->psc_buffer_8 = chr; #elif defined(CONFIG_MPC8540) || defined(CONFIG_MPC8541) || \ defined(CONFIG_MPC8548) || defined(CONFIG_MPC8555) - while ((com_port->lsr & LSR_THRE) == 0); + while ((com_port->lsr & UART_LSR_THRE) == 0); com_port->thr = chr; #else while (!(ps2ser_in(UART_LSR) & UART_LSR_THRE)); @@ -227,7 +229,7 @@ static int ps2ser_getc_hw(void) } #elif defined(CONFIG_MPC8540) || defined(CONFIG_MPC8541) || \ defined(CONFIG_MPC8548) || defined(CONFIG_MPC8555) - if (com_port->lsr & LSR_DR) { + if (com_port->lsr & UART_LSR_DR) { res = com_port->rbr; } #else @@ -315,7 +317,7 @@ static void ps2ser_interrupt(void *dev_id) } while (status & PSC_SR_RXRDY); #elif defined(CONFIG_MPC8540) || defined(CONFIG_MPC8541) || \ defined(CONFIG_MPC8548) || defined(CONFIG_MPC8555) - } while (status & LSR_DR); + } while (status & UART_LSR_DR); #else } while (status & UART_IIR_RDI); #endif diff --git a/drivers/mmc/bfin_sdh.c b/drivers/mmc/bfin_sdh.c index 7d6b495..16c9695 100644 --- a/drivers/mmc/bfin_sdh.c +++ b/drivers/mmc/bfin_sdh.c @@ -293,7 +293,7 @@ mmc_bwrite(int dev, unsigned long start, lbaint_t blkcnt, const void *buffer) printf("MMC_CMD_SET_BLOCKLEN failed\n"); goto out; } - ret = mmc_cmd(MMC_CMD_WRITE_BLOCK, + ret = mmc_cmd(MMC_CMD_WRITE_SINGLE_BLOCK, start * mmc_blkdev.blksz, resp, MMC_RSP_R1); if (ret) { @@ -462,7 +462,7 @@ static int mmc_init_card(struct mmc_cid *cid, int verbose) return ret; } -int mmc_init(int verbose) +int mmc_legacy_init(int verbose) { __u16 pwr_ctl = 0; int ret; @@ -530,16 +530,6 @@ int mmc_init(int verbose) return 0; } -int mmc_read(ulong src, uchar *dst, int size) -{ - return -ENOSYS; -} - -int mmc_write(uchar *src, ulong dst, int size) -{ - return -ENOSYS; -} - int mmc2info(ulong addr) { return 0; diff --git a/drivers/mtd/spi/Makefile b/drivers/mtd/spi/Makefile index 3d4f892..a71b16e 100644 --- a/drivers/mtd/spi/Makefile +++ b/drivers/mtd/spi/Makefile @@ -27,6 +27,8 @@ LIB := $(obj)libspi_flash.a COBJS-$(CONFIG_SPI_FLASH) += spi_flash.o COBJS-$(CONFIG_SPI_FLASH_ATMEL) += atmel.o +COBJS-$(CONFIG_SPI_FLASH_SPANSION) += spansion.o +COBJS-$(CONFIG_SPI_FLASH_SST) += sst.o COBJS-$(CONFIG_SPI_FLASH_STMICRO) += stmicro.o COBJS := $(COBJS-y) diff --git a/drivers/mtd/spi/atmel.c b/drivers/mtd/spi/atmel.c index a5f51ca..c3b936f 100644 --- a/drivers/mtd/spi/atmel.c +++ b/drivers/mtd/spi/atmel.c @@ -3,7 +3,7 @@ * * Copyright (C) 2008 Atmel Corporation */ -#define DEBUG + #include <common.h> #include <malloc.h> #include <spi_flash.h> @@ -53,6 +53,54 @@ to_atmel_spi_flash(struct spi_flash *flash) static const struct atmel_spi_flash_params atmel_spi_flash_table[] = { { + .idcode1 = 0x22, + .l2_page_size = 8, + .pages_per_block = 8, + .blocks_per_sector = 16, + .nr_sectors = 4, + .name = "AT45DB011D", + }, + { + .idcode1 = 0x23, + .l2_page_size = 8, + .pages_per_block = 8, + .blocks_per_sector = 16, + .nr_sectors = 8, + .name = "AT45DB021D", + }, + { + .idcode1 = 0x24, + .l2_page_size = 8, + .pages_per_block = 8, + .blocks_per_sector = 32, + .nr_sectors = 8, + .name = "AT45DB041D", + }, + { + .idcode1 = 0x25, + .l2_page_size = 8, + .pages_per_block = 8, + .blocks_per_sector = 32, + .nr_sectors = 16, + .name = "AT45DB081D", + }, + { + .idcode1 = 0x26, + .l2_page_size = 9, + .pages_per_block = 8, + .blocks_per_sector = 32, + .nr_sectors = 16, + .name = "AT45DB161D", + }, + { + .idcode1 = 0x27, + .l2_page_size = 9, + .pages_per_block = 8, + .blocks_per_sector = 64, + .nr_sectors = 64, + .name = "AT45DB321D", + }, + { .idcode1 = 0x28, .l2_page_size = 10, .pages_per_block = 8, diff --git a/drivers/mtd/spi/spansion.c b/drivers/mtd/spi/spansion.c new file mode 100644 index 0000000..fdb7917 --- /dev/null +++ b/drivers/mtd/spi/spansion.c @@ -0,0 +1,350 @@ +/* + * Copyright (C) 2009 Freescale Semiconductor, Inc. + * + * Author: Mingkai Hu (Mingkai.hu@freescale.com) + * Based on stmicro.c by Wolfgang Denk (wd@denx.de), + * TsiChung Liew (Tsi-Chung.Liew@freescale.com), + * and Jason McMullan (mcmullan@netapp.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" + +/* S25FLxx-specific commands */ +#define CMD_S25FLXX_READ 0x03 /* Read Data Bytes */ +#define CMD_S25FLXX_FAST_READ 0x0b /* Read Data Bytes at Higher Speed */ +#define CMD_S25FLXX_READID 0x90 /* Read Manufacture ID and Device ID */ +#define CMD_S25FLXX_WREN 0x06 /* Write Enable */ +#define CMD_S25FLXX_WRDI 0x04 /* Write Disable */ +#define CMD_S25FLXX_RDSR 0x05 /* Read Status Register */ +#define CMD_S25FLXX_WRSR 0x01 /* Write Status Register */ +#define CMD_S25FLXX_PP 0x02 /* Page Program */ +#define CMD_S25FLXX_SE 0xd8 /* Sector Erase */ +#define CMD_S25FLXX_BE 0xc7 /* Bulk Erase */ +#define CMD_S25FLXX_DP 0xb9 /* Deep Power-down */ +#define CMD_S25FLXX_RES 0xab /* Release from DP, and Read Signature */ + +#define SPSN_ID_S25FL008A 0x0213 +#define SPSN_ID_S25FL016A 0x0214 +#define SPSN_ID_S25FL032A 0x0215 +#define SPSN_ID_S25FL064A 0x0216 +#define SPSN_ID_S25FL128P 0x2018 +#define SPSN_EXT_ID_S25FL128P_256KB 0x0300 +#define SPSN_EXT_ID_S25FL128P_64KB 0x0301 + +#define SPANSION_SR_WIP (1 << 0) /* Write-in-Progress */ + +struct spansion_spi_flash_params { + u16 idcode1; + u16 idcode2; + u16 page_size; + u16 pages_per_sector; + u16 nr_sectors; + const char *name; +}; + +struct spansion_spi_flash { + struct spi_flash flash; + const struct spansion_spi_flash_params *params; +}; + +static inline struct spansion_spi_flash *to_spansion_spi_flash(struct spi_flash + *flash) +{ + return container_of(flash, struct spansion_spi_flash, flash); +} + +static const struct spansion_spi_flash_params spansion_spi_flash_table[] = { + { + .idcode1 = SPSN_ID_S25FL008A, + .idcode2 = 0, + .page_size = 256, + .pages_per_sector = 256, + .nr_sectors = 16, + .name = "S25FL008A", + }, + { + .idcode1 = SPSN_ID_S25FL016A, + .idcode2 = 0, + .page_size = 256, + .pages_per_sector = 256, + .nr_sectors = 32, + .name = "S25FL016A", + }, + { + .idcode1 = SPSN_ID_S25FL032A, + .idcode2 = 0, + .page_size = 256, + .pages_per_sector = 256, + .nr_sectors = 64, + .name = "S25FL032A", + }, + { + .idcode1 = SPSN_ID_S25FL064A, + .idcode2 = 0, + .page_size = 256, + .pages_per_sector = 256, + .nr_sectors = 128, + .name = "S25FL064A", + }, + { + .idcode1 = SPSN_ID_S25FL128P, + .idcode2 = SPSN_EXT_ID_S25FL128P_64KB, + .page_size = 256, + .pages_per_sector = 256, + .nr_sectors = 256, + .name = "S25FL128P_64K", + }, + { + .idcode1 = SPSN_ID_S25FL128P, + .idcode2 = SPSN_EXT_ID_S25FL128P_256KB, + .page_size = 256, + .pages_per_sector = 1024, + .nr_sectors = 64, + .name = "S25FL128P_256K", + }, +}; + +static int spansion_wait_ready(struct spi_flash *flash, unsigned long timeout) +{ + struct spi_slave *spi = flash->spi; + unsigned long timebase; + int ret; + u8 status; + + timebase = get_timer(0); + do { + ret = spi_flash_cmd(spi, CMD_S25FLXX_RDSR, &status, sizeof(status)); + if (ret) + return -1; + + if ((status & SPANSION_SR_WIP) == 0) + break; + + } while (get_timer(timebase) < timeout); + + + if ((status & SPANSION_SR_WIP) == 0) + return 0; + + /* Timed out */ + return -1; +} + +static int spansion_read_fast(struct spi_flash *flash, + u32 offset, size_t len, void *buf) +{ + struct spansion_spi_flash *spsn = to_spansion_spi_flash(flash); + unsigned long page_addr; + unsigned long page_size; + u8 cmd[5]; + + page_size = spsn->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; + + debug + ("READ: 0x%x => cmd = { 0x%02x 0x%02x%02x%02x%02x } len = 0x%x\n", + offset, cmd[0], cmd[1], cmd[2], cmd[3], cmd[4], len); + + return spi_flash_read_common(flash, cmd, sizeof(cmd), buf, len); +} + +static int spansion_write(struct spi_flash *flash, + u32 offset, size_t len, const void *buf) +{ + struct spansion_spi_flash *spsn = to_spansion_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 = spsn->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_S25FLXX_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_S25FLXX_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: SPANSION Page Program failed\n"); + break; + } + + ret = spansion_wait_ready(flash, SPI_FLASH_PROG_TIMEOUT); + if (ret < 0) { + debug("SF: SPANSION page programming timed out\n"); + break; + } + + page_addr++; + byte_addr = 0; + } + + debug("SF: SPANSION: Successfully programmed %u bytes @ 0x%x\n", + len, offset); + + spi_release_bus(flash->spi); + return ret; +} + +int spansion_erase(struct spi_flash *flash, u32 offset, size_t len) +{ + struct spansion_spi_flash *spsn = to_spansion_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 = spsn->params->page_size * spsn->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_S25FLXX_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_S25FLXX_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: SPANSION page erase failed\n"); + break; + } + + /* Up to 2 seconds */ + ret = spansion_wait_ready(flash, SPI_FLASH_PAGE_ERASE_TIMEOUT); + if (ret < 0) { + debug("SF: SPANSION page erase timed out\n"); + break; + } + } + + debug("SF: SPANSION: Successfully erased %u bytes @ 0x%x\n", + len * sector_size, offset); + + spi_release_bus(flash->spi); + return ret; +} + +struct spi_flash *spi_flash_probe_spansion(struct spi_slave *spi, u8 *idcode) +{ + const struct spansion_spi_flash_params *params; + struct spansion_spi_flash *spsn; + unsigned int i; + unsigned short jedec, ext_jedec; + + jedec = idcode[1] << 8 | idcode[2]; + ext_jedec = idcode[3] << 8 | idcode[4]; + + for (i = 0; i < ARRAY_SIZE(spansion_spi_flash_table); i++) { + params = &spansion_spi_flash_table[i]; + if (params->idcode1 == jedec) { + if (params->idcode2 == ext_jedec) + break; + } + } + + if (i == ARRAY_SIZE(spansion_spi_flash_table)) { + debug("SF: Unsupported SPANSION ID %04x %04x\n", jedec, ext_jedec); + return NULL; + } + + spsn = malloc(sizeof(struct spansion_spi_flash)); + if (!spsn) { + debug("SF: Failed to allocate memory\n"); + return NULL; + } + + spsn->params = params; + spsn->flash.spi = spi; + spsn->flash.name = params->name; + + spsn->flash.write = spansion_write; + spsn->flash.erase = spansion_erase; + spsn->flash.read = spansion_read_fast; + spsn->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, spsn->flash.size); + + return &spsn->flash; +} diff --git a/drivers/mtd/spi/spi_flash.c b/drivers/mtd/spi/spi_flash.c index d1d81af..274895a 100644 --- a/drivers/mtd/spi/spi_flash.c +++ b/drivers/mtd/spi/spi_flash.c @@ -3,7 +3,7 @@ * * Copyright (C) 2008 Atmel Corporation */ -#define DEBUG + #include <common.h> #include <malloc.h> #include <spi.h> @@ -101,7 +101,7 @@ struct spi_flash *spi_flash_probe(unsigned int bus, unsigned int cs, struct spi_slave *spi; struct spi_flash *flash; int ret; - u8 idcode[3]; + u8 idcode[5]; spi = spi_setup_slave(bus, cs, max_hz, spi_mode); if (!spi) { @@ -120,8 +120,8 @@ struct spi_flash *spi_flash_probe(unsigned int bus, unsigned int cs, if (ret) goto err_read_id; - debug("SF: Got idcode %02x %02x %02x\n", idcode[0], - idcode[1], idcode[2]); + debug("SF: Got idcode %02x %02x %02x %02x %02x\n", idcode[0], + idcode[1], idcode[2], idcode[3], idcode[4]); switch (idcode[0]) { #ifdef CONFIG_SPI_FLASH_SPANSION @@ -139,6 +139,11 @@ struct spi_flash *spi_flash_probe(unsigned int bus, unsigned int cs, flash = spi_flash_probe_stmicro(spi, idcode); break; #endif +#ifdef CONFIG_SPI_FLASH_SST + case 0xBF: + flash = spi_flash_probe_sst(spi, idcode); + break; +#endif default: debug("SF: Unsupported manufacturer %02X\n", idcode[0]); flash = NULL; diff --git a/drivers/mtd/spi/spi_flash_internal.h b/drivers/mtd/spi/spi_flash_internal.h index 75f5900..5d1e395 100644 --- a/drivers/mtd/spi/spi_flash_internal.h +++ b/drivers/mtd/spi/spi_flash_internal.h @@ -4,9 +4,12 @@ * Copyright (C) 2008 Atmel Corporation */ -/* Common parameters */ -#define SPI_FLASH_PROG_TIMEOUT ((10 * CONFIG_SYS_HZ) / 1000) -#define SPI_FLASH_PAGE_ERASE_TIMEOUT ((50 * CONFIG_SYS_HZ) / 1000) +/* Common parameters -- kind of high, but they should only occur when there + * is a problem (and well your system already is broken), so err on the side + * of caution in case we're dealing with slower SPI buses and/or processors. + */ +#define SPI_FLASH_PROG_TIMEOUT (2 * CONFIG_SYS_HZ) +#define SPI_FLASH_PAGE_ERASE_TIMEOUT (5 * CONFIG_SYS_HZ) #define SPI_FLASH_SECTOR_ERASE_TIMEOUT (10 * CONFIG_SYS_HZ) /* Common commands */ @@ -43,4 +46,5 @@ int spi_flash_read_common(struct spi_flash *flash, const u8 *cmd, /* 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_sst(struct spi_slave *spi, u8 *idcode); struct spi_flash *spi_flash_probe_stmicro(struct spi_slave *spi, u8 *idcode); diff --git a/drivers/mtd/spi/sst.c b/drivers/mtd/spi/sst.c new file mode 100644 index 0000000..62236d4 --- /dev/null +++ b/drivers/mtd/spi/sst.c @@ -0,0 +1,358 @@ +/* + * Driver for SST serial flashes + * + * (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) + * Copyright (c) 2008-2009 Analog Devices Inc. + * + * Licensed under the GPL-2 or later. + */ + +#include <common.h> +#include <malloc.h> +#include <spi_flash.h> + +#include "spi_flash_internal.h" + +#define CMD_SST_WREN 0x06 /* Write Enable */ +#define CMD_SST_WRDI 0x04 /* Write Disable */ +#define CMD_SST_RDSR 0x05 /* Read Status Register */ +#define CMD_SST_WRSR 0x01 /* Write Status Register */ +#define CMD_SST_READ 0x03 /* Read Data Bytes */ +#define CMD_SST_FAST_READ 0x0b /* Read Data Bytes at Higher Speed */ +#define CMD_SST_BP 0x02 /* Byte Program */ +#define CMD_SST_AAI_WP 0xAD /* Auto Address Increment Word Program */ +#define CMD_SST_SE 0x20 /* Sector Erase */ + +#define SST_SR_WIP (1 << 0) /* Write-in-Progress */ +#define SST_SR_WEL (1 << 1) /* Write enable */ +#define SST_SR_BP0 (1 << 2) /* Block Protection 0 */ +#define SST_SR_BP1 (1 << 3) /* Block Protection 1 */ +#define SST_SR_BP2 (1 << 4) /* Block Protection 2 */ +#define SST_SR_AAI (1 << 6) /* Addressing mode */ +#define SST_SR_BPL (1 << 7) /* BP bits lock */ + +struct sst_spi_flash_params { + u8 idcode1; + u16 nr_sectors; + const char *name; +}; + +struct sst_spi_flash { + struct spi_flash flash; + const struct sst_spi_flash_params *params; +}; + +static inline struct sst_spi_flash *to_sst_spi_flash(struct spi_flash *flash) +{ + return container_of(flash, struct sst_spi_flash, flash); +} + +#define SST_SECTOR_SIZE (4 * 1024) +static const struct sst_spi_flash_params sst_spi_flash_table[] = { + { + .idcode1 = 0x01, + .nr_sectors = 128, + .name = "SST25WF512", + },{ + .idcode1 = 0x02, + .nr_sectors = 256, + .name = "SST25WF010", + },{ + .idcode1 = 0x03, + .nr_sectors = 512, + .name = "SST25WF020", + },{ + .idcode1 = 0x04, + .nr_sectors = 1024, + .name = "SST25WF040", + }, +}; + +static int +sst_wait_ready(struct spi_flash *flash, unsigned long timeout) +{ + struct spi_slave *spi = flash->spi; + unsigned long timebase; + int ret; + u8 byte = CMD_SST_RDSR; + + ret = spi_xfer(spi, sizeof(byte) * 8, &byte, NULL, SPI_XFER_BEGIN); + if (ret) { + debug("SF: Failed to send command %02x: %d\n", byte, ret); + return ret; + } + + timebase = get_timer(0); + do { + ret = spi_xfer(spi, sizeof(byte) * 8, NULL, &byte, 0); + if (ret) + break; + + if ((byte & SST_SR_WIP) == 0) + break; + + } while (get_timer(timebase) < timeout); + + spi_xfer(spi, 0, NULL, NULL, SPI_XFER_END); + + if (!ret && (byte & SST_SR_WIP) != 0) + ret = -1; + + if (ret) + debug("SF: sst wait for ready timed out\n"); + return ret; +} + +static int +sst_enable_writing(struct spi_flash *flash) +{ + int ret = spi_flash_cmd(flash->spi, CMD_SST_WREN, NULL, 0); + if (ret) + debug("SF: Enabling Write failed\n"); + return ret; +} + +static int +sst_disable_writing(struct spi_flash *flash) +{ + int ret = spi_flash_cmd(flash->spi, CMD_SST_WRDI, NULL, 0); + if (ret) + debug("SF: Disabling Write failed\n"); + return ret; +} + +static int +sst_read_fast(struct spi_flash *flash, u32 offset, size_t len, void *buf) +{ + u8 cmd[5] = { + CMD_READ_ARRAY_FAST, + offset >> 16, + offset >> 8, + offset, + 0x00, + }; + return spi_flash_read_common(flash, cmd, sizeof(cmd), buf, len); +} + +static int +sst_byte_write(struct spi_flash *flash, u32 offset, const void *buf) +{ + int ret; + u8 cmd[4] = { + CMD_SST_BP, + offset >> 16, + offset >> 8, + offset, + }; + + debug("BP[%02x]: 0x%p => cmd = { 0x%02x 0x%06x }\n", + spi_w8r8(flash->spi, CMD_SST_RDSR), buf, cmd[0], offset); + + ret = sst_enable_writing(flash); + if (ret) + return ret; + + ret = spi_flash_cmd_write(flash->spi, cmd, sizeof(cmd), buf, 1); + if (ret) + return ret; + + return sst_wait_ready(flash, SPI_FLASH_PROG_TIMEOUT); +} + +static int +sst_write(struct spi_flash *flash, u32 offset, size_t len, const void *buf) +{ + size_t actual, cmd_len; + int ret; + u8 cmd[4]; + + ret = spi_claim_bus(flash->spi); + if (ret) { + debug("SF: Unable to claim SPI bus\n"); + return ret; + } + + /* If the data is not word aligned, write out leading single byte */ + actual = offset % 2; + if (actual) { + ret = sst_byte_write(flash, offset, buf); + if (ret) + goto done; + } + offset += actual; + + ret = sst_enable_writing(flash); + if (ret) + goto done; + + cmd_len = 4; + cmd[0] = CMD_SST_AAI_WP; + cmd[1] = offset >> 16; + cmd[2] = offset >> 8; + cmd[3] = offset; + + for (; actual < len - 1; actual += 2) { + debug("WP[%02x]: 0x%p => cmd = { 0x%02x 0x%06x }\n", + spi_w8r8(flash->spi, CMD_SST_RDSR), buf + actual, cmd[0], + offset); + + ret = spi_flash_cmd_write(flash->spi, cmd, cmd_len, + buf + actual, 2); + if (ret) { + debug("SF: sst word program failed\n"); + break; + } + + ret = sst_wait_ready(flash, SPI_FLASH_PROG_TIMEOUT); + if (ret) + break; + + cmd_len = 1; + offset += 2; + } + + if (!ret) + ret = sst_disable_writing(flash); + + /* If there is a single trailing byte, write it out */ + if (!ret && actual != len) + ret = sst_byte_write(flash, offset, buf + actual); + + done: + debug("SF: sst: program %s %zu bytes @ 0x%zx\n", + ret ? "failure" : "success", len, offset - actual); + + spi_release_bus(flash->spi); + return ret; +} + +int +sst_erase(struct spi_flash *flash, u32 offset, size_t len) +{ + unsigned long sector_size; + u32 start, end; + int ret; + u8 cmd[4]; + + /* + * This function currently uses sector erase only. + * Probably speed things up by using bulk erase + * when possible. + */ + + sector_size = SST_SECTOR_SIZE; + + if (offset % sector_size) { + debug("SF: Erase offset not multiple of sector size\n"); + return -1; + } + + ret = spi_claim_bus(flash->spi); + if (ret) { + debug("SF: Unable to claim SPI bus\n"); + return ret; + } + + cmd[0] = CMD_SST_SE; + cmd[3] = 0; + start = offset; + end = start + len; + + ret = 0; + while (offset < end) { + cmd[1] = offset >> 16; + cmd[2] = offset >> 8; + offset += sector_size; + + debug("SF: erase %2x %2x %2x %2x (%x)\n", cmd[0], cmd[1], + cmd[2], cmd[3], offset); + + ret = sst_enable_writing(flash); + if (ret) + break; + + ret = spi_flash_cmd_write(flash->spi, cmd, sizeof(cmd), NULL, 0); + if (ret) { + debug("SF: sst page erase failed\n"); + break; + } + + ret = sst_wait_ready(flash, SPI_FLASH_PAGE_ERASE_TIMEOUT); + if (ret) + break; + } + + debug("SF: sst: Successfully erased %lu bytes @ 0x%x\n", + len * sector_size, start); + + spi_release_bus(flash->spi); + return ret; +} + +static int +sst_unlock(struct spi_flash *flash) +{ + int ret; + u8 cmd, status; + + ret = sst_enable_writing(flash); + if (ret) + return ret; + + cmd = CMD_SST_WRSR; + status = 0; + ret = spi_flash_cmd_write(flash->spi, &cmd, 1, &status, 1); + if (ret) + debug("SF: Unable to set status byte\n"); + + debug("SF: sst: status = %x\n", spi_w8r8(flash->spi, CMD_SST_RDSR)); + + return ret; +} + +struct spi_flash * +spi_flash_probe_sst(struct spi_slave *spi, u8 *idcode) +{ + const struct sst_spi_flash_params *params; + struct sst_spi_flash *stm; + size_t i; + + for (i = 0; i < ARRAY_SIZE(sst_spi_flash_table); ++i) { + params = &sst_spi_flash_table[i]; + if (params->idcode1 == idcode[2]) + break; + } + + if (i == ARRAY_SIZE(sst_spi_flash_table)) { + debug("SF: Unsupported SST ID %02x\n", idcode[1]); + return NULL; + } + + stm = malloc(sizeof(*stm)); + 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 = sst_write; + stm->flash.erase = sst_erase; + stm->flash.read = sst_read_fast; + stm->flash.size = SST_SECTOR_SIZE * params->nr_sectors; + + debug("SF: Detected %s with page size %u, total %u bytes\n", + params->name, SST_SECTOR_SIZE, stm->flash.size); + + /* Flash powers up read-only, so clear BP# bits */ + sst_unlock(&stm->flash); + + return &stm->flash; +} diff --git a/drivers/mtd/spi/stmicro.c b/drivers/mtd/spi/stmicro.c index e7dda91..9b910c1 100644 --- a/drivers/mtd/spi/stmicro.c +++ b/drivers/mtd/spi/stmicro.c @@ -133,12 +133,12 @@ static int stmicro_wait_ready(struct spi_flash *flash, unsigned long timeout) struct spi_slave *spi = flash->spi; unsigned long timebase; int ret; + u8 cmd = CMD_M25PXX_RDSR; u8 status; - u8 cmd[4] = { CMD_M25PXX_RDSR, 0xff, 0xff, 0xff }; - ret = spi_xfer(spi, 32, &cmd[0], NULL, SPI_XFER_BEGIN); + ret = spi_xfer(spi, 8, &cmd, NULL, SPI_XFER_BEGIN); if (ret) { - debug("SF: Failed to send command %02x: %d\n", cmd[0], ret); + debug("SF: Failed to send command %02x: %d\n", cmd, ret); return ret; } @@ -295,8 +295,7 @@ int stmicro_erase(struct spi_flash *flash, u32 offset, size_t len) break; } - /* Up to 2 seconds */ - ret = stmicro_wait_ready(flash, 2 * CONFIG_SYS_HZ); + ret = stmicro_wait_ready(flash, SPI_FLASH_PAGE_ERASE_TIMEOUT); if (ret < 0) { debug("SF: STMicro page erase timed out\n"); break; @@ -315,12 +314,6 @@ 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]; @@ -330,7 +323,7 @@ struct spi_flash *spi_flash_probe_stmicro(struct spi_slave *spi, u8 * idcode) } if (i == ARRAY_SIZE(stmicro_spi_flash_table)) { - debug("SF: Unsupported STMicro ID %02x\n", id[1]); + debug("SF: Unsupported STMicro ID %02x\n", idcode[1]); return NULL; } diff --git a/drivers/serial/ns16550.c b/drivers/serial/ns16550.c index 397f5df..657c9da 100644 --- a/drivers/serial/ns16550.c +++ b/drivers/serial/ns16550.c @@ -7,9 +7,12 @@ #include <config.h> #include <ns16550.h> -#define LCRVAL LCR_8N1 /* 8 data, 1 stop, no parity */ -#define MCRVAL (MCR_DTR | MCR_RTS) /* RTS/DTR */ -#define FCRVAL (FCR_FIFO_EN | FCR_RXSR | FCR_TXSR) /* Clear & enable FIFOs */ +#define UART_LCRVAL UART_LCR_8N1 /* 8 data, 1 stop, no parity */ +#define UART_MCRVAL (UART_MCR_DTR | \ + UART_MCR_RTS) /* RTS/DTR */ +#define UART_FCRVAL (UART_FCR_FIFO_EN | \ + UART_FCR_RXSR | \ + UART_FCR_TXSR) /* Clear & enable FIFOs */ void NS16550_init (NS16550_t com_port, int baud_divisor) { @@ -17,16 +20,16 @@ void NS16550_init (NS16550_t com_port, int baud_divisor) #ifdef CONFIG_OMAP com_port->mdr1 = 0x7; /* mode select reset TL16C750*/ #endif - com_port->lcr = LCR_BKSE | LCRVAL; + com_port->lcr = UART_LCR_BKSE | UART_LCRVAL; com_port->dll = 0; com_port->dlm = 0; - com_port->lcr = LCRVAL; - com_port->mcr = MCRVAL; - com_port->fcr = FCRVAL; - com_port->lcr = LCR_BKSE | LCRVAL; + com_port->lcr = UART_LCRVAL; + com_port->mcr = UART_MCRVAL; + com_port->fcr = UART_FCRVAL; + com_port->lcr = UART_LCR_BKSE | UART_LCRVAL; com_port->dll = baud_divisor & 0xff; com_port->dlm = (baud_divisor >> 8) & 0xff; - com_port->lcr = LCRVAL; + com_port->lcr = UART_LCRVAL; #if defined(CONFIG_OMAP) #if defined(CONFIG_APTIX) com_port->mdr1 = 3; /* /13 mode so Aptix 6MHz can hit 115200 */ @@ -40,29 +43,29 @@ void NS16550_init (NS16550_t com_port, int baud_divisor) void NS16550_reinit (NS16550_t com_port, int baud_divisor) { com_port->ier = 0x00; - com_port->lcr = LCR_BKSE | LCRVAL; + com_port->lcr = UART_LCR_BKSE | UART_LCRVAL; com_port->dll = 0; com_port->dlm = 0; - com_port->lcr = LCRVAL; - com_port->mcr = MCRVAL; - com_port->fcr = FCRVAL; - com_port->lcr = LCR_BKSE; + com_port->lcr = UART_LCRVAL; + com_port->mcr = UART_MCRVAL; + com_port->fcr = UART_FCRVAL; + com_port->lcr = UART_LCR_BKSE; com_port->dll = baud_divisor & 0xff; com_port->dlm = (baud_divisor >> 8) & 0xff; - com_port->lcr = LCRVAL; + com_port->lcr = UART_LCRVAL; } #endif /* CONFIG_NS16550_MIN_FUNCTIONS */ void NS16550_putc (NS16550_t com_port, char c) { - while ((com_port->lsr & LSR_THRE) == 0); + while ((com_port->lsr & UART_LSR_THRE) == 0); com_port->thr = c; } #ifndef CONFIG_NS16550_MIN_FUNCTIONS char NS16550_getc (NS16550_t com_port) { - while ((com_port->lsr & LSR_DR) == 0) { + while ((com_port->lsr & UART_LSR_DR) == 0) { #ifdef CONFIG_USB_TTY extern void usbtty_poll(void); usbtty_poll(); @@ -73,7 +76,7 @@ char NS16550_getc (NS16550_t com_port) int NS16550_tstc (NS16550_t com_port) { - return ((com_port->lsr & LSR_DR) != 0); + return ((com_port->lsr & UART_LSR_DR) != 0); } #endif /* CONFIG_NS16550_MIN_FUNCTIONS */ diff --git a/drivers/spi/bfin_spi.c b/drivers/spi/bfin_spi.c index 0472c1a..bc3394a 100644 --- a/drivers/spi/bfin_spi.c +++ b/drivers/spi/bfin_spi.c @@ -36,6 +36,11 @@ MAKE_SPI_FUNC(SPI_BAUD, 0x14) __attribute__((weak)) int spi_cs_is_valid(unsigned int bus, unsigned int cs) { +#if defined(__ADSPBF538__) || defined(__ADSPBF539__) + /* The SPI1/SPI2 buses are weird ... only 1 CS */ + if (bus > 0 && cs != 1) + return 0; +#endif return (cs >= 1 && cs <= 7); } @@ -204,6 +209,19 @@ static void spi_portmux(struct spi_slave *slave) } bfin_write_PORT_MUX(mux); bfin_write_PORTF_FER(f_fer); +#elif defined(__ADSPBF538__) || defined(__ADSPBF539__) + u16 fer, pins; + if (slave->bus == 1) + pins = PD0 | PD1 | PD2 | (slave->cs == 1 ? PD4 : 0); + else if (slave->bus == 2) + pins = PD5 | PD6 | PD7 | (slave->cs == 1 ? PD9 : 0); + else + pins = 0; + if (pins) { + fer = bfin_read_PORTDIO_FER(); + fer &= ~pins; + bfin_write_PORTDIO_FER(fer); + } #elif defined(__ADSPBF54x__) #define DO_MUX(port, pin) \ mux = ((mux & ~PORT_x_MUX_##pin##_MASK) | PORT_x_MUX_##pin##_FUNC_1); \ |