Hi Mike, On Wed, Oct 26, 2011 at 3:30 AM, Mike Frysinger <vap...@gentoo.org> wrote: > Just a WIP brain dump. Not quite ready yet.
Looks good thanks. > > 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); > +} How are we going to deal with calls to something like this where 'whence' is defined in an OS-specific header file? I believe we need to add definitions to os.h to provide this feature, and make them match Posix. Is there a better way? open has a similar problem. > + > 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 */ Ick, but I can't see an easy alternative. > + 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; > + } I did actually create something to parse args and put them into a 'state' structure. But it uses getopt_long(). Any reason we can't? > + > /* > * 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); I would really like to have full comments on all header functions (with @param and @return). > +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 > > Regards, Simon _______________________________________________ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot