1*268ee7deSSubbaraya Sundeep /* 2*268ee7deSSubbaraya Sundeep * Block model of SPI controller present in 3*268ee7deSSubbaraya Sundeep * Microsemi's SmartFusion2 and SmartFusion SoCs. 4*268ee7deSSubbaraya Sundeep * 5*268ee7deSSubbaraya Sundeep * Copyright (C) 2017 Subbaraya Sundeep <sundeep.lkml@gmail.com> 6*268ee7deSSubbaraya Sundeep * 7*268ee7deSSubbaraya Sundeep * Permission is hereby granted, free of charge, to any person obtaining a copy 8*268ee7deSSubbaraya Sundeep * of this software and associated documentation files (the "Software"), to deal 9*268ee7deSSubbaraya Sundeep * in the Software without restriction, including without limitation the rights 10*268ee7deSSubbaraya Sundeep * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11*268ee7deSSubbaraya Sundeep * copies of the Software, and to permit persons to whom the Software is 12*268ee7deSSubbaraya Sundeep * furnished to do so, subject to the following conditions: 13*268ee7deSSubbaraya Sundeep * 14*268ee7deSSubbaraya Sundeep * The above copyright notice and this permission notice shall be included in 15*268ee7deSSubbaraya Sundeep * all copies or substantial portions of the Software. 16*268ee7deSSubbaraya Sundeep * 17*268ee7deSSubbaraya Sundeep * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18*268ee7deSSubbaraya Sundeep * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19*268ee7deSSubbaraya Sundeep * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 20*268ee7deSSubbaraya Sundeep * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21*268ee7deSSubbaraya Sundeep * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22*268ee7deSSubbaraya Sundeep * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23*268ee7deSSubbaraya Sundeep * THE SOFTWARE. 24*268ee7deSSubbaraya Sundeep */ 25*268ee7deSSubbaraya Sundeep 26*268ee7deSSubbaraya Sundeep #include "qemu/osdep.h" 27*268ee7deSSubbaraya Sundeep #include "hw/ssi/mss-spi.h" 28*268ee7deSSubbaraya Sundeep #include "qemu/log.h" 29*268ee7deSSubbaraya Sundeep 30*268ee7deSSubbaraya Sundeep #ifndef MSS_SPI_ERR_DEBUG 31*268ee7deSSubbaraya Sundeep #define MSS_SPI_ERR_DEBUG 0 32*268ee7deSSubbaraya Sundeep #endif 33*268ee7deSSubbaraya Sundeep 34*268ee7deSSubbaraya Sundeep #define DB_PRINT_L(lvl, fmt, args...) do { \ 35*268ee7deSSubbaraya Sundeep if (MSS_SPI_ERR_DEBUG >= lvl) { \ 36*268ee7deSSubbaraya Sundeep qemu_log("%s: " fmt "\n", __func__, ## args); \ 37*268ee7deSSubbaraya Sundeep } \ 38*268ee7deSSubbaraya Sundeep } while (0); 39*268ee7deSSubbaraya Sundeep 40*268ee7deSSubbaraya Sundeep #define DB_PRINT(fmt, args...) DB_PRINT_L(1, fmt, ## args) 41*268ee7deSSubbaraya Sundeep 42*268ee7deSSubbaraya Sundeep #define FIFO_CAPACITY 32 43*268ee7deSSubbaraya Sundeep 44*268ee7deSSubbaraya Sundeep #define R_SPI_CONTROL 0 45*268ee7deSSubbaraya Sundeep #define R_SPI_DFSIZE 1 46*268ee7deSSubbaraya Sundeep #define R_SPI_STATUS 2 47*268ee7deSSubbaraya Sundeep #define R_SPI_INTCLR 3 48*268ee7deSSubbaraya Sundeep #define R_SPI_RX 4 49*268ee7deSSubbaraya Sundeep #define R_SPI_TX 5 50*268ee7deSSubbaraya Sundeep #define R_SPI_CLKGEN 6 51*268ee7deSSubbaraya Sundeep #define R_SPI_SS 7 52*268ee7deSSubbaraya Sundeep #define R_SPI_MIS 8 53*268ee7deSSubbaraya Sundeep #define R_SPI_RIS 9 54*268ee7deSSubbaraya Sundeep 55*268ee7deSSubbaraya Sundeep #define S_TXDONE (1 << 0) 56*268ee7deSSubbaraya Sundeep #define S_RXRDY (1 << 1) 57*268ee7deSSubbaraya Sundeep #define S_RXCHOVRF (1 << 2) 58*268ee7deSSubbaraya Sundeep #define S_RXFIFOFUL (1 << 4) 59*268ee7deSSubbaraya Sundeep #define S_RXFIFOFULNXT (1 << 5) 60*268ee7deSSubbaraya Sundeep #define S_RXFIFOEMP (1 << 6) 61*268ee7deSSubbaraya Sundeep #define S_RXFIFOEMPNXT (1 << 7) 62*268ee7deSSubbaraya Sundeep #define S_TXFIFOFUL (1 << 8) 63*268ee7deSSubbaraya Sundeep #define S_TXFIFOFULNXT (1 << 9) 64*268ee7deSSubbaraya Sundeep #define S_TXFIFOEMP (1 << 10) 65*268ee7deSSubbaraya Sundeep #define S_TXFIFOEMPNXT (1 << 11) 66*268ee7deSSubbaraya Sundeep #define S_FRAMESTART (1 << 12) 67*268ee7deSSubbaraya Sundeep #define S_SSEL (1 << 13) 68*268ee7deSSubbaraya Sundeep #define S_ACTIVE (1 << 14) 69*268ee7deSSubbaraya Sundeep 70*268ee7deSSubbaraya Sundeep #define C_ENABLE (1 << 0) 71*268ee7deSSubbaraya Sundeep #define C_MODE (1 << 1) 72*268ee7deSSubbaraya Sundeep #define C_INTRXDATA (1 << 4) 73*268ee7deSSubbaraya Sundeep #define C_INTTXDATA (1 << 5) 74*268ee7deSSubbaraya Sundeep #define C_INTRXOVRFLO (1 << 6) 75*268ee7deSSubbaraya Sundeep #define C_SPS (1 << 26) 76*268ee7deSSubbaraya Sundeep #define C_BIGFIFO (1 << 29) 77*268ee7deSSubbaraya Sundeep #define C_RESET (1 << 31) 78*268ee7deSSubbaraya Sundeep 79*268ee7deSSubbaraya Sundeep #define FRAMESZ_MASK 0x1F 80*268ee7deSSubbaraya Sundeep #define FMCOUNT_MASK 0x00FFFF00 81*268ee7deSSubbaraya Sundeep #define FMCOUNT_SHIFT 8 82*268ee7deSSubbaraya Sundeep 83*268ee7deSSubbaraya Sundeep static void txfifo_reset(MSSSpiState *s) 84*268ee7deSSubbaraya Sundeep { 85*268ee7deSSubbaraya Sundeep fifo32_reset(&s->tx_fifo); 86*268ee7deSSubbaraya Sundeep 87*268ee7deSSubbaraya Sundeep s->regs[R_SPI_STATUS] &= ~S_TXFIFOFUL; 88*268ee7deSSubbaraya Sundeep s->regs[R_SPI_STATUS] |= S_TXFIFOEMP; 89*268ee7deSSubbaraya Sundeep } 90*268ee7deSSubbaraya Sundeep 91*268ee7deSSubbaraya Sundeep static void rxfifo_reset(MSSSpiState *s) 92*268ee7deSSubbaraya Sundeep { 93*268ee7deSSubbaraya Sundeep fifo32_reset(&s->rx_fifo); 94*268ee7deSSubbaraya Sundeep 95*268ee7deSSubbaraya Sundeep s->regs[R_SPI_STATUS] &= ~S_RXFIFOFUL; 96*268ee7deSSubbaraya Sundeep s->regs[R_SPI_STATUS] |= S_RXFIFOEMP; 97*268ee7deSSubbaraya Sundeep } 98*268ee7deSSubbaraya Sundeep 99*268ee7deSSubbaraya Sundeep static void set_fifodepth(MSSSpiState *s) 100*268ee7deSSubbaraya Sundeep { 101*268ee7deSSubbaraya Sundeep unsigned int size = s->regs[R_SPI_DFSIZE] & FRAMESZ_MASK; 102*268ee7deSSubbaraya Sundeep 103*268ee7deSSubbaraya Sundeep if (size <= 8) { 104*268ee7deSSubbaraya Sundeep s->fifo_depth = 32; 105*268ee7deSSubbaraya Sundeep } else if (size <= 16) { 106*268ee7deSSubbaraya Sundeep s->fifo_depth = 16; 107*268ee7deSSubbaraya Sundeep } else if (size <= 32) { 108*268ee7deSSubbaraya Sundeep s->fifo_depth = 8; 109*268ee7deSSubbaraya Sundeep } else { 110*268ee7deSSubbaraya Sundeep s->fifo_depth = 4; 111*268ee7deSSubbaraya Sundeep } 112*268ee7deSSubbaraya Sundeep } 113*268ee7deSSubbaraya Sundeep 114*268ee7deSSubbaraya Sundeep static void update_mis(MSSSpiState *s) 115*268ee7deSSubbaraya Sundeep { 116*268ee7deSSubbaraya Sundeep uint32_t reg = s->regs[R_SPI_CONTROL]; 117*268ee7deSSubbaraya Sundeep uint32_t tmp; 118*268ee7deSSubbaraya Sundeep 119*268ee7deSSubbaraya Sundeep /* 120*268ee7deSSubbaraya Sundeep * form the Control register interrupt enable bits 121*268ee7deSSubbaraya Sundeep * same as RIS, MIS and Interrupt clear registers for simplicity 122*268ee7deSSubbaraya Sundeep */ 123*268ee7deSSubbaraya Sundeep tmp = ((reg & C_INTRXOVRFLO) >> 4) | ((reg & C_INTRXDATA) >> 3) | 124*268ee7deSSubbaraya Sundeep ((reg & C_INTTXDATA) >> 5); 125*268ee7deSSubbaraya Sundeep s->regs[R_SPI_MIS] |= tmp & s->regs[R_SPI_RIS]; 126*268ee7deSSubbaraya Sundeep } 127*268ee7deSSubbaraya Sundeep 128*268ee7deSSubbaraya Sundeep static void spi_update_irq(MSSSpiState *s) 129*268ee7deSSubbaraya Sundeep { 130*268ee7deSSubbaraya Sundeep int irq; 131*268ee7deSSubbaraya Sundeep 132*268ee7deSSubbaraya Sundeep update_mis(s); 133*268ee7deSSubbaraya Sundeep irq = !!(s->regs[R_SPI_MIS]); 134*268ee7deSSubbaraya Sundeep 135*268ee7deSSubbaraya Sundeep qemu_set_irq(s->irq, irq); 136*268ee7deSSubbaraya Sundeep } 137*268ee7deSSubbaraya Sundeep 138*268ee7deSSubbaraya Sundeep static void mss_spi_reset(DeviceState *d) 139*268ee7deSSubbaraya Sundeep { 140*268ee7deSSubbaraya Sundeep MSSSpiState *s = MSS_SPI(d); 141*268ee7deSSubbaraya Sundeep 142*268ee7deSSubbaraya Sundeep memset(s->regs, 0, sizeof s->regs); 143*268ee7deSSubbaraya Sundeep s->regs[R_SPI_CONTROL] = 0x80000102; 144*268ee7deSSubbaraya Sundeep s->regs[R_SPI_DFSIZE] = 0x4; 145*268ee7deSSubbaraya Sundeep s->regs[R_SPI_STATUS] = S_SSEL | S_TXFIFOEMP | S_RXFIFOEMP; 146*268ee7deSSubbaraya Sundeep s->regs[R_SPI_CLKGEN] = 0x7; 147*268ee7deSSubbaraya Sundeep s->regs[R_SPI_RIS] = 0x0; 148*268ee7deSSubbaraya Sundeep 149*268ee7deSSubbaraya Sundeep s->fifo_depth = 4; 150*268ee7deSSubbaraya Sundeep s->frame_count = 1; 151*268ee7deSSubbaraya Sundeep s->enabled = false; 152*268ee7deSSubbaraya Sundeep 153*268ee7deSSubbaraya Sundeep rxfifo_reset(s); 154*268ee7deSSubbaraya Sundeep txfifo_reset(s); 155*268ee7deSSubbaraya Sundeep } 156*268ee7deSSubbaraya Sundeep 157*268ee7deSSubbaraya Sundeep static uint64_t 158*268ee7deSSubbaraya Sundeep spi_read(void *opaque, hwaddr addr, unsigned int size) 159*268ee7deSSubbaraya Sundeep { 160*268ee7deSSubbaraya Sundeep MSSSpiState *s = opaque; 161*268ee7deSSubbaraya Sundeep uint32_t ret = 0; 162*268ee7deSSubbaraya Sundeep 163*268ee7deSSubbaraya Sundeep addr >>= 2; 164*268ee7deSSubbaraya Sundeep switch (addr) { 165*268ee7deSSubbaraya Sundeep case R_SPI_RX: 166*268ee7deSSubbaraya Sundeep s->regs[R_SPI_STATUS] &= ~S_RXFIFOFUL; 167*268ee7deSSubbaraya Sundeep s->regs[R_SPI_STATUS] &= ~S_RXCHOVRF; 168*268ee7deSSubbaraya Sundeep ret = fifo32_pop(&s->rx_fifo); 169*268ee7deSSubbaraya Sundeep if (fifo32_is_empty(&s->rx_fifo)) { 170*268ee7deSSubbaraya Sundeep s->regs[R_SPI_STATUS] |= S_RXFIFOEMP; 171*268ee7deSSubbaraya Sundeep } 172*268ee7deSSubbaraya Sundeep break; 173*268ee7deSSubbaraya Sundeep 174*268ee7deSSubbaraya Sundeep case R_SPI_MIS: 175*268ee7deSSubbaraya Sundeep update_mis(s); 176*268ee7deSSubbaraya Sundeep ret = s->regs[R_SPI_MIS]; 177*268ee7deSSubbaraya Sundeep break; 178*268ee7deSSubbaraya Sundeep 179*268ee7deSSubbaraya Sundeep default: 180*268ee7deSSubbaraya Sundeep if (addr < ARRAY_SIZE(s->regs)) { 181*268ee7deSSubbaraya Sundeep ret = s->regs[addr]; 182*268ee7deSSubbaraya Sundeep } else { 183*268ee7deSSubbaraya Sundeep qemu_log_mask(LOG_GUEST_ERROR, 184*268ee7deSSubbaraya Sundeep "%s: Bad offset 0x%" HWADDR_PRIx "\n", __func__, 185*268ee7deSSubbaraya Sundeep addr * 4); 186*268ee7deSSubbaraya Sundeep return ret; 187*268ee7deSSubbaraya Sundeep } 188*268ee7deSSubbaraya Sundeep break; 189*268ee7deSSubbaraya Sundeep } 190*268ee7deSSubbaraya Sundeep 191*268ee7deSSubbaraya Sundeep DB_PRINT("addr=0x%" HWADDR_PRIx " = 0x%" PRIx32, addr * 4, ret); 192*268ee7deSSubbaraya Sundeep spi_update_irq(s); 193*268ee7deSSubbaraya Sundeep return ret; 194*268ee7deSSubbaraya Sundeep } 195*268ee7deSSubbaraya Sundeep 196*268ee7deSSubbaraya Sundeep static void assert_cs(MSSSpiState *s) 197*268ee7deSSubbaraya Sundeep { 198*268ee7deSSubbaraya Sundeep qemu_set_irq(s->cs_line, 0); 199*268ee7deSSubbaraya Sundeep } 200*268ee7deSSubbaraya Sundeep 201*268ee7deSSubbaraya Sundeep static void deassert_cs(MSSSpiState *s) 202*268ee7deSSubbaraya Sundeep { 203*268ee7deSSubbaraya Sundeep qemu_set_irq(s->cs_line, 1); 204*268ee7deSSubbaraya Sundeep } 205*268ee7deSSubbaraya Sundeep 206*268ee7deSSubbaraya Sundeep static void spi_flush_txfifo(MSSSpiState *s) 207*268ee7deSSubbaraya Sundeep { 208*268ee7deSSubbaraya Sundeep uint32_t tx; 209*268ee7deSSubbaraya Sundeep uint32_t rx; 210*268ee7deSSubbaraya Sundeep bool sps = !!(s->regs[R_SPI_CONTROL] & C_SPS); 211*268ee7deSSubbaraya Sundeep 212*268ee7deSSubbaraya Sundeep /* 213*268ee7deSSubbaraya Sundeep * Chip Select(CS) is automatically controlled by this controller. 214*268ee7deSSubbaraya Sundeep * If SPS bit is set in Control register then CS is asserted 215*268ee7deSSubbaraya Sundeep * until all the frames set in frame count of Control register are 216*268ee7deSSubbaraya Sundeep * transferred. If SPS is not set then CS pulses between frames. 217*268ee7deSSubbaraya Sundeep * Note that Slave Select register specifies which of the CS line 218*268ee7deSSubbaraya Sundeep * has to be controlled automatically by controller. Bits SS[7:1] are for 219*268ee7deSSubbaraya Sundeep * masters in FPGA fabric since we model only Microcontroller subsystem 220*268ee7deSSubbaraya Sundeep * of Smartfusion2 we control only one CS(SS[0]) line. 221*268ee7deSSubbaraya Sundeep */ 222*268ee7deSSubbaraya Sundeep while (!fifo32_is_empty(&s->tx_fifo) && s->frame_count) { 223*268ee7deSSubbaraya Sundeep assert_cs(s); 224*268ee7deSSubbaraya Sundeep 225*268ee7deSSubbaraya Sundeep s->regs[R_SPI_STATUS] &= ~(S_TXDONE | S_RXRDY); 226*268ee7deSSubbaraya Sundeep 227*268ee7deSSubbaraya Sundeep tx = fifo32_pop(&s->tx_fifo); 228*268ee7deSSubbaraya Sundeep DB_PRINT("data tx:0x%" PRIx32, tx); 229*268ee7deSSubbaraya Sundeep rx = ssi_transfer(s->spi, tx); 230*268ee7deSSubbaraya Sundeep DB_PRINT("data rx:0x%" PRIx32, rx); 231*268ee7deSSubbaraya Sundeep 232*268ee7deSSubbaraya Sundeep if (fifo32_num_used(&s->rx_fifo) == s->fifo_depth) { 233*268ee7deSSubbaraya Sundeep s->regs[R_SPI_STATUS] |= S_RXCHOVRF; 234*268ee7deSSubbaraya Sundeep s->regs[R_SPI_RIS] |= S_RXCHOVRF; 235*268ee7deSSubbaraya Sundeep } else { 236*268ee7deSSubbaraya Sundeep fifo32_push(&s->rx_fifo, rx); 237*268ee7deSSubbaraya Sundeep s->regs[R_SPI_STATUS] &= ~S_RXFIFOEMP; 238*268ee7deSSubbaraya Sundeep if (fifo32_num_used(&s->rx_fifo) == (s->fifo_depth - 1)) { 239*268ee7deSSubbaraya Sundeep s->regs[R_SPI_STATUS] |= S_RXFIFOFULNXT; 240*268ee7deSSubbaraya Sundeep } else if (fifo32_num_used(&s->rx_fifo) == s->fifo_depth) { 241*268ee7deSSubbaraya Sundeep s->regs[R_SPI_STATUS] |= S_RXFIFOFUL; 242*268ee7deSSubbaraya Sundeep } 243*268ee7deSSubbaraya Sundeep } 244*268ee7deSSubbaraya Sundeep s->frame_count--; 245*268ee7deSSubbaraya Sundeep if (!sps) { 246*268ee7deSSubbaraya Sundeep deassert_cs(s); 247*268ee7deSSubbaraya Sundeep } 248*268ee7deSSubbaraya Sundeep } 249*268ee7deSSubbaraya Sundeep 250*268ee7deSSubbaraya Sundeep if (!s->frame_count) { 251*268ee7deSSubbaraya Sundeep s->frame_count = (s->regs[R_SPI_CONTROL] & FMCOUNT_MASK) >> 252*268ee7deSSubbaraya Sundeep FMCOUNT_SHIFT; 253*268ee7deSSubbaraya Sundeep deassert_cs(s); 254*268ee7deSSubbaraya Sundeep s->regs[R_SPI_RIS] |= S_TXDONE | S_RXRDY; 255*268ee7deSSubbaraya Sundeep s->regs[R_SPI_STATUS] |= S_TXDONE | S_RXRDY; 256*268ee7deSSubbaraya Sundeep } 257*268ee7deSSubbaraya Sundeep } 258*268ee7deSSubbaraya Sundeep 259*268ee7deSSubbaraya Sundeep static void spi_write(void *opaque, hwaddr addr, 260*268ee7deSSubbaraya Sundeep uint64_t val64, unsigned int size) 261*268ee7deSSubbaraya Sundeep { 262*268ee7deSSubbaraya Sundeep MSSSpiState *s = opaque; 263*268ee7deSSubbaraya Sundeep uint32_t value = val64; 264*268ee7deSSubbaraya Sundeep 265*268ee7deSSubbaraya Sundeep DB_PRINT("addr=0x%" HWADDR_PRIx " =0x%" PRIx32, addr, value); 266*268ee7deSSubbaraya Sundeep addr >>= 2; 267*268ee7deSSubbaraya Sundeep 268*268ee7deSSubbaraya Sundeep switch (addr) { 269*268ee7deSSubbaraya Sundeep case R_SPI_TX: 270*268ee7deSSubbaraya Sundeep /* adding to already full FIFO */ 271*268ee7deSSubbaraya Sundeep if (fifo32_num_used(&s->tx_fifo) == s->fifo_depth) { 272*268ee7deSSubbaraya Sundeep break; 273*268ee7deSSubbaraya Sundeep } 274*268ee7deSSubbaraya Sundeep s->regs[R_SPI_STATUS] &= ~S_TXFIFOEMP; 275*268ee7deSSubbaraya Sundeep fifo32_push(&s->tx_fifo, value); 276*268ee7deSSubbaraya Sundeep if (fifo32_num_used(&s->tx_fifo) == (s->fifo_depth - 1)) { 277*268ee7deSSubbaraya Sundeep s->regs[R_SPI_STATUS] |= S_TXFIFOFULNXT; 278*268ee7deSSubbaraya Sundeep } else if (fifo32_num_used(&s->tx_fifo) == s->fifo_depth) { 279*268ee7deSSubbaraya Sundeep s->regs[R_SPI_STATUS] |= S_TXFIFOFUL; 280*268ee7deSSubbaraya Sundeep } 281*268ee7deSSubbaraya Sundeep if (s->enabled) { 282*268ee7deSSubbaraya Sundeep spi_flush_txfifo(s); 283*268ee7deSSubbaraya Sundeep } 284*268ee7deSSubbaraya Sundeep break; 285*268ee7deSSubbaraya Sundeep 286*268ee7deSSubbaraya Sundeep case R_SPI_CONTROL: 287*268ee7deSSubbaraya Sundeep s->regs[R_SPI_CONTROL] = value; 288*268ee7deSSubbaraya Sundeep if (value & C_BIGFIFO) { 289*268ee7deSSubbaraya Sundeep set_fifodepth(s); 290*268ee7deSSubbaraya Sundeep } else { 291*268ee7deSSubbaraya Sundeep s->fifo_depth = 4; 292*268ee7deSSubbaraya Sundeep } 293*268ee7deSSubbaraya Sundeep s->enabled = value & C_ENABLE; 294*268ee7deSSubbaraya Sundeep s->frame_count = (value & FMCOUNT_MASK) >> FMCOUNT_SHIFT; 295*268ee7deSSubbaraya Sundeep if (value & C_RESET) { 296*268ee7deSSubbaraya Sundeep mss_spi_reset(DEVICE(s)); 297*268ee7deSSubbaraya Sundeep } 298*268ee7deSSubbaraya Sundeep break; 299*268ee7deSSubbaraya Sundeep 300*268ee7deSSubbaraya Sundeep case R_SPI_DFSIZE: 301*268ee7deSSubbaraya Sundeep if (s->enabled) { 302*268ee7deSSubbaraya Sundeep break; 303*268ee7deSSubbaraya Sundeep } 304*268ee7deSSubbaraya Sundeep s->regs[R_SPI_DFSIZE] = value; 305*268ee7deSSubbaraya Sundeep break; 306*268ee7deSSubbaraya Sundeep 307*268ee7deSSubbaraya Sundeep case R_SPI_INTCLR: 308*268ee7deSSubbaraya Sundeep s->regs[R_SPI_INTCLR] = value; 309*268ee7deSSubbaraya Sundeep if (value & S_TXDONE) { 310*268ee7deSSubbaraya Sundeep s->regs[R_SPI_RIS] &= ~S_TXDONE; 311*268ee7deSSubbaraya Sundeep } 312*268ee7deSSubbaraya Sundeep if (value & S_RXRDY) { 313*268ee7deSSubbaraya Sundeep s->regs[R_SPI_RIS] &= ~S_RXRDY; 314*268ee7deSSubbaraya Sundeep } 315*268ee7deSSubbaraya Sundeep if (value & S_RXCHOVRF) { 316*268ee7deSSubbaraya Sundeep s->regs[R_SPI_RIS] &= ~S_RXCHOVRF; 317*268ee7deSSubbaraya Sundeep } 318*268ee7deSSubbaraya Sundeep break; 319*268ee7deSSubbaraya Sundeep 320*268ee7deSSubbaraya Sundeep case R_SPI_MIS: 321*268ee7deSSubbaraya Sundeep case R_SPI_STATUS: 322*268ee7deSSubbaraya Sundeep case R_SPI_RIS: 323*268ee7deSSubbaraya Sundeep qemu_log_mask(LOG_GUEST_ERROR, 324*268ee7deSSubbaraya Sundeep "%s: Write to read only register 0x%" HWADDR_PRIx "\n", 325*268ee7deSSubbaraya Sundeep __func__, addr * 4); 326*268ee7deSSubbaraya Sundeep break; 327*268ee7deSSubbaraya Sundeep 328*268ee7deSSubbaraya Sundeep default: 329*268ee7deSSubbaraya Sundeep if (addr < ARRAY_SIZE(s->regs)) { 330*268ee7deSSubbaraya Sundeep s->regs[addr] = value; 331*268ee7deSSubbaraya Sundeep } else { 332*268ee7deSSubbaraya Sundeep qemu_log_mask(LOG_GUEST_ERROR, 333*268ee7deSSubbaraya Sundeep "%s: Bad offset 0x%" HWADDR_PRIx "\n", __func__, 334*268ee7deSSubbaraya Sundeep addr * 4); 335*268ee7deSSubbaraya Sundeep } 336*268ee7deSSubbaraya Sundeep break; 337*268ee7deSSubbaraya Sundeep } 338*268ee7deSSubbaraya Sundeep 339*268ee7deSSubbaraya Sundeep spi_update_irq(s); 340*268ee7deSSubbaraya Sundeep } 341*268ee7deSSubbaraya Sundeep 342*268ee7deSSubbaraya Sundeep static const MemoryRegionOps spi_ops = { 343*268ee7deSSubbaraya Sundeep .read = spi_read, 344*268ee7deSSubbaraya Sundeep .write = spi_write, 345*268ee7deSSubbaraya Sundeep .endianness = DEVICE_NATIVE_ENDIAN, 346*268ee7deSSubbaraya Sundeep .valid = { 347*268ee7deSSubbaraya Sundeep .min_access_size = 1, 348*268ee7deSSubbaraya Sundeep .max_access_size = 4 349*268ee7deSSubbaraya Sundeep } 350*268ee7deSSubbaraya Sundeep }; 351*268ee7deSSubbaraya Sundeep 352*268ee7deSSubbaraya Sundeep static void mss_spi_realize(DeviceState *dev, Error **errp) 353*268ee7deSSubbaraya Sundeep { 354*268ee7deSSubbaraya Sundeep MSSSpiState *s = MSS_SPI(dev); 355*268ee7deSSubbaraya Sundeep SysBusDevice *sbd = SYS_BUS_DEVICE(dev); 356*268ee7deSSubbaraya Sundeep 357*268ee7deSSubbaraya Sundeep s->spi = ssi_create_bus(dev, "spi"); 358*268ee7deSSubbaraya Sundeep 359*268ee7deSSubbaraya Sundeep sysbus_init_irq(sbd, &s->irq); 360*268ee7deSSubbaraya Sundeep ssi_auto_connect_slaves(dev, &s->cs_line, s->spi); 361*268ee7deSSubbaraya Sundeep sysbus_init_irq(sbd, &s->cs_line); 362*268ee7deSSubbaraya Sundeep 363*268ee7deSSubbaraya Sundeep memory_region_init_io(&s->mmio, OBJECT(s), &spi_ops, s, 364*268ee7deSSubbaraya Sundeep TYPE_MSS_SPI, R_SPI_MAX * 4); 365*268ee7deSSubbaraya Sundeep sysbus_init_mmio(sbd, &s->mmio); 366*268ee7deSSubbaraya Sundeep 367*268ee7deSSubbaraya Sundeep fifo32_create(&s->tx_fifo, FIFO_CAPACITY); 368*268ee7deSSubbaraya Sundeep fifo32_create(&s->rx_fifo, FIFO_CAPACITY); 369*268ee7deSSubbaraya Sundeep } 370*268ee7deSSubbaraya Sundeep 371*268ee7deSSubbaraya Sundeep static const VMStateDescription vmstate_mss_spi = { 372*268ee7deSSubbaraya Sundeep .name = TYPE_MSS_SPI, 373*268ee7deSSubbaraya Sundeep .version_id = 1, 374*268ee7deSSubbaraya Sundeep .minimum_version_id = 1, 375*268ee7deSSubbaraya Sundeep .fields = (VMStateField[]) { 376*268ee7deSSubbaraya Sundeep VMSTATE_FIFO32(tx_fifo, MSSSpiState), 377*268ee7deSSubbaraya Sundeep VMSTATE_FIFO32(rx_fifo, MSSSpiState), 378*268ee7deSSubbaraya Sundeep VMSTATE_UINT32_ARRAY(regs, MSSSpiState, R_SPI_MAX), 379*268ee7deSSubbaraya Sundeep VMSTATE_END_OF_LIST() 380*268ee7deSSubbaraya Sundeep } 381*268ee7deSSubbaraya Sundeep }; 382*268ee7deSSubbaraya Sundeep 383*268ee7deSSubbaraya Sundeep static void mss_spi_class_init(ObjectClass *klass, void *data) 384*268ee7deSSubbaraya Sundeep { 385*268ee7deSSubbaraya Sundeep DeviceClass *dc = DEVICE_CLASS(klass); 386*268ee7deSSubbaraya Sundeep 387*268ee7deSSubbaraya Sundeep dc->realize = mss_spi_realize; 388*268ee7deSSubbaraya Sundeep dc->reset = mss_spi_reset; 389*268ee7deSSubbaraya Sundeep dc->vmsd = &vmstate_mss_spi; 390*268ee7deSSubbaraya Sundeep } 391*268ee7deSSubbaraya Sundeep 392*268ee7deSSubbaraya Sundeep static const TypeInfo mss_spi_info = { 393*268ee7deSSubbaraya Sundeep .name = TYPE_MSS_SPI, 394*268ee7deSSubbaraya Sundeep .parent = TYPE_SYS_BUS_DEVICE, 395*268ee7deSSubbaraya Sundeep .instance_size = sizeof(MSSSpiState), 396*268ee7deSSubbaraya Sundeep .class_init = mss_spi_class_init, 397*268ee7deSSubbaraya Sundeep }; 398*268ee7deSSubbaraya Sundeep 399*268ee7deSSubbaraya Sundeep static void mss_spi_register_types(void) 400*268ee7deSSubbaraya Sundeep { 401*268ee7deSSubbaraya Sundeep type_register_static(&mss_spi_info); 402*268ee7deSSubbaraya Sundeep } 403*268ee7deSSubbaraya Sundeep 404*268ee7deSSubbaraya Sundeep type_init(mss_spi_register_types) 405