1 /* 2 * SiFive Platform DMA emulation 3 * 4 * Copyright (c) 2020 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 10 * modify it under the terms of the GNU General Public License as 11 * published by the Free Software Foundation; either version 2 or 12 * (at your option) version 3 of the License. 13 * 14 * This program is distributed in the hope that it will be useful, 15 * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 * GNU General Public License for more details. 18 * 19 * You should have received a copy of the GNU General Public License along 20 * with this program; if not, see <http://www.gnu.org/licenses/>. 21 */ 22 23 #include "qemu/osdep.h" 24 #include "qemu/bitops.h" 25 #include "qemu/log.h" 26 #include "qapi/error.h" 27 #include "hw/irq.h" 28 #include "hw/qdev-properties.h" 29 #include "hw/sysbus.h" 30 #include "migration/vmstate.h" 31 #include "sysemu/dma.h" 32 #include "hw/dma/sifive_pdma.h" 33 34 #define DMA_CONTROL 0x000 35 #define CONTROL_CLAIM BIT(0) 36 #define CONTROL_RUN BIT(1) 37 #define CONTROL_DONE_IE BIT(14) 38 #define CONTROL_ERR_IE BIT(15) 39 #define CONTROL_DONE BIT(30) 40 #define CONTROL_ERR BIT(31) 41 42 #define DMA_NEXT_CONFIG 0x004 43 #define CONFIG_REPEAT BIT(2) 44 #define CONFIG_ORDER BIT(3) 45 #define CONFIG_WRSZ_SHIFT 24 46 #define CONFIG_RDSZ_SHIFT 28 47 #define CONFIG_SZ_MASK 0xf 48 49 #define DMA_NEXT_BYTES 0x008 50 #define DMA_NEXT_DST 0x010 51 #define DMA_NEXT_SRC 0x018 52 #define DMA_EXEC_CONFIG 0x104 53 #define DMA_EXEC_BYTES 0x108 54 #define DMA_EXEC_DST 0x110 55 #define DMA_EXEC_SRC 0x118 56 57 /* 58 * FU540/FU740 docs are incorrect with NextConfig.wsize/rsize reset values. 59 * The reset values tested on Unleashed/Unmatched boards are 6 instead of 0. 60 */ 61 #define CONFIG_WRSZ_DEFAULT 6 62 #define CONFIG_RDSZ_DEFAULT 6 63 64 enum dma_chan_state { 65 DMA_CHAN_STATE_IDLE, 66 DMA_CHAN_STATE_STARTED, 67 DMA_CHAN_STATE_ERROR, 68 DMA_CHAN_STATE_DONE 69 }; 70 71 static void sifive_pdma_run(SiFivePDMAState *s, int ch) 72 { 73 uint64_t bytes = s->chan[ch].next_bytes; 74 uint64_t dst = s->chan[ch].next_dst; 75 uint64_t src = s->chan[ch].next_src; 76 uint32_t config = s->chan[ch].next_config; 77 int wsize, rsize, size; 78 uint8_t buf[64]; 79 int n; 80 81 /* do nothing if bytes to transfer is zero */ 82 if (!bytes) { 83 goto error; 84 } 85 86 /* 87 * The manual does not describe how the hardware behaviors when 88 * config.wsize and config.rsize are given different values. 89 * A common case is memory to memory DMA, and in this case they 90 * are normally the same. Abort if this expectation fails. 91 */ 92 wsize = (config >> CONFIG_WRSZ_SHIFT) & CONFIG_SZ_MASK; 93 rsize = (config >> CONFIG_RDSZ_SHIFT) & CONFIG_SZ_MASK; 94 if (wsize != rsize) { 95 goto error; 96 } 97 98 /* 99 * Calculate the transaction size 100 * 101 * size field is base 2 logarithm of DMA transaction size, 102 * but there is an upper limit of 64 bytes per transaction. 103 */ 104 size = wsize; 105 if (size > 6) { 106 size = 6; 107 } 108 size = 1 << size; 109 110 /* the bytes to transfer should be multiple of transaction size */ 111 if (bytes % size) { 112 goto error; 113 } 114 115 /* indicate a DMA transfer is started */ 116 s->chan[ch].state = DMA_CHAN_STATE_STARTED; 117 s->chan[ch].control &= ~CONTROL_DONE; 118 s->chan[ch].control &= ~CONTROL_ERR; 119 120 /* load the next_ registers into their exec_ counterparts */ 121 s->chan[ch].exec_config = config; 122 s->chan[ch].exec_bytes = bytes; 123 s->chan[ch].exec_dst = dst; 124 s->chan[ch].exec_src = src; 125 126 for (n = 0; n < bytes / size; n++) { 127 cpu_physical_memory_read(s->chan[ch].exec_src, buf, size); 128 cpu_physical_memory_write(s->chan[ch].exec_dst, buf, size); 129 s->chan[ch].exec_src += size; 130 s->chan[ch].exec_dst += size; 131 s->chan[ch].exec_bytes -= size; 132 } 133 134 /* indicate a DMA transfer is done */ 135 s->chan[ch].state = DMA_CHAN_STATE_DONE; 136 s->chan[ch].control &= ~CONTROL_RUN; 137 s->chan[ch].control |= CONTROL_DONE; 138 139 /* reload exec_ registers if repeat is required */ 140 if (s->chan[ch].next_config & CONFIG_REPEAT) { 141 s->chan[ch].exec_bytes = bytes; 142 s->chan[ch].exec_dst = dst; 143 s->chan[ch].exec_src = src; 144 } 145 146 return; 147 148 error: 149 s->chan[ch].state = DMA_CHAN_STATE_ERROR; 150 s->chan[ch].control |= CONTROL_ERR; 151 return; 152 } 153 154 static inline void sifive_pdma_update_irq(SiFivePDMAState *s, int ch) 155 { 156 bool done_ie, err_ie; 157 158 done_ie = !!(s->chan[ch].control & CONTROL_DONE_IE); 159 err_ie = !!(s->chan[ch].control & CONTROL_ERR_IE); 160 161 if (done_ie && (s->chan[ch].control & CONTROL_DONE)) { 162 qemu_irq_raise(s->irq[ch * 2]); 163 } else { 164 qemu_irq_lower(s->irq[ch * 2]); 165 } 166 167 if (err_ie && (s->chan[ch].control & CONTROL_ERR)) { 168 qemu_irq_raise(s->irq[ch * 2 + 1]); 169 } else { 170 qemu_irq_lower(s->irq[ch * 2 + 1]); 171 } 172 173 s->chan[ch].state = DMA_CHAN_STATE_IDLE; 174 } 175 176 static uint64_t sifive_pdma_read(void *opaque, hwaddr offset, unsigned size) 177 { 178 SiFivePDMAState *s = opaque; 179 int ch = SIFIVE_PDMA_CHAN_NO(offset); 180 uint64_t val = 0; 181 182 if (ch >= SIFIVE_PDMA_CHANS) { 183 qemu_log_mask(LOG_GUEST_ERROR, "%s: Invalid channel no %d\n", 184 __func__, ch); 185 return 0; 186 } 187 188 offset &= 0xfff; 189 switch (offset) { 190 case DMA_CONTROL: 191 val = s->chan[ch].control; 192 break; 193 case DMA_NEXT_CONFIG: 194 val = s->chan[ch].next_config; 195 break; 196 case DMA_NEXT_BYTES: 197 val = s->chan[ch].next_bytes; 198 break; 199 case DMA_NEXT_DST: 200 val = s->chan[ch].next_dst; 201 break; 202 case DMA_NEXT_SRC: 203 val = s->chan[ch].next_src; 204 break; 205 case DMA_EXEC_CONFIG: 206 val = s->chan[ch].exec_config; 207 break; 208 case DMA_EXEC_BYTES: 209 val = s->chan[ch].exec_bytes; 210 break; 211 case DMA_EXEC_DST: 212 val = s->chan[ch].exec_dst; 213 break; 214 case DMA_EXEC_SRC: 215 val = s->chan[ch].exec_src; 216 break; 217 default: 218 qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%" HWADDR_PRIX "\n", 219 __func__, offset); 220 break; 221 } 222 223 return val; 224 } 225 226 static void sifive_pdma_write(void *opaque, hwaddr offset, 227 uint64_t value, unsigned size) 228 { 229 SiFivePDMAState *s = opaque; 230 int ch = SIFIVE_PDMA_CHAN_NO(offset); 231 bool claimed; 232 233 if (ch >= SIFIVE_PDMA_CHANS) { 234 qemu_log_mask(LOG_GUEST_ERROR, "%s: Invalid channel no %d\n", 235 __func__, ch); 236 return; 237 } 238 239 offset &= 0xfff; 240 switch (offset) { 241 case DMA_CONTROL: 242 claimed = !!s->chan[ch].control & CONTROL_CLAIM; 243 244 if (!claimed && (value & CONTROL_CLAIM)) { 245 /* reset Next* registers */ 246 s->chan[ch].next_config = (CONFIG_RDSZ_DEFAULT << CONFIG_RDSZ_SHIFT) | 247 (CONFIG_WRSZ_DEFAULT << CONFIG_WRSZ_SHIFT); 248 s->chan[ch].next_bytes = 0; 249 s->chan[ch].next_dst = 0; 250 s->chan[ch].next_src = 0; 251 } 252 253 s->chan[ch].control = value; 254 255 /* 256 * If channel was not claimed before run bit is set, 257 * DMA won't run. 258 */ 259 if (!claimed) { 260 s->chan[ch].control &= ~CONTROL_RUN; 261 return; 262 } 263 264 if (value & CONTROL_RUN) { 265 sifive_pdma_run(s, ch); 266 } 267 268 sifive_pdma_update_irq(s, ch); 269 break; 270 case DMA_NEXT_CONFIG: 271 s->chan[ch].next_config = value; 272 break; 273 case DMA_NEXT_BYTES: 274 s->chan[ch].next_bytes = value; 275 break; 276 case DMA_NEXT_DST: 277 s->chan[ch].next_dst = value; 278 break; 279 case DMA_NEXT_SRC: 280 s->chan[ch].next_src = value; 281 break; 282 case DMA_EXEC_CONFIG: 283 case DMA_EXEC_BYTES: 284 case DMA_EXEC_DST: 285 case DMA_EXEC_SRC: 286 /* these are read-only registers */ 287 break; 288 default: 289 qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%" HWADDR_PRIX "\n", 290 __func__, offset); 291 break; 292 } 293 } 294 295 static const MemoryRegionOps sifive_pdma_ops = { 296 .read = sifive_pdma_read, 297 .write = sifive_pdma_write, 298 .endianness = DEVICE_LITTLE_ENDIAN, 299 /* there are 32-bit and 64-bit wide registers */ 300 .impl = { 301 .min_access_size = 4, 302 .max_access_size = 8, 303 } 304 }; 305 306 static void sifive_pdma_realize(DeviceState *dev, Error **errp) 307 { 308 SiFivePDMAState *s = SIFIVE_PDMA(dev); 309 int i; 310 311 memory_region_init_io(&s->iomem, OBJECT(dev), &sifive_pdma_ops, s, 312 TYPE_SIFIVE_PDMA, SIFIVE_PDMA_REG_SIZE); 313 sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->iomem); 314 315 for (i = 0; i < SIFIVE_PDMA_IRQS; i++) { 316 sysbus_init_irq(SYS_BUS_DEVICE(dev), &s->irq[i]); 317 } 318 } 319 320 static void sifive_pdma_class_init(ObjectClass *klass, void *data) 321 { 322 DeviceClass *dc = DEVICE_CLASS(klass); 323 324 dc->desc = "SiFive Platform DMA controller"; 325 dc->realize = sifive_pdma_realize; 326 } 327 328 static const TypeInfo sifive_pdma_info = { 329 .name = TYPE_SIFIVE_PDMA, 330 .parent = TYPE_SYS_BUS_DEVICE, 331 .instance_size = sizeof(SiFivePDMAState), 332 .class_init = sifive_pdma_class_init, 333 }; 334 335 static void sifive_pdma_register_types(void) 336 { 337 type_register_static(&sifive_pdma_info); 338 } 339 340 type_init(sifive_pdma_register_types) 341