Commit 2646a0e52b65a5ea3d108794611f95df1a6cb409
Committed by
Sekhar Nori
1 parent
6cba435506
Exists in
smarc-imx_3.14.28_1.0.0_ga
and in
1 other branch
ARM: edma: Add EDMA crossbar event mux support
EDMA supports a cross bar which provides ability to mux additional events into physical channels present in the channel controller. This is required when the number of events present in the system are more than number of available physical channels. Changes by Joel: * Split EDMA xbar support out of original EDMA DT parsing patch to keep it easier for review. * Rewrite shift and offset calculation. Suggested-by: Sekhar Nori <nsekhar@ti.com> Suggested by: Andy Shevchenko <andy.shevchenko@gmail.com> Signed-off-by: Joel A Fernandes <joelagnel@ti.com> Acked-by: Arnd Bergmann <arnd@arndb.de> [nsekhar@ti.com: fix checkpatch errors and a minor coding improvement] Signed-off-by: Sekhar Nori <nsekhar@ti.com>
Showing 2 changed files with 79 additions and 0 deletions Side-by-side Diff
arch/arm/common/edma.c
... | ... | @@ -1378,12 +1378,76 @@ |
1378 | 1378 | |
1379 | 1379 | #if IS_ENABLED(CONFIG_OF) && IS_ENABLED(CONFIG_DMADEVICES) |
1380 | 1380 | |
1381 | +static int edma_of_read_u32_to_s16_array(const struct device_node *np, | |
1382 | + const char *propname, s16 *out_values, | |
1383 | + size_t sz) | |
1384 | +{ | |
1385 | + int ret; | |
1386 | + | |
1387 | + ret = of_property_read_u16_array(np, propname, out_values, sz); | |
1388 | + if (ret) | |
1389 | + return ret; | |
1390 | + | |
1391 | + /* Terminate it */ | |
1392 | + *out_values++ = -1; | |
1393 | + *out_values++ = -1; | |
1394 | + | |
1395 | + return 0; | |
1396 | +} | |
1397 | + | |
1398 | +static int edma_xbar_event_map(struct device *dev, | |
1399 | + struct device_node *node, | |
1400 | + struct edma_soc_info *pdata, int len) | |
1401 | +{ | |
1402 | + int ret, i; | |
1403 | + struct resource res; | |
1404 | + void __iomem *xbar; | |
1405 | + const s16 (*xbar_chans)[2]; | |
1406 | + u32 shift, offset, mux; | |
1407 | + | |
1408 | + xbar_chans = devm_kzalloc(dev, | |
1409 | + len/sizeof(s16) + 2*sizeof(s16), | |
1410 | + GFP_KERNEL); | |
1411 | + if (!xbar_chans) | |
1412 | + return -ENOMEM; | |
1413 | + | |
1414 | + ret = of_address_to_resource(node, 1, &res); | |
1415 | + if (ret) | |
1416 | + return -EIO; | |
1417 | + | |
1418 | + xbar = devm_ioremap(dev, res.start, resource_size(&res)); | |
1419 | + if (!xbar) | |
1420 | + return -ENOMEM; | |
1421 | + | |
1422 | + ret = edma_of_read_u32_to_s16_array(node, | |
1423 | + "ti,edma-xbar-event-map", | |
1424 | + (s16 *)xbar_chans, | |
1425 | + len/sizeof(u32)); | |
1426 | + if (ret) | |
1427 | + return -EIO; | |
1428 | + | |
1429 | + for (i = 0; xbar_chans[i][0] != -1; i++) { | |
1430 | + shift = (xbar_chans[i][1] & 0x03) << 3; | |
1431 | + offset = xbar_chans[i][1] & 0xfffffffc; | |
1432 | + mux = readl(xbar + offset); | |
1433 | + mux &= ~(0xff << shift); | |
1434 | + mux |= xbar_chans[i][0] << shift; | |
1435 | + writel(mux, (xbar + offset)); | |
1436 | + } | |
1437 | + | |
1438 | + pdata->xbar_chans = xbar_chans; | |
1439 | + | |
1440 | + return 0; | |
1441 | +} | |
1442 | + | |
1381 | 1443 | static int edma_of_parse_dt(struct device *dev, |
1382 | 1444 | struct device_node *node, |
1383 | 1445 | struct edma_soc_info *pdata) |
1384 | 1446 | { |
1385 | 1447 | int ret = 0, i; |
1386 | 1448 | u32 value; |
1449 | + struct property *prop; | |
1450 | + size_t sz; | |
1387 | 1451 | struct edma_rsv_info *rsv_info; |
1388 | 1452 | s8 (*queue_tc_map)[2], (*queue_priority_map)[2]; |
1389 | 1453 | |
... | ... | @@ -1439,6 +1503,10 @@ |
1439 | 1503 | |
1440 | 1504 | pdata->default_queue = 0; |
1441 | 1505 | |
1506 | + prop = of_find_property(node, "ti,edma-xbar-event-map", &sz); | |
1507 | + if (prop) | |
1508 | + ret = edma_xbar_event_map(dev, node, pdata, sz); | |
1509 | + | |
1442 | 1510 | return ret; |
1443 | 1511 | } |
1444 | 1512 | |
... | ... | @@ -1484,6 +1552,7 @@ |
1484 | 1552 | int status = -1; |
1485 | 1553 | const s16 (*rsv_chans)[2]; |
1486 | 1554 | const s16 (*rsv_slots)[2]; |
1555 | + const s16 (*xbar_chans)[2]; | |
1487 | 1556 | int irq[EDMA_MAX_CC] = {0, 0}; |
1488 | 1557 | int err_irq[EDMA_MAX_CC] = {0, 0}; |
1489 | 1558 | struct resource *r[EDMA_MAX_CC] = {NULL}; |
... | ... | @@ -1599,6 +1668,15 @@ |
1599 | 1668 | } |
1600 | 1669 | } |
1601 | 1670 | |
1671 | + /* Clear the xbar mapped channels in unused list */ | |
1672 | + xbar_chans = info[j]->xbar_chans; | |
1673 | + if (xbar_chans) { | |
1674 | + for (i = 0; xbar_chans[i][1] != -1; i++) { | |
1675 | + off = xbar_chans[i][1]; | |
1676 | + clear_bits(off, 1, | |
1677 | + edma_cc[j]->edma_unused); | |
1678 | + } | |
1679 | + } | |
1602 | 1680 | |
1603 | 1681 | if (node) { |
1604 | 1682 | irq[j] = irq_of_parse_and_map(node, 0); |