Skip to content

Commit 56f13c0

Browse files
Peter UjfalusiVinod Koul
authored andcommitted
dmaengine: of_dma: Support for DMA routers
DMA routers are transparent devices used to mux DMA requests from peripherals to DMA controllers. They are used when the SoC integrates more devices with DMA requests then their controller can handle. DRA7x is one example of such SoC, where the sDMA can hanlde 128 DMA request lines, but in SoC level it has 205 DMA requests. The of_dma_router will be registered as of_dma_controller with special xlate function and additional parameters. The driver for the router is responsible to craft the dma_spec (in the of_dma_route_allocate callback) which can be used to requests a DMA channel from the real DMA controller. This way the router can be transparent for the system while remaining generic enough to be used in different environments. Signed-off-by: Peter Ujfalusi <[email protected]> Signed-off-by: Vinod Koul <[email protected]>
1 parent b787f68 commit 56f13c0

File tree

5 files changed

+162
-0
lines changed

5 files changed

+162
-0
lines changed

Documentation/devicetree/bindings/dma/dma.txt

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,34 @@ Example:
3131
dma-requests = <127>;
3232
};
3333

34+
* DMA router
35+
36+
DMA routers are transparent IP blocks used to route DMA request lines from
37+
devices to the DMA controller. Some SoCs (like TI DRA7x) have more peripherals
38+
integrated with DMA requests than what the DMA controller can handle directly.
39+
40+
Required property:
41+
- dma-masters: phandle of the DMA controller or list of phandles for
42+
the DMA controllers the router can direct the signal to.
43+
- #dma-cells: Must be at least 1. Used to provide DMA router specific
44+
information. See DMA client binding below for more
45+
details.
46+
47+
Optional properties:
48+
- dma-requests: Number of incoming request lines the router can handle.
49+
- In the node pointed by the dma-masters:
50+
- dma-requests: The router driver might need to look for this in order
51+
to configure the routing.
52+
53+
Example:
54+
sdma_xbar: dma-router@4a002b78 {
55+
compatible = "ti,dra7-dma-crossbar";
56+
reg = <0x4a002b78 0xfc>;
57+
#dma-cells = <1>;
58+
dma-requests = <205>;
59+
ti,dma-safe-map = <0>;
60+
dma-masters = <&sdma>;
61+
};
3462

3563
* DMA client
3664

drivers/dma/dmaengine.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -267,6 +267,13 @@ static void dma_chan_put(struct dma_chan *chan)
267267
/* This channel is not in use anymore, free it */
268268
if (!chan->client_count && chan->device->device_free_chan_resources)
269269
chan->device->device_free_chan_resources(chan);
270+
271+
/* If the channel is used via a DMA request router, free the mapping */
272+
if (chan->router && chan->router->route_free) {
273+
chan->router->route_free(chan->router->dev, chan->route_data);
274+
chan->router = NULL;
275+
chan->route_data = NULL;
276+
}
270277
}
271278

272279
enum dma_status dma_sync_wait(struct dma_chan *chan, dma_cookie_t cookie)

drivers/dma/of-dma.c

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,50 @@ static struct of_dma *of_dma_find_controller(struct of_phandle_args *dma_spec)
4444
return NULL;
4545
}
4646

