2016-07-04 11:01:56 -04:00
/*
* Qualcomm SCM driver
*
* Copyright ( c ) 2010 , 2015 , The Linux Foundation . All rights reserved .
2015-03-02 16:30:29 -07:00
* Copyright ( C ) 2015 Linaro Ltd .
2010-08-27 10:01:23 -07:00
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License version 2 and
* only 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 .
*
*/
2016-06-03 18:25:22 -05:00
# include <linux/platform_device.h>
2016-07-04 11:01:56 -04:00
# include <linux/init.h>
2015-03-11 16:28:10 -05:00
# include <linux/cpumask.h>
# include <linux/export.h>
2015-09-23 12:56:12 -07:00
# include <linux/dma-mapping.h>
2017-08-14 15:46:18 -07:00
# include <linux/module.h>
2015-03-11 16:28:10 -05:00
# include <linux/types.h>
2015-02-26 15:49:09 -06:00
# include <linux/qcom_scm.h>
2016-06-03 18:25:22 -05:00
# include <linux/of.h>
2017-08-14 15:46:18 -07:00
# include <linux/of_address.h>
2016-06-03 18:25:22 -05:00
# include <linux/of_platform.h>
# include <linux/clk.h>
2016-06-17 10:40:43 -07:00
# include <linux/reset-controller.h>
2010-08-27 10:01:23 -07:00
2015-03-11 16:28:10 -05:00
# include "qcom_scm.h"
2015-03-02 16:30:28 -07:00
2017-08-14 15:46:18 -07:00
static bool download_mode = IS_ENABLED ( CONFIG_QCOM_SCM_DOWNLOAD_MODE_DEFAULT ) ;
module_param ( download_mode , bool , 0 ) ;
2016-11-15 17:19:24 -08:00
# define SCM_HAS_CORE_CLK BIT(0)
# define SCM_HAS_IFACE_CLK BIT(1)
# define SCM_HAS_BUS_CLK BIT(2)
2016-06-03 18:25:22 -05:00
struct qcom_scm {
struct device * dev ;
struct clk * core_clk ;
struct clk * iface_clk ;
struct clk * bus_clk ;
2016-06-17 10:40:43 -07:00
struct reset_controller_dev reset ;
2017-08-14 15:46:18 -07:00
u64 dload_mode_addr ;
2016-06-03 18:25:22 -05:00
} ;
2017-10-24 21:22:24 +05:30
struct qcom_scm_current_perm_info {
__le32 vmid ;
__le32 perm ;
__le64 ctx ;
__le32 ctx_size ;
__le32 unused ;
} ;
struct qcom_scm_mem_map_info {
__le64 mem_addr ;
__le64 mem_size ;
} ;
2016-06-03 18:25:22 -05:00
static struct qcom_scm * __scm ;
static int qcom_scm_clk_enable ( void )
{
int ret ;
ret = clk_prepare_enable ( __scm - > core_clk ) ;
if ( ret )
goto bail ;
ret = clk_prepare_enable ( __scm - > iface_clk ) ;
if ( ret )
goto disable_core ;
ret = clk_prepare_enable ( __scm - > bus_clk ) ;
if ( ret )
goto disable_iface ;
return 0 ;
disable_iface :
clk_disable_unprepare ( __scm - > iface_clk ) ;
disable_core :
clk_disable_unprepare ( __scm - > core_clk ) ;
bail :
return ret ;
}
static void qcom_scm_clk_disable ( void )
{
clk_disable_unprepare ( __scm - > core_clk ) ;
clk_disable_unprepare ( __scm - > iface_clk ) ;
clk_disable_unprepare ( __scm - > bus_clk ) ;
}
2015-03-02 16:30:28 -07:00
/**
* qcom_scm_set_cold_boot_addr ( ) - Set the cold boot address for cpus
* @ entry : Entry point function for the cpus
* @ cpus : The cpumask of cpus that will use the entry point
*
* Set the cold boot address of the cpus . Any cpu outside the supported
* range would be removed from the cpu present mask .
*/
int qcom_scm_set_cold_boot_addr ( void * entry , const cpumask_t * cpus )
{
2015-03-11 16:28:10 -05:00
return __qcom_scm_set_cold_boot_addr ( entry , cpus ) ;
2015-03-02 16:30:28 -07:00
}
EXPORT_SYMBOL ( qcom_scm_set_cold_boot_addr ) ;
2015-03-02 16:30:29 -07:00
/**
* qcom_scm_set_warm_boot_addr ( ) - Set the warm boot address for cpus
* @ entry : Entry point function for the cpus
* @ cpus : The cpumask of cpus that will use the entry point
*
* Set the Linux entry point for the SCM to transfer control to when coming
* out of a power down . CPU power down may be executed on cpuidle or hotplug .
*/
int qcom_scm_set_warm_boot_addr ( void * entry , const cpumask_t * cpus )
{
2016-06-03 18:25:25 -05:00
return __qcom_scm_set_warm_boot_addr ( __scm - > dev , entry , cpus ) ;
2015-03-02 16:30:29 -07:00
}
EXPORT_SYMBOL ( qcom_scm_set_warm_boot_addr ) ;
2015-03-02 16:30:30 -07:00
/**
* qcom_scm_cpu_power_down ( ) - Power down the cpu
* @ flags - Flags to flush cache
*
* This is an end point to power down cpu . If there was a pending interrupt ,
* the control would return from this function , otherwise , the cpu jumps to the
* warm boot entry point set for this cpu upon reset .
*/
void qcom_scm_cpu_power_down ( u32 flags )
{
2015-03-11 16:28:10 -05:00
__qcom_scm_cpu_power_down ( flags ) ;
2015-03-02 16:30:30 -07:00
}
EXPORT_SYMBOL ( qcom_scm_cpu_power_down ) ;
2015-04-10 16:15:59 -04:00
/**
* qcom_scm_hdcp_available ( ) - Check if secure environment supports HDCP .
*
* Return true if HDCP is supported , false if not .
*/
bool qcom_scm_hdcp_available ( void )
{
2016-06-03 18:25:22 -05:00
int ret = qcom_scm_clk_enable ( ) ;
if ( ret )
return ret ;
2015-04-10 16:15:59 -04:00
2016-06-03 18:25:25 -05:00
ret = __qcom_scm_is_call_available ( __scm - > dev , QCOM_SCM_SVC_HDCP ,
2016-06-03 18:25:22 -05:00
QCOM_SCM_CMD_HDCP ) ;
qcom_scm_clk_disable ( ) ;
2015-04-10 16:15:59 -04:00
2016-06-03 18:25:22 -05:00
return ret > 0 ? true : false ;
2015-04-10 16:15:59 -04:00
}
EXPORT_SYMBOL ( qcom_scm_hdcp_available ) ;
/**
* qcom_scm_hdcp_req ( ) - Send HDCP request .
* @ req : HDCP request array
* @ req_cnt : HDCP request array count
* @ resp : response buffer passed to SCM
*
* Write HDCP register ( s ) through SCM .
*/
int qcom_scm_hdcp_req ( struct qcom_scm_hdcp_req * req , u32 req_cnt , u32 * resp )
{
2016-06-03 18:25:22 -05:00
int ret = qcom_scm_clk_enable ( ) ;
if ( ret )
return ret ;
2016-06-03 18:25:25 -05:00
ret = __qcom_scm_hdcp_req ( __scm - > dev , req , req_cnt , resp ) ;
2016-06-03 18:25:22 -05:00
qcom_scm_clk_disable ( ) ;
return ret ;
2015-04-10 16:15:59 -04:00
}
EXPORT_SYMBOL ( qcom_scm_hdcp_req ) ;
2016-06-03 18:25:22 -05:00
2015-09-23 12:56:12 -07:00
/**
* qcom_scm_pas_supported ( ) - Check if the peripheral authentication service is
* available for the given peripherial
* @ peripheral : peripheral id
*
* Returns true if PAS is supported for this peripheral , otherwise false .
*/
bool qcom_scm_pas_supported ( u32 peripheral )
{
int ret ;
ret = __qcom_scm_is_call_available ( __scm - > dev , QCOM_SCM_SVC_PIL ,
QCOM_SCM_PAS_IS_SUPPORTED_CMD ) ;
if ( ret < = 0 )
return false ;
return __qcom_scm_pas_supported ( __scm - > dev , peripheral ) ;
}
EXPORT_SYMBOL ( qcom_scm_pas_supported ) ;
/**
* qcom_scm_pas_init_image ( ) - Initialize peripheral authentication service
* state machine for a given peripheral , using the
* metadata
* @ peripheral : peripheral id
* @ metadata : pointer to memory containing ELF header , program header table
* and optional blob of data used for authenticating the metadata
* and the rest of the firmware
* @ size : size of the metadata
*
* Returns 0 on success .
*/
int qcom_scm_pas_init_image ( u32 peripheral , const void * metadata , size_t size )
{
dma_addr_t mdata_phys ;
void * mdata_buf ;
int ret ;
/*
* During the scm call memory protection will be enabled for the meta
* data blob , so make sure it ' s physically contiguous , 4 K aligned and
* non - cachable to avoid XPU violations .
*/
mdata_buf = dma_alloc_coherent ( __scm - > dev , size , & mdata_phys ,
GFP_KERNEL ) ;
if ( ! mdata_buf ) {
dev_err ( __scm - > dev , " Allocation of metadata buffer failed. \n " ) ;
return - ENOMEM ;
}
memcpy ( mdata_buf , metadata , size ) ;
ret = qcom_scm_clk_enable ( ) ;
if ( ret )
goto free_metadata ;
ret = __qcom_scm_pas_init_image ( __scm - > dev , peripheral , mdata_phys ) ;
qcom_scm_clk_disable ( ) ;
free_metadata :
dma_free_coherent ( __scm - > dev , size , mdata_buf , mdata_phys ) ;
return ret ;
}
EXPORT_SYMBOL ( qcom_scm_pas_init_image ) ;
/**
* qcom_scm_pas_mem_setup ( ) - Prepare the memory related to a given peripheral
* for firmware loading
* @ peripheral : peripheral id
* @ addr : start address of memory area to prepare
* @ size : size of the memory area to prepare
*
* Returns 0 on success .
*/
int qcom_scm_pas_mem_setup ( u32 peripheral , phys_addr_t addr , phys_addr_t size )
{
int ret ;
ret = qcom_scm_clk_enable ( ) ;
if ( ret )
return ret ;
ret = __qcom_scm_pas_mem_setup ( __scm - > dev , peripheral , addr , size ) ;
qcom_scm_clk_disable ( ) ;
return ret ;
}
EXPORT_SYMBOL ( qcom_scm_pas_mem_setup ) ;
/**
* qcom_scm_pas_auth_and_reset ( ) - Authenticate the given peripheral firmware
* and reset the remote processor
* @ peripheral : peripheral id
*
* Return 0 on success .
*/
int qcom_scm_pas_auth_and_reset ( u32 peripheral )
{
int ret ;
ret = qcom_scm_clk_enable ( ) ;
if ( ret )
return ret ;
ret = __qcom_scm_pas_auth_and_reset ( __scm - > dev , peripheral ) ;
qcom_scm_clk_disable ( ) ;
return ret ;
}
EXPORT_SYMBOL ( qcom_scm_pas_auth_and_reset ) ;
/**
* qcom_scm_pas_shutdown ( ) - Shut down the remote processor
* @ peripheral : peripheral id
*
* Returns 0 on success .
*/
int qcom_scm_pas_shutdown ( u32 peripheral )
{
int ret ;
ret = qcom_scm_clk_enable ( ) ;
if ( ret )
return ret ;
ret = __qcom_scm_pas_shutdown ( __scm - > dev , peripheral ) ;
qcom_scm_clk_disable ( ) ;
return ret ;
}
EXPORT_SYMBOL ( qcom_scm_pas_shutdown ) ;
2016-06-17 10:40:43 -07:00
static int qcom_scm_pas_reset_assert ( struct reset_controller_dev * rcdev ,
unsigned long idx )
{
if ( idx ! = 0 )
return - EINVAL ;
return __qcom_scm_pas_mss_reset ( __scm - > dev , 1 ) ;
}
static int qcom_scm_pas_reset_deassert ( struct reset_controller_dev * rcdev ,
unsigned long idx )
{
if ( idx ! = 0 )
return - EINVAL ;
return __qcom_scm_pas_mss_reset ( __scm - > dev , 0 ) ;
}
static const struct reset_control_ops qcom_scm_pas_reset_ops = {
. assert = qcom_scm_pas_reset_assert ,
. deassert = qcom_scm_pas_reset_deassert ,
} ;
2017-03-14 11:18:03 -04:00
int qcom_scm_restore_sec_cfg ( u32 device_id , u32 spare )
{
return __qcom_scm_restore_sec_cfg ( __scm - > dev , device_id , spare ) ;
}
EXPORT_SYMBOL ( qcom_scm_restore_sec_cfg ) ;
2017-03-14 11:18:04 -04:00
int qcom_scm_iommu_secure_ptbl_size ( u32 spare , size_t * size )
{
return __qcom_scm_iommu_secure_ptbl_size ( __scm - > dev , spare , size ) ;
}
EXPORT_SYMBOL ( qcom_scm_iommu_secure_ptbl_size ) ;
int qcom_scm_iommu_secure_ptbl_init ( u64 addr , u32 size , u32 spare )
{
return __qcom_scm_iommu_secure_ptbl_init ( __scm - > dev , addr , size , spare ) ;
}
EXPORT_SYMBOL ( qcom_scm_iommu_secure_ptbl_init ) ;
2017-08-14 15:46:17 -07:00
int qcom_scm_io_readl ( phys_addr_t addr , unsigned int * val )
{
return __qcom_scm_io_readl ( __scm - > dev , addr , val ) ;
}
EXPORT_SYMBOL ( qcom_scm_io_readl ) ;
int qcom_scm_io_writel ( phys_addr_t addr , unsigned int val )
{
return __qcom_scm_io_writel ( __scm - > dev , addr , val ) ;
}
EXPORT_SYMBOL ( qcom_scm_io_writel ) ;
2017-08-14 15:46:18 -07:00
static void qcom_scm_set_download_mode ( bool enable )
{
bool avail ;
int ret = 0 ;
avail = __qcom_scm_is_call_available ( __scm - > dev ,
QCOM_SCM_SVC_BOOT ,
QCOM_SCM_SET_DLOAD_MODE ) ;
if ( avail ) {
ret = __qcom_scm_set_dload_mode ( __scm - > dev , enable ) ;
} else if ( __scm - > dload_mode_addr ) {
ret = __qcom_scm_io_writel ( __scm - > dev , __scm - > dload_mode_addr ,
enable ? QCOM_SCM_SET_DLOAD_MODE : 0 ) ;
} else {
dev_err ( __scm - > dev ,
" No available mechanism for setting download mode \n " ) ;
}
if ( ret )
dev_err ( __scm - > dev , " failed to set download mode: %d \n " , ret ) ;
}
static int qcom_scm_find_dload_address ( struct device * dev , u64 * addr )
{
struct device_node * tcsr ;
struct device_node * np = dev - > of_node ;
struct resource res ;
u32 offset ;
int ret ;
tcsr = of_parse_phandle ( np , " qcom,dload-mode " , 0 ) ;
if ( ! tcsr )
return 0 ;
ret = of_address_to_resource ( tcsr , 0 , & res ) ;
of_node_put ( tcsr ) ;
if ( ret )
return ret ;
ret = of_property_read_u32_index ( np , " qcom,dload-mode " , 1 , & offset ) ;
if ( ret < 0 )
return ret ;
* addr = res . start + offset ;
return 0 ;
}
2016-06-29 15:28:29 -05:00
/**
* qcom_scm_is_available ( ) - Checks if SCM is available
*/
bool qcom_scm_is_available ( void )
{
return ! ! __scm ;
}
EXPORT_SYMBOL ( qcom_scm_is_available ) ;
2016-06-17 10:40:43 -07:00
2017-01-16 23:24:15 -06:00
int qcom_scm_set_remote_state ( u32 state , u32 id )
{
return __qcom_scm_set_remote_state ( __scm - > dev , state , id ) ;
}
EXPORT_SYMBOL ( qcom_scm_set_remote_state ) ;
2017-10-24 21:22:24 +05:30
/**
* qcom_scm_assign_mem ( ) - Make a secure call to reassign memory ownership
* @ mem_addr : mem region whose ownership need to be reassigned
* @ mem_sz : size of the region .
* @ srcvm : vmid for current set of owners , each set bit in
* flag indicate a unique owner
* @ newvm : array having new owners and corrsponding permission
* flags
* @ dest_cnt : number of owners in next set .
*
* Return negative errno on failure , 0 on success , with @ srcvm updated .
*/
int qcom_scm_assign_mem ( phys_addr_t mem_addr , size_t mem_sz ,
unsigned int * srcvm ,
struct qcom_scm_vmperm * newvm , int dest_cnt )
{
struct qcom_scm_current_perm_info * destvm ;
struct qcom_scm_mem_map_info * mem_to_map ;
phys_addr_t mem_to_map_phys ;
phys_addr_t dest_phys ;
phys_addr_t ptr_phys ;
size_t mem_to_map_sz ;
size_t dest_sz ;
size_t src_sz ;
size_t ptr_sz ;
int next_vm ;
__le32 * src ;
void * ptr ;
int ret ;
int len ;
int i ;
src_sz = hweight_long ( * srcvm ) * sizeof ( * src ) ;
mem_to_map_sz = sizeof ( * mem_to_map ) ;
dest_sz = dest_cnt * sizeof ( * destvm ) ;
ptr_sz = ALIGN ( src_sz , SZ_64 ) + ALIGN ( mem_to_map_sz , SZ_64 ) +
ALIGN ( dest_sz , SZ_64 ) ;
ptr = dma_alloc_coherent ( __scm - > dev , ptr_sz , & ptr_phys , GFP_KERNEL ) ;
if ( ! ptr )
return - ENOMEM ;
/* Fill source vmid detail */
src = ptr ;
len = hweight_long ( * srcvm ) ;
for ( i = 0 ; i < len ; i + + ) {
src [ i ] = cpu_to_le32 ( ffs ( * srcvm ) - 1 ) ;
* srcvm ^ = 1 < < ( ffs ( * srcvm ) - 1 ) ;
}
/* Fill details of mem buff to map */
mem_to_map = ptr + ALIGN ( src_sz , SZ_64 ) ;
mem_to_map_phys = ptr_phys + ALIGN ( src_sz , SZ_64 ) ;
mem_to_map [ 0 ] . mem_addr = cpu_to_le64 ( mem_addr ) ;
mem_to_map [ 0 ] . mem_size = cpu_to_le64 ( mem_sz ) ;
next_vm = 0 ;
/* Fill details of next vmid detail */
destvm = ptr + ALIGN ( mem_to_map_sz , SZ_64 ) + ALIGN ( src_sz , SZ_64 ) ;
dest_phys = ptr_phys + ALIGN ( mem_to_map_sz , SZ_64 ) + ALIGN ( src_sz , SZ_64 ) ;
for ( i = 0 ; i < dest_cnt ; i + + ) {
destvm [ i ] . vmid = cpu_to_le32 ( newvm [ i ] . vmid ) ;
destvm [ i ] . perm = cpu_to_le32 ( newvm [ i ] . perm ) ;
destvm [ i ] . ctx = 0 ;
destvm [ i ] . ctx_size = 0 ;
next_vm | = BIT ( newvm [ i ] . vmid ) ;
}
ret = __qcom_scm_assign_mem ( __scm - > dev , mem_to_map_phys , mem_to_map_sz ,
ptr_phys , src_sz , dest_phys , dest_sz ) ;
dma_free_coherent ( __scm - > dev , ALIGN ( ptr_sz , SZ_64 ) , ptr , ptr_phys ) ;
if ( ret ) {
dev_err ( __scm - > dev ,
" Assign memory protection call failed %d. \n " , ret ) ;
return - EINVAL ;
}
* srcvm = next_vm ;
return 0 ;
}
EXPORT_SYMBOL ( qcom_scm_assign_mem ) ;
2016-06-03 18:25:22 -05:00
static int qcom_scm_probe ( struct platform_device * pdev )
{
struct qcom_scm * scm ;
2016-11-15 17:19:24 -08:00
unsigned long clks ;
2016-06-03 18:25:22 -05:00
int ret ;
scm = devm_kzalloc ( & pdev - > dev , sizeof ( * scm ) , GFP_KERNEL ) ;
if ( ! scm )
return - ENOMEM ;
2017-08-14 15:46:18 -07:00
ret = qcom_scm_find_dload_address ( & pdev - > dev , & scm - > dload_mode_addr ) ;
if ( ret < 0 )
return ret ;
2016-11-15 17:19:24 -08:00
clks = ( unsigned long ) of_device_get_match_data ( & pdev - > dev ) ;
if ( clks & SCM_HAS_CORE_CLK ) {
scm - > core_clk = devm_clk_get ( & pdev - > dev , " core " ) ;
if ( IS_ERR ( scm - > core_clk ) ) {
2016-11-15 17:19:25 -08:00
if ( PTR_ERR ( scm - > core_clk ) ! = - EPROBE_DEFER )
dev_err ( & pdev - > dev ,
" failed to acquire core clk \n " ) ;
return PTR_ERR ( scm - > core_clk ) ;
2016-11-15 17:19:24 -08:00
}
2016-06-03 18:25:22 -05:00
}
2016-11-15 17:19:24 -08:00
if ( clks & SCM_HAS_IFACE_CLK ) {
2016-06-03 18:25:22 -05:00
scm - > iface_clk = devm_clk_get ( & pdev - > dev , " iface " ) ;
if ( IS_ERR ( scm - > iface_clk ) ) {
if ( PTR_ERR ( scm - > iface_clk ) ! = - EPROBE_DEFER )
2016-11-15 17:19:24 -08:00
dev_err ( & pdev - > dev ,
" failed to acquire iface clk \n " ) ;
2016-06-03 18:25:22 -05:00
return PTR_ERR ( scm - > iface_clk ) ;
}
2016-11-15 17:19:24 -08:00
}
2016-06-03 18:25:22 -05:00
2016-11-15 17:19:24 -08:00
if ( clks & SCM_HAS_BUS_CLK ) {
2016-06-03 18:25:22 -05:00
scm - > bus_clk = devm_clk_get ( & pdev - > dev , " bus " ) ;
if ( IS_ERR ( scm - > bus_clk ) ) {
if ( PTR_ERR ( scm - > bus_clk ) ! = - EPROBE_DEFER )
2016-11-15 17:19:24 -08:00
dev_err ( & pdev - > dev ,
" failed to acquire bus clk \n " ) ;
2016-06-03 18:25:22 -05:00
return PTR_ERR ( scm - > bus_clk ) ;
}
}
2016-06-17 10:40:43 -07:00
scm - > reset . ops = & qcom_scm_pas_reset_ops ;
scm - > reset . nr_resets = 1 ;
scm - > reset . of_node = pdev - > dev . of_node ;
2016-08-28 16:29:10 +00:00
ret = devm_reset_controller_register ( & pdev - > dev , & scm - > reset ) ;
if ( ret )
return ret ;
2016-06-17 10:40:43 -07:00
2016-06-03 18:25:22 -05:00
/* vote for max clk rate for highest performance */
ret = clk_set_rate ( scm - > core_clk , INT_MAX ) ;
if ( ret )
return ret ;
__scm = scm ;
__scm - > dev = & pdev - > dev ;
2016-06-03 18:25:26 -05:00
__qcom_scm_init ( ) ;
2017-08-14 15:46:18 -07:00
/*
* If requested enable " download mode " , from this point on warmboot
* will cause the the boot stages to enter download mode , unless
* disabled below by a clean shutdown / reboot .
*/
if ( download_mode )
qcom_scm_set_download_mode ( true ) ;
2016-06-03 18:25:22 -05:00
return 0 ;
}
2017-08-14 15:46:18 -07:00
static void qcom_scm_shutdown ( struct platform_device * pdev )
{
/* Clean shutdown, disable download mode to allow normal restart */
if ( download_mode )
qcom_scm_set_download_mode ( false ) ;
}
2016-06-03 18:25:22 -05:00
static const struct of_device_id qcom_scm_dt_match [ ] = {
2016-11-15 17:19:24 -08:00
{ . compatible = " qcom,scm-apq8064 " ,
2017-01-11 16:58:03 -06:00
/* FIXME: This should have .data = (void *) SCM_HAS_CORE_CLK */
2016-11-15 17:19:24 -08:00
} ,
{ . compatible = " qcom,scm-msm8660 " ,
. data = ( void * ) SCM_HAS_CORE_CLK ,
} ,
{ . compatible = " qcom,scm-msm8960 " ,
. data = ( void * ) SCM_HAS_CORE_CLK ,
} ,
{ . compatible = " qcom,scm-msm8996 " ,
. data = NULL , /* no clocks */
} ,
2018-03-23 15:48:44 +05:30
{ . compatible = " qcom,scm-ipq4019 " ,
. data = NULL , /* no clocks */
} ,
2016-11-15 17:19:24 -08:00
{ . compatible = " qcom,scm " ,
. data = ( void * ) ( SCM_HAS_CORE_CLK
| SCM_HAS_IFACE_CLK
| SCM_HAS_BUS_CLK ) ,
} ,
2016-06-03 18:25:22 -05:00
{ }
} ;
static struct platform_driver qcom_scm_driver = {
. driver = {
. name = " qcom_scm " ,
. of_match_table = qcom_scm_dt_match ,
} ,
. probe = qcom_scm_probe ,
2017-08-14 15:46:18 -07:00
. shutdown = qcom_scm_shutdown ,
2016-06-03 18:25:22 -05:00
} ;
static int __init qcom_scm_init ( void )
{
return platform_driver_register ( & qcom_scm_driver ) ;
}
2016-07-01 23:04:03 -05:00
subsys_initcall ( qcom_scm_init ) ;