diff options
Diffstat (limited to 'arch/sh/drivers/dma')
| -rw-r--r-- | arch/sh/drivers/dma/Kconfig | 78 | ||||
| -rw-r--r-- | arch/sh/drivers/dma/Makefile | 7 | ||||
| -rw-r--r-- | arch/sh/drivers/dma/dma-api.c | 29 | ||||
| -rw-r--r-- | arch/sh/drivers/dma/dma-g2.c | 10 | ||||
| -rw-r--r-- | arch/sh/drivers/dma/dma-isa.c | 106 | ||||
| -rw-r--r-- | arch/sh/drivers/dma/dma-pvr2.c | 15 | ||||
| -rw-r--r-- | arch/sh/drivers/dma/dma-sh.c | 257 | ||||
| -rw-r--r-- | arch/sh/drivers/dma/dma-sh.h | 74 | ||||
| -rw-r--r-- | arch/sh/drivers/dma/dma-sysfs.c | 86 | ||||
| -rw-r--r-- | arch/sh/drivers/dma/dmabrg.c | 33 |
10 files changed, 336 insertions, 359 deletions
diff --git a/arch/sh/drivers/dma/Kconfig b/arch/sh/drivers/dma/Kconfig index 01936368b8b..cfd5b90a862 100644 --- a/arch/sh/drivers/dma/Kconfig +++ b/arch/sh/drivers/dma/Kconfig @@ -1,42 +1,44 @@ menu "DMA support" -config SH_DMA_API - bool config SH_DMA bool "SuperH on-chip DMA controller (DMAC) support" depends on CPU_SH3 || CPU_SH4 - select SH_DMA_API default n -config NR_ONCHIP_DMA_CHANNELS - int +config SH_DMA_IRQ_MULTI + bool depends on SH_DMA - default "6" if CPU_SUBTYPE_SH7720 || CPU_SUBTYPE_SH7721 - default "8" if CPU_SUBTYPE_SH7750R || CPU_SUBTYPE_SH7751R - default "12" if CPU_SUBTYPE_SH7780 - default "4" - help - This allows you to specify the number of channels that the on-chip - DMAC supports. This will be 4 for SH7750/SH7751 and 8 for the - SH7750R/SH7751R. + default y if CPU_SUBTYPE_SH7750 || CPU_SUBTYPE_SH7751 || \ + CPU_SUBTYPE_SH7750S || CPU_SUBTYPE_SH7750R || \ + CPU_SUBTYPE_SH7751R || CPU_SUBTYPE_SH7091 || \ + CPU_SUBTYPE_SH7763 || CPU_SUBTYPE_SH7764 || \ + CPU_SUBTYPE_SH7780 || CPU_SUBTYPE_SH7785 || \ + CPU_SUBTYPE_SH7760 -config NR_DMA_CHANNELS_BOOL +config SH_DMA_API depends on SH_DMA - bool "Override default number of maximum DMA channels" + bool "SuperH DMA API support" + default n help - This allows you to forcibly update the maximum number of supported - DMA channels for a given board. If this is unset, this will default - to the number of channels that the on-chip DMAC has. - -config NR_DMA_CHANNELS - int "Maximum number of DMA channels" - depends on SH_DMA && NR_DMA_CHANNELS_BOOL - default NR_ONCHIP_DMA_CHANNELS + SH_DMA_API always enabled DMA API of used SuperH. + If you want to use DMA ENGINE, you must not enable this. + Please enable DMA_ENGINE and SH_DMAE. + +config NR_ONCHIP_DMA_CHANNELS + int + depends on SH_DMA + default "4" if CPU_SUBTYPE_SH7750 || CPU_SUBTYPE_SH7751 || \ + CPU_SUBTYPE_SH7750S || CPU_SUBTYPE_SH7091 + default "8" if CPU_SUBTYPE_SH7750R || CPU_SUBTYPE_SH7751R || \ + CPU_SUBTYPE_SH7760 + default "12" if CPU_SUBTYPE_SH7723 || CPU_SUBTYPE_SH7780 || \ + CPU_SUBTYPE_SH7785 || CPU_SUBTYPE_SH7724 + default "6" help - This allows you to specify the maximum number of DMA channels to - support. Setting this to a higher value allows for cascading DMACs - with additional channels. + This allows you to specify the number of channels that the on-chip + DMAC supports. This will be 4 for SH7750/SH7751/Sh7750S/SH7091 and 8 for the + SH7750R/SH7751R/SH7760, 12 for the SH7723/SH7780/SH7785/SH7724, default is 6. config SH_DMABRG bool "SH7760 DMABRG support" @@ -46,4 +48,28 @@ config SH_DMABRG of the SH7760. Say Y if you want to use Audio/USB DMA on your SH7760 board. +config PVR2_DMA + tristate "PowerVR 2 DMAC support" + depends on SH_DREAMCAST && SH_DMA + help + Selecting this will enable support for the PVR2 DMA controller. + As this chains off of the on-chip DMAC, that must also be + enabled by default. + + This is primarily used by the pvr2fb framebuffer driver for + certain optimizations, but is not necessary for functionality. + + If in doubt, say N. + +config G2_DMA + tristate "G2 Bus DMA support" + depends on SH_DREAMCAST + select SH_DMA_API + help + This enables support for the DMA controller for the Dreamcast's + G2 bus. Drivers that want this will generally enable this on + their own. + + If in doubt, say N. + endmenu diff --git a/arch/sh/drivers/dma/Makefile b/arch/sh/drivers/dma/Makefile index 1ac812d2448..d88c9484762 100644 --- a/arch/sh/drivers/dma/Makefile +++ b/arch/sh/drivers/dma/Makefile @@ -2,8 +2,7 @@ # Makefile for the SuperH DMA specific kernel interface routines under Linux. # -obj-$(CONFIG_SH_DMA_API) += dma-api.o dma-sysfs.o -obj-$(CONFIG_ISA_DMA_API) += dma-isa.o -obj-$(CONFIG_SH_DMA) += dma-sh.o -obj-$(CONFIG_SH_DREAMCAST) += dma-pvr2.o dma-g2.o +obj-$(CONFIG_SH_DMA_API) += dma-sh.o dma-api.o dma-sysfs.o +obj-$(CONFIG_PVR2_DMA) += dma-pvr2.o +obj-$(CONFIG_G2_DMA) += dma-g2.o obj-$(CONFIG_SH_DMABRG) += dmabrg.o diff --git a/arch/sh/drivers/dma/dma-api.c b/arch/sh/drivers/dma/dma-api.c index 727126e907e..c0eec08d8f9 100644 --- a/arch/sh/drivers/dma/dma-api.c +++ b/arch/sh/drivers/dma/dma-api.c @@ -13,10 +13,12 @@ #include <linux/module.h> #include <linux/spinlock.h> #include <linux/proc_fs.h> +#include <linux/seq_file.h> #include <linux/list.h> #include <linux/platform_device.h> #include <linux/mm.h> #include <linux/sched.h> +#include <linux/slab.h> #include <asm/dma.h> DEFINE_SPINLOCK(dma_spin_lock); @@ -307,11 +309,9 @@ int dma_extend(unsigned int chan, unsigned long op, void *param) } EXPORT_SYMBOL(dma_extend); -static int dma_read_proc(char *buf, char **start, off_t off, - int len, int *eof, void *data) +static int dma_proc_show(struct seq_file *m, void *v) { - struct dma_info *info; - char *p = buf; + struct dma_info *info = v; if (list_empty(®istered_dmac_list)) return 0; @@ -331,14 +331,26 @@ static int dma_read_proc(char *buf, char **start, off_t off, if (!(channel->flags & DMA_CONFIGURED)) continue; - p += sprintf(p, "%2d: %14s %s\n", i, - info->name, channel->dev_id); + seq_printf(m, "%2d: %14s %s\n", i, + info->name, channel->dev_id); } } - return p - buf; + return 0; } +static int dma_proc_open(struct inode *inode, struct file *file) +{ + return single_open(file, dma_proc_show, NULL); +} + +static const struct file_operations dma_proc_fops = { + .open = dma_proc_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + int register_dmac(struct dma_info *info) { unsigned int total_channels, i; @@ -411,8 +423,7 @@ EXPORT_SYMBOL(unregister_dmac); static int __init dma_api_init(void) { printk(KERN_NOTICE "DMA: Registering DMA API.\n"); - create_proc_read_entry("dma", 0, 0, dma_read_proc, 0); - return 0; + return proc_create("dma", 0, NULL, &dma_proc_fops) ? 0 : -ENOMEM; } subsys_initcall(dma_api_init); diff --git a/arch/sh/drivers/dma/dma-g2.c b/arch/sh/drivers/dma/dma-g2.c index 0caf11bb7e2..e1ab6eb3c04 100644 --- a/arch/sh/drivers/dma/dma-g2.c +++ b/arch/sh/drivers/dma/dma-g2.c @@ -14,8 +14,8 @@ #include <linux/module.h> #include <linux/interrupt.h> #include <asm/cacheflush.h> -#include <asm/mach/sysasic.h> -#include <asm/mach/dma.h> +#include <mach/sysasic.h> +#include <mach/dma.h> #include <asm/dma.h> struct g2_channel { @@ -170,7 +170,7 @@ static int __init g2_dma_init(void) { int ret; - ret = request_irq(HW_EVENT_G2_DMA, g2_dma_interrupt, IRQF_DISABLED, + ret = request_irq(HW_EVENT_G2_DMA, g2_dma_interrupt, 0, "g2 DMA handler", &g2_dma_info); if (unlikely(ret)) return -EINVAL; @@ -181,14 +181,14 @@ static int __init g2_dma_init(void) ret = register_dmac(&g2_dma_info); if (unlikely(ret != 0)) - free_irq(HW_EVENT_G2_DMA, 0); + free_irq(HW_EVENT_G2_DMA, &g2_dma_info); return ret; } static void __exit g2_dma_exit(void) { - free_irq(HW_EVENT_G2_DMA, 0); + free_irq(HW_EVENT_G2_DMA, &g2_dma_info); unregister_dmac(&g2_dma_info); } diff --git a/arch/sh/drivers/dma/dma-isa.c b/arch/sh/drivers/dma/dma-isa.c deleted file mode 100644 index 5fb044b791c..00000000000 --- a/arch/sh/drivers/dma/dma-isa.c +++ /dev/null @@ -1,106 +0,0 @@ -/* - * arch/sh/drivers/dma/dma-isa.c - * - * Generic ISA DMA wrapper for SH DMA API - * - * Copyright (C) 2003, 2004 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. - */ -#include <linux/kernel.h> -#include <linux/module.h> -#include <asm/dma.h> - -/* - * This implements a small wrapper set to make code using the old ISA DMA API - * work with the SH DMA API. Since most of the work in the new API happens - * at ops->xfer() time, we simply use the various set_dma_xxx() routines to - * fill in per-channel info, and then hand hand this off to ops->xfer() at - * enable_dma() time. - * - * For channels that are doing on-demand data transfer via cascading, the - * channel itself will still need to be configured through the new API. As - * such, this code is meant for only the simplest of tasks (and shouldn't be - * used in any new drivers at all). - * - * NOTE: ops->xfer() is the preferred way of doing things. However, there - * are some users of the ISA DMA API that exist in common code that we - * don't necessarily want to go out of our way to break, so we still - * allow for some compatibility at that level. Any new code is strongly - * advised to run far away from the ISA DMA API and use the SH DMA API - * directly. - */ -unsigned long claim_dma_lock(void) -{ - unsigned long flags; - - spin_lock_irqsave(&dma_spin_lock, flags); - - return flags; -} -EXPORT_SYMBOL(claim_dma_lock); - -void release_dma_lock(unsigned long flags) -{ - spin_unlock_irqrestore(&dma_spin_lock, flags); -} -EXPORT_SYMBOL(release_dma_lock); - -void disable_dma(unsigned int chan) -{ - /* Nothing */ -} -EXPORT_SYMBOL(disable_dma); - -void enable_dma(unsigned int chan) -{ - struct dma_info *info = get_dma_info(chan); - struct dma_channel *channel = &info->channels[chan]; - - info->ops->xfer(channel); -} -EXPORT_SYMBOL(enable_dma); - -void clear_dma_ff(unsigned int chan) -{ - /* Nothing */ -} -EXPORT_SYMBOL(clear_dma_ff); - -void set_dma_mode(unsigned int chan, char mode) -{ - struct dma_info *info = get_dma_info(chan); - struct dma_channel *channel = &info->channels[chan]; - - channel->mode = mode; -} -EXPORT_SYMBOL(set_dma_mode); - -void set_dma_addr(unsigned int chan, unsigned int addr) -{ - struct dma_info *info = get_dma_info(chan); - struct dma_channel *channel = &info->channels[chan]; - - /* - * Single address mode is the only thing supported through - * this interface. - */ - if ((channel->mode & DMA_MODE_MASK) == DMA_MODE_READ) { - channel->sar = addr; - } else { - channel->dar = addr; - } -} -EXPORT_SYMBOL(set_dma_addr); - -void set_dma_count(unsigned int chan, unsigned int count) -{ - struct dma_info *info = get_dma_info(chan); - struct dma_channel *channel = &info->channels[chan]; - - channel->count = count; -} -EXPORT_SYMBOL(set_dma_count); - diff --git a/arch/sh/drivers/dma/dma-pvr2.c b/arch/sh/drivers/dma/dma-pvr2.c index 838fad566ea..706a3434af7 100644 --- a/arch/sh/drivers/dma/dma-pvr2.c +++ b/arch/sh/drivers/dma/dma-pvr2.c @@ -13,8 +13,8 @@ #include <linux/kernel.h> #include <linux/module.h> #include <linux/interrupt.h> -#include <asm/mach/sysasic.h> -#include <asm/mach/dma.h> +#include <mach/sysasic.h> +#include <mach/dma.h> #include <asm/dma.h> #include <asm/io.h> @@ -40,10 +40,10 @@ static irqreturn_t pvr2_dma_interrupt(int irq, void *dev_id) static int pvr2_request_dma(struct dma_channel *chan) { - if (ctrl_inl(PVR2_DMA_MODE) != 0) + if (__raw_readl(PVR2_DMA_MODE) != 0) return -EBUSY; - ctrl_outl(0, PVR2_DMA_LMMODE0); + __raw_writel(0, PVR2_DMA_LMMODE0); return 0; } @@ -60,9 +60,9 @@ static int pvr2_xfer_dma(struct dma_channel *chan) xfer_complete = 0; - ctrl_outl(chan->dar, PVR2_DMA_ADDR); - ctrl_outl(chan->count, PVR2_DMA_COUNT); - ctrl_outl(chan->mode & DMA_MODE_MASK, PVR2_DMA_MODE); + __raw_writel(chan->dar, PVR2_DMA_ADDR); + __raw_writel(chan->count, PVR2_DMA_COUNT); + __raw_writel(chan->mode & DMA_MODE_MASK, PVR2_DMA_MODE); return 0; } @@ -70,7 +70,6 @@ static int pvr2_xfer_dma(struct dma_channel *chan) static struct irqaction pvr2_dma_irq = { .name = "pvr2 DMA handler", .handler = pvr2_dma_interrupt, - .flags = IRQF_DISABLED, }; static struct dma_ops pvr2_dma_ops = { diff --git a/arch/sh/drivers/dma/dma-sh.c b/arch/sh/drivers/dma/dma-sh.c index 71ff3d6f26e..b2256562314 100644 --- a/arch/sh/drivers/dma/dma-sh.c +++ b/arch/sh/drivers/dma/dma-sh.c @@ -14,40 +14,72 @@ #include <linux/init.h> #include <linux/interrupt.h> #include <linux/module.h> -#include <asm/dreamcast/dma.h> +#include <linux/io.h> +#include <mach-dreamcast/mach/dma.h> #include <asm/dma.h> -#include <asm/io.h> -#include "dma-sh.h" - -static int dmte_irq_map[] = { - DMTE0_IRQ, - DMTE1_IRQ, - DMTE2_IRQ, - DMTE3_IRQ, -#if defined(CONFIG_CPU_SUBTYPE_SH7720) || \ - defined(CONFIG_CPU_SUBTYPE_SH7721) || \ - defined(CONFIG_CPU_SUBTYPE_SH7751R) || \ - defined(CONFIG_CPU_SUBTYPE_SH7760) || \ - defined(CONFIG_CPU_SUBTYPE_SH7709) || \ - defined(CONFIG_CPU_SUBTYPE_SH7780) - DMTE4_IRQ, - DMTE5_IRQ, +#include <asm/dma-register.h> +#include <cpu/dma-register.h> +#include <cpu/dma.h> + +/* + * Define the default configuration for dual address memory-memory transfer. + * The 0x400 value represents auto-request, external->external. + */ +#define RS_DUAL (DM_INC | SM_INC | 0x400 | TS_INDEX2VAL(XMIT_SZ_32BIT)) + +static unsigned long dma_find_base(unsigned int chan) +{ + unsigned long base = SH_DMAC_BASE0; + +#ifdef SH_DMAC_BASE1 + if (chan >= 6) + base = SH_DMAC_BASE1; +#endif + + return base; +} + +static unsigned long dma_base_addr(unsigned int chan) +{ + unsigned long base = dma_find_base(chan); + + /* Normalize offset calculation */ + if (chan >= 9) + chan -= 6; + if (chan >= 4) + base += 0x10; + + return base + (chan * 0x10); +} + +#ifdef CONFIG_SH_DMA_IRQ_MULTI +static inline unsigned int get_dmte_irq(unsigned int chan) +{ + return chan >= 6 ? DMTE6_IRQ : DMTE0_IRQ; +} +#else + +static unsigned int dmte_irq_map[] = { + DMTE0_IRQ, DMTE0_IRQ + 1, DMTE0_IRQ + 2, DMTE0_IRQ + 3, + +#ifdef DMTE4_IRQ + DMTE4_IRQ, DMTE4_IRQ + 1, #endif -#if defined(CONFIG_CPU_SUBTYPE_SH7751R) || \ - defined(CONFIG_CPU_SUBTYPE_SH7760) || \ - defined(CONFIG_CPU_SUBTYPE_SH7780) - DMTE6_IRQ, - DMTE7_IRQ, + +#ifdef DMTE6_IRQ + DMTE6_IRQ, DMTE6_IRQ + 1, +#endif + +#ifdef DMTE8_IRQ + DMTE8_IRQ, DMTE9_IRQ, DMTE10_IRQ, DMTE11_IRQ, #endif }; static inline unsigned int get_dmte_irq(unsigned int chan) { - unsigned int irq = 0; - if (chan < ARRAY_SIZE(dmte_irq_map)) - irq = dmte_irq_map[chan]; - return irq; + return dmte_irq_map[chan]; } +#endif /* * We determine the correct shift size based off of the CHCR transmit size @@ -57,11 +89,15 @@ static inline unsigned int get_dmte_irq(unsigned int chan) * * iterations to complete the transfer. */ +static unsigned int ts_shift[] = TS_SHIFT; + static inline unsigned int calc_xmit_shift(struct dma_channel *chan) { - u32 chcr = ctrl_inl(CHCR[chan->chan]); + u32 chcr = __raw_readl(dma_base_addr(chan->chan) + CHCR); + int cnt = ((chcr & CHCR_TS_LOW_MASK) >> CHCR_TS_LOW_SHIFT) | + ((chcr & CHCR_TS_HIGH_MASK) >> CHCR_TS_HIGH_SHIFT); - return ts_shift[(chcr & CHCR_TS_MASK)>>CHCR_TS_SHIFT]; + return ts_shift[cnt]; } /* @@ -75,13 +111,13 @@ static irqreturn_t dma_tei(int irq, void *dev_id) struct dma_channel *chan = dev_id; u32 chcr; - chcr = ctrl_inl(CHCR[chan->chan]); + chcr = __raw_readl(dma_base_addr(chan->chan) + CHCR); if (!(chcr & CHCR_TE)) return IRQ_NONE; chcr &= ~(CHCR_IE | CHCR_DE); - ctrl_outl(chcr, CHCR[chan->chan]); + __raw_writel(chcr, (dma_base_addr(chan->chan) + CHCR)); wake_up(&chan->wait_queue); @@ -93,8 +129,8 @@ static int sh_dmac_request_dma(struct dma_channel *chan) if (unlikely(!(chan->flags & DMA_TEI_CAPABLE))) return 0; - return request_irq(get_dmte_irq(chan->chan), dma_tei, - IRQF_DISABLED, chan->dev_id, chan); + return request_irq(get_dmte_irq(chan->chan), dma_tei, IRQF_SHARED, + chan->dev_id, chan); } static void sh_dmac_free_dma(struct dma_channel *chan) @@ -115,7 +151,7 @@ sh_dmac_configure_channel(struct dma_channel *chan, unsigned long chcr) chan->flags &= ~DMA_TEI_CAPABLE; } - ctrl_outl(chcr, CHCR[chan->chan]); + __raw_writel(chcr, (dma_base_addr(chan->chan) + CHCR)); chan->flags |= DMA_CONFIGURED; return 0; @@ -126,13 +162,13 @@ static void sh_dmac_enable_dma(struct dma_channel *chan) int irq; u32 chcr; - chcr = ctrl_inl(CHCR[chan->chan]); + chcr = __raw_readl(dma_base_addr(chan->chan) + CHCR); chcr |= CHCR_DE; if (chan->flags & DMA_TEI_CAPABLE) chcr |= CHCR_IE; - ctrl_outl(chcr, CHCR[chan->chan]); + __raw_writel(chcr, (dma_base_addr(chan->chan) + CHCR)); if (chan->flags & DMA_TEI_CAPABLE) { irq = get_dmte_irq(chan->chan); @@ -150,9 +186,9 @@ static void sh_dmac_disable_dma(struct dma_channel *chan) disable_irq(irq); } - chcr = ctrl_inl(CHCR[chan->chan]); + chcr = __raw_readl(dma_base_addr(chan->chan) + CHCR); chcr &= ~(CHCR_DE | CHCR_TE | CHCR_IE); - ctrl_outl(chcr, CHCR[chan->chan]); + __raw_writel(chcr, (dma_base_addr(chan->chan) + CHCR)); } static int sh_dmac_xfer_dma(struct dma_channel *chan) @@ -183,12 +219,13 @@ static int sh_dmac_xfer_dma(struct dma_channel *chan) */ if (chan->sar || (mach_is_dreamcast() && chan->chan == PVR2_CASCADE_CHAN)) - ctrl_outl(chan->sar, SAR[chan->chan]); + __raw_writel(chan->sar, (dma_base_addr(chan->chan) + SAR)); if (chan->dar || (mach_is_dreamcast() && chan->chan == PVR2_CASCADE_CHAN)) - ctrl_outl(chan->dar, DAR[chan->chan]); + __raw_writel(chan->dar, (dma_base_addr(chan->chan) + DAR)); - ctrl_outl(chan->count >> calc_xmit_shift(chan), DMATCR[chan->chan]); + __raw_writel(chan->count >> calc_xmit_shift(chan), + (dma_base_addr(chan->chan) + TCR)); sh_dmac_enable_dma(chan); @@ -197,35 +234,45 @@ static int sh_dmac_xfer_dma(struct dma_channel *chan) static int sh_dmac_get_dma_residue(struct dma_channel *chan) { - if (!(ctrl_inl(CHCR[chan->chan]) & CHCR_DE)) + if (!(__raw_readl(dma_base_addr(chan->chan) + CHCR) & CHCR_DE)) return 0; - return ctrl_inl(DMATCR[chan->chan]) << calc_xmit_shift(chan); + return __raw_readl(dma_base_addr(chan->chan) + TCR) + << calc_xmit_shift(chan); } -#if defined(CONFIG_CPU_SUBTYPE_SH7720) || \ - defined(CONFIG_CPU_SUBTYPE_SH7721) || \ - defined(CONFIG_CPU_SUBTYPE_SH7780) -#define dmaor_read_reg() ctrl_inw(DMAOR) -#define dmaor_write_reg(data) ctrl_outw(data, DMAOR) +/* + * DMAOR handling + */ +#if defined(CONFIG_CPU_SUBTYPE_SH7723) || \ + defined(CONFIG_CPU_SUBTYPE_SH7724) || \ + defined(CONFIG_CPU_SUBTYPE_SH7780) || \ + defined(CONFIG_CPU_SUBTYPE_SH7785) +#define NR_DMAOR 2 #else -#define dmaor_read_reg() ctrl_inl(DMAOR) -#define dmaor_write_reg(data) ctrl_outl(data, DMAOR) +#define NR_DMAOR 1 #endif -static inline int dmaor_reset(void) +/* + * DMAOR bases are broken out amongst channel groups. DMAOR0 manages + * channels 0 - 5, DMAOR1 6 - 11 (optional). + */ +#define dmaor_read_reg(n) __raw_readw(dma_find_base((n)*6)) +#define dmaor_write_reg(n, data) __raw_writew(data, dma_find_base(n)*6) + +static inline int dmaor_reset(int no) { - unsigned long dmaor = dmaor_read_reg(); + unsigned long dmaor = dmaor_read_reg(no); /* Try to clear the error flags first, incase they are set */ dmaor &= ~(DMAOR_NMIF | DMAOR_AE); - dmaor_write_reg(dmaor); + dmaor_write_reg(no, dmaor); dmaor |= DMAOR_INIT; - dmaor_write_reg(dmaor); + dmaor_write_reg(no, dmaor); /* See if we got an error again */ - if ((dmaor_read_reg() & (DMAOR_AE | DMAOR_NMIF))) { + if ((dmaor_read_reg(no) & (DMAOR_AE | DMAOR_NMIF))) { printk(KERN_ERR "dma-sh: Can't initialize DMAOR.\n"); return -EINVAL; } @@ -233,14 +280,87 @@ static inline int dmaor_reset(void) return 0; } -#if defined(CONFIG_CPU_SH4) +/* + * DMAE handling + */ +#ifdef CONFIG_CPU_SH4 + +#if defined(DMAE1_IRQ) +#define NR_DMAE 2 +#else +#define NR_DMAE 1 +#endif + +static const char *dmae_name[] = { + "DMAC Address Error0", + "DMAC Address Error1" +}; + +#ifdef CONFIG_SH_DMA_IRQ_MULTI +static inline unsigned int get_dma_error_irq(int n) +{ + return get_dmte_irq(n * 6); +} +#else + +static unsigned int dmae_irq_map[] = { + DMAE0_IRQ, + +#ifdef DMAE1_IRQ + DMAE1_IRQ, +#endif +}; + +static inline unsigned int get_dma_error_irq(int n) +{ + return dmae_irq_map[n]; +} +#endif + static irqreturn_t dma_err(int irq, void *dummy) { - dmaor_reset(); + int i; + + for (i = 0; i < NR_DMAOR; i++) + dmaor_reset(i); + disable_irq(irq); return IRQ_HANDLED; } + +static int dmae_irq_init(void) +{ + int n; + + for (n = 0; n < NR_DMAE; n++) { + int i = request_irq(get_dma_error_irq(n), dma_err, + IRQF_SHARED, dmae_name[n], (void *)dmae_name[n]); + if (unlikely(i < 0)) { + printk(KERN_ERR "%s request_irq fail\n", dmae_name[n]); + return i; + } + } + + return 0; +} + +static void dmae_irq_free(void) +{ + int n; + + for (n = 0; n < NR_DMAE; n++) + free_irq(get_dma_error_irq(n), NULL); +} +#else +static inline int dmae_irq_init(void) +{ + return 0; +} + +static void dmae_irq_free(void) +{ +} #endif static struct dma_ops sh_dmac_ops = { @@ -261,30 +381,31 @@ static struct dma_info sh_dmac_info = { static int __init sh_dmac_init(void) { struct dma_info *info = &sh_dmac_info; - int i; + int i, rc; -#ifdef CONFIG_CPU_SH4 - i = request_irq(DMAE_IRQ, dma_err, IRQF_DISABLED, "DMAC Address Error", 0); - if (unlikely(i < 0)) - return i; -#endif + /* + * Initialize DMAE, for parts that support it. + */ + rc = dmae_irq_init(); + if (unlikely(rc != 0)) + return rc; /* * Initialize DMAOR, and clean up any error flags that may have * been set. */ - i = dmaor_reset(); - if (unlikely(i != 0)) - return i; + for (i = 0; i < NR_DMAOR; i++) { + rc = dmaor_reset(i); + if (unlikely(rc != 0)) + return rc; + } return register_dmac(info); } static void __exit sh_dmac_exit(void) { -#ifdef CONFIG_CPU_SH4 - free_irq(DMAE_IRQ, 0); -#endif + dmae_irq_free(); unregister_dmac(&sh_dmac_info); } diff --git a/arch/sh/drivers/dma/dma-sh.h b/arch/sh/drivers/dma/dma-sh.h deleted file mode 100644 index 0f591fbc922..00000000000 --- a/arch/sh/drivers/dma/dma-sh.h +++ /dev/null @@ -1,74 +0,0 @@ -/* - * arch/sh/drivers/dma/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_SH_H -#define __DMA_SH_H - -#include <asm/cpu/dma.h> - -/* 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 SM_INC 0x00001000 -#define SM_DEC 0x00002000 -#define RS_IN 0x00000200 -#define RS_OUT 0x00000300 -#define TS_BLK 0x00000040 -#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. - */ -#define RS_DUAL (DM_INC | SM_INC | 0x400 | TS_32) - -#define MAX_DMAC_CHANNELS (CONFIG_NR_ONCHIP_DMA_CHANNELS) - -/* - * Subtypes that have fewer channels than this simply need to change - * CONFIG_NR_ONCHIP_DMA_CHANNELS. Likewise, subtypes with a larger number - * of channels should expand on this. - * - * For most subtypes we can easily figure these values out with some - * basic calculation, unfortunately on other subtypes these are more - * scattered, so we just leave it unrolled for simplicity. - */ -#define SAR ((unsigned long[]){SH_DMAC_BASE + 0x00, SH_DMAC_BASE + 0x10, \ - SH_DMAC_BASE + 0x20, SH_DMAC_BASE + 0x30, \ - SH_DMAC_BASE + 0x50, SH_DMAC_BASE + 0x60}) -#define DAR ((unsigned long[]){SH_DMAC_BASE + 0x04, SH_DMAC_BASE + 0x14, \ - SH_DMAC_BASE + 0x24, SH_DMAC_BASE + 0x34, \ - SH_DMAC_BASE + 0x54, SH_DMAC_BASE + 0x64}) -#define DMATCR ((unsigned long[]){SH_DMAC_BASE + 0x08, SH_DMAC_BASE + 0x18, \ - SH_DMAC_BASE + 0x28, SH_DMAC_BASE + 0x38, \ - SH_DMAC_BASE + 0x58, SH_DMAC_BASE + 0x68}) -#define CHCR ((unsigned long[]){SH_DMAC_BASE + 0x0c, SH_DMAC_BASE + 0x1c, \ - SH_DMAC_BASE + 0x2c, SH_DMAC_BASE + 0x3c, \ - SH_DMAC_BASE + 0x5c, SH_DMAC_BASE + 0x6c}) - -#define DMAOR (SH_DMAC_BASE + 0x40) - -#endif /* __DMA_SH_H */ - diff --git a/arch/sh/drivers/dma/dma-sysfs.c b/arch/sh/drivers/dma/dma-sysfs.c index 347ee11351e..4b15feda54b 100644 --- a/arch/sh/drivers/dma/dma-sysfs.c +++ b/arch/sh/drivers/dma/dma-sysfs.c @@ -11,25 +11,25 @@ */ #include <linux/kernel.h> #include <linux/init.h> -#include <linux/sysdev.h> +#include <linux/stat.h> +#include <linux/device.h> #include <linux/platform_device.h> -#include <linux/module.h> #include <linux/err.h> #include <linux/string.h> #include <asm/dma.h> -static struct sysdev_class dma_sysclass = { +static struct bus_type dma_subsys = { .name = "dma", + .dev_name = "dma", }; -EXPORT_SYMBOL(dma_sysclass); -static ssize_t dma_show_devices(struct sys_device *dev, - struct sysdev_attribute *attr, char *buf) +static ssize_t dma_show_devices(struct device *dev, + struct device_attribute *attr, char *buf) { ssize_t len = 0; int i; - for (i = 0; i < MAX_DMA_CHANNELS; i++) { + for (i = 0; i < 16; i++) { struct dma_info *info = get_dma_info(i); struct dma_channel *channel = get_dma_channel(i); @@ -44,29 +44,29 @@ static ssize_t dma_show_devices(struct sys_device *dev, return len; } -static SYSDEV_ATTR(devices, S_IRUGO, dma_show_devices, NULL); +static DEVICE_ATTR(devices, S_IRUGO, dma_show_devices, NULL); -static int __init dma_sysclass_init(void) +static int __init dma_subsys_init(void) { int ret; - ret = sysdev_class_register(&dma_sysclass); + ret = subsys_system_register(&dma_subsys, NULL); if (unlikely(ret)) return ret; - return sysfs_create_file(&dma_sysclass.kset.kobj, &attr_devices.attr); + return device_create_file(dma_subsys.dev_root, &dev_attr_devices); } -postcore_initcall(dma_sysclass_init); +postcore_initcall(dma_subsys_init); -static ssize_t dma_show_dev_id(struct sys_device *dev, - struct sysdev_attribute *attr, char *buf) +static ssize_t dma_show_dev_id(struct device *dev, + struct device_attribute *attr, char *buf) { struct dma_channel *channel = to_dma_channel(dev); return sprintf(buf, "%s\n", channel->dev_id); } -static ssize_t dma_store_dev_id(struct sys_device *dev, - struct sysdev_attribute *attr, +static ssize_t dma_store_dev_id(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) { struct dma_channel *channel = to_dma_channel(dev); @@ -74,10 +74,10 @@ static ssize_t dma_store_dev_id(struct sys_device *dev, return count; } -static SYSDEV_ATTR(dev_id, S_IRUGO | S_IWUSR, dma_show_dev_id, dma_store_dev_id); +static DEVICE_ATTR(dev_id, S_IRUGO | S_IWUSR, dma_show_dev_id, dma_store_dev_id); -static ssize_t dma_store_config(struct sys_device *dev, - struct sysdev_attribute *attr, +static ssize_t dma_store_config(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) { struct dma_channel *channel = to_dma_channel(dev); @@ -89,17 +89,17 @@ static ssize_t dma_store_config(struct sys_device *dev, return count; } -static SYSDEV_ATTR(config, S_IWUSR, NULL, dma_store_config); +static DEVICE_ATTR(config, S_IWUSR, NULL, dma_store_config); -static ssize_t dma_show_mode(struct sys_device *dev, - struct sysdev_attribute *attr, char *buf) +static ssize_t dma_show_mode(struct device *dev, + struct device_attribute *attr, char *buf) { struct dma_channel *channel = to_dma_channel(dev); return sprintf(buf, "0x%08x\n", channel->mode); } -static ssize_t dma_store_mode(struct sys_device *dev, - struct sysdev_attribute *attr, +static ssize_t dma_store_mode(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) { struct dma_channel *channel = to_dma_channel(dev); @@ -107,38 +107,38 @@ static ssize_t dma_store_mode(struct sys_device *dev, return count; } -static SYSDEV_ATTR(mode, S_IRUGO | S_IWUSR, dma_show_mode, dma_store_mode); +static DEVICE_ATTR(mode, S_IRUGO | S_IWUSR, dma_show_mode, dma_store_mode); #define dma_ro_attr(field, fmt) \ -static ssize_t dma_show_##field(struct sys_device *dev, \ - struct sysdev_attribute *attr, char *buf)\ +static ssize_t dma_show_##field(struct device *dev, \ + struct device_attribute *attr, char *buf)\ { \ struct dma_channel *channel = to_dma_channel(dev); \ return sprintf(buf, fmt, channel->field); \ } \ -static SYSDEV_ATTR(field, S_IRUGO, dma_show_##field, NULL); +static DEVICE_ATTR(field, S_IRUGO, dma_show_##field, NULL); dma_ro_attr(count, "0x%08x\n"); dma_ro_attr(flags, "0x%08lx\n"); int dma_create_sysfs_files(struct dma_channel *chan, struct dma_info *info) { - struct sys_device *dev = &chan->dev; + struct device *dev = &chan->dev; char name[16]; int ret; dev->id = chan->vchan; - dev->cls = &dma_sysclass; + dev->bus = &dma_subsys; - ret = sysdev_register(dev); + ret = device_register(dev); if (ret) return ret; - ret |= sysdev_create_file(dev, &attr_dev_id); - ret |= sysdev_create_file(dev, &attr_count); - ret |= sysdev_create_file(dev, &attr_mode); - ret |= sysdev_create_file(dev, &attr_flags); - ret |= sysdev_create_file(dev, &attr_config); + ret |= device_create_file(dev, &dev_attr_dev_id); + ret |= device_create_file(dev, &dev_attr_count); + ret |= device_create_file(dev, &dev_attr_mode); + ret |= device_create_file(dev, &dev_attr_flags); + ret |= device_create_file(dev, &dev_attr_config); if (unlikely(ret)) { dev_err(&info->pdev->dev, "Failed creating attrs\n"); @@ -151,17 +151,17 @@ int dma_create_sysfs_files(struct dma_channel *chan, struct dma_info *info) void dma_remove_sysfs_files(struct dma_channel *chan, struct dma_info *info) { - struct sys_device *dev = &chan->dev; + struct device *dev = &chan->dev; char name[16]; - sysdev_remove_file(dev, &attr_dev_id); - sysdev_remove_file(dev, &attr_count); - sysdev_remove_file(dev, &attr_mode); - sysdev_remove_file(dev, &attr_flags); - sysdev_remove_file(dev, &attr_config); + device_remove_file(dev, &dev_attr_dev_id); + device_remove_file(dev, &dev_attr_count); + device_remove_file(dev, &dev_attr_mode); + device_remove_file(dev, &dev_attr_flags); + device_remove_file(dev, &dev_attr_config); snprintf(name, sizeof(name), "dma%d", chan->chan); sysfs_remove_link(&info->pdev->dev.kobj, name); - sysdev_unregister(dev); + device_unregister(dev); } diff --git a/arch/sh/drivers/dma/dmabrg.c b/arch/sh/drivers/dma/dmabrg.c index 5e22689c2fc..c0dd904483c 100644 --- a/arch/sh/drivers/dma/dmabrg.c +++ b/arch/sh/drivers/dma/dmabrg.c @@ -8,6 +8,7 @@ #include <linux/interrupt.h> #include <linux/kernel.h> +#include <linux/slab.h> #include <asm/dma.h> #include <asm/dmabrg.h> #include <asm/io.h> @@ -86,8 +87,8 @@ static irqreturn_t dmabrg_irq(int irq, void *data) unsigned long dcr; unsigned int i; - dcr = ctrl_inl(DMABRGCR); - ctrl_outl(dcr & ~0x00ff0003, DMABRGCR); /* ack all */ + dcr = __raw_readl(DMABRGCR); + __raw_writel(dcr & ~0x00ff0003, DMABRGCR); /* ack all */ dcr &= dcr >> 8; /* ignore masked */ /* USB stuff, get it out of the way first */ @@ -109,17 +110,17 @@ static irqreturn_t dmabrg_irq(int irq, void *data) static void dmabrg_disable_irq(unsigned int dmairq) { unsigned long dcr; - dcr = ctrl_inl(DMABRGCR); + dcr = __raw_readl(DMABRGCR); dcr &= ~(1 << ((dmairq > 1) ? dmairq + 22 : dmairq + 8)); - ctrl_outl(dcr, DMABRGCR); + __raw_writel(dcr, DMABRGCR); } static void dmabrg_enable_irq(unsigned int dmairq) { unsigned long dcr; - dcr = ctrl_inl(DMABRGCR); + dcr = __raw_readl(DMABRGCR); dcr |= (1 << ((dmairq > 1) ? dmairq + 22 : dmairq + 8)); - ctrl_outl(dcr, DMABRGCR); + __raw_writel(dcr, DMABRGCR); } int dmabrg_request_irq(unsigned int dmairq, void(*handler)(void*), @@ -165,31 +166,31 @@ static int __init dmabrg_init(void) printk(KERN_INFO "DMABRG: DMAC ch0 not reserved!\n"); #endif - ctrl_outl(0, DMABRGCR); - ctrl_outl(0, DMACHCR0); - ctrl_outl(0x94000000, DMARSRA); /* enable DMABRG in DMAC 0 */ + __raw_writel(0, DMABRGCR); + __raw_writel(0, DMACHCR0); + __raw_writel(0x94000000, DMARSRA); /* enable DMABRG in DMAC 0 */ /* enable DMABRG mode, enable the DMAC */ - or = ctrl_inl(DMAOR); - ctrl_outl(or | DMAOR_BRG | DMAOR_DMEN, DMAOR); + or = __raw_readl(DMAOR); + __raw_writel(or | DMAOR_BRG | DMAOR_DMEN, DMAOR); - ret = request_irq(DMABRGI0, dmabrg_irq, IRQF_DISABLED, + ret = request_irq(DMABRGI0, dmabrg_irq, 0, "DMABRG USB address error", NULL); if (ret) goto out0; - ret = request_irq(DMABRGI1, dmabrg_irq, IRQF_DISABLED, + ret = request_irq(DMABRGI1, dmabrg_irq, 0, "DMABRG Transfer End", NULL); if (ret) goto out1; - ret = request_irq(DMABRGI2, dmabrg_irq, IRQF_DISABLED, + ret = request_irq(DMABRGI2, dmabrg_irq, 0, "DMABRG Transfer Half", NULL); if (ret == 0) return ret; - free_irq(DMABRGI1, 0); -out1: free_irq(DMABRGI0, 0); + free_irq(DMABRGI1, NULL); +out1: free_irq(DMABRGI0, NULL); out0: kfree(dmabrg_handlers); return ret; } |
