1 /* Blackfin Direct Memory Access (DMA) Controller model. 2 3 Copyright (C) 2010-2024 Free Software Foundation, Inc. 4 Contributed by Analog Devices, Inc. 5 6 This file is part of simulators. 7 8 This program is free software; you can redistribute it and/or modify 9 it under the terms of the GNU General Public License as published by 10 the Free Software Foundation; either version 3 of the License, or 11 (at your option) any later version. 12 13 This program is distributed in the hope that it will be useful, 14 but WITHOUT ANY WARRANTY; without even the implied warranty of 15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 GNU General Public License for more details. 17 18 You should have received a copy of the GNU General Public License 19 along with this program. If not, see <http://www.gnu.org/licenses/>. */ 20 21 /* This must come before any other includes. */ 22 #include "defs.h" 23 24 #include "sim-main.h" 25 #include "sim-hw.h" 26 #include "devices.h" 27 #include "hw-device.h" 28 #include "dv-bfin_dma.h" 29 #include "dv-bfin_dmac.h" 30 31 struct bfin_dmac 32 { 33 /* This top portion matches common dv_bfin struct. */ 34 bu32 base; 35 struct hw *dma_master; 36 bool acked; 37 38 const char * const *pmap; 39 unsigned int pmap_count; 40 }; 41 42 struct hw * 43 bfin_dmac_get_peer (struct hw *dma, bu16 pmap) 44 { 45 struct hw *ret, *me; 46 struct bfin_dmac *dmac; 47 char peer[100]; 48 49 me = hw_parent (dma); 50 dmac = hw_data (me); 51 if (pmap & CTYPE) 52 { 53 /* MDMA channel. */ 54 unsigned int chan_num = dv_get_bus_num (dma); 55 if (chan_num & 1) 56 chan_num &= ~1; 57 else 58 chan_num |= 1; 59 sprintf (peer, "%s/bfin_dma@%u", hw_path (me), chan_num); 60 } 61 else 62 { 63 unsigned int idx = pmap >> 12; 64 if (idx >= dmac->pmap_count) 65 hw_abort (me, "Invalid DMA peripheral_map %#x", pmap); 66 else 67 sprintf (peer, "/core/bfin_%s", dmac->pmap[idx]); 68 } 69 70 ret = hw_tree_find_device (me, peer); 71 if (!ret) 72 hw_abort (me, "Unable to locate peer for %s (pmap:%#x %s)", 73 hw_name (dma), pmap, peer); 74 return ret; 75 } 76 77 bu16 78 bfin_dmac_default_pmap (struct hw *dma) 79 { 80 unsigned int chan_num = dv_get_bus_num (dma); 81 82 if (chan_num < BFIN_DMAC_MDMA_BASE) 83 return (chan_num % 12) << 12; 84 else 85 return CTYPE; /* MDMA */ 86 } 87 88 static const char * const bfin_dmac_50x_pmap[] = 89 { 90 "ppi@0", "rsi", "sport@0", "sport@0", "sport@1", "sport@1", 91 "spi@0", "spi@1", "uart2@0", "uart2@0", "uart2@1", "uart2@1", 92 }; 93 94 /* XXX: Need to figure out how to handle portmuxed DMA channels. */ 95 static const struct hw_port_descriptor bfin_dmac_50x_ports[] = 96 { 97 { "ppi@0", 0, 0, input_port, }, 98 { "rsi", 1, 0, input_port, }, 99 { "sport@0_rx", 2, 0, input_port, }, 100 { "sport@0_tx", 3, 0, input_port, }, 101 { "sport@1_tx", 4, 0, input_port, }, 102 { "sport@1_rx", 5, 0, input_port, }, 103 { "spi@0", 6, 0, input_port, }, 104 { "spi@1", 7, 0, input_port, }, 105 { "uart2@0_rx", 8, 0, input_port, }, 106 { "uart2@0_tx", 9, 0, input_port, }, 107 { "uart2@1_rx", 10, 0, input_port, }, 108 { "uart2@1_tx", 11, 0, input_port, }, 109 { NULL, 0, 0, 0, }, 110 }; 111 112 static const char * const bfin_dmac_51x_pmap[] = 113 { 114 "ppi@0", "emac", "emac", "sport@0", "sport@0", "sport@1", 115 "sport@1", "spi@0", "uart@0", "uart@0", "uart@1", "uart@1", 116 }; 117 118 /* XXX: Need to figure out how to handle portmuxed DMA channels. */ 119 static const struct hw_port_descriptor bfin_dmac_51x_ports[] = 120 { 121 { "ppi@0", 0, 0, input_port, }, 122 { "emac_rx", 1, 0, input_port, }, 123 { "emac_tx", 2, 0, input_port, }, 124 { "sport@0_rx", 3, 0, input_port, }, 125 { "sport@0_tx", 4, 0, input_port, }, 126 /*{ "rsi", 4, 0, input_port, },*/ 127 { "sport@1_tx", 5, 0, input_port, }, 128 /*{ "spi@1", 5, 0, input_port, },*/ 129 { "sport@1_rx", 6, 0, input_port, }, 130 { "spi@0", 7, 0, input_port, }, 131 { "uart@0_rx", 8, 0, input_port, }, 132 { "uart@0_tx", 9, 0, input_port, }, 133 { "uart@1_rx", 10, 0, input_port, }, 134 { "uart@1_tx", 11, 0, input_port, }, 135 { NULL, 0, 0, 0, }, 136 }; 137 138 static const char * const bfin_dmac_52x_pmap[] = 139 { 140 "ppi@0", "emac", "emac", "sport@0", "sport@0", "sport@1", 141 "sport@1", "spi", "uart@0", "uart@0", "uart@1", "uart@1", 142 }; 143 144 /* XXX: Need to figure out how to handle portmuxed DMA channels 145 like PPI/NFC here which share DMA0. */ 146 static const struct hw_port_descriptor bfin_dmac_52x_ports[] = 147 { 148 { "ppi@0", 0, 0, input_port, }, 149 /*{ "nfc", 0, 0, input_port, },*/ 150 { "emac_rx", 1, 0, input_port, }, 151 /*{ "hostdp", 1, 0, input_port, },*/ 152 { "emac_tx", 2, 0, input_port, }, 153 /*{ "nfc", 2, 0, input_port, },*/ 154 { "sport@0_tx", 3, 0, input_port, }, 155 { "sport@0_rx", 4, 0, input_port, }, 156 { "sport@1_tx", 5, 0, input_port, }, 157 { "sport@1_rx", 6, 0, input_port, }, 158 { "spi", 7, 0, input_port, }, 159 { "uart@0_tx", 8, 0, input_port, }, 160 { "uart@0_rx", 9, 0, input_port, }, 161 { "uart@1_tx", 10, 0, input_port, }, 162 { "uart@1_rx", 11, 0, input_port, }, 163 { NULL, 0, 0, 0, }, 164 }; 165 166 static const char * const bfin_dmac_533_pmap[] = 167 { 168 "ppi@0", "sport@0", "sport@0", "sport@1", "sport@1", "spi", 169 "uart@0", "uart@0", 170 }; 171 172 static const struct hw_port_descriptor bfin_dmac_533_ports[] = 173 { 174 { "ppi@0", 0, 0, input_port, }, 175 { "sport@0_tx", 1, 0, input_port, }, 176 { "sport@0_rx", 2, 0, input_port, }, 177 { "sport@1_tx", 3, 0, input_port, }, 178 { "sport@1_rx", 4, 0, input_port, }, 179 { "spi", 5, 0, input_port, }, 180 { "uart@0_tx", 6, 0, input_port, }, 181 { "uart@0_rx", 7, 0, input_port, }, 182 { NULL, 0, 0, 0, }, 183 }; 184 185 static const char * const bfin_dmac_537_pmap[] = 186 { 187 "ppi@0", "emac", "emac", "sport@0", "sport@0", "sport@1", 188 "sport@1", "spi", "uart@0", "uart@0", "uart@1", "uart@1", 189 }; 190 191 static const struct hw_port_descriptor bfin_dmac_537_ports[] = 192 { 193 { "ppi@0", 0, 0, input_port, }, 194 { "emac_rx", 1, 0, input_port, }, 195 { "emac_tx", 2, 0, input_port, }, 196 { "sport@0_tx", 3, 0, input_port, }, 197 { "sport@0_rx", 4, 0, input_port, }, 198 { "sport@1_tx", 5, 0, input_port, }, 199 { "sport@1_rx", 6, 0, input_port, }, 200 { "spi", 7, 0, input_port, }, 201 { "uart@0_tx", 8, 0, input_port, }, 202 { "uart@0_rx", 9, 0, input_port, }, 203 { "uart@1_tx", 10, 0, input_port, }, 204 { "uart@1_rx", 11, 0, input_port, }, 205 { NULL, 0, 0, 0, }, 206 }; 207 208 static const char * const bfin_dmac0_538_pmap[] = 209 { 210 "ppi@0", "sport@0", "sport@0", "sport@1", "sport@1", "spi@0", 211 "uart@0", "uart@0", 212 }; 213 214 static const struct hw_port_descriptor bfin_dmac0_538_ports[] = 215 { 216 { "ppi@0", 0, 0, input_port, }, 217 { "sport@0_rx", 1, 0, input_port, }, 218 { "sport@0_tx", 2, 0, input_port, }, 219 { "sport@1_rx", 3, 0, input_port, }, 220 { "sport@1_tx", 4, 0, input_port, }, 221 { "spi@0", 5, 0, input_port, }, 222 { "uart@0_rx", 6, 0, input_port, }, 223 { "uart@0_tx", 7, 0, input_port, }, 224 { NULL, 0, 0, 0, }, 225 }; 226 227 static const char * const bfin_dmac1_538_pmap[] = 228 { 229 "sport@2", "sport@2", "sport@3", "sport@3", NULL, NULL, 230 "spi@1", "spi@2", "uart@1", "uart@1", "uart@2", "uart@2", 231 }; 232 233 static const struct hw_port_descriptor bfin_dmac1_538_ports[] = 234 { 235 { "sport@2_rx", 0, 0, input_port, }, 236 { "sport@2_tx", 1, 0, input_port, }, 237 { "sport@3_rx", 2, 0, input_port, }, 238 { "sport@3_tx", 3, 0, input_port, }, 239 { "spi@1", 6, 0, input_port, }, 240 { "spi@2", 7, 0, input_port, }, 241 { "uart@1_rx", 8, 0, input_port, }, 242 { "uart@1_tx", 9, 0, input_port, }, 243 { "uart@2_rx", 10, 0, input_port, }, 244 { "uart@2_tx", 11, 0, input_port, }, 245 { NULL, 0, 0, 0, }, 246 }; 247 248 static const char * const bfin_dmac0_54x_pmap[] = 249 { 250 "sport@0", "sport@0", "sport@1", "sport@1", "spi@0", "spi@1", 251 "uart2@0", "uart2@0", "uart2@1", "uart2@1", "atapi", "atapi", 252 }; 253 254 static const struct hw_port_descriptor bfin_dmac0_54x_ports[] = 255 { 256 { "sport@0_rx", 0, 0, input_port, }, 257 { "sport@0_tx", 1, 0, input_port, }, 258 { "sport@1_rx", 2, 0, input_port, }, 259 { "sport@1_tx", 3, 0, input_port, }, 260 { "spi@0", 4, 0, input_port, }, 261 { "spi@1", 5, 0, input_port, }, 262 { "uart2@0_rx", 6, 0, input_port, }, 263 { "uart2@0_tx", 7, 0, input_port, }, 264 { "uart2@1_rx", 8, 0, input_port, }, 265 { "uart2@1_tx", 9, 0, input_port, }, 266 { "atapi", 10, 0, input_port, }, 267 { "atapi", 11, 0, input_port, }, 268 { NULL, 0, 0, 0, }, 269 }; 270 271 static const char * const bfin_dmac1_54x_pmap[] = 272 { 273 "eppi@0", "eppi@1", "eppi@2", "pixc", "pixc", "pixc", 274 "sport@2", "sport@2", "sport@3", "sport@3", "sdh", 275 "spi@2", "uart2@2", "uart2@2", "uart2@3", "uart2@3", 276 }; 277 278 static const struct hw_port_descriptor bfin_dmac1_54x_ports[] = 279 { 280 { "eppi@0", 0, 0, input_port, }, 281 { "eppi@1", 1, 0, input_port, }, 282 { "eppi@2", 2, 0, input_port, }, 283 { "pixc", 3, 0, input_port, }, 284 { "pixc", 4, 0, input_port, }, 285 { "pixc", 5, 0, input_port, }, 286 { "sport@2_rx", 6, 0, input_port, }, 287 { "sport@2_tx", 7, 0, input_port, }, 288 { "sport@3_rx", 8, 0, input_port, }, 289 { "sport@3_tx", 9, 0, input_port, }, 290 { "sdh", 10, 0, input_port, }, 291 /*{ "nfc", 10, 0, input_port, },*/ 292 { "spi@2", 11, 0, input_port, }, 293 { "uart2@2_rx", 12, 0, input_port, }, 294 { "uart2@2_tx", 13, 0, input_port, }, 295 { "uart2@3_rx", 14, 0, input_port, }, 296 { "uart2@3_tx", 15, 0, input_port, }, 297 { NULL, 0, 0, 0, }, 298 }; 299 300 static const char * const bfin_dmac0_561_pmap[] = 301 { 302 "sport@0", "sport@0", "sport@1", "sport@1", "spi", "uart@0", "uart@0", 303 }; 304 305 static const struct hw_port_descriptor bfin_dmac0_561_ports[] = 306 { 307 { "sport@0_rx", 0, 0, input_port, }, 308 { "sport@0_tx", 1, 0, input_port, }, 309 { "sport@1_rx", 2, 0, input_port, }, 310 { "sport@1_tx", 3, 0, input_port, }, 311 { "spi@0", 4, 0, input_port, }, 312 { "uart@0_rx", 5, 0, input_port, }, 313 { "uart@0_tx", 6, 0, input_port, }, 314 { NULL, 0, 0, 0, }, 315 }; 316 317 static const char * const bfin_dmac1_561_pmap[] = 318 { 319 "ppi@0", "ppi@1", 320 }; 321 322 static const struct hw_port_descriptor bfin_dmac1_561_ports[] = 323 { 324 { "ppi@0", 0, 0, input_port, }, 325 { "ppi@1", 1, 0, input_port, }, 326 { NULL, 0, 0, 0, }, 327 }; 328 329 static const char * const bfin_dmac_59x_pmap[] = 330 { 331 "ppi@0", "sport@0", "sport@0", "sport@1", "sport@1", "spi@0", 332 "spi@1", "uart@0", "uart@0", 333 }; 334 335 static const struct hw_port_descriptor bfin_dmac_59x_ports[] = 336 { 337 { "ppi@0", 0, 0, input_port, }, 338 { "sport@0_tx", 1, 0, input_port, }, 339 { "sport@0_rx", 2, 0, input_port, }, 340 { "sport@1_tx", 3, 0, input_port, }, 341 { "sport@1_rx", 4, 0, input_port, }, 342 { "spi@0", 5, 0, input_port, }, 343 { "spi@1", 6, 0, input_port, }, 344 { "uart@0_rx", 7, 0, input_port, }, 345 { "uart@0_tx", 8, 0, input_port, }, 346 { NULL, 0, 0, 0, }, 347 }; 348 349 static void 350 bfin_dmac_port_event (struct hw *me, int my_port, struct hw *source, 351 int source_port, int level) 352 { 353 SIM_DESC sd = hw_system (me); 354 struct bfin_dmac *dmac = hw_data (me); 355 struct hw *dma = hw_child (me); 356 357 while (dma) 358 { 359 bu16 pmap; 360 sim_hw_io_read_buffer (sd, dma, &pmap, 0, 0x2c, sizeof (pmap)); 361 pmap >>= 12; 362 if (pmap == my_port) 363 break; 364 dma = hw_sibling (dma); 365 } 366 367 if (!dma) 368 hw_abort (me, "no valid dma mapping found for %s", dmac->pmap[my_port]); 369 370 /* Have the DMA channel raise its interrupt to the SIC. */ 371 hw_port_event (dma, 0, 1); 372 } 373 374 static void 375 bfin_dmac_finish (struct hw *me) 376 { 377 struct bfin_dmac *dmac; 378 unsigned int dmac_num = dv_get_bus_num (me); 379 380 dmac = HW_ZALLOC (me, struct bfin_dmac); 381 382 set_hw_data (me, dmac); 383 set_hw_port_event (me, bfin_dmac_port_event); 384 385 /* Initialize the DMA Controller. */ 386 if (hw_find_property (me, "type") == NULL) 387 hw_abort (me, "Missing \"type\" property"); 388 389 switch (hw_find_integer_property (me, "type")) 390 { 391 case 500 ... 509: 392 if (dmac_num != 0) 393 hw_abort (me, "this Blackfin only has a DMAC0"); 394 dmac->pmap = bfin_dmac_50x_pmap; 395 dmac->pmap_count = ARRAY_SIZE (bfin_dmac_50x_pmap); 396 set_hw_ports (me, bfin_dmac_50x_ports); 397 break; 398 case 510 ... 519: 399 if (dmac_num != 0) 400 hw_abort (me, "this Blackfin only has a DMAC0"); 401 dmac->pmap = bfin_dmac_51x_pmap; 402 dmac->pmap_count = ARRAY_SIZE (bfin_dmac_51x_pmap); 403 set_hw_ports (me, bfin_dmac_51x_ports); 404 break; 405 case 522 ... 527: 406 if (dmac_num != 0) 407 hw_abort (me, "this Blackfin only has a DMAC0"); 408 dmac->pmap = bfin_dmac_52x_pmap; 409 dmac->pmap_count = ARRAY_SIZE (bfin_dmac_52x_pmap); 410 set_hw_ports (me, bfin_dmac_52x_ports); 411 break; 412 case 531 ... 533: 413 if (dmac_num != 0) 414 hw_abort (me, "this Blackfin only has a DMAC0"); 415 dmac->pmap = bfin_dmac_533_pmap; 416 dmac->pmap_count = ARRAY_SIZE (bfin_dmac_533_pmap); 417 set_hw_ports (me, bfin_dmac_533_ports); 418 break; 419 case 534: 420 case 536: 421 case 537: 422 if (dmac_num != 0) 423 hw_abort (me, "this Blackfin only has a DMAC0"); 424 dmac->pmap = bfin_dmac_537_pmap; 425 dmac->pmap_count = ARRAY_SIZE (bfin_dmac_537_pmap); 426 set_hw_ports (me, bfin_dmac_537_ports); 427 break; 428 case 538 ... 539: 429 switch (dmac_num) 430 { 431 case 0: 432 dmac->pmap = bfin_dmac0_538_pmap; 433 dmac->pmap_count = ARRAY_SIZE (bfin_dmac0_538_pmap); 434 set_hw_ports (me, bfin_dmac0_538_ports); 435 break; 436 case 1: 437 dmac->pmap = bfin_dmac1_538_pmap; 438 dmac->pmap_count = ARRAY_SIZE (bfin_dmac1_538_pmap); 439 set_hw_ports (me, bfin_dmac1_538_ports); 440 break; 441 default: 442 hw_abort (me, "this Blackfin only has a DMAC0 & DMAC1"); 443 } 444 break; 445 case 540 ... 549: 446 switch (dmac_num) 447 { 448 case 0: 449 dmac->pmap = bfin_dmac0_54x_pmap; 450 dmac->pmap_count = ARRAY_SIZE (bfin_dmac0_54x_pmap); 451 set_hw_ports (me, bfin_dmac0_54x_ports); 452 break; 453 case 1: 454 dmac->pmap = bfin_dmac1_54x_pmap; 455 dmac->pmap_count = ARRAY_SIZE (bfin_dmac1_54x_pmap); 456 set_hw_ports (me, bfin_dmac1_54x_ports); 457 break; 458 default: 459 hw_abort (me, "this Blackfin only has a DMAC0 & DMAC1"); 460 } 461 break; 462 case 561: 463 switch (dmac_num) 464 { 465 case 0: 466 dmac->pmap = bfin_dmac0_561_pmap; 467 dmac->pmap_count = ARRAY_SIZE (bfin_dmac0_561_pmap); 468 set_hw_ports (me, bfin_dmac0_561_ports); 469 break; 470 case 1: 471 dmac->pmap = bfin_dmac1_561_pmap; 472 dmac->pmap_count = ARRAY_SIZE (bfin_dmac1_561_pmap); 473 set_hw_ports (me, bfin_dmac1_561_ports); 474 break; 475 default: 476 hw_abort (me, "this Blackfin only has a DMAC0 & DMAC1"); 477 } 478 break; 479 case 590 ... 599: 480 if (dmac_num != 0) 481 hw_abort (me, "this Blackfin only has a DMAC0"); 482 dmac->pmap = bfin_dmac_59x_pmap; 483 dmac->pmap_count = ARRAY_SIZE (bfin_dmac_59x_pmap); 484 set_hw_ports (me, bfin_dmac_59x_ports); 485 break; 486 default: 487 hw_abort (me, "no support for DMAC on this Blackfin model yet"); 488 } 489 } 490 491 const struct hw_descriptor dv_bfin_dmac_descriptor[] = 492 { 493 {"bfin_dmac", bfin_dmac_finish,}, 494 {NULL, NULL}, 495 }; 496