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