Merge branch 'spi' of git://git.denx.de/u-boot-x86

This commit is contained in:
Tom Rini 2013-03-20 14:55:10 -04:00
commit 8b906a9f0b
44 changed files with 1212 additions and 154 deletions

View File

@ -164,13 +164,13 @@ init_fnc_t *init_sequence_r[] = {
#ifndef CONFIG_SYS_NO_FLASH
flash_init_r,
#endif
#ifdef CONFIG_SPI
init_func_spi;
#endif
env_relocate_r,
#ifdef CONFIG_PCI
pci_init_r,
#endif
#ifdef CONFIG_SPI
init_func_spi,
#endif
env_relocate_r,
stdio_init,
jumptable_init_r,
console_init_r,

View File

@ -21,4 +21,15 @@
chosen { };
memory { device_type = "memory"; reg = <0 0>; };
spi {
#address-cells = <1>;
#size-cells = <0>;
compatible = "intel,ich9";
spi-flash@0 {
reg = <0>;
compatible = "winbond,w25q64", "spi-flash";
memory-map = <0xff800000 0x00800000>;
};
};
};

View File

@ -369,8 +369,8 @@ static void spi_test_next_stage(struct test_info *test)
* @param vbuf Verification buffer
* @return 0 if ok, -1 on error
*/
static int spi_flash_test(struct spi_flash *flash, char *buf, ulong len,
ulong offset, char *vbuf)
static int spi_flash_test(struct spi_flash *flash, uint8_t *buf, ulong len,
ulong offset, uint8_t *vbuf)
{
struct test_info test;
int i;
@ -431,9 +431,9 @@ static int do_spi_flash_test(int argc, char * const argv[])
{
unsigned long offset;
unsigned long len;
char *buf = (char *)CONFIG_SYS_TEXT_BASE;
uint8_t *buf = (uint8_t *)CONFIG_SYS_TEXT_BASE;
char *endp;
char *vbuf;
uint8_t *vbuf;
int ret;
offset = simple_strtoul(argv[1], &endp, 16);

View File

@ -480,15 +480,13 @@ struct spi_flash *spi_flash_probe_atmel(struct spi_slave *spi, u8 *idcode)
return NULL;
}
asf = malloc(sizeof(struct atmel_spi_flash));
asf = spi_flash_alloc(struct atmel_spi_flash, spi, params->name);
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;
@ -513,7 +511,6 @@ struct spi_flash *spi_flash_probe_atmel(struct spi_slave *spi, u8 *idcode)
asf->flash.erase = dataflash_erase_at45;
page_size += 1 << (params->l2_page_size - 5);
} else {
asf->flash.read = spi_flash_cmd_read_fast;
asf->flash.write = dataflash_write_p2;
asf->flash.erase = dataflash_erase_p2;
}
@ -524,9 +521,6 @@ struct spi_flash *spi_flash_probe_atmel(struct spi_slave *spi, u8 *idcode)
case DF_FAMILY_AT26F:
case DF_FAMILY_AT26DF:
asf->flash.read = spi_flash_cmd_read_fast;
asf->flash.write = spi_flash_cmd_write_multi;
asf->flash.erase = spi_flash_cmd_erase;
asf->flash.page_size = page_size;
asf->flash.sector_size = 4096;
/* clear SPRL# bit for locked flash */

View File

@ -46,18 +46,12 @@ struct spi_flash *spi_flash_probe_eon(struct spi_slave *spi, u8 *idcode)
return NULL;
}
flash = malloc(sizeof(*flash));
flash = spi_flash_alloc_base(spi, params->name);
if (!flash) {
debug("SF: Failed to allocate memory\n");
return NULL;
}
flash->spi = spi;
flash->name = params->name;
flash->write = spi_flash_cmd_write_multi;
flash->erase = spi_flash_cmd_erase;
flash->read = spi_flash_cmd_read_fast;
flash->page_size = 256;
flash->sector_size = 256 * 16 * 16;
flash->size = 256 * 16

View File

@ -97,18 +97,12 @@ struct spi_flash *spi_flash_probe_macronix(struct spi_slave *spi, u8 *idcode)
return NULL;
}
flash = malloc(sizeof(*flash));
flash = spi_flash_alloc_base(spi, params->name);
if (!flash) {
debug("SF: Failed to allocate memory\n");
return NULL;
}
flash->spi = spi;
flash->name = params->name;
flash->write = spi_flash_cmd_write_multi;
flash->erase = spi_flash_cmd_erase;
flash->read = spi_flash_cmd_read_fast;
flash->page_size = 256;
flash->sector_size = 256 * 16 * 16;
flash->size = flash->sector_size * params->nr_blocks;

View File

@ -284,15 +284,13 @@ struct spi_flash *spi_fram_probe_ramtron(struct spi_slave *spi, u8 *idcode)
return NULL;
found:
sn = malloc(sizeof(*sn));
sn = spi_flash_alloc(struct ramtron_spi_fram, spi, params->name);
if (!sn) {
debug("SF: Failed to allocate memory\n");
return NULL;
}
sn->params = params;
sn->flash.spi = spi;
sn->flash.name = params->name;
sn->flash.write = ramtron_write;
sn->flash.read = ramtron_read;

View File

@ -128,18 +128,12 @@ struct spi_flash *spi_flash_probe_spansion(struct spi_slave *spi, u8 *idcode)
return NULL;
}
flash = malloc(sizeof(*flash));
flash = spi_flash_alloc_base(spi, params->name);
if (!flash) {
debug("SF: Failed to allocate memory\n");
return NULL;
}
flash->spi = spi;
flash->name = params->name;
flash->write = spi_flash_cmd_write_multi;
flash->erase = spi_flash_cmd_erase;
flash->read = spi_flash_cmd_read_fast;
flash->page_size = 256;
flash->sector_size = 256 * params->pages_per_sector;
flash->size = flash->sector_size * params->nr_sectors;

View File

