qemu/hw/ssi/stm32f2xx_spi.c
<<
>>
Prefs
   1/*
   2 * STM32F405 SPI
   3 *
   4 * Copyright (c) 2014 Alistair Francis <alistair@alistair23.me>
   5 *
   6 * Permission is hereby granted, free of charge, to any person obtaining a copy
   7 * of this software and associated documentation files (the "Software"), to deal
   8 * in the Software without restriction, including without limitation the rights
   9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  10 * copies of the Software, and to permit persons to whom the Software is
  11 * furnished to do so, subject to the following conditions:
  12 *
  13 * The above copyright notice and this permission notice shall be included in
  14 * all copies or substantial portions of the Software.
  15 *
  16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  22 * THE SOFTWARE.
  23 */
  24
  25#include "qemu/osdep.h"
  26#include "qemu/log.h"
  27#include "qemu/module.h"
  28#include "hw/ssi/stm32f2xx_spi.h"
  29
  30#ifndef STM_SPI_ERR_DEBUG
  31#define STM_SPI_ERR_DEBUG 0
  32#endif
  33
  34#define DB_PRINT_L(lvl, fmt, args...) do { \
  35    if (STM_SPI_ERR_DEBUG >= lvl) { \
  36        qemu_log("%s: " fmt, __func__, ## args); \
  37    } \
  38} while (0)
  39
  40#define DB_PRINT(fmt, args...) DB_PRINT_L(1, fmt, ## args)
  41
  42static void stm32f2xx_spi_reset(DeviceState *dev)
  43{
  44    STM32F2XXSPIState *s = STM32F2XX_SPI(dev);
  45
  46    s->spi_cr1 = 0x00000000;
  47    s->spi_cr2 = 0x00000000;
  48    s->spi_sr = 0x0000000A;
  49    s->spi_dr = 0x0000000C;
  50    s->spi_crcpr = 0x00000007;
  51    s->spi_rxcrcr = 0x00000000;
  52    s->spi_txcrcr = 0x00000000;
  53    s->spi_i2scfgr = 0x00000000;
  54    s->spi_i2spr = 0x00000002;
  55}
  56
  57static void stm32f2xx_spi_transfer(STM32F2XXSPIState *s)
  58{
  59    DB_PRINT("Data to send: 0x%x\n", s->spi_dr);
  60
  61    s->spi_dr = ssi_transfer(s->ssi, s->spi_dr);
  62    s->spi_sr |= STM_SPI_SR_RXNE;
  63
  64    DB_PRINT("Data received: 0x%x\n", s->spi_dr);
  65}
  66
  67static uint64_t stm32f2xx_spi_read(void *opaque, hwaddr addr,
  68                                     unsigned int size)
  69{
  70    STM32F2XXSPIState *s = opaque;
  71
  72    DB_PRINT("Address: 0x%" HWADDR_PRIx "\n", addr);
  73
  74    switch (addr) {
  75    case STM_SPI_CR1:
  76        return s->spi_cr1;
  77    case STM_SPI_CR2:
  78        qemu_log_mask(LOG_UNIMP, "%s: Interrupts and DMA are not implemented\n",
  79                      __func__);
  80        return s->spi_cr2;
  81    case STM_SPI_SR:
  82        return s->spi_sr;
  83    case STM_SPI_DR:
  84        stm32f2xx_spi_transfer(s);
  85        s->spi_sr &= ~STM_SPI_SR_RXNE;
  86        return s->spi_dr;
  87    case STM_SPI_CRCPR:
  88        qemu_log_mask(LOG_UNIMP, "%s: CRC is not implemented, the registers " \
  89                      "are included for compatibility\n", __func__);
  90        return s->spi_crcpr;
  91    case STM_SPI_RXCRCR:
  92        qemu_log_mask(LOG_UNIMP, "%s: CRC is not implemented, the registers " \
  93                      "are included for compatibility\n", __func__);
  94        return s->spi_rxcrcr;
  95    case STM_SPI_TXCRCR:
  96        qemu_log_mask(LOG_UNIMP, "%s: CRC is not implemented, the registers " \
  97                      "are included for compatibility\n", __func__);
  98        return s->spi_txcrcr;
  99    case STM_SPI_I2SCFGR:
 100        qemu_log_mask(LOG_UNIMP, "%s: I2S is not implemented, the registers " \
 101                      "are included for compatibility\n", __func__);
 102        return s->spi_i2scfgr;
 103    case STM_SPI_I2SPR:
 104        qemu_log_mask(LOG_UNIMP, "%s: I2S is not implemented, the registers " \
 105                      "are included for compatibility\n", __func__);
 106        return s->spi_i2spr;
 107    default:
 108        qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%" HWADDR_PRIx "\n",
 109                      __func__, addr);
 110    }
 111
 112    return 0;
 113}
 114
 115static void stm32f2xx_spi_write(void *opaque, hwaddr addr,
 116                                uint64_t val64, unsigned int size)
 117{
 118    STM32F2XXSPIState *s = opaque;
 119    uint32_t value = val64;
 120
 121    DB_PRINT("Address: 0x%" HWADDR_PRIx ", Value: 0x%x\n", addr, value);
 122
 123    switch (addr) {
 124    case STM_SPI_CR1:
 125        s->spi_cr1 = value;
 126        return;
 127    case STM_SPI_CR2:
 128        qemu_log_mask(LOG_UNIMP, "%s: " \
 129                      "Interrupts and DMA are not implemented\n", __func__);
 130        s->spi_cr2 = value;
 131        return;
 132    case STM_SPI_SR:
 133        /* Read only register, except for clearing the CRCERR bit, which
 134         * is not supported
 135         */
 136        return;
 137    case STM_SPI_DR:
 138        s->spi_dr = value;
 139        stm32f2xx_spi_transfer(s);
 140        return;
 141    case STM_SPI_CRCPR:
 142        qemu_log_mask(LOG_UNIMP, "%s: CRC is not implemented\n", __func__);
 143        return;
 144    case STM_SPI_RXCRCR:
 145        qemu_log_mask(LOG_GUEST_ERROR, "%s: Read only register: " \
 146                      "0x%" HWADDR_PRIx "\n", __func__, addr);
 147        return;
 148    case STM_SPI_TXCRCR:
 149        qemu_log_mask(LOG_GUEST_ERROR, "%s: Read only register: " \
 150                      "0x%" HWADDR_PRIx "\n", __func__, addr);
 151        return;
 152    case STM_SPI_I2SCFGR:
 153        qemu_log_mask(LOG_UNIMP, "%s: " \
 154                      "I2S is not implemented\n", __func__);
 155        return;
 156    case STM_SPI_I2SPR:
 157        qemu_log_mask(LOG_UNIMP, "%s: " \
 158                      "I2S is not implemented\n", __func__);
 159        return;
 160    default:
 161        qemu_log_mask(LOG_GUEST_ERROR,
 162                      "%s: Bad offset 0x%" HWADDR_PRIx "\n", __func__, addr);
 163    }
 164}
 165
 166static const MemoryRegionOps stm32f2xx_spi_ops = {
 167    .read = stm32f2xx_spi_read,
 168    .write = stm32f2xx_spi_write,
 169    .endianness = DEVICE_NATIVE_ENDIAN,
 170};
 171
 172static const VMStateDescription vmstate_stm32f2xx_spi = {
 173    .name = TYPE_STM32F2XX_SPI,
 174    .version_id = 1,
 175    .minimum_version_id = 1,
 176    .fields = (VMStateField[]) {
 177        VMSTATE_UINT32(spi_cr1, STM32F2XXSPIState),
 178        VMSTATE_UINT32(spi_cr2, STM32F2XXSPIState),
 179        VMSTATE_UINT32(spi_sr, STM32F2XXSPIState),
 180        VMSTATE_UINT32(spi_dr, STM32F2XXSPIState),
 181        VMSTATE_UINT32(spi_crcpr, STM32F2XXSPIState),
 182        VMSTATE_UINT32(spi_rxcrcr, STM32F2XXSPIState),
 183        VMSTATE_UINT32(spi_txcrcr, STM32F2XXSPIState),
 184        VMSTATE_UINT32(spi_i2scfgr, STM32F2XXSPIState),
 185        VMSTATE_UINT32(spi_i2spr, STM32F2XXSPIState),
 186        VMSTATE_END_OF_LIST()
 187    }
 188};
 189
 190static void stm32f2xx_spi_init(Object *obj)
 191{
 192    STM32F2XXSPIState *s = STM32F2XX_SPI(obj);
 193    DeviceState *dev = DEVICE(obj);
 194
 195    memory_region_init_io(&s->mmio, obj, &stm32f2xx_spi_ops, s,
 196                          TYPE_STM32F2XX_SPI, 0x400);
 197    sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->mmio);
 198
 199    sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->irq);
 200
 201    s->ssi = ssi_create_bus(dev, "ssi");
 202}
 203
 204static void stm32f2xx_spi_class_init(ObjectClass *klass, void *data)
 205{
 206    DeviceClass *dc = DEVICE_CLASS(klass);
 207
 208    dc->reset = stm32f2xx_spi_reset;
 209    dc->vmsd = &vmstate_stm32f2xx_spi;
 210}
 211
 212static const TypeInfo stm32f2xx_spi_info = {
 213    .name          = TYPE_STM32F2XX_SPI,
 214    .parent        = TYPE_SYS_BUS_DEVICE,
 215    .instance_size = sizeof(STM32F2XXSPIState),
 216    .instance_init = stm32f2xx_spi_init,
 217    .class_init    = stm32f2xx_spi_class_init,
 218};
 219
 220static void stm32f2xx_spi_register_types(void)
 221{
 222    type_register_static(&stm32f2xx_spi_info);
 223}
 224
 225type_init(stm32f2xx_spi_register_types)
 226