1d2912cb1SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2d88b1397SPeter Ujfalusi /*
3d88b1397SPeter Ujfalusi * Copyright (C) 2015 Texas Instruments Incorporated - http://www.ti.com
4d88b1397SPeter Ujfalusi * Author: Peter Ujfalusi <peter.ujfalusi@ti.com>
5d88b1397SPeter Ujfalusi */
6*897500c7SRob Herring #include <linux/platform_device.h>
7d88b1397SPeter Ujfalusi #include <linux/slab.h>
8d88b1397SPeter Ujfalusi #include <linux/err.h>
9d88b1397SPeter Ujfalusi #include <linux/init.h>
10d88b1397SPeter Ujfalusi #include <linux/list.h>
11d88b1397SPeter Ujfalusi #include <linux/io.h>
12*897500c7SRob Herring #include <linux/of.h>
13d88b1397SPeter Ujfalusi #include <linux/of_dma.h>
14*897500c7SRob Herring #include <linux/of_platform.h>
15d88b1397SPeter Ujfalusi
16d88b1397SPeter Ujfalusi #define TI_XBAR_DRA7 0
17d88b1397SPeter Ujfalusi #define TI_XBAR_AM335X 1
18d88b1397SPeter Ujfalusi static const u32 ti_xbar_type[] = {
19d88b1397SPeter Ujfalusi [TI_XBAR_DRA7] = TI_XBAR_DRA7,
20d88b1397SPeter Ujfalusi [TI_XBAR_AM335X] = TI_XBAR_AM335X,
21d88b1397SPeter Ujfalusi };
22d88b1397SPeter Ujfalusi
23d88b1397SPeter Ujfalusi static const struct of_device_id ti_dma_xbar_match[] = {
24d88b1397SPeter Ujfalusi {
25d88b1397SPeter Ujfalusi .compatible = "ti,dra7-dma-crossbar",
26d88b1397SPeter Ujfalusi .data = &ti_xbar_type[TI_XBAR_DRA7],
27d88b1397SPeter Ujfalusi },
28d88b1397SPeter Ujfalusi {
29d88b1397SPeter Ujfalusi .compatible = "ti,am335x-edma-crossbar",
30d88b1397SPeter Ujfalusi .data = &ti_xbar_type[TI_XBAR_AM335X],
31d88b1397SPeter Ujfalusi },
32d88b1397SPeter Ujfalusi {},
33d88b1397SPeter Ujfalusi };
34d88b1397SPeter Ujfalusi
35d88b1397SPeter Ujfalusi /* Crossbar on AM335x/AM437x family */
36d88b1397SPeter Ujfalusi #define TI_AM335X_XBAR_LINES 64
37d88b1397SPeter Ujfalusi
38d88b1397SPeter Ujfalusi struct ti_am335x_xbar_data {
39d88b1397SPeter Ujfalusi void __iomem *iomem;
40d88b1397SPeter Ujfalusi
41d88b1397SPeter Ujfalusi struct dma_router dmarouter;
42d88b1397SPeter Ujfalusi
43d88b1397SPeter Ujfalusi u32 xbar_events; /* maximum number of events to select in xbar */
44d88b1397SPeter Ujfalusi u32 dma_requests; /* number of DMA requests on eDMA */
45d88b1397SPeter Ujfalusi };
46d88b1397SPeter Ujfalusi
47d88b1397SPeter Ujfalusi struct ti_am335x_xbar_map {
48d88b1397SPeter Ujfalusi u16 dma_line;
49d88b1397SPeter Ujfalusi u8 mux_val;
50d88b1397SPeter Ujfalusi };
51d88b1397SPeter Ujfalusi
ti_am335x_xbar_write(void __iomem * iomem,int event,u8 val)52d88b1397SPeter Ujfalusi static inline void ti_am335x_xbar_write(void __iomem *iomem, int event, u8 val)
53d88b1397SPeter Ujfalusi {
54d88b1397SPeter Ujfalusi /*
55d88b1397SPeter Ujfalusi * TPCC_EVT_MUX_60_63 register layout is different than the
56d88b1397SPeter Ujfalusi * rest, in the sense, that event 63 is mapped to lowest byte
57d88b1397SPeter Ujfalusi * and event 60 is mapped to highest, handle it separately.
58d88b1397SPeter Ujfalusi */
59d88b1397SPeter Ujfalusi if (event >= 60 && event <= 63)
60d88b1397SPeter Ujfalusi writeb_relaxed(val, iomem + (63 - event % 4));
61d88b1397SPeter Ujfalusi else
62d88b1397SPeter Ujfalusi writeb_relaxed(val, iomem + event);
63d88b1397SPeter Ujfalusi }
64d88b1397SPeter Ujfalusi
ti_am335x_xbar_free(struct device * dev,void * route_data)65d88b1397SPeter Ujfalusi static void ti_am335x_xbar_free(struct device *dev, void *route_data)
66d88b1397SPeter Ujfalusi {
67d88b1397SPeter Ujfalusi struct ti_am335x_xbar_data *xbar = dev_get_drvdata(dev);
68d88b1397SPeter Ujfalusi struct ti_am335x_xbar_map *map = route_data;
69d88b1397SPeter Ujfalusi
70d88b1397SPeter Ujfalusi dev_dbg(dev, "Unmapping XBAR event %u on channel %u\n",
71d88b1397SPeter Ujfalusi map->mux_val, map->dma_line);
72d88b1397SPeter Ujfalusi
73d88b1397SPeter Ujfalusi ti_am335x_xbar_write(xbar->iomem, map->dma_line, 0);
74d88b1397SPeter Ujfalusi kfree(map);
75d88b1397SPeter Ujfalusi }
76d88b1397SPeter Ujfalusi
ti_am335x_xbar_route_allocate(struct of_phandle_args * dma_spec,struct of_dma * ofdma)77d88b1397SPeter Ujfalusi static void *ti_am335x_xbar_route_allocate(struct of_phandle_args *dma_spec,
78d88b1397SPeter Ujfalusi struct of_dma *ofdma)
79d88b1397SPeter Ujfalusi {
80d88b1397SPeter Ujfalusi struct platform_device *pdev = of_find_device_by_node(ofdma->of_node);
81d88b1397SPeter Ujfalusi struct ti_am335x_xbar_data *xbar = platform_get_drvdata(pdev);
82d88b1397SPeter Ujfalusi struct ti_am335x_xbar_map *map;
83d88b1397SPeter Ujfalusi
84d88b1397SPeter Ujfalusi if (dma_spec->args_count != 3)
85d88b1397SPeter Ujfalusi return ERR_PTR(-EINVAL);
86d88b1397SPeter Ujfalusi
87d88b1397SPeter Ujfalusi if (dma_spec->args[2] >= xbar->xbar_events) {
88d88b1397SPeter Ujfalusi dev_err(&pdev->dev, "Invalid XBAR event number: %d\n",
89d88b1397SPeter Ujfalusi dma_spec->args[2]);
90d88b1397SPeter Ujfalusi return ERR_PTR(-EINVAL);
91d88b1397SPeter Ujfalusi }
92d88b1397SPeter Ujfalusi
93d88b1397SPeter Ujfalusi if (dma_spec->args[0] >= xbar->dma_requests) {
94d88b1397SPeter Ujfalusi dev_err(&pdev->dev, "Invalid DMA request line number: %d\n",
95d88b1397SPeter Ujfalusi dma_spec->args[0]);
96d88b1397SPeter Ujfalusi return ERR_PTR(-EINVAL);
97d88b1397SPeter Ujfalusi }
98d88b1397SPeter Ujfalusi
99d88b1397SPeter Ujfalusi /* The of_node_put() will be done in the core for the node */
100d88b1397SPeter Ujfalusi dma_spec->np = of_parse_phandle(ofdma->of_node, "dma-masters", 0);
101d88b1397SPeter Ujfalusi if (!dma_spec->np) {
102d88b1397SPeter Ujfalusi dev_err(&pdev->dev, "Can't get DMA master\n");
103d88b1397SPeter Ujfalusi return ERR_PTR(-EINVAL);
104d88b1397SPeter Ujfalusi }
105d88b1397SPeter Ujfalusi
106d88b1397SPeter Ujfalusi map = kzalloc(sizeof(*map), GFP_KERNEL);
107d88b1397SPeter Ujfalusi if (!map) {
108d88b1397SPeter Ujfalusi of_node_put(dma_spec->np);
109d88b1397SPeter Ujfalusi return ERR_PTR(-ENOMEM);
110d88b1397SPeter Ujfalusi }
111d88b1397SPeter Ujfalusi
112d88b1397SPeter Ujfalusi map->dma_line = (u16)dma_spec->args[0];
113d88b1397SPeter Ujfalusi map->mux_val = (u8)dma_spec->args[2];
114d88b1397SPeter Ujfalusi
115d88b1397SPeter Ujfalusi dma_spec->args[2] = 0;
116d88b1397SPeter Ujfalusi dma_spec->args_count = 2;
117d88b1397SPeter Ujfalusi
118d88b1397SPeter Ujfalusi dev_dbg(&pdev->dev, "Mapping XBAR event%u to DMA%u\n",
119d88b1397SPeter Ujfalusi map->mux_val, map->dma_line);
120d88b1397SPeter Ujfalusi
121d88b1397SPeter Ujfalusi ti_am335x_xbar_write(xbar->iomem, map->dma_line, map->mux_val);
122d88b1397SPeter Ujfalusi
123d88b1397SPeter Ujfalusi return map;
124d88b1397SPeter Ujfalusi }
125d88b1397SPeter Ujfalusi
1265d051f37SKrzysztof Kozlowski static const struct of_device_id ti_am335x_master_match[] __maybe_unused = {
127d88b1397SPeter Ujfalusi { .compatible = "ti,edma3-tpcc", },
128d88b1397SPeter Ujfalusi {},
129d88b1397SPeter Ujfalusi };
130d88b1397SPeter Ujfalusi
ti_am335x_xbar_probe(struct platform_device * pdev)131d88b1397SPeter Ujfalusi static int ti_am335x_xbar_probe(struct platform_device *pdev)
132d88b1397SPeter Ujfalusi {
133d88b1397SPeter Ujfalusi struct device_node *node = pdev->dev.of_node;
134d88b1397SPeter Ujfalusi const struct of_device_id *match;
135d88b1397SPeter Ujfalusi struct device_node *dma_node;
136d88b1397SPeter Ujfalusi struct ti_am335x_xbar_data *xbar;
137d88b1397SPeter Ujfalusi void __iomem *iomem;
138d88b1397SPeter Ujfalusi int i, ret;
139d88b1397SPeter Ujfalusi
140d88b1397SPeter Ujfalusi if (!node)
141d88b1397SPeter Ujfalusi return -ENODEV;
142d88b1397SPeter Ujfalusi
143d88b1397SPeter Ujfalusi xbar = devm_kzalloc(&pdev->dev, sizeof(*xbar), GFP_KERNEL);
144d88b1397SPeter Ujfalusi if (!xbar)
145d88b1397SPeter Ujfalusi return -ENOMEM;
146d88b1397SPeter Ujfalusi
147d88b1397SPeter Ujfalusi dma_node = of_parse_phandle(node, "dma-masters", 0);
148d88b1397SPeter Ujfalusi if (!dma_node) {
149d88b1397SPeter Ujfalusi dev_err(&pdev->dev, "Can't get DMA master node\n");
150d88b1397SPeter Ujfalusi return -ENODEV;
151d88b1397SPeter Ujfalusi }
152d88b1397SPeter Ujfalusi
153d88b1397SPeter Ujfalusi match = of_match_node(ti_am335x_master_match, dma_node);
154d88b1397SPeter Ujfalusi if (!match) {
155d88b1397SPeter Ujfalusi dev_err(&pdev->dev, "DMA master is not supported\n");
156d88b1397SPeter Ujfalusi of_node_put(dma_node);
157d88b1397SPeter Ujfalusi return -EINVAL;
158d88b1397SPeter Ujfalusi }
159d88b1397SPeter Ujfalusi
160d88b1397SPeter Ujfalusi if (of_property_read_u32(dma_node, "dma-requests",
161d88b1397SPeter Ujfalusi &xbar->dma_requests)) {
162d88b1397SPeter Ujfalusi dev_info(&pdev->dev,
163d88b1397SPeter Ujfalusi "Missing XBAR output information, using %u.\n",
164d88b1397SPeter Ujfalusi TI_AM335X_XBAR_LINES);
165d88b1397SPeter Ujfalusi xbar->dma_requests = TI_AM335X_XBAR_LINES;
166d88b1397SPeter Ujfalusi }
167d88b1397SPeter Ujfalusi of_node_put(dma_node);
168d88b1397SPeter Ujfalusi
169d88b1397SPeter Ujfalusi if (of_property_read_u32(node, "dma-requests", &xbar->xbar_events)) {
170d88b1397SPeter Ujfalusi dev_info(&pdev->dev,
171d88b1397SPeter Ujfalusi "Missing XBAR input information, using %u.\n",
172d88b1397SPeter Ujfalusi TI_AM335X_XBAR_LINES);
173d88b1397SPeter Ujfalusi xbar->xbar_events = TI_AM335X_XBAR_LINES;
174d88b1397SPeter Ujfalusi }
175d88b1397SPeter Ujfalusi
176acd62418Schenqiwu iomem = devm_platform_ioremap_resource(pdev, 0);
177d88b1397SPeter Ujfalusi if (IS_ERR(iomem))
178d88b1397SPeter Ujfalusi return PTR_ERR(iomem);
179d88b1397SPeter Ujfalusi
180d88b1397SPeter Ujfalusi xbar->iomem = iomem;
181d88b1397SPeter Ujfalusi
182d88b1397SPeter Ujfalusi xbar->dmarouter.dev = &pdev->dev;
183d88b1397SPeter Ujfalusi xbar->dmarouter.route_free = ti_am335x_xbar_free;
184d88b1397SPeter Ujfalusi
185d88b1397SPeter Ujfalusi platform_set_drvdata(pdev, xbar);
186d88b1397SPeter Ujfalusi
187d88b1397SPeter Ujfalusi /* Reset the crossbar */
188d88b1397SPeter Ujfalusi for (i = 0; i < xbar->dma_requests; i++)
189d88b1397SPeter Ujfalusi ti_am335x_xbar_write(xbar->iomem, i, 0);
190d88b1397SPeter Ujfalusi
191d88b1397SPeter Ujfalusi ret = of_dma_router_register(node, ti_am335x_xbar_route_allocate,
192d88b1397SPeter Ujfalusi &xbar->dmarouter);
193d88b1397SPeter Ujfalusi
194d88b1397SPeter Ujfalusi return ret;
195d88b1397SPeter Ujfalusi }
196d88b1397SPeter Ujfalusi
197d88b1397SPeter Ujfalusi /* Crossbar on DRA7xx family */
198d88b1397SPeter Ujfalusi #define TI_DRA7_XBAR_OUTPUTS 127
199d88b1397SPeter Ujfalusi #define TI_DRA7_XBAR_INPUTS 256
200d88b1397SPeter Ujfalusi
201d88b1397SPeter Ujfalusi struct ti_dra7_xbar_data {
202d88b1397SPeter Ujfalusi void __iomem *iomem;
203d88b1397SPeter Ujfalusi
204d88b1397SPeter Ujfalusi struct dma_router dmarouter;
205d88b1397SPeter Ujfalusi struct mutex mutex;
206d88b1397SPeter Ujfalusi unsigned long *dma_inuse;
207d88b1397SPeter Ujfalusi
208d88b1397SPeter Ujfalusi u16 safe_val; /* Value to rest the crossbar lines */
209d88b1397SPeter Ujfalusi u32 xbar_requests; /* number of DMA requests connected to XBAR */
210d88b1397SPeter Ujfalusi u32 dma_requests; /* number of DMA requests forwarded to DMA */
211d88b1397SPeter Ujfalusi u32 dma_offset;
212d88b1397SPeter Ujfalusi };
213d88b1397SPeter Ujfalusi
214d88b1397SPeter Ujfalusi struct ti_dra7_xbar_map {
215d88b1397SPeter Ujfalusi u16 xbar_in;
216d88b1397SPeter Ujfalusi int xbar_out;
217d88b1397SPeter Ujfalusi };
218d88b1397SPeter Ujfalusi
ti_dra7_xbar_write(void __iomem * iomem,int xbar,u16 val)219d88b1397SPeter Ujfalusi static inline void ti_dra7_xbar_write(void __iomem *iomem, int xbar, u16 val)
220d88b1397SPeter Ujfalusi {
221d88b1397SPeter Ujfalusi writew_relaxed(val, iomem + (xbar * 2));
222d88b1397SPeter Ujfalusi }
223d88b1397SPeter Ujfalusi
ti_dra7_xbar_free(struct device * dev,void * route_data)224d88b1397SPeter Ujfalusi static void ti_dra7_xbar_free(struct device *dev, void *route_data)
225d88b1397SPeter Ujfalusi {
226d88b1397SPeter Ujfalusi struct ti_dra7_xbar_data *xbar = dev_get_drvdata(dev);
227d88b1397SPeter Ujfalusi struct ti_dra7_xbar_map *map = route_data;
228d88b1397SPeter Ujfalusi
229d88b1397SPeter Ujfalusi dev_dbg(dev, "Unmapping XBAR%u (was routed to %d)\n",
230d88b1397SPeter Ujfalusi map->xbar_in, map->xbar_out);
231d88b1397SPeter Ujfalusi
232d88b1397SPeter Ujfalusi ti_dra7_xbar_write(xbar->iomem, map->xbar_out, xbar->safe_val);
233d88b1397SPeter Ujfalusi mutex_lock(&xbar->mutex);
234d88b1397SPeter Ujfalusi clear_bit(map->xbar_out, xbar->dma_inuse);
235d88b1397SPeter Ujfalusi mutex_unlock(&xbar->mutex);
236d88b1397SPeter Ujfalusi kfree(map);
237d88b1397SPeter Ujfalusi }
238d88b1397SPeter Ujfalusi
ti_dra7_xbar_route_allocate(struct of_phandle_args * dma_spec,struct of_dma * ofdma)239d88b1397SPeter Ujfalusi static void *ti_dra7_xbar_route_allocate(struct of_phandle_args *dma_spec,
240d88b1397SPeter Ujfalusi struct of_dma *ofdma)
241d88b1397SPeter Ujfalusi {
242d88b1397SPeter Ujfalusi struct platform_device *pdev = of_find_device_by_node(ofdma->of_node);
243d88b1397SPeter Ujfalusi struct ti_dra7_xbar_data *xbar = platform_get_drvdata(pdev);
244d88b1397SPeter Ujfalusi struct ti_dra7_xbar_map *map;
245d88b1397SPeter Ujfalusi
246d88b1397SPeter Ujfalusi if (dma_spec->args[0] >= xbar->xbar_requests) {
247d88b1397SPeter Ujfalusi dev_err(&pdev->dev, "Invalid XBAR request number: %d\n",
248d88b1397SPeter Ujfalusi dma_spec->args[0]);
249615a4bfcSMiaoqian Lin put_device(&pdev->dev);
250d88b1397SPeter Ujfalusi return ERR_PTR(-EINVAL);
251d88b1397SPeter Ujfalusi }
252d88b1397SPeter Ujfalusi
253d88b1397SPeter Ujfalusi /* The of_node_put() will be done in the core for the node */
254d88b1397SPeter Ujfalusi dma_spec->np = of_parse_phandle(ofdma->of_node, "dma-masters", 0);
255d88b1397SPeter Ujfalusi if (!dma_spec->np) {
256d88b1397SPeter Ujfalusi dev_err(&pdev->dev, "Can't get DMA master\n");
257615a4bfcSMiaoqian Lin put_device(&pdev->dev);
258d88b1397SPeter Ujfalusi return ERR_PTR(-EINVAL);
259d88b1397SPeter Ujfalusi }
260d88b1397SPeter Ujfalusi
261d88b1397SPeter Ujfalusi map = kzalloc(sizeof(*map), GFP_KERNEL);
262d88b1397SPeter Ujfalusi if (!map) {
263d88b1397SPeter Ujfalusi of_node_put(dma_spec->np);
264615a4bfcSMiaoqian Lin put_device(&pdev->dev);
265d88b1397SPeter Ujfalusi return ERR_PTR(-ENOMEM);
266d88b1397SPeter Ujfalusi }
267d88b1397SPeter Ujfalusi
268d88b1397SPeter Ujfalusi mutex_lock(&xbar->mutex);
269d88b1397SPeter Ujfalusi map->xbar_out = find_first_zero_bit(xbar->dma_inuse,
270d88b1397SPeter Ujfalusi xbar->dma_requests);
271d88b1397SPeter Ujfalusi if (map->xbar_out == xbar->dma_requests) {
272d88b1397SPeter Ujfalusi mutex_unlock(&xbar->mutex);
273d88b1397SPeter Ujfalusi dev_err(&pdev->dev, "Run out of free DMA requests\n");
274d88b1397SPeter Ujfalusi kfree(map);
275c132fe78SMiaoqian Lin of_node_put(dma_spec->np);
276615a4bfcSMiaoqian Lin put_device(&pdev->dev);
277d88b1397SPeter Ujfalusi return ERR_PTR(-ENOMEM);
278d88b1397SPeter Ujfalusi }
279d88b1397SPeter Ujfalusi set_bit(map->xbar_out, xbar->dma_inuse);
280d88b1397SPeter Ujfalusi mutex_unlock(&xbar->mutex);
281d88b1397SPeter Ujfalusi
282d88b1397SPeter Ujfalusi map->xbar_in = (u16)dma_spec->args[0];
283d88b1397SPeter Ujfalusi
284d88b1397SPeter Ujfalusi dma_spec->args[0] = map->xbar_out + xbar->dma_offset;
285d88b1397SPeter Ujfalusi
286d88b1397SPeter Ujfalusi dev_dbg(&pdev->dev, "Mapping XBAR%u to DMA%d\n",
287d88b1397SPeter Ujfalusi map->xbar_in, map->xbar_out);
288d88b1397SPeter Ujfalusi
289d88b1397SPeter Ujfalusi ti_dra7_xbar_write(xbar->iomem, map->xbar_out, map->xbar_in);
290d88b1397SPeter Ujfalusi
291d88b1397SPeter Ujfalusi return map;
292d88b1397SPeter Ujfalusi }
293d88b1397SPeter Ujfalusi
294d88b1397SPeter Ujfalusi #define TI_XBAR_EDMA_OFFSET 0
295d88b1397SPeter Ujfalusi #define TI_XBAR_SDMA_OFFSET 1
296d88b1397SPeter Ujfalusi static const u32 ti_dma_offset[] = {
297d88b1397SPeter Ujfalusi [TI_XBAR_EDMA_OFFSET] = 0,
298d88b1397SPeter Ujfalusi [TI_XBAR_SDMA_OFFSET] = 1,
299d88b1397SPeter Ujfalusi };
300d88b1397SPeter Ujfalusi
3015d051f37SKrzysztof Kozlowski static const struct of_device_id ti_dra7_master_match[] __maybe_unused = {
302d88b1397SPeter Ujfalusi {
303d88b1397SPeter Ujfalusi .compatible = "ti,omap4430-sdma",
304d88b1397SPeter Ujfalusi .data = &ti_dma_offset[TI_XBAR_SDMA_OFFSET],
305d88b1397SPeter Ujfalusi },
306d88b1397SPeter Ujfalusi {
307d88b1397SPeter Ujfalusi .compatible = "ti,edma3",
308d88b1397SPeter Ujfalusi .data = &ti_dma_offset[TI_XBAR_EDMA_OFFSET],
309d88b1397SPeter Ujfalusi },
310d88b1397SPeter Ujfalusi {
311d88b1397SPeter Ujfalusi .compatible = "ti,edma3-tpcc",
312d88b1397SPeter Ujfalusi .data = &ti_dma_offset[TI_XBAR_EDMA_OFFSET],
313d88b1397SPeter Ujfalusi },
314d88b1397SPeter Ujfalusi {},
315d88b1397SPeter Ujfalusi };
316d88b1397SPeter Ujfalusi
ti_dra7_xbar_reserve(int offset,int len,unsigned long * p)317d88b1397SPeter Ujfalusi static inline void ti_dra7_xbar_reserve(int offset, int len, unsigned long *p)
318d88b1397SPeter Ujfalusi {
319d88b1397SPeter Ujfalusi for (; len > 0; len--)
320d88b1397SPeter Ujfalusi set_bit(offset + (len - 1), p);
321d88b1397SPeter Ujfalusi }
322d88b1397SPeter Ujfalusi
ti_dra7_xbar_probe(struct platform_device * pdev)323d88b1397SPeter Ujfalusi static int ti_dra7_xbar_probe(struct platform_device *pdev)
324d88b1397SPeter Ujfalusi {
325d88b1397SPeter Ujfalusi struct device_node *node = pdev->dev.of_node;
326d88b1397SPeter Ujfalusi const struct of_device_id *match;
327d88b1397SPeter Ujfalusi struct device_node *dma_node;
328d88b1397SPeter Ujfalusi struct ti_dra7_xbar_data *xbar;
329d88b1397SPeter Ujfalusi struct property *prop;
330d88b1397SPeter Ujfalusi u32 safe_val;
331d88b1397SPeter Ujfalusi int sz;
332d88b1397SPeter Ujfalusi void __iomem *iomem;
333d88b1397SPeter Ujfalusi int i, ret;
334d88b1397SPeter Ujfalusi
335d88b1397SPeter Ujfalusi if (!node)
336d88b1397SPeter Ujfalusi return -ENODEV;
337d88b1397SPeter Ujfalusi
338d88b1397SPeter Ujfalusi xbar = devm_kzalloc(&pdev->dev, sizeof(*xbar), GFP_KERNEL);
339d88b1397SPeter Ujfalusi if (!xbar)
340d88b1397SPeter Ujfalusi return -ENOMEM;
341d88b1397SPeter Ujfalusi
342d88b1397SPeter Ujfalusi dma_node = of_parse_phandle(node, "dma-masters", 0);
343d88b1397SPeter Ujfalusi if (!dma_node) {
344d88b1397SPeter Ujfalusi dev_err(&pdev->dev, "Can't get DMA master node\n");
345d88b1397SPeter Ujfalusi return -ENODEV;
346d88b1397SPeter Ujfalusi }
347d88b1397SPeter Ujfalusi
348d88b1397SPeter Ujfalusi match = of_match_node(ti_dra7_master_match, dma_node);
349d88b1397SPeter Ujfalusi if (!match) {
350d88b1397SPeter Ujfalusi dev_err(&pdev->dev, "DMA master is not supported\n");
351d88b1397SPeter Ujfalusi of_node_put(dma_node);
352d88b1397SPeter Ujfalusi return -EINVAL;
353d88b1397SPeter Ujfalusi }
354d88b1397SPeter Ujfalusi
355d88b1397SPeter Ujfalusi if (of_property_read_u32(dma_node, "dma-requests",
356d88b1397SPeter Ujfalusi &xbar->dma_requests)) {
357d88b1397SPeter Ujfalusi dev_info(&pdev->dev,
358d88b1397SPeter Ujfalusi "Missing XBAR output information, using %u.\n",
359d88b1397SPeter Ujfalusi TI_DRA7_XBAR_OUTPUTS);
360d88b1397SPeter Ujfalusi xbar->dma_requests = TI_DRA7_XBAR_OUTPUTS;
361d88b1397SPeter Ujfalusi }
362d88b1397SPeter Ujfalusi of_node_put(dma_node);
363d88b1397SPeter Ujfalusi
364d88b1397SPeter Ujfalusi xbar->dma_inuse = devm_kcalloc(&pdev->dev,
365d88b1397SPeter Ujfalusi BITS_TO_LONGS(xbar->dma_requests),
366d88b1397SPeter Ujfalusi sizeof(unsigned long), GFP_KERNEL);
367d88b1397SPeter Ujfalusi if (!xbar->dma_inuse)
368d88b1397SPeter Ujfalusi return -ENOMEM;
369d88b1397SPeter Ujfalusi
370d88b1397SPeter Ujfalusi if (of_property_read_u32(node, "dma-requests", &xbar->xbar_requests)) {
371d88b1397SPeter Ujfalusi dev_info(&pdev->dev,
372d88b1397SPeter Ujfalusi "Missing XBAR input information, using %u.\n",
373d88b1397SPeter Ujfalusi TI_DRA7_XBAR_INPUTS);
374d88b1397SPeter Ujfalusi xbar->xbar_requests = TI_DRA7_XBAR_INPUTS;
375d88b1397SPeter Ujfalusi }
376d88b1397SPeter Ujfalusi
377d88b1397SPeter Ujfalusi if (!of_property_read_u32(node, "ti,dma-safe-map", &safe_val))
378d88b1397SPeter Ujfalusi xbar->safe_val = (u16)safe_val;
379d88b1397SPeter Ujfalusi
380d88b1397SPeter Ujfalusi
381d88b1397SPeter Ujfalusi prop = of_find_property(node, "ti,reserved-dma-request-ranges", &sz);
382d88b1397SPeter Ujfalusi if (prop) {
383d88b1397SPeter Ujfalusi const char pname[] = "ti,reserved-dma-request-ranges";
384d88b1397SPeter Ujfalusi u32 (*rsv_events)[2];
385d88b1397SPeter Ujfalusi size_t nelm = sz / sizeof(*rsv_events);
386d88b1397SPeter Ujfalusi int i;
387d88b1397SPeter Ujfalusi
388d88b1397SPeter Ujfalusi if (!nelm)
389d88b1397SPeter Ujfalusi return -EINVAL;
390d88b1397SPeter Ujfalusi
391d88b1397SPeter Ujfalusi rsv_events = kcalloc(nelm, sizeof(*rsv_events), GFP_KERNEL);
392d88b1397SPeter Ujfalusi if (!rsv_events)
393d88b1397SPeter Ujfalusi return -ENOMEM;
394d88b1397SPeter Ujfalusi
395d88b1397SPeter Ujfalusi ret = of_property_read_u32_array(node, pname, (u32 *)rsv_events,
396d88b1397SPeter Ujfalusi nelm * 2);
3972c231c0cSWenwen Wang if (ret) {
3982c231c0cSWenwen Wang kfree(rsv_events);
399d88b1397SPeter Ujfalusi return ret;
4002c231c0cSWenwen Wang }
401d88b1397SPeter Ujfalusi
402d88b1397SPeter Ujfalusi for (i = 0; i < nelm; i++) {
403d88b1397SPeter Ujfalusi ti_dra7_xbar_reserve(rsv_events[i][0], rsv_events[i][1],
404d88b1397SPeter Ujfalusi xbar->dma_inuse);
405d88b1397SPeter Ujfalusi }
406d88b1397SPeter Ujfalusi kfree(rsv_events);
407d88b1397SPeter Ujfalusi }
408d88b1397SPeter Ujfalusi
409acd62418Schenqiwu iomem = devm_platform_ioremap_resource(pdev, 0);
410d88b1397SPeter Ujfalusi if (IS_ERR(iomem))
411d88b1397SPeter Ujfalusi return PTR_ERR(iomem);
412d88b1397SPeter Ujfalusi
413d88b1397SPeter Ujfalusi xbar->iomem = iomem;
414d88b1397SPeter Ujfalusi
415d88b1397SPeter Ujfalusi xbar->dmarouter.dev = &pdev->dev;
416d88b1397SPeter Ujfalusi xbar->dmarouter.route_free = ti_dra7_xbar_free;
417d88b1397SPeter Ujfalusi xbar->dma_offset = *(u32 *)match->data;
418d88b1397SPeter Ujfalusi
419d88b1397SPeter Ujfalusi mutex_init(&xbar->mutex);
420d88b1397SPeter Ujfalusi platform_set_drvdata(pdev, xbar);
421d88b1397SPeter Ujfalusi
422d88b1397SPeter Ujfalusi /* Reset the crossbar */
423d88b1397SPeter Ujfalusi for (i = 0; i < xbar->dma_requests; i++) {
424d88b1397SPeter Ujfalusi if (!test_bit(i, xbar->dma_inuse))
425d88b1397SPeter Ujfalusi ti_dra7_xbar_write(xbar->iomem, i, xbar->safe_val);
426d88b1397SPeter Ujfalusi }
427d88b1397SPeter Ujfalusi
428d88b1397SPeter Ujfalusi ret = of_dma_router_register(node, ti_dra7_xbar_route_allocate,
429d88b1397SPeter Ujfalusi &xbar->dmarouter);
430d88b1397SPeter Ujfalusi if (ret) {
431d88b1397SPeter Ujfalusi /* Restore the defaults for the crossbar */
432d88b1397SPeter Ujfalusi for (i = 0; i < xbar->dma_requests; i++) {
433d88b1397SPeter Ujfalusi if (!test_bit(i, xbar->dma_inuse))
434d88b1397SPeter Ujfalusi ti_dra7_xbar_write(xbar->iomem, i, i);
435d88b1397SPeter Ujfalusi }
436d88b1397SPeter Ujfalusi }
437d88b1397SPeter Ujfalusi
438d88b1397SPeter Ujfalusi return ret;
439d88b1397SPeter Ujfalusi }
440d88b1397SPeter Ujfalusi
ti_dma_xbar_probe(struct platform_device * pdev)441d88b1397SPeter Ujfalusi static int ti_dma_xbar_probe(struct platform_device *pdev)
442d88b1397SPeter Ujfalusi {
443d88b1397SPeter Ujfalusi const struct of_device_id *match;
444d88b1397SPeter Ujfalusi int ret;
445d88b1397SPeter Ujfalusi
446d88b1397SPeter Ujfalusi match = of_match_node(ti_dma_xbar_match, pdev->dev.of_node);
447d88b1397SPeter Ujfalusi if (unlikely(!match))
448d88b1397SPeter Ujfalusi return -EINVAL;
449d88b1397SPeter Ujfalusi
450d88b1397SPeter Ujfalusi switch (*(u32 *)match->data) {
451d88b1397SPeter Ujfalusi case TI_XBAR_DRA7:
452d88b1397SPeter Ujfalusi ret = ti_dra7_xbar_probe(pdev);
453d88b1397SPeter Ujfalusi break;
454d88b1397SPeter Ujfalusi case TI_XBAR_AM335X:
455d88b1397SPeter Ujfalusi ret = ti_am335x_xbar_probe(pdev);
456d88b1397SPeter Ujfalusi break;
457d88b1397SPeter Ujfalusi default:
458d88b1397SPeter Ujfalusi dev_err(&pdev->dev, "Unsupported crossbar\n");
459d88b1397SPeter Ujfalusi ret = -ENODEV;
460d88b1397SPeter Ujfalusi break;
461d88b1397SPeter Ujfalusi }
462d88b1397SPeter Ujfalusi
463d88b1397SPeter Ujfalusi return ret;
464d88b1397SPeter Ujfalusi }
465d88b1397SPeter Ujfalusi
466d88b1397SPeter Ujfalusi static struct platform_driver ti_dma_xbar_driver = {
467d88b1397SPeter Ujfalusi .driver = {
468d88b1397SPeter Ujfalusi .name = "ti-dma-crossbar",
4695d051f37SKrzysztof Kozlowski .of_match_table = ti_dma_xbar_match,
470d88b1397SPeter Ujfalusi },
471d88b1397SPeter Ujfalusi .probe = ti_dma_xbar_probe,
472d88b1397SPeter Ujfalusi };
473d88b1397SPeter Ujfalusi
omap_dmaxbar_init(void)474d88b1397SPeter Ujfalusi static int omap_dmaxbar_init(void)
475d88b1397SPeter Ujfalusi {
476d88b1397SPeter Ujfalusi return platform_driver_register(&ti_dma_xbar_driver);
477d88b1397SPeter Ujfalusi }
478d88b1397SPeter Ujfalusi arch_initcall(omap_dmaxbar_init);
479