Commit 2646a0e52b65a5ea3d108794611f95df1a6cb409

Authored by Matt Porter
Committed by Sekhar Nori
1 parent 6cba435506

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);
include/linux/platform_data/edma.h
... ... @@ -177,6 +177,7 @@
177 177  
178 178 s8 (*queue_tc_mapping)[2];
179 179 s8 (*queue_priority_mapping)[2];
  180 + const s16 (*xbar_chans)[2];
180 181 };
181 182  
182 183 #endif