Just a WIP brain dump. Not quite ready yet. Signed-off-by: Mike Frysinger <vap...@gentoo.org> --- arch/sandbox/cpu/os.c | 31 ++++ arch/sandbox/cpu/start.c | 24 +++ drivers/spi/Makefile | 3 + drivers/spi/sandbox_spi.c | 352 +++++++++++++++++++++++++++++++++++++++++++++ include/configs/sandbox.h | 6 + include/os.h | 4 + 6 files changed, 420 insertions(+), 0 deletions(-) create mode 100644 drivers/spi/sandbox_spi.c
diff --git a/arch/sandbox/cpu/os.c b/arch/sandbox/cpu/os.c index f80faac..15a98f4 100644 --- a/arch/sandbox/cpu/os.c +++ b/arch/sandbox/cpu/os.c @@ -21,6 +21,7 @@ #include <fcntl.h> #include <stdlib.h> +#include <string.h> #include <termios.h> #include <unistd.h> #include <sys/types.h> @@ -40,6 +41,11 @@ ssize_t os_write(int fd, const void *buf, size_t count) return write(fd, buf, count); } +off_t os_lseek(int fd, off_t offset, int whence) +{ + return lseek(fd, offset, whence); +} + int os_open(const char *pathname, int flags) { return open(pathname, flags); @@ -87,3 +93,28 @@ void os_tty_raw(int fd) atexit(os_fd_restore); } + +const char *os_getenv(const char *name) +{ + /* We can't use getenv() as u-boot provides it own */ + extern char **environ; + size_t i, len = strlen(name); + + for (i = 0; environ[i]; ++i) + if (!strncmp(name, environ[i], len) && environ[i][len] == '=') + return &environ[i][len + 1]; + + return NULL; +} + +extern char **sb_argv; +const char *os_getopt(const char *name, int has_arg) +{ + size_t i; + + for (i = 0; sb_argv[i]; ++i) + if (!strcmp(sb_argv[i], name)) + return sb_argv[i + !!has_arg]; + + return NULL; +} diff --git a/arch/sandbox/cpu/start.c b/arch/sandbox/cpu/start.c index a429e29..3508a35 100644 --- a/arch/sandbox/cpu/start.c +++ b/arch/sandbox/cpu/start.c @@ -20,9 +20,33 @@ */ #include <common.h> +#include <os.h> + +char **sb_argv; + +static const char usage[] = + "Usage: u-boot [options]\n" + "\n" + "Options: (note: not all options may be available)\n" + " -h, --help this message (imagine that)\n" +#ifdef CONFIG_SANDBOX_SPI + " --spi-<bus>-<cs> <spec> connect client to spi <bus> on <cs>\n" +# ifdef CONFIG_SPI_FLASH + " spec: sf:<file> treat <file> as spi flash\n" +# endif +#endif +; int main(int argc, char *argv[]) { + /* Save the argv for people to access */ + sb_argv = argv; + + if (os_getopt("-h", 0) || os_getopt("--help", 0)) { + serial_puts(usage); + return 0; + } + /* * Do pre- and post-relocation init, then start up U-Boot. This will * never return. diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile index 96c9642..212fc8c 100644 --- a/drivers/spi/Makefile +++ b/drivers/spi/Makefile @@ -38,6 +38,7 @@ COBJS-$(CONFIG_MPC8XXX_SPI) += mpc8xxx_spi.o COBJS-$(CONFIG_MXC_SPI) += mxc_spi.o COBJS-$(CONFIG_OC_TINY_SPI) += oc_tiny_spi.o COBJS-$(CONFIG_OMAP3_SPI) += omap3_spi.o +COBJS-$(CONFIG_SANDBOX_SPI) += sandbox_spi.o COBJS-$(CONFIG_SOFT_SPI) += soft_spi.o COBJS-$(CONFIG_SH_SPI) += sh_spi.o COBJS-$(CONFIG_FSL_ESPI) += fsl_espi.o @@ -59,3 +60,5 @@ include $(SRCTREE)/rules.mk sinclude $(obj).depend ######################################################################### + +CFLAGS += -g -O0 diff --git a/drivers/spi/sandbox_spi.c b/drivers/spi/sandbox_spi.c new file mode 100644 index 0000000..172cb67 --- /dev/null +++ b/drivers/spi/sandbox_spi.c @@ -0,0 +1,352 @@ +#define DEBUG +/* + * Simulate a SPI port + * + * Copyright (c) 2011 The Chromium OS Authors. + * See file CREDITS for list of people who contributed to this + * project. + * + * Licensed under the GPL-2 or later. + */ + +#include <common.h> +#include <malloc.h> +#include <spi.h> +#include <os.h> + +#ifndef CONFIG_SPI_IDLE_VAL +# define CONFIG_SPI_IDLE_VAL 0xFF +#endif + +struct sb_spi_emu_ops { + int (*setup)(void **priv, const char *spec); + void (*free)(void *priv); + void (*cs_activate)(void *priv); + void (*cs_deactivate)(void *priv); + int (*xfer)(void *priv, const u8 *tx, u8 *rx, uint bytes); +}; + +struct sb_spi_slave { + struct spi_slave slave; + const char *spec; + const struct sb_spi_emu_ops *ops; + void *priv; +}; + +#define to_sb_spi_slave(s) container_of(s, struct sb_spi_slave, slave) + +static const char *sb_lookup_arg(unsigned int bus, unsigned int cs) +{ + char sf_arg[20]; + sprintf(sf_arg, "--spi-%u-%u", bus, cs); + return os_getopt(sf_arg, 1); +} + +struct sb_spi_flash { + enum { SF_CMD, SF_ID, SF_READ, SF_WRITE, SF_ERASE, SF_STATUS, } state; + uint off; + char *idcode; + int fd; +}; + +static int sb_sf_setup(void **priv, const char *spec) +{ + /* spec = idcode:file */ + struct sb_spi_flash *sbsf; + const char *file; + size_t idcode_len; + + file = strchr(spec, ':'); + if (!file) + return 1; + idcode_len = file - spec; + ++file; + + sbsf = malloc(sizeof(*sbsf)); + if (!sbsf) + return 1; + + sbsf->fd = os_open(file, 0); + if (sbsf->fd == -1) { + free(sbsf); + return 1; + } + + sbsf->state = SF_CMD; + sbsf->idcode = malloc(idcode_len + 1); + if (!sbsf->idcode) { + os_close(sbsf->fd); + free(sbsf); + return 1; + } + memcpy(sbsf->idcode, spec, idcode_len); + sbsf->idcode[idcode_len] = '\0'; + + *priv = sbsf; + return 0; +} + +static void sb_sf_free(void *priv) +{ + struct sb_spi_flash *sbsf = priv; + + os_close(sbsf->fd); + free(sbsf); +} + +static void sb_sf_cs_deactivate(void *priv) +{ + struct sb_spi_flash *sbsf = priv; + + /* CS is no longer being asserted, so reset state */ + sbsf->state = SF_CMD; +} + +static int sb_sf_xfer(void *priv, const u8 *tx, u8 *rx, + uint bytes) +{ + struct sb_spi_flash *sbsf = priv; + uint i, written = 0; + + debug("sb_sf: state:%x\n", sbsf->state); + + if (sbsf->state == SF_CMD) { + rx[written++] = 0; + switch (tx[0]) { + case 0x9f: //CMD_READ_ID: + sbsf->off = 0; + sbsf->state = SF_ID; + break; + case 0x03: //CMD_READ_SLOW: + case 0x0b: /*CMD_READ_FAST*/ + sbsf->off = (tx[1] << 16) | (tx[2] << 8) | tx[3]; + os_lseek(sbsf->fd, sbsf->off, 0); + bytes -= 4; + if (tx[0] == 0x0b) + --bytes; + sbsf->state = SF_READ; + break; + } + } + + switch (sbsf->state) { + case SF_ID: { + const char *idcode = sbsf->idcode; + + for (i = sbsf->off; i < strlen(idcode); i += 2) + if (written < bytes) { + char idbyte[3] = { idcode[i], idcode[i + 1], '\0', }; + rx[written++] = simple_strtoul(idbyte, NULL, 16); + } else + break; + if (written < bytes) { + i = bytes - written; + memset(rx + written, 0, i); + written += i; + } + break; + } + case SF_READ: + written += os_read(sbsf->fd, rx, bytes - written); + break; + default: + break; /* ??? */ + } + + return written == bytes ? 0 : 1; +} + +static const struct sb_spi_emu_ops sb_sf_ops = { + .setup = sb_sf_setup, + .free = sb_sf_free, + .cs_deactivate = sb_sf_cs_deactivate, + .xfer = sb_sf_xfer, +}; + +static const struct { + const char *spec; + const struct sb_spi_emu_ops *ops; +} sb_emu_map[] = { + { "sf", &sb_sf_ops, }, +}; + +static int sb_parse_type(struct sb_spi_slave *sss) +{ + size_t i; + + for (i = 0; i < ARRAY_SIZE(sb_emu_map); ++i) { + size_t len = strlen(sb_emu_map[i].spec); + const char *sub_spec = sss->spec + len; + + sss->ops = sb_emu_map[i].ops; + if (!memcmp(sss->spec, sb_emu_map[i].spec, len) && + sss->spec[len] == ':') + return sss->ops->setup(&sss->priv, sub_spec + 1); + } + + return 1; +} + +int spi_cs_is_valid(unsigned int bus, unsigned int cs) +{ +#if 0 + /* bus:cs_min:cs_max */ + char *specs, *spec, *s; + unsigned long i; + + specs = strdup(os_getenv("UBOOT_SB_SPI_BUS") ? : "0:1:7"); + if (!specs) + return 0; + + /* Walk each spec */ + spec = strtok(specs, " "); + while (spec) { + /* is this the bus ? */ + s = strtok(spec, ":"); + strict_strtoul(s, 10, &i); + if (i == bus) { + /* is the cs at least the min ? */ + s = strtok(NULL, ":"); + if (!s) + break; + strict_strtoul(s, 10, &i); + if (cs >= i) { + /* is the cs at most the max ? */ + s = strtok(NULL, ":"); + if (!s) + break; + strict_strtoul(s, 10, &i); + if (cs <= i) { + /* within range! */ + break; + } + } + } + + /* Get next spec */ + spec = strtok(NULL, " "); + } + free(specs); + + return spec ? 1 : 0; +#else + return sb_lookup_arg(bus, cs) ? 1 : 0; +#endif +} + +void spi_cs_activate(struct spi_slave *slave) +{ + struct sb_spi_slave *sss = to_sb_spi_slave(slave); + + if (sss->ops->cs_activate) + sss->ops->cs_activate(sss->priv); +} + +void spi_cs_deactivate(struct spi_slave *slave) +{ + struct sb_spi_slave *sss = to_sb_spi_slave(slave); + + if (sss->ops->cs_deactivate) + sss->ops->cs_deactivate(sss->priv); +} + +void spi_init(void) +{ +} + +void spi_set_speed(struct spi_slave *slave, uint hz) +{ +} + +struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs, + unsigned int max_hz, unsigned int mode) +{ + struct sb_spi_slave *sss; + + if (!spi_cs_is_valid(bus, cs)) + return NULL; + + sss = malloc(sizeof(*sss)); + if (!sss) + return NULL; + + sss->spec = sb_lookup_arg(bus, cs); + if (sb_parse_type(sss)) { + free(sss); + return NULL; + } + + return &sss->slave; +} + +void spi_free_slave(struct spi_slave *slave) +{ + struct sb_spi_slave *sss = to_sb_spi_slave(slave); + + if (sss->ops->free) + sss->ops->free(sss->priv); + + free(sss); +} + +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) +{ + struct sb_spi_slave *sss = to_sb_spi_slave(slave); + uint bytes = bitlen / 8, i; + int ret = 0; + u8 *tx = (void *)dout, *rx = din; + + if (bitlen == 0) + goto done; + + /* we can only do 8 bit transfers */ + if (bitlen % 8) { + flags |= SPI_XFER_END; + goto done; + } + + if (flags & SPI_XFER_BEGIN) + spi_cs_activate(slave); + + /* make sure rx/tx buffers are full so clients can assume */ + if (!tx) { + tx = malloc(bytes); + if (tx) + memset(tx, CONFIG_SPI_IDLE_VAL, bytes); + } + if (!rx) + rx = malloc(bytes); + if (tx && rx) { + debug("sb_xfer: bytes = %u\n tx:", bytes); + for (i = 0; i < bytes; ++i) + debug(" %u:%02x", i, tx[i]); + debug("\n"); + + ret = sss->ops->xfer(sss->priv, tx, rx, bytes); + + debug(" rx:"); + for (i = 0; i < bytes; ++i) + debug(" %u:%02x", i, rx[i]); + debug("\n"); + } + if (tx != dout) + free(tx); + if (rx != din) + free(rx); + + done: + if (flags & SPI_XFER_END) + spi_cs_deactivate(slave); + + return ret; +} diff --git a/include/configs/sandbox.h b/include/configs/sandbox.h index 10565e6..95a1156 100644 --- a/include/configs/sandbox.h +++ b/include/configs/sandbox.h @@ -51,6 +51,12 @@ #define CONFIG_ENV_SIZE 8192 #define CONFIG_ENV_IS_NOWHERE +/* SPI */ +#define CONFIG_SANDBOX_SPI +#define CONFIG_CMD_SF +#define CONFIG_SPI_FLASH +#define CONFIG_SPI_FLASH_STMICRO + #define CONFIG_SYS_HZ 1000 /* Memory things - we don't really want a memory test */ diff --git a/include/os.h b/include/os.h index d5df22f..0d5efef 100644 --- a/include/os.h +++ b/include/os.h @@ -76,3 +76,7 @@ void os_exit(int exit_code); * Put tty into raw mode to mimic serial console better */ void os_tty_raw(int fd); + +const char *os_getenv(const char *name); +const char *os_getopt(const char *name, int has_arg); +off_t os_lseek(int fd, off_t offset, int whence); -- 1.7.6.1 _______________________________________________ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot