2012-05-09 16:59:01 +02:00
/*
* Copyright 2008 - 2010 Freescale Semiconductor , Inc . All Rights Reserved .
*
* The code contained herein is licensed under the GNU General Public
* License . You may obtain a copy of the GNU General Public License
* Version 2 or later at the following locations :
*
* http : //www.opensource.org/licenses/gpl-license.html
* http : //www.gnu.org/copyleft/gpl.html
*/
# include <linux/export.h>
# include <linux/types.h>
# include <linux/init.h>
# include <linux/io.h>
# include <linux/errno.h>
# include <linux/spinlock.h>
# include <linux/delay.h>
# include <linux/clk.h>
# include <video/imx-ipu-v3.h>
# include "ipu-prv.h"
2014-06-25 18:05:34 -07:00
struct ipu_smfc {
struct ipu_smfc_priv * priv ;
int chno ;
bool inuse ;
} ;
2012-05-09 16:59:01 +02:00
struct ipu_smfc_priv {
void __iomem * base ;
spinlock_t lock ;
2014-06-25 18:05:34 -07:00
struct ipu_soc * ipu ;
struct ipu_smfc channel [ 4 ] ;
int use_count ;
2012-05-09 16:59:01 +02:00
} ;
/*SMFC Registers */
# define SMFC_MAP 0x0000
# define SMFC_WMC 0x0004
# define SMFC_BS 0x0008
2014-06-25 18:05:34 -07:00
int ipu_smfc_set_burstsize ( struct ipu_smfc * smfc , int burstsize )
2012-05-09 16:59:01 +02:00
{
2014-06-25 18:05:34 -07:00
struct ipu_smfc_priv * priv = smfc - > priv ;
2012-05-09 16:59:01 +02:00
unsigned long flags ;
u32 val , shift ;
2014-06-25 18:05:34 -07:00
spin_lock_irqsave ( & priv - > lock , flags ) ;
2012-05-09 16:59:01 +02:00
2014-06-25 18:05:34 -07:00
shift = smfc - > chno * 4 ;
val = readl ( priv - > base + SMFC_BS ) ;
2012-05-09 16:59:01 +02:00
val & = ~ ( 0xf < < shift ) ;
val | = burstsize < < shift ;
2014-06-25 18:05:34 -07:00
writel ( val , priv - > base + SMFC_BS ) ;
2012-05-09 16:59:01 +02:00
2014-06-25 18:05:34 -07:00
spin_unlock_irqrestore ( & priv - > lock , flags ) ;
2012-05-09 16:59:01 +02:00
return 0 ;
}
EXPORT_SYMBOL_GPL ( ipu_smfc_set_burstsize ) ;
2014-06-25 18:05:34 -07:00
int ipu_smfc_map_channel ( struct ipu_smfc * smfc , int csi_id , int mipi_id )
2012-05-09 16:59:01 +02:00
{
2014-06-25 18:05:34 -07:00
struct ipu_smfc_priv * priv = smfc - > priv ;
2012-05-09 16:59:01 +02:00
unsigned long flags ;
u32 val , shift ;
2014-06-25 18:05:34 -07:00
spin_lock_irqsave ( & priv - > lock , flags ) ;
2012-05-09 16:59:01 +02:00
2014-06-25 18:05:34 -07:00
shift = smfc - > chno * 3 ;
val = readl ( priv - > base + SMFC_MAP ) ;
2012-05-09 16:59:01 +02:00
val & = ~ ( 0x7 < < shift ) ;
val | = ( ( csi_id < < 2 ) | mipi_id ) < < shift ;
2014-06-25 18:05:34 -07:00
writel ( val , priv - > base + SMFC_MAP ) ;
2012-05-09 16:59:01 +02:00
2014-06-25 18:05:34 -07:00
spin_unlock_irqrestore ( & priv - > lock , flags ) ;
2012-05-09 16:59:01 +02:00
return 0 ;
}
EXPORT_SYMBOL_GPL ( ipu_smfc_map_channel ) ;
2014-06-25 18:05:35 -07:00
int ipu_smfc_set_watermark ( struct ipu_smfc * smfc , u32 set_level , u32 clr_level )
{
struct ipu_smfc_priv * priv = smfc - > priv ;
unsigned long flags ;
u32 val , shift ;
spin_lock_irqsave ( & priv - > lock , flags ) ;
shift = smfc - > chno * 6 + ( smfc - > chno > 1 ? 4 : 0 ) ;
val = readl ( priv - > base + SMFC_WMC ) ;
val & = ~ ( 0x3f < < shift ) ;
val | = ( ( clr_level < < 3 ) | set_level ) < < shift ;
writel ( val , priv - > base + SMFC_WMC ) ;
spin_unlock_irqrestore ( & priv - > lock , flags ) ;
return 0 ;
}
EXPORT_SYMBOL_GPL ( ipu_smfc_set_watermark ) ;
2014-06-25 18:05:34 -07:00
int ipu_smfc_enable ( struct ipu_smfc * smfc )
2014-06-25 18:05:33 -07:00
{
2014-06-25 18:05:34 -07:00
struct ipu_smfc_priv * priv = smfc - > priv ;
unsigned long flags ;
spin_lock_irqsave ( & priv - > lock , flags ) ;
if ( ! priv - > use_count )
ipu_module_enable ( priv - > ipu , IPU_CONF_SMFC_EN ) ;
priv - > use_count + + ;
spin_unlock_irqrestore ( & priv - > lock , flags ) ;
return 0 ;
2014-06-25 18:05:33 -07:00
}
EXPORT_SYMBOL_GPL ( ipu_smfc_enable ) ;
2014-06-25 18:05:34 -07:00
int ipu_smfc_disable ( struct ipu_smfc * smfc )
2014-06-25 18:05:33 -07:00
{
2014-06-25 18:05:34 -07:00
struct ipu_smfc_priv * priv = smfc - > priv ;
unsigned long flags ;
spin_lock_irqsave ( & priv - > lock , flags ) ;
priv - > use_count - - ;
if ( ! priv - > use_count )
ipu_module_disable ( priv - > ipu , IPU_CONF_SMFC_EN ) ;
if ( priv - > use_count < 0 )
priv - > use_count = 0 ;
spin_unlock_irqrestore ( & priv - > lock , flags ) ;
return 0 ;
2014-06-25 18:05:33 -07:00
}
EXPORT_SYMBOL_GPL ( ipu_smfc_disable ) ;
2014-06-25 18:05:34 -07:00
struct ipu_smfc * ipu_smfc_get ( struct ipu_soc * ipu , unsigned int chno )
{
struct ipu_smfc_priv * priv = ipu - > smfc_priv ;
struct ipu_smfc * smfc , * ret ;
unsigned long flags ;
if ( chno > = 4 )
return ERR_PTR ( - EINVAL ) ;
smfc = & priv - > channel [ chno ] ;
ret = smfc ;
spin_lock_irqsave ( & priv - > lock , flags ) ;
if ( smfc - > inuse ) {
ret = ERR_PTR ( - EBUSY ) ;
goto unlock ;
}
smfc - > inuse = true ;
unlock :
spin_unlock_irqrestore ( & priv - > lock , flags ) ;
return ret ;
}
EXPORT_SYMBOL_GPL ( ipu_smfc_get ) ;
void ipu_smfc_put ( struct ipu_smfc * smfc )
{
struct ipu_smfc_priv * priv = smfc - > priv ;
unsigned long flags ;
spin_lock_irqsave ( & priv - > lock , flags ) ;
smfc - > inuse = false ;
spin_unlock_irqrestore ( & priv - > lock , flags ) ;
}
EXPORT_SYMBOL_GPL ( ipu_smfc_put ) ;
2012-05-09 16:59:01 +02:00
int ipu_smfc_init ( struct ipu_soc * ipu , struct device * dev ,
unsigned long base )
{
2014-06-25 18:05:34 -07:00
struct ipu_smfc_priv * priv ;
int i ;
2012-05-09 16:59:01 +02:00
2014-06-25 18:05:34 -07:00
priv = devm_kzalloc ( dev , sizeof ( * priv ) , GFP_KERNEL ) ;
if ( ! priv )
2012-05-09 16:59:01 +02:00
return - ENOMEM ;
2014-06-25 18:05:34 -07:00
ipu - > smfc_priv = priv ;
spin_lock_init ( & priv - > lock ) ;
priv - > ipu = ipu ;
2012-05-09 16:59:01 +02:00
2014-06-25 18:05:34 -07:00
priv - > base = devm_ioremap ( dev , base , PAGE_SIZE ) ;
if ( ! priv - > base )
2012-05-09 16:59:01 +02:00
return - ENOMEM ;
2014-06-25 18:05:34 -07:00
for ( i = 0 ; i < 4 ; i + + ) {
priv - > channel [ i ] . priv = priv ;
priv - > channel [ i ] . chno = i ;
}
pr_debug ( " %s: ioremap 0x%08lx -> %p \n " , __func__ , base , priv - > base ) ;
2012-05-09 16:59:01 +02:00
return 0 ;
}
void ipu_smfc_exit ( struct ipu_soc * ipu )
{
}