[PATCH qemu 20/38] aspeed/smc: handle dummy bytes when doing fast reads

Andrew Jeffery andrew at aj.id.au
Mon Nov 28 12:35:12 AEDT 2016


On Fri, 2016-11-18 at 15:22 +0100, Cédric Le Goater wrote:
> When doing fast read, a certain amount of dummy bytes should be sent
> before the read. This number is configurable in the controler CE0
> Control Register and needs to be modeled using fake transfers the
> flash module.
> 
> When the controller is configured for Command mode, the SPI command
> used to do the read is stored in the CE0 control register but, in User
> mode, we need to snoop into the flow of bytes to catch the command. It
> should be the first byte after CS select.
> 
> Signed-off-by: Cédric Le Goater <clg at kaod.org>

Reviewed-by: Andrew Jeffery <andrew at aj.id.au>

> ---
>  hw/ssi/aspeed_smc.c         | 57 ++++++++++++++++++++++++++++++++++++++-------
>  include/hw/ssi/aspeed_smc.h |  1 +
>  2 files changed, 50 insertions(+), 8 deletions(-)
> 
> diff --git a/hw/ssi/aspeed_smc.c b/hw/ssi/aspeed_smc.c
> index 9596ea94a3bc..c0ae07ef8c96 100644
> --- a/hw/ssi/aspeed_smc.c
> +++ b/hw/ssi/aspeed_smc.c
> @@ -71,7 +71,9 @@
>  #define R_CTRL0           (0x10 / 4)
>  #define   CTRL_CMD_SHIFT           16
>  #define   CTRL_CMD_MASK            0xff
> +#define   CTRL_DUMMY_HIGH_SHIFT    14
>  #define   CTRL_AST2400_SPI_4BYTE   (1 << 13)
> +#define   CTRL_DUMMY_LOW_SHIFT     6
>  #define   CTRL_CE_STOP_ACTIVE      (1 << 2)
>  #define   CTRL_CMD_MODE_MASK       0x3
>  #define     CTRL_READMODE          0x0
> @@ -151,6 +153,7 @@
>  #define SPI_OP_WRDI       0x04    /* Write disable */
>  #define SPI_OP_RDSR       0x05    /* Read status register */
>  #define SPI_OP_WREN       0x06    /* Write enable */
> +#define SPI_OP_READ_FAST  0x0b    /* Read data bytes (high frequency) */
>  
>  /* Used for Macronix and Winbond flashes. */
>  #define SPI_OP_EN4B       0xb7    /* Enter 4-byte mode */
> @@ -510,6 +513,12 @@ static void aspeed_smc_flash_setup_read(AspeedSMCFlash *fl, uint32_t addr)
>      /* access can not exceed CS segment */
>      addr = aspeed_smc_check_segment_addr(fl, addr);
>  
> +    /*
> +     * Remember command as we might need to send dummy bytes before
> +     * reading data
> +     */
> +    fl->cmd = cmd;
> +
>      /* TODO: do we have to send 4BYTE each time ? */
>      if (aspeed_smc_flash_is_4byte(fl)) {
>          ssi_transfer(s->spi, SPI_OP_EN4B);
> @@ -525,27 +534,49 @@ static void aspeed_smc_flash_setup_read(AspeedSMCFlash *fl, uint32_t addr)
>      ssi_transfer(s->spi, (addr & 0xff));
>  }
>  
> +static int aspeed_smc_flash_dummies(const AspeedSMCFlash *fl)
> +{
> +    AspeedSMCState *s = fl->controller;
> +    uint32_t r_ctrl0 = s->regs[s->r_ctrl0 + fl->id];
> +
> +    return ((((r_ctrl0 >> CTRL_DUMMY_HIGH_SHIFT) & 0x1) << 2) |
> +            ((r_ctrl0 >> CTRL_DUMMY_LOW_SHIFT) & 0x3)) * 8;
> +}
> +
> +static uint64_t aspeed_smc_flash_do_read(AspeedSMCFlash *fl, unsigned size)
> +{
> +    AspeedSMCState *s = fl->controller;
> +    uint64_t ret = 0;
> +    int i;
> +
> +    if (fl->cmd == SPI_OP_READ_FAST) {
> +        for (i = 0; i < aspeed_smc_flash_dummies(fl); i++) {
> +            ssi_transfer(s->spi, 0x0);
> +        }
> +    }
> +    fl->cmd = 0;
> +
> +    for (i = 0; i < size; i++) {
> +        ret |= ssi_transfer(s->spi, 0x0) << (8 * i);
> +    }
> +    return ret;
> +}
> +
>  static uint64_t aspeed_smc_flash_read(void *opaque, hwaddr addr, unsigned size)
>  {
>      AspeedSMCFlash *fl = opaque;
> -    const AspeedSMCState *s = fl->controller;
>      uint64_t ret = 0;
> -    int i;
>  
>      switch (aspeed_smc_flash_mode(fl)) {
>      case CTRL_USERMODE:
> -        for (i = 0; i < size; i++) {
> -            ret |= ssi_transfer(s->spi, 0x0) << (8 * i);
> -        }
> +        ret = aspeed_smc_flash_do_read(fl, size);
>          break;
>      case CTRL_READMODE:
>      case CTRL_FREADMODE:
>          aspeed_smc_flash_select(fl);
>          aspeed_smc_flash_setup_read(fl, addr);
>  
> -        for (i = 0; i < size; i++) {
> -            ret |= ssi_transfer(s->spi, 0x0) << (8 * i);
> -        }
> +        ret = aspeed_smc_flash_do_read(fl, size);
>  
>          aspeed_smc_flash_unselect(fl);
>          break;
> @@ -596,6 +627,15 @@ static void aspeed_smc_flash_write(void *opaque, hwaddr addr, uint64_t data,
>  
>      switch (aspeed_smc_flash_mode(fl)) {
>      case CTRL_USERMODE:
> +        /*
> +         * First write after chip select is the chip command. Remember
> +         * it as we might need to send dummy bytes before reading
> +         * data. It will be reseted when the chip is unselected.
> +         */
> +        if (!fl->cmd) {
> +            fl->cmd = data & 0xff;
> +        }
> +
>          for (i = 0; i < size; i++) {
>              ssi_transfer(s->spi, (data >> (8 * i)) & 0xff);
>          }
> @@ -629,6 +669,7 @@ static const MemoryRegionOps aspeed_smc_flash_ops = {
>  static void aspeed_smc_flash_update_cs(AspeedSMCFlash *fl)
>  {
>      AspeedSMCState *s = fl->controller;
> +    fl->cmd = 0;
>      qemu_set_irq(s->cs_lines[fl->id], aspeed_smc_is_ce_stop_active(fl));
>  }
>  
> diff --git a/include/hw/ssi/aspeed_smc.h b/include/hw/ssi/aspeed_smc.h
> index 88a904849801..3ae0a369073d 100644
> --- a/include/hw/ssi/aspeed_smc.h
> +++ b/include/hw/ssi/aspeed_smc.h
> @@ -52,6 +52,7 @@ typedef struct AspeedSMCFlash {
>  
>      uint8_t id;
>      uint32_t size;
> +    uint8_t cmd;
>  
>      MemoryRegion mmio;
>      DeviceState *flash;
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 801 bytes
Desc: This is a digitally signed message part
URL: <http://lists.ozlabs.org/pipermail/openbmc/attachments/20161128/3f157a85/attachment.sig>


More information about the openbmc mailing list