159de3cf1SG, Manjunath Kondaiah /* 259de3cf1SG, Manjunath Kondaiah * OMAP2+ DMA driver 359de3cf1SG, Manjunath Kondaiah * 459de3cf1SG, Manjunath Kondaiah * Copyright (C) 2003 - 2008 Nokia Corporation 559de3cf1SG, Manjunath Kondaiah * Author: Juha Yrjölä <juha.yrjola@nokia.com> 659de3cf1SG, Manjunath Kondaiah * DMA channel linking for 1610 by Samuel Ortiz <samuel.ortiz@nokia.com> 759de3cf1SG, Manjunath Kondaiah * Graphics DMA and LCD DMA graphics tranformations 859de3cf1SG, Manjunath Kondaiah * by Imre Deak <imre.deak@nokia.com> 959de3cf1SG, Manjunath Kondaiah * OMAP2/3 support Copyright (C) 2004-2007 Texas Instruments, Inc. 1059de3cf1SG, Manjunath Kondaiah * Some functions based on earlier dma-omap.c Copyright (C) 2001 RidgeRun, Inc. 1159de3cf1SG, Manjunath Kondaiah * 1259de3cf1SG, Manjunath Kondaiah * Copyright (C) 2009 Texas Instruments 1359de3cf1SG, Manjunath Kondaiah * Added OMAP4 support - Santosh Shilimkar <santosh.shilimkar@ti.com> 1459de3cf1SG, Manjunath Kondaiah * 1559de3cf1SG, Manjunath Kondaiah * Copyright (C) 2010 Texas Instruments Incorporated - http://www.ti.com/ 1659de3cf1SG, Manjunath Kondaiah * Converted DMA library into platform driver 1759de3cf1SG, Manjunath Kondaiah * - G, Manjunath Kondaiah <manjugk@ti.com> 1859de3cf1SG, Manjunath Kondaiah * 1959de3cf1SG, Manjunath Kondaiah * This program is free software; you can redistribute it and/or modify 2059de3cf1SG, Manjunath Kondaiah * it under the terms of the GNU General Public License version 2 as 2159de3cf1SG, Manjunath Kondaiah * published by the Free Software Foundation. 2259de3cf1SG, Manjunath Kondaiah */ 2359de3cf1SG, Manjunath Kondaiah 2459de3cf1SG, Manjunath Kondaiah #include <linux/err.h> 2559de3cf1SG, Manjunath Kondaiah #include <linux/io.h> 2659de3cf1SG, Manjunath Kondaiah #include <linux/slab.h> 2759de3cf1SG, Manjunath Kondaiah #include <linux/module.h> 2859de3cf1SG, Manjunath Kondaiah #include <linux/init.h> 2959de3cf1SG, Manjunath Kondaiah #include <linux/device.h> 3059de3cf1SG, Manjunath Kondaiah 3159de3cf1SG, Manjunath Kondaiah #include <plat/omap_hwmod.h> 3259de3cf1SG, Manjunath Kondaiah #include <plat/omap_device.h> 3359de3cf1SG, Manjunath Kondaiah #include <plat/dma.h> 3459de3cf1SG, Manjunath Kondaiah 35f31cc962SG, Manjunath Kondaiah #define OMAP2_DMA_STRIDE 0x60 36f31cc962SG, Manjunath Kondaiah 37f31cc962SG, Manjunath Kondaiah static u32 errata; 38f31cc962SG, Manjunath Kondaiah static u8 dma_stride; 39f31cc962SG, Manjunath Kondaiah 40f31cc962SG, Manjunath Kondaiah static struct omap_dma_dev_attr *d; 41f31cc962SG, Manjunath Kondaiah 42f31cc962SG, Manjunath Kondaiah static enum omap_reg_offsets dma_common_ch_start, dma_common_ch_end; 43f31cc962SG, Manjunath Kondaiah 44f31cc962SG, Manjunath Kondaiah static u16 reg_map[] = { 45f31cc962SG, Manjunath Kondaiah [REVISION] = 0x00, 46f31cc962SG, Manjunath Kondaiah [GCR] = 0x78, 47f31cc962SG, Manjunath Kondaiah [IRQSTATUS_L0] = 0x08, 48f31cc962SG, Manjunath Kondaiah [IRQSTATUS_L1] = 0x0c, 49f31cc962SG, Manjunath Kondaiah [IRQSTATUS_L2] = 0x10, 50f31cc962SG, Manjunath Kondaiah [IRQSTATUS_L3] = 0x14, 51f31cc962SG, Manjunath Kondaiah [IRQENABLE_L0] = 0x18, 52f31cc962SG, Manjunath Kondaiah [IRQENABLE_L1] = 0x1c, 53f31cc962SG, Manjunath Kondaiah [IRQENABLE_L2] = 0x20, 54f31cc962SG, Manjunath Kondaiah [IRQENABLE_L3] = 0x24, 55f31cc962SG, Manjunath Kondaiah [SYSSTATUS] = 0x28, 56f31cc962SG, Manjunath Kondaiah [OCP_SYSCONFIG] = 0x2c, 57f31cc962SG, Manjunath Kondaiah [CAPS_0] = 0x64, 58f31cc962SG, Manjunath Kondaiah [CAPS_2] = 0x6c, 59f31cc962SG, Manjunath Kondaiah [CAPS_3] = 0x70, 60f31cc962SG, Manjunath Kondaiah [CAPS_4] = 0x74, 61f31cc962SG, Manjunath Kondaiah 62f31cc962SG, Manjunath Kondaiah /* Common register offsets */ 63f31cc962SG, Manjunath Kondaiah [CCR] = 0x80, 64f31cc962SG, Manjunath Kondaiah [CLNK_CTRL] = 0x84, 65f31cc962SG, Manjunath Kondaiah [CICR] = 0x88, 66f31cc962SG, Manjunath Kondaiah [CSR] = 0x8c, 67f31cc962SG, Manjunath Kondaiah [CSDP] = 0x90, 68f31cc962SG, Manjunath Kondaiah [CEN] = 0x94, 69f31cc962SG, Manjunath Kondaiah [CFN] = 0x98, 70f31cc962SG, Manjunath Kondaiah [CSEI] = 0xa4, 71f31cc962SG, Manjunath Kondaiah [CSFI] = 0xa8, 72f31cc962SG, Manjunath Kondaiah [CDEI] = 0xac, 73f31cc962SG, Manjunath Kondaiah [CDFI] = 0xb0, 74f31cc962SG, Manjunath Kondaiah [CSAC] = 0xb4, 75f31cc962SG, Manjunath Kondaiah [CDAC] = 0xb8, 76f31cc962SG, Manjunath Kondaiah 77f31cc962SG, Manjunath Kondaiah /* Channel specific register offsets */ 78f31cc962SG, Manjunath Kondaiah [CSSA] = 0x9c, 79f31cc962SG, Manjunath Kondaiah [CDSA] = 0xa0, 80f31cc962SG, Manjunath Kondaiah [CCEN] = 0xbc, 81f31cc962SG, Manjunath Kondaiah [CCFN] = 0xc0, 82f31cc962SG, Manjunath Kondaiah [COLOR] = 0xc4, 83f31cc962SG, Manjunath Kondaiah 84f31cc962SG, Manjunath Kondaiah /* OMAP4 specific registers */ 85f31cc962SG, Manjunath Kondaiah [CDP] = 0xd0, 86f31cc962SG, Manjunath Kondaiah [CNDP] = 0xd4, 87f31cc962SG, Manjunath Kondaiah [CCDN] = 0xd8, 88f31cc962SG, Manjunath Kondaiah }; 89f31cc962SG, Manjunath Kondaiah 9059de3cf1SG, Manjunath Kondaiah static struct omap_device_pm_latency omap2_dma_latency[] = { 9159de3cf1SG, Manjunath Kondaiah { 9259de3cf1SG, Manjunath Kondaiah .deactivate_func = omap_device_idle_hwmods, 9359de3cf1SG, Manjunath Kondaiah .activate_func = omap_device_enable_hwmods, 9459de3cf1SG, Manjunath Kondaiah .flags = OMAP_DEVICE_LATENCY_AUTO_ADJUST, 9559de3cf1SG, Manjunath Kondaiah }, 9659de3cf1SG, Manjunath Kondaiah }; 9759de3cf1SG, Manjunath Kondaiah 98f31cc962SG, Manjunath Kondaiah static void __iomem *dma_base; 99f31cc962SG, Manjunath Kondaiah static inline void dma_write(u32 val, int reg, int lch) 100f31cc962SG, Manjunath Kondaiah { 101f31cc962SG, Manjunath Kondaiah u8 stride; 102f31cc962SG, Manjunath Kondaiah u32 offset; 103f31cc962SG, Manjunath Kondaiah 104f31cc962SG, Manjunath Kondaiah stride = (reg >= dma_common_ch_start) ? dma_stride : 0; 105f31cc962SG, Manjunath Kondaiah offset = reg_map[reg] + (stride * lch); 106f31cc962SG, Manjunath Kondaiah __raw_writel(val, dma_base + offset); 107f31cc962SG, Manjunath Kondaiah } 108f31cc962SG, Manjunath Kondaiah 109f31cc962SG, Manjunath Kondaiah static inline u32 dma_read(int reg, int lch) 110f31cc962SG, Manjunath Kondaiah { 111f31cc962SG, Manjunath Kondaiah u8 stride; 112f31cc962SG, Manjunath Kondaiah u32 offset, val; 113f31cc962SG, Manjunath Kondaiah 114f31cc962SG, Manjunath Kondaiah stride = (reg >= dma_common_ch_start) ? dma_stride : 0; 115f31cc962SG, Manjunath Kondaiah offset = reg_map[reg] + (stride * lch); 116f31cc962SG, Manjunath Kondaiah val = __raw_readl(dma_base + offset); 117f31cc962SG, Manjunath Kondaiah return val; 118f31cc962SG, Manjunath Kondaiah } 119f31cc962SG, Manjunath Kondaiah 120f31cc962SG, Manjunath Kondaiah static inline void omap2_disable_irq_lch(int lch) 121f31cc962SG, Manjunath Kondaiah { 122f31cc962SG, Manjunath Kondaiah u32 val; 123f31cc962SG, Manjunath Kondaiah 124f31cc962SG, Manjunath Kondaiah val = dma_read(IRQENABLE_L0, lch); 125f31cc962SG, Manjunath Kondaiah val &= ~(1 << lch); 126f31cc962SG, Manjunath Kondaiah dma_write(val, IRQENABLE_L0, lch); 127f31cc962SG, Manjunath Kondaiah } 128f31cc962SG, Manjunath Kondaiah 129f31cc962SG, Manjunath Kondaiah static void omap2_clear_dma(int lch) 130f31cc962SG, Manjunath Kondaiah { 131f31cc962SG, Manjunath Kondaiah int i = dma_common_ch_start; 132f31cc962SG, Manjunath Kondaiah 133f31cc962SG, Manjunath Kondaiah for (; i <= dma_common_ch_end; i += 1) 134f31cc962SG, Manjunath Kondaiah dma_write(0, i, lch); 135f31cc962SG, Manjunath Kondaiah } 136f31cc962SG, Manjunath Kondaiah 137f31cc962SG, Manjunath Kondaiah static void omap2_show_dma_caps(void) 138f31cc962SG, Manjunath Kondaiah { 139f31cc962SG, Manjunath Kondaiah u8 revision = dma_read(REVISION, 0) & 0xff; 140f31cc962SG, Manjunath Kondaiah printk(KERN_INFO "OMAP DMA hardware revision %d.%d\n", 141f31cc962SG, Manjunath Kondaiah revision >> 4, revision & 0xf); 142f31cc962SG, Manjunath Kondaiah return; 143f31cc962SG, Manjunath Kondaiah } 144f31cc962SG, Manjunath Kondaiah 145f31cc962SG, Manjunath Kondaiah static u32 configure_dma_errata(void) 146f31cc962SG, Manjunath Kondaiah { 147f31cc962SG, Manjunath Kondaiah 148f31cc962SG, Manjunath Kondaiah /* 149f31cc962SG, Manjunath Kondaiah * Errata applicable for OMAP2430ES1.0 and all omap2420 150f31cc962SG, Manjunath Kondaiah * 151f31cc962SG, Manjunath Kondaiah * I. 152f31cc962SG, Manjunath Kondaiah * Erratum ID: Not Available 153f31cc962SG, Manjunath Kondaiah * Inter Frame DMA buffering issue DMA will wrongly 154f31cc962SG, Manjunath Kondaiah * buffer elements if packing and bursting is enabled. This might 155f31cc962SG, Manjunath Kondaiah * result in data gets stalled in FIFO at the end of the block. 156f31cc962SG, Manjunath Kondaiah * Workaround: DMA channels must have BUFFERING_DISABLED bit set to 157f31cc962SG, Manjunath Kondaiah * guarantee no data will stay in the DMA FIFO in case inter frame 158f31cc962SG, Manjunath Kondaiah * buffering occurs 159f31cc962SG, Manjunath Kondaiah * 160f31cc962SG, Manjunath Kondaiah * II. 161f31cc962SG, Manjunath Kondaiah * Erratum ID: Not Available 162f31cc962SG, Manjunath Kondaiah * DMA may hang when several channels are used in parallel 163f31cc962SG, Manjunath Kondaiah * In the following configuration, DMA channel hanging can occur: 164f31cc962SG, Manjunath Kondaiah * a. Channel i, hardware synchronized, is enabled 165f31cc962SG, Manjunath Kondaiah * b. Another channel (Channel x), software synchronized, is enabled. 166f31cc962SG, Manjunath Kondaiah * c. Channel i is disabled before end of transfer 167f31cc962SG, Manjunath Kondaiah * d. Channel i is reenabled. 168f31cc962SG, Manjunath Kondaiah * e. Steps 1 to 4 are repeated a certain number of times. 169f31cc962SG, Manjunath Kondaiah * f. A third channel (Channel y), software synchronized, is enabled. 170f31cc962SG, Manjunath Kondaiah * Channel x and Channel y may hang immediately after step 'f'. 171f31cc962SG, Manjunath Kondaiah * Workaround: 172f31cc962SG, Manjunath Kondaiah * For any channel used - make sure NextLCH_ID is set to the value j. 173f31cc962SG, Manjunath Kondaiah */ 174f31cc962SG, Manjunath Kondaiah if (cpu_is_omap2420() || (cpu_is_omap2430() && 175f31cc962SG, Manjunath Kondaiah (omap_type() == OMAP2430_REV_ES1_0))) { 176f31cc962SG, Manjunath Kondaiah 177f31cc962SG, Manjunath Kondaiah SET_DMA_ERRATA(DMA_ERRATA_IFRAME_BUFFERING); 178f31cc962SG, Manjunath Kondaiah SET_DMA_ERRATA(DMA_ERRATA_PARALLEL_CHANNELS); 179f31cc962SG, Manjunath Kondaiah } 180f31cc962SG, Manjunath Kondaiah 181f31cc962SG, Manjunath Kondaiah /* 182f31cc962SG, Manjunath Kondaiah * Erratum ID: i378: OMAP2+: sDMA Channel is not disabled 183f31cc962SG, Manjunath Kondaiah * after a transaction error. 184f31cc962SG, Manjunath Kondaiah * Workaround: SW should explicitely disable the channel. 185f31cc962SG, Manjunath Kondaiah */ 186f31cc962SG, Manjunath Kondaiah if (cpu_class_is_omap2()) 187f31cc962SG, Manjunath Kondaiah SET_DMA_ERRATA(DMA_ERRATA_i378); 188f31cc962SG, Manjunath Kondaiah 189f31cc962SG, Manjunath Kondaiah /* 190f31cc962SG, Manjunath Kondaiah * Erratum ID: i541: sDMA FIFO draining does not finish 191f31cc962SG, Manjunath Kondaiah * If sDMA channel is disabled on the fly, sDMA enters standby even 192f31cc962SG, Manjunath Kondaiah * through FIFO Drain is still in progress 193f31cc962SG, Manjunath Kondaiah * Workaround: Put sDMA in NoStandby more before a logical channel is 194f31cc962SG, Manjunath Kondaiah * disabled, then put it back to SmartStandby right after the channel 195f31cc962SG, Manjunath Kondaiah * finishes FIFO draining. 196f31cc962SG, Manjunath Kondaiah */ 197f31cc962SG, Manjunath Kondaiah if (cpu_is_omap34xx()) 198f31cc962SG, Manjunath Kondaiah SET_DMA_ERRATA(DMA_ERRATA_i541); 199f31cc962SG, Manjunath Kondaiah 200f31cc962SG, Manjunath Kondaiah /* 201f31cc962SG, Manjunath Kondaiah * Erratum ID: i88 : Special programming model needed to disable DMA 202f31cc962SG, Manjunath Kondaiah * before end of block. 203f31cc962SG, Manjunath Kondaiah * Workaround: software must ensure that the DMA is configured in No 204f31cc962SG, Manjunath Kondaiah * Standby mode(DMAx_OCP_SYSCONFIG.MIDLEMODE = "01") 205f31cc962SG, Manjunath Kondaiah */ 206f31cc962SG, Manjunath Kondaiah if (omap_type() == OMAP3430_REV_ES1_0) 207f31cc962SG, Manjunath Kondaiah SET_DMA_ERRATA(DMA_ERRATA_i88); 208f31cc962SG, Manjunath Kondaiah 209f31cc962SG, Manjunath Kondaiah /* 210f31cc962SG, Manjunath Kondaiah * Erratum 3.2/3.3: sometimes 0 is returned if CSAC/CDAC is 211f31cc962SG, Manjunath Kondaiah * read before the DMA controller finished disabling the channel. 212f31cc962SG, Manjunath Kondaiah */ 213f31cc962SG, Manjunath Kondaiah SET_DMA_ERRATA(DMA_ERRATA_3_3); 214f31cc962SG, Manjunath Kondaiah 215f31cc962SG, Manjunath Kondaiah /* 216f31cc962SG, Manjunath Kondaiah * Erratum ID: Not Available 217f31cc962SG, Manjunath Kondaiah * A bug in ROM code leaves IRQ status for channels 0 and 1 uncleared 218f31cc962SG, Manjunath Kondaiah * after secure sram context save and restore. 219f31cc962SG, Manjunath Kondaiah * Work around: Hence we need to manually clear those IRQs to avoid 220f31cc962SG, Manjunath Kondaiah * spurious interrupts. This affects only secure devices. 221f31cc962SG, Manjunath Kondaiah */ 222f31cc962SG, Manjunath Kondaiah if (cpu_is_omap34xx() && (omap_type() != OMAP2_DEVICE_TYPE_GP)) 223f31cc962SG, Manjunath Kondaiah SET_DMA_ERRATA(DMA_ROMCODE_BUG); 224f31cc962SG, Manjunath Kondaiah 225f31cc962SG, Manjunath Kondaiah return errata; 226f31cc962SG, Manjunath Kondaiah } 227f31cc962SG, Manjunath Kondaiah 22859de3cf1SG, Manjunath Kondaiah /* One time initializations */ 22959de3cf1SG, Manjunath Kondaiah static int __init omap2_system_dma_init_dev(struct omap_hwmod *oh, void *unused) 23059de3cf1SG, Manjunath Kondaiah { 231*3528c58eSKevin Hilman struct platform_device *pdev; 23259de3cf1SG, Manjunath Kondaiah struct omap_system_dma_plat_info *p; 233f31cc962SG, Manjunath Kondaiah struct resource *mem; 23459de3cf1SG, Manjunath Kondaiah char *name = "omap_dma_system"; 23559de3cf1SG, Manjunath Kondaiah 236f31cc962SG, Manjunath Kondaiah dma_stride = OMAP2_DMA_STRIDE; 237f31cc962SG, Manjunath Kondaiah dma_common_ch_start = CSDP; 238f31cc962SG, Manjunath Kondaiah if (cpu_is_omap3630() || cpu_is_omap4430()) 239f31cc962SG, Manjunath Kondaiah dma_common_ch_end = CCDN; 240f31cc962SG, Manjunath Kondaiah else 241f31cc962SG, Manjunath Kondaiah dma_common_ch_end = CCFN; 242f31cc962SG, Manjunath Kondaiah 24359de3cf1SG, Manjunath Kondaiah p = kzalloc(sizeof(struct omap_system_dma_plat_info), GFP_KERNEL); 24459de3cf1SG, Manjunath Kondaiah if (!p) { 24559de3cf1SG, Manjunath Kondaiah pr_err("%s: Unable to allocate pdata for %s:%s\n", 24659de3cf1SG, Manjunath Kondaiah __func__, name, oh->name); 24759de3cf1SG, Manjunath Kondaiah return -ENOMEM; 24859de3cf1SG, Manjunath Kondaiah } 24959de3cf1SG, Manjunath Kondaiah 250f31cc962SG, Manjunath Kondaiah p->dma_attr = (struct omap_dma_dev_attr *)oh->dev_attr; 251f31cc962SG, Manjunath Kondaiah p->disable_irq_lch = omap2_disable_irq_lch; 252f31cc962SG, Manjunath Kondaiah p->show_dma_caps = omap2_show_dma_caps; 253f31cc962SG, Manjunath Kondaiah p->clear_dma = omap2_clear_dma; 254f31cc962SG, Manjunath Kondaiah p->dma_write = dma_write; 255f31cc962SG, Manjunath Kondaiah p->dma_read = dma_read; 256f31cc962SG, Manjunath Kondaiah 257f31cc962SG, Manjunath Kondaiah p->clear_lch_regs = NULL; 258f31cc962SG, Manjunath Kondaiah 259f31cc962SG, Manjunath Kondaiah p->errata = configure_dma_errata(); 260f31cc962SG, Manjunath Kondaiah 261*3528c58eSKevin Hilman pdev = omap_device_build(name, 0, oh, p, sizeof(*p), 26259de3cf1SG, Manjunath Kondaiah omap2_dma_latency, ARRAY_SIZE(omap2_dma_latency), 0); 26359de3cf1SG, Manjunath Kondaiah kfree(p); 264*3528c58eSKevin Hilman if (IS_ERR(pdev)) { 26525985edcSLucas De Marchi pr_err("%s: Can't build omap_device for %s:%s.\n", 26659de3cf1SG, Manjunath Kondaiah __func__, name, oh->name); 267*3528c58eSKevin Hilman return PTR_ERR(pdev); 26859de3cf1SG, Manjunath Kondaiah } 26959de3cf1SG, Manjunath Kondaiah 270*3528c58eSKevin Hilman mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); 271f31cc962SG, Manjunath Kondaiah if (!mem) { 272*3528c58eSKevin Hilman dev_err(&pdev->dev, "%s: no mem resource\n", __func__); 273f31cc962SG, Manjunath Kondaiah return -EINVAL; 274f31cc962SG, Manjunath Kondaiah } 275f31cc962SG, Manjunath Kondaiah dma_base = ioremap(mem->start, resource_size(mem)); 276f31cc962SG, Manjunath Kondaiah if (!dma_base) { 277*3528c58eSKevin Hilman dev_err(&pdev->dev, "%s: ioremap fail\n", __func__); 278f31cc962SG, Manjunath Kondaiah return -ENOMEM; 279f31cc962SG, Manjunath Kondaiah } 280f31cc962SG, Manjunath Kondaiah 281f31cc962SG, Manjunath Kondaiah d = oh->dev_attr; 282f31cc962SG, Manjunath Kondaiah d->chan = kzalloc(sizeof(struct omap_dma_lch) * 283f31cc962SG, Manjunath Kondaiah (d->lch_count), GFP_KERNEL); 284f31cc962SG, Manjunath Kondaiah 285f31cc962SG, Manjunath Kondaiah if (!d->chan) { 286*3528c58eSKevin Hilman dev_err(&pdev->dev, "%s: kzalloc fail\n", __func__); 287f31cc962SG, Manjunath Kondaiah return -ENOMEM; 288f31cc962SG, Manjunath Kondaiah } 28959de3cf1SG, Manjunath Kondaiah return 0; 29059de3cf1SG, Manjunath Kondaiah } 29159de3cf1SG, Manjunath Kondaiah 29259de3cf1SG, Manjunath Kondaiah static int __init omap2_system_dma_init(void) 29359de3cf1SG, Manjunath Kondaiah { 29459de3cf1SG, Manjunath Kondaiah return omap_hwmod_for_each_by_class("dma", 29559de3cf1SG, Manjunath Kondaiah omap2_system_dma_init_dev, NULL); 29659de3cf1SG, Manjunath Kondaiah } 29759de3cf1SG, Manjunath Kondaiah arch_initcall(omap2_system_dma_init); 298