47+
/**
48+
* of_dma_router_xlate - translation function for router devices
49+
* @dma_spec: pointer to DMA specifier as found in the device tree
50+
* @of_dma: pointer to DMA controller data (router information)
51+
*
52+
* The function creates new dma_spec to be passed to the router driver's
53+
* of_dma_route_allocate() function to prepare a dma_spec which will be used
54+
* to request channel from the real DMA controller.
55+
*/
56+
static struct dma_chan *of_dma_router_xlate(struct of_phandle_args *dma_spec,
57+
struct of_dma *ofdma)
58+
{
59+
struct dma_chan *chan;
60+
struct of_dma *ofdma_target;
61+
struct of_phandle_args dma_spec_target;
62+
void *route_data;
63+
64+
/* translate the request for the real DMA controller */
65+
memcpy(&dma_spec_target, dma_spec, sizeof(dma_spec_target));
66+
route_data = ofdma->of_dma_route_allocate(&dma_spec_target, ofdma);
67+
if (IS_ERR(route_data))
68+
return NULL;
69+
70+
ofdma_target = of_dma_find_controller(&dma_spec_target);
71+
if (!ofdma_target)
72+
return NULL;
73+
74+
chan = ofdma_target->of_dma_xlate(&dma_spec_target, ofdma_target);
75+
if (chan) {
76+
chan->router = ofdma->dma_router;
77+
chan->route_data = route_data;
78+
} else {
79+
ofdma->dma_router->route_free(ofdma->dma_router->dev,
80+
route_data);
81+
}
82+
83+
/*
84+
* Need to put the node back since the ofdma->of_dma_route_allocate
85+
* has taken it for generating the new, translated dma_spec
86+
*/
87+
of_node_put(dma_spec_target.np);
88+
return chan;
89+
}
90+
4791
/**
4892
* of_dma_controller_register - Register a DMA controller to DT DMA helpers
4993
* @np: device node of DMA controller
@@ -109,6 +153,51 @@ void of_dma_controller_free(struct device_node *np)
109153
}
110154
EXPORT_SYMBOL_GPL(of_dma_controller_free);
111155

156+
/**
157+
* of_dma_router_register - Register a DMA router to DT DMA helpers as a
158+
* controller
159+
* @np: device node of DMA router
160+
* @of_dma_route_allocate: setup function for the router which need to
161+
* modify the dma_spec for the DMA controller to
162+
* use and to set up the requested route.
163+
* @dma_router: pointer to dma_router structure to be used when
164+
* the route need to be free up.
165+
*
166+
* Returns 0 on success or appropriate errno value on error.
167+
*
168+
* Allocated memory should be freed with appropriate of_dma_controller_free()
169+
* call.
170+
*/
171+
int of_dma_router_register(struct device_node *np,
172+
void *(*of_dma_route_allocate)
173+
(struct of_phandle_args *, struct of_dma *),
174+
struct dma_router *dma_router)
175+
{
176+
struct of_dma *ofdma;
177+
178+
if (!np || !of_dma_route_allocate || !dma_router) {
179+
pr_err("%s: not enough information provided\n", __func__);
180+
return -EINVAL;
181+
}
182+
183+
ofdma = kzalloc(sizeof(*ofdma), GFP_KERNEL);
184+
if (!ofdma)
185+
return -ENOMEM;
186+
187+
ofdma->of_node = np;
188+
ofdma->of_dma_xlate = of_dma_router_xlate;
189+
ofdma->of_dma_route_allocate = of_dma_route_allocate;
190+
ofdma->dma_router = dma_router;
191+
192+
/* Now queue of_dma controller structure in list */
193+
mutex_lock(&of_dma_lock);
194+
list_add_tail(&ofdma->of_dma_controllers, &of_dma_list);
195+
mutex_unlock(&of_dma_lock);
196+
197+
return 0;
198+
}
199+
EXPORT_SYMBOL_GPL(of_dma_router_register);
200+
112201
/**
113202
* of_dma_match_channel - Check if a DMA specifier matches name
114203
* @np: device node to look for DMA channels

include/linux/dmaengine.h

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,16 @@ struct dma_chan_percpu {
221221
unsigned long bytes_transferred;
222222
};
223223

224+
/**
225+
* struct dma_router - DMA router structure
226+
* @dev: pointer to the DMA router device
227+
* @route_free: function to be called when the route can be disconnected
228+
*/
229+
struct dma_router {
230+
struct device *dev;
231+
void (*route_free)(struct device *dev, void *route_data);
232+
};
233+
224234
/**
225235
* struct dma_chan - devices supply DMA channels, clients use them
226236
* @device: ptr to the dma device who supplies this channel, always !%NULL
@@ -232,6 +242,8 @@ struct dma_chan_percpu {
232242
* @local: per-cpu pointer to a struct dma_chan_percpu
233243
* @client_count: how many clients are using this channel
234244
* @table_count: number of appearances in the mem-to-mem allocation table
245+
* @router: pointer to the DMA router structure
246+
* @route_data: channel specific data for the router
235247
* @private: private data for certain client-channel associations
236248
*/
237249
struct dma_chan {
@@ -247,6 +259,11 @@ struct dma_chan {
247259
struct dma_chan_percpu __percpu *local;
248260
int client_count;
249261
int table_count;
262+
263+
/* DMA router */
264+
struct dma_router *router;
265+
void *route_data;
266+
250267
void *private;
251268
};
252269

include/linux/of_dma.h

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,9 @@ struct of_dma {
2323
struct device_node *of_node;
2424
struct dma_chan *(*of_dma_xlate)
2525
(struct of_phandle_args *, struct of_dma *);
26+
void *(*of_dma_route_allocate)
27+
(struct of_phandle_args *, struct of_dma *);
28+
struct dma_router *dma_router;
2629
void *of_dma_data;
2730
};
2831

@@ -37,12 +40,20 @@ extern int of_dma_controller_register(struct device_node *np,
3740
(struct of_phandle_args *, struct of_dma *),
3841
void *data);
3942
extern void of_dma_controller_free(struct device_node *np);
43+
44+
extern int of_dma_router_register(struct device_node *np,
45+
void *(*of_dma_route_allocate)
46+
(struct of_phandle_args *, struct of_dma *),
47+
struct dma_router *dma_router);
48+
#define of_dma_router_free of_dma_controller_free
49+
4050
extern struct dma_chan *of_dma_request_slave_channel(struct device_node *np,
4151
const char *name);
4252
extern struct dma_chan *of_dma_simple_xlate(struct of_phandle_args *dma_spec,
4353
struct of_dma *ofdma);
4454
extern struct dma_chan *of_dma_xlate_by_chan_id(struct of_phandle_args *dma_spec,
4555
struct of_dma *ofdma);
56+
4657
#else
4758
static inline int of_dma_controller_register(struct device_node *np,
4859
struct dma_chan *(*of_dma_xlate)
@@ -56,6 +67,16 @@ static inline void of_dma_controller_free(struct device_node *np)
5667
{
5768
}
5869

70+
static inline int of_dma_router_register(struct device_node *np,
71+
void *(*of_dma_route_allocate)
72+
(struct of_phandle_args *, struct of_dma *),
73+
struct dma_router *dma_router)
74+
{
75+
return -ENODEV;
76+
}
77+
78+
#define of_dma_router_free of_dma_controller_free
79+
5980
static inline struct dma_chan *of_dma_request_slave_channel(struct device_node *np,
6081
const char *name)
6182
{

0 commit comments

Comments
 (0)