28
28
#define SUPPORT_SYSRQ
29
29
#endif
30
30
31
+ #include <linux/dmaengine.h>
32
+ #include <linux/dma-mapping.h>
33
+ #include <linux/slab.h>
31
34
#include <linux/module.h>
32
35
#include <linux/ioport.h>
33
36
#include <linux/io.h>
@@ -453,6 +456,93 @@ static void s3c24xx_serial_break_ctl(struct uart_port *port, int break_state)
453
456
spin_unlock_irqrestore (& port -> lock , flags );
454
457
}
455
458
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
+
456
546
static void s3c24xx_serial_shutdown (struct uart_port * port )
457
547
{
458
548
struct s3c24xx_uart_port * ourport = to_ourport (port );
@@ -478,6 +568,10 @@ static void s3c24xx_serial_shutdown(struct uart_port *port)
478
568
wr_regl (port , S3C64XX_UINTP , 0xf );
479
569
wr_regl (port , S3C64XX_UINTM , 0xf );
480
570
}
571
+
572
+ if (ourport -> dma )
573
+ s3c24xx_serial_release_dma (ourport );
574
+
481
575
}
482
576
483
577
static int s3c24xx_serial_startup (struct uart_port * port )
@@ -535,6 +629,13 @@ static int s3c64xx_serial_startup(struct uart_port *port)
535
629
port , (unsigned long long )port -> mapbase , port -> membase );
536
630
537
631
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
+ }
538
639
539
640
ret = request_irq (port -> irq , s3c64xx_serial_handle_irq , IRQF_SHARED ,
540
641
s3c24xx_serial_portname (port ), ourport );
0 commit comments