1// SPDX-License-Identifier: GPL-2.0 2/* 3 * arch/sh/drivers/dma/dma-sh.c 4 * 5 * SuperH On-chip DMAC Support 6 * 7 * Copyright (C) 2000 Takashi YOSHII 8 * Copyright (C) 2003, 2004 Paul Mundt 9 * Copyright (C) 2005 Andriy Skulysh 10 */ 11#include <linux/init.h> 12#include <linux/interrupt.h> 13#include <linux/module.h> 14#include <linux/io.h> 15#include <mach-dreamcast/mach/dma.h> 16#include <asm/dma.h> 17#include <asm/dma-register.h> 18#include <cpu/dma-register.h> 19#include <cpu/dma.h> 20 21/* 22 * Some of the SoCs feature two DMAC modules. In such a case, the channels are 23 * distributed equally among them. 24 */ 25#ifdef SH_DMAC_BASE1 26#define SH_DMAC_NR_MD_CH (CONFIG_NR_ONCHIP_DMA_CHANNELS / 2) 27#else 28#define SH_DMAC_NR_MD_CH CONFIG_NR_ONCHIP_DMA_CHANNELS 29#endif 30 31#define SH_DMAC_CH_SZ 0x10 32 33/* 34 * Define the default configuration for dual address memory-memory transfer. 35 * The 0x400 value represents auto-request, external->external. 36 */ 37#define RS_DUAL (DM_INC | SM_INC | RS_AUTO | TS_INDEX2VAL(XMIT_SZ_32BIT)) 38 39static unsigned long dma_find_base(unsigned int chan) 40{ 41 unsigned long base = SH_DMAC_BASE0; 42 43#ifdef SH_DMAC_BASE1 44 if (chan >= SH_DMAC_NR_MD_CH) 45 base = SH_DMAC_BASE1; 46#endif 47 48 return base; 49} 50 51static unsigned long dma_base_addr(unsigned int chan) 52{ 53 unsigned long base = dma_find_base(chan); 54 55 chan = (chan % SH_DMAC_NR_MD_CH) * SH_DMAC_CH_SZ; 56 57 /* DMAOR is placed inside the channel register space. Step over it. */ 58 if (chan >= DMAOR) 59 base += SH_DMAC_CH_SZ; 60 61 return base + chan; 62} 63 64#ifdef CONFIG_SH_DMA_IRQ_MULTI 65static inline unsigned int get_dmte_irq(unsigned int chan) 66{ 67 return chan >= 6 ? DMTE6_IRQ : DMTE0_IRQ; 68} 69#else 70 71static unsigned int dmte_irq_map[] = { 72 DMTE0_IRQ, DMTE0_IRQ + 1, DMTE0_IRQ + 2, DMTE0_IRQ + 3, 73 74#ifdef DMTE4_IRQ 75 DMTE4_IRQ, DMTE4_IRQ + 1, 76#endif 77 78#ifdef DMTE6_IRQ 79 DMTE6_IRQ, DMTE6_IRQ + 1, 80#endif 81 82#ifdef DMTE8_IRQ 83 DMTE8_IRQ, DMTE9_IRQ, DMTE10_IRQ, DMTE11_IRQ, 84#endif 85}; 86 87static inline unsigned int get_dmte_irq(unsigned int chan) 88{ 89 return dmte_irq_map[chan]; 90} 91#endif 92 93/* 94 * We determine the correct shift size based off of the CHCR transmit size 95 * for the given channel. Since we know that it will take: 96 * 97 * info->count >> ts_shift[transmit_size] 98 * 99 * iterations to complete the transfer. 100 */ 101static unsigned int ts_shift[] = TS_SHIFT; 102 103static inline unsigned int calc_xmit_shift(struct dma_channel *chan) 104{ 105 u32 chcr = __raw_readl(dma_base_addr(chan->chan) + CHCR); 106 int cnt = ((chcr & CHCR_TS_LOW_MASK) >> CHCR_TS_LOW_SHIFT) | 107 ((chcr & CHCR_TS_HIGH_MASK) >> CHCR_TS_HIGH_SHIFT); 108 109 return ts_shift[cnt]; 110} 111 112/* 113 * The transfer end interrupt must read the chcr register to end the 114 * hardware interrupt active condition. 115 * Besides that it needs to waken any waiting process, which should handle 116 * setting up the next transfer. 117 */ 118static irqreturn_t dma_tei(int irq, void *dev_id) 119{ 120 struct dma_channel *chan = dev_id; 121 u32 chcr; 122 123 chcr = __raw_readl(dma_base_addr(chan->chan) + CHCR); 124 125 if (!(chcr & CHCR_TE)) 126 return IRQ_NONE; 127 128 chcr &= ~(CHCR_IE | CHCR_DE); 129 __raw_writel(chcr, (dma_base_addr(chan->chan) + CHCR)); 130 131 wake_up(&chan->wait_queue); 132 133 return IRQ_HANDLED; 134} 135 136static int sh_dmac_request_dma(struct dma_channel *chan) 137{ 138 if (unlikely(!(chan->flags & DMA_TEI_CAPABLE))) 139 return 0; 140 141 return request_irq(get_dmte_irq(chan->chan), dma_tei, IRQF_SHARED, 142 chan->dev_id, chan); 143} 144 145static void sh_dmac_free_dma(struct dma_channel *chan) 146{ 147 free_irq(get_dmte_irq(chan->chan), chan); 148} 149 150static int 151sh_dmac_configure_channel(struct dma_channel *chan, unsigned long chcr) 152{ 153 if (!chcr) 154 chcr = RS_DUAL | CHCR_IE; 155 156 if (chcr & CHCR_IE) { 157 chcr &= ~CHCR_IE; 158 chan->flags |= DMA_TEI_CAPABLE; 159 } else { 160 chan->flags &= ~DMA_TEI_CAPABLE; 161 } 162 163 __raw_writel(chcr, (dma_base_addr(chan->chan) + CHCR)); 164 165 chan->flags |= DMA_CONFIGURED; 166 return 0; 167} 168 169static void sh_dmac_enable_dma(struct dma_channel *chan) 170{ 171 int irq; 172 u32 chcr; 173 174 chcr = __raw_readl(dma_base_addr(chan->chan) + CHCR); 175 chcr |= CHCR_DE; 176 177 if (chan->flags & DMA_TEI_CAPABLE) 178 chcr |= CHCR_IE; 179 180 __raw_writel(chcr, (dma_base_addr(chan->chan) + CHCR)); 181 182 if (chan->flags & DMA_TEI_CAPABLE) { 183 irq = get_dmte_irq(chan->chan); 184 enable_irq(irq); 185 } 186} 187 188static void sh_dmac_disable_dma(struct dma_channel *chan) 189{ 190 int irq; 191 u32 chcr; 192 193 if (chan->flags & DMA_TEI_CAPABLE) { 194 irq = get_dmte_irq(chan->chan); 195 disable_irq(irq); 196 } 197 198 chcr = __raw_readl(dma_base_addr(chan->chan) + CHCR); 199 chcr &= ~(CHCR_DE | CHCR_TE | CHCR_IE); 200 __raw_writel(chcr, (dma_base_addr(chan->chan) + CHCR)); 201} 202 203static int sh_dmac_xfer_dma(struct dma_channel *chan) 204{ 205 /* 206 * If we haven't pre-configured the channel with special flags, use 207 * the defaults. 208 */ 209 if (unlikely(!(chan->flags & DMA_CONFIGURED))) 210 sh_dmac_configure_channel(chan, 0); 211 212 sh_dmac_disable_dma(chan); 213 214 /* 215 * Single-address mode usage note! 216 * 217 * It's important that we don't accidentally write any value to SAR/DAR 218 * (this includes 0) that hasn't been directly specified by the user if 219 * we're in single-address mode. 220 * 221 * In this case, only one address can be defined, anything else will 222 * result in a DMA address error interrupt (at least on the SH-4), 223 * which will subsequently halt the transfer. 224 * 225 * Channel 2 on the Dreamcast is a special case, as this is used for 226 * cascading to the PVR2 DMAC. In this case, we still need to write 227 * SAR and DAR, regardless of value, in order for cascading to work. 228 */ 229 if (chan->sar || (mach_is_dreamcast() && 230 chan->chan == PVR2_CASCADE_CHAN)) 231 __raw_writel(chan->sar, (dma_base_addr(chan->chan) + SAR)); 232 if (chan->dar || (mach_is_dreamcast() && 233 chan->chan == PVR2_CASCADE_CHAN)) 234 __raw_writel(chan->dar, (dma_base_addr(chan->chan) + DAR)); 235 236 __raw_writel(chan->count >> calc_xmit_shift(chan), 237 (dma_base_addr(chan->chan) + TCR)); 238 239 sh_dmac_enable_dma(chan); 240 241 return 0; 242} 243 244static int sh_dmac_get_dma_residue(struct dma_channel *chan) 245{ 246 if (!(__raw_readl(dma_base_addr(chan->chan) + CHCR) & CHCR_DE)) 247 return 0; 248 249 return __raw_readl(dma_base_addr(chan->chan) + TCR) 250 << calc_xmit_shift(chan); 251} 252 253/* 254 * DMAOR handling 255 */ 256#if defined(CONFIG_CPU_SUBTYPE_SH7723) || \ 257 defined(CONFIG_CPU_SUBTYPE_SH7724) || \ 258 defined(CONFIG_CPU_SUBTYPE_SH7780) || \ 259 defined(CONFIG_CPU_SUBTYPE_SH7785) 260#define NR_DMAOR 2 261#else 262#define NR_DMAOR 1 263#endif 264 265#define dmaor_read_reg(n) __raw_readw(dma_find_base((n) * \ 266 SH_DMAC_NR_MD_CH) + DMAOR) 267#define dmaor_write_reg(n, data) __raw_writew(data, \ 268 dma_find_base((n) * \ 269 SH_DMAC_NR_MD_CH) + DMAOR) 270 271static inline int dmaor_reset(int no) 272{ 273 unsigned long dmaor = dmaor_read_reg(no); 274 275 /* Try to clear the error flags first, incase they are set */ 276 dmaor &= ~(DMAOR_NMIF | DMAOR_AE); 277 dmaor_write_reg(no, dmaor); 278 279 dmaor |= DMAOR_INIT; 280 dmaor_write_reg(no, dmaor); 281 282 /* See if we got an error again */ 283 if ((dmaor_read_reg(no) & (DMAOR_AE | DMAOR_NMIF))) { 284 printk(KERN_ERR "dma-sh: Can't initialize DMAOR.\n"); 285 return -EINVAL; 286 } 287 288 return 0; 289} 290 291/* 292 * DMAE handling 293 */ 294#ifdef CONFIG_CPU_SH4 295 296#if defined(DMAE1_IRQ) 297#define NR_DMAE 2 298#else 299#define NR_DMAE 1 300#endif 301 302static const char *dmae_name[] = { 303 "DMAC Address Error0", 304 "DMAC Address Error1" 305}; 306 307#ifdef CONFIG_SH_DMA_IRQ_MULTI 308static inline unsigned int get_dma_error_irq(int n) 309{ 310 return get_dmte_irq(n * 6); 311} 312#else 313 314static unsigned int dmae_irq_map[] = { 315 DMAE0_IRQ, 316 317#ifdef DMAE1_IRQ 318 DMAE1_IRQ, 319#endif 320}; 321 322static inline unsigned int get_dma_error_irq(int n) 323{ 324 return dmae_irq_map[n]; 325} 326#endif 327 328static irqreturn_t dma_err(int irq, void *dummy) 329{ 330 int i; 331 332 for (i = 0; i < NR_DMAOR; i++) 333 dmaor_reset(i); 334 335 disable_irq(irq); 336 337 return IRQ_HANDLED; 338} 339 340static int dmae_irq_init(void) 341{ 342 int n; 343 344 for (n = 0; n < NR_DMAE; n++) { 345 int i = request_irq(get_dma_error_irq(n), dma_err, 346 IRQF_SHARED, dmae_name[n], (void *)dmae_name[n]); 347 if (unlikely(i < 0)) { 348 printk(KERN_ERR "%s request_irq fail\n", dmae_name[n]); 349 return i; 350 } 351 } 352 353 return 0; 354} 355 356static void dmae_irq_free(void) 357{ 358 int n; 359 360 for (n = 0; n < NR_DMAE; n++) 361 free_irq(get_dma_error_irq(n), NULL); 362} 363#else 364static inline int dmae_irq_init(void) 365{ 366 return 0; 367} 368 369static void dmae_irq_free(void) 370{ 371} 372#endif 373 374static struct dma_ops sh_dmac_ops = { 375 .request = sh_dmac_request_dma, 376 .free = sh_dmac_free_dma, 377 .get_residue = sh_dmac_get_dma_residue, 378 .xfer = sh_dmac_xfer_dma, 379 .configure = sh_dmac_configure_channel, 380}; 381 382static struct dma_info sh_dmac_info = { 383 .name = "sh_dmac", 384 .nr_channels = CONFIG_NR_ONCHIP_DMA_CHANNELS, 385 .ops = &sh_dmac_ops, 386 .flags = DMAC_CHANNELS_TEI_CAPABLE, 387}; 388 389static int __init sh_dmac_init(void) 390{ 391 struct dma_info *info = &sh_dmac_info; 392 int i, rc; 393 394 /* 395 * Initialize DMAE, for parts that support it. 396 */ 397 rc = dmae_irq_init(); 398 if (unlikely(rc != 0)) 399 return rc; 400 401 /* 402 * Initialize DMAOR, and clean up any error flags that may have 403 * been set. 404 */ 405 for (i = 0; i < NR_DMAOR; i++) { 406 rc = dmaor_reset(i); 407 if (unlikely(rc != 0)) 408 return rc; 409 } 410 411 return register_dmac(info); 412} 413 414static void __exit sh_dmac_exit(void) 415{ 416 dmae_irq_free(); 417 unregister_dmac(&sh_dmac_info); 418} 419 420subsys_initcall(sh_dmac_init); 421module_exit(sh_dmac_exit); 422 423MODULE_AUTHOR("Takashi YOSHII, Paul Mundt, Andriy Skulysh"); 424MODULE_DESCRIPTION("SuperH On-Chip DMAC Support"); 425MODULE_LICENSE("GPL v2"); 426