@ -8,6 +8,7 @@
*/
#include <common.h>
#include <fdtdec.h>
#include <malloc.h>
#include <spi.h>
#include <spi_flash.h>
@ -15,6 +16,8 @@
#include "spi_flash_internal.h"
DECLARE_GLOBAL_DATA_PTR;
static void spi_flash_addr(u32 addr, u8 *cmd)
{
/* cmd[0] is actual command */
@ -87,6 +90,9 @@ int spi_flash_cmd_write_multi(struct spi_flash *flash, u32 offset,
for (actual = 0; actual < len; actual += chunk_len) {
chunk_len = min(len - actual, page_size - byte_addr);
if (flash->spi->max_write_size)
chunk_len = min(chunk_len, flash->spi->max_write_size);
cmd[1] = page_addr >> 8;
cmd[2] = page_addr;
cmd[3] = byte_addr;
@ -111,8 +117,11 @@ int spi_flash_cmd_write_multi(struct spi_flash *flash, u32 offset,
if (ret)
break;
page_addr++;
byte_addr = 0;
byte_addr += chunk_len;
if (byte_addr == page_size) {
page_addr++;
byte_addr = 0;
}
}
debug("SF: program %s %zu bytes @ %#x\n",
@ -140,6 +149,10 @@ int spi_flash_cmd_read_fast(struct spi_flash *flash, u32 offset,
{
u8 cmd[5];
/* Handle memory-mapped SPI */
if (flash->memory_map)
memcpy(data, flash->memory_map + offset, len);
cmd[0] = CMD_READ_ARRAY_FAST;
spi_flash_addr(offset, cmd);
cmd[4] = 0x00;
@ -269,6 +282,34 @@ int spi_flash_cmd_write_status(struct spi_flash *flash, u8 sr)
return 0;
}
#ifdef CONFIG_OF_CONTROL
int spi_flash_decode_fdt(const void *blob, struct spi_flash *flash)
{
fdt_addr_t addr;
fdt_size_t size;
int node;
/* If there is no node, do nothing */
node = fdtdec_next_compatible(blob, 0, COMPAT_GENERIC_SPI_FLASH);
if (node < 0)
return 0;
addr = fdtdec_get_addr_size(blob, node, "memory-map", &size);
if (addr == FDT_ADDR_T_NONE) {
debug("%s: Cannot decode address\n", __func__);
return 0;
}
if (flash->size != size) {
debug("%s: Memory map must cover entire device\n", __func__);
return -1;
}
flash->memory_map = (void *)addr;
return 0;
}
#endif /* CONFIG_OF_CONTROL */
/*
* The following table holds all device probe functions
*
@ -385,9 +426,18 @@ struct spi_flash *spi_flash_probe(unsigned int bus, unsigned int cs,
goto err_manufacturer_probe;
}
#ifdef CONFIG_OF_CONTROL
if (spi_flash_decode_fdt(gd->fdt_blob, flash)) {
debug("SF: FDT decode error\n");
goto err_manufacturer_probe;
}
#endif
printf("SF: Detected %s with page size ", flash->name);
print_size(flash->sector_size, ", total ");
print_size(flash->size, "\n");
print_size(flash->size, "");
if (flash->memory_map)
printf(", mapped at %p", flash->memory_map);
puts("\n");
spi_release_bus(spi);
@ -401,6 +451,31 @@ err_claim_bus:
return NULL;
}
void *spi_flash_do_alloc(int offset, int size, struct spi_slave *spi,
const char *name)
{
struct spi_flash *flash;
void *ptr;
ptr = malloc(size);
if (!ptr) {
debug("SF: Failed to allocate memory\n");
return NULL;
}
memset(ptr, '\0', size);
flash = (struct spi_flash *)(ptr + offset);
/* Set up some basic fields - caller will sort out sizes */
flash->spi = spi;
flash->name = name;
flash->read = spi_flash_cmd_read_fast;
flash->write = spi_flash_cmd_write_multi;
flash->erase = spi_flash_cmd_erase;
return flash;
}
void spi_flash_free(struct spi_flash *flash)
{
spi_free_slave(flash->spi);

View File

@ -203,22 +203,16 @@ spi_flash_probe_sst(struct spi_slave *spi, u8 *idcode)
return NULL;
}
stm = malloc(sizeof(*stm));
stm = spi_flash_alloc(struct sst_spi_flash, spi, params->name);
if (!stm) {
debug("SF: Failed to allocate memory\n");
return NULL;
}
stm->params = params;
stm->flash.spi = spi;
stm->flash.name = params->name;
if (stm->params->flags & SST_FEAT_WP)
stm->flash.write = sst_write_wp;
else
stm->flash.write = spi_flash_cmd_write_multi;
stm->flash.erase = spi_flash_cmd_erase;
stm->flash.read = spi_flash_cmd_read_fast;
stm->flash.page_size = 256;
stm->flash.sector_size = 4096;
stm->flash.size = stm->flash.sector_size * params->nr_sectors;

View File

@ -176,18 +176,12 @@ struct spi_flash *spi_flash_probe_stmicro(struct spi_slave *spi, u8 * idcode)
return NULL;
}
flash = malloc(sizeof(*flash));
flash = spi_flash_alloc_base(spi, params->name);
if (!flash) {
debug("SF: Failed to allocate memory\n");
return NULL;
}
flash->spi = spi;
flash->name = params->name;
flash->write = spi_flash_cmd_write_multi;
flash->erase = spi_flash_cmd_erase;
flash->read = spi_flash_cmd_read_fast;
flash->page_size = 256;
flash->sector_size = 256 * params->pages_per_sector;
flash->size = flash->sector_size * params->nr_sectors;

View File

@ -92,18 +92,12 @@ struct spi_flash *spi_flash_probe_winbond(struct spi_slave *spi, u8 *idcode)
return NULL;
}
flash = malloc(sizeof(*flash));
flash = spi_flash_alloc_base(spi, params->name);
if (!flash) {
debug("SF: Failed to allocate memory\n");
return NULL;
}
flash->spi = spi;
flash->name = params->name;
flash->write = spi_flash_cmd_write_multi;
flash->erase = spi_flash_cmd_erase;
flash->read = spi_flash_cmd_read_fast;
flash->page_size = 256;
flash->sector_size = 4096;
flash->size = 4096 * 16 * params->nr_blocks;

View File

@ -25,6 +25,9 @@ include $(TOPDIR)/config.mk
LIB := $(obj)libspi.o
# There are many options which enable SPI, so make this library available
COBJS-y += spi.o
COBJS-$(CONFIG_ALTERA_SPI) += altera_spi.o
COBJS-$(CONFIG_ANDES_SPI) += andes_spi.o
COBJS-$(CONFIG_ARMADA100_SPI) += armada100_spi.o
@ -36,6 +39,7 @@ COBJS-$(CONFIG_CF_SPI) += cf_spi.o
COBJS-$(CONFIG_CF_QSPI) += cf_qspi.o
COBJS-$(CONFIG_DAVINCI_SPI) += davinci_spi.o
COBJS-$(CONFIG_EXYNOS_SPI) += exynos_spi.o
COBJS-$(CONFIG_ICH_SPI) += ich.o
COBJS-$(CONFIG_KIRKWOOD_SPI) += kirkwood_spi.o
COBJS-$(CONFIG_MPC52XX_SPI) += mpc52xx_spi.o
COBJS-$(CONFIG_MPC8XXX_SPI) += mpc8xxx_spi.o

View File

@ -83,12 +83,10 @@ struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
if (!spi_cs_is_valid(bus, cs))
return NULL;
altspi = malloc(sizeof(*altspi));
altspi = spi_alloc_slave(struct altera_spi_slave, bus, cs);
if (!altspi)
return NULL;
altspi->slave.bus = bus;
altspi->slave.cs = cs;
altspi->base = altera_spi_base_list[bus];
debug("%s: bus:%i cs:%i base:%lx\n", __func__,
bus, cs, altspi->base);

View File

@ -53,12 +53,10 @@ struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
if (!spi_cs_is_valid(bus, cs))
return NULL;
ds = malloc(sizeof(*ds));
ds = spi_alloc_slave(struct andes_spi_slave, bus, cs);
if (!ds)
return NULL;
ds->slave.bus = bus;
ds->slave.cs = cs;
ds->regs = (struct andes_spi_regs *)CONFIG_SYS_SPI_BASE;
/*

View File

@ -120,12 +120,10 @@ struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
{
struct armd_spi_slave *pss;
pss = malloc(sizeof(*pss));
pss = spi_alloc_slave(struct armd_spi_slave, bus, cs);
if (!pss)
return NULL;
pss->slave.bus = bus;
pss->slave.cs = cs;
pss->spi_reg = (struct ssp_reg *)SSP_REG_BASE(CONFIG_SYS_SSP_PORT);
pss->cr0 = SSCR0_MOTO | SSCR0_DATASIZE(DEFAULT_WORD_LEN) | SSCR0_SSE;

View File

@ -84,12 +84,10 @@ struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
if (mode & SPI_CPOL)
csrx |= ATMEL_SPI_CSRx_CPOL;
as = malloc(sizeof(struct atmel_spi_slave));
as = spi_alloc_slave(struct atmel_spi_slave, bus, cs);
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
#if defined(CONFIG_AT91SAM9X5) || defined(CONFIG_AT91SAM9M10G45)

View File

@ -182,12 +182,10 @@ struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
default: return NULL;
}
bss = malloc(sizeof(*bss));
bss = spi_alloc_slave(struct bfin_spi_slave, bus, cs);
if (!bss)
return NULL;
bss->slave.bus = bus;
bss->slave.cs = cs;
bss->mmr_base = (void *)mmr_base;
bss->ctl = SPE | MSTR | TDBR_CORE;
if (mode & SPI_CPHA) bss->ctl |= CPHA;

View File

@ -178,12 +178,10 @@ struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
return NULL;
}
bss = malloc(sizeof(*bss));
bss = spi_alloc_slave(struct bfin_spi_slave, bus, cs);
if (!bss)
return NULL;
bss->slave.bus = bus;
bss->slave.cs = cs;
bss->regs = (struct bfin_spi_regs *)reg_base;
bss->control = SPI_CTL_EN | SPI_CTL_MSTR;
if (mode & SPI_CPHA)

View File

@ -120,13 +120,11 @@ struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
if (!spi_cs_is_valid(bus, cs))
return NULL;
dev = malloc(sizeof(struct cf_qspi_slave));
dev = spi_alloc_slave(struct cf_qspi_slave, bus, cs);
if (!dev)
return NULL;
/* Initialize to known value */
dev->slave.bus = bus;
dev->slave.cs = cs;
dev->regs = (qspi_t *)MMAP_QSPI;
dev->qmr = 0;
dev->qwr = 0;

View File

@ -330,12 +330,10 @@ struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
if (!spi_cs_is_valid(bus, cs))
return NULL;
cfslave = malloc(sizeof(struct cf_spi_slave));
cfslave = spi_alloc_slave(struct cf_spi_slave, bus, cs);
if (!cfslave)
return NULL;
cfslave->slave.bus = bus;
cfslave->slave.cs = cs;
cfslave->baudrate = max_hz;
/* specific setup */

View File

@ -44,12 +44,10 @@ struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
if (!spi_cs_is_valid(bus, cs))
return NULL;
ds = malloc(sizeof(*ds));
ds = spi_alloc_slave(struct davinci_spi_slave, bus, cs);
if (!ds)
return NULL;
ds->slave.bus = bus;
ds->slave.cs = cs;
ds->regs = (struct davinci_spi_regs *)CONFIG_SYS_SPI_BASE;
ds->freq = max_hz;

View File

@ -89,15 +89,13 @@ struct spi_slave *spi_setup_slave(unsigned int busnum, unsigned int cs,
return NULL;
}
spi_slave = malloc(sizeof(*spi_slave));
spi_slave = spi_alloc_slave(struct exynos_spi_slave, busnum, cs);
if (!spi_slave) {
debug("%s: Could not allocate spi_slave\n", __func__);
return NULL;
}
bus = &spi_bus[busnum];
spi_slave->slave.bus = busnum;
spi_slave->slave.cs = cs;
spi_slave->regs = bus->regs;
spi_slave->mode = mode;
spi_slave->periph_id = bus->periph_id;

View File

@ -79,12 +79,10 @@ struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
if (!spi_cs_is_valid(bus, cs))
return NULL;
fsl = malloc(sizeof(struct fsl_spi_slave));
fsl = spi_alloc_slave(struct fsl_spi_slave, bus, cs);
if (!fsl)
return NULL;
fsl->slave.bus = bus;
fsl->slave.cs = cs;
fsl->mode = mode;
fsl->max_transfer_length = ESPI_MAX_DATA_TRANSFER_LEN;

754
drivers/spi/ich.c Normal file
View File

@ -0,0 +1,754 @@
/*
* Copyright (c) 2011-12 The Chromium OS Authors.
*
* 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
*
* This file is derived from the flashrom project.
*/
#include <common.h>
#include <malloc.h>
#include <spi.h>
#include <pci.h>
#include <pci_ids.h>
#include <asm/io.h>
#include "ich.h"
#define SPI_OPCODE_WREN 0x06
#define SPI_OPCODE_FAST_READ 0x0b
struct ich_ctlr {
pci_dev_t dev; /* PCI device number */
int ich_version; /* Controller version, 7 or 9 */
int ichspi_lock;
int locked;
uint8_t *opmenu;
int menubytes;
void *base; /* Base of register set */
uint16_t *preop;
uint16_t *optype;
uint32_t *addr;
uint8_t *data;
unsigned databytes;
uint8_t *status;
uint16_t *control;
uint32_t *bbar;
uint32_t *pr; /* only for ich9 */
uint8_t *speed; /* pointer to speed control */
ulong max_speed; /* Maximum bus speed in MHz */
};
struct ich_ctlr ctlr;
static inline struct ich_spi_slave *to_ich_spi(struct spi_slave *slave)
{
return container_of(slave, struct ich_spi_slave, slave);
}
static unsigned int ich_reg(const void *addr)
{
return (unsigned)(addr - ctlr.base) & 0xffff;
}
static u8 ich_readb(const void *addr)
{
u8 value = readb(addr);
debug("read %2.2x from %4.4x\n", value, ich_reg(addr));
return value;
}
static u16 ich_readw(const void *addr)
{
u16 value = readw(addr);
debug("read %4.4x from %4.4x\n", value, ich_reg(addr));
return value;
}
static u32 ich_readl(const void *addr)
{
u32 value = readl(addr);
debug("read %8.8x from %4.4x\n", value, ich_reg(addr));
return value;
}
static void ich_writeb(u8 value, void *addr)
{
writeb(value, addr);
debug("wrote %2.2x to %4.4x\n", value, ich_reg(addr));
}
static void ich_writew(u16 value, void *addr)
{
writew(value, addr);
debug("wrote %4.4x to %4.4x\n", value, ich_reg(addr));
}
static void ich_writel(u32 value, void *addr)
{
writel(value, addr);
debug("wrote %8.8x to %4.4x\n", value, ich_reg(addr));
}
static void write_reg(const void *value, void *dest, uint32_t size)
{
memcpy_toio(dest, value, size);
}
static void read_reg(const void *src, void *value, uint32_t size)
{
memcpy_fromio(value, src, size);
}
static void ich_set_bbar(struct ich_ctlr *ctlr, uint32_t minaddr)
{
const uint32_t bbar_mask = 0x00ffff00;
uint32_t ichspi_bbar;
minaddr &= bbar_mask;
ichspi_bbar = ich_readl(ctlr->bbar) & ~bbar_mask;
ichspi_bbar |= minaddr;
ich_writel(ichspi_bbar, ctlr->bbar);
}
int spi_cs_is_valid(unsigned int bus, unsigned int cs)
{
puts("spi_cs_is_valid used but not implemented\n");
return 0;
}
struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
unsigned int max_hz, unsigned int mode)
{
struct ich_spi_slave *ich;
ich = spi_alloc_slave(struct ich_spi_slave, bus, cs);
if (!ich) {
puts("ICH SPI: Out of memory\n");
return NULL;
}
/*
* Yes this controller can only write a small number of bytes at
* once! The limit is typically 64 bytes.
*/
ich->slave.max_write_size = ctlr.databytes;
ich->speed = max_hz;
return &ich->slave;
}
void spi_free_slave(struct spi_slave *slave)
{
struct ich_spi_slave *ich = to_ich_spi(slave);
free(ich);
}
/*
* Check if this device ID matches one of supported Intel PCH devices.
*
* Return the ICH version if there is a match, or zero otherwise.
*/
static int get_ich_version(uint16_t device_id)
{
if (device_id == PCI_DEVICE_ID_INTEL_TGP_LPC)
return 7;
if ((device_id >= PCI_DEVICE_ID_INTEL_COUGARPOINT_LPC_MIN &&
device_id <= PCI_DEVICE_ID_INTEL_COUGARPOINT_LPC_MAX) ||
(device_id >= PCI_DEVICE_ID_INTEL_PANTHERPOINT_LPC_MIN &&
device_id <= PCI_DEVICE_ID_INTEL_PANTHERPOINT_LPC_MAX))
return 9;
return 0;
}
/* @return 1 if the SPI flash supports the 33MHz speed */
static int ich9_can_do_33mhz(pci_dev_t dev)
{
u32 fdod, speed;
/* Observe SPI Descriptor Component Section 0 */
pci_write_config_dword(dev, 0xb0, 0x1000);
/* Extract the Write/Erase SPI Frequency from descriptor */
pci_read_config_dword(dev, 0xb4, &fdod);
/* Bits 23:21 have the fast read clock frequency, 0=20MHz, 1=33MHz */
speed = (fdod >> 21) & 7;
return speed == 1;
}
static int ich_find_spi_controller(pci_dev_t *devp, int *ich_versionp)
{
int last_bus = pci_last_busno();
int bus;
if (last_bus == -1) {
debug("No PCI busses?\n");
return -1;
}
for (bus = 0; bus <= last_bus; bus++) {
uint16_t vendor_id, device_id;
uint32_t ids;
pci_dev_t dev;
dev = PCI_BDF(bus, 31, 0);
pci_read_config_dword(dev, 0, &ids);
vendor_id = ids;
device_id = ids >> 16;
if (vendor_id == PCI_VENDOR_ID_INTEL) {
*devp = dev;
*ich_versionp = get_ich_version(device_id);
return 0;
}
}
debug("ICH SPI: No ICH found.\n");
return -1;
}
static int ich_init_controller(struct ich_ctlr *ctlr)
{
uint8_t *rcrb; /* Root Complex Register Block */
uint32_t rcba; /* Root Complex Base Address */
pci_read_config_dword(ctlr->dev, 0xf0, &rcba);
/* Bits 31-14 are the base address, 13-1 are reserved, 0 is enable. */
rcrb = (uint8_t *)(rcba & 0xffffc000);
if (ctlr->ich_version == 7) {
struct ich7_spi_regs *ich7_spi;
ich7_spi = (struct ich7_spi_regs *)(rcrb + 0x3020);
ctlr->ichspi_lock = ich_readw(&ich7_spi->spis) & SPIS_LOCK;
ctlr->opmenu = ich7_spi->opmenu;
ctlr->menubytes = sizeof(ich7_spi->opmenu);
ctlr->optype = &ich7_spi->optype;
ctlr->addr = &ich7_spi->spia;
ctlr->data = (uint8_t *)ich7_spi->spid;
ctlr->databytes = sizeof(ich7_spi->spid);
ctlr->status = (uint8_t *)&ich7_spi->spis;
ctlr->control = &ich7_spi->spic;
ctlr->bbar = &ich7_spi->bbar;
ctlr->preop = &ich7_spi->preop;
ctlr->base = ich7_spi;
} else if (ctlr->ich_version == 9) {
struct ich9_spi_regs *ich9_spi;
ich9_spi = (struct ich9_spi_regs *)(rcrb + 0x3800);
ctlr->ichspi_lock = ich_readw(&ich9_spi->hsfs) & HSFS_FLOCKDN;
ctlr->opmenu = ich9_spi->opmenu;
ctlr->menubytes = sizeof(ich9_spi->opmenu);
ctlr->optype = &ich9_spi->optype;
ctlr->addr = &ich9_spi->faddr;
ctlr->data = (uint8_t *)ich9_spi->fdata;
ctlr->databytes = sizeof(ich9_spi->fdata);
ctlr->status = &ich9_spi->ssfs;
ctlr->control = (uint16_t *)ich9_spi->ssfc;
ctlr->speed = ich9_spi->ssfc + 2;
ctlr->bbar = &ich9_spi->bbar;
ctlr->preop = &ich9_spi->preop;
ctlr->pr = &ich9_spi->pr[0];
ctlr->base = ich9_spi;
} else {
debug("ICH SPI: Unrecognized ICH version %d.\n",
ctlr->ich_version);
return -1;
}
debug("ICH SPI: Version %d detected\n", ctlr->ich_version);
/* Work out the maximum speed we can support */
ctlr->max_speed = 20000000;
if (ctlr->ich_version == 9 && ich9_can_do_33mhz(ctlr->dev))
ctlr->max_speed = 33000000;
ich_set_bbar(ctlr, 0);
return 0;
}
void spi_init(void)
{
uint8_t bios_cntl;
if (ich_find_spi_controller(&ctlr.dev, &ctlr.ich_version)) {
printf("ICH SPI: Cannot find device\n");
return;
}
if (ich_init_controller(&ctlr)) {
printf("ICH SPI: Cannot setup controller\n");
return;
}
/*
* Disable the BIOS write protect so write commands are allowed. On
* v9, deassert SMM BIOS Write Protect Disable.
*/
pci_read_config_byte(ctlr.dev, 0xdc, &bios_cntl);
if (ctlr.ich_version == 9)
bios_cntl &= ~(1 << 5);
pci_write_config_byte(ctlr.dev, 0xdc, bios_cntl | 0x1);
}
int spi_claim_bus(struct spi_slave *slave)
{
/* Handled by ICH automatically. */
return 0;
}
void spi_release_bus(struct spi_slave *slave)
{
/* Handled by ICH automatically. */
}
void spi_cs_activate(struct spi_slave *slave)
{
/* Handled by ICH automatically. */
}
void spi_cs_deactivate(struct spi_slave *slave)
{
/* Handled by ICH automatically. */
}
static inline void spi_use_out(struct spi_trans *trans, unsigned bytes)
{
trans->out += bytes;
trans->bytesout -= bytes;
}
static inline void spi_use_in(struct spi_trans *trans, unsigned bytes)
{
trans->in += bytes;
trans->bytesin -= bytes;
}
static void spi_setup_type(struct spi_trans *trans, int data_bytes)
{
trans->type = 0xFF;
/* Try to guess spi type from read/write sizes. */
if (trans->bytesin == 0) {
if (trans->bytesout + data_bytes > 4)
/*
* If bytesin = 0 and bytesout > 4, we presume this is
* a write data operation, which is accompanied by an
* address.
*/
trans->type = SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS;
else
trans->type = SPI_OPCODE_TYPE_WRITE_NO_ADDRESS;
return;
}
if (trans->bytesout == 1) { /* and bytesin is > 0 */
trans->type = SPI_OPCODE_TYPE_READ_NO_ADDRESS;
return;
}
if (trans->bytesout == 4) /* and bytesin is > 0 */
trans->type = SPI_OPCODE_TYPE_READ_WITH_ADDRESS;
/* Fast read command is called with 5 bytes instead of 4 */
if (trans->out[0] == SPI_OPCODE_FAST_READ && trans->bytesout == 5) {
trans->type = SPI_OPCODE_TYPE_READ_WITH_ADDRESS;
--trans->bytesout;
}
}
static int spi_setup_opcode(struct spi_trans *trans)
{
uint16_t optypes;
uint8_t opmenu[ctlr.menubytes];
trans->opcode = trans->out[0];
spi_use_out(trans, 1);
if (!ctlr.ichspi_lock) {
/* The lock is off, so just use index 0. */
ich_writeb(trans->opcode, ctlr.opmenu);
optypes = ich_readw(ctlr.optype);
optypes = (optypes & 0xfffc) | (trans->type & 0x3);
ich_writew(optypes, ctlr.optype);
return 0;
} else {
/* The lock is on. See if what we need is on the menu. */
uint8_t optype;
uint16_t opcode_index;
/* Write Enable is handled as atomic prefix */
if (trans->opcode == SPI_OPCODE_WREN)
return 0;
read_reg(ctlr.opmenu, opmenu, sizeof(opmenu));
for (opcode_index = 0; opcode_index < ctlr.menubytes;
opcode_index++) {
if (opmenu[opcode_index] == trans->opcode)
break;
}
if (opcode_index == ctlr.menubytes) {
printf("ICH SPI: Opcode %x not found\n",
trans->opcode);
return -1;
}
optypes = ich_readw(ctlr.optype);
optype = (optypes >> (opcode_index * 2)) & 0x3;
if (trans->type == SPI_OPCODE_TYPE_WRITE_NO_ADDRESS &&
optype == SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS &&
trans->bytesout >= 3) {
/* We guessed wrong earlier. Fix it up. */
trans->type = optype;
}
if (optype != trans->type) {
printf("ICH SPI: Transaction doesn't fit type %d\n",
optype);
return -1;
}
return opcode_index;
}
}
static int spi_setup_offset(struct spi_trans *trans)
{
/* Separate the SPI address and data. */
switch (trans->type) {
case SPI_OPCODE_TYPE_READ_NO_ADDRESS:
case SPI_OPCODE_TYPE_WRITE_NO_ADDRESS:
return 0;
case SPI_OPCODE_TYPE_READ_WITH_ADDRESS:
case SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS:
trans->offset = ((uint32_t)trans->out[0] << 16) |
((uint32_t)trans->out[1] << 8) |
((uint32_t)trans->out[2] << 0);
spi_use_out(trans, 3);
return 1;
default:
printf("Unrecognized SPI transaction type %#x\n", trans->type);
return -1;
}
}
/*
* Wait for up to 6s til status register bit(s) turn 1 (in case wait_til_set
* below is True) or 0. In case the wait was for the bit(s) to set - write
* those bits back, which would cause resetting them.
*
* Return the last read status value on success or -1 on failure.
*/
static int ich_status_poll(u16 bitmask, int wait_til_set)
{
int timeout = 600000; /* This will result in 6s */
u16 status = 0;
while (timeout--) {
status = ich_readw(ctlr.status);
if (wait_til_set ^ ((status & bitmask) == 0)) {
if (wait_til_set)
ich_writew((status & bitmask), ctlr.status);
return status;
}
udelay(10);
}
printf("ICH SPI: SCIP timeout, read %x, expected %x\n",
status, bitmask);
return -1;
}
/*
int spi_xfer(struct spi_slave *slave, const void *dout,
unsigned int bitsout, void *din, unsigned int bitsin)
*/
int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout,
void *din, unsigned long flags)
{
struct ich_spi_slave *ich = to_ich_spi(slave);
uint16_t control;
int16_t opcode_index;
int with_address;
int status;
int bytes = bitlen / 8;
struct spi_trans *trans = &ich->trans;
unsigned type = flags & (SPI_XFER_BEGIN | SPI_XFER_END);
int using_cmd = 0;
/* Align read transactions to 64-byte boundaries */
char buff[ctlr.databytes];
/* Ee don't support writing partial bytes. */
if (bitlen % 8) {
debug("ICH SPI: Accessing partial bytes not supported\n");
return -1;
}
/* An empty end transaction can be ignored */
if (type == SPI_XFER_END && !dout && !din)
return 0;
if (type & SPI_XFER_BEGIN)
memset(trans, '\0', sizeof(*trans));
/* Dp we need to come back later to finish it? */
if (dout && type == SPI_XFER_BEGIN) {
if (bytes > ICH_MAX_CMD_LEN) {
debug("ICH SPI: Command length limit exceeded\n");
return -1;
}
memcpy(trans->cmd, dout, bytes);
trans->cmd_len = bytes;
debug("ICH SPI: Saved %d bytes\n", bytes);
return 0;
}
/*
* We process a 'middle' spi_xfer() call, which has no
* SPI_XFER_BEGIN/END, as an independent transaction as if it had
* an end. We therefore repeat the command. This is because ICH
* seems to have no support for this, or because interest (in digging
* out the details and creating a special case in the code) is low.
*/
if (trans->cmd_len) {
trans->out = trans->cmd;
trans->bytesout = trans->cmd_len;
using_cmd = 1;
debug("ICH SPI: Using %d bytes\n", trans->cmd_len);
} else {
trans->out = dout;
trans->bytesout = dout ? bytes : 0;
}
trans->in = din;
trans->bytesin = din ? bytes : 0;
/* There has to always at least be an opcode. */
if (!trans->bytesout) {
debug("ICH SPI: No opcode for transfer\n");
return -1;
}
if (ich_status_poll(SPIS_SCIP, 0) == -1)
return -1;
ich_writew(SPIS_CDS | SPIS_FCERR, ctlr.status);
spi_setup_type(trans, using_cmd ? bytes : 0);
opcode_index = spi_setup_opcode(trans);
if (opcode_index < 0)
return -1;
with_address = spi_setup_offset(trans);
if (with_address < 0)
return -1;
if (trans->opcode == SPI_OPCODE_WREN) {
/*
* Treat Write Enable as Atomic Pre-Op if possible
* in order to prevent the Management Engine from
* issuing a transaction between WREN and DATA.
*/
if (!ctlr.ichspi_lock)
ich_writew(trans->opcode, ctlr.preop);
return 0;
}
if (ctlr.speed && ctlr.max_speed >= 33000000) {
int byte;
byte = ich_readb(ctlr.speed);
if (ich->speed >= 33000000)
byte |= SSFC_SCF_33MHZ;
else
byte &= ~SSFC_SCF_33MHZ;
ich_writeb(byte, ctlr.speed);
}
/* See if we have used up the command data */
if (using_cmd && dout && bytes) {
trans->out = dout;
trans->bytesout = bytes;
debug("ICH SPI: Moving to data, %d bytes\n", bytes);
}
/* Preset control fields */
control = ich_readw(ctlr.control);
control &= ~SSFC_RESERVED;
control = SPIC_SCGO | ((opcode_index & 0x07) << 4);
/* Issue atomic preop cycle if needed */
if (ich_readw(ctlr.preop))
control |= SPIC_ACS;
if (!trans->bytesout && !trans->bytesin) {
/* SPI addresses are 24 bit only */
if (with_address)
ich_writel(trans->offset & 0x00FFFFFF, ctlr.addr);
/*
* This is a 'no data' command (like Write Enable), its
* bitesout size was 1, decremented to zero while executing
* spi_setup_opcode() above. Tell the chip to send the
* command.
*/
ich_writew(control, ctlr.control);
/* wait for the result */
status = ich_status_poll(SPIS_CDS | SPIS_FCERR, 1);
if (status == -1)
return -1;
if (status & SPIS_FCERR) {
debug("ICH SPI: Command transaction error\n");
return -1;
}
return 0;
}
/*
* Check if this is a write command atempting to transfer more bytes
* than the controller can handle. Iterations for writes are not
* supported here because each SPI write command needs to be preceded
* and followed by other SPI commands, and this sequence is controlled
* by the SPI chip driver.
*/
if (trans->bytesout > ctlr.databytes) {
debug("ICH SPI: Too much to write. This should be prevented by the driver's max_write_size?\n");
return -1;
}
/*
* Read or write up to databytes bytes at a time until everything has
* been sent.
*/
while (trans->bytesout || trans->bytesin) {
uint32_t data_length;
uint32_t aligned_offset;
uint32_t diff;
aligned_offset = trans->offset & ~(ctlr.databytes - 1);
diff = trans->offset - aligned_offset;
/* SPI addresses are 24 bit only */
ich_writel(aligned_offset & 0x00FFFFFF, ctlr.addr);
if (trans->bytesout)
data_length = min(trans->bytesout, ctlr.databytes);
else
data_length = min(trans->bytesin, ctlr.databytes);
/* Program data into FDATA0 to N */
if (trans->bytesout) {
write_reg(trans->out, ctlr.data, data_length);
spi_use_out(trans, data_length);
if (with_address)
trans->offset += data_length;
}
/* Add proper control fields' values */
control &= ~((ctlr.databytes - 1) << 8);
control |= SPIC_DS;
control |= (data_length - 1) << 8;
/* write it */
ich_writew(control, ctlr.control);
/* Wait for Cycle Done Status or Flash Cycle Error. */
status = ich_status_poll(SPIS_CDS | SPIS_FCERR, 1);
if (status == -1)
return -1;
if (status & SPIS_FCERR) {
debug("ICH SPI: Data transaction error\n");
return -1;
}
if (trans->bytesin) {
if (diff) {
data_length -= diff;
read_reg(ctlr.data, buff, ctlr.databytes);
memcpy(trans->in, buff + diff, data_length);
} else {
read_reg(ctlr.data, trans->in, data_length);
}
spi_use_in(trans, data_length);
if (with_address)
trans->offset += data_length;
}
}
/* Clear atomic preop now that xfer is done */
ich_writew(0, ctlr.preop);
return 0;
}
/*
* This uses the SPI controller from the Intel Cougar Point and Panther Point
* PCH to write-protect portions of the SPI flash until reboot. The changes
* don't actually take effect until the HSFS[FLOCKDN] bit is set, but that's
* done elsewhere.
*/
int spi_write_protect_region(uint32_t lower_limit, uint32_t length, int hint)
{
uint32_t tmplong;
uint32_t upper_limit;
if (!ctlr.pr) {
printf("%s: operation not supported on this chipset\n",
__func__);
return -1;
}
if (length == 0 ||
lower_limit > (0xFFFFFFFFUL - length) + 1 ||
hint < 0 || hint > 4) {
printf("%s(0x%x, 0x%x, %d): invalid args\n", __func__,
lower_limit, length, hint);
return -1;
}
upper_limit = lower_limit + length - 1;
/*
* Determine bits to write, as follows:
* 31 Write-protection enable (includes erase operation)
* 30:29 reserved
* 28:16 Upper Limit (FLA address bits 24:12, with 11:0 == 0xfff)
* 15 Read-protection enable
* 14:13 reserved
* 12:0 Lower Limit (FLA address bits 24:12, with 11:0 == 0x000)
*/
tmplong = 0x80000000 |
((upper_limit & 0x01fff000) << 4) |
((lower_limit & 0x01fff000) >> 12);
printf("%s: writing 0x%08x to %p\n", __func__, tmplong,
&ctlr.pr[hint]);
ctlr.pr[hint] = tmplong;
return 0;
}

