From patchwork Wed Feb 3 15:03:46 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Guennadi Liakhovetski X-Patchwork-Id: 76710 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by demeter.kernel.org (8.14.3/8.14.3) with ESMTP id o13F3R1b004986 for ; Wed, 3 Feb 2010 15:03:32 GMT Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1755124Ab0BCPDc (ORCPT ); Wed, 3 Feb 2010 10:03:32 -0500 Received: from mail.gmx.net ([213.165.64.20]:57865 "HELO mail.gmx.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with SMTP id S1753719Ab0BCPDb (ORCPT ); Wed, 3 Feb 2010 10:03:31 -0500 Received: (qmail invoked by alias); 03 Feb 2010 15:03:28 -0000 Received: from p57BD1A11.dip0.t-ipconnect.de (EHLO axis700.grange) [87.189.26.17] by mail.gmx.net (mp059) with SMTP; 03 Feb 2010 16:03:28 +0100 X-Authenticated: #20450766 X-Provags-ID: V01U2FsdGVkX1/WuW12HyXW7ZzcP8pZd77LZpSI+flB3fmc2J/4gs RvYSJJyTXIdF2w Received: from lyakh (helo=localhost) by axis700.grange with local-esmtp (Exim 4.63) (envelope-from ) id 1Ncgle-0004JU-1r; Wed, 03 Feb 2010 16:03:46 +0100 Date: Wed, 3 Feb 2010 16:03:46 +0100 (CET) From: Guennadi Liakhovetski To: "linux-sh@vger.kernel.org" cc: Dan Williams , Paul Mundt Subject: [PATCH 1/4] sh: convert shdma dmaengine driver to use platform device resources In-Reply-To: Message-ID: References: MIME-Version: 1.0 X-Y-GMX-Trusted: 0 X-FuHaFi: 0.45000000000000001 Sender: linux-sh-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-sh@vger.kernel.org X-Greylist: IP, sender and recipient auto-whitelisted, not delayed by milter-greylist-4.2.3 (demeter.kernel.org [140.211.167.41]); Wed, 03 Feb 2010 15:03:33 +0000 (UTC) diff --git a/arch/sh/include/asm/dma-sh.h b/arch/sh/include/asm/dma-sh.h index e934a2e..238df83 100644 --- a/arch/sh/include/asm/dma-sh.h +++ b/arch/sh/include/asm/dma-sh.h @@ -154,10 +154,20 @@ struct sh_dmae_slave_config { char mid_rid; }; +struct sh_dmae_channel { + unsigned int offset; + int irq; + 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; + unsigned int dmaor_offset; }; struct device; diff --git a/arch/sh/kernel/cpu/sh4a/setup-sh7722.c b/arch/sh/kernel/cpu/sh4a/setup-sh7722.c index 5c6a40d..c1335e5 100644 --- a/arch/sh/kernel/cpu/sh4a/setup-sh7722.c +++ b/arch/sh/kernel/cpu/sh4a/setup-sh7722.c @@ -75,15 +75,73 @@ static struct sh_dmae_slave_config sh7722_dmae_slaves[] = { }, }; +static struct sh_dmae_channel sh7722_dmae_channels[] = { + { + .offset = 0, + .irq = 48, /* channel 0 IRQ is also used for shared IRQs */ + .dmars = 0, + .dmars_bit = 0, + }, { + .offset = 0x10, + .irq = 49, + .dmars = 0, + .dmars_bit = 8, + }, { + .offset = 0x20, + .irq = 50, + .dmars = 4, + .dmars_bit = 0, + }, { + .offset = 0x30, + .irq = 51, + .dmars = 4, + .dmars_bit = 8, + }, { + .offset = 0x50, + .irq = 76, + .dmars = 8, + .dmars_bit = 0, + }, { + .offset = 0x60, + .irq = 77, + .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, + .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 aa0f6e9..460d147 100644 --- a/arch/sh/kernel/cpu/sh4a/setup-sh7724.c +++ b/arch/sh/kernel/cpu/sh4a/setup-sh7724.c @@ -28,15 +28,143 @@ #include /* DMA */ -static struct sh_dmae_pdata dma_platform_data = { - .mode = SHDMA_DMAOR1, +static struct sh_dmae_channel sh7722_dmae0_channels[] = { + { + .offset = 0, + .irq = 48, /* channel 0 IRQ is also used for shared IRQs */ + .dmars = 0, + .dmars_bit = 0, + }, { + .offset = 0x10, + .irq = 49, + .dmars = 0, + .dmars_bit = 8, + }, { + .offset = 0x20, + .irq = 50, + .dmars = 4, + .dmars_bit = 0, + }, { + .offset = 0x30, + .irq = 51, + .dmars = 4, + .dmars_bit = 8, + }, { + .offset = 0x50, + .irq = 76, + .dmars = 8, + .dmars_bit = 0, + }, { + .offset = 0x60, + .irq = 77, + .dmars = 8, + .dmars_bit = 8, + } +}; + +static struct sh_dmae_channel sh7722_dmae1_channels[] = { + { + .offset = 0, + .irq = 40, /* channel 0 IRQ is also used for shared IRQs */ + .dmars = 0, + .dmars_bit = 0, + }, { + .offset = 0x10, + .irq = 41, + .dmars = 0, + .dmars_bit = 8, + }, { + .offset = 0x20, + .irq = 42, + .dmars = 4, + .dmars_bit = 0, + }, { + .offset = 0x30, + .irq = 43, + .dmars = 4, + .dmars_bit = 8, + }, { + .offset = 0x50, + .irq = 72, + .dmars = 8, + .dmars_bit = 0, + }, { + .offset = 0x60, + .irq = 73, + .dmars = 8, + .dmars_bit = 8, + } +}; + +static struct sh_dmae_pdata dma0_platform_data = { + .mode = 0, + .channel = sh7722_dmae0_channels, + .channel_num = ARRAY_SIZE(sh7722_dmae0_channels), +}; + +static struct sh_dmae_pdata dma1_platform_data = { + .mode = 0, + .channel = sh7722_dmae1_channels, + .channel_num = ARRAY_SIZE(sh7722_dmae1_channels), +}; + +static struct resource sh7722_dmae0_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, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct resource sh7722_dmae1_resources[] = { + [0] = { + /* Channel registers and DMAOR */ + .start = 0xfdc08020, + .end = 0xfdc0808f, + .flags = IORESOURCE_MEM, + }, + [1] = { + /* DMARSx */ + .start = 0xfdc09000, + .end = 0xfdc0900b, + .flags = IORESOURCE_MEM, + }, + { + /* DMA error IRQ */ + .start = 74, + .flags = IORESOURCE_IRQ, + }, }; -static struct platform_device dma_device = { +static struct platform_device dma0_device = { .name = "sh-dma-engine", - .id = -1, + .id = 0, + .resource = sh7722_dmae0_resources, + .num_resources = ARRAY_SIZE(sh7722_dmae0_resources), + .dev = { + .platform_data = &dma0_platform_data, + }, +}; + +static struct platform_device dma1_device = { + .name = "sh-dma-engine", + .id = 1, + .resource = sh7722_dmae1_resources, + .num_resources = ARRAY_SIZE(sh7722_dmae1_resources), .dev = { - .platform_data = &dma_platform_data, + .platform_data = &dma1_platform_data, }, }; @@ -663,7 +791,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 f8f2161..851de27 100644 --- a/arch/sh/kernel/cpu/sh4a/setup-sh7780.c +++ b/arch/sh/kernel/cpu/sh4a/setup-sh7780.c @@ -247,15 +247,128 @@ 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, + .irq = 34, /* channel 0 IRQ is also used for shared IRQs */ + .dmars = 0, + .dmars_bit = 0, + }, { + .offset = 0x10, + .irq = 35, + .dmars = 0, + .dmars_bit = 8, + }, { + .offset = 0x20, + .irq = 36, + .dmars = 4, + .dmars_bit = 0, + }, { + .offset = 0x30, + .irq = 37, + .dmars = 4, + .dmars_bit = 8, + }, { + .offset = 0x50, + .irq = 44, + .dmars = 8, + .dmars_bit = 0, + }, { + .offset = 0x60, + .irq = 45, + .dmars = 8, + .dmars_bit = 8, + } +}; + +static struct sh_dmae_channel sh7780_dmae1_channels[] = { + { + .offset = 0, + .irq = 46, /* channel 0 IRQ is also used for shared IRQs */ + }, { + .offset = 0x10, + .irq = 47, + }, { + .offset = 0x20, + .irq = 92, + }, { + .offset = 0x30, + .irq = 93, + }, { + .offset = 0x50, + .irq = 94, + }, { + .offset = 0x60, + .irq = 95, + } +}; + +static struct sh_dmae_pdata dma0_platform_data = { + .mode = SHDMA_MIX_IRQ, + .channel = sh7780_dmae0_channels, + .channel_num = ARRAY_SIZE(sh7780_dmae0_channels), +}; + +static struct sh_dmae_pdata dma1_platform_data = { + .mode = SHDMA_MIX_IRQ, + .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, + }, + { + /* DMA error IRQ */ + .start = 38, + .end = 38, + .flags = IORESOURCE_IRQ, + }, }; -static struct platform_device dma_device = { +static struct resource sh7780_dmae1_resources[] = { + [0] = { + /* Channel registers and DMAOR */ + .start = 0xfc818020, + .end = 0xfc81808f, + .flags = IORESOURCE_MEM, + }, + { + /* DMA error IRQ - shared with DMAC0 */ + .start = 38, + .end = 38, + .flags = IORESOURCE_IRQ, + }, +}; + +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 +382,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 23448d8..e3abc2d 100644 --- a/arch/sh/kernel/cpu/sh4a/setup-sh7785.c +++ b/arch/sh/kernel/cpu/sh4a/setup-sh7785.c @@ -295,15 +295,128 @@ 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, + .irq = 33, /* channel 0 IRQ is also used for shared IRQs */ + .dmars = 0, + .dmars_bit = 0, + }, { + .offset = 0x10, + .irq = 34, + .dmars = 0, + .dmars_bit = 8, + }, { + .offset = 0x20, + .irq = 35, + .dmars = 4, + .dmars_bit = 0, + }, { + .offset = 0x30, + .irq = 36, + .dmars = 4, + .dmars_bit = 8, + }, { + .offset = 0x50, + .irq = 37, + .dmars = 8, + .dmars_bit = 0, + }, { + .offset = 0x60, + .irq = 38, + .dmars = 8, + .dmars_bit = 8, + } +}; + +static struct sh_dmae_channel sh7785_dmae1_channels[] = { + { + .offset = 0, + .irq = 52, /* channel 0 IRQ is also used for shared IRQs */ + }, { + .offset = 0x10, + .irq = 53, + }, { + .offset = 0x20, + .irq = 54, + }, { + .offset = 0x30, + .irq = 55, + }, { + .offset = 0x50, + .irq = 56, + }, { + .offset = 0x60, + .irq = 57, + } +}; + +static struct sh_dmae_pdata dma0_platform_data = { + .mode = SHDMA_MIX_IRQ, + .channel = sh7785_dmae0_channels, + .channel_num = ARRAY_SIZE(sh7785_dmae0_channels), +}; + +static struct sh_dmae_pdata dma1_platform_data = { + .mode = SHDMA_MIX_IRQ, + .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, + }, + { + /* DMA error IRQ */ + .start = 39, + .end = 39, + .flags = IORESOURCE_IRQ, + }, }; -static struct platform_device dma_device = { +static struct resource sh7785_dmae1_resources[] = { + [0] = { + /* Channel registers and DMAOR */ + .start = 0xfcc08020, + .end = 0xfcc0808f, + .flags = IORESOURCE_MEM, + }, + { + /* DMA error IRQ - shared with DMAC0 */ + .start = 58, + .end = 58, + .flags = IORESOURCE_IRQ, + }, +}; + +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 +433,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 b75ce8b..7242776 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_write_reg(id, dmaor); + dmaor_write(shdev, dmaor & ~(DMAOR_NMIF | DMAOR_AE)); } -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(KERN_ERR "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; } @@ -736,33 +733,19 @@ static irqreturn_t sh_dmae_err(int irq, void *data) struct sh_dmae_device *shdev = (struct sh_dmae_device *)data; /* 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; - } - default: - return IRQ_NONE; + if (shdev->pdata->mode & SHDMA_MIX_IRQ) { + if (irq == shdev->pdata->channel[0].irq && + dmaor_read(shdev) & (DMAOR_NMIF | DMAOR_AE)) { + disable_irq(irq); + return IRQ_HANDLED; } + + return IRQ_NONE; } else { /* reset dma controller */ - err = sh_dmae_rst(0); + err = sh_dmae_rst(shdev); 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; } @@ -796,18 +779,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) { int err; - unsigned int irq = get_dmae_irq(id); + struct sh_dmae_channel *chan_pdata = &shdev->pdata->channel[id]; + struct platform_device *pdev = to_platform_device(shdev->common.dev); + unsigned int irq = chan_pdata->irq; unsigned long irqflags = IRQF_DISABLED; struct sh_dmae_chan *new_sh_chan; @@ -821,6 +798,7 @@ 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->base = shdev->chan_reg + chan_pdata->offset / sizeof(u32); /* Init DMA tasklet */ tasklet_init(&new_sh_chan->tasklet, dmae_do_tasklet, @@ -843,18 +821,17 @@ 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) { + 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; + irq = shdev->pdata->channel[0].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, @@ -882,8 +859,9 @@ 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_channel *chan_pdata = &shdev->pdata->channel[i]; + + free_irq(chan_pdata->irq, shchan); list_del(&shchan->common.device_node); kfree(shchan); @@ -895,47 +873,64 @@ 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; + int err = 0, cnt; 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_device *shdev; + struct resource *chan, *dmars; + int errirq; + struct sh_dmae_pdata *pdata = pdev->dev.platform_data; /* 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); + errirq = platform_get_irq(pdev, 0); + if (!chan || errirq < 0) 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; @@ -954,28 +949,23 @@ static int __init sh_dmae_probe(struct platform_device *pdev) #if defined(CONFIG_CPU_SH4) /* Non Mix IRQ mode SH7722/SH7730 etc... */ - if (shdev->pdata.mode & SHDMA_MIX_IRQ) { + if (pdata->mode & SHDMA_MIX_IRQ) { irqflags = IRQF_SHARED; - eirq[0] = DMTE0_IRQ; -#if defined(DMTE6_IRQ) && defined(DMAE1_IRQ) - eirq[1] = DMTE6_IRQ; -#endif + errirq = pdata->channel[0].irq; } - 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; - } + 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; } #endif /* CONFIG_CPU_SH4 */ /* Create DMA Channel */ - for (cnt = 0 ; cnt < MAX_DMA_CHANNELS ; cnt++) { + for (cnt = 0 ; cnt < pdata->channel_num ; cnt++) { err = sh_dmae_chan_probe(shdev, cnt); if (err) goto chan_probe_err; @@ -990,11 +980,20 @@ chan_probe_err: sh_dmae_chan_remove(shdev); eirq_err: - for (ecnt-- ; ecnt >= 0; ecnt--) - free_irq(eirq[ecnt], shdev); + free_irq(errirq, shdev); 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; } @@ -1002,36 +1001,41 @@ rst_err: static int __exit sh_dmae_remove(struct platform_device *pdev) { struct sh_dmae_device *shdev = platform_get_drvdata(pdev); + struct resource *res; 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 (shdev->pdata->mode & SHDMA_MIX_IRQ) { + free_irq(shdev->pdata->channel[0].irq, shdev); + } else { + int errirq = platform_get_irq(pdev, 0); + 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 7e227f3..a99c385 100644 --- a/drivers/dma/shdma.h +++ b/drivers/dma/shdma.h @@ -48,13 +48,16 @@ struct sh_dmae_chan { int descs_allocated; /* desc count */ int xmit_shift; /* log_2(bytes_per_xfer) */ 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)