162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * OMAP2+ DMA driver 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2003 - 2008 Nokia Corporation 662306a36Sopenharmony_ci * Author: Juha Yrjölä <juha.yrjola@nokia.com> 762306a36Sopenharmony_ci * DMA channel linking for 1610 by Samuel Ortiz <samuel.ortiz@nokia.com> 862306a36Sopenharmony_ci * Graphics DMA and LCD DMA graphics tranformations 962306a36Sopenharmony_ci * by Imre Deak <imre.deak@nokia.com> 1062306a36Sopenharmony_ci * OMAP2/3 support Copyright (C) 2004-2007 Texas Instruments, Inc. 1162306a36Sopenharmony_ci * Some functions based on earlier dma-omap.c Copyright (C) 2001 RidgeRun, Inc. 1262306a36Sopenharmony_ci * 1362306a36Sopenharmony_ci * Copyright (C) 2009 Texas Instruments 1462306a36Sopenharmony_ci * Added OMAP4 support - Santosh Shilimkar <santosh.shilimkar@ti.com> 1562306a36Sopenharmony_ci * 1662306a36Sopenharmony_ci * Copyright (C) 2010 Texas Instruments Incorporated - https://www.ti.com/ 1762306a36Sopenharmony_ci * Converted DMA library into platform driver 1862306a36Sopenharmony_ci * - G, Manjunath Kondaiah <manjugk@ti.com> 1962306a36Sopenharmony_ci */ 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_ci#include <linux/err.h> 2262306a36Sopenharmony_ci#include <linux/io.h> 2362306a36Sopenharmony_ci#include <linux/slab.h> 2462306a36Sopenharmony_ci#include <linux/module.h> 2562306a36Sopenharmony_ci#include <linux/init.h> 2662306a36Sopenharmony_ci#include <linux/device.h> 2762306a36Sopenharmony_ci#include <linux/dma-mapping.h> 2862306a36Sopenharmony_ci#include <linux/dmaengine.h> 2962306a36Sopenharmony_ci#include <linux/of.h> 3062306a36Sopenharmony_ci#include <linux/omap-dma.h> 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ci#include "soc.h" 3362306a36Sopenharmony_ci#include "common.h" 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_cistatic const struct omap_dma_reg reg_map[] = { 3662306a36Sopenharmony_ci [REVISION] = { 0x0000, 0x00, OMAP_DMA_REG_32BIT }, 3762306a36Sopenharmony_ci [GCR] = { 0x0078, 0x00, OMAP_DMA_REG_32BIT }, 3862306a36Sopenharmony_ci [IRQSTATUS_L0] = { 0x0008, 0x00, OMAP_DMA_REG_32BIT }, 3962306a36Sopenharmony_ci [IRQSTATUS_L1] = { 0x000c, 0x00, OMAP_DMA_REG_32BIT }, 4062306a36Sopenharmony_ci [IRQSTATUS_L2] = { 0x0010, 0x00, OMAP_DMA_REG_32BIT }, 4162306a36Sopenharmony_ci [IRQSTATUS_L3] = { 0x0014, 0x00, OMAP_DMA_REG_32BIT }, 4262306a36Sopenharmony_ci [IRQENABLE_L0] = { 0x0018, 0x00, OMAP_DMA_REG_32BIT }, 4362306a36Sopenharmony_ci [IRQENABLE_L1] = { 0x001c, 0x00, OMAP_DMA_REG_32BIT }, 4462306a36Sopenharmony_ci [IRQENABLE_L2] = { 0x0020, 0x00, OMAP_DMA_REG_32BIT }, 4562306a36Sopenharmony_ci [IRQENABLE_L3] = { 0x0024, 0x00, OMAP_DMA_REG_32BIT }, 4662306a36Sopenharmony_ci [SYSSTATUS] = { 0x0028, 0x00, OMAP_DMA_REG_32BIT }, 4762306a36Sopenharmony_ci [OCP_SYSCONFIG] = { 0x002c, 0x00, OMAP_DMA_REG_32BIT }, 4862306a36Sopenharmony_ci [CAPS_0] = { 0x0064, 0x00, OMAP_DMA_REG_32BIT }, 4962306a36Sopenharmony_ci [CAPS_2] = { 0x006c, 0x00, OMAP_DMA_REG_32BIT }, 5062306a36Sopenharmony_ci [CAPS_3] = { 0x0070, 0x00, OMAP_DMA_REG_32BIT }, 5162306a36Sopenharmony_ci [CAPS_4] = { 0x0074, 0x00, OMAP_DMA_REG_32BIT }, 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_ci /* Common register offsets */ 5462306a36Sopenharmony_ci [CCR] = { 0x0080, 0x60, OMAP_DMA_REG_32BIT }, 5562306a36Sopenharmony_ci [CLNK_CTRL] = { 0x0084, 0x60, OMAP_DMA_REG_32BIT }, 5662306a36Sopenharmony_ci [CICR] = { 0x0088, 0x60, OMAP_DMA_REG_32BIT }, 5762306a36Sopenharmony_ci [CSR] = { 0x008c, 0x60, OMAP_DMA_REG_32BIT }, 5862306a36Sopenharmony_ci [CSDP] = { 0x0090, 0x60, OMAP_DMA_REG_32BIT }, 5962306a36Sopenharmony_ci [CEN] = { 0x0094, 0x60, OMAP_DMA_REG_32BIT }, 6062306a36Sopenharmony_ci [CFN] = { 0x0098, 0x60, OMAP_DMA_REG_32BIT }, 6162306a36Sopenharmony_ci [CSEI] = { 0x00a4, 0x60, OMAP_DMA_REG_32BIT }, 6262306a36Sopenharmony_ci [CSFI] = { 0x00a8, 0x60, OMAP_DMA_REG_32BIT }, 6362306a36Sopenharmony_ci [CDEI] = { 0x00ac, 0x60, OMAP_DMA_REG_32BIT }, 6462306a36Sopenharmony_ci [CDFI] = { 0x00b0, 0x60, OMAP_DMA_REG_32BIT }, 6562306a36Sopenharmony_ci [CSAC] = { 0x00b4, 0x60, OMAP_DMA_REG_32BIT }, 6662306a36Sopenharmony_ci [CDAC] = { 0x00b8, 0x60, OMAP_DMA_REG_32BIT }, 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_ci /* Channel specific register offsets */ 6962306a36Sopenharmony_ci [CSSA] = { 0x009c, 0x60, OMAP_DMA_REG_32BIT }, 7062306a36Sopenharmony_ci [CDSA] = { 0x00a0, 0x60, OMAP_DMA_REG_32BIT }, 7162306a36Sopenharmony_ci [CCEN] = { 0x00bc, 0x60, OMAP_DMA_REG_32BIT }, 7262306a36Sopenharmony_ci [CCFN] = { 0x00c0, 0x60, OMAP_DMA_REG_32BIT }, 7362306a36Sopenharmony_ci [COLOR] = { 0x00c4, 0x60, OMAP_DMA_REG_32BIT }, 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci /* OMAP4 specific registers */ 7662306a36Sopenharmony_ci [CDP] = { 0x00d0, 0x60, OMAP_DMA_REG_32BIT }, 7762306a36Sopenharmony_ci [CNDP] = { 0x00d4, 0x60, OMAP_DMA_REG_32BIT }, 7862306a36Sopenharmony_ci [CCDN] = { 0x00d8, 0x60, OMAP_DMA_REG_32BIT }, 7962306a36Sopenharmony_ci}; 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_cistatic unsigned configure_dma_errata(void) 8262306a36Sopenharmony_ci{ 8362306a36Sopenharmony_ci unsigned errata = 0; 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_ci /* 8662306a36Sopenharmony_ci * Errata applicable for OMAP2430ES1.0 and all omap2420 8762306a36Sopenharmony_ci * 8862306a36Sopenharmony_ci * I. 8962306a36Sopenharmony_ci * Erratum ID: Not Available 9062306a36Sopenharmony_ci * Inter Frame DMA buffering issue DMA will wrongly 9162306a36Sopenharmony_ci * buffer elements if packing and bursting is enabled. This might 9262306a36Sopenharmony_ci * result in data gets stalled in FIFO at the end of the block. 9362306a36Sopenharmony_ci * Workaround: DMA channels must have BUFFERING_DISABLED bit set to 9462306a36Sopenharmony_ci * guarantee no data will stay in the DMA FIFO in case inter frame 9562306a36Sopenharmony_ci * buffering occurs 9662306a36Sopenharmony_ci * 9762306a36Sopenharmony_ci * II. 9862306a36Sopenharmony_ci * Erratum ID: Not Available 9962306a36Sopenharmony_ci * DMA may hang when several channels are used in parallel 10062306a36Sopenharmony_ci * In the following configuration, DMA channel hanging can occur: 10162306a36Sopenharmony_ci * a. Channel i, hardware synchronized, is enabled 10262306a36Sopenharmony_ci * b. Another channel (Channel x), software synchronized, is enabled. 10362306a36Sopenharmony_ci * c. Channel i is disabled before end of transfer 10462306a36Sopenharmony_ci * d. Channel i is reenabled. 10562306a36Sopenharmony_ci * e. Steps 1 to 4 are repeated a certain number of times. 10662306a36Sopenharmony_ci * f. A third channel (Channel y), software synchronized, is enabled. 10762306a36Sopenharmony_ci * Channel x and Channel y may hang immediately after step 'f'. 10862306a36Sopenharmony_ci * Workaround: 10962306a36Sopenharmony_ci * For any channel used - make sure NextLCH_ID is set to the value j. 11062306a36Sopenharmony_ci */ 11162306a36Sopenharmony_ci if (cpu_is_omap2420() || (cpu_is_omap2430() && 11262306a36Sopenharmony_ci (omap_type() == OMAP2430_REV_ES1_0))) { 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ci SET_DMA_ERRATA(DMA_ERRATA_IFRAME_BUFFERING); 11562306a36Sopenharmony_ci SET_DMA_ERRATA(DMA_ERRATA_PARALLEL_CHANNELS); 11662306a36Sopenharmony_ci } 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_ci /* 11962306a36Sopenharmony_ci * Erratum ID: i378: OMAP2+: sDMA Channel is not disabled 12062306a36Sopenharmony_ci * after a transaction error. 12162306a36Sopenharmony_ci * Workaround: SW should explicitely disable the channel. 12262306a36Sopenharmony_ci */ 12362306a36Sopenharmony_ci if (cpu_class_is_omap2()) 12462306a36Sopenharmony_ci SET_DMA_ERRATA(DMA_ERRATA_i378); 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_ci /* 12762306a36Sopenharmony_ci * Erratum ID: i541: sDMA FIFO draining does not finish 12862306a36Sopenharmony_ci * If sDMA channel is disabled on the fly, sDMA enters standby even 12962306a36Sopenharmony_ci * through FIFO Drain is still in progress 13062306a36Sopenharmony_ci * Workaround: Put sDMA in NoStandby more before a logical channel is 13162306a36Sopenharmony_ci * disabled, then put it back to SmartStandby right after the channel 13262306a36Sopenharmony_ci * finishes FIFO draining. 13362306a36Sopenharmony_ci */ 13462306a36Sopenharmony_ci if (cpu_is_omap34xx()) 13562306a36Sopenharmony_ci SET_DMA_ERRATA(DMA_ERRATA_i541); 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_ci /* 13862306a36Sopenharmony_ci * Erratum ID: i88 : Special programming model needed to disable DMA 13962306a36Sopenharmony_ci * before end of block. 14062306a36Sopenharmony_ci * Workaround: software must ensure that the DMA is configured in No 14162306a36Sopenharmony_ci * Standby mode(DMAx_OCP_SYSCONFIG.MIDLEMODE = "01") 14262306a36Sopenharmony_ci */ 14362306a36Sopenharmony_ci if (omap_type() == OMAP3430_REV_ES1_0) 14462306a36Sopenharmony_ci SET_DMA_ERRATA(DMA_ERRATA_i88); 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_ci /* 14762306a36Sopenharmony_ci * Erratum 3.2/3.3: sometimes 0 is returned if CSAC/CDAC is 14862306a36Sopenharmony_ci * read before the DMA controller finished disabling the channel. 14962306a36Sopenharmony_ci */ 15062306a36Sopenharmony_ci SET_DMA_ERRATA(DMA_ERRATA_3_3); 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_ci /* 15362306a36Sopenharmony_ci * Erratum ID: Not Available 15462306a36Sopenharmony_ci * A bug in ROM code leaves IRQ status for channels 0 and 1 uncleared 15562306a36Sopenharmony_ci * after secure sram context save and restore. 15662306a36Sopenharmony_ci * Work around: Hence we need to manually clear those IRQs to avoid 15762306a36Sopenharmony_ci * spurious interrupts. This affects only secure devices. 15862306a36Sopenharmony_ci */ 15962306a36Sopenharmony_ci if (cpu_is_omap34xx() && (omap_type() != OMAP2_DEVICE_TYPE_GP)) 16062306a36Sopenharmony_ci SET_DMA_ERRATA(DMA_ROMCODE_BUG); 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_ci return errata; 16362306a36Sopenharmony_ci} 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_cistatic const struct dma_slave_map omap24xx_sdma_dt_map[] = { 16662306a36Sopenharmony_ci /* external DMA requests when tusb6010 is used */ 16762306a36Sopenharmony_ci { "musb-hdrc.1.auto", "dmareq0", SDMA_FILTER_PARAM(2) }, 16862306a36Sopenharmony_ci { "musb-hdrc.1.auto", "dmareq1", SDMA_FILTER_PARAM(3) }, 16962306a36Sopenharmony_ci { "musb-hdrc.1.auto", "dmareq2", SDMA_FILTER_PARAM(14) }, /* OMAP2420 only */ 17062306a36Sopenharmony_ci { "musb-hdrc.1.auto", "dmareq3", SDMA_FILTER_PARAM(15) }, /* OMAP2420 only */ 17162306a36Sopenharmony_ci { "musb-hdrc.1.auto", "dmareq4", SDMA_FILTER_PARAM(16) }, /* OMAP2420 only */ 17262306a36Sopenharmony_ci { "musb-hdrc.1.auto", "dmareq5", SDMA_FILTER_PARAM(64) }, /* OMAP2420 only */ 17362306a36Sopenharmony_ci}; 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_cistatic struct omap_dma_dev_attr dma_attr = { 17662306a36Sopenharmony_ci .dev_caps = RESERVE_CHANNEL | DMA_LINKED_LCH | GLOBAL_PRIORITY | 17762306a36Sopenharmony_ci IS_CSSA_32 | IS_CDSA_32, 17862306a36Sopenharmony_ci .lch_count = 32, 17962306a36Sopenharmony_ci}; 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_cistruct omap_system_dma_plat_info dma_plat_info = { 18262306a36Sopenharmony_ci .reg_map = reg_map, 18362306a36Sopenharmony_ci .channel_stride = 0x60, 18462306a36Sopenharmony_ci .dma_attr = &dma_attr, 18562306a36Sopenharmony_ci}; 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_ci/* One time initializations */ 18862306a36Sopenharmony_cistatic int __init omap2_system_dma_init(void) 18962306a36Sopenharmony_ci{ 19062306a36Sopenharmony_ci dma_plat_info.errata = configure_dma_errata(); 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ci if (soc_is_omap24xx()) { 19362306a36Sopenharmony_ci /* DMA slave map for drivers not yet converted to DT */ 19462306a36Sopenharmony_ci dma_plat_info.slave_map = omap24xx_sdma_dt_map; 19562306a36Sopenharmony_ci dma_plat_info.slavecnt = ARRAY_SIZE(omap24xx_sdma_dt_map); 19662306a36Sopenharmony_ci } 19762306a36Sopenharmony_ci 19862306a36Sopenharmony_ci if (!soc_is_omap242x()) 19962306a36Sopenharmony_ci dma_attr.dev_caps |= IS_RW_PRIORITY; 20062306a36Sopenharmony_ci 20162306a36Sopenharmony_ci if (soc_is_omap34xx() && (omap_type() != OMAP2_DEVICE_TYPE_GP)) 20262306a36Sopenharmony_ci dma_attr.dev_caps |= HS_CHANNELS_RESERVED; 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_ci return 0; 20562306a36Sopenharmony_ci} 20662306a36Sopenharmony_ciomap_arch_initcall(omap2_system_dma_init); 207