diff options
Diffstat (limited to 'arch/arm/common')
-rw-r--r-- | arch/arm/common/edma.c | 186 |
1 files changed, 173 insertions, 13 deletions
diff --git a/arch/arm/common/edma.c b/arch/arm/common/edma.c index 7658874cc3d5..5183a310657c 100644 --- a/arch/arm/common/edma.c +++ b/arch/arm/common/edma.c | |||
@@ -25,6 +25,13 @@ | |||
25 | #include <linux/platform_device.h> | 25 | #include <linux/platform_device.h> |
26 | #include <linux/io.h> | 26 | #include <linux/io.h> |
27 | #include <linux/slab.h> | 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 | #include <linux/platform_data/edma.h> | 36 | #include <linux/platform_data/edma.h> |
30 | 37 | ||
@@ -1369,13 +1376,110 @@ void edma_clear_event(unsigned channel) | |||
1369 | } | 1376 | } |
1370 | EXPORT_SYMBOL(edma_clear_event); | 1377 | EXPORT_SYMBOL(edma_clear_event); |
1371 | 1378 | ||
1372 | /*-----------------------------------------------------------------------*/ | 1379 | #if IS_ENABLED(CONFIG_OF) && IS_ENABLED(CONFIG_DMADEVICES) |
1380 | |||
1381 | static int edma_of_parse_dt(struct device *dev, | ||
1382 | struct device_node *node, | ||
1383 | struct edma_soc_info *pdata) | ||
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; | ||
1373 | 1441 | ||
1374 | static int __init edma_probe(struct platform_device *pdev) | 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) | ||
1375 | { | 1478 | { |
1376 | struct edma_soc_info **info = pdev->dev.platform_data; | 1479 | struct edma_soc_info **info = pdev->dev.platform_data; |
1377 | const s8 (*queue_priority_mapping)[2]; | 1480 | struct edma_soc_info *ninfo[EDMA_MAX_CC] = {NULL}; |
1378 | const s8 (*queue_tc_mapping)[2]; | 1481 | s8 (*queue_priority_mapping)[2]; |
1482 | s8 (*queue_tc_mapping)[2]; | ||
1379 | int i, j, off, ln, found = 0; | 1483 | int i, j, off, ln, found = 0; |
1380 | int status = -1; | 1484 | int status = -1; |
1381 | const s16 (*rsv_chans)[2]; | 1485 | const s16 (*rsv_chans)[2]; |
@@ -1383,17 +1487,56 @@ static int __init edma_probe(struct platform_device *pdev) | |||
1383 | int irq[EDMA_MAX_CC] = {0, 0}; | 1487 | int irq[EDMA_MAX_CC] = {0, 0}; |
1384 | int err_irq[EDMA_MAX_CC] = {0, 0}; | 1488 | int err_irq[EDMA_MAX_CC] = {0, 0}; |
1385 | struct resource *r[EDMA_MAX_CC] = {NULL}; | 1489 | struct resource *r[EDMA_MAX_CC] = {NULL}; |
1490 | struct resource res[EDMA_MAX_CC]; | ||
1386 | char res_name[10]; | 1491 | char res_name[10]; |
1387 | char irq_name[10]; | 1492 | char irq_name[10]; |
1493 | struct device_node *node = pdev->dev.of_node; | ||
1494 | struct device *dev = &pdev->dev; | ||
1495 | int ret; | ||
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 | } | ||
1388 | 1512 | ||
1389 | if (!info) | 1513 | if (!info) |
1390 | return -ENODEV; | 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 | for (j = 0; j < EDMA_MAX_CC; j++) { | 1523 | for (j = 0; j < EDMA_MAX_CC; j++) { |
1393 | sprintf(res_name, "edma_cc%d", j); | 1524 | if (!info[j]) { |
1394 | r[j] = platform_get_resource_byname(pdev, IORESOURCE_MEM, | 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 | res_name); | 1537 | res_name); |
1396 | if (!r[j] || !info[j]) { | 1538 | } |
1539 | if (!r[j]) { | ||
1397 | if (found) | 1540 | if (found) |
1398 | break; | 1541 | break; |
1399 | else | 1542 | else |
@@ -1440,7 +1583,7 @@ static int __init edma_probe(struct platform_device *pdev) | |||
1440 | off = rsv_chans[i][0]; | 1583 | off = rsv_chans[i][0]; |
1441 | ln = rsv_chans[i][1]; | 1584 | ln = rsv_chans[i][1]; |
1442 | clear_bits(off, ln, | 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 @@ static int __init edma_probe(struct platform_device *pdev) | |||
1456 | } | 1599 | } |
1457 | } | 1600 | } |
1458 | 1601 | ||
1459 | sprintf(irq_name, "edma%d", j); | 1602 | |
1460 | irq[j] = platform_get_irq_byname(pdev, irq_name); | 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 | edma_cc[j]->irq_res_start = irq[j]; | 1609 | edma_cc[j]->irq_res_start = irq[j]; |
1462 | status = devm_request_irq(&pdev->dev, irq[j], | 1610 | status = devm_request_irq(&pdev->dev, irq[j], |
1463 | dma_irq_handler, 0, "edma", | 1611 | dma_irq_handler, 0, "edma", |
@@ -1469,8 +1617,12 @@ static int __init edma_probe(struct platform_device *pdev) | |||
1469 | return status; | 1617 | return status; |
1470 | } | 1618 | } |
1471 | 1619 | ||
1472 | sprintf(irq_name, "edma%d_err", j); | 1620 | if (node) { |
1473 | err_irq[j] = platform_get_irq_byname(pdev, irq_name); | 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 | edma_cc[j]->irq_res_end = err_irq[j]; | 1626 | edma_cc[j]->irq_res_end = err_irq[j]; |
1475 | status = devm_request_irq(&pdev->dev, err_irq[j], | 1627 | status = devm_request_irq(&pdev->dev, err_irq[j], |
1476 | dma_ccerr_handler, 0, | 1628 | dma_ccerr_handler, 0, |
@@ -1516,9 +1668,17 @@ static int __init edma_probe(struct platform_device *pdev) | |||
1516 | return 0; | 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 | static struct platform_driver edma_driver = { | 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 | static int __init edma_init(void) | 1684 | static int __init edma_init(void) |