diff options
author | Arnd Bergmann <arnd@arndb.de> | 2013-01-28 11:24:37 -0500 |
---|---|---|
committer | Arnd Bergmann <arnd@arndb.de> | 2013-03-12 12:56:09 -0400 |
commit | 787b0c1f8e1975157fe73104e67cac18f955281b (patch) | |
tree | 4668c8a2a16baec67e71844840b85bea03cb5566 /drivers/tty | |
parent | dc715452e9145156840b09df765ea2ede4851eda (diff) |
serial: pl011: use generic DMA slave configuration if possible
With the new OF DMA binding, it is possible to completely avoid the
need for platform_data for configuring a DMA channel. In cases where the
platform has already been converted, calling dma_request_slave_channel
should get all the necessary information from the device tree.
This also adds a binding document specific to the pl011 controller,
and extends the generic primecell binding to mention "dmas" and other
common properties.
Like the patch that converts the dw_dma controller, this is completely
untested and is looking for someone to try it out.
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
Acked-by: Grant Likely <grant.likely@secretlab.ca>
Acked-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Cc: Russell King <linux@arm.linux.org.uk>
Cc: Jiri Slaby <jslaby@suse.cz>
Cc: Viresh Kumar <viresh.kumar@linaro.org>
Cc: devicetree-discuss@lists.ozlabs.org
Cc: linux-arm-kernel@lists.infradead.org
Diffstat (limited to 'drivers/tty')
-rw-r--r-- | drivers/tty/serial/amba-pl011.c | 62 |
1 files changed, 37 insertions, 25 deletions
diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c index 3ea5408fcbeb..c25b00ef9dbb 100644 --- a/drivers/tty/serial/amba-pl011.c +++ b/drivers/tty/serial/amba-pl011.c | |||
@@ -245,7 +245,7 @@ static void pl011_sgbuf_free(struct dma_chan *chan, struct pl011_sgbuf *sg, | |||
245 | } | 245 | } |
246 | } | 246 | } |
247 | 247 | ||
248 | static void pl011_dma_probe_initcall(struct uart_amba_port *uap) | 248 | static void pl011_dma_probe_initcall(struct device *dev, struct uart_amba_port *uap) |
249 | { | 249 | { |
250 | /* DMA is the sole user of the platform data right now */ | 250 | /* DMA is the sole user of the platform data right now */ |
251 | struct amba_pl011_data *plat = uap->port.dev->platform_data; | 251 | struct amba_pl011_data *plat = uap->port.dev->platform_data; |
@@ -259,20 +259,25 @@ static void pl011_dma_probe_initcall(struct uart_amba_port *uap) | |||
259 | struct dma_chan *chan; | 259 | struct dma_chan *chan; |
260 | dma_cap_mask_t mask; | 260 | dma_cap_mask_t mask; |
261 | 261 | ||
262 | /* We need platform data */ | 262 | chan = dma_request_slave_channel(dev, "tx"); |
263 | if (!plat || !plat->dma_filter) { | ||
264 | dev_info(uap->port.dev, "no DMA platform data\n"); | ||
265 | return; | ||
266 | } | ||
267 | 263 | ||
268 | /* Try to acquire a generic DMA engine slave TX channel */ | ||
269 | dma_cap_zero(mask); | ||
270 | dma_cap_set(DMA_SLAVE, mask); | ||
271 | |||
272 | chan = dma_request_channel(mask, plat->dma_filter, plat->dma_tx_param); | ||
273 | if (!chan) { | 264 | if (!chan) { |
274 | dev_err(uap->port.dev, "no TX DMA channel!\n"); | 265 | /* We need platform data */ |
275 | return; | 266 | if (!plat || !plat->dma_filter) { |
267 | dev_info(uap->port.dev, "no DMA platform data\n"); | ||
268 | return; | ||
269 | } | ||
270 | |||
271 | /* Try to acquire a generic DMA engine slave TX channel */ | ||
272 | dma_cap_zero(mask); | ||
273 | dma_cap_set(DMA_SLAVE, mask); | ||
274 | |||
275 | chan = dma_request_channel(mask, plat->dma_filter, | ||
276 | plat->dma_tx_param); | ||
277 | if (!chan) { | ||
278 | dev_err(uap->port.dev, "no TX DMA channel!\n"); | ||
279 | return; | ||
280 | } | ||
276 | } | 281 | } |
277 | 282 | ||
278 | dmaengine_slave_config(chan, &tx_conf); | 283 | dmaengine_slave_config(chan, &tx_conf); |
@@ -282,7 +287,18 @@ static void pl011_dma_probe_initcall(struct uart_amba_port *uap) | |||
282 | dma_chan_name(uap->dmatx.chan)); | 287 | dma_chan_name(uap->dmatx.chan)); |
283 | 288 | ||
284 | /* Optionally make use of an RX channel as well */ | 289 | /* Optionally make use of an RX channel as well */ |
285 | if (plat->dma_rx_param) { | 290 | chan = dma_request_slave_channel(dev, "rx"); |
291 | |||
292 | if (!chan && plat->dma_rx_param) { | ||
293 | chan = dma_request_channel(mask, plat->dma_filter, plat->dma_rx_param); | ||
294 | |||
295 | if (!chan) { | ||
296 | dev_err(uap->port.dev, "no RX DMA channel!\n"); | ||
297 | return; | ||
298 | } | ||
299 | } | ||
300 | |||
301 | if (chan) { | ||
286 | struct dma_slave_config rx_conf = { | 302 | struct dma_slave_config rx_conf = { |
287 | .src_addr = uap->port.mapbase + UART01x_DR, | 303 | .src_addr = uap->port.mapbase + UART01x_DR, |
288 | .src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE, | 304 | .src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE, |
@@ -291,12 +307,6 @@ static void pl011_dma_probe_initcall(struct uart_amba_port *uap) | |||
291 | .device_fc = false, | 307 | .device_fc = false, |
292 | }; | 308 | }; |
293 | 309 | ||
294 | chan = dma_request_channel(mask, plat->dma_filter, plat->dma_rx_param); | ||
295 | if (!chan) { | ||
296 | dev_err(uap->port.dev, "no RX DMA channel!\n"); | ||
297 | return; | ||
298 | } | ||
299 | |||
300 | dmaengine_slave_config(chan, &rx_conf); | 310 | dmaengine_slave_config(chan, &rx_conf); |
301 | uap->dmarx.chan = chan; | 311 | uap->dmarx.chan = chan; |
302 | 312 | ||
@@ -315,6 +325,7 @@ static void pl011_dma_probe_initcall(struct uart_amba_port *uap) | |||
315 | struct dma_uap { | 325 | struct dma_uap { |
316 | struct list_head node; | 326 | struct list_head node; |
317 | struct uart_amba_port *uap; | 327 | struct uart_amba_port *uap; |
328 | struct device *dev; | ||
318 | }; | 329 | }; |
319 | 330 | ||
320 | static LIST_HEAD(pl011_dma_uarts); | 331 | static LIST_HEAD(pl011_dma_uarts); |
@@ -325,7 +336,7 @@ static int __init pl011_dma_initcall(void) | |||
325 | 336 | ||
326 | list_for_each_safe(node, tmp, &pl011_dma_uarts) { | 337 | list_for_each_safe(node, tmp, &pl011_dma_uarts) { |
327 | struct dma_uap *dmau = list_entry(node, struct dma_uap, node); | 338 | struct dma_uap *dmau = list_entry(node, struct dma_uap, node); |
328 | pl011_dma_probe_initcall(dmau->uap); | 339 | pl011_dma_probe_initcall(dmau->dev, dmau->uap); |
329 | list_del(node); | 340 | list_del(node); |
330 | kfree(dmau); | 341 | kfree(dmau); |
331 | } | 342 | } |
@@ -334,18 +345,19 @@ static int __init pl011_dma_initcall(void) | |||
334 | 345 | ||
335 | device_initcall(pl011_dma_initcall); | 346 | device_initcall(pl011_dma_initcall); |
336 | 347 | ||
337 | static void pl011_dma_probe(struct uart_amba_port *uap) | 348 | static void pl011_dma_probe(struct device *dev, struct uart_amba_port *uap) |
338 | { | 349 | { |
339 | struct dma_uap *dmau = kzalloc(sizeof(struct dma_uap), GFP_KERNEL); | 350 | struct dma_uap *dmau = kzalloc(sizeof(struct dma_uap), GFP_KERNEL); |
340 | if (dmau) { | 351 | if (dmau) { |
341 | dmau->uap = uap; | 352 | dmau->uap = uap; |
353 | dmau->dev = dev; | ||
342 | list_add_tail(&dmau->node, &pl011_dma_uarts); | 354 | list_add_tail(&dmau->node, &pl011_dma_uarts); |
343 | } | 355 | } |
344 | } | 356 | } |
345 | #else | 357 | #else |
346 | static void pl011_dma_probe(struct uart_amba_port *uap) | 358 | static void pl011_dma_probe(struct device *dev, struct uart_amba_port *uap) |
347 | { | 359 | { |
348 | pl011_dma_probe_initcall(uap); | 360 | pl011_dma_probe_initcall(dev, uap); |
349 | } | 361 | } |
350 | #endif | 362 | #endif |
351 | 363 | ||
@@ -2020,7 +2032,7 @@ static int pl011_probe(struct amba_device *dev, const struct amba_id *id) | |||
2020 | uap->port.ops = &amba_pl011_pops; | 2032 | uap->port.ops = &amba_pl011_pops; |
2021 | uap->port.flags = UPF_BOOT_AUTOCONF; | 2033 | uap->port.flags = UPF_BOOT_AUTOCONF; |
2022 | uap->port.line = i; | 2034 | uap->port.line = i; |
2023 | pl011_dma_probe(uap); | 2035 | pl011_dma_probe(&dev->dev, uap); |
2024 | 2036 | ||
2025 | /* Ensure interrupts from this UART are masked and cleared */ | 2037 | /* Ensure interrupts from this UART are masked and cleared */ |
2026 | writew(0, uap->port.membase + UART011_IMSC); | 2038 | writew(0, uap->port.membase + UART011_IMSC); |