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> 30be1f9481STony Lindgren #include <linux/dma-mapping.h> 318d30662aSJon Hunter #include <linux/of.h> 3245c3eb7dSTony Lindgren #include <linux/omap-dma.h> 3359de3cf1SG, Manjunath Kondaiah 34e4c060dbSTony Lindgren #include "soc.h" 352a296c8fSTony Lindgren #include "omap_hwmod.h" 3625c7d49eSTony Lindgren #include "omap_device.h" 3725c7d49eSTony Lindgren 38ad0c381aSRussell King static enum omap_reg_offsets dma_common_ch_end; 39f31cc962SG, Manjunath Kondaiah 4064a2dc3dSRussell King static const struct omap_dma_reg reg_map[] = { 4164a2dc3dSRussell King [REVISION] = { 0x0000, 0x00, OMAP_DMA_REG_32BIT }, 4264a2dc3dSRussell King [GCR] = { 0x0078, 0x00, OMAP_DMA_REG_32BIT }, 4364a2dc3dSRussell King [IRQSTATUS_L0] = { 0x0008, 0x00, OMAP_DMA_REG_32BIT }, 4464a2dc3dSRussell King [IRQSTATUS_L1] = { 0x000c, 0x00, OMAP_DMA_REG_32BIT }, 4564a2dc3dSRussell King [IRQSTATUS_L2] = { 0x0010, 0x00, OMAP_DMA_REG_32BIT }, 4664a2dc3dSRussell King [IRQSTATUS_L3] = { 0x0014, 0x00, OMAP_DMA_REG_32BIT }, 4764a2dc3dSRussell King [IRQENABLE_L0] = { 0x0018, 0x00, OMAP_DMA_REG_32BIT }, 4864a2dc3dSRussell King [IRQENABLE_L1] = { 0x001c, 0x00, OMAP_DMA_REG_32BIT }, 4964a2dc3dSRussell King [IRQENABLE_L2] = { 0x0020, 0x00, OMAP_DMA_REG_32BIT }, 5064a2dc3dSRussell King [IRQENABLE_L3] = { 0x0024, 0x00, OMAP_DMA_REG_32BIT }, 5164a2dc3dSRussell King [SYSSTATUS] = { 0x0028, 0x00, OMAP_DMA_REG_32BIT }, 5264a2dc3dSRussell King [OCP_SYSCONFIG] = { 0x002c, 0x00, OMAP_DMA_REG_32BIT }, 5364a2dc3dSRussell King [CAPS_0] = { 0x0064, 0x00, OMAP_DMA_REG_32BIT }, 5464a2dc3dSRussell King [CAPS_2] = { 0x006c, 0x00, OMAP_DMA_REG_32BIT }, 5564a2dc3dSRussell King [CAPS_3] = { 0x0070, 0x00, OMAP_DMA_REG_32BIT }, 5664a2dc3dSRussell King [CAPS_4] = { 0x0074, 0x00, OMAP_DMA_REG_32BIT }, 57f31cc962SG, Manjunath Kondaiah 58f31cc962SG, Manjunath Kondaiah /* Common register offsets */ 5964a2dc3dSRussell King [CCR] = { 0x0080, 0x60, OMAP_DMA_REG_32BIT }, 6064a2dc3dSRussell King [CLNK_CTRL] = { 0x0084, 0x60, OMAP_DMA_REG_32BIT }, 6164a2dc3dSRussell King [CICR] = { 0x0088, 0x60, OMAP_DMA_REG_32BIT }, 6264a2dc3dSRussell King [CSR] = { 0x008c, 0x60, OMAP_DMA_REG_32BIT }, 6364a2dc3dSRussell King [CSDP] = { 0x0090, 0x60, OMAP_DMA_REG_32BIT }, 6464a2dc3dSRussell King [CEN] = { 0x0094, 0x60, OMAP_DMA_REG_32BIT }, 6564a2dc3dSRussell King [CFN] = { 0x0098, 0x60, OMAP_DMA_REG_32BIT }, 6664a2dc3dSRussell King [CSEI] = { 0x00a4, 0x60, OMAP_DMA_REG_32BIT }, 6764a2dc3dSRussell King [CSFI] = { 0x00a8, 0x60, OMAP_DMA_REG_32BIT }, 6864a2dc3dSRussell King [CDEI] = { 0x00ac, 0x60, OMAP_DMA_REG_32BIT }, 6964a2dc3dSRussell King [CDFI] = { 0x00b0, 0x60, OMAP_DMA_REG_32BIT }, 7064a2dc3dSRussell King [CSAC] = { 0x00b4, 0x60, OMAP_DMA_REG_32BIT }, 7164a2dc3dSRussell King [CDAC] = { 0x00b8, 0x60, OMAP_DMA_REG_32BIT }, 72f31cc962SG, Manjunath Kondaiah 73f31cc962SG, Manjunath Kondaiah /* Channel specific register offsets */ 7464a2dc3dSRussell King [CSSA] = { 0x009c, 0x60, OMAP_DMA_REG_32BIT }, 7564a2dc3dSRussell King [CDSA] = { 0x00a0, 0x60, OMAP_DMA_REG_32BIT }, 7664a2dc3dSRussell King [CCEN] = { 0x00bc, 0x60, OMAP_DMA_REG_32BIT }, 7764a2dc3dSRussell King [CCFN] = { 0x00c0, 0x60, OMAP_DMA_REG_32BIT }, 7864a2dc3dSRussell King [COLOR] = { 0x00c4, 0x60, OMAP_DMA_REG_32BIT }, 79f31cc962SG, Manjunath Kondaiah 80f31cc962SG, Manjunath Kondaiah /* OMAP4 specific registers */ 8164a2dc3dSRussell King [CDP] = { 0x00d0, 0x60, OMAP_DMA_REG_32BIT }, 8264a2dc3dSRussell King [CNDP] = { 0x00d4, 0x60, OMAP_DMA_REG_32BIT }, 8364a2dc3dSRussell King [CCDN] = { 0x00d8, 0x60, OMAP_DMA_REG_32BIT }, 84f31cc962SG, Manjunath Kondaiah }; 85f31cc962SG, Manjunath Kondaiah 86f31cc962SG, Manjunath Kondaiah static void __iomem *dma_base; 87f31cc962SG, Manjunath Kondaiah static inline void dma_write(u32 val, int reg, int lch) 88f31cc962SG, Manjunath Kondaiah { 8964a2dc3dSRussell King void __iomem *addr = dma_base; 90f31cc962SG, Manjunath Kondaiah 9164a2dc3dSRussell King addr += reg_map[reg].offset; 9264a2dc3dSRussell King addr += reg_map[reg].stride * lch; 9364a2dc3dSRussell King 9464a2dc3dSRussell King __raw_writel(val, addr); 95f31cc962SG, Manjunath Kondaiah } 96f31cc962SG, Manjunath Kondaiah 97f31cc962SG, Manjunath Kondaiah static inline u32 dma_read(int reg, int lch) 98f31cc962SG, Manjunath Kondaiah { 9964a2dc3dSRussell King void __iomem *addr = dma_base; 100f31cc962SG, Manjunath Kondaiah 10164a2dc3dSRussell King addr += reg_map[reg].offset; 10264a2dc3dSRussell King addr += reg_map[reg].stride * lch; 10364a2dc3dSRussell King 10464a2dc3dSRussell King return __raw_readl(addr); 105f31cc962SG, Manjunath Kondaiah } 106f31cc962SG, Manjunath Kondaiah 107f31cc962SG, Manjunath Kondaiah static void omap2_clear_dma(int lch) 108f31cc962SG, Manjunath Kondaiah { 109ad0c381aSRussell King int i; 110f31cc962SG, Manjunath Kondaiah 111ad0c381aSRussell King for (i = CSDP; i <= dma_common_ch_end; i += 1) 112f31cc962SG, Manjunath Kondaiah dma_write(0, i, lch); 113f31cc962SG, Manjunath Kondaiah } 114f31cc962SG, Manjunath Kondaiah 115f31cc962SG, Manjunath Kondaiah static void omap2_show_dma_caps(void) 116f31cc962SG, Manjunath Kondaiah { 117f31cc962SG, Manjunath Kondaiah u8 revision = dma_read(REVISION, 0) & 0xff; 118f31cc962SG, Manjunath Kondaiah printk(KERN_INFO "OMAP DMA hardware revision %d.%d\n", 119f31cc962SG, Manjunath Kondaiah revision >> 4, revision & 0xf); 120f31cc962SG, Manjunath Kondaiah return; 121f31cc962SG, Manjunath Kondaiah } 122f31cc962SG, Manjunath Kondaiah 1230ef64986SRussell King static unsigned configure_dma_errata(void) 124f31cc962SG, Manjunath Kondaiah { 1250ef64986SRussell King unsigned errata = 0; 126f31cc962SG, Manjunath Kondaiah 127f31cc962SG, Manjunath Kondaiah /* 128f31cc962SG, Manjunath Kondaiah * Errata applicable for OMAP2430ES1.0 and all omap2420 129f31cc962SG, Manjunath Kondaiah * 130f31cc962SG, Manjunath Kondaiah * I. 131f31cc962SG, Manjunath Kondaiah * Erratum ID: Not Available 132f31cc962SG, Manjunath Kondaiah * Inter Frame DMA buffering issue DMA will wrongly 133f31cc962SG, Manjunath Kondaiah * buffer elements if packing and bursting is enabled. This might 134f31cc962SG, Manjunath Kondaiah * result in data gets stalled in FIFO at the end of the block. 135f31cc962SG, Manjunath Kondaiah * Workaround: DMA channels must have BUFFERING_DISABLED bit set to 136f31cc962SG, Manjunath Kondaiah * guarantee no data will stay in the DMA FIFO in case inter frame 137f31cc962SG, Manjunath Kondaiah * buffering occurs 138f31cc962SG, Manjunath Kondaiah * 139f31cc962SG, Manjunath Kondaiah * II. 140f31cc962SG, Manjunath Kondaiah * Erratum ID: Not Available 141f31cc962SG, Manjunath Kondaiah * DMA may hang when several channels are used in parallel 142f31cc962SG, Manjunath Kondaiah * In the following configuration, DMA channel hanging can occur: 143f31cc962SG, Manjunath Kondaiah * a. Channel i, hardware synchronized, is enabled 144f31cc962SG, Manjunath Kondaiah * b. Another channel (Channel x), software synchronized, is enabled. 145f31cc962SG, Manjunath Kondaiah * c. Channel i is disabled before end of transfer 146f31cc962SG, Manjunath Kondaiah * d. Channel i is reenabled. 147f31cc962SG, Manjunath Kondaiah * e. Steps 1 to 4 are repeated a certain number of times. 148f31cc962SG, Manjunath Kondaiah * f. A third channel (Channel y), software synchronized, is enabled. 149f31cc962SG, Manjunath Kondaiah * Channel x and Channel y may hang immediately after step 'f'. 150f31cc962SG, Manjunath Kondaiah * Workaround: 151f31cc962SG, Manjunath Kondaiah * For any channel used - make sure NextLCH_ID is set to the value j. 152f31cc962SG, Manjunath Kondaiah */ 153f31cc962SG, Manjunath Kondaiah if (cpu_is_omap2420() || (cpu_is_omap2430() && 154f31cc962SG, Manjunath Kondaiah (omap_type() == OMAP2430_REV_ES1_0))) { 155f31cc962SG, Manjunath Kondaiah 156f31cc962SG, Manjunath Kondaiah SET_DMA_ERRATA(DMA_ERRATA_IFRAME_BUFFERING); 157f31cc962SG, Manjunath Kondaiah SET_DMA_ERRATA(DMA_ERRATA_PARALLEL_CHANNELS); 158f31cc962SG, Manjunath Kondaiah } 159f31cc962SG, Manjunath Kondaiah 160f31cc962SG, Manjunath Kondaiah /* 161f31cc962SG, Manjunath Kondaiah * Erratum ID: i378: OMAP2+: sDMA Channel is not disabled 162f31cc962SG, Manjunath Kondaiah * after a transaction error. 163f31cc962SG, Manjunath Kondaiah * Workaround: SW should explicitely disable the channel. 164f31cc962SG, Manjunath Kondaiah */ 165f31cc962SG, Manjunath Kondaiah if (cpu_class_is_omap2()) 166f31cc962SG, Manjunath Kondaiah SET_DMA_ERRATA(DMA_ERRATA_i378); 167f31cc962SG, Manjunath Kondaiah 168f31cc962SG, Manjunath Kondaiah /* 169f31cc962SG, Manjunath Kondaiah * Erratum ID: i541: sDMA FIFO draining does not finish 170f31cc962SG, Manjunath Kondaiah * If sDMA channel is disabled on the fly, sDMA enters standby even 171f31cc962SG, Manjunath Kondaiah * through FIFO Drain is still in progress 172f31cc962SG, Manjunath Kondaiah * Workaround: Put sDMA in NoStandby more before a logical channel is 173f31cc962SG, Manjunath Kondaiah * disabled, then put it back to SmartStandby right after the channel 174f31cc962SG, Manjunath Kondaiah * finishes FIFO draining. 175f31cc962SG, Manjunath Kondaiah */ 176f31cc962SG, Manjunath Kondaiah if (cpu_is_omap34xx()) 177f31cc962SG, Manjunath Kondaiah SET_DMA_ERRATA(DMA_ERRATA_i541); 178f31cc962SG, Manjunath Kondaiah 179f31cc962SG, Manjunath Kondaiah /* 180f31cc962SG, Manjunath Kondaiah * Erratum ID: i88 : Special programming model needed to disable DMA 181f31cc962SG, Manjunath Kondaiah * before end of block. 182f31cc962SG, Manjunath Kondaiah * Workaround: software must ensure that the DMA is configured in No 183f31cc962SG, Manjunath Kondaiah * Standby mode(DMAx_OCP_SYSCONFIG.MIDLEMODE = "01") 184f31cc962SG, Manjunath Kondaiah */ 185f31cc962SG, Manjunath Kondaiah if (omap_type() == OMAP3430_REV_ES1_0) 186f31cc962SG, Manjunath Kondaiah SET_DMA_ERRATA(DMA_ERRATA_i88); 187f31cc962SG, Manjunath Kondaiah 188f31cc962SG, Manjunath Kondaiah /* 189f31cc962SG, Manjunath Kondaiah * Erratum 3.2/3.3: sometimes 0 is returned if CSAC/CDAC is 190f31cc962SG, Manjunath Kondaiah * read before the DMA controller finished disabling the channel. 191f31cc962SG, Manjunath Kondaiah */ 192f31cc962SG, Manjunath Kondaiah SET_DMA_ERRATA(DMA_ERRATA_3_3); 193f31cc962SG, Manjunath Kondaiah 194f31cc962SG, Manjunath Kondaiah /* 195f31cc962SG, Manjunath Kondaiah * Erratum ID: Not Available 196f31cc962SG, Manjunath Kondaiah * A bug in ROM code leaves IRQ status for channels 0 and 1 uncleared 197f31cc962SG, Manjunath Kondaiah * after secure sram context save and restore. 198f31cc962SG, Manjunath Kondaiah * Work around: Hence we need to manually clear those IRQs to avoid 199f31cc962SG, Manjunath Kondaiah * spurious interrupts. This affects only secure devices. 200f31cc962SG, Manjunath Kondaiah */ 201f31cc962SG, Manjunath Kondaiah if (cpu_is_omap34xx() && (omap_type() != OMAP2_DEVICE_TYPE_GP)) 202f31cc962SG, Manjunath Kondaiah SET_DMA_ERRATA(DMA_ROMCODE_BUG); 203f31cc962SG, Manjunath Kondaiah 204f31cc962SG, Manjunath Kondaiah return errata; 205f31cc962SG, Manjunath Kondaiah } 206f31cc962SG, Manjunath Kondaiah 20734a378fcSRussell King static struct omap_system_dma_plat_info dma_plat_info __initdata = { 20834a378fcSRussell King .show_dma_caps = omap2_show_dma_caps, 20934a378fcSRussell King .clear_dma = omap2_clear_dma, 21034a378fcSRussell King .dma_write = dma_write, 21134a378fcSRussell King .dma_read = dma_read, 21234a378fcSRussell King }; 21334a378fcSRussell King 21459de3cf1SG, Manjunath Kondaiah /* One time initializations */ 21559de3cf1SG, Manjunath Kondaiah static int __init omap2_system_dma_init_dev(struct omap_hwmod *oh, void *unused) 21659de3cf1SG, Manjunath Kondaiah { 2173528c58eSKevin Hilman struct platform_device *pdev; 21834a378fcSRussell King struct omap_system_dma_plat_info p; 21934a378fcSRussell King struct omap_dma_dev_attr *d; 220f31cc962SG, Manjunath Kondaiah struct resource *mem; 22159de3cf1SG, Manjunath Kondaiah char *name = "omap_dma_system"; 22259de3cf1SG, Manjunath Kondaiah 22334a378fcSRussell King p = dma_plat_info; 22434a378fcSRussell King p.dma_attr = (struct omap_dma_dev_attr *)oh->dev_attr; 22534a378fcSRussell King p.errata = configure_dma_errata(); 22659de3cf1SG, Manjunath Kondaiah 22734a378fcSRussell King pdev = omap_device_build(name, 0, oh, &p, sizeof(p)); 2283528c58eSKevin Hilman if (IS_ERR(pdev)) { 22925985edcSLucas De Marchi pr_err("%s: Can't build omap_device for %s:%s.\n", 23059de3cf1SG, Manjunath Kondaiah __func__, name, oh->name); 2313528c58eSKevin Hilman return PTR_ERR(pdev); 23259de3cf1SG, Manjunath Kondaiah } 23359de3cf1SG, Manjunath Kondaiah 2343528c58eSKevin Hilman mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); 235f31cc962SG, Manjunath Kondaiah if (!mem) { 2363528c58eSKevin Hilman dev_err(&pdev->dev, "%s: no mem resource\n", __func__); 237f31cc962SG, Manjunath Kondaiah return -EINVAL; 238f31cc962SG, Manjunath Kondaiah } 239f31cc962SG, Manjunath Kondaiah dma_base = ioremap(mem->start, resource_size(mem)); 240f31cc962SG, Manjunath Kondaiah if (!dma_base) { 2413528c58eSKevin Hilman dev_err(&pdev->dev, "%s: ioremap fail\n", __func__); 242f31cc962SG, Manjunath Kondaiah return -ENOMEM; 243f31cc962SG, Manjunath Kondaiah } 244f31cc962SG, Manjunath Kondaiah 245f31cc962SG, Manjunath Kondaiah d = oh->dev_attr; 246f6d5e079SR Sricharan 24782809601STony Lindgren if (cpu_is_omap34xx() && (omap_type() != OMAP2_DEVICE_TYPE_GP)) 24882809601STony Lindgren d->dev_caps |= HS_CHANNELS_RESERVED; 24982809601STony Lindgren 250f6d5e079SR Sricharan /* Check the capabilities register for descriptor loading feature */ 251f6d5e079SR Sricharan if (dma_read(CAPS_0, 0) & DMA_HAS_DESCRIPTOR_CAPS) 252f6d5e079SR Sricharan dma_common_ch_end = CCDN; 253f6d5e079SR Sricharan else 254f6d5e079SR Sricharan dma_common_ch_end = CCFN; 255f6d5e079SR Sricharan 25659de3cf1SG, Manjunath Kondaiah return 0; 25759de3cf1SG, Manjunath Kondaiah } 25859de3cf1SG, Manjunath Kondaiah 259be1f9481STony Lindgren static const struct platform_device_info omap_dma_dev_info = { 260be1f9481STony Lindgren .name = "omap-dma-engine", 261be1f9481STony Lindgren .id = -1, 262be1f9481STony Lindgren .dma_mask = DMA_BIT_MASK(32), 263be1f9481STony Lindgren }; 264be1f9481STony Lindgren 26559de3cf1SG, Manjunath Kondaiah static int __init omap2_system_dma_init(void) 26659de3cf1SG, Manjunath Kondaiah { 267be1f9481STony Lindgren struct platform_device *pdev; 268be1f9481STony Lindgren int res; 269be1f9481STony Lindgren 270be1f9481STony Lindgren res = omap_hwmod_for_each_by_class("dma", 27159de3cf1SG, Manjunath Kondaiah omap2_system_dma_init_dev, NULL); 272be1f9481STony Lindgren if (res) 273be1f9481STony Lindgren return res; 274be1f9481STony Lindgren 2758d30662aSJon Hunter if (of_have_populated_dt()) 2768d30662aSJon Hunter return res; 2778d30662aSJon Hunter 278be1f9481STony Lindgren pdev = platform_device_register_full(&omap_dma_dev_info); 279be1f9481STony Lindgren if (IS_ERR(pdev)) 280be1f9481STony Lindgren return PTR_ERR(pdev); 281be1f9481STony Lindgren 282be1f9481STony Lindgren return res; 28359de3cf1SG, Manjunath Kondaiah } 284b76c8b19STony Lindgren omap_arch_initcall(omap2_system_dma_init); 285