qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

sifive_spi.c (8810B)


      1 /*
      2  * QEMU model of the SiFive SPI Controller
      3  *
      4  * Copyright (c) 2021 Wind River Systems, Inc.
      5  *
      6  * Author:
      7  *   Bin Meng <bin.meng@windriver.com>
      8  *
      9  * This program is free software; you can redistribute it and/or modify it
     10  * under the terms and conditions of the GNU General Public License,
     11  * version 2 or later, as published by the Free Software Foundation.
     12  *
     13  * This program is distributed in the hope it will be useful, but WITHOUT
     14  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
     15  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
     16  * more details.
     17  *
     18  * You should have received a copy of the GNU General Public License along with
     19  * this program.  If not, see <http://www.gnu.org/licenses/>.
     20  */
     21 
     22 #include "qemu/osdep.h"
     23 #include "hw/irq.h"
     24 #include "hw/qdev-properties.h"
     25 #include "hw/sysbus.h"
     26 #include "hw/ssi/ssi.h"
     27 #include "qemu/fifo8.h"
     28 #include "qemu/log.h"
     29 #include "qemu/module.h"
     30 #include "hw/ssi/sifive_spi.h"
     31 
     32 #define R_SCKDIV        (0x00 / 4)
     33 #define R_SCKMODE       (0x04 / 4)
     34 #define R_CSID          (0x10 / 4)
     35 #define R_CSDEF         (0x14 / 4)
     36 #define R_CSMODE        (0x18 / 4)
     37 #define R_DELAY0        (0x28 / 4)
     38 #define R_DELAY1        (0x2C / 4)
     39 #define R_FMT           (0x40 / 4)
     40 #define R_TXDATA        (0x48 / 4)
     41 #define R_RXDATA        (0x4C / 4)
     42 #define R_TXMARK        (0x50 / 4)
     43 #define R_RXMARK        (0x54 / 4)
     44 #define R_FCTRL         (0x60 / 4)
     45 #define R_FFMT          (0x64 / 4)
     46 #define R_IE            (0x70 / 4)
     47 #define R_IP            (0x74 / 4)
     48 
     49 #define FMT_DIR         (1 << 3)
     50 
     51 #define TXDATA_FULL     (1 << 31)
     52 #define RXDATA_EMPTY    (1 << 31)
     53 
     54 #define IE_TXWM         (1 << 0)
     55 #define IE_RXWM         (1 << 1)
     56 
     57 #define IP_TXWM         (1 << 0)
     58 #define IP_RXWM         (1 << 1)
     59 
     60 #define FIFO_CAPACITY   8
     61 
     62 static void sifive_spi_txfifo_reset(SiFiveSPIState *s)
     63 {
     64     fifo8_reset(&s->tx_fifo);
     65 
     66     s->regs[R_TXDATA] &= ~TXDATA_FULL;
     67     s->regs[R_IP] &= ~IP_TXWM;
     68 }
     69 
     70 static void sifive_spi_rxfifo_reset(SiFiveSPIState *s)
     71 {
     72     fifo8_reset(&s->rx_fifo);
     73 
     74     s->regs[R_RXDATA] |= RXDATA_EMPTY;
     75     s->regs[R_IP] &= ~IP_RXWM;
     76 }
     77 
     78 static void sifive_spi_update_cs(SiFiveSPIState *s)
     79 {
     80     int i;
     81 
     82     for (i = 0; i < s->num_cs; i++) {
     83         if (s->regs[R_CSDEF] & (1 << i)) {
     84             qemu_set_irq(s->cs_lines[i], !(s->regs[R_CSMODE]));
     85         }
     86     }
     87 }
     88 
     89 static void sifive_spi_update_irq(SiFiveSPIState *s)
     90 {
     91     int level;
     92 
     93     if (fifo8_num_used(&s->tx_fifo) < s->regs[R_TXMARK]) {
     94         s->regs[R_IP] |= IP_TXWM;
     95     } else {
     96         s->regs[R_IP] &= ~IP_TXWM;
     97     }
     98 
     99     if (fifo8_num_used(&s->rx_fifo) > s->regs[R_RXMARK]) {
    100         s->regs[R_IP] |= IP_RXWM;
    101     } else {
    102         s->regs[R_IP] &= ~IP_RXWM;
    103     }
    104 
    105     level = s->regs[R_IP] & s->regs[R_IE] ? 1 : 0;
    106     qemu_set_irq(s->irq, level);
    107 }
    108 
    109 static void sifive_spi_reset(DeviceState *d)
    110 {
    111     SiFiveSPIState *s = SIFIVE_SPI(d);
    112 
    113     memset(s->regs, 0, sizeof(s->regs));
    114 
    115     /* The reset value is high for all implemented CS pins */
    116     s->regs[R_CSDEF] = (1 << s->num_cs) - 1;
    117 
    118     /* Populate register with their default value */
    119     s->regs[R_SCKDIV] = 0x03;
    120     s->regs[R_DELAY0] = 0x1001;
    121     s->regs[R_DELAY1] = 0x01;
    122 
    123     sifive_spi_txfifo_reset(s);
    124     sifive_spi_rxfifo_reset(s);
    125 
    126     sifive_spi_update_cs(s);
    127     sifive_spi_update_irq(s);
    128 }
    129 
    130 static void sifive_spi_flush_txfifo(SiFiveSPIState *s)
    131 {
    132     uint8_t tx;
    133     uint8_t rx;
    134 
    135     while (!fifo8_is_empty(&s->tx_fifo)) {
    136         tx = fifo8_pop(&s->tx_fifo);
    137         rx = ssi_transfer(s->spi, tx);
    138 
    139         if (!fifo8_is_full(&s->rx_fifo)) {
    140             if (!(s->regs[R_FMT] & FMT_DIR)) {
    141                 fifo8_push(&s->rx_fifo, rx);
    142             }
    143         }
    144     }
    145 }
    146 
    147 static bool sifive_spi_is_bad_reg(hwaddr addr, bool allow_reserved)
    148 {
    149     bool bad;
    150 
    151     switch (addr) {
    152     /* reserved offsets */
    153     case 0x08:
    154     case 0x0C:
    155     case 0x1C:
    156     case 0x20:
    157     case 0x24:
    158     case 0x30:
    159     case 0x34:
    160     case 0x38:
    161     case 0x3C:
    162     case 0x44:
    163     case 0x58:
    164     case 0x5C:
    165     case 0x68:
    166     case 0x6C:
    167         bad = allow_reserved ? false : true;
    168         break;
    169     default:
    170         bad = false;
    171     }
    172 
    173     if (addr >= (SIFIVE_SPI_REG_NUM << 2)) {
    174         bad = true;
    175     }
    176 
    177     return bad;
    178 }
    179 
    180 static uint64_t sifive_spi_read(void *opaque, hwaddr addr, unsigned int size)
    181 {
    182     SiFiveSPIState *s = opaque;
    183     uint32_t r;
    184 
    185     if (sifive_spi_is_bad_reg(addr, true)) {
    186         qemu_log_mask(LOG_GUEST_ERROR, "%s: bad read at address 0x%"
    187                       HWADDR_PRIx "\n", __func__, addr);
    188         return 0;
    189     }
    190 
    191     addr >>= 2;
    192     switch (addr) {
    193     case R_TXDATA:
    194         if (fifo8_is_full(&s->tx_fifo)) {
    195             return TXDATA_FULL;
    196         }
    197         r = 0;
    198         break;
    199 
    200     case R_RXDATA:
    201         if (fifo8_is_empty(&s->rx_fifo)) {
    202             return RXDATA_EMPTY;
    203         }
    204         r = fifo8_pop(&s->rx_fifo);
    205         break;
    206 
    207     default:
    208         r = s->regs[addr];
    209         break;
    210     }
    211 
    212     sifive_spi_update_irq(s);
    213 
    214     return r;
    215 }
    216 
    217 static void sifive_spi_write(void *opaque, hwaddr addr,
    218                              uint64_t val64, unsigned int size)
    219 {
    220     SiFiveSPIState *s = opaque;
    221     uint32_t value = val64;
    222 
    223     if (sifive_spi_is_bad_reg(addr, false)) {
    224         qemu_log_mask(LOG_GUEST_ERROR, "%s: bad write at addr=0x%"
    225                       HWADDR_PRIx " value=0x%x\n", __func__, addr, value);
    226         return;
    227     }
    228 
    229     addr >>= 2;
    230     switch (addr) {
    231     case R_CSID:
    232         if (value >= s->num_cs) {
    233             qemu_log_mask(LOG_GUEST_ERROR, "%s: invalid csid %d\n",
    234                           __func__, value);
    235         } else {
    236             s->regs[R_CSID] = value;
    237             sifive_spi_update_cs(s);
    238         }
    239         break;
    240 
    241     case R_CSDEF:
    242         if (value >= (1 << s->num_cs)) {
    243             qemu_log_mask(LOG_GUEST_ERROR, "%s: invalid csdef %x\n",
    244                           __func__, value);
    245         } else {
    246             s->regs[R_CSDEF] = value;
    247         }
    248         break;
    249 
    250     case R_CSMODE:
    251         if (value > 3) {
    252             qemu_log_mask(LOG_GUEST_ERROR, "%s: invalid csmode %x\n",
    253                           __func__, value);
    254         } else {
    255             s->regs[R_CSMODE] = value;
    256             sifive_spi_update_cs(s);
    257         }
    258         break;
    259 
    260     case R_TXDATA:
    261         if (!fifo8_is_full(&s->tx_fifo)) {
    262             fifo8_push(&s->tx_fifo, (uint8_t)value);
    263             sifive_spi_flush_txfifo(s);
    264         }
    265         break;
    266 
    267     case R_RXDATA:
    268     case R_IP:
    269         qemu_log_mask(LOG_GUEST_ERROR,
    270                       "%s: invalid write to read-only reigster 0x%"
    271                       HWADDR_PRIx " with 0x%x\n", __func__, addr << 2, value);
    272         break;
    273 
    274     case R_TXMARK:
    275     case R_RXMARK:
    276         if (value >= FIFO_CAPACITY) {
    277             qemu_log_mask(LOG_GUEST_ERROR, "%s: invalid watermark %d\n",
    278                           __func__, value);
    279         } else {
    280             s->regs[addr] = value;
    281         }
    282         break;
    283 
    284     case R_FCTRL:
    285     case R_FFMT:
    286         qemu_log_mask(LOG_UNIMP,
    287                       "%s: direct-map flash interface unimplemented\n",
    288                       __func__);
    289         break;
    290 
    291     default:
    292         s->regs[addr] = value;
    293         break;
    294     }
    295 
    296     sifive_spi_update_irq(s);
    297 }
    298 
    299 static const MemoryRegionOps sifive_spi_ops = {
    300     .read = sifive_spi_read,
    301     .write = sifive_spi_write,
    302     .endianness = DEVICE_LITTLE_ENDIAN,
    303     .valid = {
    304         .min_access_size = 4,
    305         .max_access_size = 4
    306     }
    307 };
    308 
    309 static void sifive_spi_realize(DeviceState *dev, Error **errp)
    310 {
    311     SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
    312     SiFiveSPIState *s = SIFIVE_SPI(dev);
    313     int i;
    314 
    315     s->spi = ssi_create_bus(dev, "spi");
    316     sysbus_init_irq(sbd, &s->irq);
    317 
    318     s->cs_lines = g_new0(qemu_irq, s->num_cs);
    319     for (i = 0; i < s->num_cs; i++) {
    320         sysbus_init_irq(sbd, &s->cs_lines[i]);
    321     }
    322 
    323     memory_region_init_io(&s->mmio, OBJECT(s), &sifive_spi_ops, s,
    324                           TYPE_SIFIVE_SPI, 0x1000);
    325     sysbus_init_mmio(sbd, &s->mmio);
    326 
    327     fifo8_create(&s->tx_fifo, FIFO_CAPACITY);
    328     fifo8_create(&s->rx_fifo, FIFO_CAPACITY);
    329 }
    330 
    331 static Property sifive_spi_properties[] = {
    332     DEFINE_PROP_UINT32("num-cs", SiFiveSPIState, num_cs, 1),
    333     DEFINE_PROP_END_OF_LIST(),
    334 };
    335 
    336 static void sifive_spi_class_init(ObjectClass *klass, void *data)
    337 {
    338     DeviceClass *dc = DEVICE_CLASS(klass);
    339 
    340     device_class_set_props(dc, sifive_spi_properties);
    341     dc->reset = sifive_spi_reset;
    342     dc->realize = sifive_spi_realize;
    343 }
    344 
    345 static const TypeInfo sifive_spi_info = {
    346     .name           = TYPE_SIFIVE_SPI,
    347     .parent         = TYPE_SYS_BUS_DEVICE,
    348     .instance_size  = sizeof(SiFiveSPIState),
    349     .class_init     = sifive_spi_class_init,
    350 };
    351 
    352 static void sifive_spi_register_types(void)
    353 {
    354     type_register_static(&sifive_spi_info);
    355 }
    356 
    357 type_init(sifive_spi_register_types)