1/* 2 * arch/sh/drivers/dma/dma-sh.c 3 * 4 * SuperH On-chip DMAC Support 5 * 6 * Copyright (C) 2000 Takashi YOSHII 7 * Copyright (C) 2003, 2004 Paul Mundt 8 * Copyright (C) 2005 Andriy Skulysh 9 * 10 * This file is subject to the terms and conditions of the GNU General Public 11 * License. See the file "COPYING" in the main directory of this archive 12 * for more details. 13 */ 14#include <linux/init.h> 15#include <linux/interrupt.h> 16#include <linux/module.h> 17#include <asm/dreamcast/dma.h> 18#include <asm/dma.h> 19#include <asm/io.h> 20#include "dma-sh.h" 21 22static int dmte_irq_map[] = { 23 DMTE0_IRQ, 24 DMTE1_IRQ, 25 DMTE2_IRQ, 26 DMTE3_IRQ, 27#if defined(CONFIG_CPU_SUBTYPE_SH7751R) || defined(CONFIG_CPU_SUBTYPE_SH7760) || \ 28 defined(CONFIG_CPU_SUBTYPE_SH7780) 29 DMTE4_IRQ, 30 DMTE5_IRQ, 31 DMTE6_IRQ, 32 DMTE7_IRQ, 33#endif 34}; 35 36static inline unsigned int get_dmte_irq(unsigned int chan) 37{ 38 unsigned int irq = 0; 39 if (chan < ARRAY_SIZE(dmte_irq_map)) 40 irq = dmte_irq_map[chan]; 41 return irq; 42} 43 44/* 45 * We determine the correct shift size based off of the CHCR transmit size 46 * for the given channel. Since we know that it will take: 47 * 48 * info->count >> ts_shift[transmit_size] 49 * 50 * iterations to complete the transfer. 51 */ 52static inline unsigned int calc_xmit_shift(struct dma_channel *chan) 53{ 54 u32 chcr = ctrl_inl(CHCR[chan->chan]); 55 56 return ts_shift[(chcr & CHCR_TS_MASK)>>CHCR_TS_SHIFT]; 57} 58 59/* 60 * The transfer end interrupt must read the chcr register to end the 61 * hardware interrupt active condition. 62 * Besides that it needs to waken any waiting process, which should handle 63 * setting up the next transfer. 64 */ 65static irqreturn_t dma_tei(int irq, void *dev_id) 66{ 67 struct dma_channel *chan = dev_id; 68 u32 chcr; 69 70 chcr = ctrl_inl(CHCR[chan->chan]); 71 72 if (!(chcr & CHCR_TE)) 73 return IRQ_NONE; 74 75 chcr &= ~(CHCR_IE | CHCR_DE); 76 ctrl_outl(chcr, CHCR[chan->chan]); 77 78 wake_up(&chan->wait_queue); 79 80 return IRQ_HANDLED; 81} 82 83static int sh_dmac_request_dma(struct dma_channel *chan) 84{ 85 if (unlikely(!chan->flags & DMA_TEI_CAPABLE)) 86 return 0; 87 88 return request_irq(get_dmte_irq(chan->chan), dma_tei, 89 IRQF_DISABLED, chan->dev_id, chan); 90} 91 92static void sh_dmac_free_dma(struct dma_channel *chan) 93{ 94 free_irq(get_dmte_irq(chan->chan), chan); 95} 96 97static int 98sh_dmac_configure_channel(struct dma_channel *chan, unsigned long chcr) 99{ 100 if (!chcr) 101 chcr = RS_DUAL | CHCR_IE; 102 103 if (chcr & CHCR_IE) { 104 chcr &= ~CHCR_IE; 105 chan->flags |= DMA_TEI_CAPABLE; 106 } else { 107 chan->flags &= ~DMA_TEI_CAPABLE; 108 } 109 110 ctrl_outl(chcr, CHCR[chan->chan]); 111 112 chan->flags |= DMA_CONFIGURED; 113 return 0; 114} 115 116static void sh_dmac_enable_dma(struct dma_channel *chan) 117{ 118 int irq; 119 u32 chcr; 120 121 chcr = ctrl_inl(CHCR[chan->chan]); 122 chcr |= CHCR_DE; 123 124 if (chan->flags & DMA_TEI_CAPABLE) 125 chcr |= CHCR_IE; 126 127 ctrl_outl(chcr, CHCR[chan->chan]); 128 129 if (chan->flags & DMA_TEI_CAPABLE) { 130 irq = get_dmte_irq(chan->chan); 131 enable_irq(irq); 132 } 133} 134 135static void sh_dmac_disable_dma(struct dma_channel *chan) 136{ 137 int irq; 138 u32 chcr; 139 140 if (chan->flags & DMA_TEI_CAPABLE) { 141 irq = get_dmte_irq(chan->chan); 142 disable_irq(irq); 143 } 144 145 chcr = ctrl_inl(CHCR[chan->chan]); 146 chcr &= ~(CHCR_DE | CHCR_TE | CHCR_IE); 147 ctrl_outl(chcr, CHCR[chan->chan]); 148} 149 150static int sh_dmac_xfer_dma(struct dma_channel *chan) 151{ 152 /* 153 * If we haven't pre-configured the channel with special flags, use 154 * the defaults. 155 */ 156 if (unlikely(!(chan->flags & DMA_CONFIGURED))) 157 sh_dmac_configure_channel(chan, 0); 158 159 sh_dmac_disable_dma(chan); 160 161 /* 162 * Single-address mode usage note! 163 * 164 * It's important that we don't accidentally write any value to SAR/DAR 165 * (this includes 0) that hasn't been directly specified by the user if 166 * we're in single-address mode. 167 * 168 * In this case, only one address can be defined, anything else will 169 * result in a DMA address error interrupt (at least on the SH-4), 170 * which will subsequently halt the transfer. 171 * 172 * Channel 2 on the Dreamcast is a special case, as this is used for 173 * cascading to the PVR2 DMAC. In this case, we still need to write 174 * SAR and DAR, regardless of value, in order for cascading to work. 175 */ 176 if (chan->sar || (mach_is_dreamcast() && 177 chan->chan == PVR2_CASCADE_CHAN)) 178 ctrl_outl(chan->sar, SAR[chan->chan]); 179 if (chan->dar || (mach_is_dreamcast() && 180 chan->chan == PVR2_CASCADE_CHAN)) 181 ctrl_outl(chan->dar, DAR[chan->chan]); 182 183 ctrl_outl(chan->count >> calc_xmit_shift(chan), DMATCR[chan->chan]); 184 185 sh_dmac_enable_dma(chan); 186 187 return 0; 188} 189 190static int sh_dmac_get_dma_residue(struct dma_channel *chan) 191{ 192 if (!(ctrl_inl(CHCR[chan->chan]) & CHCR_DE)) 193 return 0; 194 195 return ctrl_inl(DMATCR[chan->chan]) << calc_xmit_shift(chan); 196} 197 198#ifdef CONFIG_CPU_SUBTYPE_SH7780 199#define dmaor_read_reg() ctrl_inw(DMAOR) 200#define dmaor_write_reg(data) ctrl_outw(data, DMAOR) 201#else 202#define dmaor_read_reg() ctrl_inl(DMAOR) 203#define dmaor_write_reg(data) ctrl_outl(data, DMAOR) 204#endif 205 206static inline int dmaor_reset(void) 207{ 208 unsigned long dmaor = dmaor_read_reg(); 209 210 /* Try to clear the error flags first, incase they are set */ 211 dmaor &= ~(DMAOR_NMIF | DMAOR_AE); 212 dmaor_write_reg(dmaor); 213 214 dmaor |= DMAOR_INIT; 215 dmaor_write_reg(dmaor); 216 217 /* See if we got an error again */ 218 if ((dmaor_read_reg() & (DMAOR_AE | DMAOR_NMIF))) { 219 printk(KERN_ERR "dma-sh: Can't initialize DMAOR.\n"); 220 return -EINVAL; 221 } 222 223 return 0; 224} 225 226#if defined(CONFIG_CPU_SH4) 227static irqreturn_t dma_err(int irq, void *dummy) 228{ 229 dmaor_reset(); 230 disable_irq(irq); 231 232 return IRQ_HANDLED; 233} 234#endif 235 236static struct dma_ops sh_dmac_ops = { 237 .request = sh_dmac_request_dma, 238 .free = sh_dmac_free_dma, 239 .get_residue = sh_dmac_get_dma_residue, 240 .xfer = sh_dmac_xfer_dma, 241 .configure = sh_dmac_configure_channel, 242}; 243 244static struct dma_info sh_dmac_info = { 245 .name = "sh_dmac", 246 .nr_channels = CONFIG_NR_ONCHIP_DMA_CHANNELS, 247 .ops = &sh_dmac_ops, 248 .flags = DMAC_CHANNELS_TEI_CAPABLE, 249}; 250 251static int __init sh_dmac_init(void) 252{ 253 struct dma_info *info = &sh_dmac_info; 254 int i; 255 256#ifdef CONFIG_CPU_SH4 257 i = request_irq(DMAE_IRQ, dma_err, IRQF_DISABLED, "DMAC Address Error", 0); 258 if (unlikely(i < 0)) 259 return i; 260#endif 261 262 /* 263 * Initialize DMAOR, and clean up any error flags that may have 264 * been set. 265 */ 266 i = dmaor_reset(); 267 if (unlikely(i != 0)) 268 return i; 269 270 return register_dmac(info); 271} 272 273static void __exit sh_dmac_exit(void) 274{ 275#ifdef CONFIG_CPU_SH4 276 free_irq(DMAE_IRQ, 0); 277#endif 278 unregister_dmac(&sh_dmac_info); 279} 280 281subsys_initcall(sh_dmac_init); 282module_exit(sh_dmac_exit); 283 284MODULE_AUTHOR("Takashi YOSHII, Paul Mundt, Andriy Skulysh"); 285MODULE_DESCRIPTION("SuperH On-Chip DMAC Support"); 286MODULE_LICENSE("GPL"); 287