All of lore.kernel.org
 help / color / mirror / Atom feed
From: Kuo-Jung Su <dantesu@gmail.com>
To: Peter Crosthwaite <peter.crosthwaite@xilinx.com>
Cc: Peter Maydell <peter.maydell@linaro.org>,
	Igor Mitsyanko <i.mitsyanko@samsung.com>,
	qemu-devel@nongnu.org, Blue Swirl <blauwirbel@gmail.com>,
	Paul Brook <paul@codesourcery.com>,
	Kuo-Jung Su <dantesu@faraday-tech.com>,
	Andreas <afaerber@suse.de>,
	fred konrad <fred.konrad@greensocs.com>
Subject: Re: [Qemu-devel] [PATCH v9 16/24] The FTSSP010 is a multi-function synchronous serial port interface controller which supports SSP, SPI, I2S, AC97 and SPDIF.
Date: Mon, 1 Apr 2013 09:18:53 +0800	[thread overview]
Message-ID: <CAK65tU6K=0k7DshjaLbHv-JFupFV9RdyUscm44-VAoP6jGybqw@mail.gmail.com> (raw)
In-Reply-To: <CAEgOgz5whifqiFEaEVFKJAP3KvmakG10OYKYLDsRjm26_EAOTQ@mail.gmail.com>

2013/3/31 Peter Crosthwaite <peter.crosthwaite@xilinx.com>:
> Hi Kuo-Jung
>
> I think you may have accidentally dropped your subject line and
> promoted your long commit message to subject line. Looks better in
> previous versions.
>

Yes, it's an accident, I'll fix it later.

