2019-05-13 11:01:38 +00:00
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright 2019 NXP
*/
# include <linux/cpu.h>
# include <linux/err.h>
# include <linux/init.h>
# include <linux/kernel.h>
# include <linux/module.h>
# include <linux/nvmem-consumer.h>
# include <linux/of.h>
# include <linux/platform_device.h>
# include <linux/pm_opp.h>
# include <linux/slab.h>
# define OCOTP_CFG3_SPEED_GRADE_SHIFT 8
# define OCOTP_CFG3_SPEED_GRADE_MASK (0x3 << 8)
2019-08-18 02:32:22 -04:00
# define IMX8MN_OCOTP_CFG3_SPEED_GRADE_MASK (0xf << 8)
2019-05-13 11:01:38 +00:00
# define OCOTP_CFG3_MKT_SEGMENT_SHIFT 6
# define OCOTP_CFG3_MKT_SEGMENT_MASK (0x3 << 6)
2020-03-10 13:48:16 +08:00
# define IMX8MP_OCOTP_CFG3_MKT_SEGMENT_SHIFT 5
# define IMX8MP_OCOTP_CFG3_MKT_SEGMENT_MASK (0x3 << 5)
2019-05-13 11:01:38 +00:00
/* cpufreq-dt device registered by imx-cpufreq-dt */
static struct platform_device * cpufreq_dt_pdev ;
static struct opp_table * cpufreq_opp_table ;
static int imx_cpufreq_dt_probe ( struct platform_device * pdev )
{
struct device * cpu_dev = get_cpu_device ( 0 ) ;
u32 cell_value , supported_hw [ 2 ] ;
int speed_grade , mkt_segment ;
int ret ;
2020-02-17 17:42:55 +08:00
if ( ! of_find_property ( cpu_dev - > of_node , " cpu-supply " , NULL ) )
return - ENODEV ;
2019-05-13 11:01:38 +00:00
ret = nvmem_cell_read_u32 ( cpu_dev , " speed_grade " , & cell_value ) ;
if ( ret )
return ret ;
2019-12-26 14:52:47 +08:00
if ( of_machine_is_compatible ( " fsl,imx8mn " ) | |
of_machine_is_compatible ( " fsl,imx8mp " ) )
2019-08-18 02:32:22 -04:00
speed_grade = ( cell_value & IMX8MN_OCOTP_CFG3_SPEED_GRADE_MASK )
> > OCOTP_CFG3_SPEED_GRADE_SHIFT ;
else
speed_grade = ( cell_value & OCOTP_CFG3_SPEED_GRADE_MASK )
> > OCOTP_CFG3_SPEED_GRADE_SHIFT ;
2020-03-10 13:48:16 +08:00
if ( of_machine_is_compatible ( " fsl,imx8mp " ) )
mkt_segment = ( cell_value & IMX8MP_OCOTP_CFG3_MKT_SEGMENT_MASK )
> > IMX8MP_OCOTP_CFG3_MKT_SEGMENT_SHIFT ;
else
mkt_segment = ( cell_value & OCOTP_CFG3_MKT_SEGMENT_MASK )
> > OCOTP_CFG3_MKT_SEGMENT_SHIFT ;
2019-05-29 11:52:08 +00:00
/*
2019-10-22 16:33:19 +08:00
* Early samples without fuses written report " 0 0 " which may NOT
* match any OPP defined in DT . So clamp to minimum OPP defined in
* DT to avoid warning for " no OPPs " .
2019-05-29 11:52:08 +00:00
*
2019-07-08 11:03:08 +08:00
* Applies to i . MX8M series SoCs .
2019-05-29 11:52:08 +00:00
*/
2019-10-22 16:33:19 +08:00
if ( mkt_segment = = 0 & & speed_grade = = 0 ) {
if ( of_machine_is_compatible ( " fsl,imx8mm " ) | |
of_machine_is_compatible ( " fsl,imx8mq " ) )
speed_grade = 1 ;
2019-12-26 14:52:47 +08:00
if ( of_machine_is_compatible ( " fsl,imx8mn " ) | |
of_machine_is_compatible ( " fsl,imx8mp " ) )
2019-10-22 16:33:19 +08:00
speed_grade = 0xb ;
}
2019-05-29 11:52:08 +00:00
2019-05-13 11:01:38 +00:00
supported_hw [ 0 ] = BIT ( speed_grade ) ;
supported_hw [ 1 ] = BIT ( mkt_segment ) ;
dev_info ( & pdev - > dev , " cpu speed grade %d mkt segment %d supported-hw %#x %#x \n " ,
speed_grade , mkt_segment , supported_hw [ 0 ] , supported_hw [ 1 ] ) ;
cpufreq_opp_table = dev_pm_opp_set_supported_hw ( cpu_dev , supported_hw , 2 ) ;
if ( IS_ERR ( cpufreq_opp_table ) ) {
ret = PTR_ERR ( cpufreq_opp_table ) ;
dev_err ( & pdev - > dev , " Failed to set supported opp: %d \n " , ret ) ;
return ret ;
}
cpufreq_dt_pdev = platform_device_register_data (
& pdev - > dev , " cpufreq-dt " , - 1 , NULL , 0 ) ;
if ( IS_ERR ( cpufreq_dt_pdev ) ) {
dev_pm_opp_put_supported_hw ( cpufreq_opp_table ) ;
ret = PTR_ERR ( cpufreq_dt_pdev ) ;
dev_err ( & pdev - > dev , " Failed to register cpufreq-dt: %d \n " , ret ) ;
return ret ;
}
return 0 ;
}
static int imx_cpufreq_dt_remove ( struct platform_device * pdev )
{
platform_device_unregister ( cpufreq_dt_pdev ) ;
dev_pm_opp_put_supported_hw ( cpufreq_opp_table ) ;
return 0 ;
}
static struct platform_driver imx_cpufreq_dt_driver = {
. probe = imx_cpufreq_dt_probe ,
. remove = imx_cpufreq_dt_remove ,
. driver = {
. name = " imx-cpufreq-dt " ,
} ,
} ;
module_platform_driver ( imx_cpufreq_dt_driver ) ;
MODULE_ALIAS ( " platform:imx-cpufreq-dt " ) ;
MODULE_DESCRIPTION ( " Freescale i.MX cpufreq speed grading driver " ) ;
MODULE_LICENSE ( " GPL v2 " ) ;