1 /* 2 * OMAP1/OMAP7xx - specific DMA driver 3 * 4 * Copyright (C) 2003 - 2008 Nokia Corporation 5 * Author: Juha Yrjölä <juha.yrjola@nokia.com> 6 * DMA channel linking for 1610 by Samuel Ortiz <samuel.ortiz@nokia.com> 7 * Graphics DMA and LCD DMA graphics tranformations 8 * by Imre Deak <imre.deak@nokia.com> 9 * OMAP2/3 support Copyright (C) 2004-2007 Texas Instruments, Inc. 10 * Some functions based on earlier dma-omap.c Copyright (C) 2001 RidgeRun, Inc. 11 * 12 * Copyright (C) 2010 Texas Instruments Incorporated - http://www.ti.com/ 13 * Converted DMA library into platform driver 14 * - G, Manjunath Kondaiah <manjugk@ti.com> 15 * 16 * This program is free software; you can redistribute it and/or modify 17 * it under the terms of the GNU General Public License version 2 as 18 * published by the Free Software Foundation. 19 */ 20 21 #include <linux/err.h> 22 #include <linux/slab.h> 23 #include <linux/module.h> 24 #include <linux/init.h> 25 #include <linux/device.h> 26 #include <linux/io.h> 27 28 #include <linux/omap-dma.h> 29 #include <mach/tc.h> 30 31 #include <mach/irqs.h> 32 33 #include "dma.h" 34 35 #define OMAP1_DMA_BASE (0xfffed800) 36 #define OMAP1_LOGICAL_DMA_CH_COUNT 17 37 #define OMAP1_DMA_STRIDE 0x40 38 39 static u32 errata; 40 static u32 enable_1510_mode; 41 static u8 dma_stride; 42 static enum omap_reg_offsets dma_common_ch_start, dma_common_ch_end; 43 44 static u16 reg_map[] = { 45 [GCR] = 0x400, 46 [GSCR] = 0x404, 47 [GRST1] = 0x408, 48 [HW_ID] = 0x442, 49 [PCH2_ID] = 0x444, 50 [PCH0_ID] = 0x446, 51 [PCH1_ID] = 0x448, 52 [PCHG_ID] = 0x44a, 53 [PCHD_ID] = 0x44c, 54 [CAPS_0] = 0x44e, 55 [CAPS_1] = 0x452, 56 [CAPS_2] = 0x456, 57 [CAPS_3] = 0x458, 58 [CAPS_4] = 0x45a, 59 [PCH2_SR] = 0x460, 60 [PCH0_SR] = 0x480, 61 [PCH1_SR] = 0x482, 62 [PCHD_SR] = 0x4c0, 63 64 /* Common Registers */ 65 [CSDP] = 0x00, 66 [CCR] = 0x02, 67 [CICR] = 0x04, 68 [CSR] = 0x06, 69 [CEN] = 0x10, 70 [CFN] = 0x12, 71 [CSFI] = 0x14, 72 [CSEI] = 0x16, 73 [CPC] = 0x18, /* 15xx only */ 74 [CSAC] = 0x18, 75 [CDAC] = 0x1a, 76 [CDEI] = 0x1c, 77 [CDFI] = 0x1e, 78 [CLNK_CTRL] = 0x28, 79 80 /* Channel specific register offsets */ 81 [CSSA] = 0x08, 82 [CDSA] = 0x0c, 83 [COLOR] = 0x20, 84 [CCR2] = 0x24, 85 [LCH_CTRL] = 0x2a, 86 }; 87 88 static struct resource res[] __initdata = { 89 [0] = { 90 .start = OMAP1_DMA_BASE, 91 .end = OMAP1_DMA_BASE + SZ_2K - 1, 92 .flags = IORESOURCE_MEM, 93 }, 94 [1] = { 95 .name = "0", 96 .start = INT_DMA_CH0_6, 97 .flags = IORESOURCE_IRQ, 98 }, 99 [2] = { 100 .name = "1", 101 .start = INT_DMA_CH1_7, 102 .flags = IORESOURCE_IRQ, 103 }, 104 [3] = { 105 .name = "2", 106 .start = INT_DMA_CH2_8, 107 .flags = IORESOURCE_IRQ, 108 }, 109 [4] = { 110 .name = "3", 111 .start = INT_DMA_CH3, 112 .flags = IORESOURCE_IRQ, 113 }, 114 [5] = { 115 .name = "4", 116 .start = INT_DMA_CH4, 117 .flags = IORESOURCE_IRQ, 118 }, 119 [6] = { 120 .name = "5", 121 .start = INT_DMA_CH5, 122 .flags = IORESOURCE_IRQ, 123 }, 124 /* Handled in lcd_dma.c */ 125 [7] = { 126 .name = "6", 127 .start = INT_1610_DMA_CH6, 128 .flags = IORESOURCE_IRQ, 129 }, 130 /* irq's for omap16xx and omap7xx */ 131 [8] = { 132 .name = "7", 133 .start = INT_1610_DMA_CH7, 134 .flags = IORESOURCE_IRQ, 135 }, 136 [9] = { 137 .name = "8", 138 .start = INT_1610_DMA_CH8, 139 .flags = IORESOURCE_IRQ, 140 }, 141 [10] = { 142 .name = "9", 143 .start = INT_1610_DMA_CH9, 144 .flags = IORESOURCE_IRQ, 145 }, 146 [11] = { 147 .name = "10", 148 .start = INT_1610_DMA_CH10, 149 .flags = IORESOURCE_IRQ, 150 }, 151 [12] = { 152 .name = "11", 153 .start = INT_1610_DMA_CH11, 154 .flags = IORESOURCE_IRQ, 155 }, 156 [13] = { 157 .name = "12", 158 .start = INT_1610_DMA_CH12, 159 .flags = IORESOURCE_IRQ, 160 }, 161 [14] = { 162 .name = "13", 163 .start = INT_1610_DMA_CH13, 164 .flags = IORESOURCE_IRQ, 165 }, 166 [15] = { 167 .name = "14", 168 .start = INT_1610_DMA_CH14, 169 .flags = IORESOURCE_IRQ, 170 }, 171 [16] = { 172 .name = "15", 173 .start = INT_1610_DMA_CH15, 174 .flags = IORESOURCE_IRQ, 175 }, 176 [17] = { 177 .name = "16", 178 .start = INT_DMA_LCD, 179 .flags = IORESOURCE_IRQ, 180 }, 181 }; 182 183 static void __iomem *dma_base; 184 static inline void dma_write(u32 val, int reg, int lch) 185 { 186 u8 stride; 187 u32 offset; 188 189 stride = (reg >= dma_common_ch_start) ? dma_stride : 0; 190 offset = reg_map[reg] + (stride * lch); 191 192 __raw_writew(val, dma_base + offset); 193 if ((reg > CLNK_CTRL && reg < CCEN) || 194 (reg > PCHD_ID && reg < CAPS_2)) { 195 u32 offset2 = reg_map[reg] + 2 + (stride * lch); 196 __raw_writew(val >> 16, dma_base + offset2); 197 } 198 } 199 200 static inline u32 dma_read(int reg, int lch) 201 { 202 u8 stride; 203 u32 offset, val; 204 205 stride = (reg >= dma_common_ch_start) ? dma_stride : 0; 206 offset = reg_map[reg] + (stride * lch); 207 208 val = __raw_readw(dma_base + offset); 209 if ((reg > CLNK_CTRL && reg < CCEN) || 210 (reg > PCHD_ID && reg < CAPS_2)) { 211 u16 upper; 212 u32 offset2 = reg_map[reg] + 2 + (stride * lch); 213 upper = __raw_readw(dma_base + offset2); 214 val |= (upper << 16); 215 } 216 return val; 217 } 218 219 static void omap1_clear_lch_regs(int lch) 220 { 221 int i = dma_common_ch_start; 222 223 for (; i <= dma_common_ch_end; i += 1) 224 dma_write(0, i, lch); 225 } 226 227 static void omap1_clear_dma(int lch) 228 { 229 u32 l; 230 231 l = dma_read(CCR, lch); 232 l &= ~OMAP_DMA_CCR_EN; 233 dma_write(l, CCR, lch); 234 235 /* Clear pending interrupts */ 236 l = dma_read(CSR, lch); 237 } 238 239 static void omap1_show_dma_caps(void) 240 { 241 if (enable_1510_mode) { 242 printk(KERN_INFO "DMA support for OMAP15xx initialized\n"); 243 } else { 244 u16 w; 245 printk(KERN_INFO "OMAP DMA hardware version %d\n", 246 dma_read(HW_ID, 0)); 247 printk(KERN_INFO "DMA capabilities: %08x:%08x:%04x:%04x:%04x\n", 248 dma_read(CAPS_0, 0), dma_read(CAPS_1, 0), 249 dma_read(CAPS_2, 0), dma_read(CAPS_3, 0), 250 dma_read(CAPS_4, 0)); 251 252 /* Disable OMAP 3.0/3.1 compatibility mode. */ 253 w = dma_read(GSCR, 0); 254 w |= 1 << 3; 255 dma_write(w, GSCR, 0); 256 } 257 return; 258 } 259 260 static u32 configure_dma_errata(void) 261 { 262 263 /* 264 * Erratum 3.2/3.3: sometimes 0 is returned if CSAC/CDAC is 265 * read before the DMA controller finished disabling the channel. 266 */ 267 if (!cpu_is_omap15xx()) 268 SET_DMA_ERRATA(DMA_ERRATA_3_3); 269 270 return errata; 271 } 272 273 static int __init omap1_system_dma_init(void) 274 { 275 struct omap_system_dma_plat_info *p; 276 struct omap_dma_dev_attr *d; 277 struct platform_device *pdev; 278 int ret; 279 280 pdev = platform_device_alloc("omap_dma_system", 0); 281 if (!pdev) { 282 pr_err("%s: Unable to device alloc for dma\n", 283 __func__); 284 return -ENOMEM; 285 } 286 287 dma_base = ioremap(res[0].start, resource_size(&res[0])); 288 if (!dma_base) { 289 pr_err("%s: Unable to ioremap\n", __func__); 290 ret = -ENODEV; 291 goto exit_device_put; 292 } 293 294 ret = platform_device_add_resources(pdev, res, ARRAY_SIZE(res)); 295 if (ret) { 296 dev_err(&pdev->dev, "%s: Unable to add resources for %s%d\n", 297 __func__, pdev->name, pdev->id); 298 goto exit_device_put; 299 } 300 301 p = kzalloc(sizeof(struct omap_system_dma_plat_info), GFP_KERNEL); 302 if (!p) { 303 dev_err(&pdev->dev, "%s: Unable to allocate 'p' for %s\n", 304 __func__, pdev->name); 305 ret = -ENOMEM; 306 goto exit_device_del; 307 } 308 309 d = kzalloc(sizeof(struct omap_dma_dev_attr), GFP_KERNEL); 310 if (!d) { 311 dev_err(&pdev->dev, "%s: Unable to allocate 'd' for %s\n", 312 __func__, pdev->name); 313 ret = -ENOMEM; 314 goto exit_release_p; 315 } 316 317 d->lch_count = OMAP1_LOGICAL_DMA_CH_COUNT; 318 319 /* Valid attributes for omap1 plus processors */ 320 if (cpu_is_omap15xx()) 321 d->dev_caps = ENABLE_1510_MODE; 322 enable_1510_mode = d->dev_caps & ENABLE_1510_MODE; 323 324 if (cpu_is_omap16xx()) 325 d->dev_caps = ENABLE_16XX_MODE; 326 327 d->dev_caps |= SRC_PORT; 328 d->dev_caps |= DST_PORT; 329 d->dev_caps |= SRC_INDEX; 330 d->dev_caps |= DST_INDEX; 331 d->dev_caps |= IS_BURST_ONLY4; 332 d->dev_caps |= CLEAR_CSR_ON_READ; 333 d->dev_caps |= IS_WORD_16; 334 335 336 d->chan = kzalloc(sizeof(struct omap_dma_lch) * 337 (d->lch_count), GFP_KERNEL); 338 if (!d->chan) { 339 dev_err(&pdev->dev, 340 "%s: Memory allocation failed for d->chan!\n", 341 __func__); 342 goto exit_release_d; 343 } 344 345 if (cpu_is_omap15xx()) 346 d->chan_count = 9; 347 else if (cpu_is_omap16xx() || cpu_is_omap7xx()) { 348 if (!(d->dev_caps & ENABLE_1510_MODE)) 349 d->chan_count = 16; 350 else 351 d->chan_count = 9; 352 } 353 354 p->dma_attr = d; 355 356 p->show_dma_caps = omap1_show_dma_caps; 357 p->clear_lch_regs = omap1_clear_lch_regs; 358 p->clear_dma = omap1_clear_dma; 359 p->dma_write = dma_write; 360 p->dma_read = dma_read; 361 p->disable_irq_lch = NULL; 362 363 p->errata = configure_dma_errata(); 364 365 ret = platform_device_add_data(pdev, p, sizeof(*p)); 366 if (ret) { 367 dev_err(&pdev->dev, "%s: Unable to add resources for %s%d\n", 368 __func__, pdev->name, pdev->id); 369 goto exit_release_chan; 370 } 371 372 ret = platform_device_add(pdev); 373 if (ret) { 374 dev_err(&pdev->dev, "%s: Unable to add resources for %s%d\n", 375 __func__, pdev->name, pdev->id); 376 goto exit_release_chan; 377 } 378 379 dma_stride = OMAP1_DMA_STRIDE; 380 dma_common_ch_start = CPC; 381 dma_common_ch_end = COLOR; 382 383 return ret; 384 385 exit_release_chan: 386 kfree(d->chan); 387 exit_release_d: 388 kfree(d); 389 exit_release_p: 390 kfree(p); 391 exit_device_del: 392 platform_device_del(pdev); 393 exit_device_put: 394 platform_device_put(pdev); 395 396 return ret; 397 } 398 arch_initcall(omap1_system_dma_init); 399