diff options
-rw-r--r-- | arch/sh/include/asm/dmaengine.h | 63 | ||||
-rw-r--r-- | arch/sh/include/asm/siu.h | 8 | ||||
-rw-r--r-- | drivers/dma/Kconfig | 2 | ||||
-rw-r--r-- | drivers/dma/shdma.c | 21 | ||||
-rw-r--r-- | drivers/dma/shdma.h | 4 | ||||
-rw-r--r-- | drivers/serial/sh-sci.c | 18 | ||||
-rw-r--r-- | drivers/sh/intc.c | 95 | ||||
-rw-r--r-- | include/linux/serial_sci.h | 6 | ||||
-rw-r--r-- | include/linux/sh_dma.h | 101 | ||||
-rw-r--r-- | include/linux/sh_intc.h | 6 |
10 files changed, 229 insertions, 95 deletions
diff --git a/arch/sh/include/asm/dmaengine.h b/arch/sh/include/asm/dmaengine.h index bf2f30c..2a02b61 100644 --- a/arch/sh/include/asm/dmaengine.h +++ b/arch/sh/include/asm/dmaengine.h @@ -10,14 +10,9 @@ #ifndef ASM_DMAENGINE_H #define ASM_DMAENGINE_H -#include <linux/dmaengine.h> -#include <linux/list.h> +#include <linux/sh_dma.h> -#include <asm/dma-register.h> - -#define SH_DMAC_MAX_CHANNELS 6 - -enum sh_dmae_slave_chan_id { +enum { SHDMA_SLAVE_SCIF0_TX, SHDMA_SLAVE_SCIF0_RX, SHDMA_SLAVE_SCIF1_TX, @@ -34,60 +29,6 @@ enum sh_dmae_slave_chan_id { 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 */ -}; - -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/arch/sh/include/asm/siu.h b/arch/sh/include/asm/siu.h index f1b1e69..e8d4142 100644 --- a/arch/sh/include/asm/siu.h +++ b/arch/sh/include/asm/siu.h @@ -17,10 +17,10 @@ struct device; struct siu_platform { struct device *dma_dev; - enum sh_dmae_slave_chan_id dma_slave_tx_a; - enum sh_dmae_slave_chan_id dma_slave_rx_a; - enum sh_dmae_slave_chan_id dma_slave_tx_b; - enum sh_dmae_slave_chan_id dma_slave_rx_b; + unsigned int dma_slave_tx_a; + unsigned int dma_slave_rx_a; + unsigned int dma_slave_tx_b; + unsigned int dma_slave_rx_b; }; #endif /* ASM_SIU_H */ diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig index c27f80e..9d8ca99 100644 --- a/drivers/dma/Kconfig +++ b/drivers/dma/Kconfig @@ -128,7 +128,7 @@ config TXX9_DMAC config SH_DMAE tristate "Renesas SuperH DMAC support" - depends on SUPERH && SH_DMA + depends on (SUPERH && SH_DMA) || (ARM && ARCH_SHMOBILE) depends on !SH_DMA_API select DMA_ENGINE help diff --git a/drivers/dma/shdma.c b/drivers/dma/shdma.c index 7cc31b3..ed3ef22 100644 --- a/drivers/dma/shdma.c +++ b/drivers/dma/shdma.c @@ -26,8 +26,7 @@ #include <linux/dma-mapping.h> #include <linux/platform_device.h> #include <linux/pm_runtime.h> - -#include <asm/dmaengine.h> +#include <linux/sh_dma.h> #include "shdma.h" @@ -45,7 +44,7 @@ enum sh_dmae_desc_status { #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)]; +static unsigned long sh_dmae_slave_used[BITS_TO_LONGS(SH_DMA_SLAVE_NUMBER)]; static void sh_dmae_chan_ld_cleanup(struct sh_dmae_chan *sh_chan, bool all); @@ -267,7 +266,7 @@ static struct sh_desc *sh_dmae_get_desc(struct sh_dmae_chan *sh_chan) } static struct sh_dmae_slave_config *sh_dmae_find_slave( - struct sh_dmae_chan *sh_chan, enum sh_dmae_slave_chan_id slave_id) + struct sh_dmae_chan *sh_chan, struct sh_dmae_slave *param) { struct dma_device *dma_dev = sh_chan->common.device; struct sh_dmae_device *shdev = container_of(dma_dev, @@ -275,11 +274,11 @@ static struct sh_dmae_slave_config *sh_dmae_find_slave( struct sh_dmae_pdata *pdata = shdev->pdata; int i; - if ((unsigned)slave_id >= SHDMA_SLAVE_NUMBER) + if (param->slave_id >= SH_DMA_SLAVE_NUMBER) return NULL; for (i = 0; i < pdata->slave_num; i++) - if (pdata->slave[i].slave_id == slave_id) + if (pdata->slave[i].slave_id == param->slave_id) return pdata->slave + i; return NULL; @@ -300,7 +299,7 @@ static int sh_dmae_alloc_chan_resources(struct dma_chan *chan) if (param) { struct sh_dmae_slave_config *cfg; - cfg = sh_dmae_find_slave(sh_chan, param->slave_id); + cfg = sh_dmae_find_slave(sh_chan, param); if (!cfg) return -EINVAL; @@ -795,7 +794,7 @@ static irqreturn_t sh_dmae_interrupt(int irq, void *data) return ret; } -#if defined(CONFIG_CPU_SH4) +#if defined(CONFIG_CPU_SH4) || defined(CONFIG_ARCH_SHMOBILE) static irqreturn_t sh_dmae_err(int irq, void *data) { struct sh_dmae_device *shdev = (struct sh_dmae_device *)data; @@ -1036,7 +1035,7 @@ static int __init sh_dmae_probe(struct platform_device *pdev) /* Default transfer size of 32 bytes requires 32-byte alignment */ shdev->common.copy_align = LOG2_DEFAULT_XFER_SIZE; -#if defined(CONFIG_CPU_SH4) +#if defined(CONFIG_CPU_SH4) || defined(CONFIG_ARCH_SHMOBILE) chanirq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 1); if (!chanirq_res) @@ -1061,7 +1060,7 @@ static int __init sh_dmae_probe(struct platform_device *pdev) #else chanirq_res = errirq_res; -#endif /* CONFIG_CPU_SH4 */ +#endif /* CONFIG_CPU_SH4 || CONFIG_ARCH_SHMOBILE */ if (chanirq_res->start == chanirq_res->end && !platform_get_resource(pdev, IORESOURCE_IRQ, 1)) { @@ -1108,7 +1107,7 @@ static int __init sh_dmae_probe(struct platform_device *pdev) chan_probe_err: sh_dmae_chan_remove(shdev); eirqres: -#if defined(CONFIG_CPU_SH4) +#if defined(CONFIG_CPU_SH4) || defined(CONFIG_ARCH_SHMOBILE) free_irq(errirq, shdev); eirq_err: #endif diff --git a/drivers/dma/shdma.h b/drivers/dma/shdma.h index 153609a..4021275 100644 --- a/drivers/dma/shdma.h +++ b/drivers/dma/shdma.h @@ -17,8 +17,8 @@ #include <linux/interrupt.h> #include <linux/list.h> -#include <asm/dmaengine.h> - +#define SH_DMAC_MAX_CHANNELS 6 +#define SH_DMA_SLAVE_NUMBER 256 #define SH_DMA_TCR_MAX 0x00FFFFFF /* 16MB */ struct device; diff --git a/drivers/serial/sh-sci.c b/drivers/serial/sh-sci.c index 8eb094c..78e0545 100644 --- a/drivers/serial/sh-sci.c +++ b/drivers/serial/sh-sci.c @@ -91,8 +91,8 @@ struct sci_port { 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; + unsigned int slave_tx; + unsigned int slave_rx; struct dma_async_tx_descriptor *desc_tx; struct dma_async_tx_descriptor *desc_rx[2]; dma_cookie_t cookie_tx; @@ -913,10 +913,10 @@ static void sci_dma_tx_complete(void *arg) spin_lock_irqsave(&port->lock, flags); - xmit->tail += s->sg_tx.length; + xmit->tail += sg_dma_len(&s->sg_tx); xmit->tail &= UART_XMIT_SIZE - 1; - port->icount.tx += s->sg_tx.length; + port->icount.tx += sg_dma_len(&s->sg_tx); async_tx_ack(s->desc_tx); s->cookie_tx = -EINVAL; @@ -1131,14 +1131,13 @@ static void work_fn_tx(struct work_struct *work) */ 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_dma_address(sg) = (sg_dma_address(sg) & ~(UART_XMIT_SIZE - 1)) + sg->offset; - sg->length = min((int)CIRC_CNT(xmit->head, xmit->tail, UART_XMIT_SIZE), + sg_dma_len(sg) = 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); + BUG_ON(!sg_dma_len(sg)); desc = chan->device->device_prep_slave_sg(chan, sg, s->sg_len_tx, DMA_TO_DEVICE, @@ -1339,8 +1338,7 @@ static void sci_request_dma(struct uart_port *port) 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; + sg_dma_address(sg) = dma[i]; } INIT_WORK(&s->work_rx, work_fn_rx); diff --git a/drivers/sh/intc.c b/drivers/sh/intc.c index 94ad6bd..3c584bd 100644 --- a/drivers/sh/intc.c +++ b/drivers/sh/intc.c @@ -45,6 +45,12 @@ struct intc_handle_int { unsigned long handle; }; +struct intc_window { + phys_addr_t phys; + void __iomem *virt; + unsigned long size; +}; + struct intc_desc_int { struct list_head list; struct sys_device sysdev; @@ -58,6 +64,8 @@ struct intc_desc_int { unsigned int nr_prio; struct intc_handle_int *sense; unsigned int nr_sense; + struct intc_window *window; + unsigned int nr_windows; struct irq_chip chip; }; @@ -447,11 +455,39 @@ static int intc_set_sense(unsigned int irq, unsigned int type) return 0; } +static unsigned long intc_phys_to_virt(struct intc_desc_int *d, + unsigned long address) +{ + struct intc_window *window; + int k; + + /* scan through physical windows and convert address */ + for (k = 0; k < d->nr_windows; k++) { + window = d->window + k; + + if (address < window->phys) + continue; + + if (address >= (window->phys + window->size)) + continue; + + address -= window->phys; + address += (unsigned long)window->virt; + + return address; + } + + /* no windows defined, register must be 1:1 mapped virt:phys */ + return address; +} + static unsigned int __init intc_get_reg(struct intc_desc_int *d, - unsigned long address) + unsigned long address) { unsigned int k; + address = intc_phys_to_virt(d, address); + for (k = 0; k < d->nr_reg; k++) { if (d->reg[k] == address) return k; @@ -801,6 +837,8 @@ static unsigned int __init save_reg(struct intc_desc_int *d, unsigned int smp) { if (value) { + value = intc_phys_to_virt(d, value); + d->reg[cnt] = value; #ifdef CONFIG_SMP d->smp[cnt] = smp; @@ -816,25 +854,52 @@ static void intc_redirect_irq(unsigned int irq, struct irq_desc *desc) generic_handle_irq((unsigned int)get_irq_data(irq)); } -void __init register_intc_controller(struct intc_desc *desc) +int __init register_intc_controller(struct intc_desc *desc) { unsigned int i, k, smp; struct intc_hw_desc *hw = &desc->hw; struct intc_desc_int *d; + struct resource *res; d = kzalloc(sizeof(*d), GFP_NOWAIT); + if (!d) + goto err0; INIT_LIST_HEAD(&d->list); list_add(&d->list, &intc_list); + if (desc->num_resources) { + d->nr_windows = desc->num_resources; + d->window = kzalloc(d->nr_windows * sizeof(*d->window), + GFP_NOWAIT); + if (!d->window) + goto err1; + + for (k = 0; k < d->nr_windows; k++) { + res = desc->resource + k; + WARN_ON(resource_type(res) != IORESOURCE_MEM); + d->window[k].phys = res->start; + d->window[k].size = resource_size(res); + d->window[k].virt = ioremap_nocache(res->start, + resource_size(res)); + if (!d->window[k].virt) + goto err2; + } + } + d->nr_reg = hw->mask_regs ? hw->nr_mask_regs * 2 : 0; d->nr_reg += hw->prio_regs ? hw->nr_prio_regs * 2 : 0; d->nr_reg += hw->sense_regs ? hw->nr_sense_regs : 0; d->nr_reg += hw->ack_regs ? hw->nr_ack_regs : 0; d->reg = kzalloc(d->nr_reg * sizeof(*d->reg), GFP_NOWAIT); + if (!d->reg) + goto err2; + #ifdef CONFIG_SMP d->smp = kzalloc(d->nr_reg * sizeof(*d->smp), GFP_NOWAIT); + if (!d->smp) + goto err3; #endif k = 0; @@ -849,6 +914,8 @@ void __init register_intc_controller(struct intc_desc *desc) if (hw->prio_regs) { d->prio = kzalloc(hw->nr_vectors * sizeof(*d->prio), GFP_NOWAIT); + if (!d->prio) + goto err4; for (i = 0; i < hw->nr_prio_regs; i++) { smp = IS_SMP(hw->prio_regs[i]); @@ -860,6 +927,8 @@ void __init register_intc_controller(struct intc_desc *desc) if (hw->sense_regs) { d->sense = kzalloc(hw->nr_vectors * sizeof(*d->sense), GFP_NOWAIT); + if (!d->sense) + goto err5; for (i = 0; i < hw->nr_sense_regs; i++) k += save_reg(d, k, hw->sense_regs[i].reg, 0); @@ -942,6 +1011,28 @@ void __init register_intc_controller(struct intc_desc *desc) /* enable bits matching force_enable after registering irqs */ if (desc->force_enable) intc_enable_disable_enum(desc, d, desc->force_enable, 1); + + return 0; +err5: + kfree(d->prio); +err4: +#ifdef CONFIG_SMP + kfree(d->smp); +err3: +#endif + kfree(d->reg); +err2: + for (k = 0; k < d->nr_windows; k++) + if (d->window[k].virt) + iounmap(d->window[k].virt); + + kfree(d->window); +err1: + kfree(d); +err0: + pr_err("unable to allocate INTC memory\n"); + + return -ENOMEM; } static int intc_suspend(struct sys_device *dev, pm_message_t state) diff --git a/include/linux/serial_sci.h b/include/linux/serial_sci.h index 193d4bf..837efa4 100644 --- a/include/linux/serial_sci.h +++ b/include/linux/serial_sci.h @@ -3,7 +3,7 @@ #include <linux/serial_core.h> #ifdef CONFIG_SERIAL_SH_SCI_DMA -#include <asm/dmaengine.h> +#include <linux/sh_dma.h> #endif /* @@ -33,8 +33,8 @@ struct plat_sci_port { char *clk; /* clock string */ struct device *dma_dev; #ifdef CONFIG_SERIAL_SH_SCI_DMA - enum sh_dmae_slave_chan_id dma_slave_tx; - enum sh_dmae_slave_chan_id dma_slave_rx; + unsigned int dma_slave_tx; + unsigned int dma_slave_rx; #endif }; diff --git a/include/linux/sh_dma.h b/include/linux/sh_dma.h new file mode 100644 index 0000000..cdaaff4 --- /dev/null +++ b/include/linux/sh_dma.h @@ -0,0 +1,101 @@ +/* + * Header for the new SH dmaengine driver + * + * Copyright (C) 2010 Guennadi Liakhovetski <g.liakhovetski@gmx.de> + * + * 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 SH_DMA_H +#define SH_DMA_H + +#include <linux/list.h> +#include <linux/dmaengine.h> + +/* Used by slave DMA clients to request DMA to/from a specific peripheral */ +struct sh_dmae_slave { + unsigned int slave_id; /* Set by the platform */ + struct device *dma_dev; /* Set by the platform */ + 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; +}; +struct sh_dmae_slave_config { + unsigned int 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; +}; + +/* 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/include/linux/sh_intc.h b/include/linux/sh_intc.h index 51d288d..01d8168 100644 --- a/include/linux/sh_intc.h +++ b/include/linux/sh_intc.h @@ -1,6 +1,8 @@ #ifndef __SH_INTC_H #define __SH_INTC_H +#include <linux/ioport.h> + typedef unsigned char intc_enum; struct intc_vect { @@ -71,6 +73,8 @@ struct intc_hw_desc { struct intc_desc { char *name; + struct resource *resource; + unsigned int num_resources; intc_enum force_enable; intc_enum force_disable; struct intc_hw_desc hw; @@ -92,7 +96,7 @@ struct intc_desc symbol __initdata = { \ prio_regs, sense_regs, ack_regs), \ } -void __init register_intc_controller(struct intc_desc *desc); +int __init register_intc_controller(struct intc_desc *desc); int intc_set_priority(unsigned int irq, unsigned int prio); int reserve_irq_vector(unsigned int irq); |