1 1.1 christos /* Blackfin Serial Peripheral Interface (SPI) model 2 1.1 christos 3 1.1.1.11 christos Copyright (C) 2010-2025 Free Software Foundation, Inc. 4 1.1 christos Contributed by Analog Devices, Inc. 5 1.1 christos 6 1.1 christos This file is part of simulators. 7 1.1 christos 8 1.1 christos This program is free software; you can redistribute it and/or modify 9 1.1 christos it under the terms of the GNU General Public License as published by 10 1.1 christos the Free Software Foundation; either version 3 of the License, or 11 1.1 christos (at your option) any later version. 12 1.1 christos 13 1.1 christos This program is distributed in the hope that it will be useful, 14 1.1 christos but WITHOUT ANY WARRANTY; without even the implied warranty of 15 1.1 christos MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 1.1 christos GNU General Public License for more details. 17 1.1 christos 18 1.1 christos You should have received a copy of the GNU General Public License 19 1.1 christos along with this program. If not, see <http://www.gnu.org/licenses/>. */ 20 1.1 christos 21 1.1.1.9 christos /* This must come before any other includes. */ 22 1.1.1.9 christos #include "defs.h" 23 1.1 christos 24 1.1 christos #include "sim-main.h" 25 1.1 christos #include "devices.h" 26 1.1 christos #include "dv-bfin_spi.h" 27 1.1 christos 28 1.1 christos /* XXX: This is merely a stub. */ 29 1.1 christos 30 1.1 christos struct bfin_spi 31 1.1 christos { 32 1.1 christos /* This top portion matches common dv_bfin struct. */ 33 1.1 christos bu32 base; 34 1.1 christos struct hw *dma_master; 35 1.1 christos bool acked; 36 1.1 christos 37 1.1 christos struct hw_event *handler; 38 1.1 christos char saved_byte; 39 1.1 christos int saved_count; 40 1.1 christos 41 1.1 christos /* Order after here is important -- matches hardware MMR layout. */ 42 1.1 christos bu16 BFIN_MMR_16(ctl); 43 1.1 christos bu16 BFIN_MMR_16(flg); 44 1.1 christos bu16 BFIN_MMR_16(stat); 45 1.1 christos bu16 BFIN_MMR_16(tdbr); 46 1.1 christos bu16 BFIN_MMR_16(rdbr); 47 1.1 christos bu16 BFIN_MMR_16(baud); 48 1.1 christos bu16 BFIN_MMR_16(shadow); 49 1.1 christos }; 50 1.1 christos #define mmr_base() offsetof(struct bfin_spi, ctl) 51 1.1 christos #define mmr_offset(mmr) (offsetof(struct bfin_spi, mmr) - mmr_base()) 52 1.1 christos 53 1.1 christos static const char * const mmr_names[] = 54 1.1 christos { 55 1.1 christos "SPI_CTL", "SPI_FLG", "SPI_STAT", "SPI_TDBR", 56 1.1 christos "SPI_RDBR", "SPI_BAUD", "SPI_SHADOW", 57 1.1 christos }; 58 1.1 christos #define mmr_name(off) mmr_names[(off) / 4] 59 1.1 christos 60 1.1 christos static bool 61 1.1 christos bfin_spi_enabled (struct bfin_spi *spi) 62 1.1 christos { 63 1.1 christos return (spi->ctl & SPE); 64 1.1 christos } 65 1.1 christos 66 1.1 christos static bu16 67 1.1 christos bfin_spi_timod (struct bfin_spi *spi) 68 1.1 christos { 69 1.1 christos return (spi->ctl & TIMOD); 70 1.1 christos } 71 1.1 christos 72 1.1 christos static unsigned 73 1.1 christos bfin_spi_io_write_buffer (struct hw *me, const void *source, int space, 74 1.1 christos address_word addr, unsigned nr_bytes) 75 1.1 christos { 76 1.1 christos struct bfin_spi *spi = hw_data (me); 77 1.1 christos bu32 mmr_off; 78 1.1 christos bu32 value; 79 1.1 christos bu16 *valuep; 80 1.1 christos 81 1.1.1.5 christos /* Invalid access mode is higher priority than missing register. */ 82 1.1.1.5 christos if (!dv_bfin_mmr_require_16 (me, addr, nr_bytes, true)) 83 1.1.1.5 christos return 0; 84 1.1.1.5 christos 85 1.1 christos value = dv_load_2 (source); 86 1.1 christos mmr_off = addr - spi->base; 87 1.1.1.9 christos valuep = (void *)((uintptr_t)spi + mmr_base() + mmr_off); 88 1.1 christos 89 1.1 christos HW_TRACE_WRITE (); 90 1.1 christos 91 1.1 christos switch (mmr_off) 92 1.1 christos { 93 1.1 christos case mmr_offset(stat): 94 1.1 christos dv_w1c_2 (valuep, value, ~(SPIF | TXS | RXS)); 95 1.1 christos break; 96 1.1 christos case mmr_offset(tdbr): 97 1.1 christos *valuep = value; 98 1.1 christos if (bfin_spi_enabled (spi) && bfin_spi_timod (spi) == TDBR_CORE) 99 1.1 christos { 100 1.1 christos spi->stat |= RXS; 101 1.1 christos spi->stat &= ~TXS; 102 1.1 christos } 103 1.1 christos break; 104 1.1 christos case mmr_offset(rdbr): 105 1.1 christos case mmr_offset(ctl): 106 1.1 christos case mmr_offset(flg): 107 1.1 christos case mmr_offset(baud): 108 1.1 christos case mmr_offset(shadow): 109 1.1 christos *valuep = value; 110 1.1 christos break; 111 1.1 christos default: 112 1.1 christos dv_bfin_mmr_invalid (me, addr, nr_bytes, true); 113 1.1.1.5 christos return 0; 114 1.1 christos } 115 1.1 christos 116 1.1 christos return nr_bytes; 117 1.1 christos } 118 1.1 christos 119 1.1 christos static unsigned 120 1.1 christos bfin_spi_io_read_buffer (struct hw *me, void *dest, int space, 121 1.1 christos address_word addr, unsigned nr_bytes) 122 1.1 christos { 123 1.1 christos struct bfin_spi *spi = hw_data (me); 124 1.1 christos bu32 mmr_off; 125 1.1 christos bu16 *valuep; 126 1.1 christos 127 1.1.1.5 christos /* Invalid access mode is higher priority than missing register. */ 128 1.1.1.5 christos if (!dv_bfin_mmr_require_16 (me, addr, nr_bytes, false)) 129 1.1.1.5 christos return 0; 130 1.1.1.5 christos 131 1.1 christos mmr_off = addr - spi->base; 132 1.1.1.9 christos valuep = (void *)((uintptr_t)spi + mmr_base() + mmr_off); 133 1.1 christos 134 1.1 christos HW_TRACE_READ (); 135 1.1 christos 136 1.1 christos switch (mmr_off) 137 1.1 christos { 138 1.1 christos case mmr_offset(rdbr): 139 1.1 christos dv_store_2 (dest, *valuep); 140 1.1 christos if (bfin_spi_enabled (spi) && bfin_spi_timod (spi) == RDBR_CORE) 141 1.1 christos spi->stat &= ~(RXS | TXS); 142 1.1 christos break; 143 1.1 christos case mmr_offset(ctl): 144 1.1 christos case mmr_offset(stat): 145 1.1 christos case mmr_offset(flg): 146 1.1 christos case mmr_offset(tdbr): 147 1.1 christos case mmr_offset(baud): 148 1.1 christos case mmr_offset(shadow): 149 1.1 christos dv_store_2 (dest, *valuep); 150 1.1 christos break; 151 1.1 christos default: 152 1.1 christos dv_bfin_mmr_invalid (me, addr, nr_bytes, false); 153 1.1.1.5 christos return 0; 154 1.1 christos } 155 1.1 christos 156 1.1 christos return nr_bytes; 157 1.1 christos } 158 1.1 christos 159 1.1 christos static unsigned 160 1.1 christos bfin_spi_dma_read_buffer (struct hw *me, void *dest, int space, 161 1.1 christos unsigned_word addr, unsigned nr_bytes) 162 1.1 christos { 163 1.1 christos HW_TRACE_DMA_READ (); 164 1.1 christos return 0; 165 1.1 christos } 166 1.1 christos 167 1.1 christos static unsigned 168 1.1 christos bfin_spi_dma_write_buffer (struct hw *me, const void *source, 169 1.1 christos int space, unsigned_word addr, 170 1.1 christos unsigned nr_bytes, 171 1.1 christos int violate_read_only_section) 172 1.1 christos { 173 1.1 christos HW_TRACE_DMA_WRITE (); 174 1.1 christos return 0; 175 1.1 christos } 176 1.1 christos 177 1.1 christos static const struct hw_port_descriptor bfin_spi_ports[] = 178 1.1 christos { 179 1.1 christos { "stat", 0, 0, output_port, }, 180 1.1 christos { NULL, 0, 0, 0, }, 181 1.1 christos }; 182 1.1 christos 183 1.1 christos static void 184 1.1 christos attach_bfin_spi_regs (struct hw *me, struct bfin_spi *spi) 185 1.1 christos { 186 1.1 christos address_word attach_address; 187 1.1 christos int attach_space; 188 1.1 christos unsigned attach_size; 189 1.1 christos reg_property_spec reg; 190 1.1 christos 191 1.1 christos if (hw_find_property (me, "reg") == NULL) 192 1.1 christos hw_abort (me, "Missing \"reg\" property"); 193 1.1 christos 194 1.1 christos if (!hw_find_reg_array_property (me, "reg", 0, ®)) 195 1.1 christos hw_abort (me, "\"reg\" property must contain three addr/size entries"); 196 1.1 christos 197 1.1 christos hw_unit_address_to_attach_address (hw_parent (me), 198 1.1 christos ®.address, 199 1.1 christos &attach_space, &attach_address, me); 200 1.1 christos hw_unit_size_to_attach_size (hw_parent (me), ®.size, &attach_size, me); 201 1.1 christos 202 1.1 christos if (attach_size != BFIN_MMR_SPI_SIZE) 203 1.1 christos hw_abort (me, "\"reg\" size must be %#x", BFIN_MMR_SPI_SIZE); 204 1.1 christos 205 1.1 christos hw_attach_address (hw_parent (me), 206 1.1 christos 0, attach_space, attach_address, attach_size, me); 207 1.1 christos 208 1.1 christos spi->base = attach_address; 209 1.1 christos } 210 1.1 christos 211 1.1 christos static void 212 1.1 christos bfin_spi_finish (struct hw *me) 213 1.1 christos { 214 1.1 christos struct bfin_spi *spi; 215 1.1 christos 216 1.1 christos spi = HW_ZALLOC (me, struct bfin_spi); 217 1.1 christos 218 1.1 christos set_hw_data (me, spi); 219 1.1 christos set_hw_io_read_buffer (me, bfin_spi_io_read_buffer); 220 1.1 christos set_hw_io_write_buffer (me, bfin_spi_io_write_buffer); 221 1.1 christos set_hw_dma_read_buffer (me, bfin_spi_dma_read_buffer); 222 1.1 christos set_hw_dma_write_buffer (me, bfin_spi_dma_write_buffer); 223 1.1 christos set_hw_ports (me, bfin_spi_ports); 224 1.1 christos 225 1.1 christos attach_bfin_spi_regs (me, spi); 226 1.1 christos 227 1.1 christos /* Initialize the SPI. */ 228 1.1 christos spi->ctl = 0x0400; 229 1.1 christos spi->flg = 0xFF00; 230 1.1 christos spi->stat = 0x0001; 231 1.1 christos } 232 1.1 christos 233 1.1 christos const struct hw_descriptor dv_bfin_spi_descriptor[] = 234 1.1 christos { 235 1.1 christos {"bfin_spi", bfin_spi_finish,}, 236 1.1 christos {NULL, NULL}, 237 1.1 christos }; 238