> On Mon, Mar 25, 2013 at 10:09 PM, Kuo-Jung Su <dantesu@gmail.com> wrote:
>>
>> From: Kuo-Jung Su <dantesu@faraday-tech.com>
>>
>> Only I2S and SPI protocol have been implemented in this patch.
>>
>> Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
>> ---
>>  hw/arm/Makefile.objs    |    3 +-
>>  hw/arm/ftplat_a369.c    |   31 +++
>>  hw/arm/ftplat_a369soc.c |   17 ++
>>  hw/faraday.h            |    3 +
>>  hw/ftssp010.c           |  504 +++++++++++++++++++++++++++++++++++++++++++++++
>>  hw/ftssp010.h           |   96 +++++++++
>>  6 files changed, 653 insertions(+), 1 deletion(-)
>>  create mode 100644 hw/ftssp010.c
>>  create mode 100644 hw/ftssp010.h
>>
>> diff --git a/hw/arm/Makefile.objs b/hw/arm/Makefile.objs
>> index 2bb67f7..42c8472 100644
>> --- a/hw/arm/Makefile.objs
>> +++ b/hw/arm/Makefile.objs
>> @@ -25,7 +25,8 @@ obj-y += strongarm.o
>>  obj-y += imx_serial.o imx_ccm.o imx_timer.o imx_avic.o
>>  obj-$(CONFIG_KVM) += kvm/arm_gic.o
>>  obj-y += ftintc020.o ftahbc020.o ftddrii030.o ftpwmtmr010.o ftwdt010.o \
>> -                ftrtc011.o ftdmac020.o ftapbbrg020.o ftnandc021.o fti2c010.o
>> +                ftrtc011.o ftdmac020.o ftapbbrg020.o ftnandc021.o fti2c010.o \
>> +                ftssp010.o
>>
>>  obj-y := $(addprefix ../,$(obj-y))
>>
>> diff --git a/hw/arm/ftplat_a369.c b/hw/arm/ftplat_a369.c
>> index 827c58a..922fb55 100644
>> --- a/hw/arm/ftplat_a369.c
>> +++ b/hw/arm/ftplat_a369.c
>> @@ -11,6 +11,7 @@
>>  #include "hw/arm-misc.h"
>>  #include "hw/devices.h"
>>  #include "hw/i2c.h"
>> +#include "hw/audio.h"
>>  #include "hw/boards.h"
>>  #include "hw/ssi.h"
>>  #include "net/net.h"
>> @@ -28,6 +29,7 @@ static void a369_system_reset(void *opaque)
>>
>>  static void a369_board_init(QEMUMachineInitArgs *args)
>>  {
>> +    int i, nr_flash;
>>      ARMCPU *cpu;
>>      DeviceState *ds;
>>      FaradaySoCState *s;
>> @@ -79,6 +81,35 @@ static void a369_board_init(QEMUMachineInitArgs *args)
>>          abort();
>>      }
>>
>> +    /* Attach the spi flash to ftssp010.0 */
>> +    nr_flash = 1;
>> +    for (i = 0; i < nr_flash; i++) {
>> +        SSIBus *ssi = (SSIBus *)qdev_get_child_bus(s->spi[0], "spi");
>> +        DeviceState *fl = ssi_create_slave_no_init(ssi, "w25q64");
>> +        qemu_irq cs_line;
>> +
>> +        qdev_init_nofail(fl);
>> +        cs_line = qdev_get_gpio_in(fl, 0);
>> +        sysbus_connect_irq(SYS_BUS_DEVICE(s->spi[0]), i + 1, cs_line);
>> +    }
>> +
>> +    /* Attach the wm8731 to fti2c010.0 & ftssp010.0 */
>> +    for (i = 0; i < 1; ++i) {
>> +        i2c_bus *i2c = (i2c_bus *)qdev_get_child_bus(s->i2c[0], "i2c");
>> +        ds = i2c_create_slave(i2c, "wm8731", 0x1B);
>> +        object_property_set_link(OBJECT(s->i2s[0]),
>> +                                 OBJECT(ds),
>> +                                 "codec",
>> +                                 &local_errp);
>> +        if (local_errp) {
>> +            fprintf(stderr, "a369: Unable to set codec link for FTSSP010\n");
>> +            abort();
>> +        }
>> +        audio_codec_data_req_set(ds,
>> +                                 ftssp010_i2s_data_req,
>> +                                 s->i2s[0]);
>> +    }
>> +
>>      /* System start-up */
>>
>>      if (args->kernel_filename) {
>> diff --git a/hw/arm/ftplat_a369soc.c b/hw/arm/ftplat_a369soc.c
>> index b6e82ad..9391764 100644
>> --- a/hw/arm/ftplat_a369soc.c
>> +++ b/hw/arm/ftplat_a369soc.c
>> @@ -206,6 +206,23 @@ static void a369soc_chip_init(FaradaySoCState *s)
>>      s->i2c[0] = ds;
>>      ds = sysbus_create_simple("fti2c010", 0x92A00000, s->pic[52]);
>>      s->i2c[1] = ds;
>> +
>> +    /* ftssp010 */
>> +    ds = sysbus_create_simple("ftssp010", 0x92700000, s->pic[49]);
>> +    s->spi[0] = ds;
>> +    s->i2s[0] = ds;
>> +
>> +    /* ftssp010 - DMA (Tx) */
>> +    ack = qdev_get_gpio_in(ds, 0);
>> +    req = qdev_get_gpio_in(s->pdma[0], 7);
>> +    qdev_connect_gpio_out(s->pdma[0], 7, ack);
>> +    qdev_connect_gpio_out(ds, 0, req);
>> +
>> +    /* ftssp010 - DMA (Rx) */
>> +    ack = qdev_get_gpio_in(ds, 1);
>> +    req = qdev_get_gpio_in(s->pdma[0], 8);
>> +    qdev_connect_gpio_out(s->pdma[0], 8, ack);
>> +    qdev_connect_gpio_out(ds, 1, req);
>>  }
>>
>>  static void a369soc_realize(DeviceState *dev, Error **errp)
>> diff --git a/hw/faraday.h b/hw/faraday.h
>> index 7373ba0..39a608c 100644
>> --- a/hw/faraday.h
>> +++ b/hw/faraday.h
>> @@ -121,4 +121,7 @@ static inline void faraday_soc_ahb_remap(FaradaySoCState *s, bool active)
>>      }
>>  }
>>
>> +/* ftssp010.c */
>> +void ftssp010_i2s_data_req(void *opaque, int tx, int rx);
>> +
>>  #endif
>> diff --git a/hw/ftssp010.c b/hw/ftssp010.c
>> new file mode 100644
>> index 0000000..fe1ddbb
>> --- /dev/null
>> +++ b/hw/ftssp010.c
>> @@ -0,0 +1,504 @@
>> +/*
>> + * QEMU model of the FTSSP010 Controller
>> + *
>> + * Copyright (C) 2012 Faraday Technology
>> + * Written by Dante Su <dantesu@faraday-tech.com>
>> + *
>> + * This file is licensed under GNU GPL v2+.
>> + */
>> +
>> +#include "hw/sysbus.h"
>> +#include "hw/i2c.h"
>> +#include "hw/ssi.h"
>> +#include "hw/audio.h"
>> +#include "sysemu/sysemu.h"
>> +#include "qemu/fifo8.h"
>> +
>> +#include "hw/faraday.h"
>> +#include "hw/ftssp010.h"
>> +
>> +#define CFG_FIFO_DEPTH  16
>> +
>> +#define TYPE_FTSSP010   "ftssp010"
>> +
>> +typedef struct Ftssp010State {
>> +    /*< private >*/
>> +    SysBusDevice parent;
>> +
>> +    /*< public >*/
>> +    MemoryRegion mmio;
>> +
>> +    qemu_irq irq;
>> +    SSIBus *spi;
>> +    AudioCodecState *codec;
>> +
>> +    uint8_t num_cs;
>> +    qemu_irq *cs_lines;
>> +
>> +    Fifo8 rx_fifo;
>> +    Fifo8 tx_fifo;
>> +
>> +    uint8_t tx_thres;
>> +    uint8_t rx_thres;
>> +
>> +    int busy;
>
> Constant 0 AFAICT. Every set of busy to 1 is followed by a clear
> before fn return. I cannot see a code path where anyone reads busy as
> 1? If there is such a code path then busy should be part of the VMSD
> as well.
>

Yes, it should be a constant 0. It's going to be fixed in next version.

>> +    uint8_t bw;
>> +
>> +    /* DMA hardware handshake */
>> +    qemu_irq req[2];    /* 0 - Tx, 1 - Rx */
>> +
>> +    /* HW register caches */
>> +
>
> Are they really caches?
>
>> +    uint32_t cr0;
>> +    uint32_t cr1;
>> +    uint32_t cr2;
>> +    uint32_t icr;    /* interrupt control register */
>> +    uint32_t isr;    /* interrupt status register */
>> +
>> +} Ftssp010State;
>> +
>> +#define FTSSP010(obj) \
>> +    OBJECT_CHECK(Ftssp010State, obj, TYPE_FTSSP010)
>> +
>> +/* Update interrupts.  */
>> +static void ftssp010_update(Ftssp010State *s)
>> +{
>> +    if (!(s->cr2 & CR2_SSPEN)) {
>> +        return;
>> +    }
>> +
>> +    /* tx fifo status update */
>> +    if ((s->tx_fifo.num / (s->bw >> 3)) <= s->tx_thres) {
>> +        s->isr |=  ISR_TFTHI;
>> +        if (s->icr & ICR_TFDMA) {
>> +            qemu_set_irq(s->req[0], 1);
>> +        }
>> +    } else {
>> +        s->isr &= ~ISR_TFTHI;
>> +    }
>> +
>> +    /* rx fifo status update */
>> +    switch (s->cr0 & CR0_FFMT_MASK) {
>> +    case CR0_FFMT_SPI:
>> +        s->isr |=  ISR_RFTHI;
>> +        if (s->icr & ICR_RFDMA) {
>> +            qemu_set_irq(s->req[1], 1);
>> +        }
>> +        break;
>> +    default:
>> +        if ((s->rx_fifo.num / (s->bw >> 3)) >= s->rx_thres) {
>> +            s->isr |=  ISR_RFTHI;
>> +            if (s->icr & ICR_RFDMA) {
>> +                qemu_set_irq(s->req[1], 1);
>> +            }
>> +        } else {
>> +            s->isr &= ~ISR_RFTHI;
>> +        }
>> +        break;
>> +    }
>> +
>> +    /* update the interrupt signal */
>> +    qemu_set_irq(s->irq, (s->icr & s->isr) ? 1 : 0);
>> +}
>> +
>> +static void ftssp010_handle_ack(void *opaque, int line, int level)
>> +{
>> +    Ftssp010State *s = FTSSP010(opaque);
>> +
>> +    switch (line) {
>> +    case 0:    /* Tx */
>> +        if (s->icr & ICR_TFDMA) {
>> +            if (level) {
>> +                qemu_set_irq(s->req[0], 0);
>> +            } else if ((s->tx_fifo.num / (s->bw >> 3)) <= s->tx_thres) {
>> +                qemu_set_irq(s->req[0], 1);
>> +            }
>> +        }
>> +        break;
>> +    case 1:    /* Rx */
>> +        if (s->icr & ICR_RFDMA) {
>> +            if (level) {
>> +                qemu_set_irq(s->req[1], 0);
>> +            } else {
>> +                switch (s->cr0 & CR0_FFMT_MASK) {
>> +                case CR0_FFMT_SPI:
>> +                    qemu_set_irq(s->req[1], 1);
>> +                    break;
>> +                default:
>> +                    if ((s->rx_fifo.num / (s->bw >> 3)) >= s->rx_thres) {
>> +                        qemu_set_irq(s->req[1], 1);
>> +                    }
>> +                    break;
>> +                }
>> +            }
>> +        }
>> +        break;
>> +    default:
>> +        break;
>> +    }
>> +}
>> +
>> +void ftssp010_i2s_data_req(void *opaque, int tx, int rx)
>> +{
>> +    int i, len;
>> +    uint32_t sample;
>> +    Ftssp010State *s = FTSSP010(opaque);
>> +
>> +    if (!(s->cr2 & CR2_SSPEN)) {
>> +        return;
>> +    }
>> +
>> +    if ((s->cr0 & CR0_FFMT_MASK) != CR0_FFMT_I2S) {
>> +        return;
>> +    }
>> +
>> +    s->busy = 1;
>> +
>> +    if ((s->cr2 & CR2_TXEN) && (s->cr2 & CR2_TXDOE)) {
>> +        len = tx * (s->bw / 8);
>> +        while (!fifo8_is_empty(&s->tx_fifo) && len > 0) {
>> +            sample = 0;
>> +            for (i = 0; i < (s->bw >> 3) && len > 0; i++, len--) {
>> +                sample = deposit32(sample, i * 8, 8, fifo8_pop(&s->tx_fifo));
>> +            }
>> +            audio_codec_dac_dat(s->codec, sample);
>> +        }
>> +
>> +        if (fifo8_is_empty(&s->tx_fifo) && len > 0) {
>> +            s->isr |= ISR_TFURI;
>> +        }
>> +    }
>> +
>> +    if (s->cr2 & CR2_RXEN) {
>> +        len = rx * (s->bw / 8);
>> +        while (!fifo8_is_full(&s->rx_fifo) && len > 0) {
>> +            sample = audio_codec_adc_dat(s->codec);
>> +            for (i = 0; i < (s->bw >> 3) && len > 0; i++, len--) {
>> +                fifo8_push(&s->rx_fifo, extract32(sample, i * 8, 8));
>> +            }
>> +        }
>> +
>> +        if (fifo8_is_full(&s->rx_fifo) && len > 0) {
>> +            s->isr |= ISR_RFORI;
>> +        }
>> +    }
>> +
>> +    s->busy = 0;
>> +
>> +    ftssp010_update(s);
>> +}
>> +
>> +static void ftssp010_spi_tx(Ftssp010State *s)
>> +{
>> +    if (!(s->cr2 & CR2_TXEN)) {
>> +        return;
>> +    }
>> +
>> +    s->busy = 1;
>> +
>> +    if (fifo8_is_empty(&s->tx_fifo)) {
>> +        s->isr |= ISR_TFURI;
>> +    }
>> +
>> +    while (!fifo8_is_empty(&s->tx_fifo)) {
>> +        ssi_transfer(s->spi, fifo8_pop(&s->tx_fifo));
>> +    }
>> +
>> +    s->busy = 0;
>> +}
>> +
>> +static uint64_t
>> +ftssp010_mem_read(void *opaque, hwaddr addr, unsigned size)
>> +{
>> +    Ftssp010State *s = FTSSP010(opaque);
>> +    uint32_t i, ret = 0;
>> +
>> +    if (addr & 0x03) {
>> +        fprintf(stderr, "ftssp010: "
>> +                 "Although ftssp010 supports byte/half-word access, "
>> +                 "the target address still needs to be word aligned\n");
>> +        abort();
>> +    }
>> +
>> +    switch (addr) {
>> +    case REG_CR0:    /* Control Register 0 */
>> +        return s->cr0;
>> +    case REG_CR1:    /* Control Register 1 */
>> +        return s->cr1;
>> +    case REG_CR2:    /* Control Register 2 */
>> +        return s->cr2;
>> +    case REG_SR:    /* Status Register */
>> +        ret |= s->busy ? SR_BUSY : 0;
>> +        /* tx fifo status */
>> +        ret |= SR_TFVE(s->tx_fifo.num / (s->bw >> 3));
>> +        if (!fifo8_is_full(&s->tx_fifo)) {
>> +            ret |= SR_TFNF;
>> +        }
>> +        /* rx fifo status */
>> +        switch (s->cr0 & CR0_FFMT_MASK) {
>> +        case CR0_FFMT_SPI:
>> +            ret |= SR_RFF | SR_RFVE(CFG_FIFO_DEPTH);
>> +            break;
>> +        case CR0_FFMT_I2S:
>> +            ret |= SR_RFVE(s->rx_fifo.num / (s->bw >> 3));
>> +            if (fifo8_is_full(&s->rx_fifo)) {
>> +                ret |= SR_RFF;
>> +            }
>> +            break;
>> +        default:
>> +            break;
>> +        }
>> +        break;
>> +    case REG_ICR:    /* Interrupt Control Register */
>> +        return s->icr;
>> +    case REG_ISR:    /* Interrupt Status Register */
>> +        ret = s->isr;
>> +        s->isr &= ~ISR_RCMASK;
>> +        ftssp010_update(s);
>> +        break;
>> +    case REG_DR:    /* Data Register */
>> +        if (!(s->cr2 & CR2_SSPEN)) {
>> +            break;
>> +        }
>> +        if (!(s->cr2 & CR2_RXEN)) {
>> +            break;
>> +        }
>> +        switch (s->cr0 & CR0_FFMT_MASK) {
>> +        case CR0_FFMT_SPI:
>> +            for (i = 0; i < (s->bw >> 3); i++) {
>> +                ret = deposit32(ret, i * 8, 8, ssi_transfer(s->spi, 0));
>> +            }
>> +            break;
>> +        case CR0_FFMT_I2S:
>> +            for (i = 0; i < (s->bw >> 3); i++) {
>> +                if (fifo8_is_empty(&s->rx_fifo)) {
>> +                    break;
>> +                }
>> +                ret = deposit32(ret, i * 8, 8, fifo8_pop(&s->rx_fifo));
>> +            }
>> +            break;
>> +        default:
>> +            break;
>> +        }
>> +        ftssp010_update(s);
>> +        break;
>> +    case REG_REVR:
>> +        return 0x00011901;    /* ver. 1.19.1 */
>> +    case REG_FEAR:
>> +        return 0x660f0f1f;    /* SPI+I2S, FIFO=16 */
>> +    default:
>> +        qemu_log_mask(LOG_GUEST_ERROR,
>> +            "ftssp010: undefined memory access@%#" HWADDR_PRIx "\n", addr);
>> +        break;
>> +    }
>> +
>> +    return ret;
>> +}
>> +
>> +static void
>> +ftssp010_mem_write(void *opaque, hwaddr addr, uint64_t val, unsigned size)
>> +{
>> +    int i;
>> +    Ftssp010State *s = FTSSP010(opaque);
>> +
>> +    if (addr & 0x03) {
>> +        fprintf(stderr, "ftssp010: "
>> +                 "Although ftssp010 supports byte/half-word access, "
>> +                 "the target address still needs to be word aligned\n");
>> +        abort();
>
> Guest error. Buggy guests should not crash the VM.
>

Got it, thanks

>> +    }
>> +
>> +    switch (addr) {
>> +    case REG_CR0:    /* Control Register 0 */
>> +        s->cr0 = (uint32_t)val;
>> +        break;
>> +    case REG_CR1:    /* Control Register 1 */
>> +        s->cr1 = (uint32_t)val;
>> +        s->bw  = extract32(s->cr1, 16, 7) + 1;
>> +        break;
>> +    case REG_CR2:    /* Control Register 2 */
>> +        s->cr2 = (uint32_t)val;
>> +        if (s->cr2 & CR2_SSPRST) {
>> +            fifo8_reset(&s->tx_fifo);
>> +            fifo8_reset(&s->rx_fifo);
>> +            s->busy = 0;
>> +            s->cr2 &= ~(CR2_SSPRST | CR2_TXFCLR | CR2_RXFCLR);
>> +            if (s->cr0 & CR0_FLASH) {
>> +                int cs = extract32(s->cr2, 10, 2);
>> +                qemu_set_irq(s->cs_lines[cs], 1);
>> +                s->cr2 |= CR2_FS;
>> +            };
>> +        }
>> +        if (s->cr2 & CR2_TXFCLR) {
>> +            fifo8_reset(&s->tx_fifo);
>> +            s->cr2 &= ~CR2_TXFCLR;
>> +        }
>> +        if (s->cr2 & CR2_RXFCLR) {
>> +            fifo8_reset(&s->rx_fifo);
>> +            s->cr2 &= ~CR2_RXFCLR;
>> +        }
>> +        if (s->cr0 & CR0_FLASH) {
>> +            int cs = extract32(s->cr2, 10, 2);
>> +            qemu_set_irq(s->cs_lines[cs], (s->cr2 & CR2_FS) ? 1 : 0);
>> +        }
>> +        if (s->cr2 & CR2_SSPEN) {
>> +            switch (s->cr0 & CR0_FFMT_MASK) {
>> +            case CR0_FFMT_SPI:
>> +                ftssp010_spi_tx(s);
>> +                break;
>> +            default:
>> +                break;
>> +            }
>> +        }
>> +        ftssp010_update(s);
>> +        break;
>> +    case REG_ICR:    /* Interrupt Control Register */
>> +        s->icr = (uint32_t)val;
>> +        s->tx_thres = extract32(s->icr, 12, 5);
>> +        s->rx_thres = extract32(s->icr,  7, 5);
>> +        break;
>> +    case REG_DR:    /* Data Register */
>> +        if (!(s->cr2 & CR2_SSPEN)) {
>> +            break;
>> +        }
>> +        for (i = 0; i < (s->bw >> 3) && !fifo8_is_full(&s->tx_fifo); i++) {
>> +            fifo8_push(&s->tx_fifo, extract32((uint32_t)val, i * 8, 8));
>> +        }
>> +        switch (s->cr0 & CR0_FFMT_MASK) {
>> +        case CR0_FFMT_SPI:
>> +            ftssp010_spi_tx(s);
>> +            break;
>> +        default:
>> +            break;
>> +        }
>> +        ftssp010_update(s);
>> +        break;
>> +    default:
>> +        qemu_log_mask(LOG_GUEST_ERROR,
>> +            "ftssp010: undefined memory access@%#" HWADDR_PRIx "\n", addr);
>> +        break;
>> +    }
>> +}
>> +
>> +static const MemoryRegionOps mmio_ops = {
>> +    .read  = ftssp010_mem_read,
>> +    .write = ftssp010_mem_write,
>> +    .endianness = DEVICE_LITTLE_ENDIAN,
>> +    .valid = {
>> +        .min_access_size = 1,
>> +        .max_access_size = 4
>> +    }
>> +};
>> +
>> +static void ftssp010_reset(DeviceState *ds)
>> +{
>> +    Ftssp010State *s = FTSSP010(SYS_BUS_DEVICE(ds));
>> +    Error *local_errp = NULL;
>> +
>> +    s->codec = AUDIO_CODEC(object_property_get_link(OBJECT(s),
>> +                            "codec", &local_errp));
>> +    if (local_errp) {
>> +        fprintf(stderr, "ftssp010: Unable to get codec link\n");
>> +        abort();
>> +    }
>> +
>> +    s->busy = 0;
>> +    s->bw   = 8;    /* 8-bit */
>> +
>> +    s->cr0 = 0;
>> +    s->cr1 = 0;
>> +    s->cr2 = 0;
>> +    s->tx_thres = 4;
>> +    s->rx_thres = 4;
>> +    s->icr = ICR_TFTHOD(4) | ICR_RFTHOD(4);
>> +    s->isr = ISR_TFTHI;
>> +
>> +    fifo8_reset(&s->tx_fifo);
>> +    fifo8_reset(&s->rx_fifo);
>> +
>> +    ftssp010_update(s);
>> +}
>> +
>> +static void ftssp010_realize(DeviceState *dev, Error **errp)
>> +{
>> +    Ftssp010State *s = FTSSP010(dev);
>> +    SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
>> +    int i;
>> +
>> +    s->spi = ssi_create_bus(&sbd->qdev, "spi");
>> +
>> +    fifo8_create(&s->tx_fifo, CFG_FIFO_DEPTH * 4);
>> +    fifo8_create(&s->rx_fifo, CFG_FIFO_DEPTH * 4);
>> +
>> +    memory_region_init_io(&s->mmio,
>> +                          &mmio_ops,
>> +                          s,
>> +                          TYPE_FTSSP010,
>> +                          0x1000);
>> +    sysbus_init_mmio(sbd, &s->mmio);
>> +    sysbus_init_irq(sbd, &s->irq);
>> +
>> +    s->num_cs = 4;
>> +    s->cs_lines = g_new(qemu_irq, s->num_cs);
>
> g_new0
>

Got it, thanks

Best wishes,
Kuo-Jung Su

> Regards,
> Peter
>
>> +    ssi_auto_connect_slaves(dev, s->cs_lines, s->spi);
>> +    for (i = 0; i < s->num_cs; ++i) {
>> +        sysbus_init_irq(sbd, &s->cs_lines[i]);
>> +    }
>> +
>> +    /* DMA hardware handshake */
>> +    qdev_init_gpio_in(&sbd->qdev, ftssp010_handle_ack, 2);
>> +    qdev_init_gpio_out(&sbd->qdev, s->req, 2);
>> +}
>> +
>> +static const VMStateDescription vmstate_ftssp010 = {
>> +    .name = TYPE_FTSSP010,
>> +    .version_id = 1,
>> +    .minimum_version_id = 1,
>> +    .minimum_version_id_old = 1,
>> +    .fields = (VMStateField[]) {
>> +        VMSTATE_UINT32(cr0, Ftssp010State),
>> +        VMSTATE_UINT32(cr1, Ftssp010State),
>> +        VMSTATE_UINT32(cr2, Ftssp010State),
>> +        VMSTATE_UINT32(icr, Ftssp010State),
>> +        VMSTATE_UINT32(isr, Ftssp010State),
>> +        VMSTATE_FIFO8(tx_fifo, Ftssp010State),
>> +        VMSTATE_FIFO8(rx_fifo, Ftssp010State),
>> +        VMSTATE_END_OF_LIST()
>> +    }
>> +};
>> +
>> +static void ftssp010_instance_init(Object *obj)
>> +{
>> +    Ftssp010State *s = FTSSP010(obj);
>> +
>> +    object_property_add_link(obj,
>> +                             "codec",
>> +                             TYPE_AUDIO_CODEC,
>> +                             (Object **) &s->codec,
>> +                             NULL);
>> +}
>> +
>> +static void ftssp010_class_init(ObjectClass *klass, void *data)
>> +{
>> +    DeviceClass *dc = DEVICE_CLASS(klass);
>> +
>> +    dc->vmsd    = &vmstate_ftssp010;
>> +    dc->reset   = ftssp010_reset;
>> +    dc->realize = ftssp010_realize;
>> +    dc->no_user = 1;
>> +}
>> +
>> +static const TypeInfo ftssp010_info = {
>> +    .name          = TYPE_FTSSP010,
>> +    .parent        = TYPE_SYS_BUS_DEVICE,
>> +    .instance_size = sizeof(Ftssp010State),
>> +    .instance_init = ftssp010_instance_init,
>> +    .class_init    = ftssp010_class_init,
>> +};
>> +
>> +static void ftssp010_register_types(void)
>> +{
>> +    type_register_static(&ftssp010_info);
>> +}
>> +
>> +type_init(ftssp010_register_types)
>> diff --git a/hw/ftssp010.h b/hw/ftssp010.h
>> new file mode 100644
>> index 0000000..e3d3e7a
>> --- /dev/null
>> +++ b/hw/ftssp010.h
>> @@ -0,0 +1,96 @@
>> +/*
>> + * QEMU model of the FTSSP010 Controller
>> + *
>> + * Copyright (C) 2012 Faraday Technology
>> + * Written by Dante Su <dantesu@faraday-tech.com>
>> + *
>> + * This file is licensed under GNU GPL v2+.
>> + */
>> +
>> +#ifndef HW_ARM_FTSSP010_H
>> +#define HW_ARM_FTSSP010_H
>> +
>> +/* FTSSP010: Registers */
>> +#define REG_CR0             0x00    /* control register 0 */
>> +#define REG_CR1             0x04    /* control register 1 */
>> +#define REG_CR2             0x08    /* control register 2 */
>> +#define REG_SR              0x0C    /* status register */
>> +#define REG_ICR             0X10    /* interrupt control register */
>> +#define REG_ISR             0x14    /* interrupt statis register */
>> +#define REG_DR              0x18    /* data register */
>> +#define REG_REVR            0x60    /* revision register */
>> +#define REG_FEAR            0x64    /* feature register */
>> +
>> +/* Control register 0  */
>> +
>> +#define CR0_FFMT_MASK       (7 << 12)
>> +#define CR0_FFMT_SSP        (0 << 12)
>> +#define CR0_FFMT_SPI        (1 << 12)
>> +#define CR0_FFMT_MICROWIRE  (2 << 12)
>> +#define CR0_FFMT_I2S        (3 << 12)
>> +#define CR0_FFMT_AC97       (4 << 12)
>> +#define CR0_FLASH           (1 << 11)
>> +#define CR0_FSDIST(x)       (((x) & 0x03) << 8)
>> +#define CR0_LBM             (1 << 7)  /* Loopback mode */
>> +#define CR0_LSB             (1 << 6)  /* LSB first */
>> +#define CR0_FSPO            (1 << 5)  /* Frame sync atcive low */
>> +#define CR0_FSJUSTIFY       (1 << 4)
>> +#define CR0_OPM_SLAVE       (0 << 2)
>> +#define CR0_OPM_MASTER      (3 << 2)
>> +#define CR0_OPM_I2S_MSST    (3 << 2)  /* Master stereo mode */
>> +#define CR0_OPM_I2S_MSMO    (2 << 2)  /* Master mono mode */
>> +#define CR0_OPM_I2S_SLST    (1 << 2)  /* Slave stereo mode */
>> +#define CR0_OPM_I2S_SLMO    (0 << 2)  /* Slave mono mode */
>> +#define CR0_SCLKPO          (1 << 1)  /* SCLK Remain HIGH */
>> +#define CR0_SCLKPH          (1 << 0)  /* Half CLK cycle */
>> +
>> +/* Control Register 1 */
>> +
>> +/* padding data length */
>> +#define CR1_PDL(x)          (((x) & 0xff) << 24)
>> +/* serial data length(actual data length-1) */
>> +#define CR1_SDL(x)          ((((x) - 1) & 0x1f) << 16)
>> +/*  clk divider */
>> +#define CR1_CLKDIV(x)       ((x) & 0xffff)
>> +
>> +/* Control Register 2 */
>> +#define CR2_FSOS(x)         (((x) & 0x03) << 10)        /* FS/CS Select */
>> +#define CR2_FS              (1 << 9)    /* FS/CS Signal Level */
>> +#define CR2_TXEN            (1 << 8)    /* Tx Enable */
>> +#define CR2_RXEN            (1 << 7)    /* Rx Enable */
>> +#define CR2_SSPRST          (1 << 6)    /* SSP reset */
>> +#define CR2_TXFCLR          (1 << 3)    /* TX FIFO Clear */
>> +#define CR2_RXFCLR          (1 << 2)    /* RX FIFO Clear */
>> +#define CR2_TXDOE           (1 << 1)    /* TX Data Output Enable */
>> +#define CR2_SSPEN           (1 << 0)    /* SSP Enable */
>> +
>> +/*
>> + * Status Register
>> + */
>> +#define SR_TFVE(reg)        (((reg) & 0x1F) << 12)
>> +#define SR_RFVE(reg)        (((reg) & 0x1F) << 4)
>> +#define SR_BUSY             (1 << 2)
>> +#define SR_TFNF             (1 << 1)    /* Tx FIFO Not Full */
>> +#define SR_RFF              (1 << 0)    /* Rx FIFO Full */
>> +
>> +/* Interrupr Control Register */
>> +#define ICR_TFTHOD(x)       (((x) & 0x1f) << 12)/* TX FIFO Threshold */
>> +#define ICR_RFTHOD(x)       (((x) & 0x1f) << 7) /* RX FIFO Threshold */
>> +#define ICR_AC97I           0x40      /* AC97 intr enable */
>> +#define ICR_TFDMA           0x20      /* TX DMA enable */
>> +#define ICR_RFDMA           0x10      /* RX DMA enable */
>> +#define ICR_TFTHI           0x08      /* TX FIFO intr enable */
>> +#define ICR_RFTHI           0x04      /* RX FIFO intr enable */
>> +#define ICR_TFURI           0x02      /* TX FIFO Underrun intr enable */
>> +#define ICR_RFORI           0x01      /* RX FIFO Overrun intr enable */
>> +
>> +/* Interrupr Status Register */
>> +#define ISR_AC97I           0x10      /* AC97 interrupt */
>> +#define ISR_TFTHI           0x08      /* TX FIFO interrupt */
>> +#define ISR_RFTHI           0x04      /* RX FIFO interrupt */
>> +#define ISR_TFURI           0x02      /* TX FIFO Underrun interrupt */
>> +#define ISR_RFORI           0x01      /* RX FIFO Overrun interrupt */
>> +/* Read-Clear status mask */
>> +#define ISR_RCMASK          (ISR_RFORI | ISR_TFURI | ISR_AC97I)
>> +
>> +#endif
>> --
>> 1.7.9.5
>>
>>

  reply	other threads:[~2013-04-01  1:19 UTC|newest]

