2015-06-24 08:17:04 +02:00
/*
* Copyright ( c ) 2015 Pengutronix , Sascha Hauer < kernel @ pengutronix . de >
*
* 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 .
*
* 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/clk.h>
2016-10-20 16:56:35 +08:00
# include <linux/init.h>
2015-06-24 08:17:04 +02:00
# include <linux/io.h>
# include <linux/mfd/syscon.h>
# include <linux/of_device.h>
# include <linux/platform_device.h>
# include <linux/pm_domain.h>
2015-11-30 11:41:40 +01:00
# include <linux/regulator/consumer.h>
2016-10-20 16:56:35 +08:00
# include <linux/soc/mediatek/infracfg.h>
2016-10-20 16:56:38 +08:00
# include <dt-bindings/power/mt2701-power.h>
2015-06-24 08:17:04 +02:00
# include <dt-bindings/power/mt8173-power.h>
# define SPM_VDE_PWR_CON 0x0210
# define SPM_MFG_PWR_CON 0x0214
# define SPM_VEN_PWR_CON 0x0230
# define SPM_ISP_PWR_CON 0x0238
# define SPM_DIS_PWR_CON 0x023c
2016-10-20 16:56:38 +08:00
# define SPM_CONN_PWR_CON 0x0280
2015-06-24 08:17:04 +02:00
# define SPM_VEN2_PWR_CON 0x0298
2016-10-20 16:56:38 +08:00
# define SPM_AUDIO_PWR_CON 0x029c /* MT8173 */
# define SPM_BDP_PWR_CON 0x029c /* MT2701 */
# define SPM_ETH_PWR_CON 0x02a0
# define SPM_HIF_PWR_CON 0x02a4
# define SPM_IFR_MSC_PWR_CON 0x02a8
2015-06-24 08:17:04 +02:00
# define SPM_MFG_2D_PWR_CON 0x02c0
# define SPM_MFG_ASYNC_PWR_CON 0x02c4
# define SPM_USB_PWR_CON 0x02cc
2016-10-20 16:56:35 +08:00
2015-06-24 08:17:04 +02:00
# define SPM_PWR_STATUS 0x060c
# define SPM_PWR_STATUS_2ND 0x0610
# define PWR_RST_B_BIT BIT(0)
# define PWR_ISO_BIT BIT(1)
# define PWR_ON_BIT BIT(2)
# define PWR_ON_2ND_BIT BIT(3)
# define PWR_CLK_DIS_BIT BIT(4)
2016-10-20 16:56:38 +08:00
# define PWR_STATUS_CONN BIT(1)
2015-06-24 08:17:04 +02:00
# define PWR_STATUS_DISP BIT(3)
# define PWR_STATUS_MFG BIT(4)
# define PWR_STATUS_ISP BIT(5)
# define PWR_STATUS_VDEC BIT(7)
2016-10-20 16:56:38 +08:00
# define PWR_STATUS_BDP BIT(14)
# define PWR_STATUS_ETH BIT(15)
# define PWR_STATUS_HIF BIT(16)
# define PWR_STATUS_IFR_MSC BIT(17)
2015-06-24 08:17:04 +02:00
# define PWR_STATUS_VENC_LT BIT(20)
# define PWR_STATUS_VENC BIT(21)
# define PWR_STATUS_MFG_2D BIT(22)
# define PWR_STATUS_MFG_ASYNC BIT(23)
# define PWR_STATUS_AUDIO BIT(24)
# define PWR_STATUS_USB BIT(25)
enum clk_id {
2016-10-20 16:56:35 +08:00
CLK_NONE ,
CLK_MM ,
CLK_MFG ,
CLK_VENC ,
CLK_VENC_LT ,
2016-10-20 16:56:38 +08:00
CLK_ETHIF ,
2016-10-20 16:56:35 +08:00
CLK_MAX ,
} ;
static const char * const clk_names [ ] = {
NULL ,
" mm " ,
" mfg " ,
" venc " ,
" venc_lt " ,
2016-10-20 16:56:38 +08:00
" ethif " ,
2016-10-20 16:56:35 +08:00
NULL ,
2015-06-24 08:17:04 +02:00
} ;
2015-10-07 17:14:40 +08:00
# define MAX_CLKS 2
2015-06-24 08:17:04 +02:00
struct scp_domain_data {
const char * name ;
u32 sta_mask ;
int ctl_offs ;
u32 sram_pdn_bits ;
u32 sram_pdn_ack_bits ;
u32 bus_prot_mask ;
2015-10-07 17:14:40 +08:00
enum clk_id clk_id [ MAX_CLKS ] ;
2015-08-26 15:14:41 +08:00
bool active_wakeup ;
2015-06-24 08:17:04 +02:00
} ;
struct scp ;
struct scp_domain {
struct generic_pm_domain genpd ;
struct scp * scp ;
2015-10-07 17:14:40 +08:00
struct clk * clk [ MAX_CLKS ] ;
2015-12-30 09:30:40 +01:00
const struct scp_domain_data * data ;
2015-11-30 11:41:40 +01:00
struct regulator * supply ;
2015-06-24 08:17:04 +02:00
} ;
2017-04-08 09:20:31 +08:00
struct scp_ctrl_reg {
int pwr_sta_offs ;
int pwr_sta2nd_offs ;
} ;
2015-06-24 08:17:04 +02:00
struct scp {
2016-10-20 16:56:35 +08:00
struct scp_domain * domains ;
2015-06-24 08:17:04 +02:00
struct genpd_onecell_data pd_data ;
struct device * dev ;
void __iomem * base ;
struct regmap * infracfg ;
2017-04-08 09:20:31 +08:00
struct scp_ctrl_reg ctrl_reg ;
2015-06-24 08:17:04 +02:00
} ;
static int scpsys_domain_is_on ( struct scp_domain * scpd )
{
struct scp * scp = scpd - > scp ;
2017-04-08 09:20:31 +08:00
u32 status = readl ( scp - > base + scp - > ctrl_reg . pwr_sta_offs ) &
scpd - > data - > sta_mask ;
u32 status2 = readl ( scp - > base + scp - > ctrl_reg . pwr_sta2nd_offs ) &
scpd - > data - > sta_mask ;
2015-06-24 08:17:04 +02:00
/*
* A domain is on when both status bits are set . If only one is set
* return an error . This happens while powering up a domain
*/
if ( status & & status2 )
return true ;
if ( ! status & & ! status2 )
return false ;
return - EINVAL ;
}
static int scpsys_power_on ( struct generic_pm_domain * genpd )
{
struct scp_domain * scpd = container_of ( genpd , struct scp_domain , genpd ) ;
struct scp * scp = scpd - > scp ;
unsigned long timeout ;
bool expired ;
2015-12-30 09:30:40 +01:00
void __iomem * ctl_addr = scp - > base + scpd - > data - > ctl_offs ;
u32 sram_pdn_ack = scpd - > data - > sram_pdn_ack_bits ;
2015-06-24 08:17:04 +02:00
u32 val ;
int ret ;
2015-10-07 17:14:40 +08:00
int i ;
2015-11-30 11:41:40 +01:00
if ( scpd - > supply ) {
ret = regulator_enable ( scpd - > supply ) ;
if ( ret )
return ret ;
}
2015-10-07 17:14:40 +08:00
for ( i = 0 ; i < MAX_CLKS & & scpd - > clk [ i ] ; i + + ) {
ret = clk_prepare_enable ( scpd - > clk [ i ] ) ;
if ( ret ) {
for ( - - i ; i > = 0 ; i - - )
clk_disable_unprepare ( scpd - > clk [ i ] ) ;
2015-06-24 08:17:04 +02:00
goto err_clk ;
2015-10-07 17:14:40 +08:00
}
2015-06-24 08:17:04 +02:00
}
val = readl ( ctl_addr ) ;
val | = PWR_ON_BIT ;
writel ( val , ctl_addr ) ;
val | = PWR_ON_2ND_BIT ;
writel ( val , ctl_addr ) ;
/* wait until PWR_ACK = 1 */
timeout = jiffies + HZ ;
expired = false ;
while ( 1 ) {
ret = scpsys_domain_is_on ( scpd ) ;
if ( ret > 0 )
break ;
if ( expired ) {
ret = - ETIMEDOUT ;
goto err_pwr_ack ;
}
cpu_relax ( ) ;
if ( time_after ( jiffies , timeout ) )
expired = true ;
}
val & = ~ PWR_CLK_DIS_BIT ;
writel ( val , ctl_addr ) ;
val & = ~ PWR_ISO_BIT ;
writel ( val , ctl_addr ) ;
val | = PWR_RST_B_BIT ;
writel ( val , ctl_addr ) ;
2015-12-30 09:30:40 +01:00
val & = ~ scpd - > data - > sram_pdn_bits ;
2015-06-24 08:17:04 +02:00
writel ( val , ctl_addr ) ;
/* wait until SRAM_PDN_ACK all 0 */
timeout = jiffies + HZ ;
expired = false ;
while ( sram_pdn_ack & & ( readl ( ctl_addr ) & sram_pdn_ack ) ) {
if ( expired ) {
ret = - ETIMEDOUT ;
goto err_pwr_ack ;
}
cpu_relax ( ) ;
if ( time_after ( jiffies , timeout ) )
expired = true ;
}
2015-12-30 09:30:40 +01:00
if ( scpd - > data - > bus_prot_mask ) {
2015-06-24 08:17:04 +02:00
ret = mtk_infracfg_clear_bus_protection ( scp - > infracfg ,
2015-12-30 09:30:40 +01:00
scpd - > data - > bus_prot_mask ) ;
2015-06-24 08:17:04 +02:00
if ( ret )
goto err_pwr_ack ;
}
return 0 ;
err_pwr_ack :
2015-10-07 17:14:40 +08:00
for ( i = MAX_CLKS - 1 ; i > = 0 ; i - - ) {
if ( scpd - > clk [ i ] )
clk_disable_unprepare ( scpd - > clk [ i ] ) ;
}
2015-06-24 08:17:04 +02:00
err_clk :
2015-11-30 11:41:40 +01:00
if ( scpd - > supply )
regulator_disable ( scpd - > supply ) ;
2015-06-24 08:17:04 +02:00
dev_err ( scp - > dev , " Failed to power on domain %s \n " , genpd - > name ) ;
return ret ;
}
static int scpsys_power_off ( struct generic_pm_domain * genpd )
{
struct scp_domain * scpd = container_of ( genpd , struct scp_domain , genpd ) ;
struct scp * scp = scpd - > scp ;
unsigned long timeout ;
bool expired ;
2015-12-30 09:30:40 +01:00
void __iomem * ctl_addr = scp - > base + scpd - > data - > ctl_offs ;
u32 pdn_ack = scpd - > data - > sram_pdn_ack_bits ;
2015-06-24 08:17:04 +02:00
u32 val ;
int ret ;
2015-10-07 17:14:40 +08:00
int i ;
2015-06-24 08:17:04 +02:00
2015-12-30 09:30:40 +01:00
if ( scpd - > data - > bus_prot_mask ) {
2015-06-24 08:17:04 +02:00
ret = mtk_infracfg_set_bus_protection ( scp - > infracfg ,
2015-12-30 09:30:40 +01:00
scpd - > data - > bus_prot_mask ) ;
2015-06-24 08:17:04 +02:00
if ( ret )
goto out ;
}
val = readl ( ctl_addr ) ;
2015-12-30 09:30:40 +01:00
val | = scpd - > data - > sram_pdn_bits ;
2015-06-24 08:17:04 +02:00
writel ( val , ctl_addr ) ;
/* wait until SRAM_PDN_ACK all 1 */
timeout = jiffies + HZ ;
expired = false ;
while ( pdn_ack & & ( readl ( ctl_addr ) & pdn_ack ) ! = pdn_ack ) {
if ( expired ) {
ret = - ETIMEDOUT ;
goto out ;
}
cpu_relax ( ) ;
if ( time_after ( jiffies , timeout ) )
expired = true ;
}
val | = PWR_ISO_BIT ;
writel ( val , ctl_addr ) ;
val & = ~ PWR_RST_B_BIT ;
writel ( val , ctl_addr ) ;
val | = PWR_CLK_DIS_BIT ;
writel ( val , ctl_addr ) ;
val & = ~ PWR_ON_BIT ;
writel ( val , ctl_addr ) ;
val & = ~ PWR_ON_2ND_BIT ;
writel ( val , ctl_addr ) ;
/* wait until PWR_ACK = 0 */
timeout = jiffies + HZ ;
expired = false ;
while ( 1 ) {
ret = scpsys_domain_is_on ( scpd ) ;
if ( ret = = 0 )
break ;
if ( expired ) {
ret = - ETIMEDOUT ;
goto out ;
}
cpu_relax ( ) ;
if ( time_after ( jiffies , timeout ) )
expired = true ;
}
2015-10-07 17:14:40 +08:00
for ( i = 0 ; i < MAX_CLKS & & scpd - > clk [ i ] ; i + + )
clk_disable_unprepare ( scpd - > clk [ i ] ) ;
2015-06-24 08:17:04 +02:00
2015-11-30 11:41:40 +01:00
if ( scpd - > supply )
regulator_disable ( scpd - > supply ) ;
2015-06-24 08:17:04 +02:00
return 0 ;
out :
dev_err ( scp - > dev , " Failed to power off domain %s \n " , genpd - > name ) ;
return ret ;
}
2015-08-26 15:14:41 +08:00
static bool scpsys_active_wakeup ( struct device * dev )
{
struct generic_pm_domain * genpd ;
struct scp_domain * scpd ;
genpd = pd_to_genpd ( dev - > pm_domain ) ;
scpd = container_of ( genpd , struct scp_domain , genpd ) ;
2015-12-30 09:30:40 +01:00
return scpd - > data - > active_wakeup ;
2015-08-26 15:14:41 +08:00
}
2016-10-20 16:56:35 +08:00
static void init_clks ( struct platform_device * pdev , struct clk * * clk )
{
int i ;
for ( i = CLK_NONE + 1 ; i < CLK_MAX ; i + + )
clk [ i ] = devm_clk_get ( & pdev - > dev , clk_names [ i ] ) ;
}
static struct scp * init_scp ( struct platform_device * pdev ,
2017-04-08 09:20:31 +08:00
const struct scp_domain_data * scp_domain_data , int num ,
struct scp_ctrl_reg * scp_ctrl_reg )
2015-06-24 08:17:04 +02:00
{
struct genpd_onecell_data * pd_data ;
struct resource * res ;
2016-10-20 16:56:35 +08:00
int i , j ;
2015-06-24 08:17:04 +02:00
struct scp * scp ;
2016-10-20 16:56:35 +08:00
struct clk * clk [ CLK_MAX ] ;
2015-06-24 08:17:04 +02:00
scp = devm_kzalloc ( & pdev - > dev , sizeof ( * scp ) , GFP_KERNEL ) ;
if ( ! scp )
2016-10-20 16:56:35 +08:00
return ERR_PTR ( - ENOMEM ) ;
2015-06-24 08:17:04 +02:00
2017-04-08 09:20:31 +08:00
scp - > ctrl_reg . pwr_sta_offs = scp_ctrl_reg - > pwr_sta_offs ;
scp - > ctrl_reg . pwr_sta2nd_offs = scp_ctrl_reg - > pwr_sta2nd_offs ;
2015-06-24 08:17:04 +02:00
scp - > dev = & pdev - > dev ;
res = platform_get_resource ( pdev , IORESOURCE_MEM , 0 ) ;
scp - > base = devm_ioremap_resource ( & pdev - > dev , res ) ;
if ( IS_ERR ( scp - > base ) )
2016-10-20 16:56:35 +08:00
return ERR_CAST ( scp - > base ) ;
scp - > domains = devm_kzalloc ( & pdev - > dev ,
sizeof ( * scp - > domains ) * num , GFP_KERNEL ) ;
if ( ! scp - > domains )
return ERR_PTR ( - ENOMEM ) ;
2015-06-24 08:17:04 +02:00
pd_data = & scp - > pd_data ;
pd_data - > domains = devm_kzalloc ( & pdev - > dev ,
2016-10-20 16:56:35 +08:00
sizeof ( * pd_data - > domains ) * num , GFP_KERNEL ) ;
2015-06-24 08:17:04 +02:00
if ( ! pd_data - > domains )
2016-10-20 16:56:35 +08:00
return ERR_PTR ( - ENOMEM ) ;
2015-10-07 17:14:40 +08:00
2015-06-24 08:17:04 +02:00
scp - > infracfg = syscon_regmap_lookup_by_phandle ( pdev - > dev . of_node ,
" infracfg " ) ;
if ( IS_ERR ( scp - > infracfg ) ) {
dev_err ( & pdev - > dev , " Cannot find infracfg controller: %ld \n " ,
PTR_ERR ( scp - > infracfg ) ) ;
2016-10-20 16:56:35 +08:00
return ERR_CAST ( scp - > infracfg ) ;
2015-06-24 08:17:04 +02:00
}
2016-10-20 16:56:35 +08:00
for ( i = 0 ; i < num ; i + + ) {
2015-11-30 11:41:40 +01:00
struct scp_domain * scpd = & scp - > domains [ i ] ;
const struct scp_domain_data * data = & scp_domain_data [ i ] ;
scpd - > supply = devm_regulator_get_optional ( & pdev - > dev , data - > name ) ;
if ( IS_ERR ( scpd - > supply ) ) {
if ( PTR_ERR ( scpd - > supply ) = = - ENODEV )
scpd - > supply = NULL ;
else
2016-10-20 16:56:35 +08:00
return ERR_CAST ( scpd - > supply ) ;
2015-11-30 11:41:40 +01:00
}
}
2016-10-20 16:56:35 +08:00
pd_data - > num_domains = num ;
2015-06-24 08:17:04 +02:00
2016-10-20 16:56:35 +08:00
init_clks ( pdev , clk ) ;
for ( i = 0 ; i < num ; i + + ) {
2015-06-24 08:17:04 +02:00
struct scp_domain * scpd = & scp - > domains [ i ] ;
struct generic_pm_domain * genpd = & scpd - > genpd ;
const struct scp_domain_data * data = & scp_domain_data [ i ] ;
pd_data - > domains [ i ] = genpd ;
scpd - > scp = scp ;
2015-12-30 09:30:40 +01:00
scpd - > data = data ;
2016-10-20 16:56:35 +08:00
for ( j = 0 ; j < MAX_CLKS & & data - > clk_id [ j ] ; j + + ) {
struct clk * c = clk [ data - > clk_id [ j ] ] ;
if ( IS_ERR ( c ) ) {
dev_err ( & pdev - > dev , " %s: clk unavailable \n " ,
data - > name ) ;
return ERR_CAST ( c ) ;
}
scpd - > clk [ j ] = c ;
}
2015-06-24 08:17:04 +02:00
genpd - > name = data - > name ;
genpd - > power_off = scpsys_power_off ;
genpd - > power_on = scpsys_power_on ;
2015-08-26 15:14:41 +08:00
genpd - > dev_ops . active_wakeup = scpsys_active_wakeup ;
2016-10-20 16:56:35 +08:00
}
return scp ;
}
static void mtk_register_power_domains ( struct platform_device * pdev ,
struct scp * scp , int num )
{
struct genpd_onecell_data * pd_data ;
int i , ret ;
for ( i = 0 ; i < num ; i + + ) {
struct scp_domain * scpd = & scp - > domains [ i ] ;
struct generic_pm_domain * genpd = & scpd - > genpd ;
2015-06-24 08:17:04 +02:00
/*
2016-04-12 16:34:30 +08:00
* Initially turn on all domains to make the domains usable
* with ! CONFIG_PM and to get the hardware in sync with the
* software . The unused domains will be switched off during
* late_init time .
2015-06-24 08:17:04 +02:00
*/
2016-04-12 16:34:30 +08:00
genpd - > power_on ( genpd ) ;
2015-06-24 08:17:04 +02:00
2016-04-12 16:34:30 +08:00
pm_genpd_init ( genpd , NULL , false ) ;
2015-06-24 08:17:04 +02:00
}
/*
* We are not allowed to fail here since there is no way to unregister
* a power domain . Once registered above we have to keep the domains
* valid .
*/
2016-10-20 16:56:35 +08:00
pd_data = & scp - > pd_data ;
ret = of_genpd_add_provider_onecell ( pdev - > dev . of_node , pd_data ) ;
if ( ret )
dev_err ( & pdev - > dev , " Failed to add OF provider: %d \n " , ret ) ;
}
2016-10-20 16:56:38 +08:00
/*
* MT2701 power domain support
*/
static const struct scp_domain_data scp_domain_data_mt2701 [ ] = {
[ MT2701_POWER_DOMAIN_CONN ] = {
. name = " conn " ,
. sta_mask = PWR_STATUS_CONN ,
. ctl_offs = SPM_CONN_PWR_CON ,
. bus_prot_mask = 0x0104 ,
. clk_id = { CLK_NONE } ,
. active_wakeup = true ,
} ,
[ MT2701_POWER_DOMAIN_DISP ] = {
. name = " disp " ,
. sta_mask = PWR_STATUS_DISP ,
. ctl_offs = SPM_DIS_PWR_CON ,
. sram_pdn_bits = GENMASK ( 11 , 8 ) ,
. clk_id = { CLK_MM } ,
. bus_prot_mask = 0x0002 ,
. active_wakeup = true ,
} ,
[ MT2701_POWER_DOMAIN_MFG ] = {
. name = " mfg " ,
. sta_mask = PWR_STATUS_MFG ,
. ctl_offs = SPM_MFG_PWR_CON ,
. sram_pdn_bits = GENMASK ( 11 , 8 ) ,
. sram_pdn_ack_bits = GENMASK ( 12 , 12 ) ,
. clk_id = { CLK_MFG } ,
. active_wakeup = true ,
} ,
[ MT2701_POWER_DOMAIN_VDEC ] = {
. name = " vdec " ,
. sta_mask = PWR_STATUS_VDEC ,
. ctl_offs = SPM_VDE_PWR_CON ,
. sram_pdn_bits = GENMASK ( 11 , 8 ) ,
. sram_pdn_ack_bits = GENMASK ( 12 , 12 ) ,
. clk_id = { CLK_MM } ,
. active_wakeup = true ,
} ,
[ MT2701_POWER_DOMAIN_ISP ] = {
. name = " isp " ,
. sta_mask = PWR_STATUS_ISP ,
. ctl_offs = SPM_ISP_PWR_CON ,
. sram_pdn_bits = GENMASK ( 11 , 8 ) ,
. sram_pdn_ack_bits = GENMASK ( 13 , 12 ) ,
. clk_id = { CLK_MM } ,
. active_wakeup = true ,
} ,
[ MT2701_POWER_DOMAIN_BDP ] = {
. name = " bdp " ,
. sta_mask = PWR_STATUS_BDP ,
. ctl_offs = SPM_BDP_PWR_CON ,
. sram_pdn_bits = GENMASK ( 11 , 8 ) ,
. clk_id = { CLK_NONE } ,
. active_wakeup = true ,
} ,
[ MT2701_POWER_DOMAIN_ETH ] = {
. name = " eth " ,
. sta_mask = PWR_STATUS_ETH ,
. ctl_offs = SPM_ETH_PWR_CON ,
. sram_pdn_bits = GENMASK ( 11 , 8 ) ,
. sram_pdn_ack_bits = GENMASK ( 15 , 12 ) ,
. clk_id = { CLK_ETHIF } ,
. active_wakeup = true ,
} ,
[ MT2701_POWER_DOMAIN_HIF ] = {
. name = " hif " ,
. sta_mask = PWR_STATUS_HIF ,
. ctl_offs = SPM_HIF_PWR_CON ,
. sram_pdn_bits = GENMASK ( 11 , 8 ) ,
. sram_pdn_ack_bits = GENMASK ( 15 , 12 ) ,
. clk_id = { CLK_ETHIF } ,
. active_wakeup = true ,
} ,
[ MT2701_POWER_DOMAIN_IFR_MSC ] = {
. name = " ifr_msc " ,
. sta_mask = PWR_STATUS_IFR_MSC ,
. ctl_offs = SPM_IFR_MSC_PWR_CON ,
. clk_id = { CLK_NONE } ,
. active_wakeup = true ,
} ,
} ;
# define NUM_DOMAINS_MT2701 ARRAY_SIZE(scp_domain_data_mt2701)
static int __init scpsys_probe_mt2701 ( struct platform_device * pdev )
{
struct scp * scp ;
2017-04-08 09:20:31 +08:00
struct scp_ctrl_reg scp_reg ;
2016-10-20 16:56:38 +08:00
2017-04-08 09:20:31 +08:00
scp_reg . pwr_sta_offs = SPM_PWR_STATUS ;
scp_reg . pwr_sta2nd_offs = SPM_PWR_STATUS_2ND ;
scp = init_scp ( pdev , scp_domain_data_mt2701 , NUM_DOMAINS_MT2701 ,
& scp_reg ) ;
2016-10-20 16:56:38 +08:00
if ( IS_ERR ( scp ) )
return PTR_ERR ( scp ) ;
mtk_register_power_domains ( pdev , scp , NUM_DOMAINS_MT2701 ) ;
return 0 ;
}
2016-10-20 16:56:35 +08:00
/*
* MT8173 power domain support
*/
static const struct scp_domain_data scp_domain_data_mt8173 [ ] = {
[ MT8173_POWER_DOMAIN_VDEC ] = {
. name = " vdec " ,
. sta_mask = PWR_STATUS_VDEC ,
. ctl_offs = SPM_VDE_PWR_CON ,
. sram_pdn_bits = GENMASK ( 11 , 8 ) ,
. sram_pdn_ack_bits = GENMASK ( 12 , 12 ) ,
. clk_id = { CLK_MM } ,
} ,
[ MT8173_POWER_DOMAIN_VENC ] = {
. name = " venc " ,
. sta_mask = PWR_STATUS_VENC ,
. ctl_offs = SPM_VEN_PWR_CON ,
. sram_pdn_bits = GENMASK ( 11 , 8 ) ,
. sram_pdn_ack_bits = GENMASK ( 15 , 12 ) ,
. clk_id = { CLK_MM , CLK_VENC } ,
} ,
[ MT8173_POWER_DOMAIN_ISP ] = {
. name = " isp " ,
. sta_mask = PWR_STATUS_ISP ,
. ctl_offs = SPM_ISP_PWR_CON ,
. sram_pdn_bits = GENMASK ( 11 , 8 ) ,
. sram_pdn_ack_bits = GENMASK ( 13 , 12 ) ,
. clk_id = { CLK_MM } ,
} ,
[ MT8173_POWER_DOMAIN_MM ] = {
. name = " mm " ,
. sta_mask = PWR_STATUS_DISP ,
. ctl_offs = SPM_DIS_PWR_CON ,
. sram_pdn_bits = GENMASK ( 11 , 8 ) ,
. sram_pdn_ack_bits = GENMASK ( 12 , 12 ) ,
. clk_id = { CLK_MM } ,
. bus_prot_mask = MT8173_TOP_AXI_PROT_EN_MM_M0 |
MT8173_TOP_AXI_PROT_EN_MM_M1 ,
} ,
[ MT8173_POWER_DOMAIN_VENC_LT ] = {
. name = " venc_lt " ,
. sta_mask = PWR_STATUS_VENC_LT ,
. ctl_offs = SPM_VEN2_PWR_CON ,
. sram_pdn_bits = GENMASK ( 11 , 8 ) ,
. sram_pdn_ack_bits = GENMASK ( 15 , 12 ) ,
. clk_id = { CLK_MM , CLK_VENC_LT } ,
} ,
[ MT8173_POWER_DOMAIN_AUDIO ] = {
. name = " audio " ,
. sta_mask = PWR_STATUS_AUDIO ,
. ctl_offs = SPM_AUDIO_PWR_CON ,
. sram_pdn_bits = GENMASK ( 11 , 8 ) ,
. sram_pdn_ack_bits = GENMASK ( 15 , 12 ) ,
. clk_id = { CLK_NONE } ,
} ,
[ MT8173_POWER_DOMAIN_USB ] = {
. name = " usb " ,
. sta_mask = PWR_STATUS_USB ,
. ctl_offs = SPM_USB_PWR_CON ,
. sram_pdn_bits = GENMASK ( 11 , 8 ) ,
. sram_pdn_ack_bits = GENMASK ( 15 , 12 ) ,
. clk_id = { CLK_NONE } ,
. active_wakeup = true ,
} ,
[ MT8173_POWER_DOMAIN_MFG_ASYNC ] = {
. name = " mfg_async " ,
. sta_mask = PWR_STATUS_MFG_ASYNC ,
. ctl_offs = SPM_MFG_ASYNC_PWR_CON ,
. sram_pdn_bits = GENMASK ( 11 , 8 ) ,
. sram_pdn_ack_bits = 0 ,
. clk_id = { CLK_MFG } ,
} ,
[ MT8173_POWER_DOMAIN_MFG_2D ] = {
. name = " mfg_2d " ,
. sta_mask = PWR_STATUS_MFG_2D ,
. ctl_offs = SPM_MFG_2D_PWR_CON ,
. sram_pdn_bits = GENMASK ( 11 , 8 ) ,
. sram_pdn_ack_bits = GENMASK ( 13 , 12 ) ,
. clk_id = { CLK_NONE } ,
} ,
[ MT8173_POWER_DOMAIN_MFG ] = {
. name = " mfg " ,
. sta_mask = PWR_STATUS_MFG ,
. ctl_offs = SPM_MFG_PWR_CON ,
. sram_pdn_bits = GENMASK ( 13 , 8 ) ,
. sram_pdn_ack_bits = GENMASK ( 21 , 16 ) ,
. clk_id = { CLK_NONE } ,
. bus_prot_mask = MT8173_TOP_AXI_PROT_EN_MFG_S |
MT8173_TOP_AXI_PROT_EN_MFG_M0 |
MT8173_TOP_AXI_PROT_EN_MFG_M1 |
MT8173_TOP_AXI_PROT_EN_MFG_SNOOP_OUT ,
} ,
} ;
# define NUM_DOMAINS_MT8173 ARRAY_SIZE(scp_domain_data_mt8173)
static int __init scpsys_probe_mt8173 ( struct platform_device * pdev )
{
struct scp * scp ;
struct genpd_onecell_data * pd_data ;
int ret ;
2017-04-08 09:20:31 +08:00
struct scp_ctrl_reg scp_reg ;
scp_reg . pwr_sta_offs = SPM_PWR_STATUS ;
scp_reg . pwr_sta2nd_offs = SPM_PWR_STATUS_2ND ;
2016-10-20 16:56:35 +08:00
2017-04-08 09:20:31 +08:00
scp = init_scp ( pdev , scp_domain_data_mt8173 , NUM_DOMAINS_MT8173 ,
& scp_reg ) ;
2016-10-20 16:56:35 +08:00
if ( IS_ERR ( scp ) )
return PTR_ERR ( scp ) ;
mtk_register_power_domains ( pdev , scp , NUM_DOMAINS_MT8173 ) ;
pd_data = & scp - > pd_data ;
2015-06-24 08:17:04 +02:00
ret = pm_genpd_add_subdomain ( pd_data - > domains [ MT8173_POWER_DOMAIN_MFG_ASYNC ] ,
pd_data - > domains [ MT8173_POWER_DOMAIN_MFG_2D ] ) ;
if ( ret & & IS_ENABLED ( CONFIG_PM ) )
dev_err ( & pdev - > dev , " Failed to add subdomain: %d \n " , ret ) ;
ret = pm_genpd_add_subdomain ( pd_data - > domains [ MT8173_POWER_DOMAIN_MFG_2D ] ,
pd_data - > domains [ MT8173_POWER_DOMAIN_MFG ] ) ;
if ( ret & & IS_ENABLED ( CONFIG_PM ) )
dev_err ( & pdev - > dev , " Failed to add subdomain: %d \n " , ret ) ;
return 0 ;
}
2016-10-20 16:56:35 +08:00
/*
* scpsys driver init
*/
2015-06-24 08:17:04 +02:00
static const struct of_device_id of_scpsys_match_tbl [ ] = {
{
2016-10-20 16:56:38 +08:00
. compatible = " mediatek,mt2701-scpsys " ,
. data = scpsys_probe_mt2701 ,
} , {
2015-06-24 08:17:04 +02:00
. compatible = " mediatek,mt8173-scpsys " ,
2016-10-20 16:56:35 +08:00
. data = scpsys_probe_mt8173 ,
2015-06-24 08:17:04 +02:00
} , {
/* sentinel */
}
} ;
2016-10-20 16:56:35 +08:00
static int scpsys_probe ( struct platform_device * pdev )
{
int ( * probe ) ( struct platform_device * ) ;
const struct of_device_id * of_id ;
of_id = of_match_node ( of_scpsys_match_tbl , pdev - > dev . of_node ) ;
if ( ! of_id | | ! of_id - > data )
return - EINVAL ;
probe = of_id - > data ;
return probe ( pdev ) ;
}
2015-06-24 08:17:04 +02:00
static struct platform_driver scpsys_drv = {
2015-12-30 09:30:40 +01:00
. probe = scpsys_probe ,
2015-06-24 08:17:04 +02:00
. driver = {
. name = " mtk-scpsys " ,
2015-12-30 09:30:40 +01:00
. suppress_bind_attrs = true ,
2015-06-24 08:17:04 +02:00
. owner = THIS_MODULE ,
. of_match_table = of_match_ptr ( of_scpsys_match_tbl ) ,
} ,
} ;
2015-12-30 09:30:40 +01:00
builtin_platform_driver ( scpsys_drv ) ;