Commit 6cba4355066bda19f14d4da66b8abbca0ffdfd59
Committed by
Sekhar Nori
1 parent
bf3156dde3
ARM: edma: Add DT and runtime PM support to the private EDMA API
Adds support for parsing the TI EDMA DT data into the required EDMA private API platform data. Enables runtime PM support to initialize the EDMA hwmod. Enables build on OMAP. Changes by Joel: * Setup default one-to-one mapping for queue_priority and queue_tc mapping as discussed in [1]. * Split out xbar stuff to separate patch. [1] * Dropped unused DT helper to convert to array * Fixed dangling pointer issue with Sekhar's changes [1] https://patchwork.kernel.org/patch/2226761/ Signed-off-by: Matt Porter <mporter@ti.com> [nsekhar@ti.com: fix checkpatch errors, build breakages. Introduce edma_setup_info_from_dt() as part of that effort] Signed-off-by: Joel A Fernandes <joelagnel@ti.com> Acked-by: Arnd Bergmann <arnd@arndb.de> Signed-off-by: Sekhar Nori <nsekhar@ti.com>
Showing 8 changed files with 189 additions and 29 deletions Side-by-side Diff
arch/arm/common/edma.c
... | ... | @@ -25,6 +25,13 @@ |
25 | 25 | #include <linux/platform_device.h> |
26 | 26 | #include <linux/io.h> |
27 | 27 | #include <linux/slab.h> |
28 | +#include <linux/edma.h> | |
29 | +#include <linux/err.h> | |
30 | +#include <linux/of_address.h> | |
31 | +#include <linux/of_device.h> | |
32 | +#include <linux/of_dma.h> | |
33 | +#include <linux/of_irq.h> | |
34 | +#include <linux/pm_runtime.h> | |
28 | 35 | |
29 | 36 | #include <linux/platform_data/edma.h> |
30 | 37 | |
31 | 38 | |
32 | 39 | |
33 | 40 | |
... | ... | @@ -1369,13 +1376,110 @@ |
1369 | 1376 | } |
1370 | 1377 | EXPORT_SYMBOL(edma_clear_event); |
1371 | 1378 | |
1372 | -/*-----------------------------------------------------------------------*/ | |
1379 | +#if IS_ENABLED(CONFIG_OF) && IS_ENABLED(CONFIG_DMADEVICES) | |
1373 | 1380 | |
1374 | -static int __init edma_probe(struct platform_device *pdev) | |
1381 | +static int edma_of_parse_dt(struct device *dev, | |
1382 | + struct device_node *node, | |
1383 | + struct edma_soc_info *pdata) | |
1375 | 1384 | { |
1385 | + int ret = 0, i; | |
1386 | + u32 value; | |
1387 | + struct edma_rsv_info *rsv_info; | |
1388 | + s8 (*queue_tc_map)[2], (*queue_priority_map)[2]; | |
1389 | + | |
1390 | + memset(pdata, 0, sizeof(struct edma_soc_info)); | |
1391 | + | |
1392 | + ret = of_property_read_u32(node, "dma-channels", &value); | |
1393 | + if (ret < 0) | |
1394 | + return ret; | |
1395 | + pdata->n_channel = value; | |
1396 | + | |
1397 | + ret = of_property_read_u32(node, "ti,edma-regions", &value); | |
1398 | + if (ret < 0) | |
1399 | + return ret; | |
1400 | + pdata->n_region = value; | |
1401 | + | |
1402 | + ret = of_property_read_u32(node, "ti,edma-slots", &value); | |
1403 | + if (ret < 0) | |
1404 | + return ret; | |
1405 | + pdata->n_slot = value; | |
1406 | + | |
1407 | + pdata->n_cc = 1; | |
1408 | + | |
1409 | + rsv_info = devm_kzalloc(dev, sizeof(struct edma_rsv_info), GFP_KERNEL); | |
1410 | + if (!rsv_info) | |
1411 | + return -ENOMEM; | |
1412 | + pdata->rsv = rsv_info; | |
1413 | + | |
1414 | + queue_tc_map = devm_kzalloc(dev, 8*sizeof(s8), GFP_KERNEL); | |
1415 | + if (!queue_tc_map) | |
1416 | + return -ENOMEM; | |
1417 | + | |
1418 | + for (i = 0; i < 3; i++) { | |
1419 | + queue_tc_map[i][0] = i; | |
1420 | + queue_tc_map[i][1] = i; | |
1421 | + } | |
1422 | + queue_tc_map[i][0] = -1; | |
1423 | + queue_tc_map[i][1] = -1; | |
1424 | + | |
1425 | + pdata->queue_tc_mapping = queue_tc_map; | |
1426 | + | |
1427 | + queue_priority_map = devm_kzalloc(dev, 8*sizeof(s8), GFP_KERNEL); | |
1428 | + if (!queue_priority_map) | |
1429 | + return -ENOMEM; | |
1430 | + | |
1431 | + for (i = 0; i < 3; i++) { | |
1432 | + queue_priority_map[i][0] = i; | |
1433 | + queue_priority_map[i][1] = i; | |
1434 | + } | |
1435 | + queue_priority_map[i][0] = -1; | |
1436 | + queue_priority_map[i][1] = -1; | |
1437 | + | |
1438 | + pdata->queue_priority_mapping = queue_priority_map; | |
1439 | + | |
1440 | + pdata->default_queue = 0; | |
1441 | + | |
1442 | + return ret; | |
1443 | +} | |
1444 | + | |
1445 | +static struct of_dma_filter_info edma_filter_info = { | |
1446 | + .filter_fn = edma_filter_fn, | |
1447 | +}; | |
1448 | + | |
1449 | +static struct edma_soc_info *edma_setup_info_from_dt(struct device *dev, | |
1450 | + struct device_node *node) | |
1451 | +{ | |
1452 | + struct edma_soc_info *info; | |
1453 | + int ret; | |
1454 | + | |
1455 | + info = devm_kzalloc(dev, sizeof(struct edma_soc_info), GFP_KERNEL); | |
1456 | + if (!info) | |
1457 | + return ERR_PTR(-ENOMEM); | |
1458 | + | |
1459 | + ret = edma_of_parse_dt(dev, node, info); | |
1460 | + if (ret) | |
1461 | + return ERR_PTR(ret); | |
1462 | + | |
1463 | + dma_cap_set(DMA_SLAVE, edma_filter_info.dma_cap); | |
1464 | + of_dma_controller_register(dev->of_node, of_dma_simple_xlate, | |
1465 | + &edma_filter_info); | |
1466 | + | |
1467 | + return info; | |
1468 | +} | |
1469 | +#else | |
1470 | +static struct edma_soc_info *edma_setup_info_from_dt(struct device *dev, | |
1471 | + struct device_node *node) | |
1472 | +{ | |
1473 | + return ERR_PTR(-ENOSYS); | |
1474 | +} | |
1475 | +#endif | |
1476 | + | |
1477 | +static int edma_probe(struct platform_device *pdev) | |
1478 | +{ | |
1376 | 1479 | struct edma_soc_info **info = pdev->dev.platform_data; |
1377 | - const s8 (*queue_priority_mapping)[2]; | |
1378 | - const s8 (*queue_tc_mapping)[2]; | |
1480 | + struct edma_soc_info *ninfo[EDMA_MAX_CC] = {NULL}; | |
1481 | + s8 (*queue_priority_mapping)[2]; | |
1482 | + s8 (*queue_tc_mapping)[2]; | |
1379 | 1483 | int i, j, off, ln, found = 0; |
1380 | 1484 | int status = -1; |
1381 | 1485 | const s16 (*rsv_chans)[2]; |
1382 | 1486 | |
1383 | 1487 | |
1384 | 1488 | |
1385 | 1489 | |
1386 | 1490 | |
... | ... | @@ -1383,17 +1487,56 @@ |
1383 | 1487 | int irq[EDMA_MAX_CC] = {0, 0}; |
1384 | 1488 | int err_irq[EDMA_MAX_CC] = {0, 0}; |
1385 | 1489 | struct resource *r[EDMA_MAX_CC] = {NULL}; |
1490 | + struct resource res[EDMA_MAX_CC]; | |
1386 | 1491 | char res_name[10]; |
1387 | 1492 | char irq_name[10]; |
1493 | + struct device_node *node = pdev->dev.of_node; | |
1494 | + struct device *dev = &pdev->dev; | |
1495 | + int ret; | |
1388 | 1496 | |
1497 | + if (node) { | |
1498 | + /* Check if this is a second instance registered */ | |
1499 | + if (arch_num_cc) { | |
1500 | + dev_err(dev, "only one EDMA instance is supported via DT\n"); | |
1501 | + return -ENODEV; | |
1502 | + } | |
1503 | + | |
1504 | + ninfo[0] = edma_setup_info_from_dt(dev, node); | |
1505 | + if (IS_ERR(ninfo[0])) { | |
1506 | + dev_err(dev, "failed to get DT data\n"); | |
1507 | + return PTR_ERR(ninfo[0]); | |
1508 | + } | |
1509 | + | |
1510 | + info = ninfo; | |
1511 | + } | |
1512 | + | |
1389 | 1513 | if (!info) |
1390 | 1514 | return -ENODEV; |
1391 | 1515 | |
1516 | + pm_runtime_enable(dev); | |
1517 | + ret = pm_runtime_get_sync(dev); | |
1518 | + if (ret < 0) { | |
1519 | + dev_err(dev, "pm_runtime_get_sync() failed\n"); | |
1520 | + return ret; | |
1521 | + } | |
1522 | + | |
1392 | 1523 | for (j = 0; j < EDMA_MAX_CC; j++) { |
1393 | - sprintf(res_name, "edma_cc%d", j); | |
1394 | - r[j] = platform_get_resource_byname(pdev, IORESOURCE_MEM, | |
1524 | + if (!info[j]) { | |
1525 | + if (!found) | |
1526 | + return -ENODEV; | |
1527 | + break; | |
1528 | + } | |
1529 | + if (node) { | |
1530 | + ret = of_address_to_resource(node, j, &res[j]); | |
1531 | + if (!ret) | |
1532 | + r[j] = &res[j]; | |
1533 | + } else { | |
1534 | + sprintf(res_name, "edma_cc%d", j); | |
1535 | + r[j] = platform_get_resource_byname(pdev, | |
1536 | + IORESOURCE_MEM, | |
1395 | 1537 | res_name); |
1396 | - if (!r[j] || !info[j]) { | |
1538 | + } | |
1539 | + if (!r[j]) { | |
1397 | 1540 | if (found) |
1398 | 1541 | break; |
1399 | 1542 | else |
... | ... | @@ -1440,7 +1583,7 @@ |
1440 | 1583 | off = rsv_chans[i][0]; |
1441 | 1584 | ln = rsv_chans[i][1]; |
1442 | 1585 | clear_bits(off, ln, |
1443 | - edma_cc[j]->edma_unused); | |
1586 | + edma_cc[j]->edma_unused); | |
1444 | 1587 | } |
1445 | 1588 | } |
1446 | 1589 | |
... | ... | @@ -1456,8 +1599,13 @@ |
1456 | 1599 | } |
1457 | 1600 | } |
1458 | 1601 | |
1459 | - sprintf(irq_name, "edma%d", j); | |
1460 | - irq[j] = platform_get_irq_byname(pdev, irq_name); | |
1602 | + | |
1603 | + if (node) { | |
1604 | + irq[j] = irq_of_parse_and_map(node, 0); | |
1605 | + } else { | |
1606 | + sprintf(irq_name, "edma%d", j); | |
1607 | + irq[j] = platform_get_irq_byname(pdev, irq_name); | |
1608 | + } | |
1461 | 1609 | edma_cc[j]->irq_res_start = irq[j]; |
1462 | 1610 | status = devm_request_irq(&pdev->dev, irq[j], |
1463 | 1611 | dma_irq_handler, 0, "edma", |
... | ... | @@ -1469,8 +1617,12 @@ |
1469 | 1617 | return status; |
1470 | 1618 | } |
1471 | 1619 | |
1472 | - sprintf(irq_name, "edma%d_err", j); | |
1473 | - err_irq[j] = platform_get_irq_byname(pdev, irq_name); | |
1620 | + if (node) { | |
1621 | + err_irq[j] = irq_of_parse_and_map(node, 2); | |
1622 | + } else { | |
1623 | + sprintf(irq_name, "edma%d_err", j); | |
1624 | + err_irq[j] = platform_get_irq_byname(pdev, irq_name); | |
1625 | + } | |
1474 | 1626 | edma_cc[j]->irq_res_end = err_irq[j]; |
1475 | 1627 | status = devm_request_irq(&pdev->dev, err_irq[j], |
1476 | 1628 | dma_ccerr_handler, 0, |
1477 | 1629 | |
... | ... | @@ -1516,9 +1668,17 @@ |
1516 | 1668 | return 0; |
1517 | 1669 | } |
1518 | 1670 | |
1671 | +static const struct of_device_id edma_of_ids[] = { | |
1672 | + { .compatible = "ti,edma3", }, | |
1673 | + {} | |
1674 | +}; | |
1519 | 1675 | |
1520 | 1676 | static struct platform_driver edma_driver = { |
1521 | - .driver.name = "edma", | |
1677 | + .driver = { | |
1678 | + .name = "edma", | |
1679 | + .of_match_table = edma_of_ids, | |
1680 | + }, | |
1681 | + .probe = edma_probe, | |
1522 | 1682 | }; |
1523 | 1683 | |
1524 | 1684 | static int __init edma_init(void) |
arch/arm/mach-davinci/devices-da8xx.c
... | ... | @@ -105,27 +105,27 @@ |
105 | 105 | }, |
106 | 106 | }; |
107 | 107 | |
108 | -static const s8 da8xx_queue_tc_mapping[][2] = { | |
108 | +static s8 da8xx_queue_tc_mapping[][2] = { | |
109 | 109 | /* {event queue no, TC no} */ |
110 | 110 | {0, 0}, |
111 | 111 | {1, 1}, |
112 | 112 | {-1, -1} |
113 | 113 | }; |
114 | 114 | |
115 | -static const s8 da8xx_queue_priority_mapping[][2] = { | |
115 | +static s8 da8xx_queue_priority_mapping[][2] = { | |
116 | 116 | /* {event queue no, Priority} */ |
117 | 117 | {0, 3}, |
118 | 118 | {1, 7}, |
119 | 119 | {-1, -1} |
120 | 120 | }; |
121 | 121 | |
122 | -static const s8 da850_queue_tc_mapping[][2] = { | |
122 | +static s8 da850_queue_tc_mapping[][2] = { | |
123 | 123 | /* {event queue no, TC no} */ |
124 | 124 | {0, 0}, |
125 | 125 | {-1, -1} |
126 | 126 | }; |
127 | 127 | |
128 | -static const s8 da850_queue_priority_mapping[][2] = { | |
128 | +static s8 da850_queue_priority_mapping[][2] = { | |
129 | 129 | /* {event queue no, Priority} */ |
130 | 130 | {0, 3}, |
131 | 131 | {-1, -1} |
arch/arm/mach-davinci/devices-tnetv107x.c
... | ... | @@ -58,14 +58,14 @@ |
58 | 58 | #define TNETV107X_DMACH_SDIO1_RX 28 |
59 | 59 | #define TNETV107X_DMACH_SDIO1_TX 29 |
60 | 60 | |
61 | -static const s8 edma_tc_mapping[][2] = { | |
61 | +static s8 edma_tc_mapping[][2] = { | |
62 | 62 | /* event queue no TC no */ |
63 | 63 | { 0, 0 }, |
64 | 64 | { 1, 1 }, |
65 | 65 | { -1, -1 } |
66 | 66 | }; |
67 | 67 | |
68 | -static const s8 edma_priority_mapping[][2] = { | |
68 | +static s8 edma_priority_mapping[][2] = { | |
69 | 69 | /* event queue no Prio */ |
70 | 70 | { 0, 3 }, |
71 | 71 | { 1, 7 }, |
arch/arm/mach-davinci/dm355.c
... | ... | @@ -569,7 +569,7 @@ |
569 | 569 | |
570 | 570 | /*----------------------------------------------------------------------*/ |
571 | 571 | |
572 | -static const s8 | |
572 | +static s8 | |
573 | 573 | queue_tc_mapping[][2] = { |
574 | 574 | /* {event queue no, TC no} */ |
575 | 575 | {0, 0}, |
... | ... | @@ -577,7 +577,7 @@ |
577 | 577 | {-1, -1}, |
578 | 578 | }; |
579 | 579 | |
580 | -static const s8 | |
580 | +static s8 | |
581 | 581 | queue_priority_mapping[][2] = { |
582 | 582 | /* {event queue no, Priority} */ |
583 | 583 | {0, 3}, |
arch/arm/mach-davinci/dm365.c
... | ... | @@ -826,7 +826,7 @@ |
826 | 826 | }; |
827 | 827 | |
828 | 828 | /* Four Transfer Controllers on DM365 */ |
829 | -static const s8 | |
829 | +static s8 | |
830 | 830 | dm365_queue_tc_mapping[][2] = { |
831 | 831 | /* {event queue no, TC no} */ |
832 | 832 | {0, 0}, |
... | ... | @@ -836,7 +836,7 @@ |
836 | 836 | {-1, -1}, |
837 | 837 | }; |
838 | 838 | |
839 | -static const s8 | |
839 | +static s8 | |
840 | 840 | dm365_queue_priority_mapping[][2] = { |
841 | 841 | /* {event queue no, Priority} */ |
842 | 842 | {0, 7}, |
arch/arm/mach-davinci/dm644x.c
... | ... | @@ -497,7 +497,7 @@ |
497 | 497 | |
498 | 498 | /*----------------------------------------------------------------------*/ |
499 | 499 | |
500 | -static const s8 | |
500 | +static s8 | |
501 | 501 | queue_tc_mapping[][2] = { |
502 | 502 | /* {event queue no, TC no} */ |
503 | 503 | {0, 0}, |
... | ... | @@ -505,7 +505,7 @@ |
505 | 505 | {-1, -1}, |
506 | 506 | }; |
507 | 507 | |
508 | -static const s8 | |
508 | +static s8 | |
509 | 509 | queue_priority_mapping[][2] = { |
510 | 510 | /* {event queue no, Priority} */ |
511 | 511 | {0, 3}, |
arch/arm/mach-davinci/dm646x.c
... | ... | @@ -531,7 +531,7 @@ |
531 | 531 | /*----------------------------------------------------------------------*/ |
532 | 532 | |
533 | 533 | /* Four Transfer Controllers on DM646x */ |
534 | -static const s8 | |
534 | +static s8 | |
535 | 535 | dm646x_queue_tc_mapping[][2] = { |
536 | 536 | /* {event queue no, TC no} */ |
537 | 537 | {0, 0}, |
... | ... | @@ -541,7 +541,7 @@ |
541 | 541 | {-1, -1}, |
542 | 542 | }; |
543 | 543 | |
544 | -static const s8 | |
544 | +static s8 | |
545 | 545 | dm646x_queue_priority_mapping[][2] = { |
546 | 546 | /* {event queue no, Priority} */ |
547 | 547 | {0, 4}, |
include/linux/platform_data/edma.h
... | ... | @@ -175,8 +175,8 @@ |
175 | 175 | /* Resource reservation for other cores */ |
176 | 176 | struct edma_rsv_info *rsv; |
177 | 177 | |
178 | - const s8 (*queue_tc_mapping)[2]; | |
179 | - const s8 (*queue_priority_mapping)[2]; | |
178 | + s8 (*queue_tc_mapping)[2]; | |
179 | + s8 (*queue_priority_mapping)[2]; | |
180 | 180 | }; |
181 | 181 | |
182 | 182 | #endif |