2018-04-10 20:57:23 +03:00
/* SPDX-License-Identifier: GPL-2.0 */
/* Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. */
# include <linux/kernel.h>
# include <linux/of.h>
# include <linux/of_address.h>
# include <linux/of_platform.h>
# include <linux/of_reserved_mem.h>
# include <linux/platform_device.h>
# include <linux/types.h>
# include <soc/qcom/cmd-db.h>
# define NUM_PRIORITY 2
# define MAX_SLV_ID 8
# define SLAVE_ID_MASK 0x7
# define SLAVE_ID_SHIFT 16
/**
* struct entry_header : header for each entry in cmddb
*
* @ id : resource ' s identifier
* @ priority : unused
* @ addr : the address of the resource
* @ len : length of the data
* @ offset : offset from : @ data_offset , start of the data
*/
struct entry_header {
2018-04-19 21:29:24 +03:00
u8 id [ 8 ] ;
__le32 priority [ NUM_PRIORITY ] ;
__le32 addr ;
__le16 len ;
__le16 offset ;
2018-04-10 20:57:23 +03:00
} ;
/**
* struct rsc_hdr : resource header information
*
* @ slv_id : id for the resource
* @ header_offset : entry ' s header at offset from the end of the cmd_db_header
* @ data_offset : entry ' s data at offset from the end of the cmd_db_header
* @ cnt : number of entries for HW type
* @ version : MSB is major , LSB is minor
* @ reserved : reserved for future use .
*/
struct rsc_hdr {
2018-04-19 21:29:24 +03:00
__le16 slv_id ;
__le16 header_offset ;
__le16 data_offset ;
__le16 cnt ;
__le16 version ;
__le16 reserved [ 3 ] ;
2018-04-10 20:57:23 +03:00
} ;
/**
* struct cmd_db_header : The DB header information
*
* @ version : The cmd db version
2018-04-19 21:29:24 +03:00
* @ magic : constant expected in the database
2018-04-10 20:57:23 +03:00
* @ header : array of resources
* @ checksum : checksum for the header . Unused .
* @ reserved : reserved memory
* @ data : driver specific data
*/
struct cmd_db_header {
2018-04-19 21:29:24 +03:00
__le32 version ;
u8 magic [ 4 ] ;
2018-04-10 20:57:23 +03:00
struct rsc_hdr header [ MAX_SLV_ID ] ;
2018-04-19 21:29:24 +03:00
__le32 checksum ;
__le32 reserved ;
2018-04-10 20:57:23 +03:00
u8 data [ ] ;
} ;
/**
* DOC : Description of the Command DB database .
*
* At the start of the command DB memory is the cmd_db_header structure .
* The cmd_db_header holds the version , checksum , magic key as well as an
* array for header for each slave ( depicted by the rsc_header ) . Each h / w
* based accelerator is a ' slave ' ( shared resource ) and has slave id indicating
* the type of accelerator . The rsc_header is the header for such individual
* slaves of a given type . The entries for each of these slaves begin at the
* rsc_hdr . header_offset . In addition each slave could have auxiliary data
* that may be needed by the driver . The data for the slave starts at the
* entry_header . offset to the location pointed to by the rsc_hdr . data_offset .
*
* Drivers have a stringified key to a slave / resource . They can query the slave
* information and get the slave id and the auxiliary data and the length of the
* data . Using this information , they can format the request to be sent to the
* h / w accelerator and request a resource state .
*/
2018-04-19 21:29:24 +03:00
static const u8 CMD_DB_MAGIC [ ] = { 0xdb , 0x30 , 0x03 , 0x0c } ;
static bool cmd_db_magic_matches ( const struct cmd_db_header * header )
{
const u8 * magic = header - > magic ;
return memcmp ( magic , CMD_DB_MAGIC , ARRAY_SIZE ( CMD_DB_MAGIC ) ) = = 0 ;
}
2018-04-10 20:57:23 +03:00
static struct cmd_db_header * cmd_db_header ;
2018-09-26 21:02:33 +03:00
static inline const void * rsc_to_entry_header ( const struct rsc_hdr * hdr )
2018-04-19 21:29:24 +03:00
{
u16 offset = le16_to_cpu ( hdr - > header_offset ) ;
return cmd_db_header - > data + offset ;
}
static inline void *
2018-09-26 21:02:33 +03:00
rsc_offset ( const struct rsc_hdr * hdr , const struct entry_header * ent )
2018-04-19 21:29:24 +03:00
{
u16 offset = le16_to_cpu ( hdr - > data_offset ) ;
u16 loffset = le16_to_cpu ( ent - > offset ) ;
return cmd_db_header - > data + offset + loffset ;
}
2018-04-10 20:57:23 +03:00
/**
* cmd_db_ready - Indicates if command DB is available
*
* Return : 0 on success , errno otherwise
*/
int cmd_db_ready ( void )
{
if ( cmd_db_header = = NULL )
return - EPROBE_DEFER ;
2018-04-19 21:29:24 +03:00
else if ( ! cmd_db_magic_matches ( cmd_db_header ) )
2018-04-10 20:57:23 +03:00
return - EINVAL ;
return 0 ;
}
EXPORT_SYMBOL ( cmd_db_ready ) ;
2018-09-26 21:02:33 +03:00
static int cmd_db_get_header ( const char * id , const struct entry_header * * eh ,
const struct rsc_hdr * * rh )
2018-04-10 20:57:23 +03:00
{
2018-09-26 21:02:33 +03:00
const struct rsc_hdr * rsc_hdr ;
const struct entry_header * ent ;
2018-04-10 20:57:23 +03:00
int ret , i , j ;
2018-04-19 21:29:24 +03:00
u8 query [ 8 ] ;
2018-04-10 20:57:23 +03:00
ret = cmd_db_ready ( ) ;
if ( ret )
return ret ;
2018-04-19 21:29:24 +03:00
/* Pad out query string to same length as in DB */
strncpy ( query , id , sizeof ( query ) ) ;
2018-04-10 20:57:23 +03:00
for ( i = 0 ; i < MAX_SLV_ID ; i + + ) {
rsc_hdr = & cmd_db_header - > header [ i ] ;
if ( ! rsc_hdr - > slv_id )
break ;
2018-04-19 21:29:24 +03:00
ent = rsc_to_entry_header ( rsc_hdr ) ;
for ( j = 0 ; j < le16_to_cpu ( rsc_hdr - > cnt ) ; j + + , ent + + ) {
2018-09-26 21:02:33 +03:00
if ( memcmp ( ent - > id , query , sizeof ( ent - > id ) ) = = 0 ) {
if ( eh )
* eh = ent ;
if ( rh )
* rh = rsc_hdr ;
return 0 ;
}
2018-04-10 20:57:23 +03:00
}
}
return - ENODEV ;
}
/**
* cmd_db_read_addr ( ) - Query command db for resource id address .
*
* @ id : resource id to query for address
*
* Return : resource address on success , 0 on error
*
* This is used to retrieve resource address based on resource
* id .
*/
u32 cmd_db_read_addr ( const char * id )
{
int ret ;
2018-09-26 21:02:33 +03:00
const struct entry_header * ent ;
2018-04-10 20:57:23 +03:00
2018-09-26 21:02:33 +03:00
ret = cmd_db_get_header ( id , & ent , NULL ) ;
2018-04-10 20:57:23 +03:00
2018-09-26 21:02:33 +03:00
return ret < 0 ? 0 : le32_to_cpu ( ent - > addr ) ;
2018-04-10 20:57:23 +03:00
}
EXPORT_SYMBOL ( cmd_db_read_addr ) ;
/**
* cmd_db_read_aux_data ( ) - Query command db for aux data .
*
2018-09-26 21:02:34 +03:00
* @ id : Resource to retrieve AUX Data on
* @ len : size of data buffer returned
2018-04-10 20:57:23 +03:00
*
2018-09-26 21:02:34 +03:00
* Return : pointer to data on success , error pointer otherwise
2018-04-10 20:57:23 +03:00
*/
2018-09-26 21:02:34 +03:00
const void * cmd_db_read_aux_data ( const char * id , size_t * len )
2018-04-10 20:57:23 +03:00
{
int ret ;
2018-09-26 21:02:33 +03:00
const struct entry_header * ent ;
const struct rsc_hdr * rsc_hdr ;
2018-04-10 20:57:23 +03:00
2018-04-19 21:29:24 +03:00
ret = cmd_db_get_header ( id , & ent , & rsc_hdr ) ;
2018-04-10 20:57:23 +03:00
if ( ret )
2018-09-26 21:02:34 +03:00
return ERR_PTR ( ret ) ;
2018-04-10 20:57:23 +03:00
2018-09-26 21:02:34 +03:00
if ( len )
* len = le16_to_cpu ( ent - > len ) ;
2018-04-10 20:57:23 +03:00
2018-09-26 21:02:34 +03:00
return rsc_offset ( rsc_hdr , ent ) ;
2018-04-10 20:57:23 +03:00
}
EXPORT_SYMBOL ( cmd_db_read_aux_data ) ;
/**
* cmd_db_read_slave_id - Get the slave ID for a given resource address
*
* @ id : Resource id to query the DB for version
*
* Return : cmd_db_hw_type enum on success , CMD_DB_HW_INVALID on error
*/
enum cmd_db_hw_type cmd_db_read_slave_id ( const char * id )
{
int ret ;
2018-09-26 21:02:33 +03:00
const struct entry_header * ent ;
2018-04-19 21:29:24 +03:00
u32 addr ;
2018-04-10 20:57:23 +03:00
2018-09-26 21:02:33 +03:00
ret = cmd_db_get_header ( id , & ent , NULL ) ;
2018-04-19 21:29:24 +03:00
if ( ret < 0 )
return CMD_DB_HW_INVALID ;
2018-04-10 20:57:23 +03:00
2018-09-26 21:02:33 +03:00
addr = le32_to_cpu ( ent - > addr ) ;
2018-04-19 21:29:24 +03:00
return ( addr > > SLAVE_ID_SHIFT ) & SLAVE_ID_MASK ;
2018-04-10 20:57:23 +03:00
}
EXPORT_SYMBOL ( cmd_db_read_slave_id ) ;
static int cmd_db_dev_probe ( struct platform_device * pdev )
{
struct reserved_mem * rmem ;
int ret = 0 ;
rmem = of_reserved_mem_lookup ( pdev - > dev . of_node ) ;
if ( ! rmem ) {
dev_err ( & pdev - > dev , " failed to acquire memory region \n " ) ;
return - EINVAL ;
}
cmd_db_header = memremap ( rmem - > base , rmem - > size , MEMREMAP_WB ) ;
2019-02-28 08:48:49 +03:00
if ( ! cmd_db_header ) {
ret = - ENOMEM ;
2018-04-10 20:57:23 +03:00
cmd_db_header = NULL ;
return ret ;
}
2018-04-19 21:29:24 +03:00
if ( ! cmd_db_magic_matches ( cmd_db_header ) ) {
2018-04-10 20:57:23 +03:00
dev_err ( & pdev - > dev , " Invalid Command DB Magic \n " ) ;
return - EINVAL ;
}
return 0 ;
}
static const struct of_device_id cmd_db_match_table [ ] = {
{ . compatible = " qcom,cmd-db " } ,
{ } ,
} ;
static struct platform_driver cmd_db_dev_driver = {
. probe = cmd_db_dev_probe ,
. driver = {
. name = " cmd-db " ,
. of_match_table = cmd_db_match_table ,
} ,
} ;
static int __init cmd_db_device_init ( void )
{
return platform_driver_register ( & cmd_db_dev_driver ) ;
}
arch_initcall ( cmd_db_device_init ) ;