143
drivers/spi/ich.h Normal file
View File

@ -0,0 +1,143 @@
/*
* Copyright (c) 2011 The Chromium OS Authors.
*
* 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
*
* This file is derived from the flashrom project.
*/
struct ich7_spi_regs {
uint16_t spis;
uint16_t spic;
uint32_t spia;
uint64_t spid[8];
uint64_t _pad;
uint32_t bbar;
uint16_t preop;
uint16_t optype;
uint8_t opmenu[8];
} __packed;
struct ich9_spi_regs {
uint32_t bfpr; /* 0x00 */
uint16_t hsfs;
uint16_t hsfc;
uint32_t faddr;
uint32_t _reserved0;
uint32_t fdata[16]; /* 0x10 */
uint32_t frap; /* 0x50 */
uint32_t freg[5];
uint32_t _reserved1[3];
uint32_t pr[5]; /* 0x74 */
uint32_t _reserved2[2];
uint8_t ssfs; /* 0x90 */
uint8_t ssfc[3];
uint16_t preop; /* 0x94 */
uint16_t optype;
uint8_t opmenu[8]; /* 0x98 */
uint32_t bbar;
uint8_t _reserved3[12];
uint32_t fdoc;
uint32_t fdod;
uint8_t _reserved4[8];
uint32_t afc;
uint32_t lvscc;
uint32_t uvscc;
uint8_t _reserved5[4];
uint32_t fpb;
uint8_t _reserved6[28];
uint32_t srdl;
uint32_t srdc;
uint32_t srd;
} __packed;
enum {
SPIS_SCIP = 0x0001,
SPIS_GRANT = 0x0002,
SPIS_CDS = 0x0004,
SPIS_FCERR = 0x0008,
SSFS_AEL = 0x0010,
SPIS_LOCK = 0x8000,
SPIS_RESERVED_MASK = 0x7ff0,
SSFS_RESERVED_MASK = 0x7fe2
};
enum {
SPIC_SCGO = 0x000002,
SPIC_ACS = 0x000004,
SPIC_SPOP = 0x000008,
SPIC_DBC = 0x003f00,
SPIC_DS = 0x004000,
SPIC_SME = 0x008000,
SSFC_SCF_MASK = 0x070000,
SSFC_RESERVED = 0xf80000,
/* Mask for speed byte, biuts 23:16 of SSFC */
SSFC_SCF_33MHZ = 0x01,
};
enum {
HSFS_FDONE = 0x0001,
HSFS_FCERR = 0x0002,
HSFS_AEL = 0x0004,
HSFS_BERASE_MASK = 0x0018,
HSFS_BERASE_SHIFT = 3,
HSFS_SCIP = 0x0020,
HSFS_FDOPSS = 0x2000,
HSFS_FDV = 0x4000,
HSFS_FLOCKDN = 0x8000
};
enum {
HSFC_FGO = 0x0001,
HSFC_FCYCLE_MASK = 0x0006,
HSFC_FCYCLE_SHIFT = 1,
HSFC_FDBC_MASK = 0x3f00,
HSFC_FDBC_SHIFT = 8,
HSFC_FSMIE = 0x8000
};
enum {
SPI_OPCODE_TYPE_READ_NO_ADDRESS = 0,
SPI_OPCODE_TYPE_WRITE_NO_ADDRESS = 1,
SPI_OPCODE_TYPE_READ_WITH_ADDRESS = 2,
SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS = 3
};
enum {
ICH_MAX_CMD_LEN = 5,
};
struct spi_trans {
uint8_t cmd[ICH_MAX_CMD_LEN];
int cmd_len;
const uint8_t *out;
uint32_t bytesout;
uint8_t *in;
uint32_t bytesin;
uint8_t type;
uint8_t opcode;
uint32_t offset;
};
struct ich_spi_slave {
struct spi_slave slave;
struct spi_trans trans; /* current transaction in progress */
int speed; /* SPI speed in Hz */
};

