2019-05-27 09:55:21 +03:00
// SPDX-License-Identifier: GPL-2.0-only
2016-02-22 20:20:49 +03:00
/*
* Copyright ( c ) 2015 - 2016 MediaTek Inc .
* Author : Yong Wu < yong . wu @ mediatek . com >
*/
# include <linux/clk.h>
# include <linux/component.h>
# include <linux/device.h>
# include <linux/err.h>
# include <linux/io.h>
2017-08-21 14:00:21 +03:00
# include <linux/module.h>
2016-02-22 20:20:49 +03:00
# include <linux/of.h>
# include <linux/of_platform.h>
# include <linux/platform_device.h>
# include <linux/pm_runtime.h>
# include <soc/mediatek/smi.h>
2016-06-08 12:50:59 +03:00
# include <dt-bindings/memory/mt2701-larb-port.h>
2021-01-11 14:18:49 +03:00
# include <dt-bindings/memory/mtk-memory-port.h>
2016-02-22 20:20:49 +03:00
2017-08-21 14:00:16 +03:00
/* mt8173 */
2016-02-22 20:20:49 +03:00
# define SMI_LARB_MMU_EN 0xf00
2017-08-21 14:00:16 +03:00
2020-09-06 21:09:38 +03:00
/* mt8167 */
# define MT8167_SMI_LARB_MMU_EN 0xfc0
2017-08-21 14:00:16 +03:00
/* mt2701 */
2016-06-08 12:50:59 +03:00
# define REG_SMI_SECUR_CON_BASE 0x5c0
/* every register control 8 port, register offset 0x4 */
# define REG_SMI_SECUR_CON_OFFSET(id) (((id) >> 3) << 2)
# define REG_SMI_SECUR_CON_ADDR(id) \
( REG_SMI_SECUR_CON_BASE + REG_SMI_SECUR_CON_OFFSET ( id ) )
/*
* every port have 4 bit to control , bit [ port + 3 ] control virtual or physical ,
* bit [ port + 2 : port + 1 ] control the domain , bit [ port ] control the security
* or non - security .
*/
# define SMI_SECUR_CON_VAL_MSK(id) (~(0xf << (((id) & 0x7) << 2)))
# define SMI_SECUR_CON_VAL_VIRT(id) BIT((((id) & 0x7) << 2) + 3)
/* mt2701 domain should be set to 3 */
# define SMI_SECUR_CON_VAL_DOMAIN(id) (0x3 << ((((id) & 0x7) << 2) + 1))
2017-08-21 14:00:16 +03:00
/* mt2712 */
# define SMI_LARB_NONSEC_CON(id) (0x380 + ((id) * 4))
# define F_MMU_EN BIT(0)
2021-01-11 14:19:11 +03:00
# define BANK_SEL(id) ({ \
u32 _id = ( id ) & 0x3 ; \
( _id < < 8 | _id < < 10 | _id < < 12 | _id < < 14 ) ; \
} )
2017-08-21 14:00:16 +03:00
2019-08-24 06:02:05 +03:00
/* SMI COMMON */
# define SMI_BUS_SEL 0x220
# define SMI_BUS_LARB_SHIFT(larbid) ((larbid) << 1)
/* All are MMU0 defaultly. Only specialize mmu1 here. */
# define F_MMU1_LARB(larbid) (0x1 << SMI_BUS_LARB_SHIFT(larbid))
2019-08-24 06:01:49 +03:00
enum mtk_smi_gen {
MTK_SMI_GEN1 ,
MTK_SMI_GEN2
} ;
struct mtk_smi_common_plat {
enum mtk_smi_gen gen ;
2019-08-24 06:02:01 +03:00
bool has_gals ;
2019-08-24 06:02:05 +03:00
u32 bus_sel ; /* Balance some larbs to enter mmu0 or mmu1 */
2019-08-24 06:01:49 +03:00
} ;
2016-06-08 12:50:59 +03:00
struct mtk_smi_larb_gen {
int port_in_larb [ MTK_LARB_NR_MAX + 1 ] ;
2020-07-24 10:40:28 +03:00
void ( * config_port ) ( struct device * dev ) ;
2019-08-24 06:01:48 +03:00
unsigned int larb_direct_to_common_mask ;
2019-08-24 06:02:01 +03:00
bool has_gals ;
2016-06-08 12:50:59 +03:00
} ;
2016-02-22 20:20:49 +03:00
struct mtk_smi {
2016-06-08 12:50:59 +03:00
struct device * dev ;
struct clk * clk_apb , * clk_smi ;
2019-08-24 06:02:01 +03:00
struct clk * clk_gals0 , * clk_gals1 ;
2016-06-08 12:50:59 +03:00
struct clk * clk_async ; /*only needed by mt2701*/
2019-08-24 06:02:05 +03:00
union {
void __iomem * smi_ao_base ; /* only for gen1 */
void __iomem * base ; /* only for gen2 */
} ;
2019-08-24 06:01:49 +03:00
const struct mtk_smi_common_plat * plat ;
2016-02-22 20:20:49 +03:00
} ;
struct mtk_smi_larb { /* larb: local arbiter */
2016-06-08 12:50:59 +03:00
struct mtk_smi smi ;
void __iomem * base ;
struct device * smi_common_dev ;
const struct mtk_smi_larb_gen * larb_gen ;
int larbid ;
u32 * mmu ;
2021-01-11 14:19:11 +03:00
unsigned char * bank ;
2016-06-08 12:50:59 +03:00
} ;
2019-08-24 06:02:04 +03:00
static int mtk_smi_clk_enable ( const struct mtk_smi * smi )
2016-02-22 20:20:49 +03:00
{
int ret ;
ret = clk_prepare_enable ( smi - > clk_apb ) ;
if ( ret )
2019-08-24 06:02:04 +03:00
return ret ;
2016-02-22 20:20:49 +03:00
ret = clk_prepare_enable ( smi - > clk_smi ) ;
if ( ret )
goto err_disable_apb ;
2019-08-24 06:02:01 +03:00
ret = clk_prepare_enable ( smi - > clk_gals0 ) ;
if ( ret )
goto err_disable_smi ;
ret = clk_prepare_enable ( smi - > clk_gals1 ) ;
if ( ret )
goto err_disable_gals0 ;
2016-02-22 20:20:49 +03:00
return 0 ;
2019-08-24 06:02:01 +03:00
err_disable_gals0 :
clk_disable_unprepare ( smi - > clk_gals0 ) ;
err_disable_smi :
clk_disable_unprepare ( smi - > clk_smi ) ;
2016-02-22 20:20:49 +03:00
err_disable_apb :
clk_disable_unprepare ( smi - > clk_apb ) ;
return ret ;
}
2019-08-24 06:02:04 +03:00
static void mtk_smi_clk_disable ( const struct mtk_smi * smi )
2016-02-22 20:20:49 +03:00
{
2019-08-24 06:02:01 +03:00
clk_disable_unprepare ( smi - > clk_gals1 ) ;
clk_disable_unprepare ( smi - > clk_gals0 ) ;
2016-02-22 20:20:49 +03:00
clk_disable_unprepare ( smi - > clk_smi ) ;
clk_disable_unprepare ( smi - > clk_apb ) ;
}
int mtk_smi_larb_get ( struct device * larbdev )
{
2020-11-23 13:21:18 +03:00
int ret = pm_runtime_resume_and_get ( larbdev ) ;
2016-02-22 20:20:49 +03:00
2019-08-24 06:02:04 +03:00
return ( ret < 0 ) ? ret : 0 ;
2016-02-22 20:20:49 +03:00
}
2016-04-27 11:48:00 +03:00
EXPORT_SYMBOL_GPL ( mtk_smi_larb_get ) ;
2016-02-22 20:20:49 +03:00
void mtk_smi_larb_put ( struct device * larbdev )
{
2019-08-24 06:02:04 +03:00
pm_runtime_put_sync ( larbdev ) ;
2016-02-22 20:20:49 +03:00
}
2016-04-27 11:48:00 +03:00
EXPORT_SYMBOL_GPL ( mtk_smi_larb_put ) ;
2016-02-22 20:20:49 +03:00
static int
mtk_smi_larb_bind ( struct device * dev , struct device * master , void * data )
{
struct mtk_smi_larb * larb = dev_get_drvdata ( dev ) ;
2019-08-24 06:02:08 +03:00
struct mtk_smi_larb_iommu * larb_mmu = data ;
2016-02-22 20:20:49 +03:00
unsigned int i ;
2019-08-24 06:02:07 +03:00
for ( i = 0 ; i < MTK_LARB_NR_MAX ; i + + ) {
2019-08-24 06:02:08 +03:00
if ( dev = = larb_mmu [ i ] . dev ) {
2019-08-24 06:02:07 +03:00
larb - > larbid = i ;
2019-08-24 06:02:08 +03:00
larb - > mmu = & larb_mmu [ i ] . mmu ;
2021-01-11 14:19:11 +03:00
larb - > bank = larb_mmu [ i ] . bank ;
2016-02-22 20:20:49 +03:00
return 0 ;
}
}
return - ENODEV ;
}
2019-08-24 06:01:48 +03:00
static void mtk_smi_larb_config_port_gen2_general ( struct device * dev )
2016-06-08 12:50:59 +03:00
{
struct mtk_smi_larb * larb = dev_get_drvdata ( dev ) ;
2017-08-21 14:00:16 +03:00
u32 reg ;
int i ;
2016-06-08 12:50:59 +03:00
2019-08-24 06:01:48 +03:00
if ( BIT ( larb - > larbid ) & larb - > larb_gen - > larb_direct_to_common_mask )
2017-08-21 14:00:16 +03:00
return ;
for_each_set_bit ( i , ( unsigned long * ) larb - > mmu , 32 ) {
reg = readl_relaxed ( larb - > base + SMI_LARB_NONSEC_CON ( i ) ) ;
reg | = F_MMU_EN ;
2021-01-11 14:19:11 +03:00
reg | = BANK_SEL ( larb - > bank [ i ] ) ;
2017-08-21 14:00:16 +03:00
writel ( reg , larb - > base + SMI_LARB_NONSEC_CON ( i ) ) ;
}
2016-06-08 12:50:59 +03:00
}
2017-08-21 14:00:16 +03:00
static void mtk_smi_larb_config_port_mt8173 ( struct device * dev )
{
struct mtk_smi_larb * larb = dev_get_drvdata ( dev ) ;
writel ( * larb - > mmu , larb - > base + SMI_LARB_MMU_EN ) ;
}
2016-06-08 12:50:59 +03:00
2020-09-06 21:09:38 +03:00
static void mtk_smi_larb_config_port_mt8167 ( struct device * dev )
{
struct mtk_smi_larb * larb = dev_get_drvdata ( dev ) ;
writel ( * larb - > mmu , larb - > base + MT8167_SMI_LARB_MMU_EN ) ;
}
2016-06-08 12:50:59 +03:00
static void mtk_smi_larb_config_port_gen1 ( struct device * dev )
{
struct mtk_smi_larb * larb = dev_get_drvdata ( dev ) ;
const struct mtk_smi_larb_gen * larb_gen = larb - > larb_gen ;
struct mtk_smi * common = dev_get_drvdata ( larb - > smi_common_dev ) ;
int i , m4u_port_id , larb_port_num ;
u32 sec_con_val , reg_val ;
m4u_port_id = larb_gen - > port_in_larb [ larb - > larbid ] ;
larb_port_num = larb_gen - > port_in_larb [ larb - > larbid + 1 ]
- larb_gen - > port_in_larb [ larb - > larbid ] ;
for ( i = 0 ; i < larb_port_num ; i + + , m4u_port_id + + ) {
if ( * larb - > mmu & BIT ( i ) ) {
/* bit[port + 3] controls the virtual or physical */
sec_con_val = SMI_SECUR_CON_VAL_VIRT ( m4u_port_id ) ;
} else {
/* do not need to enable m4u for this port */
continue ;
}
reg_val = readl ( common - > smi_ao_base
+ REG_SMI_SECUR_CON_ADDR ( m4u_port_id ) ) ;
reg_val & = SMI_SECUR_CON_VAL_MSK ( m4u_port_id ) ;
reg_val | = sec_con_val ;
reg_val | = SMI_SECUR_CON_VAL_DOMAIN ( m4u_port_id ) ;
writel ( reg_val ,
common - > smi_ao_base
+ REG_SMI_SECUR_CON_ADDR ( m4u_port_id ) ) ;
}
}
2016-02-22 20:20:49 +03:00
static void
mtk_smi_larb_unbind ( struct device * dev , struct device * master , void * data )
{
/* Do nothing as the iommu is always enabled. */
}
static const struct component_ops mtk_smi_larb_component_ops = {
. bind = mtk_smi_larb_bind ,
. unbind = mtk_smi_larb_unbind ,
} ;
2016-06-08 12:50:59 +03:00
static const struct mtk_smi_larb_gen mtk_smi_larb_mt8173 = {
/* mt8173 do not need the port in larb */
2017-08-21 14:00:16 +03:00
. config_port = mtk_smi_larb_config_port_mt8173 ,
2016-06-08 12:50:59 +03:00
} ;
2020-09-06 21:09:38 +03:00
static const struct mtk_smi_larb_gen mtk_smi_larb_mt8167 = {
/* mt8167 do not need the port in larb */
. config_port = mtk_smi_larb_config_port_mt8167 ,
} ;
2016-06-08 12:50:59 +03:00
static const struct mtk_smi_larb_gen mtk_smi_larb_mt2701 = {
. port_in_larb = {
LARB0_PORT_OFFSET , LARB1_PORT_OFFSET ,
LARB2_PORT_OFFSET , LARB3_PORT_OFFSET
} ,
. config_port = mtk_smi_larb_config_port_gen1 ,
} ;
2017-08-21 14:00:16 +03:00
static const struct mtk_smi_larb_gen mtk_smi_larb_mt2712 = {
2019-08-24 06:01:48 +03:00
. config_port = mtk_smi_larb_config_port_gen2_general ,
. larb_direct_to_common_mask = BIT ( 8 ) | BIT ( 9 ) , /* bdpsys */
2017-08-21 14:00:16 +03:00
} ;
2020-01-08 09:41:30 +03:00
static const struct mtk_smi_larb_gen mtk_smi_larb_mt6779 = {
. config_port = mtk_smi_larb_config_port_gen2_general ,
. larb_direct_to_common_mask =
BIT ( 4 ) | BIT ( 6 ) | BIT ( 11 ) | BIT ( 12 ) | BIT ( 13 ) ,
/* DUMMY | IPU0 | IPU1 | CCU | MDLA */
} ;
2019-08-24 06:02:02 +03:00
static const struct mtk_smi_larb_gen mtk_smi_larb_mt8183 = {
. has_gals = true ,
. config_port = mtk_smi_larb_config_port_gen2_general ,
. larb_direct_to_common_mask = BIT ( 2 ) | BIT ( 3 ) | BIT ( 7 ) ,
/* IPU0 | IPU1 | CCU */
} ;
2020-11-03 08:42:00 +03:00
static const struct mtk_smi_larb_gen mtk_smi_larb_mt8192 = {
. config_port = mtk_smi_larb_config_port_gen2_general ,
} ;
2016-06-08 12:50:59 +03:00
static const struct of_device_id mtk_smi_larb_of_ids [ ] = {
2020-09-06 21:09:38 +03:00
{
. compatible = " mediatek,mt8167-smi-larb " ,
. data = & mtk_smi_larb_mt8167
} ,
2016-06-08 12:50:59 +03:00
{
. compatible = " mediatek,mt8173-smi-larb " ,
. data = & mtk_smi_larb_mt8173
} ,
{
. compatible = " mediatek,mt2701-smi-larb " ,
. data = & mtk_smi_larb_mt2701
} ,
2017-08-21 14:00:16 +03:00
{
. compatible = " mediatek,mt2712-smi-larb " ,
. data = & mtk_smi_larb_mt2712
} ,
2020-01-08 09:41:30 +03:00
{
. compatible = " mediatek,mt6779-smi-larb " ,
. data = & mtk_smi_larb_mt6779
} ,
2019-08-24 06:02:02 +03:00
{
. compatible = " mediatek,mt8183-smi-larb " ,
. data = & mtk_smi_larb_mt8183
} ,
2020-11-03 08:42:00 +03:00
{
. compatible = " mediatek,mt8192-smi-larb " ,
. data = & mtk_smi_larb_mt8192
} ,
2016-06-08 12:50:59 +03:00
{ }
} ;
2016-02-22 20:20:49 +03:00
static int mtk_smi_larb_probe ( struct platform_device * pdev )
{
struct mtk_smi_larb * larb ;
struct resource * res ;
struct device * dev = & pdev - > dev ;
struct device_node * smi_node ;
struct platform_device * smi_pdev ;
2021-04-10 12:11:16 +03:00
struct device_link * link ;
2016-02-22 20:20:49 +03:00
larb = devm_kzalloc ( dev , sizeof ( * larb ) , GFP_KERNEL ) ;
if ( ! larb )
return - ENOMEM ;
2017-08-04 04:32:25 +03:00
larb - > larb_gen = of_device_get_match_data ( dev ) ;
2016-02-22 20:20:49 +03:00
res = platform_get_resource ( pdev , IORESOURCE_MEM , 0 ) ;
larb - > base = devm_ioremap_resource ( dev , res ) ;
if ( IS_ERR ( larb - > base ) )
return PTR_ERR ( larb - > base ) ;
larb - > smi . clk_apb = devm_clk_get ( dev , " apb " ) ;
if ( IS_ERR ( larb - > smi . clk_apb ) )
return PTR_ERR ( larb - > smi . clk_apb ) ;
larb - > smi . clk_smi = devm_clk_get ( dev , " smi " ) ;
if ( IS_ERR ( larb - > smi . clk_smi ) )
return PTR_ERR ( larb - > smi . clk_smi ) ;
2019-08-24 06:02:01 +03:00
if ( larb - > larb_gen - > has_gals ) {
/* The larbs may still haven't gals even if the SoC support.*/
larb - > smi . clk_gals0 = devm_clk_get ( dev , " gals " ) ;
if ( PTR_ERR ( larb - > smi . clk_gals0 ) = = - ENOENT )
larb - > smi . clk_gals0 = NULL ;
else if ( IS_ERR ( larb - > smi . clk_gals0 ) )
return PTR_ERR ( larb - > smi . clk_gals0 ) ;
}
2016-02-22 20:20:49 +03:00
larb - > smi . dev = dev ;
smi_node = of_parse_phandle ( dev - > of_node , " mediatek,smi " , 0 ) ;
if ( ! smi_node )
return - EINVAL ;
smi_pdev = of_find_device_by_node ( smi_node ) ;
of_node_put ( smi_node ) ;
if ( smi_pdev ) {
2017-08-21 14:00:21 +03:00
if ( ! platform_get_drvdata ( smi_pdev ) )
return - EPROBE_DEFER ;
2016-02-22 20:20:49 +03:00
larb - > smi_common_dev = & smi_pdev - > dev ;
2021-04-10 12:11:16 +03:00
link = device_link_add ( dev , larb - > smi_common_dev ,
DL_FLAG_PM_RUNTIME | DL_FLAG_STATELESS ) ;
if ( ! link ) {
dev_err ( dev , " Unable to link smi-common dev \n " ) ;
return - ENODEV ;
}
2016-02-22 20:20:49 +03:00
} else {
dev_err ( dev , " Failed to get the smi_common device \n " ) ;
return - EINVAL ;
}
pm_runtime_enable ( dev ) ;
platform_set_drvdata ( pdev , larb ) ;
return component_add ( dev , & mtk_smi_larb_component_ops ) ;
}
static int mtk_smi_larb_remove ( struct platform_device * pdev )
{
2021-04-10 12:11:16 +03:00
struct mtk_smi_larb * larb = platform_get_drvdata ( pdev ) ;
device_link_remove ( & pdev - > dev , larb - > smi_common_dev ) ;
2016-02-22 20:20:49 +03:00
pm_runtime_disable ( & pdev - > dev ) ;
component_del ( & pdev - > dev , & mtk_smi_larb_component_ops ) ;
return 0 ;
}
2019-08-24 06:02:04 +03:00
static int __maybe_unused mtk_smi_larb_resume ( struct device * dev )
{
struct mtk_smi_larb * larb = dev_get_drvdata ( dev ) ;
const struct mtk_smi_larb_gen * larb_gen = larb - > larb_gen ;
int ret ;
ret = mtk_smi_clk_enable ( & larb - > smi ) ;
if ( ret < 0 ) {
dev_err ( dev , " Failed to enable clock(%d). \n " , ret ) ;
return ret ;
}
/* Configure the basic setting for this larb */
larb_gen - > config_port ( dev ) ;
return 0 ;
}
static int __maybe_unused mtk_smi_larb_suspend ( struct device * dev )
{
struct mtk_smi_larb * larb = dev_get_drvdata ( dev ) ;
mtk_smi_clk_disable ( & larb - > smi ) ;
return 0 ;
}
static const struct dev_pm_ops smi_larb_pm_ops = {
SET_RUNTIME_PM_OPS ( mtk_smi_larb_suspend , mtk_smi_larb_resume , NULL )
2019-10-09 14:59:33 +03:00
SET_LATE_SYSTEM_SLEEP_PM_OPS ( pm_runtime_force_suspend ,
pm_runtime_force_resume )
2019-08-24 06:02:04 +03:00
} ;
2016-02-22 20:20:49 +03:00
static struct platform_driver mtk_smi_larb_driver = {
. probe = mtk_smi_larb_probe ,
2016-06-08 12:50:59 +03:00
. remove = mtk_smi_larb_remove ,
2016-02-22 20:20:49 +03:00
. driver = {
. name = " mtk-smi-larb " ,
. of_match_table = mtk_smi_larb_of_ids ,
2019-08-24 06:02:04 +03:00
. pm = & smi_larb_pm_ops ,
2016-02-22 20:20:49 +03:00
}
} ;
2019-08-24 06:01:49 +03:00
static const struct mtk_smi_common_plat mtk_smi_common_gen1 = {
. gen = MTK_SMI_GEN1 ,
} ;
static const struct mtk_smi_common_plat mtk_smi_common_gen2 = {
. gen = MTK_SMI_GEN2 ,
} ;
2020-01-08 09:41:30 +03:00
static const struct mtk_smi_common_plat mtk_smi_common_mt6779 = {
. gen = MTK_SMI_GEN2 ,
. has_gals = true ,
. bus_sel = F_MMU1_LARB ( 1 ) | F_MMU1_LARB ( 2 ) | F_MMU1_LARB ( 4 ) |
F_MMU1_LARB ( 5 ) | F_MMU1_LARB ( 6 ) | F_MMU1_LARB ( 7 ) ,
} ;
2019-08-24 06:02:02 +03:00
static const struct mtk_smi_common_plat mtk_smi_common_mt8183 = {
. gen = MTK_SMI_GEN2 ,
. has_gals = true ,
2019-08-24 06:02:05 +03:00
. bus_sel = F_MMU1_LARB ( 1 ) | F_MMU1_LARB ( 2 ) | F_MMU1_LARB ( 5 ) |
F_MMU1_LARB ( 7 ) ,
2019-08-24 06:02:02 +03:00
} ;
2020-11-03 08:42:00 +03:00
static const struct mtk_smi_common_plat mtk_smi_common_mt8192 = {
. gen = MTK_SMI_GEN2 ,
. has_gals = true ,
. bus_sel = F_MMU1_LARB ( 1 ) | F_MMU1_LARB ( 2 ) | F_MMU1_LARB ( 5 ) |
F_MMU1_LARB ( 6 ) ,
} ;
2016-06-08 12:50:59 +03:00
static const struct of_device_id mtk_smi_common_of_ids [ ] = {
{
. compatible = " mediatek,mt8173-smi-common " ,
2019-08-24 06:01:49 +03:00
. data = & mtk_smi_common_gen2 ,
2016-06-08 12:50:59 +03:00
} ,
2020-09-06 21:09:38 +03:00
{
. compatible = " mediatek,mt8167-smi-common " ,
. data = & mtk_smi_common_gen2 ,
} ,
2016-06-08 12:50:59 +03:00
{
. compatible = " mediatek,mt2701-smi-common " ,
2019-08-24 06:01:49 +03:00
. data = & mtk_smi_common_gen1 ,
2016-06-08 12:50:59 +03:00
} ,
2017-08-21 14:00:16 +03:00
{
. compatible = " mediatek,mt2712-smi-common " ,
2019-08-24 06:01:49 +03:00
. data = & mtk_smi_common_gen2 ,
2017-08-21 14:00:16 +03:00
} ,
2020-01-08 09:41:30 +03:00
{
. compatible = " mediatek,mt6779-smi-common " ,
. data = & mtk_smi_common_mt6779 ,
} ,
2019-08-24 06:02:02 +03:00
{
. compatible = " mediatek,mt8183-smi-common " ,
. data = & mtk_smi_common_mt8183 ,
} ,
2020-11-03 08:42:00 +03:00
{
. compatible = " mediatek,mt8192-smi-common " ,
. data = & mtk_smi_common_mt8192 ,
} ,
2016-06-08 12:50:59 +03:00
{ }
} ;
2016-02-22 20:20:49 +03:00
static int mtk_smi_common_probe ( struct platform_device * pdev )
{
struct device * dev = & pdev - > dev ;
struct mtk_smi * common ;
2016-06-08 12:50:59 +03:00
struct resource * res ;
2017-08-10 08:17:32 +03:00
int ret ;
2016-02-22 20:20:49 +03:00
common = devm_kzalloc ( dev , sizeof ( * common ) , GFP_KERNEL ) ;
if ( ! common )
return - ENOMEM ;
common - > dev = dev ;
2019-08-24 06:01:49 +03:00
common - > plat = of_device_get_match_data ( dev ) ;
2016-02-22 20:20:49 +03:00
common - > clk_apb = devm_clk_get ( dev , " apb " ) ;
if ( IS_ERR ( common - > clk_apb ) )
return PTR_ERR ( common - > clk_apb ) ;
common - > clk_smi = devm_clk_get ( dev , " smi " ) ;
if ( IS_ERR ( common - > clk_smi ) )
return PTR_ERR ( common - > clk_smi ) ;
2019-08-24 06:02:01 +03:00
if ( common - > plat - > has_gals ) {
common - > clk_gals0 = devm_clk_get ( dev , " gals0 " ) ;
if ( IS_ERR ( common - > clk_gals0 ) )
return PTR_ERR ( common - > clk_gals0 ) ;
common - > clk_gals1 = devm_clk_get ( dev , " gals1 " ) ;
if ( IS_ERR ( common - > clk_gals1 ) )
return PTR_ERR ( common - > clk_gals1 ) ;
}
2016-06-08 12:50:59 +03:00
/*
* for mtk smi gen 1 , we need to get the ao ( always on ) base to config
* m4u port , and we need to enable the aync clock for transform the smi
* clock into emi clock domain , but for mtk smi gen2 , there ' s no smi ao
* base .
*/
2019-08-24 06:01:49 +03:00
if ( common - > plat - > gen = = MTK_SMI_GEN1 ) {
2016-06-08 12:50:59 +03:00
res = platform_get_resource ( pdev , IORESOURCE_MEM , 0 ) ;
common - > smi_ao_base = devm_ioremap_resource ( dev , res ) ;
if ( IS_ERR ( common - > smi_ao_base ) )
return PTR_ERR ( common - > smi_ao_base ) ;
common - > clk_async = devm_clk_get ( dev , " async " ) ;
if ( IS_ERR ( common - > clk_async ) )
return PTR_ERR ( common - > clk_async ) ;
2017-08-10 08:17:32 +03:00
ret = clk_prepare_enable ( common - > clk_async ) ;
if ( ret )
return ret ;
2019-08-24 06:02:05 +03:00
} else {
res = platform_get_resource ( pdev , IORESOURCE_MEM , 0 ) ;
common - > base = devm_ioremap_resource ( dev , res ) ;
if ( IS_ERR ( common - > base ) )
return PTR_ERR ( common - > base ) ;
2016-06-08 12:50:59 +03:00
}
2016-02-22 20:20:49 +03:00
pm_runtime_enable ( dev ) ;
platform_set_drvdata ( pdev , common ) ;
return 0 ;
}
static int mtk_smi_common_remove ( struct platform_device * pdev )
{
pm_runtime_disable ( & pdev - > dev ) ;
return 0 ;
}
2019-08-24 06:02:04 +03:00
static int __maybe_unused mtk_smi_common_resume ( struct device * dev )
{
struct mtk_smi * common = dev_get_drvdata ( dev ) ;
2019-08-24 06:02:05 +03:00
u32 bus_sel = common - > plat - > bus_sel ;
2019-08-24 06:02:04 +03:00
int ret ;
ret = mtk_smi_clk_enable ( common ) ;
if ( ret ) {
dev_err ( common - > dev , " Failed to enable clock(%d). \n " , ret ) ;
return ret ;
}
2019-08-24 06:02:05 +03:00
if ( common - > plat - > gen = = MTK_SMI_GEN2 & & bus_sel )
writel ( bus_sel , common - > base + SMI_BUS_SEL ) ;
2019-08-24 06:02:04 +03:00
return 0 ;
}
static int __maybe_unused mtk_smi_common_suspend ( struct device * dev )
{
struct mtk_smi * common = dev_get_drvdata ( dev ) ;
mtk_smi_clk_disable ( common ) ;
return 0 ;
}
static const struct dev_pm_ops smi_common_pm_ops = {
SET_RUNTIME_PM_OPS ( mtk_smi_common_suspend , mtk_smi_common_resume , NULL )
2019-10-09 14:59:33 +03:00
SET_LATE_SYSTEM_SLEEP_PM_OPS ( pm_runtime_force_suspend ,
pm_runtime_force_resume )
2019-08-24 06:02:04 +03:00
} ;
2016-02-22 20:20:49 +03:00
static struct platform_driver mtk_smi_common_driver = {
. probe = mtk_smi_common_probe ,
. remove = mtk_smi_common_remove ,
. driver = {
. name = " mtk-smi-common " ,
. of_match_table = mtk_smi_common_of_ids ,
2019-08-24 06:02:04 +03:00
. pm = & smi_common_pm_ops ,
2016-02-22 20:20:49 +03:00
}
} ;
2021-01-21 09:24:27 +03:00
static struct platform_driver * const smidrivers [ ] = {
& mtk_smi_common_driver ,
& mtk_smi_larb_driver ,
} ;
2016-02-22 20:20:49 +03:00
static int __init mtk_smi_init ( void )
{
2021-01-21 09:24:27 +03:00
return platform_register_drivers ( smidrivers , ARRAY_SIZE ( smidrivers ) ) ;
2016-02-22 20:20:49 +03:00
}
2017-08-21 14:00:21 +03:00
module_init ( mtk_smi_init ) ;
2021-01-26 09:00:55 +03:00
static void __exit mtk_smi_exit ( void )
{
platform_unregister_drivers ( smidrivers , ARRAY_SIZE ( smidrivers ) ) ;
}
module_exit ( mtk_smi_exit ) ;
MODULE_DESCRIPTION ( " MediaTek SMI driver " ) ;
MODULE_LICENSE ( " GPL v2 " ) ;