2013-10-08 12:55:26 +05:30
/*
* HDMI PLL
*
2017-12-05 14:29:31 -06:00
* Copyright ( C ) 2013 Texas Instruments Incorporated - http : //www.ti.com/
2013-10-08 12:55:26 +05:30
*
* 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 .
*/
2013-11-14 13:46:32 +02:00
# define DSS_SUBSYS_NAME "HDMIPLL"
2013-10-08 12:55:26 +05:30
# include <linux/kernel.h>
# include <linux/module.h>
# include <linux/err.h>
# include <linux/io.h>
# include <linux/platform_device.h>
2014-10-22 15:02:17 +03:00
# include <linux/clk.h>
2016-05-11 18:01:45 +02:00
# include <linux/seq_file.h>
2016-05-17 17:07:46 +03:00
# include <linux/pm_runtime.h>
2014-10-22 15:02:17 +03:00
2016-05-27 14:40:49 +03:00
# include "omapdss.h"
2013-10-08 12:55:26 +05:30
# include "dss.h"
2013-09-12 17:45:57 +05:30
# include "hdmi.h"
2013-10-08 12:55:26 +05:30
void hdmi_pll_dump ( struct hdmi_pll_data * pll , struct seq_file * s )
{
# define DUMPPLL(r) seq_printf(s, "%-35s %08x\n", #r,\
hdmi_read_reg ( pll - > base , r ) )
DUMPPLL ( PLLCTRL_PLL_CONTROL ) ;
DUMPPLL ( PLLCTRL_PLL_STATUS ) ;
DUMPPLL ( PLLCTRL_PLL_GO ) ;
DUMPPLL ( PLLCTRL_CFG1 ) ;
DUMPPLL ( PLLCTRL_CFG2 ) ;
DUMPPLL ( PLLCTRL_CFG3 ) ;
DUMPPLL ( PLLCTRL_SSC_CFG1 ) ;
DUMPPLL ( PLLCTRL_SSC_CFG2 ) ;
DUMPPLL ( PLLCTRL_CFG4 ) ;
}
2014-10-22 15:02:17 +03:00
static int hdmi_pll_enable ( struct dss_pll * dsspll )
2013-10-08 12:55:26 +05:30
{
2014-10-22 15:02:17 +03:00
struct hdmi_pll_data * pll = container_of ( dsspll , struct hdmi_pll_data , pll ) ;
2014-10-16 15:31:38 +03:00
struct hdmi_wp_data * wp = pll - > wp ;
2016-05-17 17:00:52 +03:00
int r ;
2013-10-08 12:55:26 +05:30
2016-05-17 17:07:46 +03:00
r = pm_runtime_get_sync ( & pll - > pdev - > dev ) ;
WARN_ON ( r < 0 ) ;
2013-10-08 12:55:26 +05:30
2018-02-13 14:00:22 +02:00
dss_ctrl_pll_enable ( dsspll , true ) ;
2014-12-31 11:26:18 +02:00
2013-10-08 12:55:26 +05:30
r = hdmi_wp_set_pll_pwr ( wp , HDMI_PLLPWRCMD_BOTHON_ALLCLKS ) ;
if ( r )
return r ;
return 0 ;
}
2014-10-22 15:02:17 +03:00
static void hdmi_pll_disable ( struct dss_pll * dsspll )
2013-10-08 12:55:26 +05:30
{
2014-10-22 15:02:17 +03:00
struct hdmi_pll_data * pll = container_of ( dsspll , struct hdmi_pll_data , pll ) ;
2014-10-16 15:31:38 +03:00
struct hdmi_wp_data * wp = pll - > wp ;
2016-05-17 17:07:46 +03:00
int r ;
2014-10-16 15:31:38 +03:00
2013-10-08 12:55:26 +05:30
hdmi_wp_set_pll_pwr ( wp , HDMI_PLLPWRCMD_ALLOFF ) ;
2014-12-31 11:26:18 +02:00
2018-02-13 14:00:22 +02:00
dss_ctrl_pll_enable ( dsspll , false ) ;
2016-05-17 17:07:46 +03:00
r = pm_runtime_put_sync ( & pll - > pdev - > dev ) ;
WARN_ON ( r < 0 & & r ! = - ENOSYS ) ;
2013-10-08 12:55:26 +05:30
}
2017-08-11 16:49:02 +03:00
static const struct dss_pll_ops hdmi_pll_ops = {
2014-10-22 15:02:17 +03:00
. enable = hdmi_pll_enable ,
. disable = hdmi_pll_disable ,
. set_config = dss_pll_write_config_type_b ,
} ;
static const struct dss_pll_hw dss_omap4_hdmi_pll_hw = {
2016-05-18 10:48:44 +03:00
. type = DSS_PLL_TYPE_B ,
2014-10-22 15:02:17 +03:00
. n_max = 255 ,
. m_min = 20 ,
. m_max = 4095 ,
. mX_max = 127 ,
. fint_min = 500000 ,
. fint_max = 2500000 ,
. clkdco_min = 500000000 ,
. clkdco_low = 1000000000 ,
. clkdco_max = 2000000000 ,
. n_msb = 8 ,
. n_lsb = 1 ,
. m_msb = 20 ,
. m_lsb = 9 ,
. mX_msb [ 0 ] = 24 ,
. mX_lsb [ 0 ] = 18 ,
. has_selfreqdco = true ,
2013-09-23 15:12:34 +05:30
} ;
2014-10-22 15:02:17 +03:00
static const struct dss_pll_hw dss_omap5_hdmi_pll_hw = {
2016-05-18 10:48:44 +03:00
. type = DSS_PLL_TYPE_B ,
2014-10-22 15:02:17 +03:00
. n_max = 255 ,
. m_min = 20 ,
. m_max = 2045 ,
. mX_max = 127 ,
. fint_min = 620000 ,
. fint_max = 2500000 ,
. clkdco_min = 750000000 ,
. clkdco_low = 1500000000 ,
. clkdco_max = 2500000000UL ,
. n_msb = 8 ,
. n_lsb = 1 ,
. m_msb = 20 ,
. m_lsb = 9 ,
. mX_msb [ 0 ] = 24 ,
. mX_lsb [ 0 ] = 18 ,
. has_selfreqdco = true ,
. has_refsel = true ,
2013-09-23 15:12:34 +05:30
} ;
2018-02-13 14:00:21 +02:00
static int hdmi_init_pll_data ( struct dss_device * dss ,
struct platform_device * pdev ,
2017-08-11 16:49:02 +03:00
struct hdmi_pll_data * hpll )
2013-09-23 15:12:34 +05:30
{
2014-10-22 15:02:17 +03:00
struct dss_pll * pll = & hpll - > pll ;
struct clk * clk ;
int r ;
2013-09-23 15:12:34 +05:30
2014-10-22 15:02:17 +03:00
clk = devm_clk_get ( & pdev - > dev , " sys_clk " ) ;
if ( IS_ERR ( clk ) ) {
DSSERR ( " can't get sys_clk \n " ) ;
return PTR_ERR ( clk ) ;
2013-09-23 15:12:34 +05:30
}
2014-10-22 15:02:17 +03:00
pll - > name = " hdmi " ;
2015-01-02 10:05:33 +02:00
pll - > id = DSS_PLL_HDMI ;
2014-10-22 15:02:17 +03:00
pll - > base = hpll - > base ;
pll - > clkin = clk ;
2017-08-11 16:49:05 +03:00
if ( hpll - > wp - > version = = 4 )
2014-10-22 15:02:17 +03:00
pll - > hw = & dss_omap4_hdmi_pll_hw ;
2017-08-11 16:49:05 +03:00
else
2014-10-22 15:02:17 +03:00
pll - > hw = & dss_omap5_hdmi_pll_hw ;
2013-09-23 15:12:34 +05:30
2017-08-11 16:49:02 +03:00
pll - > ops = & hdmi_pll_ops ;
2014-10-22 15:02:17 +03:00
2018-02-13 14:00:30 +02:00
r = dss_pll_register ( dss , pll ) ;
2014-10-22 15:02:17 +03:00
if ( r )
return r ;
2013-09-23 15:12:34 +05:30
return 0 ;
}
2018-02-13 14:00:21 +02:00
int hdmi_pll_init ( struct dss_device * dss , struct platform_device * pdev ,
struct hdmi_pll_data * pll , struct hdmi_wp_data * wp )
2013-10-08 12:55:26 +05:30
{
2013-09-23 15:12:34 +05:30
int r ;
2013-10-08 12:55:26 +05:30
struct resource * res ;
2016-05-17 17:07:46 +03:00
pll - > pdev = pdev ;
2014-10-16 15:31:38 +03:00
pll - > wp = wp ;
2013-12-17 14:41:14 +02:00
res = platform_get_resource_byname ( pdev , IORESOURCE_MEM , " pll " ) ;
2014-04-28 16:11:01 +03:00
pll - > base = devm_ioremap_resource ( & pdev - > dev , res ) ;
2017-05-07 00:29:09 +03:00
if ( IS_ERR ( pll - > base ) )
2014-05-23 14:50:09 +03:00
return PTR_ERR ( pll - > base ) ;
2013-10-08 12:55:26 +05:30
2018-02-13 14:00:21 +02:00
r = hdmi_init_pll_data ( dss , pdev , pll ) ;
2014-10-22 15:02:17 +03:00
if ( r ) {
DSSERR ( " failed to init HDMI PLL \n " ) ;
return r ;
}
2013-10-08 12:55:26 +05:30
return 0 ;
}
2014-10-22 15:02:17 +03:00
void hdmi_pll_uninit ( struct hdmi_pll_data * hpll )
{
struct dss_pll * pll = & hpll - > pll ;
dss_pll_unregister ( pll ) ;
}