Thread overview: 35+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2013-03-25 12:09 [Qemu-devel] [PATCH v9 00/24] hw/arm: add Faraday A369 SoC platform support Kuo-Jung Su
2013-03-25 12:09 ` [Qemu-devel] [PATCH v9 01/24] target-arm: add Faraday ARMv5TE processors support Kuo-Jung Su
2013-03-25 12:09 ` [Qemu-devel] [PATCH v9 02/24] hw/arm: add Faraday a369 SoC platform support Kuo-Jung Su
2013-03-25 12:09 ` [Qemu-devel] [PATCH v9 03/24] hw/arm: add FTINTC020 interrupt controller support Kuo-Jung Su
2013-03-25 12:09 ` [Qemu-devel] [PATCH v9 04/24] hw/arm: add FTAHBC020 AHB " Kuo-Jung Su
2013-03-25 12:09 ` [Qemu-devel] [PATCH v9 05/24] hw/arm: add FTDDRII030 DDRII " Kuo-Jung Su
2013-03-28  0:09   ` Peter Crosthwaite
2013-03-28  3:24     ` Kuo-Jung Su
2013-03-28  3:58       ` Peter Crosthwaite
2013-03-28  5:28         ` Kuo-Jung Su
2013-03-25 12:09 ` [Qemu-devel] [PATCH v9 06/24] hw/arm: add FTPWMTMR010 timer support Kuo-Jung Su
2013-03-25 12:09 ` [Qemu-devel] [PATCH v9 07/24] hw/arm: add FTWDT010 watchdog " Kuo-Jung Su
2013-03-25 12:09 ` [Qemu-devel] [PATCH v9 08/24] hw/arm: add FTRTC011 RTC " Kuo-Jung Su
2013-03-25 12:09 ` [Qemu-devel] [PATCH v9 09/24] tests: add QTest for FTRTC011 Kuo-Jung Su
2013-03-25 12:09 ` [Qemu-devel] [PATCH v9 10/24] hw/arm: add FTDMAC020 AHB DMA support Kuo-Jung Su
2013-03-29  0:22   ` Peter Crosthwaite
2013-03-29  7:23     ` Kuo-Jung Su
2013-03-25 12:09 ` [Qemu-devel] [PATCH v9 11/24] hw/arm: add FTAPBBRG020 APB " Kuo-Jung Su
2013-03-25 12:09 ` [Qemu-devel] [PATCH v9 12/24] hw/arm: add FTNANDC021 nand flash controller support Kuo-Jung Su
2013-03-25 12:09 ` [Qemu-devel] [PATCH v9 13/24] hw/arm: add FTI2C010 I2C " Kuo-Jung Su
2013-03-25 12:09 ` [Qemu-devel] [PATCH v9 14/24] hw: Add AudioCodecClass for wm87xx audio class abstration Kuo-Jung Su
2013-03-25 12:09 ` [Qemu-devel] [PATCH v9 15/24] hw: add WM8731 audio codec support Kuo-Jung Su
2013-03-25 12:09 ` [Qemu-devel] [PATCH v9 16/24] The FTSSP010 is a multi-function synchronous serial port interface controller which supports SSP, SPI, I2S, AC97 and SPDIF Kuo-Jung Su
2013-03-31  2:39   ` Peter Crosthwaite
2013-04-01  1:18     ` Kuo-Jung Su [this message]
2013-03-25 12:09 ` [Qemu-devel] [PATCH v9 17/24] qemu/bitops.h: add the bit ordering reversal functions Kuo-Jung Su
2013-03-25 12:09 ` [Qemu-devel] [PATCH v9 18/24] hw/arm: add FTGMAC100 1Gbps ethernet support Kuo-Jung Su
2013-03-25 12:09 ` [Qemu-devel] [PATCH v9 19/24] hw/arm: add FTLCDC200 LCD controller support Kuo-Jung Su
2013-03-25 12:09 ` [Qemu-devel] [PATCH v9 20/24] hw/arm: add FTTSC010 touchscreen " Kuo-Jung Su
2013-03-25 12:09 ` [Qemu-devel] [PATCH v9 21/24] hw/arm: add FTSDC010 MMC/SD " Kuo-Jung Su
2013-03-25 12:09 ` [Qemu-devel] [PATCH v9 22/24] hw/arm: add FTMAC110 10/100Mbps ethernet support Kuo-Jung Su
2013-03-25 12:09 ` [Qemu-devel] [PATCH v9 23/24] hw/arm: add FTTMR010 timer support Kuo-Jung Su
2013-03-25 12:10 ` [Qemu-devel] [PATCH v9 24/24] hw/arm: add FTSPI020 SPI flash controller support Kuo-Jung Su
2013-03-29  0:02   ` Peter Crosthwaite
2013-03-29  7:15     ` Kuo-Jung Su

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to='CAK65tU6K=0k7DshjaLbHv-JFupFV9RdyUscm44-VAoP6jGybqw@mail.gmail.com' \
    --to=dantesu@gmail.com \
    --cc=afaerber@suse.de \
    --cc=blauwirbel@gmail.com \
    --cc=dantesu@faraday-tech.com \
    --cc=fred.konrad@greensocs.com \
    --cc=i.mitsyanko@samsung.com \
    --cc=paul@codesourcery.com \
    --cc=peter.crosthwaite@xilinx.com \
    --cc=peter.maydell@linaro.org \
    --cc=qemu-devel@nongnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.