diff options
-rw-r--r-- | Documentation/devicetree/bindings/dma/snps-dma.txt | 44 | ||||
-rw-r--r-- | drivers/dma/dw_dmac.c | 134 | ||||
-rw-r--r-- | drivers/dma/dw_dmac_regs.h | 4 | ||||
-rw-r--r-- | include/linux/dw_dmac.h | 43 |
4 files changed, 208 insertions, 17 deletions
diff --git a/Documentation/devicetree/bindings/dma/snps-dma.txt b/Documentation/devicetree/bindings/dma/snps-dma.txt index c0d85dbcada5..5bb3dfb6f1d8 100644 --- a/Documentation/devicetree/bindings/dma/snps-dma.txt +++ b/Documentation/devicetree/bindings/dma/snps-dma.txt | |||
@@ -6,6 +6,26 @@ Required properties: | |||
6 | - interrupt-parent: Should be the phandle for the interrupt controller | 6 | - interrupt-parent: Should be the phandle for the interrupt controller |
7 | that services interrupts for this device | 7 | that services interrupts for this device |
8 | - interrupt: Should contain the DMAC interrupt number | 8 | - interrupt: Should contain the DMAC interrupt number |
9 | - nr_channels: Number of channels supported by hardware | ||
10 | - is_private: The device channels should be marked as private and not for by the | ||
11 | general purpose DMA channel allocator. False if not passed. | ||
12 | - chan_allocation_order: order of allocation of channel, 0 (default): ascending, | ||
13 | 1: descending | ||
14 | - chan_priority: priority of channels. 0 (default): increase from chan 0->n, 1: | ||
15 | increase from chan n->0 | ||
16 | - block_size: Maximum block size supported by the controller | ||
17 | - nr_masters: Number of AHB masters supported by the controller | ||
18 | - data_width: Maximum data width supported by hardware per AHB master | ||
19 | (0 - 8bits, 1 - 16bits, ..., 5 - 256bits) | ||
20 | - slave_info: | ||
21 | - bus_id: name of this device channel, not just a device name since | ||
22 | devices may have more than one channel e.g. "foo_tx". For using the | ||
23 | dw_generic_filter(), slave drivers must pass exactly this string as | ||
24 | param to filter function. | ||
25 | - cfg_hi: Platform-specific initializer for the CFG_HI register | ||
26 | - cfg_lo: Platform-specific initializer for the CFG_LO register | ||
27 | - src_master: src master for transfers on allocated channel. | ||
28 | - dst_master: dest master for transfers on allocated channel. | ||
9 | 29 | ||
10 | Example: | 30 | Example: |
11 | 31 | ||
@@ -14,4 +34,28 @@ Example: | |||
14 | reg = <0xfc000000 0x1000>; | 34 | reg = <0xfc000000 0x1000>; |
15 | interrupt-parent = <&vic1>; | 35 | interrupt-parent = <&vic1>; |
16 | interrupts = <12>; | 36 | interrupts = <12>; |
37 | |||
38 | nr_channels = <8>; | ||
39 | chan_allocation_order = <1>; | ||
40 | chan_priority = <1>; | ||
41 | block_size = <0xfff>; | ||
42 | nr_masters = <2>; | ||
43 | data_width = <3 3 0 0>; | ||
44 | |||
45 | slave_info { | ||
46 | uart0-tx { | ||
47 | bus_id = "uart0-tx"; | ||
48 | cfg_hi = <0x4000>; /* 0x8 << 11 */ | ||
49 | cfg_lo = <0>; | ||
50 | src_master = <0>; | ||
51 | dst_master = <1>; | ||
52 | }; | ||
53 | spi0-tx { | ||
54 | bus_id = "spi0-tx"; | ||
55 | cfg_hi = <0x2000>; /* 0x4 << 11 */ | ||
56 | cfg_lo = <0>; | ||
57 | src_master = <0>; | ||
58 | dst_master = <0>; | ||
59 | }; | ||
60 | }; | ||
17 | }; | 61 | }; |
diff --git a/drivers/dma/dw_dmac.c b/drivers/dma/dw_dmac.c index 8f0b111af4de..27b8e1d1845e 100644 --- a/drivers/dma/dw_dmac.c +++ b/drivers/dma/dw_dmac.c | |||
@@ -1179,6 +1179,50 @@ static void dwc_free_chan_resources(struct dma_chan *chan) | |||
1179 | dev_vdbg(chan2dev(chan), "%s: done\n", __func__); | 1179 | dev_vdbg(chan2dev(chan), "%s: done\n", __func__); |
1180 | } | 1180 | } |
1181 | 1181 | ||
1182 | bool dw_dma_generic_filter(struct dma_chan *chan, void *param) | ||
1183 | { | ||
1184 | struct dw_dma *dw = to_dw_dma(chan->device); | ||
1185 | static struct dw_dma *last_dw; | ||
1186 | static char *last_bus_id; | ||
1187 | int i = -1; | ||
1188 | |||
1189 | /* | ||
1190 | * dmaengine framework calls this routine for all channels of all dma | ||
1191 | * controller, until true is returned. If 'param' bus_id is not | ||
1192 | * registered with a dma controller (dw), then there is no need of | ||
1193 | * running below function for all channels of dw. | ||
1194 | * | ||
1195 | * This block of code does this by saving the parameters of last | ||
1196 | * failure. If dw and param are same, i.e. trying on same dw with | ||
1197 | * different channel, return false. | ||
1198 | */ | ||
1199 | if ((last_dw == dw) && (last_bus_id == param)) | ||
1200 | return false; | ||
1201 | /* | ||
1202 | * Return true: | ||
1203 | * - If dw_dma's platform data is not filled with slave info, then all | ||
1204 | * dma controllers are fine for transfer. | ||
1205 | * - Or if param is NULL | ||
1206 | */ | ||
1207 | if (!dw->sd || !param) | ||
1208 | return true; | ||
1209 | |||
1210 | while (++i < dw->sd_count) { | ||
1211 | if (!strcmp(dw->sd[i].bus_id, param)) { | ||
1212 | chan->private = &dw->sd[i]; | ||
1213 | last_dw = NULL; | ||
1214 | last_bus_id = NULL; | ||
1215 | |||
1216 | return true; | ||
1217 | } | ||
1218 | } | ||
1219 | |||
1220 | last_dw = dw; | ||
1221 | last_bus_id = param; | ||
1222 | return false; | ||
1223 | } | ||
1224 | EXPORT_SYMBOL(dw_dma_generic_filter); | ||
1225 | |||
1182 | /* --------------------- Cyclic DMA API extensions -------------------- */ | 1226 | /* --------------------- Cyclic DMA API extensions -------------------- */ |
1183 | 1227 | ||
1184 | /** | 1228 | /** |
@@ -1462,6 +1506,91 @@ static void dw_dma_off(struct dw_dma *dw) | |||
1462 | dw->chan[i].initialized = false; | 1506 | dw->chan[i].initialized = false; |
1463 | } | 1507 | } |
1464 | 1508 | ||
1509 | #ifdef CONFIG_OF | ||
1510 | static struct dw_dma_platform_data * | ||
1511 | dw_dma_parse_dt(struct platform_device *pdev) | ||
1512 | { | ||
1513 | struct device_node *sn, *cn, *np = pdev->dev.of_node; | ||
1514 | struct dw_dma_platform_data *pdata; | ||
1515 | struct dw_dma_slave *sd; | ||
1516 | u32 tmp, arr[4]; | ||
1517 | |||
1518 | if (!np) { | ||
1519 | dev_err(&pdev->dev, "Missing DT data\n"); | ||
1520 | return NULL; | ||
1521 | } | ||
1522 | |||
1523 | pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); | ||
1524 | if (!pdata) | ||
1525 | return NULL; | ||
1526 | |||
1527 | if (of_property_read_u32(np, "nr_channels", &pdata->nr_channels)) | ||
1528 | return NULL; | ||
1529 | |||
1530 | if (of_property_read_bool(np, "is_private")) | ||
1531 | pdata->is_private = true; | ||
1532 | |||
1533 | if (!of_property_read_u32(np, "chan_allocation_order", &tmp)) | ||
1534 | pdata->chan_allocation_order = (unsigned char)tmp; | ||
1535 | |||
1536 | if (!of_property_read_u32(np, "chan_priority", &tmp)) | ||
1537 | pdata->chan_priority = tmp; | ||
1538 | |||
1539 | if (!of_property_read_u32(np, "block_size", &tmp)) | ||
1540 | pdata->block_size = tmp; | ||
1541 | |||
1542 | if (!of_property_read_u32(np, "nr_masters", &tmp)) { | ||
1543 | if (tmp > 4) | ||
1544 | return NULL; | ||
1545 | |||
1546 | pdata->nr_masters = tmp; | ||
1547 | } | ||
1548 | |||
1549 | if (!of_property_read_u32_array(np, "data_width", arr, | ||
1550 | pdata->nr_masters)) | ||
1551 | for (tmp = 0; tmp < pdata->nr_masters; tmp++) | ||
1552 | pdata->data_width[tmp] = arr[tmp]; | ||
1553 | |||
1554 | /* parse slave data */ | ||
1555 | sn = of_find_node_by_name(np, "slave_info"); | ||
1556 | if (!sn) | ||
1557 | return pdata; | ||
1558 | |||
1559 | /* calculate number of slaves */ | ||
1560 | tmp = of_get_child_count(sn); | ||
1561 | if (!tmp) | ||
1562 | return NULL; | ||
1563 | |||
1564 | sd = devm_kzalloc(&pdev->dev, sizeof(*sd) * tmp, GFP_KERNEL); | ||
1565 | if (!sd) | ||
1566 | return NULL; | ||
1567 | |||
1568 | pdata->sd = sd; | ||
1569 | pdata->sd_count = tmp; | ||
1570 | |||
1571 | for_each_child_of_node(sn, cn) { | ||
1572 | sd->dma_dev = &pdev->dev; | ||
1573 | of_property_read_string(cn, "bus_id", &sd->bus_id); | ||
1574 | of_property_read_u32(cn, "cfg_hi", &sd->cfg_hi); | ||
1575 | of_property_read_u32(cn, "cfg_lo", &sd->cfg_lo); | ||
1576 | if (!of_property_read_u32(cn, "src_master", &tmp)) | ||
1577 | sd->src_master = tmp; | ||
1578 | |||
1579 | if (!of_property_read_u32(cn, "dst_master", &tmp)) | ||
1580 | sd->dst_master = tmp; | ||
1581 | sd++; | ||
1582 | } | ||
1583 | |||
1584 | return pdata; | ||
1585 | } | ||
1586 | #else | ||
1587 | static inline struct dw_dma_platform_data * | ||
1588 | dw_dma_parse_dt(struct platform_device *pdev) | ||
1589 | { | ||
1590 | return NULL; | ||
1591 | } | ||
1592 | #endif | ||
1593 | |||
1465 | static int dw_probe(struct platform_device *pdev) | 1594 | static int dw_probe(struct platform_device *pdev) |
1466 | { | 1595 | { |
1467 | struct dw_dma_platform_data *pdata; | 1596 | struct dw_dma_platform_data *pdata; |
@@ -1478,6 +1607,9 @@ static int dw_probe(struct platform_device *pdev) | |||
1478 | int i; | 1607 | int i; |
1479 | 1608 | ||
1480 | pdata = dev_get_platdata(&pdev->dev); | 1609 | pdata = dev_get_platdata(&pdev->dev); |
1610 | if (!pdata) | ||
1611 | pdata = dw_dma_parse_dt(pdev); | ||
1612 | |||
1481 | if (!pdata || pdata->nr_channels > DW_DMA_MAX_NR_CHANNELS) | 1613 | if (!pdata || pdata->nr_channels > DW_DMA_MAX_NR_CHANNELS) |
1482 | return -EINVAL; | 1614 | return -EINVAL; |
1483 | 1615 | ||
@@ -1512,6 +1644,8 @@ static int dw_probe(struct platform_device *pdev) | |||
1512 | clk_prepare_enable(dw->clk); | 1644 | clk_prepare_enable(dw->clk); |
1513 | 1645 | ||
1514 | dw->regs = regs; | 1646 | dw->regs = regs; |
1647 | dw->sd = pdata->sd; | ||
1648 | dw->sd_count = pdata->sd_count; | ||
1515 | 1649 | ||
1516 | /* get hardware configuration parameters */ | 1650 | /* get hardware configuration parameters */ |
1517 | if (autocfg) { | 1651 | if (autocfg) { |
diff --git a/drivers/dma/dw_dmac_regs.h b/drivers/dma/dw_dmac_regs.h index 88965597b7d0..88a069f66b89 100644 --- a/drivers/dma/dw_dmac_regs.h +++ b/drivers/dma/dw_dmac_regs.h | |||
@@ -239,6 +239,10 @@ struct dw_dma { | |||
239 | struct tasklet_struct tasklet; | 239 | struct tasklet_struct tasklet; |
240 | struct clk *clk; | 240 | struct clk *clk; |
241 | 241 | ||
242 | /* slave information */ | ||
243 | struct dw_dma_slave *sd; | ||
244 | unsigned int sd_count; | ||
245 | |||
242 | u8 all_chan_mask; | 246 | u8 all_chan_mask; |
243 | 247 | ||
244 | /* hardware configuration */ | 248 | /* hardware configuration */ |
diff --git a/include/linux/dw_dmac.h b/include/linux/dw_dmac.h index 62a6190dee22..41766de66e33 100644 --- a/include/linux/dw_dmac.h +++ b/include/linux/dw_dmac.h | |||
@@ -15,6 +15,26 @@ | |||
15 | #include <linux/dmaengine.h> | 15 | #include <linux/dmaengine.h> |
16 | 16 | ||
17 | /** | 17 | /** |
18 | * struct dw_dma_slave - Controller-specific information about a slave | ||
19 | * | ||
20 | * @dma_dev: required DMA master device. Depricated. | ||
21 | * @bus_id: name of this device channel, not just a device name since | ||
22 | * devices may have more than one channel e.g. "foo_tx" | ||
23 | * @cfg_hi: Platform-specific initializer for the CFG_HI register | ||
24 | * @cfg_lo: Platform-specific initializer for the CFG_LO register | ||
25 | * @src_master: src master for transfers on allocated channel. | ||
26 | * @dst_master: dest master for transfers on allocated channel. | ||
27 | */ | ||
28 | struct dw_dma_slave { | ||
29 | struct device *dma_dev; | ||
30 | const char *bus_id; | ||
31 | u32 cfg_hi; | ||
32 | u32 cfg_lo; | ||
33 | u8 src_master; | ||
34 | u8 dst_master; | ||
35 | }; | ||
36 | |||
37 | /** | ||
18 | * struct dw_dma_platform_data - Controller configuration parameters | 38 | * struct dw_dma_platform_data - Controller configuration parameters |
19 | * @nr_channels: Number of channels supported by hardware (max 8) | 39 | * @nr_channels: Number of channels supported by hardware (max 8) |
20 | * @is_private: The device channels should be marked as private and not for | 40 | * @is_private: The device channels should be marked as private and not for |
@@ -25,6 +45,8 @@ | |||
25 | * @nr_masters: Number of AHB masters supported by the controller | 45 | * @nr_masters: Number of AHB masters supported by the controller |
26 | * @data_width: Maximum data width supported by hardware per AHB master | 46 | * @data_width: Maximum data width supported by hardware per AHB master |
27 | * (0 - 8bits, 1 - 16bits, ..., 5 - 256bits) | 47 | * (0 - 8bits, 1 - 16bits, ..., 5 - 256bits) |
48 | * @sd: slave specific data. Used for configuring channels | ||
49 | * @sd_count: count of slave data structures passed. | ||
28 | */ | 50 | */ |
29 | struct dw_dma_platform_data { | 51 | struct dw_dma_platform_data { |
30 | unsigned int nr_channels; | 52 | unsigned int nr_channels; |
@@ -38,6 +60,9 @@ struct dw_dma_platform_data { | |||
38 | unsigned short block_size; | 60 | unsigned short block_size; |
39 | unsigned char nr_masters; | 61 | unsigned char nr_masters; |
40 | unsigned char data_width[4]; | 62 | unsigned char data_width[4]; |
63 | |||
64 | struct dw_dma_slave *sd; | ||
65 | unsigned int sd_count; | ||
41 | }; | 66 | }; |
42 | 67 | ||
43 | /* bursts size */ | 68 | /* bursts size */ |
@@ -52,23 +77,6 @@ enum dw_dma_msize { | |||
52 | DW_DMA_MSIZE_256, | 77 | DW_DMA_MSIZE_256, |
53 | }; | 78 | }; |
54 | 79 | ||
55 | /** | ||
56 | * struct dw_dma_slave - Controller-specific information about a slave | ||
57 | * | ||
58 | * @dma_dev: required DMA master device | ||
59 | * @cfg_hi: Platform-specific initializer for the CFG_HI register | ||
60 | * @cfg_lo: Platform-specific initializer for the CFG_LO register | ||
61 | * @src_master: src master for transfers on allocated channel. | ||
62 | * @dst_master: dest master for transfers on allocated channel. | ||
63 | */ | ||
64 | struct dw_dma_slave { | ||
65 | struct device *dma_dev; | ||
66 | u32 cfg_hi; | ||
67 | u32 cfg_lo; | ||
68 | u8 src_master; | ||
69 | u8 dst_master; | ||
70 | }; | ||
71 | |||
72 | /* Platform-configurable bits in CFG_HI */ | 80 | /* Platform-configurable bits in CFG_HI */ |
73 | #define DWC_CFGH_FCMODE (1 << 0) | 81 | #define DWC_CFGH_FCMODE (1 << 0) |
74 | #define DWC_CFGH_FIFO_MODE (1 << 1) | 82 | #define DWC_CFGH_FIFO_MODE (1 << 1) |
@@ -106,5 +114,6 @@ void dw_dma_cyclic_stop(struct dma_chan *chan); | |||
106 | dma_addr_t dw_dma_get_src_addr(struct dma_chan *chan); | 114 | dma_addr_t dw_dma_get_src_addr(struct dma_chan *chan); |
107 | 115 | ||
108 | dma_addr_t dw_dma_get_dst_addr(struct dma_chan *chan); | 116 | dma_addr_t dw_dma_get_dst_addr(struct dma_chan *chan); |
117 | bool dw_dma_generic_filter(struct dma_chan *chan, void *param); | ||
109 | 118 | ||
110 | #endif /* DW_DMAC_H */ | 119 | #endif /* DW_DMAC_H */ |