From 47a4dc26eeb89a3746f9b1e2092602b40469640a Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Thu, 11 Feb 2010 16:50:05 +0000 Subject: dmaengine: shdma: fix DMA error handling. Present DMA error ISR in shdma.c is bogus, it locks the system hard in multiple ways. Fix it to abort all queued transactions on all channels on the affected controller and giving submitters a chance to get a DMA_ERROR status for aborted transactions. Afterwards further functionality is again possible without the need to re-load the driver. Signed-off-by: Guennadi Liakhovetski Signed-off-by: Paul Mundt --- drivers/dma/shdma.c | 89 +++++++++++++++++++++++++++++++---------------------- 1 file changed, 53 insertions(+), 36 deletions(-) (limited to 'drivers') diff --git a/drivers/dma/shdma.c b/drivers/dma/shdma.c index b75ce8b84c4..77311698c04 100644 --- a/drivers/dma/shdma.c +++ b/drivers/dma/shdma.c @@ -73,7 +73,7 @@ static void sh_dmae_ctl_stop(int id) { unsigned short dmaor = dmaor_read_reg(id); - dmaor &= ~(DMAOR_NMIF | DMAOR_AE); + dmaor &= ~(DMAOR_NMIF | DMAOR_AE | DMAOR_DME); dmaor_write_reg(id, dmaor); } @@ -86,7 +86,7 @@ static int sh_dmae_rst(int id) dmaor_write_reg(id, dmaor); if (dmaor_read_reg(id) & (DMAOR_AE | DMAOR_NMIF)) { - pr_warning(KERN_ERR "dma-sh: Can't initialize DMAOR.\n"); + pr_warning("dma-sh: Can't initialize DMAOR.\n"); return -EINVAL; } return 0; @@ -661,7 +661,7 @@ static void sh_dmae_chan_ld_cleanup(struct sh_dmae_chan *sh_chan, bool all) static void sh_chan_xfer_ld_queue(struct sh_dmae_chan *sh_chan) { - struct sh_desc *sd; + struct sh_desc *desc; spin_lock_bh(&sh_chan->desc_lock); /* DMA work check */ @@ -671,10 +671,10 @@ static void sh_chan_xfer_ld_queue(struct sh_dmae_chan *sh_chan) } /* Find the first not transferred desciptor */ - list_for_each_entry(sd, &sh_chan->ld_queue, node) - if (sd->mark == DESC_SUBMITTED) { + list_for_each_entry(desc, &sh_chan->ld_queue, node) + if (desc->mark == DESC_SUBMITTED) { /* Get the ld start address from ld_queue */ - dmae_set_reg(sh_chan, &sd->hw); + dmae_set_reg(sh_chan, &desc->hw); dmae_start(sh_chan); break; } @@ -696,6 +696,7 @@ static enum dma_status sh_dmae_is_complete(struct dma_chan *chan, struct sh_dmae_chan *sh_chan = to_sh_chan(chan); dma_cookie_t last_used; dma_cookie_t last_complete; + enum dma_status status; sh_dmae_chan_ld_cleanup(sh_chan, false); @@ -709,7 +710,27 @@ static enum dma_status sh_dmae_is_complete(struct dma_chan *chan, if (used) *used = last_used; - return dma_async_is_complete(cookie, last_complete, last_used); + spin_lock_bh(&sh_chan->desc_lock); + + status = dma_async_is_complete(cookie, last_complete, last_used); + + /* + * If we don't find cookie on the queue, it has been aborted and we have + * to report error + */ + if (status != DMA_SUCCESS) { + struct sh_desc *desc; + status = DMA_ERROR; + list_for_each_entry(desc, &sh_chan->ld_queue, node) + if (desc->cookie == cookie) { + status = DMA_IN_PROGRESS; + break; + } + } + + spin_unlock_bh(&sh_chan->desc_lock); + + return status; } static irqreturn_t sh_dmae_interrupt(int irq, void *data) @@ -732,40 +753,36 @@ static irqreturn_t sh_dmae_interrupt(int irq, void *data) #if defined(CONFIG_CPU_SH4) static irqreturn_t sh_dmae_err(int irq, void *data) { - int err = 0; struct sh_dmae_device *shdev = (struct sh_dmae_device *)data; + int i; - /* IRQ Multi */ - if (shdev->pdata.mode & SHDMA_MIX_IRQ) { - int __maybe_unused cnt = 0; - switch (irq) { -#if defined(DMTE6_IRQ) && defined(DMAE1_IRQ) - case DMTE6_IRQ: - cnt++; -#endif - case DMTE0_IRQ: - if (dmaor_read_reg(cnt) & (DMAOR_NMIF | DMAOR_AE)) { - disable_irq(irq); - return IRQ_HANDLED; + /* halt the dma controller */ + sh_dmae_ctl_stop(0); + if (shdev->pdata.mode & SHDMA_DMAOR1) + sh_dmae_ctl_stop(1); + + /* We cannot detect, which channel caused the error, have to reset all */ + for (i = 0; i < MAX_DMA_CHANNELS; i++) { + struct sh_dmae_chan *sh_chan = shdev->chan[i]; + if (sh_chan) { + struct sh_desc *desc; + /* Stop the channel */ + dmae_halt(sh_chan); + /* Complete all */ + list_for_each_entry(desc, &sh_chan->ld_queue, node) { + struct dma_async_tx_descriptor *tx = &desc->async_tx; + desc->mark = DESC_IDLE; + if (tx->callback) + tx->callback(tx->callback_param); } - default: - return IRQ_NONE; + list_splice_init(&sh_chan->ld_queue, &sh_chan->ld_free); } - } else { - /* reset dma controller */ - err = sh_dmae_rst(0); - if (err) - return err; -#ifdef SH_DMAC_BASE1 - if (shdev->pdata.mode & SHDMA_DMAOR1) { - err = sh_dmae_rst(1); - if (err) - return err; - } -#endif - disable_irq(irq); - return IRQ_HANDLED; } + sh_dmae_rst(0); + if (shdev->pdata.mode & SHDMA_DMAOR1) + sh_dmae_rst(1); + + return IRQ_HANDLED; } #endif -- cgit v1.2.3-70-g09d2 From 027811b9b81a6b3ae5aa20c3302897bee9dcf09e Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Thu, 11 Feb 2010 16:50:10 +0000 Subject: dmaengine: shdma: convert to platform device resources The shdma dmaengine driver currently uses numerous macros to support various platforms, selected by ifdef's. Convert it to use platform device resources and lists of channel descriptors to specify register locations, interrupt numbers and other system-specific configuration variants. Unavoidably, we have to simultaneously convert all shdma users to provide those resources. Signed-off-by: Guennadi Liakhovetski Signed-off-by: Paul Mundt --- arch/sh/include/asm/dma-sh.h | 13 +- arch/sh/kernel/cpu/sh4a/setup-sh7722.c | 70 +++++++- arch/sh/kernel/cpu/sh4a/setup-sh7724.c | 159 ++++++++++++++++- arch/sh/kernel/cpu/sh4a/setup-sh7780.c | 113 +++++++++++- arch/sh/kernel/cpu/sh4a/setup-sh7785.c | 113 +++++++++++- drivers/dma/shdma.c | 318 ++++++++++++++++++++------------- drivers/dma/shdma.h | 6 +- 7 files changed, 636 insertions(+), 156 deletions(-) (limited to 'drivers') diff --git a/arch/sh/include/asm/dma-sh.h b/arch/sh/include/asm/dma-sh.h index e934a2e6665..2e3631d6e27 100644 --- a/arch/sh/include/asm/dma-sh.h +++ b/arch/sh/include/asm/dma-sh.h @@ -154,10 +154,17 @@ struct sh_dmae_slave_config { char mid_rid; }; +struct sh_dmae_channel { + unsigned int offset; + unsigned int dmars; + unsigned int dmars_bit; +}; + struct sh_dmae_pdata { - unsigned int mode; - struct sh_dmae_slave_config *config; - int config_num; + struct sh_dmae_slave_config *slave; + int slave_num; + struct sh_dmae_channel *channel; + int channel_num; }; struct device; diff --git a/arch/sh/kernel/cpu/sh4a/setup-sh7722.c b/arch/sh/kernel/cpu/sh4a/setup-sh7722.c index 538280a3dc6..aec182bed8a 100644 --- a/arch/sh/kernel/cpu/sh4a/setup-sh7722.c +++ b/arch/sh/kernel/cpu/sh4a/setup-sh7722.c @@ -75,15 +75,79 @@ static struct sh_dmae_slave_config sh7722_dmae_slaves[] = { }, }; +static struct sh_dmae_channel sh7722_dmae_channels[] = { + { + .offset = 0, + .dmars = 0, + .dmars_bit = 0, + }, { + .offset = 0x10, + .dmars = 0, + .dmars_bit = 8, + }, { + .offset = 0x20, + .dmars = 4, + .dmars_bit = 0, + }, { + .offset = 0x30, + .dmars = 4, + .dmars_bit = 8, + }, { + .offset = 0x50, + .dmars = 8, + .dmars_bit = 0, + }, { + .offset = 0x60, + .dmars = 8, + .dmars_bit = 8, + } +}; + static struct sh_dmae_pdata dma_platform_data = { - .mode = 0, - .config = sh7722_dmae_slaves, - .config_num = ARRAY_SIZE(sh7722_dmae_slaves), + .slave = sh7722_dmae_slaves, + .slave_num = ARRAY_SIZE(sh7722_dmae_slaves), + .channel = sh7722_dmae_channels, + .channel_num = ARRAY_SIZE(sh7722_dmae_channels), +}; + +static struct resource sh7722_dmae_resources[] = { + [0] = { + /* Channel registers and DMAOR */ + .start = 0xfe008020, + .end = 0xfe00808f, + .flags = IORESOURCE_MEM, + }, + [1] = { + /* DMARSx */ + .start = 0xfe009000, + .end = 0xfe00900b, + .flags = IORESOURCE_MEM, + }, + { + /* DMA error IRQ */ + .start = 78, + .end = 78, + .flags = IORESOURCE_IRQ, + }, + { + /* IRQ for channels 0-3 */ + .start = 48, + .end = 51, + .flags = IORESOURCE_IRQ, + }, + { + /* IRQ for channels 4-5 */ + .start = 76, + .end = 77, + .flags = IORESOURCE_IRQ, + }, }; struct platform_device dma_device = { .name = "sh-dma-engine", .id = -1, + .resource = sh7722_dmae_resources, + .num_resources = ARRAY_SIZE(sh7722_dmae_resources), .dev = { .platform_data = &dma_platform_data, }, diff --git a/arch/sh/kernel/cpu/sh4a/setup-sh7724.c b/arch/sh/kernel/cpu/sh4a/setup-sh7724.c index 31e3451f7e3..aca1fb2c571 100644 --- a/arch/sh/kernel/cpu/sh4a/setup-sh7724.c +++ b/arch/sh/kernel/cpu/sh4a/setup-sh7724.c @@ -28,15 +28,157 @@ #include /* DMA */ -static struct sh_dmae_pdata dma_platform_data = { - .mode = SHDMA_DMAOR1, +static struct sh_dmae_channel sh7724_dmae0_channels[] = { + { + .offset = 0, + .dmars = 0, + .dmars_bit = 0, + }, { + .offset = 0x10, + .dmars = 0, + .dmars_bit = 8, + }, { + .offset = 0x20, + .dmars = 4, + .dmars_bit = 0, + }, { + .offset = 0x30, + .dmars = 4, + .dmars_bit = 8, + }, { + .offset = 0x50, + .dmars = 8, + .dmars_bit = 0, + }, { + .offset = 0x60, + .dmars = 8, + .dmars_bit = 8, + } +}; + +static struct sh_dmae_channel sh7724_dmae1_channels[] = { + { + .offset = 0, + .dmars = 0, + .dmars_bit = 0, + }, { + .offset = 0x10, + .dmars = 0, + .dmars_bit = 8, + }, { + .offset = 0x20, + .dmars = 4, + .dmars_bit = 0, + }, { + .offset = 0x30, + .dmars = 4, + .dmars_bit = 8, + }, { + .offset = 0x50, + .dmars = 8, + .dmars_bit = 0, + }, { + .offset = 0x60, + .dmars = 8, + .dmars_bit = 8, + } +}; + +static struct sh_dmae_pdata dma0_platform_data = { + .channel = sh7724_dmae0_channels, + .channel_num = ARRAY_SIZE(sh7724_dmae0_channels), +}; + +static struct sh_dmae_pdata dma1_platform_data = { + .channel = sh7724_dmae1_channels, + .channel_num = ARRAY_SIZE(sh7724_dmae1_channels), +}; + +/* Resource order important! */ +static struct resource sh7724_dmae0_resources[] = { + { + /* Channel registers and DMAOR */ + .start = 0xfe008020, + .end = 0xfe00808f, + .flags = IORESOURCE_MEM, + }, + { + /* DMARSx */ + .start = 0xfe009000, + .end = 0xfe00900b, + .flags = IORESOURCE_MEM, + }, + { + /* DMA error IRQ */ + .start = 78, + .end = 78, + .flags = IORESOURCE_IRQ, + }, + { + /* IRQ for channels 0-3 */ + .start = 48, + .end = 51, + .flags = IORESOURCE_IRQ, + }, + { + /* IRQ for channels 4-5 */ + .start = 76, + .end = 77, + .flags = IORESOURCE_IRQ, + }, }; -static struct platform_device dma_device = { - .name = "sh-dma-engine", - .id = -1, - .dev = { - .platform_data = &dma_platform_data, +/* Resource order important! */ +static struct resource sh7724_dmae1_resources[] = { + { + /* Channel registers and DMAOR */ + .start = 0xfdc08020, + .end = 0xfdc0808f, + .flags = IORESOURCE_MEM, + }, + { + /* DMARSx */ + .start = 0xfdc09000, + .end = 0xfdc0900b, + .flags = IORESOURCE_MEM, + }, + { + /* DMA error IRQ */ + .start = 74, + .end = 74, + .flags = IORESOURCE_IRQ, + }, + { + /* IRQ for channels 0-3 */ + .start = 40, + .end = 43, + .flags = IORESOURCE_IRQ, + }, + { + /* IRQ for channels 4-5 */ + .start = 72, + .end = 73, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device dma0_device = { + .name = "sh-dma-engine", + .id = 0, + .resource = sh7724_dmae0_resources, + .num_resources = ARRAY_SIZE(sh7724_dmae0_resources), + .dev = { + .platform_data = &dma0_platform_data, + }, +}; + +static struct platform_device dma1_device = { + .name = "sh-dma-engine", + .id = 1, + .resource = sh7724_dmae1_resources, + .num_resources = ARRAY_SIZE(sh7724_dmae1_resources), + .dev = { + .platform_data = &dma1_platform_data, }, }; @@ -663,7 +805,8 @@ static struct platform_device *sh7724_devices[] __initdata = { &tmu3_device, &tmu4_device, &tmu5_device, - &dma_device, + &dma0_device, + &dma1_device, &rtc_device, &iic0_device, &iic1_device, diff --git a/arch/sh/kernel/cpu/sh4a/setup-sh7780.c b/arch/sh/kernel/cpu/sh4a/setup-sh7780.c index f8f21618d78..338dfc2c2bb 100644 --- a/arch/sh/kernel/cpu/sh4a/setup-sh7780.c +++ b/arch/sh/kernel/cpu/sh4a/setup-sh7780.c @@ -247,15 +247,115 @@ static struct platform_device rtc_device = { .resource = rtc_resources, }; -static struct sh_dmae_pdata dma_platform_data = { - .mode = (SHDMA_MIX_IRQ | SHDMA_DMAOR1), +/* DMA */ +static struct sh_dmae_channel sh7780_dmae0_channels[] = { + { + .offset = 0, + .dmars = 0, + .dmars_bit = 0, + }, { + .offset = 0x10, + .dmars = 0, + .dmars_bit = 8, + }, { + .offset = 0x20, + .dmars = 4, + .dmars_bit = 0, + }, { + .offset = 0x30, + .dmars = 4, + .dmars_bit = 8, + }, { + .offset = 0x50, + .dmars = 8, + .dmars_bit = 0, + }, { + .offset = 0x60, + .dmars = 8, + .dmars_bit = 8, + } +}; + +static struct sh_dmae_channel sh7780_dmae1_channels[] = { + { + .offset = 0, + }, { + .offset = 0x10, + }, { + .offset = 0x20, + }, { + .offset = 0x30, + }, { + .offset = 0x50, + }, { + .offset = 0x60, + } +}; + +static struct sh_dmae_pdata dma0_platform_data = { + .channel = sh7780_dmae0_channels, + .channel_num = ARRAY_SIZE(sh7780_dmae0_channels), +}; + +static struct sh_dmae_pdata dma1_platform_data = { + .channel = sh7780_dmae1_channels, + .channel_num = ARRAY_SIZE(sh7780_dmae1_channels), +}; + +static struct resource sh7780_dmae0_resources[] = { + [0] = { + /* Channel registers and DMAOR */ + .start = 0xfc808020, + .end = 0xfc80808f, + .flags = IORESOURCE_MEM, + }, + [1] = { + /* DMARSx */ + .start = 0xfc809000, + .end = 0xfc80900b, + .flags = IORESOURCE_MEM, + }, + { + /* Real DMA error IRQ is 38, and channel IRQs are 34-37, 44-45 */ + .start = 34, + .end = 34, + .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_SHAREABLE, + }, +}; + +static struct resource sh7780_dmae1_resources[] = { + [0] = { + /* Channel registers and DMAOR */ + .start = 0xfc818020, + .end = 0xfc81808f, + .flags = IORESOURCE_MEM, + }, + /* DMAC1 has no DMARS */ + { + /* Real DMA error IRQ is 38, and channel IRQs are 46-47, 92-95 */ + .start = 46, + .end = 46, + .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_SHAREABLE, + }, }; -static struct platform_device dma_device = { +static struct platform_device dma0_device = { .name = "sh-dma-engine", - .id = -1, + .id = 0, + .resource = sh7780_dmae0_resources, + .num_resources = ARRAY_SIZE(sh7780_dmae0_resources), .dev = { - .platform_data = &dma_platform_data, + .platform_data = &dma0_platform_data, + }, +}; + +static struct platform_device dma1_device = { + .name = "sh-dma-engine", + .id = 1, + .resource = sh7780_dmae1_resources, + .num_resources = ARRAY_SIZE(sh7780_dmae1_resources), + .dev = { + .platform_data = &dma1_platform_data, }, }; @@ -269,7 +369,8 @@ static struct platform_device *sh7780_devices[] __initdata = { &tmu4_device, &tmu5_device, &rtc_device, - &dma_device, + &dma0_device, + &dma1_device, }; static int __init sh7780_devices_setup(void) diff --git a/arch/sh/kernel/cpu/sh4a/setup-sh7785.c b/arch/sh/kernel/cpu/sh4a/setup-sh7785.c index 23448d8c671..fbb5d1f51f1 100644 --- a/arch/sh/kernel/cpu/sh4a/setup-sh7785.c +++ b/arch/sh/kernel/cpu/sh4a/setup-sh7785.c @@ -295,15 +295,115 @@ static struct platform_device tmu5_device = { .num_resources = ARRAY_SIZE(tmu5_resources), }; -static struct sh_dmae_pdata dma_platform_data = { - .mode = (SHDMA_MIX_IRQ | SHDMA_DMAOR1), +/* DMA */ +static struct sh_dmae_channel sh7785_dmae0_channels[] = { + { + .offset = 0, + .dmars = 0, + .dmars_bit = 0, + }, { + .offset = 0x10, + .dmars = 0, + .dmars_bit = 8, + }, { + .offset = 0x20, + .dmars = 4, + .dmars_bit = 0, + }, { + .offset = 0x30, + .dmars = 4, + .dmars_bit = 8, + }, { + .offset = 0x50, + .dmars = 8, + .dmars_bit = 0, + }, { + .offset = 0x60, + .dmars = 8, + .dmars_bit = 8, + } +}; + +static struct sh_dmae_channel sh7785_dmae1_channels[] = { + { + .offset = 0, + }, { + .offset = 0x10, + }, { + .offset = 0x20, + }, { + .offset = 0x30, + }, { + .offset = 0x50, + }, { + .offset = 0x60, + } +}; + +static struct sh_dmae_pdata dma0_platform_data = { + .channel = sh7785_dmae0_channels, + .channel_num = ARRAY_SIZE(sh7785_dmae0_channels), +}; + +static struct sh_dmae_pdata dma1_platform_data = { + .channel = sh7785_dmae1_channels, + .channel_num = ARRAY_SIZE(sh7785_dmae1_channels), +}; + +static struct resource sh7785_dmae0_resources[] = { + [0] = { + /* Channel registers and DMAOR */ + .start = 0xfc808020, + .end = 0xfc80808f, + .flags = IORESOURCE_MEM, + }, + [1] = { + /* DMARSx */ + .start = 0xfc809000, + .end = 0xfc80900b, + .flags = IORESOURCE_MEM, + }, + { + /* Real DMA error IRQ is 39, and channel IRQs are 33-38 */ + .start = 33, + .end = 33, + .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_SHAREABLE, + }, +}; + +static struct resource sh7785_dmae1_resources[] = { + [0] = { + /* Channel registers and DMAOR */ + .start = 0xfcc08020, + .end = 0xfcc0808f, + .flags = IORESOURCE_MEM, + }, + /* DMAC1 has no DMARS */ + { + /* Real DMA error IRQ is 58, and channel IRQs are 52-57 */ + .start = 52, + .end = 52, + .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_SHAREABLE, + }, }; -static struct platform_device dma_device = { +static struct platform_device dma0_device = { .name = "sh-dma-engine", - .id = -1, + .id = 0, + .resource = sh7785_dmae0_resources, + .num_resources = ARRAY_SIZE(sh7785_dmae0_resources), .dev = { - .platform_data = &dma_platform_data, + .platform_data = &dma0_platform_data, + }, +}; + +static struct platform_device dma1_device = { + .name = "sh-dma-engine", + .id = 1, + .resource = sh7785_dmae1_resources, + .num_resources = ARRAY_SIZE(sh7785_dmae1_resources), + .dev = { + .platform_data = &dma1_platform_data, }, }; @@ -320,7 +420,8 @@ static struct platform_device *sh7785_devices[] __initdata = { &tmu3_device, &tmu4_device, &tmu5_device, - &dma_device, + &dma0_device, + &dma1_device, }; static int __init sh7785_devices_setup(void) diff --git a/drivers/dma/shdma.c b/drivers/dma/shdma.c index 77311698c04..ab12fa5a129 100644 --- a/drivers/dma/shdma.c +++ b/drivers/dma/shdma.c @@ -53,15 +53,24 @@ static unsigned long sh_dmae_slave_used[BITS_TO_LONGS(SHDMA_SLAVE_NUMBER)]; static void sh_dmae_chan_ld_cleanup(struct sh_dmae_chan *sh_chan, bool all); -#define SH_DMAC_CHAN_BASE(id) (dma_base_addr[id]) static void sh_dmae_writel(struct sh_dmae_chan *sh_dc, u32 data, u32 reg) { - ctrl_outl(data, SH_DMAC_CHAN_BASE(sh_dc->id) + reg); + __raw_writel(data, sh_dc->base + reg / sizeof(u32)); } static u32 sh_dmae_readl(struct sh_dmae_chan *sh_dc, u32 reg) { - return ctrl_inl(SH_DMAC_CHAN_BASE(sh_dc->id) + reg); + return __raw_readl(sh_dc->base + reg / sizeof(u32)); +} + +static u16 dmaor_read(struct sh_dmae_device *shdev) +{ + return __raw_readw(shdev->chan_reg + DMAOR / sizeof(u32)); +} + +static void dmaor_write(struct sh_dmae_device *shdev, u16 data) +{ + __raw_writew(data, shdev->chan_reg + DMAOR / sizeof(u32)); } /* @@ -69,23 +78,22 @@ static u32 sh_dmae_readl(struct sh_dmae_chan *sh_dc, u32 reg) * * SH7780 has two DMAOR register */ -static void sh_dmae_ctl_stop(int id) +static void sh_dmae_ctl_stop(struct sh_dmae_device *shdev) { - unsigned short dmaor = dmaor_read_reg(id); + unsigned short dmaor = dmaor_read(shdev); - dmaor &= ~(DMAOR_NMIF | DMAOR_AE | DMAOR_DME); - dmaor_write_reg(id, dmaor); + dmaor_write(shdev, dmaor & ~(DMAOR_NMIF | DMAOR_AE | DMAOR_DME)); } -static int sh_dmae_rst(int id) +static int sh_dmae_rst(struct sh_dmae_device *shdev) { unsigned short dmaor; - sh_dmae_ctl_stop(id); - dmaor = dmaor_read_reg(id) | DMAOR_INIT; + sh_dmae_ctl_stop(shdev); + dmaor = dmaor_read(shdev) | DMAOR_INIT; - dmaor_write_reg(id, dmaor); - if (dmaor_read_reg(id) & (DMAOR_AE | DMAOR_NMIF)) { + dmaor_write(shdev, dmaor); + if (dmaor_read(shdev) & (DMAOR_AE | DMAOR_NMIF)) { pr_warning("dma-sh: Can't initialize DMAOR.\n"); return -EINVAL; } @@ -153,31 +161,20 @@ static int dmae_set_chcr(struct sh_dmae_chan *sh_chan, u32 val) return 0; } -#define DMARS_SHIFT 8 -#define DMARS_CHAN_MSK 0x01 static int dmae_set_dmars(struct sh_dmae_chan *sh_chan, u16 val) { - u32 addr; - int shift = 0; + struct sh_dmae_device *shdev = container_of(sh_chan->common.device, + struct sh_dmae_device, common); + struct sh_dmae_pdata *pdata = shdev->pdata; + struct sh_dmae_channel *chan_pdata = &pdata->channel[sh_chan->id]; + u16 __iomem *addr = shdev->dmars + chan_pdata->dmars / sizeof(u16); + int shift = chan_pdata->dmars_bit; if (dmae_is_busy(sh_chan)) return -EBUSY; - if (sh_chan->id & DMARS_CHAN_MSK) - shift = DMARS_SHIFT; - - if (sh_chan->id < 6) - /* DMA0RS0 - DMA0RS2 */ - addr = SH_DMARS_BASE0 + (sh_chan->id / 2) * 4; -#ifdef SH_DMARS_BASE1 - else if (sh_chan->id < 12) - /* DMA1RS0 - DMA1RS2 */ - addr = SH_DMARS_BASE1 + ((sh_chan->id - 6) / 2) * 4; -#endif - else - return -EINVAL; - - ctrl_outw((val << shift) | (ctrl_inw(addr) & (0xFF00 >> shift)), addr); + __raw_writew((__raw_readw(addr) & (0xff00 >> shift)) | (val << shift), + addr); return 0; } @@ -251,15 +248,15 @@ static struct sh_dmae_slave_config *sh_dmae_find_slave( struct dma_device *dma_dev = sh_chan->common.device; struct sh_dmae_device *shdev = container_of(dma_dev, struct sh_dmae_device, common); - struct sh_dmae_pdata *pdata = &shdev->pdata; + struct sh_dmae_pdata *pdata = shdev->pdata; int i; if ((unsigned)slave_id >= SHDMA_SLAVE_NUMBER) return NULL; - for (i = 0; i < pdata->config_num; i++) - if (pdata->config[i].slave_id == slave_id) - return pdata->config + i; + for (i = 0; i < pdata->slave_num; i++) + if (pdata->slave[i].slave_id == slave_id) + return pdata->slave + i; return NULL; } @@ -757,9 +754,7 @@ static irqreturn_t sh_dmae_err(int irq, void *data) int i; /* halt the dma controller */ - sh_dmae_ctl_stop(0); - if (shdev->pdata.mode & SHDMA_DMAOR1) - sh_dmae_ctl_stop(1); + sh_dmae_ctl_stop(shdev); /* We cannot detect, which channel caused the error, have to reset all */ for (i = 0; i < MAX_DMA_CHANNELS; i++) { @@ -778,9 +773,7 @@ static irqreturn_t sh_dmae_err(int irq, void *data) list_splice_init(&sh_chan->ld_queue, &sh_chan->ld_free); } } - sh_dmae_rst(0); - if (shdev->pdata.mode & SHDMA_DMAOR1) - sh_dmae_rst(1); + sh_dmae_rst(shdev); return IRQ_HANDLED; } @@ -813,19 +806,12 @@ static void dmae_do_tasklet(unsigned long data) sh_dmae_chan_ld_cleanup(sh_chan, false); } -static unsigned int get_dmae_irq(unsigned int id) -{ - unsigned int irq = 0; - if (id < ARRAY_SIZE(dmte_irq_map)) - irq = dmte_irq_map[id]; - return irq; -} - -static int __devinit sh_dmae_chan_probe(struct sh_dmae_device *shdev, int id) +static int __devinit sh_dmae_chan_probe(struct sh_dmae_device *shdev, int id, + int irq, unsigned long flags) { int err; - unsigned int irq = get_dmae_irq(id); - unsigned long irqflags = IRQF_DISABLED; + struct sh_dmae_channel *chan_pdata = &shdev->pdata->channel[id]; + struct platform_device *pdev = to_platform_device(shdev->common.dev); struct sh_dmae_chan *new_sh_chan; /* alloc channel */ @@ -838,6 +824,8 @@ static int __devinit sh_dmae_chan_probe(struct sh_dmae_device *shdev, int id) new_sh_chan->dev = shdev->common.dev; new_sh_chan->id = id; + new_sh_chan->irq = irq; + new_sh_chan->base = shdev->chan_reg + chan_pdata->offset / sizeof(u32); /* Init DMA tasklet */ tasklet_init(&new_sh_chan->tasklet, dmae_do_tasklet, @@ -860,21 +848,15 @@ static int __devinit sh_dmae_chan_probe(struct sh_dmae_device *shdev, int id) &shdev->common.channels); shdev->common.chancnt++; - if (shdev->pdata.mode & SHDMA_MIX_IRQ) { - irqflags = IRQF_SHARED; -#if defined(DMTE6_IRQ) - if (irq >= DMTE6_IRQ) - irq = DMTE6_IRQ; - else -#endif - irq = DMTE0_IRQ; - } - - snprintf(new_sh_chan->dev_id, sizeof(new_sh_chan->dev_id), - "sh-dmae%d", new_sh_chan->id); + if (pdev->id >= 0) + snprintf(new_sh_chan->dev_id, sizeof(new_sh_chan->dev_id), + "sh-dmae%d.%d", pdev->id, new_sh_chan->id); + else + snprintf(new_sh_chan->dev_id, sizeof(new_sh_chan->dev_id), + "sh-dma%d", new_sh_chan->id); /* set up channel irq */ - err = request_irq(irq, &sh_dmae_interrupt, irqflags, + err = request_irq(irq, &sh_dmae_interrupt, flags, new_sh_chan->dev_id, new_sh_chan); if (err) { dev_err(shdev->common.dev, "DMA channel %d request_irq error " @@ -898,12 +880,12 @@ static void sh_dmae_chan_remove(struct sh_dmae_device *shdev) for (i = shdev->common.chancnt - 1 ; i >= 0 ; i--) { if (shdev->chan[i]) { - struct sh_dmae_chan *shchan = shdev->chan[i]; - if (!(shdev->pdata.mode & SHDMA_MIX_IRQ)) - free_irq(dmte_irq_map[i], shchan); + struct sh_dmae_chan *sh_chan = shdev->chan[i]; + + free_irq(sh_chan->irq, sh_chan); - list_del(&shchan->common.device_node); - kfree(shchan); + list_del(&sh_chan->common.device_node); + kfree(sh_chan); shdev->chan[i] = NULL; } } @@ -912,47 +894,81 @@ static void sh_dmae_chan_remove(struct sh_dmae_device *shdev) static int __init sh_dmae_probe(struct platform_device *pdev) { - int err = 0, cnt, ecnt; - unsigned long irqflags = IRQF_DISABLED; -#if defined(CONFIG_CPU_SH4) - int eirq[] = { DMAE0_IRQ, -#if defined(DMAE1_IRQ) - DMAE1_IRQ -#endif - }; -#endif + struct sh_dmae_pdata *pdata = pdev->dev.platform_data; + unsigned long irqflags = IRQF_DISABLED, + chan_flag[MAX_DMA_CHANNELS] = {}; + int errirq, chan_irq[MAX_DMA_CHANNELS]; + int err, i, irq_cnt = 0, irqres = 0; struct sh_dmae_device *shdev; + struct resource *chan, *dmars, *errirq_res, *chanirq_res; /* get platform data */ - if (!pdev->dev.platform_data) + if (!pdata || !pdata->channel_num) return -ENODEV; + chan = platform_get_resource(pdev, IORESOURCE_MEM, 0); + /* DMARS area is optional, if absent, this controller cannot do slave DMA */ + dmars = platform_get_resource(pdev, IORESOURCE_MEM, 1); + /* + * IRQ resources: + * 1. there always must be at least one IRQ IO-resource. On SH4 it is + * the error IRQ, in which case it is the only IRQ in this resource: + * start == end. If it is the only IRQ resource, all channels also + * use the same IRQ. + * 2. DMA channel IRQ resources can be specified one per resource or in + * ranges (start != end) + * 3. iff all events (channels and, optionally, error) on this + * controller use the same IRQ, only one IRQ resource can be + * specified, otherwise there must be one IRQ per channel, even if + * some of them are equal + * 4. if all IRQs on this controller are equal or if some specific IRQs + * specify IORESOURCE_IRQ_SHAREABLE in their resources, they will be + * requested with the IRQF_SHARED flag + */ + errirq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); + if (!chan || !errirq_res) + return -ENODEV; + + if (!request_mem_region(chan->start, resource_size(chan), pdev->name)) { + dev_err(&pdev->dev, "DMAC register region already claimed\n"); + return -EBUSY; + } + + if (dmars && !request_mem_region(dmars->start, resource_size(dmars), pdev->name)) { + dev_err(&pdev->dev, "DMAC DMARS region already claimed\n"); + err = -EBUSY; + goto ermrdmars; + } + + err = -ENOMEM; shdev = kzalloc(sizeof(struct sh_dmae_device), GFP_KERNEL); if (!shdev) { - dev_err(&pdev->dev, "No enough memory\n"); - return -ENOMEM; + dev_err(&pdev->dev, "Not enough memory\n"); + goto ealloc; + } + + shdev->chan_reg = ioremap(chan->start, resource_size(chan)); + if (!shdev->chan_reg) + goto emapchan; + if (dmars) { + shdev->dmars = ioremap(dmars->start, resource_size(dmars)); + if (!shdev->dmars) + goto emapdmars; } /* platform data */ - memcpy(&shdev->pdata, pdev->dev.platform_data, - sizeof(struct sh_dmae_pdata)); + shdev->pdata = pdata; /* reset dma controller */ - err = sh_dmae_rst(0); + err = sh_dmae_rst(shdev); if (err) goto rst_err; - /* SH7780/85/23 has DMAOR1 */ - if (shdev->pdata.mode & SHDMA_DMAOR1) { - err = sh_dmae_rst(1); - if (err) - goto rst_err; - } - INIT_LIST_HEAD(&shdev->common.channels); dma_cap_set(DMA_MEMCPY, shdev->common.cap_mask); - dma_cap_set(DMA_SLAVE, shdev->common.cap_mask); + if (dmars) + dma_cap_set(DMA_SLAVE, shdev->common.cap_mask); shdev->common.device_alloc_chan_resources = sh_dmae_alloc_chan_resources; @@ -970,30 +986,63 @@ static int __init sh_dmae_probe(struct platform_device *pdev) shdev->common.copy_align = 5; #if defined(CONFIG_CPU_SH4) - /* Non Mix IRQ mode SH7722/SH7730 etc... */ - if (shdev->pdata.mode & SHDMA_MIX_IRQ) { + chanirq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 1); + + if (!chanirq_res) + chanirq_res = errirq_res; + else + irqres++; + + if (chanirq_res == errirq_res || + (errirq_res->flags & IORESOURCE_BITS) == IORESOURCE_IRQ_SHAREABLE) irqflags = IRQF_SHARED; - eirq[0] = DMTE0_IRQ; -#if defined(DMTE6_IRQ) && defined(DMAE1_IRQ) - eirq[1] = DMTE6_IRQ; -#endif + + errirq = errirq_res->start; + + err = request_irq(errirq, sh_dmae_err, irqflags, + "DMAC Address Error", shdev); + if (err) { + dev_err(&pdev->dev, + "DMA failed requesting irq #%d, error %d\n", + errirq, err); + goto eirq_err; } - for (ecnt = 0 ; ecnt < ARRAY_SIZE(eirq); ecnt++) { - err = request_irq(eirq[ecnt], sh_dmae_err, irqflags, - "DMAC Address Error", shdev); - if (err) { - dev_err(&pdev->dev, "DMA device request_irq" - "error (irq %d) with return %d\n", - eirq[ecnt], err); - goto eirq_err; +#else + chanirq_res = errirq_res; +#endif /* CONFIG_CPU_SH4 */ + + if (chanirq_res->start == chanirq_res->end && + !platform_get_resource(pdev, IORESOURCE_IRQ, 1)) { + /* Special case - all multiplexed */ + for (; irq_cnt < pdata->channel_num; irq_cnt++) { + chan_irq[irq_cnt] = chanirq_res->start; + chan_flag[irq_cnt] = IRQF_SHARED; } + } else { + do { + for (i = chanirq_res->start; i <= chanirq_res->end; i++) { + if ((errirq_res->flags & IORESOURCE_BITS) == + IORESOURCE_IRQ_SHAREABLE) + chan_flag[irq_cnt] = IRQF_SHARED; + else + chan_flag[irq_cnt] = IRQF_DISABLED; + dev_dbg(&pdev->dev, + "Found IRQ %d for channel %d\n", + i, irq_cnt); + chan_irq[irq_cnt++] = i; + } + chanirq_res = platform_get_resource(pdev, + IORESOURCE_IRQ, ++irqres); + } while (irq_cnt < pdata->channel_num && chanirq_res); } -#endif /* CONFIG_CPU_SH4 */ + + if (irq_cnt < pdata->channel_num) + goto eirqres; /* Create DMA Channel */ - for (cnt = 0 ; cnt < MAX_DMA_CHANNELS ; cnt++) { - err = sh_dmae_chan_probe(shdev, cnt); + for (i = 0; i < pdata->channel_num; i++) { + err = sh_dmae_chan_probe(shdev, i, chan_irq[i], chan_flag[i]); if (err) goto chan_probe_err; } @@ -1005,13 +1054,23 @@ static int __init sh_dmae_probe(struct platform_device *pdev) chan_probe_err: sh_dmae_chan_remove(shdev); - +eirqres: +#if defined(CONFIG_CPU_SH4) + free_irq(errirq, shdev); eirq_err: - for (ecnt-- ; ecnt >= 0; ecnt--) - free_irq(eirq[ecnt], shdev); - +#endif rst_err: + if (dmars) + iounmap(shdev->dmars); +emapdmars: + iounmap(shdev->chan_reg); +emapchan: kfree(shdev); +ealloc: + if (dmars) + release_mem_region(dmars->start, resource_size(dmars)); +ermrdmars: + release_mem_region(chan->start, resource_size(chan)); return err; } @@ -1019,36 +1078,37 @@ rst_err: static int __exit sh_dmae_remove(struct platform_device *pdev) { struct sh_dmae_device *shdev = platform_get_drvdata(pdev); + struct resource *res; + int errirq = platform_get_irq(pdev, 0); dma_async_device_unregister(&shdev->common); - if (shdev->pdata.mode & SHDMA_MIX_IRQ) { - free_irq(DMTE0_IRQ, shdev); -#if defined(DMTE6_IRQ) - free_irq(DMTE6_IRQ, shdev); -#endif - } + if (errirq > 0) + free_irq(errirq, shdev); /* channel data remove */ sh_dmae_chan_remove(shdev); - if (!(shdev->pdata.mode & SHDMA_MIX_IRQ)) { - free_irq(DMAE0_IRQ, shdev); -#if defined(DMAE1_IRQ) - free_irq(DMAE1_IRQ, shdev); -#endif - } + if (shdev->dmars) + iounmap(shdev->dmars); + iounmap(shdev->chan_reg); + kfree(shdev); + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (res) + release_mem_region(res->start, resource_size(res)); + res = platform_get_resource(pdev, IORESOURCE_MEM, 1); + if (res) + release_mem_region(res->start, resource_size(res)); + return 0; } static void sh_dmae_shutdown(struct platform_device *pdev) { struct sh_dmae_device *shdev = platform_get_drvdata(pdev); - sh_dmae_ctl_stop(0); - if (shdev->pdata.mode & SHDMA_DMAOR1) - sh_dmae_ctl_stop(1); + sh_dmae_ctl_stop(shdev); } static struct platform_driver sh_dmae_driver = { diff --git a/drivers/dma/shdma.h b/drivers/dma/shdma.h index 7e227f3c87c..800fd884be8 100644 --- a/drivers/dma/shdma.h +++ b/drivers/dma/shdma.h @@ -47,14 +47,18 @@ struct sh_dmae_chan { struct tasklet_struct tasklet; /* Tasklet */ int descs_allocated; /* desc count */ int xmit_shift; /* log_2(bytes_per_xfer) */ + int irq; int id; /* Raw id of this channel */ + u32 __iomem *base; char dev_id[16]; /* unique name per DMAC of channel */ }; struct sh_dmae_device { struct dma_device common; struct sh_dmae_chan *chan[MAX_DMA_CHANNELS]; - struct sh_dmae_pdata pdata; + struct sh_dmae_pdata *pdata; + u32 __iomem *chan_reg; + u16 __iomem *dmars; }; #define to_sh_chan(chan) container_of(chan, struct sh_dmae_chan, common) -- cgit v1.2.3-70-g09d2 From 8b1935e6a36b0967efc593d67ed3aebbfbc1f5b1 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Thu, 11 Feb 2010 16:50:14 +0000 Subject: dmaengine: shdma: separate DMA headers. Separate SH DMA headers into ones, commonly used by both drivers, and ones, specific to each of them. This will make the future development of the dmaengine driver easier. Signed-off-by: Guennadi Liakhovetski Acked-by: Mark Brown Signed-off-by: Paul Mundt --- arch/sh/include/asm/dma-register.h | 51 +++++++++++++ arch/sh/include/asm/dma-sh.h | 95 +---------------------- arch/sh/include/asm/dmaengine.h | 73 ++++++++++++++++++ arch/sh/include/asm/siu.h | 2 +- arch/sh/include/cpu-sh3/cpu/dma-register.h | 41 ++++++++++ arch/sh/include/cpu-sh3/cpu/dma.h | 27 ------- arch/sh/include/cpu-sh4/cpu/dma-register.h | 116 +++++++++++++++++++++++++++++ arch/sh/include/cpu-sh4/cpu/dma-sh4a.h | 62 --------------- arch/sh/include/cpu-sh4/cpu/dma.h | 36 +-------- arch/sh/kernel/cpu/sh4a/setup-sh7722.c | 20 ++++- arch/sh/kernel/cpu/sh4a/setup-sh7724.c | 21 +++++- arch/sh/kernel/cpu/sh4a/setup-sh7780.c | 21 +++++- arch/sh/kernel/cpu/sh4a/setup-sh7785.c | 21 +++++- drivers/dma/shdma.c | 79 ++++++++++++-------- drivers/dma/shdma.h | 4 +- sound/soc/sh/siu.h | 2 +- sound/soc/sh/siu_pcm.c | 2 +- 17 files changed, 415 insertions(+), 258 deletions(-) create mode 100644 arch/sh/include/asm/dma-register.h create mode 100644 arch/sh/include/asm/dmaengine.h create mode 100644 arch/sh/include/cpu-sh3/cpu/dma-register.h create mode 100644 arch/sh/include/cpu-sh4/cpu/dma-register.h (limited to 'drivers') diff --git a/arch/sh/include/asm/dma-register.h b/arch/sh/include/asm/dma-register.h new file mode 100644 index 00000000000..51cd78feacf --- /dev/null +++ b/arch/sh/include/asm/dma-register.h @@ -0,0 +1,51 @@ +/* + * Common header for the legacy SH DMA driver and the new dmaengine driver + * + * extracted from arch/sh/include/asm/dma-sh.h: + * + * Copyright (C) 2000 Takashi YOSHII + * Copyright (C) 2003 Paul Mundt + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + */ +#ifndef DMA_REGISTER_H +#define DMA_REGISTER_H + +/* DMA register */ +#define SAR 0x00 +#define DAR 0x04 +#define TCR 0x08 +#define CHCR 0x0C +#define DMAOR 0x40 + +/* DMAOR definitions */ +#define DMAOR_AE 0x00000004 +#define DMAOR_NMIF 0x00000002 +#define DMAOR_DME 0x00000001 + +/* Definitions for the SuperH DMAC */ +#define REQ_L 0x00000000 +#define REQ_E 0x00080000 +#define RACK_H 0x00000000 +#define RACK_L 0x00040000 +#define ACK_R 0x00000000 +#define ACK_W 0x00020000 +#define ACK_H 0x00000000 +#define ACK_L 0x00010000 +#define DM_INC 0x00004000 +#define DM_DEC 0x00008000 +#define DM_FIX 0x0000c000 +#define SM_INC 0x00001000 +#define SM_DEC 0x00002000 +#define SM_FIX 0x00003000 +#define RS_IN 0x00000200 +#define RS_OUT 0x00000300 +#define TS_BLK 0x00000040 +#define TM_BUR 0x00000020 +#define CHCR_DE 0x00000001 +#define CHCR_TE 0x00000002 +#define CHCR_IE 0x00000004 + +#endif diff --git a/arch/sh/include/asm/dma-sh.h b/arch/sh/include/asm/dma-sh.h index 2e3631d6e27..f3acb8e34c6 100644 --- a/arch/sh/include/asm/dma-sh.h +++ b/arch/sh/include/asm/dma-sh.h @@ -11,7 +11,8 @@ #ifndef __DMA_SH_H #define __DMA_SH_H -#include +#include +#include #include /* DMAOR contorl: The DMAOR access size is different by CPU.*/ @@ -53,34 +54,6 @@ static int dmte_irq_map[] __maybe_unused = { #endif }; -/* Definitions for the SuperH DMAC */ -#define REQ_L 0x00000000 -#define REQ_E 0x00080000 -#define RACK_H 0x00000000 -#define RACK_L 0x00040000 -#define ACK_R 0x00000000 -#define ACK_W 0x00020000 -#define ACK_H 0x00000000 -#define ACK_L 0x00010000 -#define DM_INC 0x00004000 -#define DM_DEC 0x00008000 -#define DM_FIX 0x0000c000 -#define SM_INC 0x00001000 -#define SM_DEC 0x00002000 -#define SM_FIX 0x00003000 -#define RS_IN 0x00000200 -#define RS_OUT 0x00000300 -#define TS_BLK 0x00000040 -#define TM_BUR 0x00000020 -#define CHCR_DE 0x00000001 -#define CHCR_TE 0x00000002 -#define CHCR_IE 0x00000004 - -/* DMAOR definitions */ -#define DMAOR_AE 0x00000004 -#define DMAOR_NMIF 0x00000002 -#define DMAOR_DME 0x00000001 - /* * Define the default configuration for dual address memory-memory transfer. * The 0x400 value represents auto-request, external->external. @@ -111,68 +84,4 @@ static u32 dma_base_addr[] __maybe_unused = { #endif }; -/* DMA register */ -#define SAR 0x00 -#define DAR 0x04 -#define TCR 0x08 -#define CHCR 0x0C -#define DMAOR 0x40 - -/* - * for dma engine - * - * SuperH DMA mode - */ -#define SHDMA_MIX_IRQ (1 << 1) -#define SHDMA_DMAOR1 (1 << 2) -#define SHDMA_DMAE1 (1 << 3) - -enum sh_dmae_slave_chan_id { - SHDMA_SLAVE_SCIF0_TX, - SHDMA_SLAVE_SCIF0_RX, - SHDMA_SLAVE_SCIF1_TX, - SHDMA_SLAVE_SCIF1_RX, - SHDMA_SLAVE_SCIF2_TX, - SHDMA_SLAVE_SCIF2_RX, - SHDMA_SLAVE_SCIF3_TX, - SHDMA_SLAVE_SCIF3_RX, - SHDMA_SLAVE_SCIF4_TX, - SHDMA_SLAVE_SCIF4_RX, - SHDMA_SLAVE_SCIF5_TX, - SHDMA_SLAVE_SCIF5_RX, - SHDMA_SLAVE_SIUA_TX, - SHDMA_SLAVE_SIUA_RX, - SHDMA_SLAVE_SIUB_TX, - SHDMA_SLAVE_SIUB_RX, - SHDMA_SLAVE_NUMBER, /* Must stay last */ -}; - -struct sh_dmae_slave_config { - enum sh_dmae_slave_chan_id slave_id; - dma_addr_t addr; - u32 chcr; - char mid_rid; -}; - -struct sh_dmae_channel { - unsigned int offset; - unsigned int dmars; - unsigned int dmars_bit; -}; - -struct sh_dmae_pdata { - struct sh_dmae_slave_config *slave; - int slave_num; - struct sh_dmae_channel *channel; - int channel_num; -}; - -struct device; - -struct sh_dmae_slave { - enum sh_dmae_slave_chan_id slave_id; /* Set by the platform */ - struct device *dma_dev; /* Set by the platform */ - struct sh_dmae_slave_config *config; /* Set by the driver */ -}; - #endif /* __DMA_SH_H */ diff --git a/arch/sh/include/asm/dmaengine.h b/arch/sh/include/asm/dmaengine.h new file mode 100644 index 00000000000..9586e4a482b --- /dev/null +++ b/arch/sh/include/asm/dmaengine.h @@ -0,0 +1,73 @@ +/* + * Header for the new SH dmaengine driver + * + * Copyright (C) 2010 Guennadi Liakhovetski + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#ifndef ASM_DMAENGINE_H +#define ASM_DMAENGINE_H + +#include + +#define SH_DMAC_MAX_CHANNELS 6 + +enum sh_dmae_slave_chan_id { + SHDMA_SLAVE_SCIF0_TX, + SHDMA_SLAVE_SCIF0_RX, + SHDMA_SLAVE_SCIF1_TX, + SHDMA_SLAVE_SCIF1_RX, + SHDMA_SLAVE_SCIF2_TX, + SHDMA_SLAVE_SCIF2_RX, + SHDMA_SLAVE_SCIF3_TX, + SHDMA_SLAVE_SCIF3_RX, + SHDMA_SLAVE_SCIF4_TX, + SHDMA_SLAVE_SCIF4_RX, + SHDMA_SLAVE_SCIF5_TX, + SHDMA_SLAVE_SCIF5_RX, + SHDMA_SLAVE_SIUA_TX, + SHDMA_SLAVE_SIUA_RX, + SHDMA_SLAVE_SIUB_TX, + SHDMA_SLAVE_SIUB_RX, + SHDMA_SLAVE_NUMBER, /* Must stay last */ +}; + +struct sh_dmae_slave_config { + enum sh_dmae_slave_chan_id slave_id; + dma_addr_t addr; + u32 chcr; + char mid_rid; +}; + +struct sh_dmae_channel { + unsigned int offset; + unsigned int dmars; + unsigned int dmars_bit; +}; + +struct sh_dmae_pdata { + struct sh_dmae_slave_config *slave; + int slave_num; + struct sh_dmae_channel *channel; + int channel_num; + unsigned int ts_low_shift; + unsigned int ts_low_mask; + unsigned int ts_high_shift; + unsigned int ts_high_mask; + unsigned int *ts_shift; + int ts_shift_num; + u16 dmaor_init; +}; + +struct device; + +/* Used by slave DMA clients to request DMA to/from a specific peripheral */ +struct sh_dmae_slave { + enum sh_dmae_slave_chan_id slave_id; /* Set by the platform */ + struct device *dma_dev; /* Set by the platform */ + struct sh_dmae_slave_config *config; /* Set by the driver */ +}; + +#endif diff --git a/arch/sh/include/asm/siu.h b/arch/sh/include/asm/siu.h index 57565a3b551..f1b1e6944a5 100644 --- a/arch/sh/include/asm/siu.h +++ b/arch/sh/include/asm/siu.h @@ -11,7 +11,7 @@ #ifndef ASM_SIU_H #define ASM_SIU_H -#include +#include struct device; diff --git a/arch/sh/include/cpu-sh3/cpu/dma-register.h b/arch/sh/include/cpu-sh3/cpu/dma-register.h new file mode 100644 index 00000000000..2349e488c9a --- /dev/null +++ b/arch/sh/include/cpu-sh3/cpu/dma-register.h @@ -0,0 +1,41 @@ +/* + * SH3 CPU-specific DMA definitions, used by both DMA drivers + * + * Copyright (C) 2010 Guennadi Liakhovetski + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#ifndef CPU_DMA_REGISTER_H +#define CPU_DMA_REGISTER_H + +#define CHCR_TS_LOW_MASK 0x18 +#define CHCR_TS_LOW_SHIFT 3 +#define CHCR_TS_HIGH_MASK 0 +#define CHCR_TS_HIGH_SHIFT 0 + +#define DMAOR_INIT DMAOR_DME + +/* + * The SuperH DMAC supports a number of transmit sizes, we list them here, + * with their respective values as they appear in the CHCR registers. + */ +enum { + XMIT_SZ_8BIT, + XMIT_SZ_16BIT, + XMIT_SZ_32BIT, + XMIT_SZ_128BIT, +}; + +/* log2(size / 8) - used to calculate number of transfers */ +#define TS_SHIFT { \ + [XMIT_SZ_8BIT] = 0, \ + [XMIT_SZ_16BIT] = 1, \ + [XMIT_SZ_32BIT] = 2, \ + [XMIT_SZ_128BIT] = 4, \ +} + +#define TS_INDEX2VAL(i) (((i) & 3) << CHCR_TS_LOW_SHIFT) + +#endif diff --git a/arch/sh/include/cpu-sh3/cpu/dma.h b/arch/sh/include/cpu-sh3/cpu/dma.h index 207811a7a65..24e28b91c9d 100644 --- a/arch/sh/include/cpu-sh3/cpu/dma.h +++ b/arch/sh/include/cpu-sh3/cpu/dma.h @@ -20,31 +20,4 @@ #define TS_32 0x00000010 #define TS_128 0x00000018 -#define CHCR_TS_LOW_MASK 0x18 -#define CHCR_TS_LOW_SHIFT 3 -#define CHCR_TS_HIGH_MASK 0 -#define CHCR_TS_HIGH_SHIFT 0 - -#define DMAOR_INIT DMAOR_DME - -/* - * The SuperH DMAC supports a number of transmit sizes, we list them here, - * with their respective values as they appear in the CHCR registers. - */ -enum { - XMIT_SZ_8BIT, - XMIT_SZ_16BIT, - XMIT_SZ_32BIT, - XMIT_SZ_128BIT, -}; - -#define TS_SHIFT { \ - [XMIT_SZ_8BIT] = 0, \ - [XMIT_SZ_16BIT] = 1, \ - [XMIT_SZ_32BIT] = 2, \ - [XMIT_SZ_128BIT] = 4, \ -} - -#define TS_INDEX2VAL(i) (((i) & 3) << CHCR_TS_LOW_SHIFT) - #endif /* __ASM_CPU_SH3_DMA_H */ diff --git a/arch/sh/include/cpu-sh4/cpu/dma-register.h b/arch/sh/include/cpu-sh4/cpu/dma-register.h new file mode 100644 index 00000000000..008e7fc8f6c --- /dev/null +++ b/arch/sh/include/cpu-sh4/cpu/dma-register.h @@ -0,0 +1,116 @@ +/* + * SH4 CPU-specific DMA definitions, used by both DMA drivers + * + * Copyright (C) 2010 Guennadi Liakhovetski + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#ifndef CPU_DMA_REGISTER_H +#define CPU_DMA_REGISTER_H + +/* SH7751/7760/7780 DMA IRQ sources */ + +#ifdef CONFIG_CPU_SH4A + +#define DMAOR_INIT DMAOR_DME + +#if defined(CONFIG_CPU_SUBTYPE_SH7343) || \ + defined(CONFIG_CPU_SUBTYPE_SH7730) +#define CHCR_TS_LOW_MASK 0x00000018 +#define CHCR_TS_LOW_SHIFT 3 +#define CHCR_TS_HIGH_MASK 0 +#define CHCR_TS_HIGH_SHIFT 0 +#elif defined(CONFIG_CPU_SUBTYPE_SH7722) +#define CHCR_TS_LOW_MASK 0x00000018 +#define CHCR_TS_LOW_SHIFT 3 +#define CHCR_TS_HIGH_MASK 0x00300000 +#define CHCR_TS_HIGH_SHIFT (20 - 2) /* 2 bits for shifted low TS */ +#elif defined(CONFIG_CPU_SUBTYPE_SH7763) || \ + defined(CONFIG_CPU_SUBTYPE_SH7764) +#define CHCR_TS_LOW_MASK 0x00000018 +#define CHCR_TS_LOW_SHIFT 3 +#define CHCR_TS_HIGH_MASK 0 +#define CHCR_TS_HIGH_SHIFT 0 +#elif defined(CONFIG_CPU_SUBTYPE_SH7723) +#define CHCR_TS_LOW_MASK 0x00000018 +#define CHCR_TS_LOW_SHIFT 3 +#define CHCR_TS_HIGH_MASK 0 +#define CHCR_TS_HIGH_SHIFT 0 +#elif defined(CONFIG_CPU_SUBTYPE_SH7724) +#define CHCR_TS_LOW_MASK 0x00000018 +#define CHCR_TS_LOW_SHIFT 3 +#define CHCR_TS_HIGH_MASK 0x00600000 +#define CHCR_TS_HIGH_SHIFT (20 - 2) /* 2 bits for shifted low TS */ +#elif defined(CONFIG_CPU_SUBTYPE_SH7780) +#define CHCR_TS_LOW_MASK 0x00000018 +#define CHCR_TS_LOW_SHIFT 3 +#define CHCR_TS_HIGH_MASK 0 +#define CHCR_TS_HIGH_SHIFT 0 +#else /* SH7785 */ +#define CHCR_TS_LOW_MASK 0x00000018 +#define CHCR_TS_LOW_SHIFT 3 +#define CHCR_TS_HIGH_MASK 0 +#define CHCR_TS_HIGH_SHIFT 0 +#endif + +/* Transmit sizes and respective CHCR register values */ +enum { + XMIT_SZ_8BIT = 0, + XMIT_SZ_16BIT = 1, + XMIT_SZ_32BIT = 2, + XMIT_SZ_64BIT = 7, + XMIT_SZ_128BIT = 3, + XMIT_SZ_256BIT = 4, + XMIT_SZ_128BIT_BLK = 0xb, + XMIT_SZ_256BIT_BLK = 0xc, +}; + +/* log2(size / 8) - used to calculate number of transfers */ +#define TS_SHIFT { \ + [XMIT_SZ_8BIT] = 0, \ + [XMIT_SZ_16BIT] = 1, \ + [XMIT_SZ_32BIT] = 2, \ + [XMIT_SZ_64BIT] = 3, \ + [XMIT_SZ_128BIT] = 4, \ + [XMIT_SZ_256BIT] = 5, \ + [XMIT_SZ_128BIT_BLK] = 4, \ + [XMIT_SZ_256BIT_BLK] = 5, \ +} + +#define TS_INDEX2VAL(i) ((((i) & 3) << CHCR_TS_LOW_SHIFT) | \ + ((((i) >> 2) & 3) << CHCR_TS_HIGH_SHIFT)) + +#else /* CONFIG_CPU_SH4A */ + +#define DMAOR_INIT (0x8000 | DMAOR_DME) + +#define CHCR_TS_LOW_MASK 0x70 +#define CHCR_TS_LOW_SHIFT 4 +#define CHCR_TS_HIGH_MASK 0 +#define CHCR_TS_HIGH_SHIFT 0 + +/* Transmit sizes and respective CHCR register values */ +enum { + XMIT_SZ_8BIT = 1, + XMIT_SZ_16BIT = 2, + XMIT_SZ_32BIT = 3, + XMIT_SZ_64BIT = 0, + XMIT_SZ_256BIT = 4, +}; + +/* log2(size / 8) - used to calculate number of transfers */ +#define TS_SHIFT { \ + [XMIT_SZ_8BIT] = 0, \ + [XMIT_SZ_16BIT] = 1, \ + [XMIT_SZ_32BIT] = 2, \ + [XMIT_SZ_64BIT] = 3, \ + [XMIT_SZ_256BIT] = 5, \ +} + +#define TS_INDEX2VAL(i) (((i) & 7) << CHCR_TS_LOW_SHIFT) + +#endif /* CONFIG_CPU_SH4A */ + +#endif diff --git a/arch/sh/include/cpu-sh4/cpu/dma-sh4a.h b/arch/sh/include/cpu-sh4/cpu/dma-sh4a.h index e734ea47d8a..9647e681fd2 100644 --- a/arch/sh/include/cpu-sh4/cpu/dma-sh4a.h +++ b/arch/sh/include/cpu-sh4/cpu/dma-sh4a.h @@ -8,20 +8,12 @@ #define DMAE0_IRQ 78 /* DMA Error IRQ*/ #define SH_DMAC_BASE0 0xFE008020 #define SH_DMARS_BASE0 0xFE009000 -#define CHCR_TS_LOW_MASK 0x00000018 -#define CHCR_TS_LOW_SHIFT 3 -#define CHCR_TS_HIGH_MASK 0 -#define CHCR_TS_HIGH_SHIFT 0 #elif defined(CONFIG_CPU_SUBTYPE_SH7722) #define DMTE0_IRQ 48 #define DMTE4_IRQ 76 #define DMAE0_IRQ 78 /* DMA Error IRQ*/ #define SH_DMAC_BASE0 0xFE008020 #define SH_DMARS_BASE0 0xFE009000 -#define CHCR_TS_LOW_MASK 0x00000018 -#define CHCR_TS_LOW_SHIFT 3 -#define CHCR_TS_HIGH_MASK 0x00300000 -#define CHCR_TS_HIGH_SHIFT 20 #elif defined(CONFIG_CPU_SUBTYPE_SH7763) || \ defined(CONFIG_CPU_SUBTYPE_SH7764) #define DMTE0_IRQ 34 @@ -29,10 +21,6 @@ #define DMAE0_IRQ 38 #define SH_DMAC_BASE0 0xFF608020 #define SH_DMARS_BASE0 0xFF609000 -#define CHCR_TS_LOW_MASK 0x00000018 -#define CHCR_TS_LOW_SHIFT 3 -#define CHCR_TS_HIGH_MASK 0 -#define CHCR_TS_HIGH_SHIFT 0 #elif defined(CONFIG_CPU_SUBTYPE_SH7723) #define DMTE0_IRQ 48 /* DMAC0A*/ #define DMTE4_IRQ 76 /* DMAC0B */ @@ -46,10 +34,6 @@ #define SH_DMAC_BASE0 0xFE008020 #define SH_DMAC_BASE1 0xFDC08020 #define SH_DMARS_BASE0 0xFDC09000 -#define CHCR_TS_LOW_MASK 0x00000018 -#define CHCR_TS_LOW_SHIFT 3 -#define CHCR_TS_HIGH_MASK 0 -#define CHCR_TS_HIGH_SHIFT 0 #elif defined(CONFIG_CPU_SUBTYPE_SH7724) #define DMTE0_IRQ 48 /* DMAC0A*/ #define DMTE4_IRQ 76 /* DMAC0B */ @@ -64,10 +48,6 @@ #define SH_DMAC_BASE1 0xFDC08020 #define SH_DMARS_BASE0 0xFE009000 #define SH_DMARS_BASE1 0xFDC09000 -#define CHCR_TS_LOW_MASK 0x00000018 -#define CHCR_TS_LOW_SHIFT 3 -#define CHCR_TS_HIGH_MASK 0x00600000 -#define CHCR_TS_HIGH_SHIFT 21 #elif defined(CONFIG_CPU_SUBTYPE_SH7780) #define DMTE0_IRQ 34 #define DMTE4_IRQ 44 @@ -80,10 +60,6 @@ #define SH_DMAC_BASE0 0xFC808020 #define SH_DMAC_BASE1 0xFC818020 #define SH_DMARS_BASE0 0xFC809000 -#define CHCR_TS_LOW_MASK 0x00000018 -#define CHCR_TS_LOW_SHIFT 3 -#define CHCR_TS_HIGH_MASK 0 -#define CHCR_TS_HIGH_SHIFT 0 #else /* SH7785 */ #define DMTE0_IRQ 33 #define DMTE4_IRQ 37 @@ -97,10 +73,6 @@ #define SH_DMAC_BASE0 0xFC808020 #define SH_DMAC_BASE1 0xFCC08020 #define SH_DMARS_BASE0 0xFC809000 -#define CHCR_TS_LOW_MASK 0x00000018 -#define CHCR_TS_LOW_SHIFT 3 -#define CHCR_TS_HIGH_MASK 0 -#define CHCR_TS_HIGH_SHIFT 0 #endif #define REQ_HE 0x000000C0 @@ -108,38 +80,4 @@ #define REQ_LE 0x00000040 #define TM_BURST 0x00000020 -/* - * The SuperH DMAC supports a number of transmit sizes, we list them here, - * with their respective values as they appear in the CHCR registers. - * - * Defaults to a 64-bit transfer size. - */ -enum { - XMIT_SZ_8BIT = 0, - XMIT_SZ_16BIT = 1, - XMIT_SZ_32BIT = 2, - XMIT_SZ_64BIT = 7, - XMIT_SZ_128BIT = 3, - XMIT_SZ_256BIT = 4, - XMIT_SZ_128BIT_BLK = 0xb, - XMIT_SZ_256BIT_BLK = 0xc, -}; - -/* - * The DMA count is defined as the number of bytes to transfer. - */ -#define TS_SHIFT { \ - [XMIT_SZ_8BIT] = 0, \ - [XMIT_SZ_16BIT] = 1, \ - [XMIT_SZ_32BIT] = 2, \ - [XMIT_SZ_64BIT] = 3, \ - [XMIT_SZ_128BIT] = 4, \ - [XMIT_SZ_256BIT] = 5, \ - [XMIT_SZ_128BIT_BLK] = 4, \ - [XMIT_SZ_256BIT_BLK] = 5, \ -} - -#define TS_INDEX2VAL(i) ((((i) & 3) << CHCR_TS_LOW_SHIFT) | \ - ((((i) >> 2) & 3) << CHCR_TS_HIGH_SHIFT)) - #endif /* __ASM_SH_CPU_SH4_DMA_SH7780_H */ diff --git a/arch/sh/include/cpu-sh4/cpu/dma.h b/arch/sh/include/cpu-sh4/cpu/dma.h index 114a369705b..ca747e93c2e 100644 --- a/arch/sh/include/cpu-sh4/cpu/dma.h +++ b/arch/sh/include/cpu-sh4/cpu/dma.h @@ -5,9 +5,8 @@ #ifdef CONFIG_CPU_SH4A -#define DMAOR_INIT (DMAOR_DME) - #include + #else /* CONFIG_CPU_SH4A */ /* * SH7750/SH7751/SH7760 @@ -17,7 +16,6 @@ #define DMTE6_IRQ 46 #define DMAE0_IRQ 38 -#define DMAOR_INIT (0x8000|DMAOR_DME) #define SH_DMAC_BASE0 0xffa00000 #define SH_DMAC_BASE1 0xffa00070 /* Definitions for the SuperH DMAC */ @@ -27,40 +25,8 @@ #define TS_32 0x00000030 #define TS_64 0x00000000 -#define CHCR_TS_LOW_MASK 0x70 -#define CHCR_TS_LOW_SHIFT 4 -#define CHCR_TS_HIGH_MASK 0 -#define CHCR_TS_HIGH_SHIFT 0 - #define DMAOR_COD 0x00000008 -/* - * The SuperH DMAC supports a number of transmit sizes, we list them here, - * with their respective values as they appear in the CHCR registers. - * - * Defaults to a 64-bit transfer size. - */ -enum { - XMIT_SZ_8BIT = 1, - XMIT_SZ_16BIT = 2, - XMIT_SZ_32BIT = 3, - XMIT_SZ_64BIT = 0, - XMIT_SZ_256BIT = 4, -}; - -/* - * The DMA count is defined as the number of bytes to transfer. - */ -#define TS_SHIFT { \ - [XMIT_SZ_8BIT] = 0, \ - [XMIT_SZ_16BIT] = 1, \ - [XMIT_SZ_32BIT] = 2, \ - [XMIT_SZ_64BIT] = 3, \ - [XMIT_SZ_256BIT] = 5, \ -} - -#define TS_INDEX2VAL(i) (((i) & 7) << CHCR_TS_LOW_SHIFT) - #endif #endif /* __ASM_CPU_SH4_DMA_H */ diff --git a/arch/sh/kernel/cpu/sh4a/setup-sh7722.c b/arch/sh/kernel/cpu/sh4a/setup-sh7722.c index aec182bed8a..89f84911c35 100644 --- a/arch/sh/kernel/cpu/sh4a/setup-sh7722.c +++ b/arch/sh/kernel/cpu/sh4a/setup-sh7722.c @@ -7,18 +7,21 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. */ -#include #include +#include +#include #include #include -#include +#include #include #include -#include + #include +#include #include -#include #include + +#include #include static struct sh_dmae_slave_config sh7722_dmae_slaves[] = { @@ -103,11 +106,20 @@ static struct sh_dmae_channel sh7722_dmae_channels[] = { } }; +static unsigned int ts_shift[] = TS_SHIFT; + static struct sh_dmae_pdata dma_platform_data = { .slave = sh7722_dmae_slaves, .slave_num = ARRAY_SIZE(sh7722_dmae_slaves), .channel = sh7722_dmae_channels, .channel_num = ARRAY_SIZE(sh7722_dmae_channels), + .ts_low_shift = CHCR_TS_LOW_SHIFT, + .ts_low_mask = CHCR_TS_LOW_MASK, + .ts_high_shift = CHCR_TS_HIGH_SHIFT, + .ts_high_mask = CHCR_TS_HIGH_MASK, + .ts_shift = ts_shift, + .ts_shift_num = ARRAY_SIZE(ts_shift), + .dmaor_init = DMAOR_INIT, }; static struct resource sh7722_dmae_resources[] = { diff --git a/arch/sh/kernel/cpu/sh4a/setup-sh7724.c b/arch/sh/kernel/cpu/sh4a/setup-sh7724.c index aca1fb2c571..d9cb2c471a3 100644 --- a/arch/sh/kernel/cpu/sh4a/setup-sh7724.c +++ b/arch/sh/kernel/cpu/sh4a/setup-sh7724.c @@ -21,10 +21,13 @@ #include #include #include + #include #include -#include +#include #include + +#include #include /* DMA */ @@ -84,14 +87,30 @@ static struct sh_dmae_channel sh7724_dmae1_channels[] = { } }; +static unsigned int ts_shift[] = TS_SHIFT; + static struct sh_dmae_pdata dma0_platform_data = { .channel = sh7724_dmae0_channels, .channel_num = ARRAY_SIZE(sh7724_dmae0_channels), + .ts_low_shift = CHCR_TS_LOW_SHIFT, + .ts_low_mask = CHCR_TS_LOW_MASK, + .ts_high_shift = CHCR_TS_HIGH_SHIFT, + .ts_high_mask = CHCR_TS_HIGH_MASK, + .ts_shift = ts_shift, + .ts_shift_num = ARRAY_SIZE(ts_shift), + .dmaor_init = DMAOR_INIT, }; static struct sh_dmae_pdata dma1_platform_data = { .channel = sh7724_dmae1_channels, .channel_num = ARRAY_SIZE(sh7724_dmae1_channels), + .ts_low_shift = CHCR_TS_LOW_SHIFT, + .ts_low_mask = CHCR_TS_LOW_MASK, + .ts_high_shift = CHCR_TS_HIGH_SHIFT, + .ts_high_mask = CHCR_TS_HIGH_MASK, + .ts_shift = ts_shift, + .ts_shift_num = ARRAY_SIZE(ts_shift), + .dmaor_init = DMAOR_INIT, }; /* Resource order important! */ diff --git a/arch/sh/kernel/cpu/sh4a/setup-sh7780.c b/arch/sh/kernel/cpu/sh4a/setup-sh7780.c index 338dfc2c2bb..02e792c90de 100644 --- a/arch/sh/kernel/cpu/sh4a/setup-sh7780.c +++ b/arch/sh/kernel/cpu/sh4a/setup-sh7780.c @@ -13,7 +13,10 @@ #include #include #include -#include + +#include + +#include static struct plat_sci_port scif0_platform_data = { .mapbase = 0xffe00000, @@ -292,14 +295,30 @@ static struct sh_dmae_channel sh7780_dmae1_channels[] = { } }; +static unsigned int ts_shift[] = TS_SHIFT; + static struct sh_dmae_pdata dma0_platform_data = { .channel = sh7780_dmae0_channels, .channel_num = ARRAY_SIZE(sh7780_dmae0_channels), + .ts_low_shift = CHCR_TS_LOW_SHIFT, + .ts_low_mask = CHCR_TS_LOW_MASK, + .ts_high_shift = CHCR_TS_HIGH_SHIFT, + .ts_high_mask = CHCR_TS_HIGH_MASK, + .ts_shift = ts_shift, + .ts_shift_num = ARRAY_SIZE(ts_shift), + .dmaor_init = DMAOR_INIT, }; static struct sh_dmae_pdata dma1_platform_data = { .channel = sh7780_dmae1_channels, .channel_num = ARRAY_SIZE(sh7780_dmae1_channels), + .ts_low_shift = CHCR_TS_LOW_SHIFT, + .ts_low_mask = CHCR_TS_LOW_MASK, + .ts_high_shift = CHCR_TS_HIGH_SHIFT, + .ts_high_mask = CHCR_TS_HIGH_MASK, + .ts_shift = ts_shift, + .ts_shift_num = ARRAY_SIZE(ts_shift), + .dmaor_init = DMAOR_INIT, }; static struct resource sh7780_dmae0_resources[] = { diff --git a/arch/sh/kernel/cpu/sh4a/setup-sh7785.c b/arch/sh/kernel/cpu/sh4a/setup-sh7785.c index fbb5d1f51f1..1fcd88b1671 100644 --- a/arch/sh/kernel/cpu/sh4a/setup-sh7785.c +++ b/arch/sh/kernel/cpu/sh4a/setup-sh7785.c @@ -14,9 +14,12 @@ #include #include #include -#include + +#include #include +#include + static struct plat_sci_port scif0_platform_data = { .mapbase = 0xffea0000, .flags = UPF_BOOT_AUTOCONF, @@ -340,14 +343,30 @@ static struct sh_dmae_channel sh7785_dmae1_channels[] = { } }; +static unsigned int ts_shift[] = TS_SHIFT; + static struct sh_dmae_pdata dma0_platform_data = { .channel = sh7785_dmae0_channels, .channel_num = ARRAY_SIZE(sh7785_dmae0_channels), + .ts_low_shift = CHCR_TS_LOW_SHIFT, + .ts_low_mask = CHCR_TS_LOW_MASK, + .ts_high_shift = CHCR_TS_HIGH_SHIFT, + .ts_high_mask = CHCR_TS_HIGH_MASK, + .ts_shift = ts_shift, + .ts_shift_num = ARRAY_SIZE(ts_shift), + .dmaor_init = DMAOR_INIT, }; static struct sh_dmae_pdata dma1_platform_data = { .channel = sh7785_dmae1_channels, .channel_num = ARRAY_SIZE(sh7785_dmae1_channels), + .ts_low_shift = CHCR_TS_LOW_SHIFT, + .ts_low_mask = CHCR_TS_LOW_MASK, + .ts_high_shift = CHCR_TS_HIGH_SHIFT, + .ts_high_mask = CHCR_TS_HIGH_MASK, + .ts_shift = ts_shift, + .ts_shift_num = ARRAY_SIZE(ts_shift), + .dmaor_init = DMAOR_INIT, }; static struct resource sh7785_dmae0_resources[] = { diff --git a/drivers/dma/shdma.c b/drivers/dma/shdma.c index ab12fa5a129..b419afaa238 100644 --- a/drivers/dma/shdma.c +++ b/drivers/dma/shdma.c @@ -24,8 +24,7 @@ #include #include #include -#include -#include +#include #include "shdma.h" /* DMA descriptor control */ @@ -38,15 +37,8 @@ enum sh_dmae_desc_status { }; #define NR_DESCS_PER_CHANNEL 32 -/* - * Define the default configuration for dual address memory-memory transfer. - * The 0x400 value represents auto-request, external->external. - * - * And this driver set 4byte burst mode. - * If you want to change mode, you need to change RS_DEFAULT of value. - * (ex 1byte burst mode -> (RS_DUAL & ~TS_32) - */ -#define RS_DEFAULT (RS_DUAL) +/* Default MEMCPY transfer size = 2^2 = 4 bytes */ +#define LOG2_DEFAULT_XFER_SIZE 2 /* A bitmask with bits enough for enum sh_dmae_slave_chan_id */ static unsigned long sh_dmae_slave_used[BITS_TO_LONGS(SHDMA_SLAVE_NUMBER)]; @@ -90,7 +82,7 @@ static int sh_dmae_rst(struct sh_dmae_device *shdev) unsigned short dmaor; sh_dmae_ctl_stop(shdev); - dmaor = dmaor_read(shdev) | DMAOR_INIT; + dmaor = dmaor_read(shdev) | shdev->pdata->dmaor_init; dmaor_write(shdev, dmaor); if (dmaor_read(shdev) & (DMAOR_AE | DMAOR_NMIF)) { @@ -110,13 +102,36 @@ static bool dmae_is_busy(struct sh_dmae_chan *sh_chan) return false; /* waiting */ } -static unsigned int ts_shift[] = TS_SHIFT; -static inline unsigned int calc_xmit_shift(u32 chcr) +static unsigned int calc_xmit_shift(struct sh_dmae_chan *sh_chan, u32 chcr) { - int cnt = ((chcr & CHCR_TS_LOW_MASK) >> CHCR_TS_LOW_SHIFT) | - ((chcr & CHCR_TS_HIGH_MASK) >> CHCR_TS_HIGH_SHIFT); + struct sh_dmae_device *shdev = container_of(sh_chan->common.device, + struct sh_dmae_device, common); + struct sh_dmae_pdata *pdata = shdev->pdata; + int cnt = ((chcr & pdata->ts_low_mask) >> pdata->ts_low_shift) | + ((chcr & pdata->ts_high_mask) >> pdata->ts_high_shift); + + if (cnt >= pdata->ts_shift_num) + cnt = 0; - return ts_shift[cnt]; + return pdata->ts_shift[cnt]; +} + +static u32 log2size_to_chcr(struct sh_dmae_chan *sh_chan, int l2size) +{ + struct sh_dmae_device *shdev = container_of(sh_chan->common.device, + struct sh_dmae_device, common); + struct sh_dmae_pdata *pdata = shdev->pdata; + int i; + + for (i = 0; i < pdata->ts_shift_num; i++) + if (pdata->ts_shift[i] == l2size) + break; + + if (i == pdata->ts_shift_num) + i = 0; + + return ((i << pdata->ts_low_shift) & pdata->ts_low_mask) | + ((i << pdata->ts_high_shift) & pdata->ts_high_mask); } static void dmae_set_reg(struct sh_dmae_chan *sh_chan, struct sh_dmae_regs *hw) @@ -144,8 +159,13 @@ static void dmae_halt(struct sh_dmae_chan *sh_chan) static void dmae_init(struct sh_dmae_chan *sh_chan) { - u32 chcr = RS_DEFAULT; /* default is DUAL mode */ - sh_chan->xmit_shift = calc_xmit_shift(chcr); + /* + * Default configuration for dual address memory-memory transfer. + * 0x400 represents auto-request. + */ + u32 chcr = DM_INC | SM_INC | 0x400 | log2size_to_chcr(sh_chan, + LOG2_DEFAULT_XFER_SIZE); + sh_chan->xmit_shift = calc_xmit_shift(sh_chan, chcr); sh_dmae_writel(sh_chan, chcr, CHCR); } @@ -155,7 +175,7 @@ static int dmae_set_chcr(struct sh_dmae_chan *sh_chan, u32 val) if (dmae_is_busy(sh_chan)) return -EBUSY; - sh_chan->xmit_shift = calc_xmit_shift(val); + sh_chan->xmit_shift = calc_xmit_shift(sh_chan, val); sh_dmae_writel(sh_chan, val, CHCR); return 0; @@ -285,9 +305,8 @@ static int sh_dmae_alloc_chan_resources(struct dma_chan *chan) dmae_set_dmars(sh_chan, cfg->mid_rid); dmae_set_chcr(sh_chan, cfg->chcr); - } else { - if ((sh_dmae_readl(sh_chan, CHCR) & 0x700) != 0x400) - dmae_set_chcr(sh_chan, RS_DEFAULT); + } else if ((sh_dmae_readl(sh_chan, CHCR) & 0xf00) != 0x400) { + dmae_init(sh_chan); } spin_lock_bh(&sh_chan->desc_lock); @@ -757,7 +776,7 @@ static irqreturn_t sh_dmae_err(int irq, void *data) sh_dmae_ctl_stop(shdev); /* We cannot detect, which channel caused the error, have to reset all */ - for (i = 0; i < MAX_DMA_CHANNELS; i++) { + for (i = 0; i < SH_DMAC_MAX_CHANNELS; i++) { struct sh_dmae_chan *sh_chan = shdev->chan[i]; if (sh_chan) { struct sh_desc *desc; @@ -822,6 +841,9 @@ static int __devinit sh_dmae_chan_probe(struct sh_dmae_device *shdev, int id, return -ENOMEM; } + /* copy struct dma_device */ + new_sh_chan->common.device = &shdev->common; + new_sh_chan->dev = shdev->common.dev; new_sh_chan->id = id; new_sh_chan->irq = irq; @@ -840,9 +862,6 @@ static int __devinit sh_dmae_chan_probe(struct sh_dmae_device *shdev, int id, INIT_LIST_HEAD(&new_sh_chan->ld_queue); INIT_LIST_HEAD(&new_sh_chan->ld_free); - /* copy struct dma_device */ - new_sh_chan->common.device = &shdev->common; - /* Add the channel to DMA device channel list */ list_add_tail(&new_sh_chan->common.device_node, &shdev->common.channels); @@ -896,8 +915,8 @@ static int __init sh_dmae_probe(struct platform_device *pdev) { struct sh_dmae_pdata *pdata = pdev->dev.platform_data; unsigned long irqflags = IRQF_DISABLED, - chan_flag[MAX_DMA_CHANNELS] = {}; - int errirq, chan_irq[MAX_DMA_CHANNELS]; + chan_flag[SH_DMAC_MAX_CHANNELS] = {}; + int errirq, chan_irq[SH_DMAC_MAX_CHANNELS]; int err, i, irq_cnt = 0, irqres = 0; struct sh_dmae_device *shdev; struct resource *chan, *dmars, *errirq_res, *chanirq_res; @@ -983,7 +1002,7 @@ static int __init sh_dmae_probe(struct platform_device *pdev) shdev->common.dev = &pdev->dev; /* Default transfer size of 32 bytes requires 32-byte alignment */ - shdev->common.copy_align = 5; + shdev->common.copy_align = LOG2_DEFAULT_XFER_SIZE; #if defined(CONFIG_CPU_SH4) chanirq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 1); diff --git a/drivers/dma/shdma.h b/drivers/dma/shdma.h index 800fd884be8..9f0897f7fe3 100644 --- a/drivers/dma/shdma.h +++ b/drivers/dma/shdma.h @@ -17,6 +17,8 @@ #include #include +#include + #define SH_DMA_TCR_MAX 0x00FFFFFF /* 16MB */ struct sh_dmae_regs { @@ -55,7 +57,7 @@ struct sh_dmae_chan { struct sh_dmae_device { struct dma_device common; - struct sh_dmae_chan *chan[MAX_DMA_CHANNELS]; + struct sh_dmae_chan *chan[SH_DMAC_MAX_CHANNELS]; struct sh_dmae_pdata *pdata; u32 __iomem *chan_reg; u16 __iomem *dmars; diff --git a/sound/soc/sh/siu.h b/sound/soc/sh/siu.h index 9cc04ab2bce..c0bfab8fed3 100644 --- a/sound/soc/sh/siu.h +++ b/sound/soc/sh/siu.h @@ -72,7 +72,7 @@ struct siu_firmware { #include #include -#include +#include #include #include diff --git a/sound/soc/sh/siu_pcm.c b/sound/soc/sh/siu_pcm.c index c5efc30f013..ba7f8d05d97 100644 --- a/sound/soc/sh/siu_pcm.c +++ b/sound/soc/sh/siu_pcm.c @@ -32,7 +32,7 @@ #include #include -#include +#include #include #include "siu.h" -- cgit v1.2.3-70-g09d2 From 20f2a3b5d57701c54bdd59b89dd37fe775926bae Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Thu, 11 Feb 2010 16:50:18 +0000 Subject: dmaengine: shdma: add runtime PM support. Provided platforms implement runtime PM, this disables the controller, when not in use. Signed-off-by: Guennadi Liakhovetski Signed-off-by: Paul Mundt --- drivers/dma/shdma.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) (limited to 'drivers') diff --git a/drivers/dma/shdma.c b/drivers/dma/shdma.c index b419afaa238..ea6779f3e73 100644 --- a/drivers/dma/shdma.c +++ b/drivers/dma/shdma.c @@ -24,7 +24,10 @@ #include #include #include +#include + #include + #include "shdma.h" /* DMA descriptor control */ @@ -287,6 +290,8 @@ static int sh_dmae_alloc_chan_resources(struct dma_chan *chan) struct sh_desc *desc; struct sh_dmae_slave *param = chan->private; + pm_runtime_get_sync(sh_chan->dev); + /* * This relies on the guarantee from dmaengine that alloc_chan_resources * never runs concurrently with itself or free_chan_resources. @@ -328,6 +333,9 @@ static int sh_dmae_alloc_chan_resources(struct dma_chan *chan) } spin_unlock_bh(&sh_chan->desc_lock); + if (!sh_chan->descs_allocated) + pm_runtime_put(sh_chan->dev); + return sh_chan->descs_allocated; } @@ -339,6 +347,7 @@ static void sh_dmae_free_chan_resources(struct dma_chan *chan) struct sh_dmae_chan *sh_chan = to_sh_chan(chan); struct sh_desc *desc, *_desc; LIST_HEAD(list); + int descs = sh_chan->descs_allocated; dmae_halt(sh_chan); @@ -359,6 +368,9 @@ static void sh_dmae_free_chan_resources(struct dma_chan *chan) spin_unlock_bh(&sh_chan->desc_lock); + if (descs > 0) + pm_runtime_put(sh_chan->dev); + list_for_each_entry_safe(desc, _desc, &list, node) kfree(desc); } @@ -978,6 +990,9 @@ static int __init sh_dmae_probe(struct platform_device *pdev) /* platform data */ shdev->pdata = pdata; + pm_runtime_enable(&pdev->dev); + pm_runtime_get_sync(&pdev->dev); + /* reset dma controller */ err = sh_dmae_rst(shdev); if (err) @@ -1066,6 +1081,8 @@ static int __init sh_dmae_probe(struct platform_device *pdev) goto chan_probe_err; } + pm_runtime_put(&pdev->dev); + platform_set_drvdata(pdev, shdev); dma_async_device_register(&shdev->common); @@ -1079,6 +1096,7 @@ eirqres: eirq_err: #endif rst_err: + pm_runtime_put(&pdev->dev); if (dmars) iounmap(shdev->dmars); emapdmars: @@ -1108,6 +1126,8 @@ static int __exit sh_dmae_remove(struct platform_device *pdev) /* channel data remove */ sh_dmae_chan_remove(shdev); + pm_runtime_disable(&pdev->dev); + if (shdev->dmars) iounmap(shdev->dmars); iounmap(shdev->chan_reg); -- cgit v1.2.3-70-g09d2 From c014906a870ce70e009def0c9d170ccabeb0be63 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Thu, 18 Feb 2010 16:30:02 +0000 Subject: dmaengine: shdma: extend .device_terminate_all() to record partial transfer This patch extends the .device_terminate_all() method of the shdma driver to return number of bytes transfered in the current descriptor. Signed-off-by: Guennadi Liakhovetski Signed-off-by: Paul Mundt --- arch/sh/include/asm/dmaengine.h | 20 ++++++++++++++++++++ drivers/dma/shdma.c | 16 ++++++++++++++++ drivers/dma/shdma.h | 16 ---------------- 3 files changed, 36 insertions(+), 16 deletions(-) (limited to 'drivers') diff --git a/arch/sh/include/asm/dmaengine.h b/arch/sh/include/asm/dmaengine.h index 9586e4a482b..bf2f30cf0a2 100644 --- a/arch/sh/include/asm/dmaengine.h +++ b/arch/sh/include/asm/dmaengine.h @@ -10,6 +10,9 @@ #ifndef ASM_DMAENGINE_H #define ASM_DMAENGINE_H +#include +#include + #include #define SH_DMAC_MAX_CHANNELS 6 @@ -70,4 +73,21 @@ struct sh_dmae_slave { struct sh_dmae_slave_config *config; /* Set by the driver */ }; +struct sh_dmae_regs { + u32 sar; /* SAR / source address */ + u32 dar; /* DAR / destination address */ + u32 tcr; /* TCR / transfer count */ +}; + +struct sh_desc { + struct sh_dmae_regs hw; + struct list_head node; + struct dma_async_tx_descriptor async_tx; + enum dma_data_direction direction; + dma_cookie_t cookie; + size_t partial; + int chunks; + int mark; +}; + #endif diff --git a/drivers/dma/shdma.c b/drivers/dma/shdma.c index ea6779f3e73..5d17e09cb62 100644 --- a/drivers/dma/shdma.c +++ b/drivers/dma/shdma.c @@ -587,6 +587,19 @@ static void sh_dmae_terminate_all(struct dma_chan *chan) if (!chan) return; + dmae_halt(sh_chan); + + spin_lock_bh(&sh_chan->desc_lock); + if (!list_empty(&sh_chan->ld_queue)) { + /* Record partial transfer */ + struct sh_desc *desc = list_entry(sh_chan->ld_queue.next, + struct sh_desc, node); + desc->partial = (desc->hw.tcr - sh_dmae_readl(sh_chan, TCR)) << + sh_chan->xmit_shift; + + } + spin_unlock_bh(&sh_chan->desc_lock); + sh_dmae_chan_ld_cleanup(sh_chan, true); } @@ -701,6 +714,9 @@ static void sh_chan_xfer_ld_queue(struct sh_dmae_chan *sh_chan) /* Find the first not transferred desciptor */ list_for_each_entry(desc, &sh_chan->ld_queue, node) if (desc->mark == DESC_SUBMITTED) { + dev_dbg(sh_chan->dev, "Queue #%d to %d: %u@%x -> %x\n", + desc->async_tx.cookie, sh_chan->id, + desc->hw.tcr, desc->hw.sar, desc->hw.dar); /* Get the ld start address from ld_queue */ dmae_set_reg(sh_chan, &desc->hw); dmae_start(sh_chan); diff --git a/drivers/dma/shdma.h b/drivers/dma/shdma.h index 9f0897f7fe3..153609a1e96 100644 --- a/drivers/dma/shdma.h +++ b/drivers/dma/shdma.h @@ -21,22 +21,6 @@ #define SH_DMA_TCR_MAX 0x00FFFFFF /* 16MB */ -struct sh_dmae_regs { - u32 sar; /* SAR / source address */ - u32 dar; /* DAR / destination address */ - u32 tcr; /* TCR / transfer count */ -}; - -struct sh_desc { - struct sh_dmae_regs hw; - struct list_head node; - struct dma_async_tx_descriptor async_tx; - enum dma_data_direction direction; - dma_cookie_t cookie; - int chunks; - int mark; -}; - struct device; struct sh_dmae_chan { -- cgit v1.2.3-70-g09d2 From 73a19e4c0301908ce6346715fd08a74308451f5a Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Tue, 2 Mar 2010 11:39:15 +0900 Subject: serial: sh-sci: Add DMA support. Support using DMA for sending and receiving data over SCI(F) interfaces of various SH SoCs. Signed-off-by: Guennadi Liakhovetski Signed-off-by: Paul Mundt --- drivers/serial/Kconfig | 4 + drivers/serial/sh-sci.c | 618 +++++++++++++++++++++++++++++++++++++++++---- include/linux/serial_sci.h | 6 + 3 files changed, 582 insertions(+), 46 deletions(-) (limited to 'drivers') diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig index 888a0ce91c4..11ebe862457 100644 --- a/drivers/serial/Kconfig +++ b/drivers/serial/Kconfig @@ -1009,6 +1009,10 @@ config SERIAL_SH_SCI_CONSOLE depends on SERIAL_SH_SCI=y select SERIAL_CORE_CONSOLE +config SERIAL_SH_SCI_DMA + bool "DMA support" + depends on SERIAL_SH_SCI && SH_DMAE && EXPERIMENTAL + config SERIAL_PNX8XXX bool "Enable PNX8XXX SoCs' UART Support" depends on MIPS && (SOC_PNX8550 || SOC_PNX833X) diff --git a/drivers/serial/sh-sci.c b/drivers/serial/sh-sci.c index 42f3333c4ad..f3841cd8fc5 100644 --- a/drivers/serial/sh-sci.c +++ b/drivers/serial/sh-sci.c @@ -48,6 +48,9 @@ #include #include #include +#include +#include +#include #ifdef CONFIG_SUPERH #include @@ -84,6 +87,27 @@ struct sci_port { struct clk *dclk; struct list_head node; + struct dma_chan *chan_tx; + struct dma_chan *chan_rx; +#ifdef CONFIG_SERIAL_SH_SCI_DMA + struct device *dma_dev; + enum sh_dmae_slave_chan_id slave_tx; + enum sh_dmae_slave_chan_id slave_rx; + struct dma_async_tx_descriptor *desc_tx; + struct dma_async_tx_descriptor *desc_rx[2]; + dma_cookie_t cookie_tx; + dma_cookie_t cookie_rx[2]; + dma_cookie_t active_rx; + struct scatterlist sg_tx; + unsigned int sg_len_tx; + struct scatterlist sg_rx[2]; + size_t buf_len_rx; + struct sh_dmae_slave param_tx; + struct sh_dmae_slave param_rx; + struct work_struct work_tx; + struct work_struct work_rx; + struct timer_list rx_timer; +#endif }; struct sh_sci_priv { @@ -269,29 +293,44 @@ static inline void sci_init_pins(struct uart_port *port, unsigned int cflag) defined(CONFIG_CPU_SUBTYPE_SH7780) || \ defined(CONFIG_CPU_SUBTYPE_SH7785) || \ defined(CONFIG_CPU_SUBTYPE_SH7786) -static inline int scif_txroom(struct uart_port *port) +static int scif_txfill(struct uart_port *port) { - return SCIF_TXROOM_MAX - (sci_in(port, SCTFDR) & 0xff); + return sci_in(port, SCTFDR) & 0xff; } -static inline int scif_rxroom(struct uart_port *port) +static int scif_txroom(struct uart_port *port) +{ + return SCIF_TXROOM_MAX - scif_txfill(port); +} + +static int scif_rxfill(struct uart_port *port) { return sci_in(port, SCRFDR) & 0xff; } #elif defined(CONFIG_CPU_SUBTYPE_SH7763) -static inline int scif_txroom(struct uart_port *port) +static int scif_txfill(struct uart_port *port) { - if ((port->mapbase == 0xffe00000) || - (port->mapbase == 0xffe08000)) { + if (port->mapbase == 0xffe00000 || + port->mapbase == 0xffe08000) /* SCIF0/1*/ - return SCIF_TXROOM_MAX - (sci_in(port, SCTFDR) & 0xff); - } else { + return sci_in(port, SCTFDR) & 0xff; + else /* SCIF2 */ - return SCIF2_TXROOM_MAX - (sci_in(port, SCFDR) >> 8); - } + return sci_in(port, SCFDR) >> 8; +} + +static int scif_txroom(struct uart_port *port) +{ + if (port->mapbase == 0xffe00000 || + port->mapbase == 0xffe08000) + /* SCIF0/1*/ + return SCIF_TXROOM_MAX - scif_txfill(port); + else + /* SCIF2 */ + return SCIF2_TXROOM_MAX - scif_txfill(port); } -static inline int scif_rxroom(struct uart_port *port) +static int scif_rxfill(struct uart_port *port) { if ((port->mapbase == 0xffe00000) || (port->mapbase == 0xffe08000)) { @@ -303,23 +342,33 @@ static inline int scif_rxroom(struct uart_port *port) } } #else -static inline int scif_txroom(struct uart_port *port) +static int scif_txfill(struct uart_port *port) { - return SCIF_TXROOM_MAX - (sci_in(port, SCFDR) >> 8); + return sci_in(port, SCFDR) >> 8; } -static inline int scif_rxroom(struct uart_port *port) +static int scif_txroom(struct uart_port *port) +{ + return SCIF_TXROOM_MAX - scif_txfill(port); +} + +static int scif_rxfill(struct uart_port *port) { return sci_in(port, SCFDR) & SCIF_RFDC_MASK; } #endif -static inline int sci_txroom(struct uart_port *port) +static int sci_txfill(struct uart_port *port) { - return (sci_in(port, SCxSR) & SCI_TDRE) != 0; + return !(sci_in(port, SCxSR) & SCI_TDRE); } -static inline int sci_rxroom(struct uart_port *port) +static int sci_txroom(struct uart_port *port) +{ + return !sci_txfill(port); +} + +static int sci_rxfill(struct uart_port *port) { return (sci_in(port, SCxSR) & SCxSR_RDxF(port)) != 0; } @@ -406,9 +455,9 @@ static inline void sci_receive_chars(struct uart_port *port) while (1) { if (port->type == PORT_SCI) - count = sci_rxroom(port); + count = sci_rxfill(port); else - count = scif_rxroom(port); + count = scif_rxfill(port); /* Don't copy more bytes than there is room for in the buffer */ count = tty_buffer_request_room(tty, count); @@ -453,10 +502,10 @@ static inline void sci_receive_chars(struct uart_port *port) } /* Store data and status */ - if (status&SCxSR_FER(port)) { + if (status & SCxSR_FER(port)) { flag = TTY_FRAME; dev_notice(port->dev, "frame error\n"); - } else if (status&SCxSR_PER(port)) { + } else if (status & SCxSR_PER(port)) { flag = TTY_PARITY; dev_notice(port->dev, "parity error\n"); } else @@ -618,13 +667,39 @@ static inline int sci_handle_breaks(struct uart_port *port) return copied; } -static irqreturn_t sci_rx_interrupt(int irq, void *port) +static irqreturn_t sci_rx_interrupt(int irq, void *ptr) { +#ifdef CONFIG_SERIAL_SH_SCI_DMA + struct uart_port *port = ptr; + struct sci_port *s = to_sci_port(port); + + if (s->chan_rx) { + unsigned long tout; + u16 scr = sci_in(port, SCSCR); + u16 ssr = sci_in(port, SCxSR); + + /* Disable future Rx interrupts */ + sci_out(port, SCSCR, scr & ~SCI_CTRL_FLAGS_RIE); + /* Clear current interrupt */ + sci_out(port, SCxSR, ssr & ~(1 | SCxSR_RDxF(port))); + /* Calculate delay for 1.5 DMA buffers */ + tout = (port->timeout - HZ / 50) * s->buf_len_rx * 3 / + port->fifosize / 2; + dev_dbg(port->dev, "Rx IRQ: setup timeout in %u ms\n", + tout * 1000 / HZ); + if (tout < 2) + tout = 2; + mod_timer(&s->rx_timer, jiffies + tout); + + return IRQ_HANDLED; + } +#endif + /* I think sci_receive_chars has to be called irrespective * of whether the I_IXOFF is set, otherwise, how is the interrupt * to be disabled? */ - sci_receive_chars(port); + sci_receive_chars(ptr); return IRQ_HANDLED; } @@ -680,6 +755,7 @@ static irqreturn_t sci_mpxed_interrupt(int irq, void *ptr) { unsigned short ssr_status, scr_status, err_enabled; struct uart_port *port = ptr; + struct sci_port *s = to_sci_port(port); irqreturn_t ret = IRQ_NONE; ssr_status = sci_in(port, SCxSR); @@ -687,10 +763,15 @@ static irqreturn_t sci_mpxed_interrupt(int irq, void *ptr) err_enabled = scr_status & (SCI_CTRL_FLAGS_REIE | SCI_CTRL_FLAGS_RIE); /* Tx Interrupt */ - if ((ssr_status & SCxSR_TDxE(port)) && (scr_status & SCI_CTRL_FLAGS_TIE)) + if ((ssr_status & SCxSR_TDxE(port)) && (scr_status & SCI_CTRL_FLAGS_TIE) && + !s->chan_tx) ret = sci_tx_interrupt(irq, ptr); - /* Rx Interrupt */ - if ((ssr_status & SCxSR_RDxF(port)) && (scr_status & SCI_CTRL_FLAGS_RIE)) + /* + * Rx Interrupt: if we're using DMA, the DMA controller clears RDF / + * DR flags + */ + if (((ssr_status & SCxSR_RDxF(port)) || s->chan_rx) && + (scr_status & SCI_CTRL_FLAGS_RIE)) ret = sci_rx_interrupt(irq, ptr); /* Error Interrupt */ if ((ssr_status & SCxSR_ERRORS(port)) && err_enabled) @@ -699,6 +780,10 @@ static irqreturn_t sci_mpxed_interrupt(int irq, void *ptr) if ((ssr_status & SCxSR_BRK(port)) && err_enabled) ret = sci_br_interrupt(irq, ptr); + WARN_ONCE(ret == IRQ_NONE, + "%s: %d IRQ %d, status %x, control %x\n", __func__, + irq, port->line, ssr_status, scr_status); + return ret; } @@ -800,7 +885,9 @@ static void sci_free_irq(struct sci_port *port) static unsigned int sci_tx_empty(struct uart_port *port) { unsigned short status = sci_in(port, SCxSR); - return status & SCxSR_TEND(port) ? TIOCSER_TEMT : 0; + unsigned short in_tx_fifo = scif_txfill(port); + + return (status & SCxSR_TEND(port)) && !in_tx_fifo ? TIOCSER_TEMT : 0; } static void sci_set_mctrl(struct uart_port *port, unsigned int mctrl) @@ -812,16 +899,299 @@ static void sci_set_mctrl(struct uart_port *port, unsigned int mctrl) static unsigned int sci_get_mctrl(struct uart_port *port) { - /* This routine is used for geting signals of: DTR, DCD, DSR, RI, + /* This routine is used for getting signals of: DTR, DCD, DSR, RI, and CTS/RTS */ return TIOCM_DTR | TIOCM_RTS | TIOCM_DSR; } +#ifdef CONFIG_SERIAL_SH_SCI_DMA +static void sci_dma_tx_complete(void *arg) +{ + struct sci_port *s = arg; + struct uart_port *port = &s->port; + struct circ_buf *xmit = &port->state->xmit; + unsigned long flags; + + dev_dbg(port->dev, "%s(%d)\n", __func__, port->line); + + spin_lock_irqsave(&port->lock, flags); + + xmit->tail += s->sg_tx.length; + xmit->tail &= UART_XMIT_SIZE - 1; + + port->icount.tx += s->sg_tx.length; + + async_tx_ack(s->desc_tx); + s->cookie_tx = -EINVAL; + s->desc_tx = NULL; + + spin_unlock_irqrestore(&port->lock, flags); + + if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + uart_write_wakeup(port); + + if (uart_circ_chars_pending(xmit)) + schedule_work(&s->work_tx); +} + +/* Locking: called with port lock held */ +static int sci_dma_rx_push(struct sci_port *s, struct tty_struct *tty, + size_t count) +{ + struct uart_port *port = &s->port; + int i, active, room; + + room = tty_buffer_request_room(tty, count); + + if (s->active_rx == s->cookie_rx[0]) { + active = 0; + } else if (s->active_rx == s->cookie_rx[1]) { + active = 1; + } else { + dev_err(port->dev, "cookie %d not found!\n", s->active_rx); + return 0; + } + + if (room < count) + dev_warn(port->dev, "Rx overrun: dropping %u bytes\n", + count - room); + if (!room) + return room; + + for (i = 0; i < room; i++) + tty_insert_flip_char(tty, ((u8 *)sg_virt(&s->sg_rx[active]))[i], + TTY_NORMAL); + + port->icount.rx += room; + + return room; +} + +static void sci_dma_rx_complete(void *arg) +{ + struct sci_port *s = arg; + struct uart_port *port = &s->port; + struct tty_struct *tty = port->state->port.tty; + unsigned long flags; + int count; + + dev_dbg(port->dev, "%s(%d)\n", __func__, port->line); + + spin_lock_irqsave(&port->lock, flags); + + count = sci_dma_rx_push(s, tty, s->buf_len_rx); + + mod_timer(&s->rx_timer, jiffies + msecs_to_jiffies(5)); + + spin_unlock_irqrestore(&port->lock, flags); + + if (count) + tty_flip_buffer_push(tty); + + schedule_work(&s->work_rx); +} + +static void sci_start_rx(struct uart_port *port); +static void sci_start_tx(struct uart_port *port); + +static void sci_rx_dma_release(struct sci_port *s, bool enable_pio) +{ + struct dma_chan *chan = s->chan_rx; + struct uart_port *port = &s->port; + unsigned long flags; + + s->chan_rx = NULL; + s->cookie_rx[0] = s->cookie_rx[1] = -EINVAL; + dma_release_channel(chan); + dma_free_coherent(port->dev, s->buf_len_rx * 2, + sg_virt(&s->sg_rx[0]), sg_dma_address(&s->sg_rx[0])); + if (enable_pio) + sci_start_rx(port); +} + +static void sci_tx_dma_release(struct sci_port *s, bool enable_pio) +{ + struct dma_chan *chan = s->chan_tx; + struct uart_port *port = &s->port; + unsigned long flags; + + s->chan_tx = NULL; + s->cookie_tx = -EINVAL; + dma_release_channel(chan); + if (enable_pio) + sci_start_tx(port); +} + +static void sci_submit_rx(struct sci_port *s) +{ + struct dma_chan *chan = s->chan_rx; + int i; + + for (i = 0; i < 2; i++) { + struct scatterlist *sg = &s->sg_rx[i]; + struct dma_async_tx_descriptor *desc; + + desc = chan->device->device_prep_slave_sg(chan, + sg, 1, DMA_FROM_DEVICE, DMA_PREP_INTERRUPT); + + if (desc) { + s->desc_rx[i] = desc; + desc->callback = sci_dma_rx_complete; + desc->callback_param = s; + s->cookie_rx[i] = desc->tx_submit(desc); + } + + if (!desc || s->cookie_rx[i] < 0) { + if (i) { + async_tx_ack(s->desc_rx[0]); + s->cookie_rx[0] = -EINVAL; + } + if (desc) { + async_tx_ack(desc); + s->cookie_rx[i] = -EINVAL; + } + dev_warn(s->port.dev, + "failed to re-start DMA, using PIO\n"); + sci_rx_dma_release(s, true); + return; + } + } + + s->active_rx = s->cookie_rx[0]; + + dma_async_issue_pending(chan); +} + +static void work_fn_rx(struct work_struct *work) +{ + struct sci_port *s = container_of(work, struct sci_port, work_rx); + struct uart_port *port = &s->port; + struct dma_async_tx_descriptor *desc; + int new; + + if (s->active_rx == s->cookie_rx[0]) { + new = 0; + } else if (s->active_rx == s->cookie_rx[1]) { + new = 1; + } else { + dev_err(port->dev, "cookie %d not found!\n", s->active_rx); + return; + } + desc = s->desc_rx[new]; + + if (dma_async_is_tx_complete(s->chan_rx, s->active_rx, NULL, NULL) != + DMA_SUCCESS) { + /* Handle incomplete DMA receive */ + struct tty_struct *tty = port->state->port.tty; + struct dma_chan *chan = s->chan_rx; + struct sh_desc *sh_desc = container_of(desc, struct sh_desc, + async_tx); + unsigned long flags; + int count; + + chan->device->device_terminate_all(chan); + dev_dbg(port->dev, "Read %u bytes with cookie %d\n", + sh_desc->partial, sh_desc->cookie); + + spin_lock_irqsave(&port->lock, flags); + count = sci_dma_rx_push(s, tty, sh_desc->partial); + spin_unlock_irqrestore(&port->lock, flags); + + if (count) + tty_flip_buffer_push(tty); + + sci_submit_rx(s); + + return; + } + + s->cookie_rx[new] = desc->tx_submit(desc); + if (s->cookie_rx[new] < 0) { + dev_warn(port->dev, "Failed submitting Rx DMA descriptor\n"); + sci_rx_dma_release(s, true); + return; + } + + dev_dbg(port->dev, "%s: cookie %d #%d\n", __func__, + s->cookie_rx[new], new); + + s->active_rx = s->cookie_rx[!new]; +} + +static void work_fn_tx(struct work_struct *work) +{ + struct sci_port *s = container_of(work, struct sci_port, work_tx); + struct dma_async_tx_descriptor *desc; + struct dma_chan *chan = s->chan_tx; + struct uart_port *port = &s->port; + struct circ_buf *xmit = &port->state->xmit; + struct scatterlist *sg = &s->sg_tx; + + /* + * DMA is idle now. + * Port xmit buffer is already mapped, and it is one page... Just adjust + * offsets and lengths. Since it is a circular buffer, we have to + * transmit till the end, and then the rest. Take the port lock to get a + * consistent xmit buffer state. + */ + spin_lock_irq(&port->lock); + sg->offset = xmit->tail & (UART_XMIT_SIZE - 1); + sg->dma_address = (sg_dma_address(sg) & ~(UART_XMIT_SIZE - 1)) + + sg->offset; + sg->length = min((int)CIRC_CNT(xmit->head, xmit->tail, UART_XMIT_SIZE), + CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE)); + sg->dma_length = sg->length; + spin_unlock_irq(&port->lock); + + BUG_ON(!sg->length); + + desc = chan->device->device_prep_slave_sg(chan, + sg, s->sg_len_tx, DMA_TO_DEVICE, + DMA_PREP_INTERRUPT | DMA_CTRL_ACK); + if (!desc) { + /* switch to PIO */ + sci_tx_dma_release(s, true); + return; + } + + dma_sync_sg_for_device(port->dev, sg, 1, DMA_TO_DEVICE); + + spin_lock_irq(&port->lock); + s->desc_tx = desc; + desc->callback = sci_dma_tx_complete; + desc->callback_param = s; + spin_unlock_irq(&port->lock); + s->cookie_tx = desc->tx_submit(desc); + if (s->cookie_tx < 0) { + dev_warn(port->dev, "Failed submitting Tx DMA descriptor\n"); + /* switch to PIO */ + sci_tx_dma_release(s, true); + return; + } + + dev_dbg(port->dev, "%s: %p: %d...%d, cookie %d\n", __func__, + xmit->buf, xmit->tail, xmit->head, s->cookie_tx); + + dma_async_issue_pending(chan); +} +#endif + static void sci_start_tx(struct uart_port *port) { unsigned short ctrl; +#ifdef CONFIG_SERIAL_SH_SCI_DMA + struct sci_port *s = to_sci_port(port); + + if (s->chan_tx) { + if (!uart_circ_empty(&s->port.state->xmit) && s->cookie_tx < 0) + schedule_work(&s->work_tx); + + return; + } +#endif + /* Set TIE (Transmit Interrupt Enable) bit in SCSCR */ ctrl = sci_in(port, SCSCR); ctrl |= SCI_CTRL_FLAGS_TIE; @@ -838,13 +1208,12 @@ static void sci_stop_tx(struct uart_port *port) sci_out(port, SCSCR, ctrl); } -static void sci_start_rx(struct uart_port *port, unsigned int tty_start) +static void sci_start_rx(struct uart_port *port) { - unsigned short ctrl; + unsigned short ctrl = SCI_CTRL_FLAGS_RIE | SCI_CTRL_FLAGS_REIE; /* Set RIE (Receive Interrupt Enable) bit in SCSCR */ - ctrl = sci_in(port, SCSCR); - ctrl |= SCI_CTRL_FLAGS_RIE | SCI_CTRL_FLAGS_REIE; + ctrl |= sci_in(port, SCSCR); sci_out(port, SCSCR, ctrl); } @@ -868,16 +1237,154 @@ static void sci_break_ctl(struct uart_port *port, int break_state) /* Nothing here yet .. */ } +#ifdef CONFIG_SERIAL_SH_SCI_DMA +static bool filter(struct dma_chan *chan, void *slave) +{ + struct sh_dmae_slave *param = slave; + + dev_dbg(chan->device->dev, "%s: slave ID %d\n", __func__, + param->slave_id); + + if (param->dma_dev == chan->device->dev) { + chan->private = param; + return true; + } else { + return false; + } +} + +static void rx_timer_fn(unsigned long arg) +{ + struct sci_port *s = (struct sci_port *)arg; + struct uart_port *port = &s->port; + + u16 scr = sci_in(port, SCSCR); + sci_out(port, SCSCR, scr | SCI_CTRL_FLAGS_RIE); + dev_dbg(port->dev, "DMA Rx timed out\n"); + schedule_work(&s->work_rx); +} + +static void sci_request_dma(struct uart_port *port) +{ + struct sci_port *s = to_sci_port(port); + struct sh_dmae_slave *param; + struct dma_chan *chan; + dma_cap_mask_t mask; + int nent; + + dev_dbg(port->dev, "%s: port %d DMA %p\n", __func__, + port->line, s->dma_dev); + + if (!s->dma_dev) + return; + + dma_cap_zero(mask); + dma_cap_set(DMA_SLAVE, mask); + + param = &s->param_tx; + + /* Slave ID, e.g., SHDMA_SLAVE_SCIF0_TX */ + param->slave_id = s->slave_tx; + param->dma_dev = s->dma_dev; + + s->cookie_tx = -EINVAL; + chan = dma_request_channel(mask, filter, param); + dev_dbg(port->dev, "%s: TX: got channel %p\n", __func__, chan); + if (chan) { + s->chan_tx = chan; + sg_init_table(&s->sg_tx, 1); + /* UART circular tx buffer is an aligned page. */ + BUG_ON((int)port->state->xmit.buf & ~PAGE_MASK); + sg_set_page(&s->sg_tx, virt_to_page(port->state->xmit.buf), + UART_XMIT_SIZE, (int)port->state->xmit.buf & ~PAGE_MASK); + nent = dma_map_sg(port->dev, &s->sg_tx, 1, DMA_TO_DEVICE); + if (!nent) + sci_tx_dma_release(s, false); + else + dev_dbg(port->dev, "%s: mapped %d@%p to %x\n", __func__, + sg_dma_len(&s->sg_tx), + port->state->xmit.buf, sg_dma_address(&s->sg_tx)); + + s->sg_len_tx = nent; + + INIT_WORK(&s->work_tx, work_fn_tx); + } + + param = &s->param_rx; + + /* Slave ID, e.g., SHDMA_SLAVE_SCIF0_RX */ + param->slave_id = s->slave_rx; + param->dma_dev = s->dma_dev; + + chan = dma_request_channel(mask, filter, param); + dev_dbg(port->dev, "%s: RX: got channel %p\n", __func__, chan); + if (chan) { + dma_addr_t dma[2]; + void *buf[2]; + int i; + + s->chan_rx = chan; + + s->buf_len_rx = 2 * max(16, (int)port->fifosize); + buf[0] = dma_alloc_coherent(port->dev, s->buf_len_rx * 2, + &dma[0], GFP_KERNEL); + + if (!buf[0]) { + dev_warn(port->dev, + "failed to allocate dma buffer, using PIO\n"); + sci_rx_dma_release(s, true); + return; + } + + buf[1] = buf[0] + s->buf_len_rx; + dma[1] = dma[0] + s->buf_len_rx; + + for (i = 0; i < 2; i++) { + struct scatterlist *sg = &s->sg_rx[i]; + + sg_init_table(sg, 1); + sg_set_page(sg, virt_to_page(buf[i]), s->buf_len_rx, + (int)buf[i] & ~PAGE_MASK); + sg->dma_address = dma[i]; + sg->dma_length = sg->length; + } + + INIT_WORK(&s->work_rx, work_fn_rx); + setup_timer(&s->rx_timer, rx_timer_fn, (unsigned long)s); + + sci_submit_rx(s); + } +} + +static void sci_free_dma(struct uart_port *port) +{ + struct sci_port *s = to_sci_port(port); + + if (!s->dma_dev) + return; + + if (s->chan_tx) + sci_tx_dma_release(s, false); + if (s->chan_rx) + sci_rx_dma_release(s, false); +} +#endif + static int sci_startup(struct uart_port *port) { struct sci_port *s = to_sci_port(port); + dev_dbg(port->dev, "%s(%d)\n", __func__, port->line); + if (s->enable) s->enable(port); sci_request_irq(s); +#ifdef CONFIG_SERIAL_SH_SCI_DMA + sci_request_dma(port); +#endif sci_start_tx(port); - sci_start_rx(port, 1); + sci_start_rx(port); return 0; } @@ -886,8 +1393,13 @@ static void sci_shutdown(struct uart_port *port) { struct sci_port *s = to_sci_port(port); + dev_dbg(port->dev, "%s(%d)\n", __func__, port->line); + sci_stop_rx(port); sci_stop_tx(port); +#ifdef CONFIG_SERIAL_SH_SCI_DMA + sci_free_dma(port); +#endif sci_free_irq(s); if (s->disable) @@ -937,6 +1449,9 @@ static void sci_set_termios(struct uart_port *port, struct ktermios *termios, sci_out(port, SCSMR, smr_val); + dev_dbg(port->dev, "%s: SMR %x, t %x, SCSCR %x\n", __func__, smr_val, t, + SCSCR_INIT(port)); + if (t > 0) { if (t >= 256) { sci_out(port, SCSMR, (sci_in(port, SCSMR) & ~3) | 1); @@ -954,7 +1469,7 @@ static void sci_set_termios(struct uart_port *port, struct ktermios *termios, sci_out(port, SCSCR, SCSCR_INIT(port)); if ((termios->c_cflag & CREAD) != 0) - sci_start_rx(port, 0); + sci_start_rx(port); } static const char *sci_type(struct uart_port *port) @@ -1049,19 +1564,21 @@ static void __devinit sci_init_single(struct platform_device *dev, unsigned int index, struct plat_sci_port *p) { - sci_port->port.ops = &sci_uart_ops; - sci_port->port.iotype = UPIO_MEM; - sci_port->port.line = index; + struct uart_port *port = &sci_port->port; + + port->ops = &sci_uart_ops; + port->iotype = UPIO_MEM; + port->line = index; switch (p->type) { case PORT_SCIFA: - sci_port->port.fifosize = 64; + port->fifosize = 64; break; case PORT_SCIF: - sci_port->port.fifosize = 16; + port->fifosize = 16; break; default: - sci_port->port.fifosize = 1; + port->fifosize = 1; break; } @@ -1070,19 +1587,28 @@ static void __devinit sci_init_single(struct platform_device *dev, sci_port->dclk = clk_get(&dev->dev, "peripheral_clk"); sci_port->enable = sci_clk_enable; sci_port->disable = sci_clk_disable; - sci_port->port.dev = &dev->dev; + port->dev = &dev->dev; } sci_port->break_timer.data = (unsigned long)sci_port; sci_port->break_timer.function = sci_break_timer; init_timer(&sci_port->break_timer); - sci_port->port.mapbase = p->mapbase; - sci_port->port.membase = p->membase; + port->mapbase = p->mapbase; + port->membase = p->membase; - sci_port->port.irq = p->irqs[SCIx_TXI_IRQ]; - sci_port->port.flags = p->flags; - sci_port->type = sci_port->port.type = p->type; + port->irq = p->irqs[SCIx_TXI_IRQ]; + port->flags = p->flags; + sci_port->type = port->type = p->type; + +#ifdef CONFIG_SERIAL_SH_SCI_DMA + sci_port->dma_dev = p->dma_dev; + sci_port->slave_tx = p->dma_slave_tx; + sci_port->slave_rx = p->dma_slave_rx; + + dev_dbg(port->dev, "%s: DMA device %p, tx %d, rx %d\n", __func__, + p->dma_dev, p->dma_slave_tx, p->dma_slave_rx); +#endif memcpy(&sci_port->irqs, &p->irqs, sizeof(p->irqs)); } diff --git a/include/linux/serial_sci.h b/include/linux/serial_sci.h index 1c297ddc9d5..1b177d29a7f 100644 --- a/include/linux/serial_sci.h +++ b/include/linux/serial_sci.h @@ -2,6 +2,7 @@ #define __LINUX_SERIAL_SCI_H #include +#include /* * Generic header for SuperH SCI(F) (used by sh/sh64/h8300 and related parts) @@ -16,6 +17,8 @@ enum { SCIx_NR_IRQS, }; +struct device; + /* * Platform device specific platform_data struct */ @@ -26,6 +29,9 @@ struct plat_sci_port { unsigned int type; /* SCI / SCIF / IRDA */ upf_t flags; /* UPF_* flags */ char *clk; /* clock string */ + struct device *dma_dev; + enum sh_dmae_slave_chan_id dma_slave_tx; + enum sh_dmae_slave_chan_id dma_slave_rx; }; #endif /* __LINUX_SERIAL_SCI_H */ -- cgit v1.2.3-70-g09d2 From c6efd46b98f30863ca3a9982312db87b826cf715 Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Tue, 2 Mar 2010 11:53:54 +0900 Subject: serial: sh-sci: Tidy up build warnings. The recent sh-sci DMA support introduces a number of trivial build warnings, clean them up. Signed-off-by: Paul Mundt --- drivers/serial/sh-sci.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/serial/sh-sci.c b/drivers/serial/sh-sci.c index f3841cd8fc5..980f39449ee 100644 --- a/drivers/serial/sh-sci.c +++ b/drivers/serial/sh-sci.c @@ -685,7 +685,7 @@ static irqreturn_t sci_rx_interrupt(int irq, void *ptr) /* Calculate delay for 1.5 DMA buffers */ tout = (port->timeout - HZ / 50) * s->buf_len_rx * 3 / port->fifosize / 2; - dev_dbg(port->dev, "Rx IRQ: setup timeout in %u ms\n", + dev_dbg(port->dev, "Rx IRQ: setup timeout in %lu ms\n", tout * 1000 / HZ); if (tout < 2) tout = 2; @@ -999,7 +999,6 @@ static void sci_rx_dma_release(struct sci_port *s, bool enable_pio) { struct dma_chan *chan = s->chan_rx; struct uart_port *port = &s->port; - unsigned long flags; s->chan_rx = NULL; s->cookie_rx[0] = s->cookie_rx[1] = -EINVAL; @@ -1014,7 +1013,6 @@ static void sci_tx_dma_release(struct sci_port *s, bool enable_pio) { struct dma_chan *chan = s->chan_tx; struct uart_port *port = &s->port; - unsigned long flags; s->chan_tx = NULL; s->cookie_tx = -EINVAL; -- cgit v1.2.3-70-g09d2