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 31*45c3eb7dSTony Lindgren #include <linux/omap-dma.h> 3259de3cf1SG, Manjunath Kondaiah 33e4c060dbSTony Lindgren #include "soc.h" 342a296c8fSTony Lindgren #include "omap_hwmod.h" 3525c7d49eSTony Lindgren #include "omap_device.h" 3625c7d49eSTony Lindgren 37f31cc962SG, Manjunath Kondaiah #define OMAP2_DMA_STRIDE 0x60 38f31cc962SG, Manjunath Kondaiah 39f31cc962SG, Manjunath Kondaiah static u32 errata; 40f31cc962SG, Manjunath Kondaiah static u8 dma_stride; 41f31cc962SG, Manjunath Kondaiah 42f31cc962SG, Manjunath Kondaiah static struct omap_dma_dev_attr *d; 43f31cc962SG, Manjunath Kondaiah 44f31cc962SG, Manjunath Kondaiah static enum omap_reg_offsets dma_common_ch_start, dma_common_ch_end; 45f31cc962SG, Manjunath Kondaiah 46f31cc962SG, Manjunath Kondaiah static u16 reg_map[] = { 47f31cc962SG, Manjunath Kondaiah [REVISION] = 0x00, 48f31cc962SG, Manjunath Kondaiah [GCR] = 0x78, 49f31cc962SG, Manjunath Kondaiah [IRQSTATUS_L0] = 0x08, 50f31cc962SG, Manjunath Kondaiah [IRQSTATUS_L1] = 0x0c, 51f31cc962SG, Manjunath Kondaiah [IRQSTATUS_L2] = 0x10, 52f31cc962SG, Manjunath Kondaiah [IRQSTATUS_L3] = 0x14, 53f31cc962SG, Manjunath Kondaiah [IRQENABLE_L0] = 0x18, 54f31cc962SG, Manjunath Kondaiah [IRQENABLE_L1] = 0x1c, 55f31cc962SG, Manjunath Kondaiah [IRQENABLE_L2] = 0x20, 56f31cc962SG, Manjunath Kondaiah [IRQENABLE_L3] = 0x24, 57f31cc962SG, Manjunath Kondaiah [SYSSTATUS] = 0x28, 58f31cc962SG, Manjunath Kondaiah [OCP_SYSCONFIG] = 0x2c, 59f31cc962SG, Manjunath Kondaiah [CAPS_0] = 0x64, 60f31cc962SG, Manjunath Kondaiah [CAPS_2] = 0x6c, 61f31cc962SG, Manjunath Kondaiah [CAPS_3] = 0x70, 62f31cc962SG, Manjunath Kondaiah [CAPS_4] = 0x74, 63f31cc962SG, Manjunath Kondaiah 64f31cc962SG, Manjunath Kondaiah /* Common register offsets */ 65f31cc962SG, Manjunath Kondaiah [CCR] = 0x80, 66f31cc962SG, Manjunath Kondaiah [CLNK_CTRL] = 0x84, 67f31cc962SG, Manjunath Kondaiah [CICR] = 0x88, 68f31cc962SG, Manjunath Kondaiah [CSR] = 0x8c, 69f31cc962SG, Manjunath Kondaiah [CSDP] = 0x90, 70f31cc962SG, Manjunath Kondaiah [CEN] = 0x94, 71f31cc962SG, Manjunath Kondaiah [CFN] = 0x98, 72f31cc962SG, Manjunath Kondaiah [CSEI] = 0xa4, 73f31cc962SG, Manjunath Kondaiah [CSFI] = 0xa8, 74f31cc962SG, Manjunath Kondaiah [CDEI] = 0xac, 75f31cc962SG, Manjunath Kondaiah [CDFI] = 0xb0, 76f31cc962SG, Manjunath Kondaiah [CSAC] = 0xb4, 77f31cc962SG, Manjunath Kondaiah [CDAC] = 0xb8, 78f31cc962SG, Manjunath Kondaiah 79f31cc962SG, Manjunath Kondaiah /* Channel specific register offsets */ 80f31cc962SG, Manjunath Kondaiah [CSSA] = 0x9c, 81f31cc962SG, Manjunath Kondaiah [CDSA] = 0xa0, 82f31cc962SG, Manjunath Kondaiah [CCEN] = 0xbc, 83f31cc962SG, Manjunath Kondaiah [CCFN] = 0xc0, 84f31cc962SG, Manjunath Kondaiah [COLOR] = 0xc4, 85f31cc962SG, Manjunath Kondaiah 86f31cc962SG, Manjunath Kondaiah /* OMAP4 specific registers */ 87f31cc962SG, Manjunath Kondaiah [CDP] = 0xd0, 88f31cc962SG, Manjunath Kondaiah [CNDP] = 0xd4, 89f31cc962SG, Manjunath Kondaiah [CCDN] = 0xd8, 90f31cc962SG, Manjunath Kondaiah }; 91f31cc962SG, Manjunath Kondaiah 92f31cc962SG, Manjunath Kondaiah static void __iomem *dma_base; 93f31cc962SG, Manjunath Kondaiah static inline void dma_write(u32 val, int reg, int lch) 94f31cc962SG, Manjunath Kondaiah { 95f31cc962SG, Manjunath Kondaiah u8 stride; 96f31cc962SG, Manjunath Kondaiah u32 offset; 97f31cc962SG, Manjunath Kondaiah 98f31cc962SG, Manjunath Kondaiah stride = (reg >= dma_common_ch_start) ? dma_stride : 0; 99f31cc962SG, Manjunath Kondaiah offset = reg_map[reg] + (stride * lch); 100f31cc962SG, Manjunath Kondaiah __raw_writel(val, dma_base + offset); 101f31cc962SG, Manjunath Kondaiah } 102f31cc962SG, Manjunath Kondaiah 103f31cc962SG, Manjunath Kondaiah static inline u32 dma_read(int reg, int lch) 104f31cc962SG, Manjunath Kondaiah { 105f31cc962SG, Manjunath Kondaiah u8 stride; 106f31cc962SG, Manjunath Kondaiah u32 offset, val; 107f31cc962SG, Manjunath Kondaiah 108f31cc962SG, Manjunath Kondaiah stride = (reg >= dma_common_ch_start) ? dma_stride : 0; 109f31cc962SG, Manjunath Kondaiah offset = reg_map[reg] + (stride * lch); 110f31cc962SG, Manjunath Kondaiah val = __raw_readl(dma_base + offset); 111f31cc962SG, Manjunath Kondaiah return val; 112f31cc962SG, Manjunath Kondaiah } 113f31cc962SG, Manjunath Kondaiah 114f31cc962SG, Manjunath Kondaiah static inline void omap2_disable_irq_lch(int lch) 115f31cc962SG, Manjunath Kondaiah { 116f31cc962SG, Manjunath Kondaiah u32 val; 117f31cc962SG, Manjunath Kondaiah 118f31cc962SG, Manjunath Kondaiah val = dma_read(IRQENABLE_L0, lch); 119f31cc962SG, Manjunath Kondaiah val &= ~(1 << lch); 120f31cc962SG, Manjunath Kondaiah dma_write(val, IRQENABLE_L0, lch); 121f31cc962SG, Manjunath Kondaiah } 122f31cc962SG, Manjunath Kondaiah 123f31cc962SG, Manjunath Kondaiah static void omap2_clear_dma(int lch) 124f31cc962SG, Manjunath Kondaiah { 125f31cc962SG, Manjunath Kondaiah int i = dma_common_ch_start; 126f31cc962SG, Manjunath Kondaiah 127f31cc962SG, Manjunath Kondaiah for (; i <= dma_common_ch_end; i += 1) 128f31cc962SG, Manjunath Kondaiah dma_write(0, i, lch); 129f31cc962SG, Manjunath Kondaiah } 130f31cc962SG, Manjunath Kondaiah 131f31cc962SG, Manjunath Kondaiah static void omap2_show_dma_caps(void) 132f31cc962SG, Manjunath Kondaiah { 133f31cc962SG, Manjunath Kondaiah u8 revision = dma_read(REVISION, 0) & 0xff; 134f31cc962SG, Manjunath Kondaiah printk(KERN_INFO "OMAP DMA hardware revision %d.%d\n", 135f31cc962SG, Manjunath Kondaiah revision >> 4, revision & 0xf); 136f31cc962SG, Manjunath Kondaiah return; 137f31cc962SG, Manjunath Kondaiah } 138f31cc962SG, Manjunath Kondaiah 139f31cc962SG, Manjunath Kondaiah static u32 configure_dma_errata(void) 140f31cc962SG, Manjunath Kondaiah { 141f31cc962SG, Manjunath Kondaiah 142f31cc962SG, Manjunath Kondaiah /* 143f31cc962SG, Manjunath Kondaiah * Errata applicable for OMAP2430ES1.0 and all omap2420 144f31cc962SG, Manjunath Kondaiah * 145f31cc962SG, Manjunath Kondaiah * I. 146f31cc962SG, Manjunath Kondaiah * Erratum ID: Not Available 147f31cc962SG, Manjunath Kondaiah * Inter Frame DMA buffering issue DMA will wrongly 148f31cc962SG, Manjunath Kondaiah * buffer elements if packing and bursting is enabled. This might 149f31cc962SG, Manjunath Kondaiah * result in data gets stalled in FIFO at the end of the block. 150f31cc962SG, Manjunath Kondaiah * Workaround: DMA channels must have BUFFERING_DISABLED bit set to 151f31cc962SG, Manjunath Kondaiah * guarantee no data will stay in the DMA FIFO in case inter frame 152f31cc962SG, Manjunath Kondaiah * buffering occurs 153f31cc962SG, Manjunath Kondaiah * 154f31cc962SG, Manjunath Kondaiah * II. 155f31cc962SG, Manjunath Kondaiah * Erratum ID: Not Available 156f31cc962SG, Manjunath Kondaiah * DMA may hang when several channels are used in parallel 157f31cc962SG, Manjunath Kondaiah * In the following configuration, DMA channel hanging can occur: 158f31cc962SG, Manjunath Kondaiah * a. Channel i, hardware synchronized, is enabled 159f31cc962SG, Manjunath Kondaiah * b. Another channel (Channel x), software synchronized, is enabled. 160f31cc962SG, Manjunath Kondaiah * c. Channel i is disabled before end of transfer 161f31cc962SG, Manjunath Kondaiah * d. Channel i is reenabled. 162f31cc962SG, Manjunath Kondaiah * e. Steps 1 to 4 are repeated a certain number of times. 163f31cc962SG, Manjunath Kondaiah * f. A third channel (Channel y), software synchronized, is enabled. 164f31cc962SG, Manjunath Kondaiah * Channel x and Channel y may hang immediately after step 'f'. 165f31cc962SG, Manjunath Kondaiah * Workaround: 166f31cc962SG, Manjunath Kondaiah * For any channel used - make sure NextLCH_ID is set to the value j. 167f31cc962SG, Manjunath Kondaiah */ 168f31cc962SG, Manjunath Kondaiah if (cpu_is_omap2420() || (cpu_is_omap2430() && 169f31cc962SG, Manjunath Kondaiah (omap_type() == OMAP2430_REV_ES1_0))) { 170f31cc962SG, Manjunath Kondaiah 171f31cc962SG, Manjunath Kondaiah SET_DMA_ERRATA(DMA_ERRATA_IFRAME_BUFFERING); 172f31cc962SG, Manjunath Kondaiah SET_DMA_ERRATA(DMA_ERRATA_PARALLEL_CHANNELS); 173f31cc962SG, Manjunath Kondaiah } 174f31cc962SG, Manjunath Kondaiah 175f31cc962SG, Manjunath Kondaiah /* 176f31cc962SG, Manjunath Kondaiah * Erratum ID: i378: OMAP2+: sDMA Channel is not disabled 177f31cc962SG, Manjunath Kondaiah * after a transaction error. 178f31cc962SG, Manjunath Kondaiah * Workaround: SW should explicitely disable the channel. 179f31cc962SG, Manjunath Kondaiah */ 180f31cc962SG, Manjunath Kondaiah if (cpu_class_is_omap2()) 181f31cc962SG, Manjunath Kondaiah SET_DMA_ERRATA(DMA_ERRATA_i378); 182f31cc962SG, Manjunath Kondaiah 183f31cc962SG, Manjunath Kondaiah /* 184f31cc962SG, Manjunath Kondaiah * Erratum ID: i541: sDMA FIFO draining does not finish 185f31cc962SG, Manjunath Kondaiah * If sDMA channel is disabled on the fly, sDMA enters standby even 186f31cc962SG, Manjunath Kondaiah * through FIFO Drain is still in progress 187f31cc962SG, Manjunath Kondaiah * Workaround: Put sDMA in NoStandby more before a logical channel is 188f31cc962SG, Manjunath Kondaiah * disabled, then put it back to SmartStandby right after the channel 189f31cc962SG, Manjunath Kondaiah * finishes FIFO draining. 190f31cc962SG, Manjunath Kondaiah */ 191f31cc962SG, Manjunath Kondaiah if (cpu_is_omap34xx()) 192f31cc962SG, Manjunath Kondaiah SET_DMA_ERRATA(DMA_ERRATA_i541); 193f31cc962SG, Manjunath Kondaiah 194f31cc962SG, Manjunath Kondaiah /* 195f31cc962SG, Manjunath Kondaiah * Erratum ID: i88 : Special programming model needed to disable DMA 196f31cc962SG, Manjunath Kondaiah * before end of block. 197f31cc962SG, Manjunath Kondaiah * Workaround: software must ensure that the DMA is configured in No 198f31cc962SG, Manjunath Kondaiah * Standby mode(DMAx_OCP_SYSCONFIG.MIDLEMODE = "01") 199f31cc962SG, Manjunath Kondaiah */ 200f31cc962SG, Manjunath Kondaiah if (omap_type() == OMAP3430_REV_ES1_0) 201f31cc962SG, Manjunath Kondaiah SET_DMA_ERRATA(DMA_ERRATA_i88); 202f31cc962SG, Manjunath Kondaiah 203f31cc962SG, Manjunath Kondaiah /* 204f31cc962SG, Manjunath Kondaiah * Erratum 3.2/3.3: sometimes 0 is returned if CSAC/CDAC is 205f31cc962SG, Manjunath Kondaiah * read before the DMA controller finished disabling the channel. 206f31cc962SG, Manjunath Kondaiah */ 207f31cc962SG, Manjunath Kondaiah SET_DMA_ERRATA(DMA_ERRATA_3_3); 208f31cc962SG, Manjunath Kondaiah 209f31cc962SG, Manjunath Kondaiah /* 210f31cc962SG, Manjunath Kondaiah * Erratum ID: Not Available 211f31cc962SG, Manjunath Kondaiah * A bug in ROM code leaves IRQ status for channels 0 and 1 uncleared 212f31cc962SG, Manjunath Kondaiah * after secure sram context save and restore. 213f31cc962SG, Manjunath Kondaiah * Work around: Hence we need to manually clear those IRQs to avoid 214f31cc962SG, Manjunath Kondaiah * spurious interrupts. This affects only secure devices. 215f31cc962SG, Manjunath Kondaiah */ 216f31cc962SG, Manjunath Kondaiah if (cpu_is_omap34xx() && (omap_type() != OMAP2_DEVICE_TYPE_GP)) 217f31cc962SG, Manjunath Kondaiah SET_DMA_ERRATA(DMA_ROMCODE_BUG); 218f31cc962SG, Manjunath Kondaiah 219f31cc962SG, Manjunath Kondaiah return errata; 220f31cc962SG, Manjunath Kondaiah } 221f31cc962SG, Manjunath Kondaiah 22259de3cf1SG, Manjunath Kondaiah /* One time initializations */ 22359de3cf1SG, Manjunath Kondaiah static int __init omap2_system_dma_init_dev(struct omap_hwmod *oh, void *unused) 22459de3cf1SG, Manjunath Kondaiah { 2253528c58eSKevin Hilman struct platform_device *pdev; 22659de3cf1SG, Manjunath Kondaiah struct omap_system_dma_plat_info *p; 227f31cc962SG, Manjunath Kondaiah struct resource *mem; 22859de3cf1SG, Manjunath Kondaiah char *name = "omap_dma_system"; 22959de3cf1SG, Manjunath Kondaiah 230f31cc962SG, Manjunath Kondaiah dma_stride = OMAP2_DMA_STRIDE; 231f31cc962SG, Manjunath Kondaiah dma_common_ch_start = CSDP; 232f31cc962SG, Manjunath Kondaiah 23359de3cf1SG, Manjunath Kondaiah p = kzalloc(sizeof(struct omap_system_dma_plat_info), GFP_KERNEL); 23459de3cf1SG, Manjunath Kondaiah if (!p) { 23559de3cf1SG, Manjunath Kondaiah pr_err("%s: Unable to allocate pdata for %s:%s\n", 23659de3cf1SG, Manjunath Kondaiah __func__, name, oh->name); 23759de3cf1SG, Manjunath Kondaiah return -ENOMEM; 23859de3cf1SG, Manjunath Kondaiah } 23959de3cf1SG, Manjunath Kondaiah 240f31cc962SG, Manjunath Kondaiah p->dma_attr = (struct omap_dma_dev_attr *)oh->dev_attr; 241f31cc962SG, Manjunath Kondaiah p->disable_irq_lch = omap2_disable_irq_lch; 242f31cc962SG, Manjunath Kondaiah p->show_dma_caps = omap2_show_dma_caps; 243f31cc962SG, Manjunath Kondaiah p->clear_dma = omap2_clear_dma; 244f31cc962SG, Manjunath Kondaiah p->dma_write = dma_write; 245f31cc962SG, Manjunath Kondaiah p->dma_read = dma_read; 246f31cc962SG, Manjunath Kondaiah 247f31cc962SG, Manjunath Kondaiah p->clear_lch_regs = NULL; 248f31cc962SG, Manjunath Kondaiah 249f31cc962SG, Manjunath Kondaiah p->errata = configure_dma_errata(); 250f31cc962SG, Manjunath Kondaiah 251f718e2c0SBenoit Cousson pdev = omap_device_build(name, 0, oh, p, sizeof(*p), NULL, 0, 0); 25259de3cf1SG, Manjunath Kondaiah kfree(p); 2533528c58eSKevin Hilman if (IS_ERR(pdev)) { 25425985edcSLucas De Marchi pr_err("%s: Can't build omap_device for %s:%s.\n", 25559de3cf1SG, Manjunath Kondaiah __func__, name, oh->name); 2563528c58eSKevin Hilman return PTR_ERR(pdev); 25759de3cf1SG, Manjunath Kondaiah } 25859de3cf1SG, Manjunath Kondaiah 2593528c58eSKevin Hilman mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); 260f31cc962SG, Manjunath Kondaiah if (!mem) { 2613528c58eSKevin Hilman dev_err(&pdev->dev, "%s: no mem resource\n", __func__); 262f31cc962SG, Manjunath Kondaiah return -EINVAL; 263f31cc962SG, Manjunath Kondaiah } 264f31cc962SG, Manjunath Kondaiah dma_base = ioremap(mem->start, resource_size(mem)); 265f31cc962SG, Manjunath Kondaiah if (!dma_base) { 2663528c58eSKevin Hilman dev_err(&pdev->dev, "%s: ioremap fail\n", __func__); 267f31cc962SG, Manjunath Kondaiah return -ENOMEM; 268f31cc962SG, Manjunath Kondaiah } 269f31cc962SG, Manjunath Kondaiah 270f31cc962SG, Manjunath Kondaiah d = oh->dev_attr; 271f31cc962SG, Manjunath Kondaiah d->chan = kzalloc(sizeof(struct omap_dma_lch) * 272f31cc962SG, Manjunath Kondaiah (d->lch_count), GFP_KERNEL); 273f31cc962SG, Manjunath Kondaiah 274f31cc962SG, Manjunath Kondaiah if (!d->chan) { 2753528c58eSKevin Hilman dev_err(&pdev->dev, "%s: kzalloc fail\n", __func__); 276f31cc962SG, Manjunath Kondaiah return -ENOMEM; 277f31cc962SG, Manjunath Kondaiah } 278f6d5e079SR Sricharan 27982809601STony Lindgren if (cpu_is_omap34xx() && (omap_type() != OMAP2_DEVICE_TYPE_GP)) 28082809601STony Lindgren d->dev_caps |= HS_CHANNELS_RESERVED; 28182809601STony Lindgren 282f6d5e079SR Sricharan /* Check the capabilities register for descriptor loading feature */ 283f6d5e079SR Sricharan if (dma_read(CAPS_0, 0) & DMA_HAS_DESCRIPTOR_CAPS) 284f6d5e079SR Sricharan dma_common_ch_end = CCDN; 285f6d5e079SR Sricharan else 286f6d5e079SR Sricharan dma_common_ch_end = CCFN; 287f6d5e079SR Sricharan 28859de3cf1SG, Manjunath Kondaiah return 0; 28959de3cf1SG, Manjunath Kondaiah } 29059de3cf1SG, Manjunath Kondaiah 29159de3cf1SG, Manjunath Kondaiah static int __init omap2_system_dma_init(void) 29259de3cf1SG, Manjunath Kondaiah { 29359de3cf1SG, Manjunath Kondaiah return omap_hwmod_for_each_by_class("dma", 29459de3cf1SG, Manjunath Kondaiah omap2_system_dma_init_dev, NULL); 29559de3cf1SG, Manjunath Kondaiah } 29659de3cf1SG, Manjunath Kondaiah arch_initcall(omap2_system_dma_init); 297