2012-09-21 10:07:49 +02:00
/*
* Copyright ( c ) 2010 Sascha Hauer < s . hauer @ pengutronix . de >
* Copyright ( C ) 2005 - 2009 Freescale Semiconductor , Inc .
*
* This program is free software ; you can redistribute it and / or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation ; either version 2 of the License , or ( at your
* option ) any later version .
*
* This program is distributed in the hope that it will be useful , but
* WITHOUT ANY WARRANTY ; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE . See the GNU General Public License
* for more details .
*/
# include <linux/export.h>
# include <linux/types.h>
# include <linux/errno.h>
# include <linux/io.h>
2013-09-30 16:13:39 +02:00
# include <video/imx-ipu-v3.h>
2012-09-21 10:07:49 +02:00
# include "ipu-prv.h"
# define DMFC_RD_CHAN 0x0000
# define DMFC_WR_CHAN 0x0004
# define DMFC_WR_CHAN_DEF 0x0008
# define DMFC_DP_CHAN 0x000c
# define DMFC_DP_CHAN_DEF 0x0010
# define DMFC_GENERAL1 0x0014
# define DMFC_GENERAL2 0x0018
# define DMFC_IC_CTRL 0x001c
2014-04-14 23:53:18 +02:00
# define DMFC_WR_CHAN_ALT 0x0020
# define DMFC_WR_CHAN_DEF_ALT 0x0024
# define DMFC_DP_CHAN_ALT 0x0028
# define DMFC_DP_CHAN_DEF_ALT 0x002c
# define DMFC_GENERAL1_ALT 0x0030
# define DMFC_STAT 0x0034
2012-09-21 10:07:49 +02:00
# define DMFC_WR_CHAN_1_28 0
# define DMFC_WR_CHAN_2_41 8
# define DMFC_WR_CHAN_1C_42 16
# define DMFC_WR_CHAN_2C_43 24
# define DMFC_DP_CHAN_5B_23 0
# define DMFC_DP_CHAN_5F_27 8
# define DMFC_DP_CHAN_6B_24 16
# define DMFC_DP_CHAN_6F_29 24
struct dmfc_channel_data {
int ipu_channel ;
unsigned long channel_reg ;
unsigned long shift ;
unsigned eot_shift ;
unsigned max_fifo_lines ;
} ;
static const struct dmfc_channel_data dmfcdata [ ] = {
{
2013-06-21 10:57:21 +02:00
. ipu_channel = IPUV3_CHANNEL_MEM_BG_SYNC ,
2012-09-21 10:07:49 +02:00
. channel_reg = DMFC_DP_CHAN ,
. shift = DMFC_DP_CHAN_5B_23 ,
. eot_shift = 20 ,
. max_fifo_lines = 3 ,
} , {
. ipu_channel = 24 ,
. channel_reg = DMFC_DP_CHAN ,
. shift = DMFC_DP_CHAN_6B_24 ,
. eot_shift = 22 ,
. max_fifo_lines = 1 ,
} , {
2013-06-21 10:57:21 +02:00
. ipu_channel = IPUV3_CHANNEL_MEM_FG_SYNC ,
2012-09-21 10:07:49 +02:00
. channel_reg = DMFC_DP_CHAN ,
. shift = DMFC_DP_CHAN_5F_27 ,
. eot_shift = 21 ,
. max_fifo_lines = 2 ,
} , {
2013-06-21 10:57:21 +02:00
. ipu_channel = IPUV3_CHANNEL_MEM_DC_SYNC ,
2012-09-21 10:07:49 +02:00
. channel_reg = DMFC_WR_CHAN ,
. shift = DMFC_WR_CHAN_1_28 ,
. eot_shift = 16 ,
. max_fifo_lines = 2 ,
} , {
. ipu_channel = 29 ,
. channel_reg = DMFC_DP_CHAN ,
. shift = DMFC_DP_CHAN_6F_29 ,
. eot_shift = 23 ,
. max_fifo_lines = 1 ,
} ,
} ;
# define DMFC_NUM_CHANNELS ARRAY_SIZE(dmfcdata)
struct ipu_dmfc_priv ;
struct dmfc_channel {
unsigned slots ;
struct ipu_soc * ipu ;
struct ipu_dmfc_priv * priv ;
const struct dmfc_channel_data * data ;
} ;
struct ipu_dmfc_priv {
struct ipu_soc * ipu ;
struct device * dev ;
struct dmfc_channel channels [ DMFC_NUM_CHANNELS ] ;
struct mutex mutex ;
void __iomem * base ;
int use_count ;
} ;
int ipu_dmfc_enable_channel ( struct dmfc_channel * dmfc )
{
struct ipu_dmfc_priv * priv = dmfc - > priv ;
mutex_lock ( & priv - > mutex ) ;
if ( ! priv - > use_count )
ipu_module_enable ( priv - > ipu , IPU_CONF_DMFC_EN ) ;
priv - > use_count + + ;
mutex_unlock ( & priv - > mutex ) ;
return 0 ;
}
EXPORT_SYMBOL_GPL ( ipu_dmfc_enable_channel ) ;
void ipu_dmfc_disable_channel ( struct dmfc_channel * dmfc )
{
struct ipu_dmfc_priv * priv = dmfc - > priv ;
mutex_lock ( & priv - > mutex ) ;
priv - > use_count - - ;
2016-08-26 15:30:41 +08:00
if ( ! priv - > use_count )
2012-09-21 10:07:49 +02:00
ipu_module_disable ( priv - > ipu , IPU_CONF_DMFC_EN ) ;
if ( priv - > use_count < 0 )
priv - > use_count = 0 ;
mutex_unlock ( & priv - > mutex ) ;
}
EXPORT_SYMBOL_GPL ( ipu_dmfc_disable_channel ) ;
2016-03-14 16:10:10 +08:00
void ipu_dmfc_config_wait4eot ( struct dmfc_channel * dmfc , int width )
2012-09-21 10:07:49 +02:00
{
struct ipu_dmfc_priv * priv = dmfc - > priv ;
u32 dmfc_gen1 ;
2016-03-14 16:10:08 +08:00
mutex_lock ( & priv - > mutex ) ;
2012-09-21 10:07:49 +02:00
dmfc_gen1 = readl ( priv - > base + DMFC_GENERAL1 ) ;
if ( ( dmfc - > slots * 64 * 4 ) / width > dmfc - > data - > max_fifo_lines )
dmfc_gen1 | = 1 < < dmfc - > data - > eot_shift ;
else
dmfc_gen1 & = ~ ( 1 < < dmfc - > data - > eot_shift ) ;
writel ( dmfc_gen1 , priv - > base + DMFC_GENERAL1 ) ;
2016-03-14 16:10:08 +08:00
mutex_unlock ( & priv - > mutex ) ;
2012-09-21 10:07:49 +02:00
}
2016-03-14 16:10:10 +08:00
EXPORT_SYMBOL_GPL ( ipu_dmfc_config_wait4eot ) ;
2012-09-21 10:07:49 +02:00
struct dmfc_channel * ipu_dmfc_get ( struct ipu_soc * ipu , int ipu_channel )
{
struct ipu_dmfc_priv * priv = ipu - > dmfc_priv ;
int i ;
for ( i = 0 ; i < DMFC_NUM_CHANNELS ; i + + )
if ( dmfcdata [ i ] . ipu_channel = = ipu_channel )
return & priv - > channels [ i ] ;
return ERR_PTR ( - ENODEV ) ;
}
EXPORT_SYMBOL_GPL ( ipu_dmfc_get ) ;
void ipu_dmfc_put ( struct dmfc_channel * dmfc )
{
}
EXPORT_SYMBOL_GPL ( ipu_dmfc_put ) ;
int ipu_dmfc_init ( struct ipu_soc * ipu , struct device * dev , unsigned long base ,
struct clk * ipu_clk )
{
struct ipu_dmfc_priv * priv ;
int i ;
priv = devm_kzalloc ( dev , sizeof ( * priv ) , GFP_KERNEL ) ;
if ( ! priv )
return - ENOMEM ;
priv - > base = devm_ioremap ( dev , base , PAGE_SIZE ) ;
if ( ! priv - > base )
return - ENOMEM ;
priv - > dev = dev ;
priv - > ipu = ipu ;
mutex_init ( & priv - > mutex ) ;
ipu - > dmfc_priv = priv ;
for ( i = 0 ; i < DMFC_NUM_CHANNELS ; i + + ) {
priv - > channels [ i ] . priv = priv ;
priv - > channels [ i ] . ipu = ipu ;
priv - > channels [ i ] . data = & dmfcdata [ i ] ;
2016-07-08 17:40:54 +08:00
if ( dmfcdata [ i ] . ipu_channel = = IPUV3_CHANNEL_MEM_BG_SYNC | |
dmfcdata [ i ] . ipu_channel = = IPUV3_CHANNEL_MEM_FG_SYNC | |
dmfcdata [ i ] . ipu_channel = = IPUV3_CHANNEL_MEM_DC_SYNC )
priv - > channels [ i ] . slots = 2 ;
}
2012-09-21 10:07:49 +02:00
2016-07-08 17:40:54 +08:00
writel ( 0x00000050 , priv - > base + DMFC_WR_CHAN ) ;
writel ( 0x00005654 , priv - > base + DMFC_DP_CHAN ) ;
2012-09-21 10:07:49 +02:00
writel ( 0x202020f6 , priv - > base + DMFC_WR_CHAN_DEF ) ;
writel ( 0x2020f6f6 , priv - > base + DMFC_DP_CHAN_DEF ) ;
writel ( 0x00000003 , priv - > base + DMFC_GENERAL1 ) ;
return 0 ;
}
void ipu_dmfc_exit ( struct ipu_soc * ipu )
{
}