2019-05-27 08:55:21 +02:00
// SPDX-License-Identifier: GPL-2.0-only
2014-07-04 13:38:27 +05:30
/*
2017-12-05 14:29:31 -06:00
* Copyright ( C ) 2014 Texas Instruments Incorporated - http : //www.ti.com/
*/
2014-07-04 13:38:27 +05:30
# include <linux/clk.h>
# include <linux/delay.h>
# include <linux/err.h>
# include <linux/io.h>
# include <linux/kernel.h>
# include <linux/platform_device.h>
# include <linux/sched.h>
2016-05-27 14:40:49 +03:00
# include "omapdss.h"
2014-07-04 13:38:27 +05:30
# include "dss.h"
struct dss_video_pll {
struct dss_pll pll ;
struct device * dev ;
void __iomem * clkctrl_base ;
} ;
# define REG_MOD(reg, val, start, end) \
writel_relaxed ( FLD_MOD ( readl_relaxed ( reg ) , val , start , end ) , reg )
static void dss_dpll_enable_scp_clk ( struct dss_video_pll * vpll )
{
REG_MOD ( vpll - > clkctrl_base , 1 , 14 , 14 ) ; /* CIO_CLK_ICG */
}
static void dss_dpll_disable_scp_clk ( struct dss_video_pll * vpll )
{
REG_MOD ( vpll - > clkctrl_base , 0 , 14 , 14 ) ; /* CIO_CLK_ICG */
}
static void dss_dpll_power_enable ( struct dss_video_pll * vpll )
{
REG_MOD ( vpll - > clkctrl_base , 2 , 31 , 30 ) ; /* PLL_POWER_ON_ALL */
/*
* DRA7x PLL CTRL ' s PLL_PWR_STATUS seems to always return 0 ,
* so we have to use fixed delay here .
*/
msleep ( 1 ) ;
}
static void dss_dpll_power_disable ( struct dss_video_pll * vpll )
{
REG_MOD ( vpll - > clkctrl_base , 0 , 31 , 30 ) ; /* PLL_POWER_OFF */
}
static int dss_video_pll_enable ( struct dss_pll * pll )
{
struct dss_video_pll * vpll = container_of ( pll , struct dss_video_pll , pll ) ;
int r ;
2018-02-13 14:00:21 +02:00
r = dss_runtime_get ( pll - > dss ) ;
2014-07-04 13:38:27 +05:30
if ( r )
return r ;
2018-02-13 14:00:22 +02:00
dss_ctrl_pll_enable ( pll , true ) ;
2014-07-04 13:38:27 +05:30
dss_dpll_enable_scp_clk ( vpll ) ;
r = dss_pll_wait_reset_done ( pll ) ;
if ( r )
goto err_reset ;
dss_dpll_power_enable ( vpll ) ;
return 0 ;
err_reset :
dss_dpll_disable_scp_clk ( vpll ) ;
2018-02-13 14:00:22 +02:00
dss_ctrl_pll_enable ( pll , false ) ;
2018-02-13 14:00:21 +02:00
dss_runtime_put ( pll - > dss ) ;
2014-07-04 13:38:27 +05:30
return r ;
}
static void dss_video_pll_disable ( struct dss_pll * pll )
{
struct dss_video_pll * vpll = container_of ( pll , struct dss_video_pll , pll ) ;
dss_dpll_power_disable ( vpll ) ;
dss_dpll_disable_scp_clk ( vpll ) ;
2018-02-13 14:00:22 +02:00
dss_ctrl_pll_enable ( pll , false ) ;
2014-07-04 13:38:27 +05:30
2018-02-13 14:00:21 +02:00
dss_runtime_put ( pll - > dss ) ;
2014-07-04 13:38:27 +05:30
}
static const struct dss_pll_ops dss_pll_ops = {
. enable = dss_video_pll_enable ,
. disable = dss_video_pll_disable ,
. set_config = dss_pll_write_config_type_a ,
} ;
static const struct dss_pll_hw dss_dra7_video_pll_hw = {
2016-05-18 10:48:44 +03:00
. type = DSS_PLL_TYPE_A ,
2014-07-04 13:38:27 +05:30
. n_max = ( 1 < < 8 ) - 1 ,
. m_max = ( 1 < < 12 ) - 1 ,
. mX_max = ( 1 < < 5 ) - 1 ,
. fint_min = 500000 ,
. fint_max = 2500000 ,
. clkdco_max = 1800000000 ,
. n_msb = 8 ,
. n_lsb = 1 ,
. m_msb = 20 ,
. m_lsb = 9 ,
. mX_msb [ 0 ] = 25 ,
. mX_lsb [ 0 ] = 21 ,
. mX_msb [ 1 ] = 30 ,
. mX_lsb [ 1 ] = 26 ,
2016-05-17 16:31:41 +03:00
. mX_msb [ 2 ] = 4 ,
. mX_lsb [ 2 ] = 0 ,
. mX_msb [ 3 ] = 9 ,
. mX_lsb [ 3 ] = 5 ,
2014-07-04 13:38:27 +05:30
. has_refsel = true ,
2017-06-13 12:02:10 +03:00
. errata_i886 = true ,
2018-01-24 16:15:09 +05:30
. errata_i932 = true ,
2014-07-04 13:38:27 +05:30
} ;
2018-02-13 14:00:21 +02:00
struct dss_pll * dss_video_pll_init ( struct dss_device * dss ,
struct platform_device * pdev , int id ,
struct regulator * regulator )
2014-07-04 13:38:27 +05:30
{
const char * const reg_name [ ] = { " pll1 " , " pll2 " } ;
const char * const clkctrl_name [ ] = { " pll1_clkctrl " , " pll2_clkctrl " } ;
const char * const clkin_name [ ] = { " video1_clk " , " video2_clk " } ;
struct resource * res ;
struct dss_video_pll * vpll ;
void __iomem * pll_base , * clkctrl_base ;
struct clk * clk ;
struct dss_pll * pll ;
int r ;
/* PLL CONTROL */
res = platform_get_resource_byname ( pdev , IORESOURCE_MEM , reg_name [ id ] ) ;
pll_base = devm_ioremap_resource ( & pdev - > dev , res ) ;
2017-05-07 00:29:09 +03:00
if ( IS_ERR ( pll_base ) )
2014-07-04 13:38:27 +05:30
return ERR_CAST ( pll_base ) ;
/* CLOCK CONTROL */
res = platform_get_resource_byname ( pdev , IORESOURCE_MEM ,
clkctrl_name [ id ] ) ;
clkctrl_base = devm_ioremap_resource ( & pdev - > dev , res ) ;
2017-05-07 00:29:09 +03:00
if ( IS_ERR ( clkctrl_base ) )
2014-07-04 13:38:27 +05:30
return ERR_CAST ( clkctrl_base ) ;
/* CLKIN */
clk = devm_clk_get ( & pdev - > dev , clkin_name [ id ] ) ;
if ( IS_ERR ( clk ) ) {
DSSERR ( " can't get video pll clkin \n " ) ;
return ERR_CAST ( clk ) ;
}
vpll = devm_kzalloc ( & pdev - > dev , sizeof ( * vpll ) , GFP_KERNEL ) ;
if ( ! vpll )
return ERR_PTR ( - ENOMEM ) ;
vpll - > dev = & pdev - > dev ;
vpll - > clkctrl_base = clkctrl_base ;
pll = & vpll - > pll ;
pll - > name = id = = 0 ? " video0 " : " video1 " ;
pll - > id = id = = 0 ? DSS_PLL_VIDEO1 : DSS_PLL_VIDEO2 ;
pll - > clkin = clk ;
pll - > regulator = regulator ;
pll - > base = pll_base ;
pll - > hw = & dss_dra7_video_pll_hw ;
pll - > ops = & dss_pll_ops ;
2018-02-13 14:00:30 +02:00
r = dss_pll_register ( dss , pll ) ;
2014-07-04 13:38:27 +05:30
if ( r )
return ERR_PTR ( r ) ;
return pll ;
}
void dss_video_pll_uninit ( struct dss_pll * pll )
{
dss_pll_unregister ( pll ) ;
}