Skip to content

Commit 62c37ee

Browse files
Robert Baldygagregkh
Robert Baldyga
authored andcommitted
serial: samsung: add dma reqest/release functions
Add functions requesting and releasing RX and TX DMA channels. This function are called only when "dmas" property in serial device-tree node is defined. Based on previous work of Sylwester Nawrocki and Lukasz Czerwinski. Signed-off-by: Robert Baldyga <[email protected]> Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent a291b7d commit 62c37ee

File tree

1 file changed

+101
-0
lines changed

1 file changed

+101
-0
lines changed

drivers/tty/serial/samsung.c

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,9 @@
2828
#define SUPPORT_SYSRQ
2929
#endif
3030

31+
#include <linux/dmaengine.h>
32+
#include <linux/dma-mapping.h>
33+
#include <linux/slab.h>
3134
#include <linux/module.h>
3235
#include <linux/ioport.h>
3336
#include <linux/io.h>
@@ -453,6 +456,93 @@ static void s3c24xx_serial_break_ctl(struct uart_port *port, int break_state)
453456
spin_unlock_irqrestore(&port->lock, flags);
454457
}
455458

459+
static int s3c24xx_serial_request_dma(struct s3c24xx_uart_port *p)
460+
{
461+
struct s3c24xx_uart_dma *dma = p->dma;
462+
dma_cap_mask_t mask;
463+
unsigned long flags;
464+
465+
/* Default slave configuration parameters */
466+
dma->rx_conf.direction = DMA_DEV_TO_MEM;
467+
dma->rx_conf.src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
468+
dma->rx_conf.src_addr = p->port.mapbase + S3C2410_URXH;
469+
dma->rx_conf.src_maxburst = 16;
470+
471+
dma->tx_conf.direction = DMA_MEM_TO_DEV;
472+
dma->tx_conf.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
473+
dma->tx_conf.dst_addr = p->port.mapbase + S3C2410_UTXH;
474+
if (dma_get_cache_alignment() >= 16)
475+
dma->tx_conf.dst_maxburst = 16;
476+
else
477+
dma->tx_conf.dst_maxburst = 1;
478+
479+
dma_cap_zero(mask);
480+
dma_cap_set(DMA_SLAVE, mask);
481+
482+
dma->rx_chan = dma_request_slave_channel_compat(mask, dma->fn,
483+
dma->rx_param, p->port.dev, "rx");
484+
if (!dma->rx_chan)
485+
return -ENODEV;
486+
487+
dmaengine_slave_config(dma->rx_chan, &dma->rx_conf);
488+
489+
dma->tx_chan = dma_request_slave_channel_compat(mask, dma->fn,
490+
dma->tx_param, p->port.dev, "tx");
491+
if (!dma->tx_chan) {
492+
dma_release_channel(dma->rx_chan);
493+
return -ENODEV;
494+
}
495+
496+
dmaengine_slave_config(dma->tx_chan, &dma->tx_conf);
497+
498+
/* RX buffer */
499+
dma->rx_size = PAGE_SIZE;
500+
501+
dma->rx_buf = kmalloc(dma->rx_size, GFP_KERNEL);
502+
503+
if (!dma->rx_buf) {
504+
dma_release_channel(dma->rx_chan);
505+
dma_release_channel(dma->tx_chan);
506+
return -ENOMEM;
507+
}
508+
509+
dma->rx_addr = dma_map_single(dma->rx_chan->device->dev, dma->rx_buf,
510+
dma->rx_size, DMA_FROM_DEVICE);
511+
512+
spin_lock_irqsave(&p->port.lock, flags);
513+
514+
/* TX buffer */
515+
dma->tx_addr = dma_map_single(dma->tx_chan->device->dev,
516+
p->port.state->xmit.buf,
517+
UART_XMIT_SIZE, DMA_TO_DEVICE);
518+
519+
spin_unlock_irqrestore(&p->port.lock, flags);
520+
521+
return 0;
522+
}
523+
524+
static void s3c24xx_serial_release_dma(struct s3c24xx_uart_port *p)
525+
{
526+
struct s3c24xx_uart_dma *dma = p->dma;
527+
528+
if (dma->rx_chan) {
529+
dmaengine_terminate_all(dma->rx_chan);
530+
dma_unmap_single(dma->rx_chan->device->dev, dma->rx_addr,
531+
dma->rx_size, DMA_FROM_DEVICE);
532+
kfree(dma->rx_buf);
533+
dma_release_channel(dma->rx_chan);
534+
dma->rx_chan = NULL;
535+
}
536+
537+
if (dma->tx_chan) {
538+
dmaengine_terminate_all(dma->tx_chan);
539+
dma_unmap_single(dma->tx_chan->device->dev, dma->tx_addr,
540+
UART_XMIT_SIZE, DMA_TO_DEVICE);
541+
dma_release_channel(dma->tx_chan);
542+
dma->tx_chan = NULL;
543+
}
544+
}
545+
456546
static void s3c24xx_serial_shutdown(struct uart_port *port)
457547
{
458548
struct s3c24xx_uart_port *ourport = to_ourport(port);
@@ -478,6 +568,10 @@ static void s3c24xx_serial_shutdown(struct uart_port *port)
478568
wr_regl(port, S3C64XX_UINTP, 0xf);
479569
wr_regl(port, S3C64XX_UINTM, 0xf);
480570
}
571+
572+
if (ourport->dma)
573+
s3c24xx_serial_release_dma(ourport);
574+
481575
}
482576

483577
static int s3c24xx_serial_startup(struct uart_port *port)
@@ -535,6 +629,13 @@ static int s3c64xx_serial_startup(struct uart_port *port)
535629
port, (unsigned long long)port->mapbase, port->membase);
536630

537631
wr_regl(port, S3C64XX_UINTM, 0xf);
632+
if (ourport->dma) {
633+
ret = s3c24xx_serial_request_dma(ourport);
634+
if (ret < 0) {
635+
dev_warn(port->dev, "DMA request failed\n");
636+
return ret;
637+
}
638+
}
538639

539640
ret = request_irq(port->irq, s3c64xx_serial_handle_irq, IRQF_SHARED,
540641
s3c24xx_serial_portname(port), ourport);

0 commit comments

Comments
 (0)