View File

@ -49,13 +49,10 @@ struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
if (!spi_cs_is_valid(bus, cs))
return NULL;
slave = malloc(sizeof(struct spi_slave));
slave = spi_alloc_slave_base(bus, cs);
if (!slave)
return NULL;
slave->bus = bus;
slave->cs = cs;
writel(~KWSPI_CSN_ACT | KWSPI_SMEMRDY, &spireg->ctrl);
/* calculate spi clock prescaller using max_hz */

View File

@ -48,13 +48,10 @@ struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
{
struct spi_slave *slave;
slave = malloc(sizeof(struct spi_slave));
slave = spi_alloc_slave_base(bus, cs);
if (!slave)
return NULL;
slave->bus = bus;
slave->cs = cs;
return slave;
}

View File

@ -45,13 +45,10 @@ struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
if (!spi_cs_is_valid(bus, cs))
return NULL;
slave = malloc(sizeof(struct spi_slave));
slave = spi_alloc_slave_base(bus, cs);
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.

View File

@ -408,7 +408,7 @@ struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
if (bus >= ARRAY_SIZE(spi_bases))
return NULL;
mxcs = calloc(sizeof(struct mxc_spi_slave), 1);
mxcs = spi_alloc_slave(struct mxc_spi_slave, bus, cs);
if (!mxcs) {
puts("mxc_spi: SPI Slave not allocated !\n");
return NULL;
@ -424,8 +424,6 @@ struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
cs = ret;
mxcs->slave.bus = bus;
mxcs->slave.cs = cs;
mxcs->base = spi_bases[bus];
ret = spi_cfg_mxc(mxcs, cs, max_hz, mode);

View File

@ -77,15 +77,13 @@ struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
return NULL;
}
mxs_slave = calloc(sizeof(struct mxs_spi_slave), 1);
mxs_slave = spi_alloc_slave(struct mxs_spi_slave, bus, cs);
if (!mxs_slave)
return NULL;
if (mxs_dma_init_channel(MXS_DMA_CHANNEL_AHB_APBH_SSP0 + bus))
goto err_init;
mxs_slave->slave.bus = bus;
mxs_slave->slave.cs = cs;
mxs_slave->max_khz = max_hz / 1000;
mxs_slave->mode = mode;
mxs_slave->regs = mxs_ssp_regs_by_bus(bus);

