diff mbox

[v4,21/23] hw/arm: add Faraday FTSPI020 SPI flash controller support

Message ID CAEgOgz6WUQ1KuBq1MykKzp2xFOwz_oQVg+KUkt=HXh9Ury3xMg@mail.gmail.com
State New
Headers show

Commit Message

Peter Crosthwaite Feb. 27, 2013, 4:30 a.m. UTC
Hi Kuo-Jung,

On Wed, Feb 27, 2013 at 12:08 PM, Kuo-Jung Su <dantesu@gmail.com> wrote:
> 2013/2/26 Peter Crosthwaite <peter.crosthwaite@xilinx.com>:
>> Hi Kuo-Jung,
>>
>> On Tue, Feb 26, 2013 at 7:14 PM, Kuo-Jung Su <dantesu@gmail.com> wrote:
>>> From: Kuo-Jung Su <dantesu@faraday-tech.com>
>>>
>>> The FTSPI020 is an integrated SPI Flash controller
>>> which supports upto 4 flash chips.
>>>
>>> Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
>>> ---
>>
>> Please provide change logs below the line as per the patch submission process.
>>
>>>  hw/arm/Makefile.objs      |    1 +
>>>  hw/arm/faraday_a369.c     |   13 ++
>>>  hw/arm/faraday_a369_soc.c |    4 +
>>>  hw/arm/ftspi020.c         |  333 +++++++++++++++++++++++++++++++++++++++++++++
>>>  hw/arm/ftspi020.h         |   81 +++++++++++
>>>  5 files changed, 432 insertions(+)
>>>  create mode 100644 hw/arm/ftspi020.c
>>>  create mode 100644 hw/arm/ftspi020.h
>>>
>>> diff --git a/hw/arm/Makefile.objs b/hw/arm/Makefile.objs
>>> index c25eba2..2ed1c7c 100644
>>> --- a/hw/arm/Makefile.objs
>>> +++ b/hw/arm/Makefile.objs
>>> @@ -52,3 +52,4 @@ obj-y += ftgmac100.o
>>>  obj-y += ftlcdc200.o
>>>  obj-y += fttsc010.o
>>>  obj-y += ftsdc010.o
>>> +obj-y += ftspi020.o
>>> diff --git a/hw/arm/faraday_a369.c b/hw/arm/faraday_a369.c
>>> index 46fc570..ace0784 100644
>>> --- a/hw/arm/faraday_a369.c
>>> +++ b/hw/arm/faraday_a369.c
>>> @@ -67,6 +67,19 @@ a369_board_init(QEMUMachineInitArgs *args)
>>>          wm8731_data_req_set(s->codec, ftssp010_i2s_data_req, s->i2s[0]);
>>>      }
>>>
>>> +    /* Attach the spi flash to ftspi020.0 */
>>> +    nr_flash = 1;
>>> +    for (i = 0; i < nr_flash; i++) {
>>> +        SSIBus *ssi = (SSIBus *)qdev_get_child_bus(s->spi[1], "spi");
>>> +        DeviceState *fl = ssi_create_slave_no_init(ssi, "m25p80");
>>> +        qemu_irq cs_line;
>>> +
>>> +        qdev_prop_set_string(fl, "partname", "w25q64");
>>> +        qdev_init_nofail(fl);
>>> +        cs_line = qdev_get_gpio_in(fl, 0);
>>> +        sysbus_connect_irq(SYS_BUS_DEVICE(s->spi[1]), i + 1, cs_line);
>>> +    }
>>> +
>>>      if (args->kernel_filename) {
>>>          s->bi = g_new0(struct arm_boot_info, 1);
>>>
>>> diff --git a/hw/arm/faraday_a369_soc.c b/hw/arm/faraday_a369_soc.c
>>> index eb9dd2f..8b07689 100644
>>> --- a/hw/arm/faraday_a369_soc.c
>>> +++ b/hw/arm/faraday_a369_soc.c
>>> @@ -272,6 +272,10 @@ a369soc_device_init(FaradaySoCState *s)
>>>      req = qdev_get_gpio_in(s->hdma[0], 13);
>>>      qdev_connect_gpio_out(s->hdma[0], 13, ack);
>>>      qdev_connect_gpio_out(ds, 0, req);
>>> +
>>> +    /* ftspi020: as an external AHB device */
>>> +    ds = sysbus_create_simple("ftspi020", 0xC0000000, pic[4]);
>>> +    s->spi[1] = ds;
>>>  }
>>>
>>>  static int a369soc_init(SysBusDevice *busdev)
>>> diff --git a/hw/arm/ftspi020.c b/hw/arm/ftspi020.c
>>> new file mode 100644
>>> index 0000000..fb8a510
>>> --- /dev/null
>>> +++ b/hw/arm/ftspi020.c
>>> @@ -0,0 +1,333 @@
>>> +/*
>>> + * Faraday FTSPI020 Flash Controller
>>> + *
>>> + * Copyright (c) 2012 Faraday Technology
>>> + * Written by Dante Su <dantesu@faraday-tech.com>
>>> + *
>>> + * This code is licensed under GNU GPL v2+.
>>> + */
>>> +
>>> +#include "hw/hw.h"
>>> +#include "sysemu/sysemu.h"
>>> +#include "hw/sysbus.h"
>>> +#include "hw/ssi.h"
>>> +
>>> +#include "ftspi020.h"
>>> +
>>> +#define TYPE_FTSPI020   "ftspi020"
>>> +
>>> +typedef struct Ftspi020State {
>>> +    SysBusDevice busdev;
>>> +    MemoryRegion iomem;
>>> +    qemu_irq irq;
>>> +
>>> +    /* DMA hardware handshake */
>>> +    qemu_irq req;
>>> +
>>> +    SSIBus *spi;
>>> +    qemu_irq *cs_lines;
>>> +
>>> +    int wip;    /* SPI Flash Status: Write In Progress BIT shift */
>>> +
>>> +    /* HW register caches */
>>> +    uint32_t cmd[4];
>>> +    uint32_t ctrl;
>>> +    uint32_t timing;
>>> +    uint32_t icr;
>>> +    uint32_t isr;
>>> +    uint32_t rdsr;
>>> +} Ftspi020State;
>>> +
>>> +#define FTSPI020(obj) \
>>> +    OBJECT_CHECK(Ftspi020State, obj, TYPE_FTSPI020)
>>> +
>>> +static void ftspi020_update_irq(Ftspi020State *s)
>>> +{
>>> +    qemu_set_irq(s->irq, s->isr ? 1 : 0);
>>> +}
>>> +
>>> +static void ftspi020_handle_ack(void *opaque, int line, int level)
>>> +{
>>> +    Ftspi020State *s = FTSPI020(opaque);
>>> +
>>> +    if (!(s->icr & ICR_DMA)) {
>>> +        return;
>>> +    }
>>> +
>>> +    if (level) {
>>> +        qemu_set_irq(s->req, 0);
>>> +    } else if (s->cmd[2]) {
>>> +        qemu_set_irq(s->req, 1);
>>> +    }
>>> +}
>>> +
>>> +static int ftspi020_do_command(Ftspi020State *s)
>>> +{
>>> +    uint32_t cs   = extract32(s->cmd[3],  8, 2);
>>> +    uint32_t cmd  = extract32(s->cmd[3], 24, 8);
>>> +    uint32_t ilen = extract32(s->cmd[1], 24, 2);
>>> +    uint32_t alen = extract32(s->cmd[1],  0, 3);
>>> +    uint32_t dcyc = extract32(s->cmd[1], 16, 8);
>>> +
>>> +    if (dcyc % 8) {
>>> +        hw_error("ftspi020: bad dummy clock (%u) to QEMU\n", dcyc);
>>> +        exit(1);
>>> +    }
>>> +
>>> +    /* make sure the spi flash is de-activated */
>>> +    qemu_set_irq(s->cs_lines[cs], 1);
>>> +
>>> +    /* activate the spi flash */
>>> +    qemu_set_irq(s->cs_lines[cs], 0);
>>> +
>>> +    /* if it's a SPI flash READ_STATUS command */
>>> +    if ((s->cmd[3] & (CMD3_RDSR | CMD3_WRITE)) == CMD3_RDSR) {
>>> +        uint32_t rdsr;
>>> +
>>> +        ssi_transfer(s->spi, cmd);
>>> +        do {
>>> +            rdsr = ssi_transfer(s->spi, 0x00);
>>> +            if (s->cmd[3] & CMD3_RDSR_SW) {
>>> +                break;
>>> +            }
>>> +        } while (rdsr & (1 << s->wip));
>>> +        s->rdsr = rdsr;
>>> +    } else {
>>> +    /* otherwise */
>>> +        int i;
>>> +
>>> +        ilen = MIN(ilen, 2);
>>> +        alen = MIN(alen, 4);
>>> +
>>> +        /* command cycles */
>>> +        for (i = 0; i < ilen; ++i) {
>>> +            ssi_transfer(s->spi, cmd);
>>> +        }
>>> +        /* address cycles */
>>> +        for (i = alen - 1; i >= 0; --i) {
>>> +            ssi_transfer(s->spi, extract32(s->cmd[0], i * 8, 8));
>>> +        }
>>> +        /* dummy cycles */
>>> +        for (i = 0; i < (dcyc >> 3); ++i) {
>>> +            ssi_transfer(s->spi, 0x00);
>>> +        }
>>> +    }
>>> +
>>> +    if (!s->cmd[2]) {
>>> +        qemu_set_irq(s->cs_lines[cs], 1);
>>> +    } else if (s->icr & ICR_DMA) {
>>> +        qemu_set_irq(s->req, 1);
>>> +    }
>>> +
>>> +    if (s->cmd[3] & CMD3_INTR) {
>>> +        s->isr |= ISR_CMDFIN;
>>> +    }
>>> +    ftspi020_update_irq(s);
>>> +
>>> +    return 0;
>>> +}
>>> +
>>> +static void ftspi020_chip_reset(Ftspi020State *s)
>>> +{
>>> +    int i;
>>> +
>>> +    for (i = 0; i < 4; ++i) {
>>> +        s->cmd[i] = 0;
>>> +    }
>>> +    s->wip = 0;
>>> +    s->ctrl = 0;
>>> +    s->timing = 0;
>>> +    s->icr = 0;
>>> +    s->isr = 0;
>>> +    s->rdsr = 0;
>>> +
>>> +    qemu_set_irq(s->irq, 0);
>>> +
>>> +    /* DO NOT reset cs lines here, or the QEMU would crash */
>>
>> More information please. This should work. What happened?
>>
>
> If there is no spi flash connected with the specific cs_line,
> de-activate the cs_line
> in the ftspi020_chip_reset() would crash the QEMU without any error message.
> I've checked qemu_set_irq() and ssi_cs_default(), but no luck.
>

It might be a case of un-initialised irqs. See my comment further below.

>>> +}
>>> +
>>> +static uint64_t
>>> +ftspi020_mem_read(void *opaque, hwaddr addr, unsigned size)
>>> +{
>>> +    Ftspi020State *s = FTSPI020(opaque);
>>> +    uint64_t ret = 0;
>>> +
>>> +    switch (addr) {
>>> +    case REG_CMD0 ... REG_CMD3:
>>> +        return s->cmd[(addr - REG_CMD0) / 4];
>>> +    case REG_CR:
>>> +        return s->ctrl;
>>> +    case REG_TR:
>>> +        return s->timing;
>>> +    case REG_SR:
>>> +        /* In QEMU, the data fifo is always ready for read/write */
>>> +        return SR_RX_READY | SR_TX_READY;
>>> +    case REG_ISR:
>>> +        return s->isr;
>>> +    case REG_ICR:
>>> +        return s->icr;
>>> +    case REG_RDSR:
>>> +        return s->rdsr;
>>> +    case REG_REVR:
>>> +        return 0x00010001;  /* rev. 1.0.1 */
>>> +    case REG_FEAR:
>>> +        return FEAR_CLKM_SYNC
>>> +            | FEAR_CMDQ(2) | FEAR_RXFIFO(32) | FEAR_TXFIFO(32);
>>> +    case REG_DR:
>>> +        if (!(s->cmd[3] & CMD3_WRITE)) {
>>> +            int i;
>>> +            uint32_t cs = extract32(s->cmd[3], 8, 2);
>>> +            for (i = 0; i < 4 && s->cmd[2]; i++, s->cmd[2]--) {
>>> +                ret = deposit32(ret, i * 8, 8,
>>> +                    ssi_transfer(s->spi, 0x00) & 0xff);
>>> +            }
>>> +            if (!s->cmd[2]) {
>>> +                qemu_set_irq(s->cs_lines[cs], 1);
>>> +                if (s->cmd[3] & CMD3_INTR) {
>>> +                    s->isr |= ISR_CMDFIN;
>>> +                }
>>> +                ftspi020_update_irq(s);
>>> +            }
>>> +        }
>>> +        break;
>>> +        /* we don't care */
>>> +    default:
>>
>> You could qemu_log_mask(LOG_GUEST_ERROR on undefined memory accesses.
>>
>
> Got it, thanks.
>
>>> +        break;
>>> +    }
>>> +
>>> +    return ret;
>>> +}
>>> +
>>> +static void
>>> +ftspi020_mem_write(void *opaque, hwaddr addr, uint64_t val, unsigned size)
>>> +{
>>> +    Ftspi020State *s = FTSPI020(opaque);
>>> +
>>> +    switch (addr) {
>>> +    case REG_CMD0 ... REG_CMD2:
>>> +        s->cmd[(addr - REG_CMD0) / 4] = (uint32_t)val;
>>> +        break;
>>> +    case REG_CMD3:
>>> +        s->cmd[3] = (uint32_t)val;
>>> +        ftspi020_do_command(s);
>>> +        break;
>>> +    case REG_CR:
>>> +        if (val & CR_ABORT) {
>>> +            ftspi020_chip_reset(s);
>>> +            val &= ~CR_ABORT;
>>> +        }
>>> +        s->ctrl = (uint32_t)val;
>>> +        s->wip  = extract32(val, 16, 3);
>>> +        break;
>>> +    case REG_TR:
>>> +        s->timing = (uint32_t)val;
>>> +        break;
>>> +    case REG_DR:
>>> +        if (s->cmd[3] & CMD3_WRITE) {
>>> +            int i;
>>> +            uint32_t cs = extract32(s->cmd[3], 8, 2);
>>> +            for (i = 0; i < 4 && s->cmd[2]; i++, s->cmd[2]--) {
>>> +                ssi_transfer(s->spi, extract32((uint32_t)val, i * 8, 8));
>>> +            }
>>> +            if (!s->cmd[2]) {
>>> +                qemu_set_irq(s->cs_lines[cs], 1);
>>> +                if (s->cmd[3] & CMD3_INTR) {
>>> +                    s->isr |= ISR_CMDFIN;
>>> +                }
>>> +                ftspi020_update_irq(s);
>>> +            }
>>> +        }
>>> +        break;
>>> +    case REG_ISR:
>>> +        s->isr &= ~((uint32_t)val);
>>> +        ftspi020_update_irq(s);
>>> +        break;
>>> +    case REG_ICR:
>>> +        s->icr = (uint32_t)val;
>>> +        break;
>>> +        /* we don't care */
>>> +    default:
>>> +        break;
>>> +    }
>>> +}
>>> +
>>> +static const MemoryRegionOps ftspi020_ops = {
>>> +    .read  = ftspi020_mem_read,
>>> +    .write = ftspi020_mem_write,
>>
>> Your REG_FOO macros are jumping in fours, and the case statement in
>> your read/write handlers only handles those values, leading me to
>> believe your device only supports full word access. You should enforce
>> this by setting min/max_access size to 4 here.
>>
>
> Got it, thanks.
>
>> Regards,
>> Peter
>>
>>> +    .endianness = DEVICE_LITTLE_ENDIAN,
>>> +};
>>> +
>>> +static void ftspi020_reset(DeviceState *ds)
>>> +{
>>> +    SysBusDevice *busdev = SYS_BUS_DEVICE(ds);
>>> +    Ftspi020State *s = FTSPI020(FROM_SYSBUS(Ftspi020State, busdev));
>>> +
>>> +    ftspi020_chip_reset(s);
>>> +}
>>> +
>>> +static int ftspi020_init(SysBusDevice *dev)
>>> +{
>>> +    Ftspi020State *s = FTSPI020(FROM_SYSBUS(Ftspi020State, dev));
>>> +    int i;
>>> +
>>> +    memory_region_init_io(&s->iomem,
>>> +                          &ftspi020_ops,
>>> +                          s,
>>> +                          TYPE_FTSPI020,
>>> +                          0x1000);
>>> +    sysbus_init_mmio(dev, &s->iomem);
>>> +    sysbus_init_irq(dev, &s->irq);
>>> +
>>> +    s->spi = ssi_create_bus(&dev->qdev, "spi");
>>> +    s->cs_lines = g_new(qemu_irq, CFG_NR_CSLINES);

s/g_new/g_new0. That will knock out your un-attached IRQ lines. You
may have contagiously contracted this bug from xilinx_spips I think.
My fix to spips is currently on list:

commit d474fc0447fabaeb5f51ccbd88973c7f85ea1abe
Author: Peter Crosthwaite <peter.crosthwaite@xilinx.com>
Date:   Thu Nov 29 14:39:56 2012 +1000

    xilinx_spips: Set unused IRQs to NULL

    Unused CS lines should init to 0 to avoid segfaulting when accessing an
    unattached QSPI controller.

    Signed-off-by: Peter Crosthwaite <peter.crosthwaite@xilinx.com>


Regards,
Peter

>>> +    ssi_auto_connect_slaves(DEVICE(s), s->cs_lines, s->spi);
>>> +    for (i = 0; i < CFG_NR_CSLINES; ++i) {
>>> +        sysbus_init_irq(dev, &s->cs_lines[i]);
>>> +    }
>>> +
>>> +    qdev_init_gpio_in(&s->busdev.qdev, ftspi020_handle_ack, 1);
>>> +    qdev_init_gpio_out(&s->busdev.qdev, &s->req, 1);
>>> +
>>> +    return 0;
>>> +}
>>> +
>>> +static const VMStateDescription vmstate_ftspi020 = {
>>> +    .name = TYPE_FTSPI020,
>>> +    .version_id = 1,
>>> +    .minimum_version_id = 1,
>>> +    .minimum_version_id_old = 1,
>>> +    .fields = (VMStateField[]) {
>>> +        VMSTATE_UINT32_ARRAY(cmd, Ftspi020State, 4),
>>> +        VMSTATE_UINT32(ctrl, Ftspi020State),
>>> +        VMSTATE_UINT32(timing, Ftspi020State),
>>> +        VMSTATE_UINT32(icr, Ftspi020State),
>>> +        VMSTATE_UINT32(isr, Ftspi020State),
>>> +        VMSTATE_UINT32(rdsr, Ftspi020State),
>>> +        VMSTATE_END_OF_LIST(),
>>> +    }
>>> +};
>>> +
>>> +static void ftspi020_class_init(ObjectClass *klass, void *data)
>>> +{
>>> +    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
>>> +    DeviceClass *dc = DEVICE_CLASS(klass);
>>> +
>>> +    k->init     = ftspi020_init;
>>> +    dc->vmsd    = &vmstate_ftspi020;
>>> +    dc->reset   = ftspi020_reset;
>>> +    dc->no_user = 1;
>>> +}
>>> +
>>> +static const TypeInfo ftspi020_info = {
>>> +    .name          = TYPE_FTSPI020,
>>> +    .parent        = TYPE_SYS_BUS_DEVICE,
>>> +    .instance_size = sizeof(Ftspi020State),
>>> +    .class_init    = ftspi020_class_init,
>>> +};
>>> +
>>> +static void ftspi020_register_types(void)
>>> +{
>>> +    type_register_static(&ftspi020_info);
>>> +}
>>> +
>>> +type_init(ftspi020_register_types)
>>> diff --git a/hw/arm/ftspi020.h b/hw/arm/ftspi020.h
>>> new file mode 100644
>>> index 0000000..47b5d2e
>>> --- /dev/null
>>> +++ b/hw/arm/ftspi020.h
>>> @@ -0,0 +1,81 @@
>>> +/*
>>> + * Faraday FTSPI020 Flash Controller
>>> + *
>>> + * Copyright (c) 2012 Faraday Technology
>>> + * Written by Dante Su <dantesu@faraday-tech.com>
>>> + *
>>> + * This code is licensed under GNU GPL v2+.
>>> + */
>>> +
>>> +#ifndef HW_ARM_FTSPI020_H
>>> +#define HW_ARM_FTSPI020_H
>>> +
>>> +#include "qemu/bitops.h"
>>> +
>>> +/* Number of CS lines */
>>> +#define CFG_NR_CSLINES      4
>>> +
>>> +/******************************************************************************
>>> + * FTSPI020 registers
>>> + *****************************************************************************/
>>> +#define REG_CMD0            0x00    /* Flash address */
>>> +#define REG_CMD1            0x04
>>> +#define REG_CMD2            0x08    /* Flash data counter */
>>> +#define REG_CMD3            0x0c
>>> +#define REG_CR              0x10    /* Control Register */
>>> +#define REG_TR              0x14    /* AC Timing Register */
>>> +#define REG_SR              0x18    /* Status Register */
>>> +#define REG_ICR             0x20    /* Interrupt Control Register */
>>> +#define REG_ISR             0x24    /* Interrupt Status Register */
>>> +#define REG_RDSR            0x28    /* Read Status Register */
>>> +#define REG_REVR            0x50    /* Revision Register */
>>> +#define REG_FEAR            0x54    /* Feature Register */
>>> +#define REG_DR              0x100   /* Data Register */
>>> +
>>> +#define CMD1_CTRD           BIT(28) /* Enable 1 byte continuous read */
>>> +#define CMD1_INST_LEN(x)    (((x) & 0x03) << 24)/* instruction length */
>>> +#define CMD1_DCLK_LEN(x)    (((x) & 0xff) << 16)/* dummy clock length */
>>> +#define CMD1_ADDR_LEN(x)    (((x) & 0x07) << 0) /* address length */
>>> +
>>> +#define CMD3_INST_OPC(x)    (((x) & 0xff) << 24)/* instruction op code */
>>> +#define CMD3_CTRD_OPC(x)    (((x) & 0xff) << 16)/* cont. read op code */
>>> +#define CMD3_CS(x)          (((x) & 0x0f) << 8) /* chip select */
>>> +#define CMD3_OPM_STD        (0)         /* standard 1-bit serial mode */
>>> +#define CMD3_OPM_DUAL       (1 << 5)    /* fast read dual */
>>> +#define CMD3_OPM_QUAD       (2 << 5)    /* fast read quad */
>>> +#define CMD3_OPM_DUALIO     (3 << 5)    /* fast read dual io */
>>> +#define CMD3_OPM_QUADIO     (4 << 5)    /* fast read quad io */
>>> +#define CMD3_DTR            BIT(4)  /* Enable double transfer rate */
>>> +#define CMD3_RDSR_HW        (0)     /* Enable HW polling RDSR */
>>> +#define CMD3_RDSR_SW        BIT(3)  /* Disable HW polling RDSR */
>>> +#define CMD3_RDSR           BIT(2)  /* Indicate it's a RDSR command */
>>> +#define CMD3_READ           0       /* Indicate it's a read command */
>>> +#define CMD3_WRITE          BIT(1)  /* Indicate it's a write command */
>>> +#define CMD3_INTR           BIT(0)  /* Enable interrupt and status update */
>>> +
>>> +#define CR_BUSYBIT(x)       (((x) & 0x07) << 16) /* Busy bit in the RDSR */
>>> +#define CR_ABORT            BIT(8)
>>> +#define CR_MODE0            0       /* SPI MODE0 */
>>> +#define CR_MODE3            BIT(4)  /* SPI MODE3 */
>>> +#define CR_CLKDIV(n)        ((n) & 0x03)    /* Clock divider = 2 * (n + 1) */
>>> +
>>> +#define TR_TRACE(x)         (((x) & 0x0f) << 4) /* trace delay */
>>> +#define TR_CS(x)            (((x) & 0x0f) << 0) /* cs delay */
>>> +
>>> +#define SR_RX_READY         BIT(1)  /* Rx Ready */
>>> +#define SR_TX_READY         BIT(0)  /* Tx Ready */
>>> +
>>> +#define ICR_RX_THRES(x)     (((x) & 0x03) << 12)/* rx interrupt threshold */
>>> +#define ICR_TX_THRES(x)     (((x) & 0x03) << 8) /* tx interrupt threshold */
>>> +#define ICR_DMA             BIT(0)  /* Enable DMA HW handshake */
>>> +
>>> +#define ISR_CMDFIN          BIT(0)  /* Command finished interrupt */
>>> +
>>> +#define FEAR_CLKM_BYPORT    0       /* clock mode = byport */
>>> +#define FEAR_CLKM_SYNC      BIT(25) /* clock mode = sync */
>>> +#define FEAR_SUPP_DTR       BIT(24) /* support double transfer rate */
>>> +#define FEAR_CMDQ(x)        (((x) & 0x07) << 16)    /* cmd queue depth */
>>> +#define FEAR_RXFIFO(x)      (((x) & 0xff) << 8)     /* rx fifo depth */
>>> +#define FEAR_TXFIFO(x)      (((x) & 0xff) << 0)     /* tx fifo depth */
>>> +
>>> +#endif  /* HW_ARM_FTSPI020_H */
>>> --
>>> 1.7.9.5
>>>
>>>
>
>
>
> --
> Best wishes,
> Kuo-Jung Su
>

Comments

Kuo-Jung Su Feb. 27, 2013, 6:49 a.m. UTC | #1
2013/2/27 Peter Crosthwaite <peter.crosthwaite@xilinx.com>:
> Hi Kuo-Jung,
>
> On Wed, Feb 27, 2013 at 12:08 PM, Kuo-Jung Su <dantesu@gmail.com> wrote:
>> 2013/2/26 Peter Crosthwaite <peter.crosthwaite@xilinx.com>:
>>> Hi Kuo-Jung,
>>>
>>> On Tue, Feb 26, 2013 at 7:14 PM, Kuo-Jung Su <dantesu@gmail.com> wrote:
>>>> From: Kuo-Jung Su <dantesu@faraday-tech.com>
>>>>
>>>> The FTSPI020 is an integrated SPI Flash controller
>>>> which supports upto 4 flash chips.
>>>>
>>>> Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
>>>> ---
>>>
>>> Please provide change logs below the line as per the patch submission process.
>>>
>>>>  hw/arm/Makefile.objs      |    1 +
>>>>  hw/arm/faraday_a369.c     |   13 ++
>>>>  hw/arm/faraday_a369_soc.c |    4 +
>>>>  hw/arm/ftspi020.c         |  333 +++++++++++++++++++++++++++++++++++++++++++++
>>>>  hw/arm/ftspi020.h         |   81 +++++++++++
>>>>  5 files changed, 432 insertions(+)
>>>>  create mode 100644 hw/arm/ftspi020.c
>>>>  create mode 100644 hw/arm/ftspi020.h
>>>>
>>>> diff --git a/hw/arm/Makefile.objs b/hw/arm/Makefile.objs
>>>> index c25eba2..2ed1c7c 100644
>>>> --- a/hw/arm/Makefile.objs
>>>> +++ b/hw/arm/Makefile.objs
>>>> @@ -52,3 +52,4 @@ obj-y += ftgmac100.o
>>>>  obj-y += ftlcdc200.o
>>>>  obj-y += fttsc010.o
>>>>  obj-y += ftsdc010.o
>>>> +obj-y += ftspi020.o
>>>> diff --git a/hw/arm/faraday_a369.c b/hw/arm/faraday_a369.c
>>>> index 46fc570..ace0784 100644
>>>> --- a/hw/arm/faraday_a369.c
>>>> +++ b/hw/arm/faraday_a369.c
>>>> @@ -67,6 +67,19 @@ a369_board_init(QEMUMachineInitArgs *args)
>>>>          wm8731_data_req_set(s->codec, ftssp010_i2s_data_req, s->i2s[0]);
>>>>      }
>>>>
>>>> +    /* Attach the spi flash to ftspi020.0 */
>>>> +    nr_flash = 1;
>>>> +    for (i = 0; i < nr_flash; i++) {
>>>> +        SSIBus *ssi = (SSIBus *)qdev_get_child_bus(s->spi[1], "spi");
>>>> +        DeviceState *fl = ssi_create_slave_no_init(ssi, "m25p80");
>>>> +        qemu_irq cs_line;
>>>> +
>>>> +        qdev_prop_set_string(fl, "partname", "w25q64");
>>>> +        qdev_init_nofail(fl);
>>>> +        cs_line = qdev_get_gpio_in(fl, 0);
>>>> +        sysbus_connect_irq(SYS_BUS_DEVICE(s->spi[1]), i + 1, cs_line);
>>>> +    }
>>>> +
>>>>      if (args->kernel_filename) {
>>>>          s->bi = g_new0(struct arm_boot_info, 1);
>>>>
>>>> diff --git a/hw/arm/faraday_a369_soc.c b/hw/arm/faraday_a369_soc.c
>>>> index eb9dd2f..8b07689 100644
>>>> --- a/hw/arm/faraday_a369_soc.c
>>>> +++ b/hw/arm/faraday_a369_soc.c
>>>> @@ -272,6 +272,10 @@ a369soc_device_init(FaradaySoCState *s)
>>>>      req = qdev_get_gpio_in(s->hdma[0], 13);
>>>>      qdev_connect_gpio_out(s->hdma[0], 13, ack);
>>>>      qdev_connect_gpio_out(ds, 0, req);
>>>> +
>>>> +    /* ftspi020: as an external AHB device */
>>>> +    ds = sysbus_create_simple("ftspi020", 0xC0000000, pic[4]);
>>>> +    s->spi[1] = ds;
>>>>  }
>>>>
>>>>  static int a369soc_init(SysBusDevice *busdev)
>>>> diff --git a/hw/arm/ftspi020.c b/hw/arm/ftspi020.c
>>>> new file mode 100644
>>>> index 0000000..fb8a510
>>>> --- /dev/null
>>>> +++ b/hw/arm/ftspi020.c
>>>> @@ -0,0 +1,333 @@
>>>> +/*
>>>> + * Faraday FTSPI020 Flash Controller
>>>> + *
>>>> + * Copyright (c) 2012 Faraday Technology
>>>> + * Written by Dante Su <dantesu@faraday-tech.com>
>>>> + *
>>>> + * This code is licensed under GNU GPL v2+.
>>>> + */
>>>> +
>>>> +#include "hw/hw.h"
>>>> +#include "sysemu/sysemu.h"
>>>> +#include "hw/sysbus.h"
>>>> +#include "hw/ssi.h"
>>>> +
>>>> +#include "ftspi020.h"
>>>> +
>>>> +#define TYPE_FTSPI020   "ftspi020"
>>>> +
>>>> +typedef struct Ftspi020State {
>>>> +    SysBusDevice busdev;
>>>> +    MemoryRegion iomem;
>>>> +    qemu_irq irq;
>>>> +
>>>> +    /* DMA hardware handshake */
>>>> +    qemu_irq req;
>>>> +
>>>> +    SSIBus *spi;
>>>> +    qemu_irq *cs_lines;
>>>> +
>>>> +    int wip;    /* SPI Flash Status: Write In Progress BIT shift */
>>>> +
>>>> +    /* HW register caches */
>>>> +    uint32_t cmd[4];
>>>> +    uint32_t ctrl;
>>>> +    uint32_t timing;
>>>> +    uint32_t icr;
>>>> +    uint32_t isr;
>>>> +    uint32_t rdsr;
>>>> +} Ftspi020State;
>>>> +
>>>> +#define FTSPI020(obj) \
>>>> +    OBJECT_CHECK(Ftspi020State, obj, TYPE_FTSPI020)
>>>> +
>>>> +static void ftspi020_update_irq(Ftspi020State *s)
>>>> +{
>>>> +    qemu_set_irq(s->irq, s->isr ? 1 : 0);
>>>> +}
>>>> +
>>>> +static void ftspi020_handle_ack(void *opaque, int line, int level)
>>>> +{
>>>> +    Ftspi020State *s = FTSPI020(opaque);
>>>> +
>>>> +    if (!(s->icr & ICR_DMA)) {
>>>> +        return;
>>>> +    }
>>>> +
>>>> +    if (level) {
>>>> +        qemu_set_irq(s->req, 0);
>>>> +    } else if (s->cmd[2]) {
>>>> +        qemu_set_irq(s->req, 1);
>>>> +    }
>>>> +}
>>>> +
>>>> +static int ftspi020_do_command(Ftspi020State *s)
>>>> +{
>>>> +    uint32_t cs   = extract32(s->cmd[3],  8, 2);
>>>> +    uint32_t cmd  = extract32(s->cmd[3], 24, 8);
>>>> +    uint32_t ilen = extract32(s->cmd[1], 24, 2);
>>>> +    uint32_t alen = extract32(s->cmd[1],  0, 3);
>>>> +    uint32_t dcyc = extract32(s->cmd[1], 16, 8);
>>>> +
>>>> +    if (dcyc % 8) {
>>>> +        hw_error("ftspi020: bad dummy clock (%u) to QEMU\n", dcyc);
>>>> +        exit(1);
>>>> +    }
>>>> +
>>>> +    /* make sure the spi flash is de-activated */
>>>> +    qemu_set_irq(s->cs_lines[cs], 1);
>>>> +
>>>> +    /* activate the spi flash */
>>>> +    qemu_set_irq(s->cs_lines[cs], 0);
>>>> +
>>>> +    /* if it's a SPI flash READ_STATUS command */
>>>> +    if ((s->cmd[3] & (CMD3_RDSR | CMD3_WRITE)) == CMD3_RDSR) {
>>>> +        uint32_t rdsr;
>>>> +
>>>> +        ssi_transfer(s->spi, cmd);
>>>> +        do {
>>>> +            rdsr = ssi_transfer(s->spi, 0x00);
>>>> +            if (s->cmd[3] & CMD3_RDSR_SW) {
>>>> +                break;
>>>> +            }
>>>> +        } while (rdsr & (1 << s->wip));
>>>> +        s->rdsr = rdsr;
>>>> +    } else {
>>>> +    /* otherwise */
>>>> +        int i;
>>>> +
>>>> +        ilen = MIN(ilen, 2);
>>>> +        alen = MIN(alen, 4);
>>>> +
>>>> +        /* command cycles */
>>>> +        for (i = 0; i < ilen; ++i) {
>>>> +            ssi_transfer(s->spi, cmd);
>>>> +        }
>>>> +        /* address cycles */
>>>> +        for (i = alen - 1; i >= 0; --i) {
>>>> +            ssi_transfer(s->spi, extract32(s->cmd[0], i * 8, 8));
>>>> +        }
>>>> +        /* dummy cycles */
>>>> +        for (i = 0; i < (dcyc >> 3); ++i) {
>>>> +            ssi_transfer(s->spi, 0x00);
>>>> +        }
>>>> +    }
>>>> +
>>>> +    if (!s->cmd[2]) {
>>>> +        qemu_set_irq(s->cs_lines[cs], 1);
>>>> +    } else if (s->icr & ICR_DMA) {
>>>> +        qemu_set_irq(s->req, 1);
>>>> +    }
>>>> +
>>>> +    if (s->cmd[3] & CMD3_INTR) {
>>>> +        s->isr |= ISR_CMDFIN;
>>>> +    }
>>>> +    ftspi020_update_irq(s);
>>>> +
>>>> +    return 0;
>>>> +}
>>>> +
>>>> +static void ftspi020_chip_reset(Ftspi020State *s)
>>>> +{
>>>> +    int i;
>>>> +
>>>> +    for (i = 0; i < 4; ++i) {
>>>> +        s->cmd[i] = 0;
>>>> +    }
>>>> +    s->wip = 0;
>>>> +    s->ctrl = 0;
>>>> +    s->timing = 0;
>>>> +    s->icr = 0;
>>>> +    s->isr = 0;
>>>> +    s->rdsr = 0;
>>>> +
>>>> +    qemu_set_irq(s->irq, 0);
>>>> +
>>>> +    /* DO NOT reset cs lines here, or the QEMU would crash */
>>>
>>> More information please. This should work. What happened?
>>>
>>
>> If there is no spi flash connected with the specific cs_line,
>> de-activate the cs_line
>> in the ftspi020_chip_reset() would crash the QEMU without any error message.
>> I've checked qemu_set_irq() and ssi_cs_default(), but no luck.
>>
>
> It might be a case of un-initialised irqs. See my comment further below.
>
>>>> +}
>>>> +
>>>> +static uint64_t
>>>> +ftspi020_mem_read(void *opaque, hwaddr addr, unsigned size)
>>>> +{
>>>> +    Ftspi020State *s = FTSPI020(opaque);
>>>> +    uint64_t ret = 0;
>>>> +
>>>> +    switch (addr) {
>>>> +    case REG_CMD0 ... REG_CMD3:
>>>> +        return s->cmd[(addr - REG_CMD0) / 4];
>>>> +    case REG_CR:
>>>> +        return s->ctrl;
>>>> +    case REG_TR:
>>>> +        return s->timing;
>>>> +    case REG_SR:
>>>> +        /* In QEMU, the data fifo is always ready for read/write */
>>>> +        return SR_RX_READY | SR_TX_READY;
>>>> +    case REG_ISR:
>>>> +        return s->isr;
>>>> +    case REG_ICR:
>>>> +        return s->icr;
>>>> +    case REG_RDSR:
>>>> +        return s->rdsr;
>>>> +    case REG_REVR:
>>>> +        return 0x00010001;  /* rev. 1.0.1 */
>>>> +    case REG_FEAR:
>>>> +        return FEAR_CLKM_SYNC
>>>> +            | FEAR_CMDQ(2) | FEAR_RXFIFO(32) | FEAR_TXFIFO(32);
>>>> +    case REG_DR:
>>>> +        if (!(s->cmd[3] & CMD3_WRITE)) {
>>>> +            int i;
>>>> +            uint32_t cs = extract32(s->cmd[3], 8, 2);
>>>> +            for (i = 0; i < 4 && s->cmd[2]; i++, s->cmd[2]--) {
>>>> +                ret = deposit32(ret, i * 8, 8,
>>>> +                    ssi_transfer(s->spi, 0x00) & 0xff);
>>>> +            }
>>>> +            if (!s->cmd[2]) {
>>>> +                qemu_set_irq(s->cs_lines[cs], 1);
>>>> +                if (s->cmd[3] & CMD3_INTR) {
>>>> +                    s->isr |= ISR_CMDFIN;
>>>> +                }
>>>> +                ftspi020_update_irq(s);
>>>> +            }
>>>> +        }
>>>> +        break;
>>>> +        /* we don't care */
>>>> +    default:
>>>
>>> You could qemu_log_mask(LOG_GUEST_ERROR on undefined memory accesses.
>>>
>>
>> Got it, thanks.
>>
>>>> +        break;
>>>> +    }
>>>> +
>>>> +    return ret;
>>>> +}
>>>> +
>>>> +static void
>>>> +ftspi020_mem_write(void *opaque, hwaddr addr, uint64_t val, unsigned size)
>>>> +{
>>>> +    Ftspi020State *s = FTSPI020(opaque);
>>>> +
>>>> +    switch (addr) {
>>>> +    case REG_CMD0 ... REG_CMD2:
>>>> +        s->cmd[(addr - REG_CMD0) / 4] = (uint32_t)val;
>>>> +        break;
>>>> +    case REG_CMD3:
>>>> +        s->cmd[3] = (uint32_t)val;
>>>> +        ftspi020_do_command(s);
>>>> +        break;
>>>> +    case REG_CR:
>>>> +        if (val & CR_ABORT) {
>>>> +            ftspi020_chip_reset(s);
>>>> +            val &= ~CR_ABORT;
>>>> +        }
>>>> +        s->ctrl = (uint32_t)val;
>>>> +        s->wip  = extract32(val, 16, 3);
>>>> +        break;
>>>> +    case REG_TR:
>>>> +        s->timing = (uint32_t)val;
>>>> +        break;
>>>> +    case REG_DR:
>>>> +        if (s->cmd[3] & CMD3_WRITE) {
>>>> +            int i;
>>>> +            uint32_t cs = extract32(s->cmd[3], 8, 2);
>>>> +            for (i = 0; i < 4 && s->cmd[2]; i++, s->cmd[2]--) {
>>>> +                ssi_transfer(s->spi, extract32((uint32_t)val, i * 8, 8));
>>>> +            }
>>>> +            if (!s->cmd[2]) {
>>>> +                qemu_set_irq(s->cs_lines[cs], 1);
>>>> +                if (s->cmd[3] & CMD3_INTR) {
>>>> +                    s->isr |= ISR_CMDFIN;
>>>> +                }
>>>> +                ftspi020_update_irq(s);
>>>> +            }
>>>> +        }
>>>> +        break;
>>>> +    case REG_ISR:
>>>> +        s->isr &= ~((uint32_t)val);
>>>> +        ftspi020_update_irq(s);
>>>> +        break;
>>>> +    case REG_ICR:
>>>> +        s->icr = (uint32_t)val;
>>>> +        break;
>>>> +        /* we don't care */
>>>> +    default:
>>>> +        break;
>>>> +    }
>>>> +}
>>>> +
>>>> +static const MemoryRegionOps ftspi020_ops = {
>>>> +    .read  = ftspi020_mem_read,
>>>> +    .write = ftspi020_mem_write,
>>>
>>> Your REG_FOO macros are jumping in fours, and the case statement in
>>> your read/write handlers only handles those values, leading me to
>>> believe your device only supports full word access. You should enforce
>>> this by setting min/max_access size to 4 here.
>>>
>>
>> Got it, thanks.
>>
>>> Regards,
>>> Peter
>>>
>>>> +    .endianness = DEVICE_LITTLE_ENDIAN,
>>>> +};
>>>> +
>>>> +static void ftspi020_reset(DeviceState *ds)
>>>> +{
>>>> +    SysBusDevice *busdev = SYS_BUS_DEVICE(ds);
>>>> +    Ftspi020State *s = FTSPI020(FROM_SYSBUS(Ftspi020State, busdev));
>>>> +
>>>> +    ftspi020_chip_reset(s);
>>>> +}
>>>> +
>>>> +static int ftspi020_init(SysBusDevice *dev)
>>>> +{
>>>> +    Ftspi020State *s = FTSPI020(FROM_SYSBUS(Ftspi020State, dev));
>>>> +    int i;
>>>> +
>>>> +    memory_region_init_io(&s->iomem,
>>>> +                          &ftspi020_ops,
>>>> +                          s,
>>>> +                          TYPE_FTSPI020,
>>>> +                          0x1000);
>>>> +    sysbus_init_mmio(dev, &s->iomem);
>>>> +    sysbus_init_irq(dev, &s->irq);
>>>> +
>>>> +    s->spi = ssi_create_bus(&dev->qdev, "spi");
>>>> +    s->cs_lines = g_new(qemu_irq, CFG_NR_CSLINES);
>
> s/g_new/g_new0. That will knock out your un-attached IRQ lines. You
> may have contagiously contracted this bug from xilinx_spips I think.
> My fix to spips is currently on list:
>
> commit d474fc0447fabaeb5f51ccbd88973c7f85ea1abe
> Author: Peter Crosthwaite <peter.crosthwaite@xilinx.com>
> Date:   Thu Nov 29 14:39:56 2012 +1000
>
>     xilinx_spips: Set unused IRQs to NULL
>
>     Unused CS lines should init to 0 to avoid segfaulting when accessing an
>     unattached QSPI controller.
>
>     Signed-off-by: Peter Crosthwaite <peter.crosthwaite@xilinx.com>
>
> diff --git a/hw/xilinx_spips.c b/hw/xilinx_spips.c
> index 42e019d..3eee828 100644
> --- a/hw/xilinx_spips.c
> +++ b/hw/xilinx_spips.c
> @@ -497,7 +497,7 @@ static int xilinx_spips_init(SysBusDevice *dev)
>          s->spi[i] = ssi_create_bus(&dev->qdev, bus_name);
>      }
>
> -    s->cs_lines = g_new(qemu_irq, s->num_cs * s->num_busses);
> +    s->cs_lines = g_new0(qemu_irq, s->num_cs * s->num_busses);
>      ssi_auto_connect_slaves(DEVICE(s), s->cs_lines, s->spi[0]);
>      ssi_auto_connect_slaves(DEVICE(s), s->cs_lines, s->spi[1]);
>      sysbus_init_irq(dev, &s->irq);
>
> Regards,
> Peter
>

You're absolutely right, after replacing 'g_new' with 'g_new0' for s->cs_lines,
the FTSPI020 now works gracefully with de-activating the cs lines in
its own reset functions.

>>>> +    ssi_auto_connect_slaves(DEVICE(s), s->cs_lines, s->spi);
>>>> +    for (i = 0; i < CFG_NR_CSLINES; ++i) {
>>>> +        sysbus_init_irq(dev, &s->cs_lines[i]);
>>>> +    }
>>>> +
>>>> +    qdev_init_gpio_in(&s->busdev.qdev, ftspi020_handle_ack, 1);
>>>> +    qdev_init_gpio_out(&s->busdev.qdev, &s->req, 1);
>>>> +
>>>> +    return 0;
>>>> +}
>>>> +
>>>> +static const VMStateDescription vmstate_ftspi020 = {
>>>> +    .name = TYPE_FTSPI020,
>>>> +    .version_id = 1,
>>>> +    .minimum_version_id = 1,
>>>> +    .minimum_version_id_old = 1,
>>>> +    .fields = (VMStateField[]) {
>>>> +        VMSTATE_UINT32_ARRAY(cmd, Ftspi020State, 4),
>>>> +        VMSTATE_UINT32(ctrl, Ftspi020State),
>>>> +        VMSTATE_UINT32(timing, Ftspi020State),
>>>> +        VMSTATE_UINT32(icr, Ftspi020State),
>>>> +        VMSTATE_UINT32(isr, Ftspi020State),
>>>> +        VMSTATE_UINT32(rdsr, Ftspi020State),
>>>> +        VMSTATE_END_OF_LIST(),
>>>> +    }
>>>> +};
>>>> +
>>>> +static void ftspi020_class_init(ObjectClass *klass, void *data)
>>>> +{
>>>> +    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
>>>> +    DeviceClass *dc = DEVICE_CLASS(klass);
>>>> +
>>>> +    k->init     = ftspi020_init;
>>>> +    dc->vmsd    = &vmstate_ftspi020;
>>>> +    dc->reset   = ftspi020_reset;
>>>> +    dc->no_user = 1;
>>>> +}
>>>> +
>>>> +static const TypeInfo ftspi020_info = {
>>>> +    .name          = TYPE_FTSPI020,
>>>> +    .parent        = TYPE_SYS_BUS_DEVICE,
>>>> +    .instance_size = sizeof(Ftspi020State),
>>>> +    .class_init    = ftspi020_class_init,
>>>> +};
>>>> +
>>>> +static void ftspi020_register_types(void)
>>>> +{
>>>> +    type_register_static(&ftspi020_info);
>>>> +}
>>>> +
>>>> +type_init(ftspi020_register_types)
>>>> diff --git a/hw/arm/ftspi020.h b/hw/arm/ftspi020.h
>>>> new file mode 100644
>>>> index 0000000..47b5d2e
>>>> --- /dev/null
>>>> +++ b/hw/arm/ftspi020.h
>>>> @@ -0,0 +1,81 @@
>>>> +/*
>>>> + * Faraday FTSPI020 Flash Controller
>>>> + *
>>>> + * Copyright (c) 2012 Faraday Technology
>>>> + * Written by Dante Su <dantesu@faraday-tech.com>
>>>> + *
>>>> + * This code is licensed under GNU GPL v2+.
>>>> + */
>>>> +
>>>> +#ifndef HW_ARM_FTSPI020_H
>>>> +#define HW_ARM_FTSPI020_H
>>>> +
>>>> +#include "qemu/bitops.h"
>>>> +
>>>> +/* Number of CS lines */
>>>> +#define CFG_NR_CSLINES      4
>>>> +
>>>> +/******************************************************************************
>>>> + * FTSPI020 registers
>>>> + *****************************************************************************/
>>>> +#define REG_CMD0            0x00    /* Flash address */
>>>> +#define REG_CMD1            0x04
>>>> +#define REG_CMD2            0x08    /* Flash data counter */
>>>> +#define REG_CMD3            0x0c
>>>> +#define REG_CR              0x10    /* Control Register */
>>>> +#define REG_TR              0x14    /* AC Timing Register */
>>>> +#define REG_SR              0x18    /* Status Register */
>>>> +#define REG_ICR             0x20    /* Interrupt Control Register */
>>>> +#define REG_ISR             0x24    /* Interrupt Status Register */
>>>> +#define REG_RDSR            0x28    /* Read Status Register */
>>>> +#define REG_REVR            0x50    /* Revision Register */
>>>> +#define REG_FEAR            0x54    /* Feature Register */
>>>> +#define REG_DR              0x100   /* Data Register */
>>>> +
>>>> +#define CMD1_CTRD           BIT(28) /* Enable 1 byte continuous read */
>>>> +#define CMD1_INST_LEN(x)    (((x) & 0x03) << 24)/* instruction length */
>>>> +#define CMD1_DCLK_LEN(x)    (((x) & 0xff) << 16)/* dummy clock length */
>>>> +#define CMD1_ADDR_LEN(x)    (((x) & 0x07) << 0) /* address length */
>>>> +
>>>> +#define CMD3_INST_OPC(x)    (((x) & 0xff) << 24)/* instruction op code */
>>>> +#define CMD3_CTRD_OPC(x)    (((x) & 0xff) << 16)/* cont. read op code */
>>>> +#define CMD3_CS(x)          (((x) & 0x0f) << 8) /* chip select */
>>>> +#define CMD3_OPM_STD        (0)         /* standard 1-bit serial mode */
>>>> +#define CMD3_OPM_DUAL       (1 << 5)    /* fast read dual */
>>>> +#define CMD3_OPM_QUAD       (2 << 5)    /* fast read quad */
>>>> +#define CMD3_OPM_DUALIO     (3 << 5)    /* fast read dual io */
>>>> +#define CMD3_OPM_QUADIO     (4 << 5)    /* fast read quad io */
>>>> +#define CMD3_DTR            BIT(4)  /* Enable double transfer rate */
>>>> +#define CMD3_RDSR_HW        (0)     /* Enable HW polling RDSR */
>>>> +#define CMD3_RDSR_SW        BIT(3)  /* Disable HW polling RDSR */
>>>> +#define CMD3_RDSR           BIT(2)  /* Indicate it's a RDSR command */
>>>> +#define CMD3_READ           0       /* Indicate it's a read command */
>>>> +#define CMD3_WRITE          BIT(1)  /* Indicate it's a write command */
>>>> +#define CMD3_INTR           BIT(0)  /* Enable interrupt and status update */
>>>> +
>>>> +#define CR_BUSYBIT(x)       (((x) & 0x07) << 16) /* Busy bit in the RDSR */
>>>> +#define CR_ABORT            BIT(8)
>>>> +#define CR_MODE0            0       /* SPI MODE0 */
>>>> +#define CR_MODE3            BIT(4)  /* SPI MODE3 */
>>>> +#define CR_CLKDIV(n)        ((n) & 0x03)    /* Clock divider = 2 * (n + 1) */
>>>> +
>>>> +#define TR_TRACE(x)         (((x) & 0x0f) << 4) /* trace delay */
>>>> +#define TR_CS(x)            (((x) & 0x0f) << 0) /* cs delay */
>>>> +
>>>> +#define SR_RX_READY         BIT(1)  /* Rx Ready */
>>>> +#define SR_TX_READY         BIT(0)  /* Tx Ready */
>>>> +
>>>> +#define ICR_RX_THRES(x)     (((x) & 0x03) << 12)/* rx interrupt threshold */
>>>> +#define ICR_TX_THRES(x)     (((x) & 0x03) << 8) /* tx interrupt threshold */
>>>> +#define ICR_DMA             BIT(0)  /* Enable DMA HW handshake */
>>>> +
>>>> +#define ISR_CMDFIN          BIT(0)  /* Command finished interrupt */
>>>> +
>>>> +#define FEAR_CLKM_BYPORT    0       /* clock mode = byport */
>>>> +#define FEAR_CLKM_SYNC      BIT(25) /* clock mode = sync */
>>>> +#define FEAR_SUPP_DTR       BIT(24) /* support double transfer rate */
>>>> +#define FEAR_CMDQ(x)        (((x) & 0x07) << 16)    /* cmd queue depth */
>>>> +#define FEAR_RXFIFO(x)      (((x) & 0xff) << 8)     /* rx fifo depth */
>>>> +#define FEAR_TXFIFO(x)      (((x) & 0xff) << 0)     /* tx fifo depth */
>>>> +
>>>> +#endif  /* HW_ARM_FTSPI020_H */
>>>> --
>>>> 1.7.9.5
>>>>
>>>>
>>
>>
>>
>> --
>> Best wishes,
>> Kuo-Jung Su
>>



--
Best wishes,
Kuo-Jung Su
diff mbox

Patch

diff --git a/hw/xilinx_spips.c b/hw/xilinx_spips.c
index 42e019d..3eee828 100644
--- a/hw/xilinx_spips.c
+++ b/hw/xilinx_spips.c
@@ -497,7 +497,7 @@  static int xilinx_spips_init(SysBusDevice *dev)
         s->spi[i] = ssi_create_bus(&dev->qdev, bus_name);
     }

-    s->cs_lines = g_new(qemu_irq, s->num_cs * s->num_busses);
+    s->cs_lines = g_new0(qemu_irq, s->num_cs * s->num_busses);
     ssi_auto_connect_slaves(DEVICE(s), s->cs_lines, s->spi[0]);
     ssi_auto_connect_slaves(DEVICE(s), s->cs_lines, s->spi[1]);
     sysbus_init_irq(dev, &s->irq);