2010-12-21 05:27:19 +03:00
/*
* OMAP2 + DMA driver
*
* Copyright ( C ) 2003 - 2008 Nokia Corporation
* Author : Juha Yrjölä < juha . yrjola @ nokia . com >
* DMA channel linking for 1610 by Samuel Ortiz < samuel . ortiz @ nokia . com >
* Graphics DMA and LCD DMA graphics tranformations
* by Imre Deak < imre . deak @ nokia . com >
* OMAP2 / 3 support Copyright ( C ) 2004 - 2007 Texas Instruments , Inc .
* Some functions based on earlier dma - omap . c Copyright ( C ) 2001 RidgeRun , Inc .
*
* Copyright ( C ) 2009 Texas Instruments
* Added OMAP4 support - Santosh Shilimkar < santosh . shilimkar @ ti . com >
*
* Copyright ( C ) 2010 Texas Instruments Incorporated - http : //www.ti.com/
* Converted DMA library into platform driver
* - G , Manjunath Kondaiah < manjugk @ ti . com >
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation .
*/
# include <linux/err.h>
# include <linux/io.h>
# include <linux/slab.h>
# include <linux/module.h>
# include <linux/init.h>
# include <linux/device.h>
2013-01-11 23:24:19 +04:00
# include <linux/dma-mapping.h>
2013-02-26 22:27:24 +04:00
# include <linux/of.h>
2012-11-30 20:41:50 +04:00
# include <linux/omap-dma.h>
2010-12-21 05:27:19 +03:00
2012-10-06 00:25:59 +04:00
# include "soc.h"
2012-10-03 04:41:35 +04:00
# include "omap_hwmod.h"
2012-10-03 04:25:48 +04:00
# include "omap_device.h"
2010-12-21 05:27:19 +03:00
# define OMAP2_DMA_STRIDE 0x60
static u32 errata ;
static struct omap_dma_dev_attr * d ;
2013-11-08 18:53:35 +04:00
static enum omap_reg_offsets dma_common_ch_end ;
2010-12-21 05:27:19 +03:00
static u16 reg_map [ ] = {
[ REVISION ] = 0x00 ,
[ GCR ] = 0x78 ,
[ IRQSTATUS_L0 ] = 0x08 ,
[ IRQSTATUS_L1 ] = 0x0c ,
[ IRQSTATUS_L2 ] = 0x10 ,
[ IRQSTATUS_L3 ] = 0x14 ,
[ IRQENABLE_L0 ] = 0x18 ,
[ IRQENABLE_L1 ] = 0x1c ,
[ IRQENABLE_L2 ] = 0x20 ,
[ IRQENABLE_L3 ] = 0x24 ,
[ SYSSTATUS ] = 0x28 ,
[ OCP_SYSCONFIG ] = 0x2c ,
[ CAPS_0 ] = 0x64 ,
[ CAPS_2 ] = 0x6c ,
[ CAPS_3 ] = 0x70 ,
[ CAPS_4 ] = 0x74 ,
/* Common register offsets */
[ CCR ] = 0x80 ,
[ CLNK_CTRL ] = 0x84 ,
[ CICR ] = 0x88 ,
[ CSR ] = 0x8c ,
[ CSDP ] = 0x90 ,
[ CEN ] = 0x94 ,
[ CFN ] = 0x98 ,
[ CSEI ] = 0xa4 ,
[ CSFI ] = 0xa8 ,
[ CDEI ] = 0xac ,
[ CDFI ] = 0xb0 ,
[ CSAC ] = 0xb4 ,
[ CDAC ] = 0xb8 ,
/* Channel specific register offsets */
[ CSSA ] = 0x9c ,
[ CDSA ] = 0xa0 ,
[ CCEN ] = 0xbc ,
[ CCFN ] = 0xc0 ,
[ COLOR ] = 0xc4 ,
/* OMAP4 specific registers */
[ CDP ] = 0xd0 ,
[ CNDP ] = 0xd4 ,
[ CCDN ] = 0xd8 ,
} ;
static void __iomem * dma_base ;
static inline void dma_write ( u32 val , int reg , int lch )
{
u8 stride ;
u32 offset ;
2013-11-08 18:53:35 +04:00
stride = ( reg > = CSDP ) ? OMAP2_DMA_STRIDE : 0 ;
2010-12-21 05:27:19 +03:00
offset = reg_map [ reg ] + ( stride * lch ) ;
__raw_writel ( val , dma_base + offset ) ;
}
static inline u32 dma_read ( int reg , int lch )
{
u8 stride ;
u32 offset , val ;
2013-11-08 18:53:35 +04:00
stride = ( reg > = CSDP ) ? OMAP2_DMA_STRIDE : 0 ;
2010-12-21 05:27:19 +03:00
offset = reg_map [ reg ] + ( stride * lch ) ;
val = __raw_readl ( dma_base + offset ) ;
return val ;
}
static void omap2_clear_dma ( int lch )
{
2013-11-08 18:53:35 +04:00
int i ;
2010-12-21 05:27:19 +03:00
2013-11-08 18:53:35 +04:00
for ( i = CSDP ; i < = dma_common_ch_end ; i + = 1 )
2010-12-21 05:27:19 +03:00
dma_write ( 0 , i , lch ) ;
}
static void omap2_show_dma_caps ( void )
{
u8 revision = dma_read ( REVISION , 0 ) & 0xff ;
printk ( KERN_INFO " OMAP DMA hardware revision %d.%d \n " ,
revision > > 4 , revision & 0xf ) ;
return ;
}
static u32 configure_dma_errata ( void )
{
/*
* Errata applicable for OMAP2430ES1 .0 and all omap2420
*
* I .
* Erratum ID : Not Available
* Inter Frame DMA buffering issue DMA will wrongly
* buffer elements if packing and bursting is enabled . This might
* result in data gets stalled in FIFO at the end of the block .
* Workaround : DMA channels must have BUFFERING_DISABLED bit set to
* guarantee no data will stay in the DMA FIFO in case inter frame
* buffering occurs
*
* II .
* Erratum ID : Not Available
* DMA may hang when several channels are used in parallel
* In the following configuration , DMA channel hanging can occur :
* a . Channel i , hardware synchronized , is enabled
* b . Another channel ( Channel x ) , software synchronized , is enabled .
* c . Channel i is disabled before end of transfer
* d . Channel i is reenabled .
* e . Steps 1 to 4 are repeated a certain number of times .
* f . A third channel ( Channel y ) , software synchronized , is enabled .
* Channel x and Channel y may hang immediately after step ' f ' .
* Workaround :
* For any channel used - make sure NextLCH_ID is set to the value j .
*/
if ( cpu_is_omap2420 ( ) | | ( cpu_is_omap2430 ( ) & &
( omap_type ( ) = = OMAP2430_REV_ES1_0 ) ) ) {
SET_DMA_ERRATA ( DMA_ERRATA_IFRAME_BUFFERING ) ;
SET_DMA_ERRATA ( DMA_ERRATA_PARALLEL_CHANNELS ) ;
}
/*
* Erratum ID : i378 : OMAP2 + : sDMA Channel is not disabled
* after a transaction error .
* Workaround : SW should explicitely disable the channel .
*/
if ( cpu_class_is_omap2 ( ) )
SET_DMA_ERRATA ( DMA_ERRATA_i378 ) ;
/*
* Erratum ID : i541 : sDMA FIFO draining does not finish
* If sDMA channel is disabled on the fly , sDMA enters standby even
* through FIFO Drain is still in progress
* Workaround : Put sDMA in NoStandby more before a logical channel is
* disabled , then put it back to SmartStandby right after the channel
* finishes FIFO draining .
*/
if ( cpu_is_omap34xx ( ) )
SET_DMA_ERRATA ( DMA_ERRATA_i541 ) ;
/*
* Erratum ID : i88 : Special programming model needed to disable DMA
* before end of block .
* Workaround : software must ensure that the DMA is configured in No
* Standby mode ( DMAx_OCP_SYSCONFIG . MIDLEMODE = " 01 " )
*/
if ( omap_type ( ) = = OMAP3430_REV_ES1_0 )
SET_DMA_ERRATA ( DMA_ERRATA_i88 ) ;
/*
* Erratum 3.2 / 3.3 : sometimes 0 is returned if CSAC / CDAC is
* read before the DMA controller finished disabling the channel .
*/
SET_DMA_ERRATA ( DMA_ERRATA_3_3 ) ;
/*
* Erratum ID : Not Available
* A bug in ROM code leaves IRQ status for channels 0 and 1 uncleared
* after secure sram context save and restore .
* Work around : Hence we need to manually clear those IRQs to avoid
* spurious interrupts . This affects only secure devices .
*/
if ( cpu_is_omap34xx ( ) & & ( omap_type ( ) ! = OMAP2_DEVICE_TYPE_GP ) )
SET_DMA_ERRATA ( DMA_ROMCODE_BUG ) ;
return errata ;
}
2010-12-21 05:27:19 +03:00
/* One time initializations */
static int __init omap2_system_dma_init_dev ( struct omap_hwmod * oh , void * unused )
{
2011-07-22 00:48:45 +04:00
struct platform_device * pdev ;
2010-12-21 05:27:19 +03:00
struct omap_system_dma_plat_info * p ;
2010-12-21 05:27:19 +03:00
struct resource * mem ;
2010-12-21 05:27:19 +03:00
char * name = " omap_dma_system " ;
p = kzalloc ( sizeof ( struct omap_system_dma_plat_info ) , GFP_KERNEL ) ;
if ( ! p ) {
pr_err ( " %s: Unable to allocate pdata for %s:%s \n " ,
__func__ , name , oh - > name ) ;
return - ENOMEM ;
}
2010-12-21 05:27:19 +03:00
p - > dma_attr = ( struct omap_dma_dev_attr * ) oh - > dev_attr ;
p - > show_dma_caps = omap2_show_dma_caps ;
p - > clear_dma = omap2_clear_dma ;
p - > dma_write = dma_write ;
p - > dma_read = dma_read ;
p - > clear_lch_regs = NULL ;
p - > errata = configure_dma_errata ( ) ;
2013-01-26 11:48:53 +04:00
pdev = omap_device_build ( name , 0 , oh , p , sizeof ( * p ) ) ;
2010-12-21 05:27:19 +03:00
kfree ( p ) ;
2011-07-22 00:48:45 +04:00
if ( IS_ERR ( pdev ) ) {
2011-03-31 05:57:33 +04:00
pr_err ( " %s: Can't build omap_device for %s:%s. \n " ,
2010-12-21 05:27:19 +03:00
__func__ , name , oh - > name ) ;
2011-07-22 00:48:45 +04:00
return PTR_ERR ( pdev ) ;
2010-12-21 05:27:19 +03:00
}
2011-07-22 00:48:45 +04:00
mem = platform_get_resource ( pdev , IORESOURCE_MEM , 0 ) ;
2010-12-21 05:27:19 +03:00
if ( ! mem ) {
2011-07-22 00:48:45 +04:00
dev_err ( & pdev - > dev , " %s: no mem resource \n " , __func__ ) ;
2010-12-21 05:27:19 +03:00
return - EINVAL ;
}
dma_base = ioremap ( mem - > start , resource_size ( mem ) ) ;
if ( ! dma_base ) {
2011-07-22 00:48:45 +04:00
dev_err ( & pdev - > dev , " %s: ioremap fail \n " , __func__ ) ;
2010-12-21 05:27:19 +03:00
return - ENOMEM ;
}
d = oh - > dev_attr ;
d - > chan = kzalloc ( sizeof ( struct omap_dma_lch ) *
( d - > lch_count ) , GFP_KERNEL ) ;
if ( ! d - > chan ) {
2011-07-22 00:48:45 +04:00
dev_err ( & pdev - > dev , " %s: kzalloc fail \n " , __func__ ) ;
2010-12-21 05:27:19 +03:00
return - ENOMEM ;
}
2012-05-07 12:32:25 +04:00
2012-10-30 22:03:22 +04:00
if ( cpu_is_omap34xx ( ) & & ( omap_type ( ) ! = OMAP2_DEVICE_TYPE_GP ) )
d - > dev_caps | = HS_CHANNELS_RESERVED ;
2012-05-07 12:32:25 +04:00
/* Check the capabilities register for descriptor loading feature */
if ( dma_read ( CAPS_0 , 0 ) & DMA_HAS_DESCRIPTOR_CAPS )
dma_common_ch_end = CCDN ;
else
dma_common_ch_end = CCFN ;
2010-12-21 05:27:19 +03:00
return 0 ;
}
2013-01-11 23:24:19 +04:00
static const struct platform_device_info omap_dma_dev_info = {
. name = " omap-dma-engine " ,
. id = - 1 ,
. dma_mask = DMA_BIT_MASK ( 32 ) ,
} ;
2010-12-21 05:27:19 +03:00
static int __init omap2_system_dma_init ( void )
{
2013-01-11 23:24:19 +04:00
struct platform_device * pdev ;
int res ;
res = omap_hwmod_for_each_by_class ( " dma " ,
2010-12-21 05:27:19 +03:00
omap2_system_dma_init_dev , NULL ) ;
2013-01-11 23:24:19 +04:00
if ( res )
return res ;
2013-02-26 22:27:24 +04:00
if ( of_have_populated_dt ( ) )
return res ;
2013-01-11 23:24:19 +04:00
pdev = platform_device_register_full ( & omap_dma_dev_info ) ;
if ( IS_ERR ( pdev ) )
return PTR_ERR ( pdev ) ;
return res ;
2010-12-21 05:27:19 +03:00
}
2013-01-11 23:24:18 +04:00
omap_arch_initcall ( omap2_system_dma_init ) ;