View File

@ -90,13 +90,10 @@ struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
if (!spi_cs_is_valid(bus, cs) || gpio_request(cs, "tiny_spi"))
return NULL;
tiny_spi = malloc(sizeof(*tiny_spi));
tiny_spi = spi_alloc_slave(struct tiny_spi_slave, bus, cs);
if (!tiny_spi)
return NULL;
memset(tiny_spi, 0, sizeof(*tiny_spi));
tiny_spi->slave.bus = bus;
tiny_spi->slave.cs = cs;
tiny_spi->host = &tiny_spi_host_list[bus];
tiny_spi->mode = mode & (SPI_CPOL | SPI_CPHA);
tiny_spi->flg = mode & SPI_CS_HIGH ? 1 : 0;

View File

@ -80,12 +80,7 @@ struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
unsigned int max_hz, unsigned int mode)
{
struct omap3_spi_slave *ds;
ds = malloc(sizeof(struct omap3_spi_slave));
if (!ds) {
printf("SPI error: malloc of SPI structure failed\n");
return NULL;
}
struct mcspi *regs;
/*
* OMAP3 McSPI (MultiChannel SPI) has 4 busses (modules)
@ -98,21 +93,21 @@ struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
switch (bus) {
case 0:
ds->regs = (struct mcspi *)OMAP3_MCSPI1_BASE;
regs = (struct mcspi *)OMAP3_MCSPI1_BASE;
break;
#ifdef OMAP3_MCSPI2_BASE
case 1:
ds->regs = (struct mcspi *)OMAP3_MCSPI2_BASE;
regs = (struct mcspi *)OMAP3_MCSPI2_BASE;
break;
#endif
#ifdef OMAP3_MCSPI3_BASE
case 2:
ds->regs = (struct mcspi *)OMAP3_MCSPI3_BASE;
regs = (struct mcspi *)OMAP3_MCSPI3_BASE;
break;
#endif
#ifdef OMAP3_MCSPI4_BASE
case 3:
ds->regs = (struct mcspi *)OMAP3_MCSPI4_BASE;
regs = (struct mcspi *)OMAP3_MCSPI4_BASE;
break;
#endif
default:
@ -120,7 +115,6 @@ struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
Supported busses 0 - 3\n", bus);
return NULL;
}
ds->slave.bus = bus;
if (((bus == 0) && (cs > 3)) ||
((bus == 1) && (cs > 1)) ||
@ -130,19 +124,26 @@ struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
on bus %i\n", cs, bus);
return NULL;
}
ds->slave.cs = cs;
if (max_hz > OMAP3_MCSPI_MAX_FREQ) {
printf("SPI error: unsupported frequency %i Hz. \
Max frequency is 48 Mhz\n", max_hz);
return NULL;
}
ds->freq = max_hz;
if (mode > SPI_MODE_3) {
printf("SPI error: unsupported SPI mode %i\n", mode);
return NULL;
}
ds = spi_alloc_slave(struct omap3_spi_slave, bus, cs);
if (!ds) {
printf("SPI error: malloc of SPI structure failed\n");
return NULL;
}
ds->regs = regs;
ds->freq = max_hz;
ds->mode = mode;
return &ds->slave;

View File

@ -103,12 +103,10 @@ struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
if (!spi_cs_is_valid(bus, cs))
return NULL;
ss = malloc(sizeof(struct spi_slave));
ss = spi_alloc_slave(struct sh_spi, bus, cs);
if (!ss)
return NULL;
ss->slave.bus = bus;
ss->slave.cs = cs;
ss->regs = (struct sh_spi_regs *)CONFIG_SH_SPI_BASE;
/* SPI sycle stop */

View File

@ -73,12 +73,10 @@ struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
if (!spi_cs_is_valid(bus, cs))
return NULL;
ss = malloc(sizeof(struct soft_spi_slave));
ss = spi_alloc_slave(struct soft_spi_slave, bus, cs);
if (!ss)
return NULL;
ss->slave.bus = bus;
ss->slave.cs = cs;
ss->mode = mode;
/* TODO: Use max_hz to limit the SCK rate */

39
drivers/spi/spi.c Normal file
View File

@ -0,0 +1,39 @@
/*
* Copyright (c) 2011 The Chromium OS Authors.
*
* 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.h>
void *spi_do_alloc_slave(int offset, int size, unsigned int bus,
unsigned int cs)
{
struct spi_slave *slave;
void *ptr;
ptr = malloc(size);
if (ptr) {
memset(ptr, '\0', size);
slave = (struct spi_slave *)(ptr + offset);
slave->bus = bus;
slave->cs = cs;
}
return ptr;
}

View File

@ -81,13 +81,11 @@ struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
return NULL;
}
spi = malloc(sizeof(struct tegra_spi_slave));
spi = spi_alloc_slave(struct tegra_spi_slave, bus, cs);
if (!spi) {
printf("SPI error: malloc of SPI structure failed\n");
return NULL;
}
spi->slave.bus = bus;
spi->slave.cs = cs;
spi->ctrl = &spi_ctrls[bus];
if (!spi->ctrl) {
printf("SPI error: could not find controller for bus %d\n",

View File

@ -81,13 +81,11 @@ struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
return NULL;
}
spi = malloc(sizeof(struct tegra_spi_slave));
spi = spi_alloc_slave(struct tegra_spi_slave, bus, cs);
if (!spi) {
printf("SPI error: malloc of SPI structure failed\n");
return NULL;
}
spi->slave.bus = bus;
spi->slave.cs = cs;
#ifdef CONFIG_OF_CONTROL
int node = fdtdec_next_compatible(gd->fdt_blob, 0,
COMPAT_NVIDIA_TEGRA20_SFLASH);

View File

@ -85,14 +85,12 @@ struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
return NULL;
}
xilspi = malloc(sizeof(*xilspi));
xilspi = spi_alloc_slave(struct xilinx_spi_slave, bus, cs);
if (!xilspi) {
printf("XILSPI error: %s: malloc of SPI structure failed\n",
__func__);
return NULL;
}
xilspi->slave.bus = bus;
xilspi->slave.cs = cs;
xilspi->regs = (struct xilinx_spi_reg *)xilinx_spi_base_list[bus];
xilspi->freq = max_hz;
xilspi->mode = mode;

View File

@ -179,6 +179,8 @@
#define CONFIG_CMD_SAVEENV
#define CONFIG_CMD_SETGETDCR
#define CONFIG_CMD_SOURCE
#define CONFIG_CMD_TIME
#define CONFIG_CMD_GETTIME
#define CONFIG_CMD_XIMG
#define CONFIG_CMD_SCSI
@ -257,10 +259,16 @@
/*-----------------------------------------------------------------------
* FLASH configuration
*/
#define CONFIG_ICH_SPI
#define CONFIG_SPI_FLASH
#define CONFIG_SPI_FLASH_MACRONIX
#define CONFIG_SPI_FLASH_WINBOND
#define CONFIG_SPI_FLASH_GIGADEVICE
#define CONFIG_SYS_NO_FLASH
#undef CONFIG_FLASH_CFI_DRIVER
#define CONFIG_SYS_MAX_FLASH_SECT 1
#define CONFIG_SYS_MAX_FLASH_BANKS 1
#define CONFIG_CMD_SF
#define CONFIG_CMD_SF_TEST
#define CONFIG_CMD_SPI
#define CONFIG_SPI
/*-----------------------------------------------------------------------
* Environment configuration

View File

@ -38,11 +38,13 @@
*/
#ifdef CONFIG_PHYS_64BIT
typedef u64 fdt_addr_t;
typedef u64 fdt_size_t;
#define FDT_ADDR_T_NONE (-1ULL)
#define fdt_addr_to_cpu(reg) be64_to_cpu(reg)
#define fdt_size_to_cpu(reg) be64_to_cpu(reg)
#else
typedef u32 fdt_addr_t;
typedef u32 fdt_size_t;
#define FDT_ADDR_T_NONE (-1U)
#define fdt_addr_to_cpu(reg) be32_to_cpu(reg)
#define fdt_size_to_cpu(reg) be32_to_cpu(reg)
@ -84,6 +86,7 @@ enum fdt_compat_id {
COMPAT_SAMSUNG_EXYNOS_EHCI, /* Exynos EHCI controller */
COMPAT_SAMSUNG_EXYNOS_USB_PHY, /* Exynos phy controller for usb2.0 */
COMPAT_MAXIM_MAX77686_PMIC, /* MAX77686 PMIC */
COMPAT_GENERIC_SPI_FLASH, /* Generic SPI Flash chip */
COMPAT_COUNT,
};
@ -199,6 +202,19 @@ int fdtdec_next_compatible_subnode(const void *blob, int node,
fdt_addr_t fdtdec_get_addr(const void *blob, int node,
const char *prop_name);
/**
* Look up an address property in a node and return it as an address.
* The property must hold one address with a length. This is only tested
* on 32-bit machines.
*
* @param blob FDT blob
* @param node node to examine
* @param prop_name name of property to find
* @return address, if found, or FDT_ADDR_T_NONE if not
*/
fdt_addr_t fdtdec_get_addr_size(const void *blob, int node,
const char *prop_name, fdt_size_t *sizep);
/**
* Look up a 32-bit integer property in a node and return it. The property
* must have at least 4 bytes of data. The value of the first cell is

View File

@ -49,10 +49,13 @@
*
* bus: ID of the bus that the slave is attached to.
* cs: ID of the chip select connected to the slave.
* max_write_size: If non-zero, the maximum number of bytes which can
* be written at once, excluding command bytes.
*/
struct spi_slave {
unsigned int bus;
unsigned int cs;
unsigned int max_write_size;
};
/*-----------------------------------------------------------------------
@ -62,6 +65,47 @@ struct spi_slave {
*/
void spi_init(void);
/**
* spi_do_alloc_slave - Allocate a new SPI slave (internal)
*
* Allocate and zero all fields in the spi slave, and set the bus/chip
* select. Use the helper macro spi_alloc_slave() to call this.
*
* @offset: Offset of struct spi_slave within slave structure
* @size: Size of slave structure
* @bus: Bus ID of the slave chip.
* @cs: Chip select ID of the slave chip on the specified bus.
*/
void *spi_do_alloc_slave(int offset, int size, unsigned int bus,
unsigned int cs);
/**
* spi_alloc_slave - Allocate a new SPI slave
*
* Allocate and zero all fields in the spi slave, and set the bus/chip
* select.
*
* @_struct: Name of structure to allocate (e.g. struct tegra_spi). This
* structure must contain a member 'struct spi_slave *slave'.
* @bus: Bus ID of the slave chip.
* @cs: Chip select ID of the slave chip on the specified bus.
*/
#define spi_alloc_slave(_struct, bus, cs) \
spi_do_alloc_slave(offsetof(_struct, slave), \
sizeof(_struct), bus, cs)
/**
* spi_alloc_slave_base - Allocate a new SPI slave with no private data
*
* Allocate and zero all fields in the spi slave, and set the bus/chip
* select.
*
* @bus: Bus ID of the slave chip.
* @cs: Chip select ID of the slave chip on the specified bus.
*/
#define spi_alloc_slave_base(bus, cs) \
spi_do_alloc_slave(0, sizeof(struct spi_slave), bus, cs)
/*-----------------------------------------------------------------------
* Set up communications parameters for a SPI slave.
*

View File

@ -39,6 +39,7 @@ struct spi_flash {
/* Erase (sector) size */
u32 sector_size;
void *memory_map; /* Address of read-only SPI flash access */
int (*read)(struct spi_flash *flash, u32 offset,
size_t len, void *buf);
int (*write)(struct spi_flash *flash, u32 offset,
@ -47,6 +48,44 @@ struct spi_flash {
size_t len);
};
/**
* spi_flash_do_alloc - Allocate a new spi flash structure
*
* The structure is allocated and cleared with default values for
* read, write and erase, which the caller can modify. The caller must set
* up size, page_size and sector_size.
*
* Use the helper macro spi_flash_alloc() to call this.
*
* @offset: Offset of struct spi_slave within slave structure
* @size: Size of slave structure
* @spi: SPI slave
* @name: Name of SPI flash device
*/
void *spi_flash_do_alloc(int offset, int size, struct spi_slave *spi,
const char *name);
/**
* spi_flash_alloc - Allocate a new SPI flash structure
*
* @_struct: Name of structure to allocate (e.g. struct ramtron_spi_fram). This
* structure must contain a member 'struct spi_flash *flash'.
* @spi: SPI slave
* @name: Name of SPI flash device
*/
#define spi_flash_alloc(_struct, spi, name) \
spi_flash_do_alloc(offsetof(_struct, flash), sizeof(_struct), \
spi, name)
/**
* spi_flash_alloc_base - Allocate a new SPI flash structure with no private data
*
* @spi: SPI slave
* @name: Name of SPI flash device
*/
#define spi_flash_alloc_base(spi, name) \
spi_flash_do_alloc(0, sizeof(struct spi_flash), spi, name)
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);

View File

@ -59,6 +59,7 @@ static const char * const compat_names[COMPAT_COUNT] = {
COMPAT(SAMSUNG_EXYNOS_EHCI, "samsung,exynos-ehci"),
COMPAT(SAMSUNG_EXYNOS_USB_PHY, "samsung,exynos-usb-phy"),
COMPAT(MAXIM_MAX77686_PMIC, "maxim,max77686_pmic"),
COMPAT(GENERIC_SPI_FLASH, "spi-flash"),
};
const char *fdtdec_get_compatible(enum fdt_compat_id id)
@ -68,25 +69,40 @@ const char *fdtdec_get_compatible(enum fdt_compat_id id)
return compat_names[id];
}
fdt_addr_t fdtdec_get_addr(const void *blob, int node,
const char *prop_name)
fdt_addr_t fdtdec_get_addr_size(const void *blob, int node,
const char *prop_name, fdt_size_t *sizep)
{
const fdt_addr_t *cell;
int len;
debug("%s: %s: ", __func__, prop_name);
cell = fdt_getprop(blob, node, prop_name, &len);
if (cell && (len == sizeof(fdt_addr_t) ||
len == sizeof(fdt_addr_t) * 2)) {
if (cell && ((!sizep && len == sizeof(fdt_addr_t)) ||
len == sizeof(fdt_addr_t) * 2)) {
fdt_addr_t addr = fdt_addr_to_cpu(*cell);
if (sizep) {
const fdt_size_t *size;
debug("%p\n", (void *)addr);
size = (fdt_size_t *)((char *)cell +
sizeof(fdt_addr_t));
*sizep = fdt_size_to_cpu(*size);
debug("addr=%p, size=%p\n", (void *)addr,
(void *)*sizep);
} else {
debug("%p\n", (void *)addr);
}
return addr;
}
debug("(not found)\n");
return FDT_ADDR_T_NONE;
}
fdt_addr_t fdtdec_get_addr(const void *blob, int node,
const char *prop_name)
{
return fdtdec_get_addr_size(blob, node, prop_name, NULL);
}
s32 fdtdec_get_int(const void *blob, int node, const char *prop_name,
s32 default_val)
{