2646 lines
70 KiB
C
Executable File
2646 lines
70 KiB
C
Executable File
#include <soc/samsung/ect_parser.h>
|
|
|
|
#include <asm/uaccess.h>
|
|
#include <asm/map.h>
|
|
#include <asm/memory.h>
|
|
|
|
#include <linux/device.h>
|
|
#include <linux/errno.h>
|
|
#include <linux/fs.h>
|
|
#include <linux/file.h>
|
|
#include <linux/module.h>
|
|
#include <linux/vmalloc.h>
|
|
|
|
#define ALIGNMENT_SIZE 4
|
|
|
|
#define S5P_VA_ECT (VMALLOC_START + 0xF6000000 + 0x02D00000)
|
|
|
|
#define ARRAY_SIZE32(array) ((u32)ARRAY_SIZE(array))
|
|
|
|
/* Variable */
|
|
|
|
static struct ect_info ect_list[];
|
|
|
|
static char ect_signature[] = "PARA";
|
|
|
|
static struct class *ect_class;
|
|
|
|
static phys_addr_t ect_address;
|
|
static phys_addr_t ect_size;
|
|
|
|
static struct vm_struct ect_early_vm;
|
|
|
|
/* API for internal */
|
|
|
|
static void ect_parse_integer(void **address, void *value)
|
|
{
|
|
*((unsigned int *)value) = __raw_readl(*address);
|
|
*address += sizeof(uint32_t);
|
|
}
|
|
|
|
static void ect_parse_integer64(void **address, void *value)
|
|
{
|
|
unsigned int top, half;
|
|
|
|
half = __raw_readl(*address);
|
|
*address += sizeof(uint32_t);
|
|
top = __raw_readl(*address);
|
|
*address += sizeof(uint32_t);
|
|
|
|
*(unsigned long long *)value = ((unsigned long long)top << 32 | half);
|
|
}
|
|
|
|
static int ect_parse_string(void **address, char **value, unsigned int *length)
|
|
{
|
|
ect_parse_integer(address, length);
|
|
(*length)++;
|
|
|
|
*value = *address;
|
|
|
|
if (*length % ALIGNMENT_SIZE != 0)
|
|
*address += (unsigned long)(*length + ALIGNMENT_SIZE - (*length % ALIGNMENT_SIZE));
|
|
else
|
|
*address += (unsigned long)*length;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int ect_parse_dvfs_domain(int parser_version, void *address, struct ect_dvfs_domain *domain)
|
|
{
|
|
int ret = 0;
|
|
int i;
|
|
char *clock_name;
|
|
int length;
|
|
|
|
ect_parse_integer(&address, &domain->max_frequency);
|
|
ect_parse_integer(&address, &domain->min_frequency);
|
|
|
|
if (parser_version >= 2) {
|
|
ect_parse_integer(&address, &domain->boot_level_idx);
|
|
ect_parse_integer(&address, &domain->resume_level_idx);
|
|
} else {
|
|
domain->boot_level_idx = -1;
|
|
domain->resume_level_idx = -1;
|
|
}
|
|
|
|
if (parser_version >= 3) {
|
|
ect_parse_integer(&address, &domain->mode);
|
|
} else {
|
|
domain->mode = e_dvfs_mode_clock_name;
|
|
}
|
|
|
|
ect_parse_integer(&address, &domain->num_of_clock);
|
|
ect_parse_integer(&address, &domain->num_of_level);
|
|
|
|
if (domain->mode == e_dvfs_mode_sfr_address) {
|
|
domain->list_sfr = address;
|
|
domain->list_clock = NULL;
|
|
|
|
address += sizeof(unsigned int) * domain->num_of_clock;
|
|
} else if (domain->mode == e_dvfs_mode_clock_name) {
|
|
domain->list_clock = kzalloc(sizeof(char *) * domain->num_of_clock, GFP_KERNEL);
|
|
domain->list_sfr = NULL;
|
|
if (domain->list_clock == NULL) {
|
|
ret = -ENOMEM;
|
|
goto err_list_clock_allocation;
|
|
}
|
|
|
|
for (i = 0; i < domain->num_of_clock; ++i) {
|
|
if (ect_parse_string(&address, &clock_name, &length)) {
|
|
ret = -EINVAL;
|
|
goto err_parse_string;
|
|
}
|
|
|
|
domain->list_clock[i] = clock_name;
|
|
}
|
|
}
|
|
|
|
domain->list_level = address;
|
|
address += sizeof(struct ect_dvfs_level) * domain->num_of_level;
|
|
|
|
domain->list_dvfs_value = address;
|
|
|
|
return 0;
|
|
|
|
err_parse_string:
|
|
kfree(domain->list_clock);
|
|
err_list_clock_allocation:
|
|
return ret;
|
|
}
|
|
|
|
static int ect_parse_dvfs_header(void *address, struct ect_info *info)
|
|
{
|
|
int ret = 0;
|
|
int i;
|
|
char *domain_name;
|
|
unsigned int length, offset;
|
|
struct ect_dvfs_header *ect_dvfs_header;
|
|
struct ect_dvfs_domain *ect_dvfs_domain;
|
|
void *address_dvfs_header = address;
|
|
|
|
if (address == NULL)
|
|
return -EINVAL;
|
|
|
|
ect_dvfs_header = kzalloc(sizeof(struct ect_dvfs_header), GFP_KERNEL);
|
|
if (ect_dvfs_header == NULL)
|
|
return -ENOMEM;
|
|
|
|
ect_parse_integer(&address, &ect_dvfs_header->parser_version);
|
|
ect_parse_integer(&address, &ect_dvfs_header->version);
|
|
ect_parse_integer(&address, &ect_dvfs_header->num_of_domain);
|
|
|
|
ect_dvfs_header->domain_list = kzalloc(sizeof(struct ect_dvfs_domain) * ect_dvfs_header->num_of_domain,
|
|
GFP_KERNEL);
|
|
if (ect_dvfs_header->domain_list == NULL) {
|
|
ret = -EINVAL;
|
|
goto err_domain_list_allocation;
|
|
}
|
|
|
|
for (i = 0; i < ect_dvfs_header->num_of_domain; ++i) {
|
|
if (ect_parse_string(&address, &domain_name, &length)) {
|
|
ret = -EINVAL;
|
|
goto err_parse_string;
|
|
}
|
|
|
|
ect_parse_integer(&address, &offset);
|
|
|
|
ect_dvfs_domain = &ect_dvfs_header->domain_list[i];
|
|
ect_dvfs_domain->domain_name = domain_name;
|
|
ect_dvfs_domain->domain_offset = offset;
|
|
}
|
|
|
|
for (i = 0; i < ect_dvfs_header->num_of_domain; ++i) {
|
|
ect_dvfs_domain = &ect_dvfs_header->domain_list[i];
|
|
|
|
if (ect_parse_dvfs_domain(ect_dvfs_header->parser_version,
|
|
address_dvfs_header + ect_dvfs_domain->domain_offset,
|
|
ect_dvfs_domain)) {
|
|
ret = -EINVAL;
|
|
goto err_parse_domain;
|
|
}
|
|
}
|
|
|
|
info->block_handle = ect_dvfs_header;
|
|
|
|
return 0;
|
|
|
|
err_parse_domain:
|
|
err_parse_string:
|
|
kfree(ect_dvfs_header->domain_list);
|
|
err_domain_list_allocation:
|
|
kfree(ect_dvfs_header);
|
|
return ret;
|
|
}
|
|
|
|
static int ect_parse_pll(int parser_version, void *address, struct ect_pll *ect_pll)
|
|
{
|
|
ect_parse_integer(&address, &ect_pll->type_pll);
|
|
ect_parse_integer(&address, &ect_pll->num_of_frequency);
|
|
|
|
ect_pll->frequency_list = address;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int ect_parse_pll_header(void *address, struct ect_info *info)
|
|
{
|
|
int ret = 0;
|
|
int i;
|
|
char *pll_name;
|
|
unsigned int length, offset;
|
|
struct ect_pll_header *ect_pll_header;
|
|
struct ect_pll *ect_pll;
|
|
void *address_pll_header = address;
|
|
|
|
if (address == NULL)
|
|
return -EINVAL;
|
|
|
|
ect_pll_header = kzalloc(sizeof(struct ect_pll_header), GFP_KERNEL);
|
|
if (ect_pll_header == NULL)
|
|
return -ENOMEM;
|
|
|
|
ect_parse_integer(&address, &ect_pll_header->parser_version);
|
|
ect_parse_integer(&address, &ect_pll_header->version);
|
|
ect_parse_integer(&address, &ect_pll_header->num_of_pll);
|
|
|
|
ect_pll_header->pll_list = kzalloc(sizeof(struct ect_pll) * ect_pll_header->num_of_pll,
|
|
GFP_KERNEL);
|
|
if (ect_pll_header->pll_list == NULL) {
|
|
ret = -ENOMEM;
|
|
goto err_pll_list_allocation;
|
|
}
|
|
|
|
for (i = 0; i < ect_pll_header->num_of_pll; ++i) {
|
|
|
|
if (ect_parse_string(&address, &pll_name, &length)) {
|
|
ret = -EINVAL;
|
|
goto err_parse_string;
|
|
}
|
|
|
|
ect_parse_integer(&address, &offset);
|
|
|
|
ect_pll = &ect_pll_header->pll_list[i];
|
|
ect_pll->pll_name = pll_name;
|
|
ect_pll->pll_offset = offset;
|
|
}
|
|
|
|
for (i = 0; i < ect_pll_header->num_of_pll; ++i) {
|
|
ect_pll = &ect_pll_header->pll_list[i];
|
|
|
|
if (ect_parse_pll(ect_pll_header->parser_version,
|
|
address_pll_header + ect_pll->pll_offset, ect_pll)) {
|
|
ret = -EINVAL;
|
|
goto err_parse_pll;
|
|
}
|
|
}
|
|
|
|
info->block_handle = ect_pll_header;
|
|
|
|
return 0;
|
|
|
|
err_parse_pll:
|
|
err_parse_string:
|
|
kfree(ect_pll_header->pll_list);
|
|
err_pll_list_allocation:
|
|
kfree(ect_pll_header);
|
|
return ret;
|
|
}
|
|
|
|
static int ect_parse_voltage_table(int parser_version, void **address, struct ect_voltage_domain *domain, struct ect_voltage_table *table)
|
|
{
|
|
int num_of_data = domain->num_of_group * domain->num_of_level;
|
|
|
|
ect_parse_integer(address, &table->table_version);
|
|
|
|
if (parser_version >= 2) {
|
|
ect_parse_integer(address, &table->boot_level_idx);
|
|
ect_parse_integer(address, &table->resume_level_idx);
|
|
|
|
table->level_en = *address;
|
|
*address += sizeof(int32_t) * domain->num_of_level;
|
|
} else {
|
|
table->boot_level_idx = -1;
|
|
table->resume_level_idx = -1;
|
|
|
|
table->level_en = NULL;
|
|
}
|
|
|
|
if (parser_version >= 3) {
|
|
table->voltages = NULL;
|
|
|
|
table->voltages_step = *address;
|
|
*address += sizeof(unsigned char) * num_of_data;
|
|
table->volt_step = PMIC_VOLTAGE_STEP;
|
|
|
|
} else {
|
|
table->voltages = *address;
|
|
*address += sizeof(int32_t) * num_of_data;
|
|
|
|
table->voltages_step = NULL;
|
|
table->volt_step = 0;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int ect_parse_voltage_domain(int parser_version, void *address, struct ect_voltage_domain *domain)
|
|
{
|
|
int ret = 0;
|
|
int i;
|
|
|
|
ect_parse_integer(&address, &domain->num_of_group);
|
|
ect_parse_integer(&address, &domain->num_of_level);
|
|
ect_parse_integer(&address, &domain->num_of_table);
|
|
|
|
domain->level_list = address;
|
|
address += sizeof(int32_t) * domain->num_of_level;
|
|
|
|
domain->table_list = kzalloc(sizeof(struct ect_voltage_table) * domain->num_of_table, GFP_KERNEL);
|
|
if (domain->table_list == NULL) {
|
|
ret = -ENOMEM;
|
|
goto err_table_list_allocation;
|
|
}
|
|
|
|
for (i = 0; i < domain->num_of_table; ++i) {
|
|
if (ect_parse_voltage_table(parser_version,
|
|
&address,
|
|
domain,
|
|
&domain->table_list[i])) {
|
|
ret = -EINVAL;
|
|
goto err_parse_voltage_table;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
|
|
err_parse_voltage_table:
|
|
kfree(domain->table_list);
|
|
err_table_list_allocation:
|
|
return ret;
|
|
}
|
|
|
|
static int ect_parse_voltage_header(void *address, struct ect_info *info)
|
|
{
|
|
int ret = 0;
|
|
int i;
|
|
char *domain_name;
|
|
unsigned int length, offset;
|
|
struct ect_voltage_header *ect_voltage_header;
|
|
struct ect_voltage_domain *ect_voltage_domain;
|
|
void *address_voltage_header = address;
|
|
|
|
if (address == NULL)
|
|
return -EINVAL;
|
|
|
|
ect_voltage_header = kzalloc(sizeof(struct ect_voltage_header), GFP_KERNEL);
|
|
if (ect_voltage_header == NULL)
|
|
return -EINVAL;
|
|
|
|
ect_parse_integer(&address, &ect_voltage_header->parser_version);
|
|
ect_parse_integer(&address, &ect_voltage_header->version);
|
|
ect_parse_integer(&address, &ect_voltage_header->num_of_domain);
|
|
|
|
ect_voltage_header->domain_list = kzalloc(sizeof(struct ect_voltage_domain) * ect_voltage_header->num_of_domain,
|
|
GFP_KERNEL);
|
|
if (ect_voltage_header->domain_list == NULL) {
|
|
ret = -ENOMEM;
|
|
goto err_domain_list_allocation;
|
|
}
|
|
|
|
for (i = 0; i < ect_voltage_header->num_of_domain; ++i) {
|
|
if (ect_parse_string(&address, &domain_name, &length)) {
|
|
ret = -EINVAL;
|
|
goto err_parse_string;
|
|
}
|
|
|
|
ect_parse_integer(&address, &offset);
|
|
|
|
ect_voltage_domain = &ect_voltage_header->domain_list[i];
|
|
ect_voltage_domain->domain_name = domain_name;
|
|
ect_voltage_domain->domain_offset = offset;
|
|
}
|
|
|
|
for (i = 0; i < ect_voltage_header->num_of_domain; ++i) {
|
|
ect_voltage_domain = &ect_voltage_header->domain_list[i];
|
|
|
|
if (ect_parse_voltage_domain(ect_voltage_header->parser_version,
|
|
address_voltage_header + ect_voltage_domain->domain_offset,
|
|
ect_voltage_domain)) {
|
|
ret = -EINVAL;
|
|
goto err_parse_voltage_domain;
|
|
}
|
|
}
|
|
|
|
info->block_handle = ect_voltage_header;
|
|
|
|
return 0;
|
|
|
|
err_parse_voltage_domain:
|
|
err_parse_string:
|
|
kfree(ect_voltage_header->domain_list);
|
|
err_domain_list_allocation:
|
|
kfree(ect_voltage_header);
|
|
return ret;
|
|
}
|
|
|
|
static int ect_parse_rcc_table(int parser_version, void **address, struct ect_rcc_domain *domain, struct ect_rcc_table *table)
|
|
{
|
|
int num_of_data = domain->num_of_group * domain->num_of_level;
|
|
|
|
ect_parse_integer(address, &table->table_version);
|
|
|
|
if (parser_version >= 2) {
|
|
table->rcc_compact = *address;
|
|
*address += sizeof(unsigned char) * num_of_data;
|
|
} else {
|
|
table->rcc = *address;
|
|
*address += sizeof(int32_t) * num_of_data;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int ect_parse_rcc_domain(int parser_version, void *address, struct ect_rcc_domain *domain)
|
|
{
|
|
int ret = 0;
|
|
int i;
|
|
|
|
ect_parse_integer(&address, &domain->num_of_group);
|
|
ect_parse_integer(&address, &domain->num_of_level);
|
|
ect_parse_integer(&address, &domain->num_of_table);
|
|
|
|
domain->level_list = address;
|
|
address += sizeof(int32_t) * domain->num_of_level;
|
|
|
|
domain->table_list = kzalloc(sizeof(struct ect_rcc_table) * domain->num_of_table, GFP_KERNEL);
|
|
if (domain->table_list == NULL) {
|
|
ret = -ENOMEM;
|
|
goto err_table_list_allocation;
|
|
}
|
|
|
|
for (i = 0; i < domain->num_of_table; ++i) {
|
|
if (ect_parse_rcc_table(parser_version,
|
|
&address,
|
|
domain, &domain->table_list[i])) {
|
|
ret = -EINVAL;
|
|
goto err_parse_rcc_table;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
|
|
err_parse_rcc_table:
|
|
kfree(domain->table_list);
|
|
err_table_list_allocation:
|
|
return ret;
|
|
}
|
|
|
|
static int ect_parse_rcc_header(void *address, struct ect_info *info)
|
|
{
|
|
int ret = 0;
|
|
int i;
|
|
char *domain_name;
|
|
unsigned int length, offset;
|
|
struct ect_rcc_header *ect_rcc_header;
|
|
struct ect_rcc_domain *ect_rcc_domain;
|
|
void *address_rcc_header = address;
|
|
|
|
if (address == NULL)
|
|
return -EINVAL;
|
|
|
|
ect_rcc_header = kzalloc(sizeof(struct ect_rcc_header), GFP_KERNEL);
|
|
|
|
if (ect_rcc_header == NULL)
|
|
return -EINVAL;
|
|
|
|
ect_parse_integer(&address, &ect_rcc_header->parser_version);
|
|
ect_parse_integer(&address, &ect_rcc_header->version);
|
|
ect_parse_integer(&address, &ect_rcc_header->num_of_domain);
|
|
|
|
ect_rcc_header->domain_list = kzalloc(sizeof(struct ect_rcc_domain) * ect_rcc_header->num_of_domain,
|
|
GFP_KERNEL);
|
|
|
|
if (ect_rcc_header->domain_list == NULL) {
|
|
ret = -ENOMEM;
|
|
goto err_domain_list_allocation;
|
|
}
|
|
|
|
for (i = 0; i < ect_rcc_header->num_of_domain; ++i) {
|
|
if (ect_parse_string(&address, &domain_name, &length)) {
|
|
ret = -EINVAL;
|
|
goto err_parse_string;
|
|
}
|
|
|
|
ect_parse_integer(&address, &offset);
|
|
|
|
ect_rcc_domain = &ect_rcc_header->domain_list[i];
|
|
ect_rcc_domain->domain_name = domain_name;
|
|
ect_rcc_domain->domain_offset = offset;
|
|
}
|
|
|
|
for (i = 0; i < ect_rcc_header->num_of_domain; ++i) {
|
|
ect_rcc_domain = &ect_rcc_header->domain_list[i];
|
|
|
|
if (ect_parse_rcc_domain(ect_rcc_header->parser_version,
|
|
address_rcc_header + ect_rcc_domain->domain_offset,
|
|
ect_rcc_domain)) {
|
|
ret = -EINVAL;
|
|
goto err_parse_rcc_domain;
|
|
}
|
|
}
|
|
|
|
info->block_handle = ect_rcc_header;
|
|
|
|
return 0;
|
|
|
|
err_parse_rcc_domain:
|
|
err_parse_string:
|
|
kfree(ect_rcc_header->domain_list);
|
|
err_domain_list_allocation:
|
|
kfree(ect_rcc_header);
|
|
return ret;
|
|
}
|
|
|
|
static int ect_parse_mif_thermal_header(void *address, struct ect_info *info)
|
|
{
|
|
struct ect_mif_thermal_header *ect_mif_thermal_header;
|
|
|
|
if (address == NULL)
|
|
return -EINVAL;
|
|
|
|
ect_mif_thermal_header = kzalloc(sizeof(struct ect_mif_thermal_header), GFP_KERNEL);
|
|
if (ect_mif_thermal_header == NULL)
|
|
return -EINVAL;
|
|
|
|
ect_parse_integer(&address, &ect_mif_thermal_header->parser_version);
|
|
ect_parse_integer(&address, &ect_mif_thermal_header->version);
|
|
ect_parse_integer(&address, &ect_mif_thermal_header->num_of_level);
|
|
|
|
ect_mif_thermal_header->level = address;
|
|
|
|
info->block_handle = ect_mif_thermal_header;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int ect_parse_ap_thermal_function(int parser_version, void *address, struct ect_ap_thermal_function *function)
|
|
{
|
|
int i;
|
|
struct ect_ap_thermal_range *range;
|
|
|
|
ect_parse_integer(&address, &function->num_of_range);
|
|
|
|
function->range_list = kzalloc(sizeof(struct ect_ap_thermal_range) * function->num_of_range, GFP_KERNEL);
|
|
|
|
for (i = 0; i < function->num_of_range; ++i) {
|
|
range = &function->range_list[i];
|
|
|
|
ect_parse_integer(&address, &range->lower_bound_temperature);
|
|
ect_parse_integer(&address, &range->upper_bound_temperature);
|
|
ect_parse_integer(&address, &range->max_frequency);
|
|
ect_parse_integer(&address, &range->sw_trip);
|
|
ect_parse_integer(&address, &range->flag);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int ect_parse_ap_thermal_header(void *address, struct ect_info *info)
|
|
{
|
|
int ret = 0;
|
|
int i;
|
|
char *function_name;
|
|
unsigned int length, offset;
|
|
struct ect_ap_thermal_header *ect_ap_thermal_header;
|
|
struct ect_ap_thermal_function *ect_ap_thermal_function;
|
|
void *address_thermal_header = address;
|
|
|
|
if (address == NULL)
|
|
return -EINVAL;
|
|
|
|
ect_ap_thermal_header = kzalloc(sizeof(struct ect_ap_thermal_header), GFP_KERNEL);
|
|
if (ect_ap_thermal_header == NULL)
|
|
return -EINVAL;
|
|
|
|
ect_parse_integer(&address, &ect_ap_thermal_header->parser_version);
|
|
ect_parse_integer(&address, &ect_ap_thermal_header->version);
|
|
ect_parse_integer(&address, &ect_ap_thermal_header->num_of_function);
|
|
|
|
ect_ap_thermal_header->function_list = kzalloc(sizeof(struct ect_ap_thermal_function) * ect_ap_thermal_header->num_of_function,
|
|
GFP_KERNEL);
|
|
if (ect_ap_thermal_header->function_list == NULL) {
|
|
ret = -ENOMEM;
|
|
goto err_function_list_allocation;
|
|
}
|
|
|
|
for (i = 0; i < ect_ap_thermal_header->num_of_function; ++i) {
|
|
if (ect_parse_string(&address, &function_name, &length)) {
|
|
ret = -EINVAL;
|
|
goto err_parse_string;
|
|
}
|
|
|
|
ect_parse_integer(&address, &offset);
|
|
|
|
ect_ap_thermal_function = &ect_ap_thermal_header->function_list[i];
|
|
ect_ap_thermal_function->function_name = function_name;
|
|
ect_ap_thermal_function->function_offset = offset;
|
|
}
|
|
|
|
for (i = 0; i < ect_ap_thermal_header->num_of_function; ++i) {
|
|
ect_ap_thermal_function = &ect_ap_thermal_header->function_list[i];
|
|
|
|
if (ect_parse_ap_thermal_function(ect_ap_thermal_header->parser_version,
|
|
address_thermal_header + ect_ap_thermal_function->function_offset,
|
|
ect_ap_thermal_function)) {
|
|
ret = -EINVAL;
|
|
goto err_parse_ap_thermal_function;
|
|
}
|
|
}
|
|
|
|
info->block_handle = ect_ap_thermal_header;
|
|
|
|
return 0;
|
|
|
|
err_parse_ap_thermal_function:
|
|
err_parse_string:
|
|
kfree(ect_ap_thermal_header->function_list);
|
|
err_function_list_allocation:
|
|
kfree(ect_ap_thermal_header);
|
|
return ret;
|
|
}
|
|
|
|
static int ect_parse_margin_domain(int parser_version, void *address, struct ect_margin_domain *domain)
|
|
{
|
|
ect_parse_integer(&address, &domain->num_of_group);
|
|
ect_parse_integer(&address, &domain->num_of_level);
|
|
|
|
if (parser_version >= 2) {
|
|
domain->offset = NULL;
|
|
domain->offset_compact = address;
|
|
domain->volt_step = PMIC_VOLTAGE_STEP;
|
|
} else {
|
|
domain->offset = address;
|
|
domain->offset_compact = NULL;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int ect_parse_margin_header(void *address, struct ect_info *info)
|
|
{
|
|
int ret = 0;
|
|
int i;
|
|
char *domain_name;
|
|
unsigned int length, offset;
|
|
struct ect_margin_header *ect_margin_header;
|
|
struct ect_margin_domain *ect_margin_domain;
|
|
void *address_margin_header = address;
|
|
|
|
if (address == NULL)
|
|
return -EINVAL;
|
|
|
|
ect_margin_header = kzalloc(sizeof(struct ect_margin_header), GFP_KERNEL);
|
|
if (ect_margin_header == NULL)
|
|
return -EINVAL;
|
|
|
|
ect_parse_integer(&address, &ect_margin_header->parser_version);
|
|
ect_parse_integer(&address, &ect_margin_header->version);
|
|
ect_parse_integer(&address, &ect_margin_header->num_of_domain);
|
|
|
|
ect_margin_header->domain_list = kzalloc(sizeof(struct ect_margin_domain) * ect_margin_header->num_of_domain,
|
|
GFP_KERNEL);
|
|
if (ect_margin_header->domain_list == NULL) {
|
|
ret = -ENOMEM;
|
|
goto err_domain_list_allocation;
|
|
}
|
|
|
|
for (i = 0; i < ect_margin_header->num_of_domain; ++i) {
|
|
if (ect_parse_string(&address, &domain_name, &length)) {
|
|
ret = -EINVAL;
|
|
goto err_parse_string;
|
|
}
|
|
|
|
ect_parse_integer(&address, &offset);
|
|
|
|
ect_margin_domain = &ect_margin_header->domain_list[i];
|
|
ect_margin_domain->domain_name = domain_name;
|
|
ect_margin_domain->domain_offset = offset;
|
|
}
|
|
|
|
for (i = 0; i < ect_margin_header->num_of_domain; ++i) {
|
|
ect_margin_domain = &ect_margin_header->domain_list[i];
|
|
|
|
if (ect_parse_margin_domain(ect_margin_header->parser_version,
|
|
address_margin_header + ect_margin_domain->domain_offset,
|
|
ect_margin_domain)) {
|
|
ret = -EINVAL;
|
|
goto err_parse_margin_domain;
|
|
}
|
|
}
|
|
|
|
info->block_handle = ect_margin_header;
|
|
|
|
return 0;
|
|
|
|
err_parse_margin_domain:
|
|
err_parse_string:
|
|
kfree(ect_margin_header->domain_list);
|
|
err_domain_list_allocation:
|
|
kfree(ect_margin_header);
|
|
return ret;
|
|
}
|
|
|
|
static int ect_parse_timing_param_size(int parser_version, void *address, struct ect_timing_param_size *size)
|
|
{
|
|
ect_parse_integer(&address, &size->num_of_timing_param);
|
|
ect_parse_integer(&address, &size->num_of_level);
|
|
|
|
size->timing_parameter = address;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int ect_parse_timing_param_header(void *address, struct ect_info *info)
|
|
{
|
|
int ret = 0;
|
|
int i;
|
|
struct ect_timing_param_header *ect_timing_param_header;
|
|
struct ect_timing_param_size *ect_timing_param_size;
|
|
void *address_param_header = address;
|
|
|
|
if (address == NULL)
|
|
return -EINVAL;
|
|
|
|
ect_timing_param_header = kzalloc(sizeof(struct ect_timing_param_header), GFP_KERNEL);
|
|
if (ect_timing_param_header == NULL)
|
|
return -ENOMEM;
|
|
|
|
ect_parse_integer(&address, &ect_timing_param_header->parser_version);
|
|
ect_parse_integer(&address, &ect_timing_param_header->version);
|
|
ect_parse_integer(&address, &ect_timing_param_header->num_of_size);
|
|
|
|
ect_timing_param_header->size_list = kzalloc(sizeof(struct ect_timing_param_size) * ect_timing_param_header->num_of_size,
|
|
GFP_KERNEL);
|
|
if (ect_timing_param_header->size_list == NULL) {
|
|
ret = -ENOMEM;
|
|
goto err_size_list_allocation;
|
|
}
|
|
|
|
for (i = 0; i < ect_timing_param_header->num_of_size; ++i) {
|
|
ect_timing_param_size = &ect_timing_param_header->size_list[i];
|
|
|
|
if (ect_timing_param_header->parser_version >= 3) {
|
|
ect_parse_integer64(&address, &ect_timing_param_size->parameter_key);
|
|
ect_timing_param_size->memory_size = (unsigned int)ect_timing_param_size->parameter_key;
|
|
} else {
|
|
ect_parse_integer(&address, &ect_timing_param_size->memory_size);
|
|
ect_timing_param_size->parameter_key = ect_timing_param_size->memory_size;
|
|
}
|
|
|
|
ect_parse_integer(&address, &ect_timing_param_size->offset);
|
|
}
|
|
|
|
for (i = 0; i < ect_timing_param_header->num_of_size; ++i) {
|
|
ect_timing_param_size = &ect_timing_param_header->size_list[i];
|
|
|
|
if (ect_parse_timing_param_size(ect_timing_param_header->parser_version,
|
|
address_param_header + ect_timing_param_size->offset,
|
|
ect_timing_param_size)) {
|
|
ret = -EINVAL;
|
|
goto err_parse_timing_param_size;
|
|
}
|
|
}
|
|
|
|
info->block_handle = ect_timing_param_header;
|
|
|
|
return 0;
|
|
|
|
err_parse_timing_param_size:
|
|
kfree(ect_timing_param_header->size_list);
|
|
err_size_list_allocation:
|
|
kfree(ect_timing_param_header);
|
|
return ret;
|
|
}
|
|
|
|
static int ect_parse_minlock_domain(int parser_version, void *address, struct ect_minlock_domain *domain)
|
|
{
|
|
ect_parse_integer(&address, &domain->num_of_level);
|
|
|
|
domain->level = address;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int ect_parse_minlock_header(void *address, struct ect_info *info)
|
|
{
|
|
int ret = 0;
|
|
int i;
|
|
char *domain_name;
|
|
unsigned int length, offset;
|
|
struct ect_minlock_header *ect_minlock_header;
|
|
struct ect_minlock_domain *ect_minlock_domain;
|
|
void *address_minlock_header = address;
|
|
|
|
if (address == NULL)
|
|
return -EINVAL;
|
|
|
|
ect_minlock_header = kzalloc(sizeof(struct ect_minlock_header), GFP_KERNEL);
|
|
if (ect_minlock_header == NULL)
|
|
return -ENOMEM;
|
|
|
|
ect_parse_integer(&address, &ect_minlock_header->parser_version);
|
|
ect_parse_integer(&address, &ect_minlock_header->version);
|
|
ect_parse_integer(&address, &ect_minlock_header->num_of_domain);
|
|
|
|
ect_minlock_header->domain_list = kzalloc(sizeof(struct ect_minlock_domain) * ect_minlock_header->num_of_domain,
|
|
GFP_KERNEL);
|
|
if (ect_minlock_header->domain_list == NULL) {
|
|
ret = -ENOMEM;
|
|
goto err_domain_list_allocation;
|
|
}
|
|
|
|
for (i = 0; i < ect_minlock_header->num_of_domain; ++i) {
|
|
if (ect_parse_string(&address, &domain_name, &length)) {
|
|
ret = -EINVAL;
|
|
goto err_parse_string;
|
|
}
|
|
|
|
ect_parse_integer(&address, &offset);
|
|
|
|
ect_minlock_domain = &ect_minlock_header->domain_list[i];
|
|
ect_minlock_domain->domain_name = domain_name;
|
|
ect_minlock_domain->domain_offset = offset;
|
|
}
|
|
|
|
for (i = 0; i < ect_minlock_header->num_of_domain; ++i) {
|
|
ect_minlock_domain = &ect_minlock_header->domain_list[i];
|
|
|
|
if (ect_parse_minlock_domain(ect_minlock_header->parser_version,
|
|
address_minlock_header + ect_minlock_domain->domain_offset,
|
|
ect_minlock_domain)) {
|
|
ret = -EINVAL;
|
|
goto err_parse_minlock_domain;
|
|
}
|
|
}
|
|
|
|
info->block_handle = ect_minlock_header;
|
|
|
|
return 0;
|
|
|
|
err_parse_minlock_domain:
|
|
err_parse_string:
|
|
kfree(ect_minlock_header->domain_list);
|
|
err_domain_list_allocation:
|
|
kfree(ect_minlock_header);
|
|
return ret;
|
|
}
|
|
|
|
static int ect_parse_gen_param_table(int parser_version, void *address, struct ect_gen_param_table *size)
|
|
{
|
|
ect_parse_integer(&address, &size->num_of_col);
|
|
ect_parse_integer(&address, &size->num_of_row);
|
|
|
|
size->parameter = address;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int ect_parse_gen_param_header(void *address, struct ect_info *info)
|
|
{
|
|
int ret = 0;
|
|
int i;
|
|
char *table_name;
|
|
unsigned int length, offset;
|
|
struct ect_gen_param_header *ect_gen_param_header;
|
|
struct ect_gen_param_table *ect_gen_param_table;
|
|
void *address_param_header = address;
|
|
|
|
if (address == NULL)
|
|
return -EINVAL;
|
|
|
|
ect_gen_param_header = kzalloc(sizeof(struct ect_gen_param_header), GFP_KERNEL);
|
|
if (ect_gen_param_header == NULL)
|
|
return -ENOMEM;
|
|
|
|
ect_parse_integer(&address, &ect_gen_param_header->parser_version);
|
|
ect_parse_integer(&address, &ect_gen_param_header->version);
|
|
ect_parse_integer(&address, &ect_gen_param_header->num_of_table);
|
|
|
|
ect_gen_param_header->table_list = kzalloc(sizeof(struct ect_gen_param_table) * ect_gen_param_header->num_of_table,
|
|
GFP_KERNEL);
|
|
if (ect_gen_param_header->table_list == NULL) {
|
|
ret = -ENOMEM;
|
|
goto err_table_list_allocation;
|
|
}
|
|
|
|
for (i = 0; i < ect_gen_param_header->num_of_table; ++i) {
|
|
if (ect_parse_string(&address, &table_name, &length)) {
|
|
ret = -EINVAL;
|
|
goto err_parse_string;
|
|
}
|
|
|
|
ect_parse_integer(&address, &offset);
|
|
|
|
ect_gen_param_table = &ect_gen_param_header->table_list[i];
|
|
ect_gen_param_table->table_name = table_name;
|
|
ect_gen_param_table->offset = offset;
|
|
}
|
|
|
|
for (i = 0; i < ect_gen_param_header->num_of_table; ++i) {
|
|
ect_gen_param_table = &ect_gen_param_header->table_list[i];
|
|
|
|
if (ect_parse_gen_param_table(ect_gen_param_header->parser_version,
|
|
address_param_header + ect_gen_param_table->offset,
|
|
ect_gen_param_table)) {
|
|
ret = -EINVAL;
|
|
goto err_parse_gen_param_table;
|
|
}
|
|
}
|
|
|
|
info->block_handle = ect_gen_param_header;
|
|
|
|
return 0;
|
|
|
|
err_parse_gen_param_table:
|
|
err_parse_string:
|
|
kfree(ect_gen_param_header->table_list);
|
|
err_table_list_allocation:
|
|
kfree(ect_gen_param_header);
|
|
return ret;
|
|
}
|
|
|
|
static int ect_parse_bin(int parser_version, void *address, struct ect_bin *binary)
|
|
{
|
|
ect_parse_integer(&address, &binary->binary_size);
|
|
|
|
binary->ptr = address;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int ect_parse_bin_header(void *address, struct ect_info *info)
|
|
{
|
|
int ret = 0;
|
|
int i;
|
|
struct ect_bin_header *ect_bin_header;
|
|
struct ect_bin *ect_binary_bin;
|
|
void *address_param_header = address;
|
|
char *binary_name;
|
|
int offset, length;
|
|
|
|
if (address == NULL)
|
|
return -1;
|
|
|
|
ect_bin_header = kzalloc(sizeof(struct ect_bin_header), GFP_KERNEL);
|
|
if (ect_bin_header == NULL)
|
|
return -2;
|
|
|
|
ect_parse_integer(&address, &ect_bin_header->parser_version);
|
|
ect_parse_integer(&address, &ect_bin_header->version);
|
|
ect_parse_integer(&address, &ect_bin_header->num_of_binary);
|
|
|
|
ect_bin_header->binary_list = kzalloc(sizeof(struct ect_bin) * ect_bin_header->num_of_binary, GFP_KERNEL);
|
|
if (ect_bin_header->binary_list == NULL) {
|
|
ret = -ENOMEM;
|
|
goto err_binary_list_allocation;
|
|
}
|
|
|
|
for (i = 0; i < ect_bin_header->num_of_binary; ++i) {
|
|
ect_binary_bin = &ect_bin_header->binary_list[i];
|
|
|
|
if (ect_parse_string(&address, &binary_name, &length)) {
|
|
ret = -EINVAL;
|
|
goto err_parse_string;
|
|
}
|
|
|
|
ect_parse_integer(&address, &offset);
|
|
ect_binary_bin->binary_name = binary_name;
|
|
ect_binary_bin->offset = offset;
|
|
}
|
|
|
|
for (i = 0; i < ect_bin_header->num_of_binary; ++i) {
|
|
ect_binary_bin = &ect_bin_header->binary_list[i];
|
|
|
|
if (ect_parse_bin(ect_bin_header->parser_version,
|
|
address_param_header + ect_binary_bin->offset,
|
|
ect_binary_bin)) {
|
|
ret = -EINVAL;
|
|
goto err_parse_bin;
|
|
}
|
|
}
|
|
|
|
info->block_handle = ect_bin_header;
|
|
|
|
return 0;
|
|
|
|
err_parse_bin:
|
|
err_parse_string:
|
|
kfree(ect_bin_header->binary_list);
|
|
err_binary_list_allocation:
|
|
kfree(ect_bin_header);
|
|
return ret;
|
|
}
|
|
|
|
static int ect_parse_new_timing_param_size(int parser_version, void *address, struct ect_new_timing_param_size *size)
|
|
{
|
|
ect_parse_integer(&address, &size->mode);
|
|
ect_parse_integer(&address, &size->num_of_timing_param);
|
|
ect_parse_integer(&address, &size->num_of_level);
|
|
|
|
size->timing_parameter = address;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int ect_parse_new_timing_param_header(void *address, struct ect_info *info)
|
|
{
|
|
int ret = 0;
|
|
int i;
|
|
struct ect_new_timing_param_header *ect_new_timing_param_header;
|
|
struct ect_new_timing_param_size *ect_new_timing_param_size;
|
|
void *address_param_header = address;
|
|
|
|
if (address == NULL)
|
|
return -EINVAL;
|
|
|
|
ect_new_timing_param_header = kzalloc(sizeof(struct ect_new_timing_param_header), GFP_KERNEL);
|
|
if (ect_new_timing_param_header == NULL)
|
|
return -ENOMEM;
|
|
|
|
ect_parse_integer(&address, &ect_new_timing_param_header->parser_version);
|
|
ect_parse_integer(&address, &ect_new_timing_param_header->version);
|
|
ect_parse_integer(&address, &ect_new_timing_param_header->num_of_size);
|
|
|
|
ect_new_timing_param_header->size_list = kzalloc(sizeof(struct ect_new_timing_param_size) * ect_new_timing_param_header->num_of_size,
|
|
GFP_KERNEL);
|
|
if (ect_new_timing_param_header->size_list == NULL) {
|
|
ret = -ENOMEM;
|
|
goto err_size_list_allocation;
|
|
}
|
|
|
|
for (i = 0; i < ect_new_timing_param_header->num_of_size; ++i) {
|
|
ect_new_timing_param_size = &ect_new_timing_param_header->size_list[i];
|
|
|
|
ect_parse_integer64(&address, &ect_new_timing_param_size->parameter_key);
|
|
ect_parse_integer(&address, &ect_new_timing_param_size->offset);
|
|
}
|
|
|
|
for (i = 0; i < ect_new_timing_param_header->num_of_size; ++i) {
|
|
ect_new_timing_param_size = &ect_new_timing_param_header->size_list[i];
|
|
|
|
if (ect_parse_new_timing_param_size(ect_new_timing_param_header->parser_version,
|
|
address_param_header + ect_new_timing_param_size->offset,
|
|
ect_new_timing_param_size)) {
|
|
ret = -EINVAL;
|
|
goto err_parse_new_timing_param_size;
|
|
}
|
|
}
|
|
|
|
info->block_handle = ect_new_timing_param_header;
|
|
|
|
return 0;
|
|
|
|
err_parse_new_timing_param_size:
|
|
kfree(ect_new_timing_param_header->size_list);
|
|
err_size_list_allocation:
|
|
kfree(ect_new_timing_param_header);
|
|
return ret;
|
|
}
|
|
|
|
static int ect_parse_pidtm_block(int parser_version, void *address, struct ect_pidtm_block *block)
|
|
{
|
|
int ret = 0;
|
|
int i, length;
|
|
|
|
ect_parse_integer(&address, &block->num_of_temperature);
|
|
block->temperature_list = address;
|
|
|
|
address += sizeof(int32_t) * block->num_of_temperature;
|
|
|
|
ect_parse_integer(&address, &block->num_of_parameter);
|
|
block->param_name_list = kzalloc(sizeof(char *) * block->num_of_parameter, GFP_KERNEL);
|
|
if (block->param_name_list == NULL) {
|
|
ret = -ENOMEM;
|
|
goto err_param_name_list_allocation;
|
|
}
|
|
|
|
for (i = 0; i < block->num_of_parameter; ++i) {
|
|
if (ect_parse_string(&address, &block->param_name_list[i], &length)) {
|
|
ret = -EINVAL;
|
|
goto err_parse_param_name;
|
|
}
|
|
}
|
|
|
|
block->param_value_list = address;
|
|
|
|
return 0;
|
|
|
|
err_parse_param_name:
|
|
kfree(block->param_name_list);
|
|
err_param_name_list_allocation:
|
|
return ret;
|
|
}
|
|
|
|
static int ect_parse_pidtm_header(void *address, struct ect_info *info)
|
|
{
|
|
int ret = 0;
|
|
int i;
|
|
struct ect_pidtm_header *ect_pidtm_header;
|
|
struct ect_pidtm_block *ect_pidtm_block;
|
|
void *address_param_header = address;
|
|
char *block_name;
|
|
int offset, length;
|
|
|
|
if (address == NULL)
|
|
return -EINVAL;
|
|
|
|
ect_pidtm_header = kzalloc(sizeof(struct ect_pidtm_header), GFP_KERNEL);
|
|
if (ect_pidtm_header == NULL)
|
|
return -ENOMEM;
|
|
|
|
ect_parse_integer(&address, &ect_pidtm_header->parser_version);
|
|
ect_parse_integer(&address, &ect_pidtm_header->version);
|
|
ect_parse_integer(&address, &ect_pidtm_header->num_of_block);
|
|
|
|
ect_pidtm_header->block_list = kzalloc(sizeof(struct ect_pidtm_block) * ect_pidtm_header->num_of_block,
|
|
GFP_KERNEL);
|
|
if (ect_pidtm_header->block_list == NULL) {
|
|
ret = -ENOMEM;
|
|
goto err_block_list_allocation;
|
|
}
|
|
|
|
for (i = 0; i < ect_pidtm_header->num_of_block; ++i) {
|
|
ect_pidtm_block = &ect_pidtm_header->block_list[i];
|
|
|
|
if (ect_parse_string(&address, &block_name, &length)) {
|
|
ret = -EINVAL;
|
|
goto err_parse_string;
|
|
}
|
|
|
|
ect_parse_integer(&address, &offset);
|
|
ect_pidtm_block->block_name = block_name;
|
|
ect_pidtm_block->offset = offset;
|
|
}
|
|
|
|
for (i = 0; i < ect_pidtm_header->num_of_block; ++i) {
|
|
ect_pidtm_block = &ect_pidtm_header->block_list[i];
|
|
|
|
if (ect_parse_pidtm_block(ect_pidtm_header->parser_version,
|
|
address_param_header + ect_pidtm_block->offset,
|
|
ect_pidtm_block)) {
|
|
ret = -EINVAL;
|
|
goto err_parse_pidtm_block;
|
|
}
|
|
|
|
}
|
|
|
|
info->block_handle = ect_pidtm_header;
|
|
|
|
return 0;
|
|
|
|
err_parse_pidtm_block:
|
|
err_parse_string:
|
|
kfree(ect_pidtm_header->block_list);
|
|
err_block_list_allocation:
|
|
kfree(ect_pidtm_header);
|
|
return ret;
|
|
}
|
|
|
|
static void ect_present_test_data(char *version)
|
|
{
|
|
if (version[1] == '.')
|
|
return;
|
|
|
|
if (version[3] == '0')
|
|
return;
|
|
|
|
pr_info("========================================\n");
|
|
pr_info("=\n");
|
|
pr_info("= [ECT] current version is TEST VERSION!!\n");
|
|
pr_info("= Please be aware that error can be happen.\n");
|
|
pr_info("= [VERSION] : %c%c%c%c\n", version[0], version[1], version[2], version[3]);
|
|
pr_info("=\n");
|
|
pr_info("========================================\n");
|
|
}
|
|
|
|
#if defined(CONFIG_ECT_DUMP)
|
|
|
|
static int ect_dump_header(struct seq_file *s, void *data);
|
|
static int ect_dump_dvfs(struct seq_file *s, void *data);
|
|
static int ect_dump_pll(struct seq_file *s, void *data);
|
|
static int ect_dump_voltage(struct seq_file *s, void *data);
|
|
static int ect_dump_rcc(struct seq_file *s, void *data);
|
|
static int ect_dump_mif_thermal(struct seq_file *s, void *data);
|
|
static int ect_dump_ap_thermal(struct seq_file *s, void *data);
|
|
static int ect_dump_margin(struct seq_file *s, void *data);
|
|
static int ect_dump_timing_parameter(struct seq_file *s, void *data);
|
|
static int ect_dump_minlock(struct seq_file *s, void *data);
|
|
static int ect_dump_gen_parameter(struct seq_file *s, void *data);
|
|
static int ect_dump_binary(struct seq_file *s, void *data);
|
|
static int ect_dump_new_timing_parameter(struct seq_file *s, void *data);
|
|
static int ect_dump_pidtm(struct seq_file *s, void *data);
|
|
|
|
static int dump_open(struct inode *inode, struct file *file);
|
|
|
|
#else
|
|
|
|
#define ect_dump_header NULL
|
|
#define ect_dump_ap_thermal NULL
|
|
#define ect_dump_voltage NULL
|
|
#define ect_dump_dvfs NULL
|
|
#define ect_dump_margin NULL
|
|
#define ect_dump_mif_thermal NULL
|
|
#define ect_dump_pll NULL
|
|
#define ect_dump_rcc NULL
|
|
#define ect_dump_timing_parameter NULL
|
|
#define ect_dump_minlock NULL
|
|
#define ect_dump_gen_parameter NULL
|
|
#define ect_dump_binary NULL
|
|
#define ect_dump_new_timing_parameter NULL
|
|
#define ect_dump_pidtm NULL
|
|
|
|
#define dump_open NULL
|
|
|
|
#endif
|
|
|
|
static struct ect_info ect_header_info = {
|
|
.block_name = BLOCK_HEADER,
|
|
.dump = ect_dump_header,
|
|
.dump_ops = {
|
|
.open = dump_open,
|
|
.read = seq_read,
|
|
.llseek = seq_lseek,
|
|
.release = single_release,
|
|
},
|
|
.dump_node_name = SYSFS_NODE_HEADER,
|
|
.block_handle = NULL,
|
|
.block_precedence = -1,
|
|
};
|
|
|
|
static struct ect_info ect_list[] = {
|
|
{
|
|
.block_name = BLOCK_AP_THERMAL,
|
|
.block_name_length = sizeof(BLOCK_AP_THERMAL) - 1,
|
|
.parser = ect_parse_ap_thermal_header,
|
|
.dump = ect_dump_ap_thermal,
|
|
.dump_ops = {
|
|
.open = dump_open,
|
|
.read = seq_read,
|
|
.llseek = seq_lseek,
|
|
.release = single_release
|
|
},
|
|
.dump_node_name = SYSFS_NODE_AP_THERMAL,
|
|
.block_handle = NULL,
|
|
.block_precedence = -1,
|
|
}, {
|
|
.block_name = BLOCK_ASV,
|
|
.block_name_length = sizeof(BLOCK_ASV) - 1,
|
|
.parser = ect_parse_voltage_header,
|
|
.dump = ect_dump_voltage,
|
|
.dump_ops = {
|
|
.open = dump_open,
|
|
.read = seq_read,
|
|
.llseek = seq_lseek,
|
|
.release = single_release
|
|
},
|
|
.dump_node_name = SYSFS_NODE_ASV,
|
|
.block_handle = NULL,
|
|
.block_precedence = -1,
|
|
}, {
|
|
.block_name = BLOCK_DVFS,
|
|
.block_name_length = sizeof(BLOCK_DVFS) - 1,
|
|
.parser = ect_parse_dvfs_header,
|
|
.dump = ect_dump_dvfs,
|
|
.dump_ops = {
|
|
.open = dump_open,
|
|
.read = seq_read,
|
|
.llseek = seq_lseek,
|
|
.release = single_release
|
|
},
|
|
.dump_node_name = SYSFS_NODE_DVFS,
|
|
.block_handle = NULL,
|
|
.block_precedence = -1,
|
|
}, {
|
|
.block_name = BLOCK_MARGIN,
|
|
.block_name_length = sizeof(BLOCK_MARGIN) - 1,
|
|
.parser = ect_parse_margin_header,
|
|
.dump = ect_dump_margin,
|
|
.dump_ops = {
|
|
.open = dump_open,
|
|
.read = seq_read,
|
|
.llseek = seq_lseek,
|
|
.release = single_release
|
|
},
|
|
.dump_node_name = SYSFS_NODE_MARGIN,
|
|
.block_handle = NULL,
|
|
.block_precedence = -1,
|
|
}, {
|
|
.block_name = BLOCK_MIF_THERMAL,
|
|
.block_name_length = sizeof(BLOCK_MIF_THERMAL) - 1,
|
|
.parser = ect_parse_mif_thermal_header,
|
|
.dump = ect_dump_mif_thermal,
|
|
.dump_ops = {
|
|
.open = dump_open,
|
|
.read = seq_read,
|
|
.llseek = seq_lseek,
|
|
.release = single_release
|
|
},
|
|
.dump_node_name = SYSFS_NODE_MIF_THERMAL,
|
|
.block_handle = NULL,
|
|
.block_precedence = -1,
|
|
}, {
|
|
.block_name = BLOCK_PLL,
|
|
.block_name_length = sizeof(BLOCK_PLL) - 1,
|
|
.parser = ect_parse_pll_header,
|
|
.dump = ect_dump_pll,
|
|
.dump_ops = {
|
|
.open = dump_open,
|
|
.read = seq_read,
|
|
.llseek = seq_lseek,
|
|
.release = single_release
|
|
},
|
|
.dump_node_name = SYSFS_NODE_PLL,
|
|
.block_handle = NULL,
|
|
.block_precedence = -1,
|
|
}, {
|
|
.block_name = BLOCK_RCC,
|
|
.block_name_length = sizeof(BLOCK_RCC) - 1,
|
|
.parser = ect_parse_rcc_header,
|
|
.dump = ect_dump_rcc,
|
|
.dump_ops = {
|
|
.open = dump_open,
|
|
.read = seq_read,
|
|
.llseek = seq_lseek,
|
|
.release = single_release
|
|
},
|
|
.dump_node_name = SYSFS_NODE_RCC,
|
|
.block_handle = NULL,
|
|
.block_precedence = -1,
|
|
}, {
|
|
.block_name = BLOCK_TIMING_PARAM,
|
|
.block_name_length = sizeof(BLOCK_TIMING_PARAM) - 1,
|
|
.parser = ect_parse_timing_param_header,
|
|
.dump = ect_dump_timing_parameter,
|
|
.dump_ops = {
|
|
.open = dump_open,
|
|
.read = seq_read,
|
|
.llseek = seq_lseek,
|
|
.release = single_release
|
|
},
|
|
.dump_node_name = SYSFS_NODE_TIMING_PARAM,
|
|
.block_handle = NULL,
|
|
.block_precedence = -1,
|
|
}, {
|
|
.block_name = BLOCK_MINLOCK,
|
|
.block_name_length = sizeof(BLOCK_MINLOCK) - 1,
|
|
.parser = ect_parse_minlock_header,
|
|
.dump = ect_dump_minlock,
|
|
.dump_ops = {
|
|
.open = dump_open,
|
|
.read = seq_read,
|
|
.llseek = seq_lseek,
|
|
.release = single_release
|
|
},
|
|
.dump_node_name = SYSFS_NODE_MINLOCK,
|
|
.block_handle = NULL,
|
|
.block_precedence = -1,
|
|
}, {
|
|
.block_name = BLOCK_GEN_PARAM,
|
|
.block_name_length = sizeof(BLOCK_GEN_PARAM) - 1,
|
|
.parser = ect_parse_gen_param_header,
|
|
.dump = ect_dump_gen_parameter,
|
|
.dump_ops = {
|
|
.open = dump_open,
|
|
.read = seq_read,
|
|
.llseek = seq_lseek,
|
|
.release = single_release
|
|
},
|
|
.dump_node_name = SYSFS_NODE_GEN_PARAM,
|
|
.block_handle = NULL,
|
|
.block_precedence = -1,
|
|
}, {
|
|
.block_name = BLOCK_BIN,
|
|
.block_name_length = sizeof(BLOCK_BIN) - 1,
|
|
.parser = ect_parse_bin_header,
|
|
.dump = ect_dump_binary,
|
|
.dump_ops = {
|
|
.open = dump_open,
|
|
.read = seq_read,
|
|
.llseek = seq_lseek,
|
|
.release = single_release
|
|
},
|
|
.dump_node_name = SYSFS_NODE_BIN,
|
|
.block_handle = NULL,
|
|
.block_precedence = -1,
|
|
}, {
|
|
.block_name = BLOCK_NEW_TIMING_PARAM,
|
|
.block_name_length = sizeof(BLOCK_NEW_TIMING_PARAM) - 1,
|
|
.parser = ect_parse_new_timing_param_header,
|
|
.dump = ect_dump_new_timing_parameter,
|
|
.dump_ops = {
|
|
.open = dump_open,
|
|
.read = seq_read,
|
|
.llseek = seq_lseek,
|
|
.release = single_release,
|
|
},
|
|
.dump_node_name = SYSFS_NODE_NEW_TIMING_PARAM,
|
|
.block_handle = NULL,
|
|
.block_precedence = -1,
|
|
}, {
|
|
.block_name = BLOCK_PIDTM,
|
|
.block_name_length = sizeof(BLOCK_PIDTM) - 1,
|
|
.parser = ect_parse_pidtm_header,
|
|
.dump = ect_dump_pidtm,
|
|
.dump_ops = {
|
|
.open = dump_open,
|
|
.read = seq_read,
|
|
.llseek = seq_lseek,
|
|
.release = single_release,
|
|
},
|
|
.dump_node_name = SYSFS_NODE_PIDTM,
|
|
.block_handle = NULL,
|
|
.block_precedence = -1,
|
|
}
|
|
};
|
|
|
|
#if defined(CONFIG_ECT_DUMP)
|
|
|
|
static struct ect_info* ect_get_info(char *block_name)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < ARRAY_SIZE32(ect_list); ++i) {
|
|
if (ect_strcmp(block_name, ect_list[i].block_name) == 0)
|
|
return &ect_list[i];
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
static int ect_dump_header(struct seq_file *s, void *data)
|
|
{
|
|
struct ect_info *info = &ect_header_info;
|
|
struct ect_header *header = info->block_handle;
|
|
|
|
if (header == NULL) {
|
|
seq_printf(s, "[ECT] : there is no ECT Information\n");
|
|
return 0;
|
|
}
|
|
|
|
seq_printf(s, "[ECT] : ECT Information\n");
|
|
seq_printf(s, "\t[VA] : %p\n", (void *)S5P_VA_ECT);
|
|
seq_printf(s, "\t[SIGN] : %c%c%c%c\n",
|
|
header->sign[0],
|
|
header->sign[1],
|
|
header->sign[2],
|
|
header->sign[3]);
|
|
seq_printf(s, "\t[VERSION] : %c%c%c%c\n",
|
|
header->version[0],
|
|
header->version[1],
|
|
header->version[2],
|
|
header->version[3]);
|
|
seq_printf(s, "\t[TOTAL SIZE] : %d\n", header->total_size);
|
|
seq_printf(s, "\t[NUM OF HEADER] : %d\n", header->num_of_header);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int ect_dump_dvfs(struct seq_file *s, void *data)
|
|
{
|
|
int i, j, k;
|
|
struct ect_info *info = ect_get_info(BLOCK_DVFS);
|
|
struct ect_dvfs_header *ect_dvfs_header = info->block_handle;
|
|
struct ect_dvfs_domain *domain;
|
|
|
|
if (ect_dvfs_header == NULL) {
|
|
seq_printf(s, "[ECT] : there is no dvfs information\n");
|
|
return 0;
|
|
}
|
|
|
|
seq_printf(s, "[ECT] : DVFS Information\n");
|
|
seq_printf(s, "\t[PARSER VERSION] : %d\n", ect_dvfs_header->parser_version);
|
|
seq_printf(s, "\t[VERSION] : %c%c%c%c\n",
|
|
ect_dvfs_header->version[0],
|
|
ect_dvfs_header->version[1],
|
|
ect_dvfs_header->version[2],
|
|
ect_dvfs_header->version[3]);
|
|
seq_printf(s, "\t[NUM OF DOMAIN] : %d\n", ect_dvfs_header->num_of_domain);
|
|
|
|
for (i = 0; i < ect_dvfs_header->num_of_domain; ++i) {
|
|
domain = &ect_dvfs_header->domain_list[i];
|
|
|
|
seq_printf(s, "\t\t[DOMAIN NAME] : %s\n", domain->domain_name);
|
|
seq_printf(s, "\t\t[BOOT LEVEL IDX] : ");
|
|
if (domain->boot_level_idx == -1) {
|
|
seq_printf(s, "NONE\n");
|
|
} else {
|
|
seq_printf(s, "%d\n", domain->boot_level_idx);
|
|
}
|
|
seq_printf(s, "\t\t[RESUME LEVEL IDX] : ");
|
|
if (domain->resume_level_idx == -1) {
|
|
seq_printf(s, "NONE\n");
|
|
} else {
|
|
seq_printf(s, "%d\n", domain->resume_level_idx);
|
|
}
|
|
seq_printf(s, "\t\t[MAX FREQ] : %u\n", domain->max_frequency);
|
|
seq_printf(s, "\t\t[MIN FREQ] : %u\n", domain->min_frequency);
|
|
if (domain->mode == e_dvfs_mode_clock_name) {
|
|
seq_printf(s, "\t\t[NUM OF CLOCK] : %d\n", domain->num_of_clock);
|
|
|
|
for (j = 0; j < domain->num_of_clock; ++j) {
|
|
seq_printf(s, "\t\t\t[CLOCK NAME] : %s\n", domain->list_clock[j]);
|
|
}
|
|
} else if (domain->mode == e_dvfs_mode_sfr_address) {
|
|
seq_printf(s, "\t\t[NUM OF SFR] : %d\n", domain->num_of_clock);
|
|
|
|
for (j = 0; j < domain->num_of_clock; ++j) {
|
|
seq_printf(s, "\t\t\t[SFR ADDRESS] : %x\n", domain->list_sfr[j]);
|
|
}
|
|
}
|
|
|
|
seq_printf(s, "\t\t[NUM OF LEVEL] : %d\n", domain->num_of_level);
|
|
|
|
for (j = 0; j < domain->num_of_level; ++j) {
|
|
seq_printf(s, "\t\t\t[LEVEL] : %u(%c)\n",
|
|
domain->list_level[j].level,
|
|
domain->list_level[j].level_en ? 'O' : 'X');
|
|
}
|
|
|
|
seq_printf(s, "\t\t\t\t[TABLE]\n");
|
|
for (j = 0; j < domain->num_of_level; ++j) {
|
|
seq_printf(s, "\t\t\t\t");
|
|
for (k = 0; k < domain->num_of_clock; ++k) {
|
|
seq_printf(s, "%u ", domain->list_dvfs_value[j * domain->num_of_clock + k]);
|
|
}
|
|
seq_printf(s, "\n");
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int ect_dump_pll(struct seq_file *s, void *data)
|
|
{
|
|
int i, j;
|
|
struct ect_info *info = ect_get_info(BLOCK_PLL);
|
|
struct ect_pll_header *ect_pll_header = info->block_handle;
|
|
struct ect_pll *pll;
|
|
struct ect_pll_frequency *frequency;
|
|
|
|
if (ect_pll_header == NULL) {
|
|
seq_printf(s, "[ECT] : there is no pll information\n");
|
|
return 0;
|
|
}
|
|
|
|
seq_printf(s, "[ECT] : PLL Information\n");
|
|
seq_printf(s, "\t[PARSER VERSION] : %d\n", ect_pll_header->parser_version);
|
|
seq_printf(s, "\t[VERSION] : %c%c%c%c\n",
|
|
ect_pll_header->version[0],
|
|
ect_pll_header->version[1],
|
|
ect_pll_header->version[2],
|
|
ect_pll_header->version[3]);
|
|
seq_printf(s, "\t[NUM OF PLL] : %d\n", ect_pll_header->num_of_pll);
|
|
|
|
for (i = 0; i < ect_pll_header->num_of_pll; ++i) {
|
|
pll = &ect_pll_header->pll_list[i];
|
|
|
|
seq_printf(s, "\t\t[PLL NAME] : %s\n", pll->pll_name);
|
|
seq_printf(s, "\t\t[PLL TYPE] : %d\n", pll->type_pll);
|
|
seq_printf(s, "\t\t[NUM OF FREQUENCY] : %d\n", pll->num_of_frequency);
|
|
|
|
for (j = 0; j < pll->num_of_frequency; ++j) {
|
|
frequency = &pll->frequency_list[j];
|
|
|
|
seq_printf(s, "\t\t\t[FREQUENCY] : %u\n", frequency->frequency);
|
|
seq_printf(s, "\t\t\t[P] : %d\n", frequency->p);
|
|
seq_printf(s, "\t\t\t[M] : %d\n", frequency->m);
|
|
seq_printf(s, "\t\t\t[S] : %d\n", frequency->s);
|
|
seq_printf(s, "\t\t\t[K] : %d\n", frequency->k);
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int ect_dump_voltage(struct seq_file *s, void *data)
|
|
{
|
|
int i, j, k, l;
|
|
struct ect_info *info = ect_get_info(BLOCK_ASV);
|
|
struct ect_voltage_header *ect_voltage_header = info->block_handle;
|
|
struct ect_voltage_domain *domain;
|
|
|
|
if (ect_voltage_header == NULL) {
|
|
seq_printf(s, "[ECT] : there is no asv information\n");
|
|
return 0;
|
|
}
|
|
|
|
seq_printf(s, "[ECT] : ASV Voltage Information\n");
|
|
seq_printf(s, "\t[PARSER VERSION] : %d\n", ect_voltage_header->parser_version);
|
|
seq_printf(s, "\t[VERSION] : %c%c%c%c\n",
|
|
ect_voltage_header->version[0],
|
|
ect_voltage_header->version[1],
|
|
ect_voltage_header->version[2],
|
|
ect_voltage_header->version[3]);
|
|
seq_printf(s, "\t[NUM OF DOMAIN] : %d\n", ect_voltage_header->num_of_domain);
|
|
|
|
for (i = 0; i < ect_voltage_header->num_of_domain; ++i) {
|
|
domain = &ect_voltage_header->domain_list[i];
|
|
|
|
seq_printf(s, "\t\t[DOMAIN NAME] : %s\n", domain->domain_name);
|
|
seq_printf(s, "\t\t[NUM OF ASV GROUP] : %d\n", domain->num_of_group);
|
|
seq_printf(s, "\t\t[NUM OF LEVEL] : %d\n", domain->num_of_level);
|
|
|
|
for (j = 0; j < domain->num_of_level; ++j) {
|
|
seq_printf(s, "\t\t\t[FREQUENCY] : %u\n", domain->level_list[j]);
|
|
}
|
|
|
|
seq_printf(s, "\t\t[NUM OF TABLE] : %d\n", domain->num_of_table);
|
|
|
|
for (j = 0; j < domain->num_of_table; ++j) {
|
|
seq_printf(s, "\t\t\t[TABLE VERSION] : %d\n", domain->table_list[j].table_version);
|
|
seq_printf(s, "\t\t\t[BOOT LEVEL IDX] : ");
|
|
if (domain->table_list[j].boot_level_idx == -1) {
|
|
seq_printf(s, "NONE\n");
|
|
} else {
|
|
seq_printf(s, "%d\n", domain->table_list[j].boot_level_idx);
|
|
}
|
|
seq_printf(s, "\t\t\t[RESUME LEVEL IDX] : ");
|
|
if (domain->table_list[j].resume_level_idx == -1) {
|
|
seq_printf(s, "NONE\n");
|
|
} else {
|
|
seq_printf(s, "%d\n", domain->table_list[j].resume_level_idx);
|
|
}
|
|
seq_printf(s, "\t\t\t\t[TABLE]\n");
|
|
for (k = 0; k < domain->num_of_level; ++k) {
|
|
seq_printf(s, "\t\t\t\t");
|
|
for (l = 0; l < domain->num_of_group; ++l) {
|
|
if (domain->table_list[j].voltages != NULL)
|
|
seq_printf(s, "%u ", domain->table_list[j].voltages[k * domain->num_of_group + l]);
|
|
else if (domain->table_list[j].voltages_step != NULL)
|
|
seq_printf(s, "%u ", domain->table_list[j].voltages_step[k * domain->num_of_group + l]
|
|
* domain->table_list[j].volt_step);
|
|
}
|
|
seq_printf(s, "\n");
|
|
}
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int ect_dump_rcc(struct seq_file *s, void *data)
|
|
{
|
|
int i, j, k, l;
|
|
struct ect_info *info = ect_get_info(BLOCK_RCC);
|
|
struct ect_rcc_header *ect_rcc_header = info->block_handle;
|
|
struct ect_rcc_domain *domain;
|
|
|
|
if (ect_rcc_header == NULL) {
|
|
seq_printf(s, "[ECT] : there is no rcc information\n");
|
|
return 0;
|
|
}
|
|
|
|
seq_printf(s, "[ECT] : RCC Information\n");
|
|
seq_printf(s, "\t[PARSER VERSION] : %d\n", ect_rcc_header->parser_version);
|
|
seq_printf(s, "\t[VERSION] : %c%c%c%c\n",
|
|
ect_rcc_header->version[0],
|
|
ect_rcc_header->version[1],
|
|
ect_rcc_header->version[2],
|
|
ect_rcc_header->version[3]);
|
|
seq_printf(s, "\t[NUM OF DOMAIN] : %d\n", ect_rcc_header->num_of_domain);
|
|
|
|
for (i = 0; i < ect_rcc_header->num_of_domain; ++i) {
|
|
domain = &ect_rcc_header->domain_list[i];
|
|
|
|
seq_printf(s, "\t\t[DOMAIN NAME] : %s\n", domain->domain_name);
|
|
seq_printf(s, "\t\t[NUM OF ASV GROUP] : %d\n", domain->num_of_group);
|
|
seq_printf(s, "\t\t[NUM OF LEVEL] : %d\n", domain->num_of_level);
|
|
|
|
for (j = 0; j < domain->num_of_level; ++j) {
|
|
seq_printf(s, "\t\t\t[FREQUENCY] : %u\n", domain->level_list[j]);
|
|
}
|
|
|
|
seq_printf(s, "\t\t[NUM OF TABLE] : %d\n", domain->num_of_table);
|
|
|
|
for (j = 0; j < domain->num_of_table; ++j) {
|
|
seq_printf(s, "\t\t\t[TABLE VERSION] : %d\n", domain->table_list[j].table_version);
|
|
|
|
seq_printf(s, "\t\t\t\t[TABLE]\n");
|
|
for (k = 0; k < domain->num_of_level; ++k) {
|
|
seq_printf(s, "\t\t\t\t");
|
|
for (l = 0; l < domain->num_of_group; ++l) {
|
|
if (domain->table_list[j].rcc != NULL)
|
|
seq_printf(s, "%u ", domain->table_list[j].rcc[k * domain->num_of_group + l]);
|
|
else if (domain->table_list[j].rcc_compact != NULL)
|
|
seq_printf(s, "%u ", domain->table_list[j].rcc_compact[k * domain->num_of_group + l]);
|
|
}
|
|
seq_printf(s, "\n");
|
|
}
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int ect_dump_mif_thermal(struct seq_file *s, void *data)
|
|
{
|
|
int i;
|
|
struct ect_info *info = ect_get_info(BLOCK_MIF_THERMAL);
|
|
struct ect_mif_thermal_header *ect_mif_thermal_header = info->block_handle;
|
|
struct ect_mif_thermal_level *level;
|
|
|
|
if (ect_mif_thermal_header == NULL) {
|
|
seq_printf(s, "[ECT] : there is no mif thermal information\n");
|
|
return 0;
|
|
}
|
|
|
|
seq_printf(s, "[ECT] : MIF Thermal Information\n");
|
|
seq_printf(s, "\t[PARSER VERSION] : %d\n", ect_mif_thermal_header->parser_version);
|
|
seq_printf(s, "\t[VERSION] : %c%c%c%c\n",
|
|
ect_mif_thermal_header->version[0],
|
|
ect_mif_thermal_header->version[1],
|
|
ect_mif_thermal_header->version[2],
|
|
ect_mif_thermal_header->version[3]);
|
|
seq_printf(s, "\t[NUM OF LEVEL] : %d\n", ect_mif_thermal_header->num_of_level);
|
|
|
|
for (i = 0; i < ect_mif_thermal_header->num_of_level; ++i) {
|
|
level = &ect_mif_thermal_header->level[i];
|
|
|
|
seq_printf(s, "\t\t[MR4 LEVEL] : %d\n", level->mr4_level);
|
|
seq_printf(s, "\t\t[MAX FREQUENCY] : %u\n", level->max_frequency);
|
|
seq_printf(s, "\t\t[MIN FREQUENCY] : %u\n", level->min_frequency);
|
|
seq_printf(s, "\t\t[REFRESH RATE] : %u\n", level->refresh_rate_value);
|
|
seq_printf(s, "\t\t[POLLING PERIOD] : %u\n", level->polling_period);
|
|
seq_printf(s, "\t\t[SW TRIP] : %u\n", level->sw_trip);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int ect_dump_ap_thermal(struct seq_file *s, void *data)
|
|
{
|
|
int i, j;
|
|
struct ect_info *info = ect_get_info(BLOCK_AP_THERMAL);
|
|
struct ect_ap_thermal_header *ect_ap_thermal_header = info->block_handle;
|
|
struct ect_ap_thermal_function *function;
|
|
struct ect_ap_thermal_range *range;
|
|
|
|
if (ect_ap_thermal_header == NULL) {
|
|
seq_printf(s, "[ECT] : there is no ap thermal information\n");
|
|
return 0;
|
|
}
|
|
|
|
seq_printf(s, "[ECT] : AP Thermal Information\n");
|
|
seq_printf(s, "\t[PARSER VERSION] : %d\n", ect_ap_thermal_header->parser_version);
|
|
seq_printf(s, "\t[VERSION] : %c%c%c%c\n",
|
|
ect_ap_thermal_header->version[0],
|
|
ect_ap_thermal_header->version[1],
|
|
ect_ap_thermal_header->version[2],
|
|
ect_ap_thermal_header->version[3]);
|
|
seq_printf(s, "\t[NUM OF FUNCTION] : %d\n", ect_ap_thermal_header->num_of_function);
|
|
|
|
for (i = 0; i < ect_ap_thermal_header->num_of_function; ++i) {
|
|
function = &ect_ap_thermal_header->function_list[i];
|
|
|
|
seq_printf(s, "\t\t[FUNCTION NAME] : %s\n", function->function_name);
|
|
seq_printf(s, "\t\t[NUM OF RANGE] : %d\n", function->num_of_range);
|
|
|
|
for (j = 0; j < function->num_of_range; ++j) {
|
|
range = &function->range_list[j];
|
|
|
|
seq_printf(s, "\t\t\t[LOWER BOUND TEMPERATURE] : %u\n", range->lower_bound_temperature);
|
|
seq_printf(s, "\t\t\t[UPPER BOUND TEMPERATURE] : %u\n", range->upper_bound_temperature);
|
|
seq_printf(s, "\t\t\t[MAX FREQUENCY] : %u\n", range->max_frequency);
|
|
seq_printf(s, "\t\t\t[SW TRIP] : %u\n", range->sw_trip);
|
|
seq_printf(s, "\t\t\t[FLAG] : %u\n", range->flag);
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int ect_dump_margin(struct seq_file *s, void *data)
|
|
{
|
|
int i, j, k;
|
|
struct ect_info *info = ect_get_info(BLOCK_MARGIN);
|
|
struct ect_margin_header *ect_margin_header = info->block_handle;
|
|
struct ect_margin_domain *domain;
|
|
|
|
if (ect_margin_header == NULL) {
|
|
seq_printf(s, "[ECT] : there is no margin information\n");
|
|
return 0;
|
|
}
|
|
|
|
seq_printf(s, "[ECT] : Margin Information\n");
|
|
seq_printf(s, "\t[PARSER VERSION] : %d\n", ect_margin_header->parser_version);
|
|
seq_printf(s, "\t[VERSION] : %c%c%c%c\n",
|
|
ect_margin_header->version[0],
|
|
ect_margin_header->version[1],
|
|
ect_margin_header->version[2],
|
|
ect_margin_header->version[3]);
|
|
seq_printf(s, "\t[NUM OF DOMAIN] : %d\n", ect_margin_header->num_of_domain);
|
|
|
|
for (i = 0; i < ect_margin_header->num_of_domain; ++i) {
|
|
domain = &ect_margin_header->domain_list[i];
|
|
|
|
seq_printf(s, "\t\t[DOMAIN NAME] : %s\n", domain->domain_name);
|
|
seq_printf(s, "\t\t[NUM OF GROUP] : %d\n", domain->num_of_group);
|
|
seq_printf(s, "\t\t[NUM OF LEVEL] : %d\n", domain->num_of_level);
|
|
|
|
seq_printf(s, "\t\t\t[TABLE]\n");
|
|
for (j = 0; j < domain->num_of_level; ++j) {
|
|
seq_printf(s, "\t\t\t");
|
|
for (k = 0; k < domain->num_of_group; ++k) {
|
|
if (domain->offset != NULL)
|
|
seq_printf(s, "%u ", domain->offset[j * domain->num_of_group + k]);
|
|
else if (domain->offset_compact != NULL)
|
|
seq_printf(s, "%u ", domain->offset_compact[j * domain->num_of_group + k]
|
|
* domain->volt_step);
|
|
}
|
|
seq_printf(s, "\n");
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int ect_dump_timing_parameter(struct seq_file *s, void *data)
|
|
{
|
|
int i, j, k;
|
|
struct ect_info *info = ect_get_info(BLOCK_TIMING_PARAM);
|
|
struct ect_timing_param_header *ect_timing_param_header = info->block_handle;
|
|
struct ect_timing_param_size *size;
|
|
|
|
if (ect_timing_param_header == NULL) {
|
|
seq_printf(s, "[ECT] : there is no timing parameter information\n");
|
|
return 0;
|
|
}
|
|
|
|
seq_printf(s, "[ECT] : Timing-Parameter Information\n");
|
|
seq_printf(s, "\t[PARSER VERSION] : %d\n", ect_timing_param_header->parser_version);
|
|
seq_printf(s, "\t[VERSION] : %c%c%c%c\n",
|
|
ect_timing_param_header->version[0],
|
|
ect_timing_param_header->version[1],
|
|
ect_timing_param_header->version[2],
|
|
ect_timing_param_header->version[3]);
|
|
seq_printf(s, "\t[NUM OF SIZE] : %d\n", ect_timing_param_header->num_of_size);
|
|
|
|
for (i = 0; i < ect_timing_param_header->num_of_size; ++i) {
|
|
size = &ect_timing_param_header->size_list[i];
|
|
|
|
seq_printf(s, "\t\t[PARAMETER KEY] : %p\n", (void *)size->parameter_key);
|
|
seq_printf(s, "\t\t[NUM OF TIMING PARAMETER] : %d\n", size->num_of_timing_param);
|
|
seq_printf(s, "\t\t[NUM OF LEVEL] : %d\n", size->num_of_level);
|
|
|
|
seq_printf(s, "\t\t\t[TABLE]\n");
|
|
for (j = 0; j < size->num_of_level; ++j) {
|
|
seq_printf(s, "\t\t\t");
|
|
for (k = 0; k < size->num_of_timing_param; ++k) {
|
|
seq_printf(s, "%X ", size->timing_parameter[j * size->num_of_timing_param + k]);
|
|
}
|
|
seq_printf(s, "\n");
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int ect_dump_minlock(struct seq_file *s, void *data)
|
|
{
|
|
int i, j;
|
|
struct ect_info *info = ect_get_info(BLOCK_MINLOCK);
|
|
struct ect_minlock_header *ect_minlock_header = info->block_handle;
|
|
struct ect_minlock_domain *domain;
|
|
|
|
if (ect_minlock_header == NULL) {
|
|
seq_printf(s, "[ECT] : there is no minlock information\n");
|
|
return 0;
|
|
}
|
|
|
|
seq_printf(s, "[ECT] : Minlock Information\n");
|
|
seq_printf(s, "\t[PARSER VERSION] : %d\n", ect_minlock_header->parser_version);
|
|
seq_printf(s, "\t[VERSION] : %c%c%c%c\n",
|
|
ect_minlock_header->version[0],
|
|
ect_minlock_header->version[1],
|
|
ect_minlock_header->version[2],
|
|
ect_minlock_header->version[3]);
|
|
seq_printf(s, "\t[NUM OF DOMAIN] : %d\n", ect_minlock_header->num_of_domain);
|
|
|
|
for (i = 0; i < ect_minlock_header->num_of_domain; ++i) {
|
|
domain = &ect_minlock_header->domain_list[i];
|
|
|
|
seq_printf(s, "\t\t[DOMAIN NAME] : %s\n", domain->domain_name);
|
|
|
|
for (j = 0; j < domain->num_of_level; ++j) {
|
|
seq_printf(s, "\t\t\t[Frequency] : (MAIN)%u, (SUB)%u\n",
|
|
domain->level[j].main_frequencies,
|
|
domain->level[j].sub_frequencies);
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int ect_dump_gen_parameter(struct seq_file *s, void *data)
|
|
{
|
|
int i, j, k;
|
|
struct ect_info *info = ect_get_info(BLOCK_GEN_PARAM);
|
|
struct ect_gen_param_header *ect_gen_param_header = info->block_handle;
|
|
struct ect_gen_param_table *table;
|
|
|
|
if (ect_gen_param_header == NULL) {
|
|
seq_printf(s, "[ECT] : there is no general parameter information\n");
|
|
return 0;
|
|
}
|
|
|
|
seq_printf(s, "[ECT] : General-Parameter Information\n");
|
|
seq_printf(s, "\t[PARSER VERSION] : %d\n", ect_gen_param_header->parser_version);
|
|
seq_printf(s, "\t[VERSION] : %c%c%c%c\n",
|
|
ect_gen_param_header->version[0],
|
|
ect_gen_param_header->version[1],
|
|
ect_gen_param_header->version[2],
|
|
ect_gen_param_header->version[3]);
|
|
seq_printf(s, "\t[NUM OF TABLE] : %d\n", ect_gen_param_header->num_of_table);
|
|
|
|
for (i = 0; i < ect_gen_param_header->num_of_table; ++i) {
|
|
table = &ect_gen_param_header->table_list[i];
|
|
|
|
seq_printf(s, "\t\t[TABLE NAME] : %s\n", table->table_name);
|
|
seq_printf(s, "\t\t[NUM OF COLUMN] : %d\n", table->num_of_col);
|
|
seq_printf(s, "\t\t[NUM OF ROW] : %d\n", table->num_of_row);
|
|
|
|
seq_printf(s, "\t\t\t[TABLE]\n");
|
|
for (j = 0; j < table->num_of_row; ++j) {
|
|
seq_printf(s, "\t\t\t");
|
|
for (k = 0; k < table->num_of_col; ++k) {
|
|
seq_printf(s, "%u ", table->parameter[j * table->num_of_col + k]);
|
|
}
|
|
seq_printf(s, "\n");
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int ect_dump_binary(struct seq_file *s, void *data)
|
|
{
|
|
int i, j, crc;
|
|
struct ect_info *info = ect_get_info(BLOCK_BIN);
|
|
struct ect_bin_header *ect_binary_header = info->block_handle;
|
|
struct ect_bin *bin;
|
|
char *data_ptr;
|
|
|
|
if (ect_binary_header == NULL) {
|
|
seq_printf(s, "[ECT] : there is no binary information\n");
|
|
return 0;
|
|
}
|
|
|
|
seq_printf(s, "[ECT] : Binary Information\n");
|
|
seq_printf(s, "\t[PARSER VERSION] : %d\n", ect_binary_header->parser_version);
|
|
seq_printf(s, "\t[VERSION] : %c%c%c%c\n",
|
|
ect_binary_header->version[0],
|
|
ect_binary_header->version[1],
|
|
ect_binary_header->version[2],
|
|
ect_binary_header->version[3]);
|
|
seq_printf(s, "\t[NUM OF BINARY] : %d\n", ect_binary_header->num_of_binary);
|
|
|
|
for (i = 0; i < ect_binary_header->num_of_binary; ++i) {
|
|
bin = &ect_binary_header->binary_list[i];
|
|
|
|
seq_printf(s, "\t\t[BINARY NAME] : %s\n", bin->binary_name);
|
|
|
|
crc = 0;
|
|
data_ptr = bin->ptr;
|
|
for (j = 0; j < bin->binary_size; ++j) {
|
|
crc ^= data_ptr[j] << (j & 31);
|
|
}
|
|
seq_printf(s, "\t\t\t[BINARY CRC] : %x\n", crc);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int ect_dump_new_timing_parameter(struct seq_file *s, void *data)
|
|
{
|
|
int i, j, k;
|
|
struct ect_info *info = ect_get_info(BLOCK_NEW_TIMING_PARAM);
|
|
struct ect_new_timing_param_header *ect_new_timing_param_header = info->block_handle;
|
|
struct ect_new_timing_param_size *size;
|
|
|
|
if (ect_new_timing_param_header == NULL) {
|
|
seq_printf(s, "[ECT] : there is no new timing parameter information\n");
|
|
return 0;
|
|
}
|
|
|
|
seq_printf(s, "[ECT] : New Timing-Parameter Information\n");
|
|
seq_printf(s, "\t[PARSER VERSION] : %d\n", ect_new_timing_param_header->parser_version);
|
|
seq_printf(s, "\t[VERSION] : %c%c%c%c\n",
|
|
ect_new_timing_param_header->version[0],
|
|
ect_new_timing_param_header->version[1],
|
|
ect_new_timing_param_header->version[2],
|
|
ect_new_timing_param_header->version[3]);
|
|
seq_printf(s, "\t[NUM OF SIZE] : %d\n", ect_new_timing_param_header->num_of_size);
|
|
|
|
for (i = 0; i < ect_new_timing_param_header->num_of_size; ++i) {
|
|
size = &ect_new_timing_param_header->size_list[i];
|
|
|
|
seq_printf(s, "\t\t[PARAMETER KEY] : %llX\n", size->parameter_key);
|
|
seq_printf(s, "\t\t[NUM OF TIMING PARAMETER] : %d\n", size->num_of_timing_param);
|
|
seq_printf(s, "\t\t[NUM OF LEVEL] : %d\n", size->num_of_level);
|
|
|
|
seq_printf(s, "\t\t\t[TABLE]\n");
|
|
for (j = 0; j < size->num_of_level; ++j) {
|
|
seq_printf(s, "\t\t\t");
|
|
for (k = 0; k < size->num_of_timing_param; ++k) {
|
|
if (size->mode == e_mode_normal_value)
|
|
seq_printf(s, "%X ", size->timing_parameter[j * size->num_of_timing_param + k]);
|
|
else if (size->mode == e_mode_extend_value)
|
|
seq_printf(s, "%llX ", ect_read_value64(size->timing_parameter, j * size->num_of_timing_param + k));
|
|
}
|
|
seq_printf(s, "\n");
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int ect_dump_pidtm(struct seq_file *s, void *data)
|
|
{
|
|
int i, j;
|
|
struct ect_info *info = ect_get_info(BLOCK_PIDTM);
|
|
struct ect_pidtm_header *ect_pidtm_header = info->block_handle;
|
|
struct ect_pidtm_block *block;
|
|
|
|
if (ect_pidtm_header == NULL) {
|
|
seq_printf(s, "[ECT] : there is no pidtm parameter information\n");
|
|
return 0;
|
|
}
|
|
|
|
seq_printf(s, "[ECT] : PIDTM Parameter Information\n");
|
|
seq_printf(s, "\t[PARSER VERSION] : %d\n", ect_pidtm_header->parser_version);
|
|
seq_printf(s, "\t[VERSION] : %c%c%c%c\n",
|
|
ect_pidtm_header->version[0],
|
|
ect_pidtm_header->version[1],
|
|
ect_pidtm_header->version[2],
|
|
ect_pidtm_header->version[3]);
|
|
seq_printf(s, "\t[NUM OF BLOCK] : %d\n", ect_pidtm_header->num_of_block);
|
|
|
|
for (i = 0; i < ect_pidtm_header->num_of_block; ++i) {
|
|
block = &ect_pidtm_header->block_list[i];
|
|
|
|
seq_printf(s, "\t\t[BLOCK NAME] : %s\n", block->block_name);
|
|
seq_printf(s, "\t\t[NUM OF TEMPERATURE] : %d\n", block->num_of_temperature);
|
|
|
|
for (j = 0; j < block->num_of_temperature; ++j) {
|
|
seq_printf(s, "\t\t\t[TRIGGER TEMPERATURE] : %d\n", block->temperature_list[j]);
|
|
}
|
|
|
|
seq_printf(s, "\t\t[NUM OF PARAMETER] : %d\n", block->num_of_parameter);
|
|
for (j = 0; j < block->num_of_parameter; ++j) {
|
|
seq_printf(s, "\t\t\t[PARAMETER] : %s, %d\n", block->param_name_list[j], block->param_value_list[j]);
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int dump_open(struct inode *inode, struct file *file)
|
|
{
|
|
struct ect_info *info = (struct ect_info *)inode->i_private;
|
|
|
|
return single_open(file, info->dump, inode->i_private);
|
|
}
|
|
|
|
static int ect_dump_all(struct seq_file *s, void *data)
|
|
{
|
|
int i, j, ret;
|
|
|
|
ret = ect_header_info.dump(s, data);
|
|
if (ret)
|
|
return ret;
|
|
|
|
for (i = 0; i < ARRAY_SIZE32(ect_list); ++i) {
|
|
for (j = 0; j < ARRAY_SIZE32(ect_list); ++j) {
|
|
if (ect_list[j].block_precedence != i)
|
|
continue;
|
|
|
|
ret = ect_list[j].dump(s, data);
|
|
if (ret)
|
|
return ret;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int dump_all_open(struct inode *inode, struct file *file)
|
|
{
|
|
return single_open(file, ect_dump_all, inode->i_private);
|
|
}
|
|
|
|
static struct file_operations ops_all_dump = {
|
|
.open = dump_all_open,
|
|
.read = seq_read,
|
|
.llseek = seq_lseek,
|
|
.release = single_release,
|
|
};
|
|
|
|
static ssize_t create_binary_store(struct class *class,
|
|
struct class_attribute *attr, const char *buf, size_t size)
|
|
{
|
|
char filename_buffer[512];
|
|
long pattern_fd;
|
|
mm_segment_t old_fs;
|
|
struct file *fp;
|
|
loff_t pos = 0;
|
|
int ret;
|
|
|
|
ret = sscanf(buf, "%511s", filename_buffer);
|
|
if (ret != 1)
|
|
return -EINVAL;
|
|
|
|
old_fs = get_fs();
|
|
set_fs(KERNEL_DS);
|
|
|
|
pattern_fd = do_sys_open(AT_FDCWD, filename_buffer, O_WRONLY | O_CREAT | O_TRUNC | O_SYNC | O_NOFOLLOW, 0664);
|
|
if (pattern_fd < 0) {
|
|
pr_err("[ECT] : error to open file\n");
|
|
set_fs(old_fs);
|
|
return -EINVAL;
|
|
}
|
|
|
|
fp = fget(pattern_fd);
|
|
if (fp) {
|
|
vfs_write(fp, (const char *)ect_address, ect_size, &pos);
|
|
vfs_fsync(fp, 0);
|
|
fput(fp);
|
|
} else {
|
|
pr_err("[ECT] : error to convert file\n");
|
|
}
|
|
|
|
get_close_on_exec(pattern_fd);
|
|
set_fs(old_fs);
|
|
|
|
return size;
|
|
}
|
|
|
|
|
|
static CLASS_ATTR_WO(create_binary);
|
|
|
|
|
|
static int ect_dump_init(void)
|
|
{
|
|
int i;
|
|
struct dentry *root, *d;
|
|
|
|
root = debugfs_create_dir("ect", NULL);
|
|
if (!root) {
|
|
pr_err("%s: couln't create debugfs\n", __FILE__);
|
|
return -ENOMEM;
|
|
}
|
|
|
|
d = debugfs_create_file("all_dump", S_IRUGO, root, NULL,
|
|
&ops_all_dump);
|
|
if (!d)
|
|
return -ENOMEM;
|
|
|
|
d = debugfs_create_file(ect_header_info.dump_node_name, S_IRUGO, root, &ect_header_info,
|
|
&ect_header_info.dump_ops);
|
|
if (!d)
|
|
return -ENOMEM;
|
|
|
|
for (i = 0; i < ARRAY_SIZE32(ect_list); ++i) {
|
|
if (ect_list[i].block_handle == NULL)
|
|
continue;
|
|
|
|
d = debugfs_create_file(ect_list[i].dump_node_name, S_IRUGO, root, &(ect_list[i]),
|
|
&ect_list[i].dump_ops);
|
|
if (!d)
|
|
return -ENOMEM;
|
|
}
|
|
|
|
ect_class = class_create(THIS_MODULE, "ect");
|
|
if (IS_ERR(ect_class)) {
|
|
pr_err("%s: couldn't create class\n", __FILE__);
|
|
return PTR_ERR(ect_class);
|
|
}
|
|
|
|
if (class_create_file(ect_class, &class_attr_create_binary)) {
|
|
pr_err("%s: couldn't create generate_data node\n", __FILE__);
|
|
return -EINVAL;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
late_initcall_sync(ect_dump_init);
|
|
#endif
|
|
|
|
/* API for external */
|
|
|
|
void __init ect_init(phys_addr_t address, phys_addr_t size)
|
|
{
|
|
ect_early_vm.phys_addr = address;
|
|
ect_early_vm.addr = (void *)S5P_VA_ECT;
|
|
ect_early_vm.size = size;
|
|
|
|
vm_area_add_early(&ect_early_vm);
|
|
|
|
ect_address = (phys_addr_t)S5P_VA_ECT;
|
|
ect_size = size;
|
|
}
|
|
|
|
unsigned long long ect_read_value64(unsigned int *address, int index)
|
|
{
|
|
unsigned int top, half;
|
|
|
|
index *= 2;
|
|
|
|
half = address[index];
|
|
top = address[index + 1];
|
|
|
|
return ((unsigned long long)top << 32 | half);
|
|
}
|
|
|
|
void *ect_get_block(char *block_name)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < ARRAY_SIZE32(ect_list); ++i) {
|
|
if (ect_strcmp(block_name, ect_list[i].block_name) == 0)
|
|
return ect_list[i].block_handle;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
struct ect_dvfs_domain *ect_dvfs_get_domain(void *block, char *domain_name)
|
|
{
|
|
int i;
|
|
struct ect_dvfs_header *header;
|
|
struct ect_dvfs_domain *domain;
|
|
|
|
if (block == NULL ||
|
|
domain_name == NULL)
|
|
return NULL;
|
|
|
|
header = (struct ect_dvfs_header *)block;
|
|
|
|
for (i = 0; i < header->num_of_domain; ++i) {
|
|
domain = &header->domain_list[i];
|
|
|
|
if (ect_strcmp(domain_name, domain->domain_name) == 0)
|
|
return domain;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
struct ect_pll *ect_pll_get_pll(void *block, char *pll_name)
|
|
{
|
|
int i;
|
|
struct ect_pll_header *header;
|
|
struct ect_pll *pll;
|
|
|
|
if (block == NULL ||
|
|
pll_name == NULL)
|
|
return NULL;
|
|
|
|
header = (struct ect_pll_header *)block;
|
|
|
|
for (i = 0; i < header->num_of_pll; ++i) {
|
|
pll = &header->pll_list[i];
|
|
|
|
if (ect_strcmp(pll_name, pll->pll_name) == 0)
|
|
return pll;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
struct ect_voltage_domain *ect_asv_get_domain(void *block, char *domain_name)
|
|
{
|
|
int i;
|
|
struct ect_voltage_header *header;
|
|
struct ect_voltage_domain *domain;
|
|
|
|
if (block == NULL ||
|
|
domain_name == NULL)
|
|
return NULL;
|
|
|
|
header = (struct ect_voltage_header *)block;
|
|
|
|
for (i = 0; i < header->num_of_domain; ++i) {
|
|
domain = &header->domain_list[i];
|
|
|
|
if (ect_strcmp(domain_name, domain->domain_name) == 0)
|
|
return domain;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
struct ect_rcc_domain *ect_rcc_get_domain(void *block, char *domain_name)
|
|
{
|
|
int i;
|
|
struct ect_rcc_header *header;
|
|
struct ect_rcc_domain *domain;
|
|
|
|
if (block == NULL ||
|
|
domain_name == NULL)
|
|
return NULL;
|
|
|
|
header = (struct ect_rcc_header *)block;
|
|
|
|
for (i = 0; i < header->num_of_domain; ++i) {
|
|
domain = &header->domain_list[i];
|
|
|
|
if (ect_strcmp(domain_name, domain->domain_name) == 0)
|
|
return domain;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
struct ect_mif_thermal_level *ect_mif_thermal_get_level(void *block, int mr4_level)
|
|
{
|
|
int i;
|
|
struct ect_mif_thermal_header *header;
|
|
struct ect_mif_thermal_level *level;
|
|
|
|
if (block == NULL)
|
|
return NULL;
|
|
|
|
header = (struct ect_mif_thermal_header *)block;
|
|
|
|
for (i = 0; i < header->num_of_level; ++i) {
|
|
level = &header->level[i];
|
|
|
|
if (level->mr4_level == mr4_level)
|
|
return level;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
struct ect_ap_thermal_function *ect_ap_thermal_get_function(void *block, char *function_name)
|
|
{
|
|
int i;
|
|
struct ect_ap_thermal_header *header;
|
|
struct ect_ap_thermal_function *function;
|
|
|
|
if (block == NULL ||
|
|
function_name == NULL)
|
|
return NULL;
|
|
|
|
header = (struct ect_ap_thermal_header *)block;
|
|
|
|
for (i = 0; i < header->num_of_function; ++i) {
|
|
function = &header->function_list[i];
|
|
|
|
if (ect_strcmp(function_name, function->function_name) == 0)
|
|
return function;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
struct ect_pidtm_block *ect_pidtm_get_block(void *block, char *block_name)
|
|
{
|
|
int i;
|
|
struct ect_pidtm_header *header;
|
|
struct ect_pidtm_block *pidtm_block;
|
|
|
|
if (block == NULL ||
|
|
block_name == NULL)
|
|
return NULL;
|
|
|
|
header = (struct ect_pidtm_header *)block;
|
|
|
|
for (i = 0; i < header->num_of_block; ++i) {
|
|
pidtm_block = &header->block_list[i];
|
|
|
|
if (ect_strcmp(block_name, pidtm_block->block_name) == 0)
|
|
return pidtm_block;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
struct ect_margin_domain *ect_margin_get_domain(void *block, char *domain_name)
|
|
{
|
|
int i;
|
|
struct ect_margin_header *header;
|
|
struct ect_margin_domain *domain;
|
|
|
|
if (block == NULL ||
|
|
domain_name == NULL)
|
|
return NULL;
|
|
|
|
header = (struct ect_margin_header *)block;
|
|
|
|
for (i = 0; i < header->num_of_domain; ++i) {
|
|
domain = &header->domain_list[i];
|
|
|
|
if (ect_strcmp(domain_name, domain->domain_name) == 0)
|
|
return domain;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
struct ect_timing_param_size *ect_timing_param_get_size(void *block, int dram_size)
|
|
{
|
|
int i;
|
|
struct ect_timing_param_header *header;
|
|
struct ect_timing_param_size *size;
|
|
|
|
if (block == NULL)
|
|
return NULL;
|
|
|
|
header = (struct ect_timing_param_header *)block;
|
|
|
|
for (i = 0; i < header->num_of_size; ++i) {
|
|
size = &header->size_list[i];
|
|
|
|
if (size->memory_size == dram_size)
|
|
return size;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
struct ect_timing_param_size *ect_timing_param_get_key(void *block, unsigned long long key)
|
|
{
|
|
int i;
|
|
struct ect_timing_param_header *header;
|
|
struct ect_timing_param_size *size;
|
|
|
|
if (block == NULL)
|
|
return NULL;
|
|
|
|
header = (struct ect_timing_param_header *)block;
|
|
|
|
for (i = 0; i < header->num_of_size; ++i) {
|
|
size = &header->size_list[i];
|
|
|
|
if (key == size->parameter_key)
|
|
return size;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
struct ect_minlock_domain *ect_minlock_get_domain(void *block, char *domain_name)
|
|
{
|
|
int i;
|
|
struct ect_minlock_header *header;
|
|
struct ect_minlock_domain *domain;
|
|
|
|
if (block == NULL ||
|
|
domain_name == NULL)
|
|
return NULL;
|
|
|
|
header = (struct ect_minlock_header *)block;
|
|
|
|
for (i = 0; i < header->num_of_domain; ++i) {
|
|
domain = &header->domain_list[i];
|
|
|
|
if (ect_strcmp(domain_name, domain->domain_name) == 0)
|
|
return domain;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
struct ect_gen_param_table *ect_gen_param_get_table(void *block, char *table_name)
|
|
{
|
|
int i;
|
|
struct ect_gen_param_header *header;
|
|
struct ect_gen_param_table *table;
|
|
|
|
if (block == NULL)
|
|
return NULL;
|
|
|
|
header = (struct ect_gen_param_header *)block;
|
|
|
|
for (i = 0; i < header->num_of_table; ++i) {
|
|
table = &header->table_list[i];
|
|
|
|
if (ect_strcmp(table->table_name, table_name) == 0)
|
|
return table;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
struct ect_bin *ect_binary_get_bin(void *block, char *binary_name)
|
|
{
|
|
int i;
|
|
struct ect_bin_header *header;
|
|
struct ect_bin *bin;
|
|
|
|
if (block == NULL)
|
|
return NULL;
|
|
|
|
header = (struct ect_bin_header *)block;
|
|
|
|
for (i = 0; i < header->num_of_binary; ++i) {
|
|
bin = &header->binary_list[i];
|
|
|
|
if (ect_strcmp(bin->binary_name, binary_name) == 0)
|
|
return bin;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
struct ect_new_timing_param_size *ect_new_timing_param_get_key(void *block, unsigned long long key)
|
|
{
|
|
int i;
|
|
struct ect_new_timing_param_header *header;
|
|
struct ect_new_timing_param_size *size;
|
|
|
|
if (block == NULL)
|
|
return NULL;
|
|
|
|
header = (struct ect_new_timing_param_header *)block;
|
|
|
|
for (i = 0; i < header->num_of_size; ++i) {
|
|
size = &header->size_list[i];
|
|
|
|
if (key == size->parameter_key)
|
|
return size;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
int ect_parse_binary_header(void)
|
|
{
|
|
int ret = 0;
|
|
int i, j;
|
|
char *block_name;
|
|
void *address;
|
|
unsigned int length, offset;
|
|
struct ect_header *ect_header;
|
|
|
|
ect_init_map_io();
|
|
|
|
address = (void *)ect_address;
|
|
if (address == NULL)
|
|
return -EINVAL;
|
|
|
|
ect_header = kzalloc(sizeof(struct ect_header), GFP_KERNEL);
|
|
|
|
ect_parse_integer(&address, ect_header->sign);
|
|
ect_parse_integer(&address, ect_header->version);
|
|
ect_parse_integer(&address, &ect_header->total_size);
|
|
ect_parse_integer(&address, &ect_header->num_of_header);
|
|
|
|
if (memcmp(ect_header->sign, ect_signature, sizeof(ect_signature) - 1)) {
|
|
ret = -EINVAL;
|
|
goto err_memcmp;
|
|
}
|
|
|
|
ect_present_test_data(ect_header->version);
|
|
|
|
for (i = 0; i < ect_header->num_of_header; ++i) {
|
|
if (ect_parse_string(&address, &block_name, &length)) {
|
|
ret = -EINVAL;
|
|
goto err_parse_string;
|
|
}
|
|
|
|
ect_parse_integer(&address, &offset);
|
|
|
|
for (j = 0; j < ARRAY_SIZE32(ect_list); ++j) {
|
|
if (strncmp(block_name, ect_list[j].block_name, ect_list[j].block_name_length) != 0)
|
|
continue;
|
|
|
|
if (ect_list[j].parser((void *)ect_address + offset, ect_list + j)) {
|
|
pr_err("[ECT] : parse error %s\n", block_name);
|
|
ret = -EINVAL;
|
|
goto err_parser;
|
|
}
|
|
|
|
ect_list[j].block_precedence = i;
|
|
}
|
|
}
|
|
|
|
ect_header_info.block_handle = ect_header;
|
|
|
|
return ret;
|
|
|
|
err_parser:
|
|
err_parse_string:
|
|
err_memcmp:
|
|
kfree(ect_header);
|
|
|
|
return ret;
|
|
}
|
|
|
|
int ect_strcmp(char *src1, char *src2)
|
|
{
|
|
for ( ; *src1 == *src2; src1++, src2++)
|
|
if (*src1 == '\0')
|
|
return 0;
|
|
|
|
return ((*(unsigned char *)src1 < *(unsigned char *)src2) ? -1 : +1);
|
|
}
|
|
|
|
int ect_strncmp(char *src1, char *src2, int length)
|
|
{
|
|
int i;
|
|
|
|
if (length <= 0)
|
|
return -1;
|
|
|
|
for (i = 0; i < length; i++, src1++, src2++)
|
|
if (*src1 != *src2)
|
|
return ((*(unsigned char *)src1 < *(unsigned char *)src2) ? -1 : +1);
|
|
|
|
return 0;
|
|
}
|
|
|
|
void ect_init_map_io(void)
|
|
{
|
|
int page_size, i;
|
|
struct page *page;
|
|
struct page **pages;
|
|
int ret;
|
|
|
|
page_size = ect_early_vm.size / PAGE_SIZE;
|
|
if (ect_early_vm.size % PAGE_SIZE)
|
|
page_size++;
|
|
pages = kzalloc((sizeof(struct page *) * page_size), GFP_KERNEL);
|
|
page = phys_to_page(ect_early_vm.phys_addr);
|
|
|
|
for (i = 0; i < page_size; ++i)
|
|
pages[i] = page++;
|
|
|
|
ret = map_vm_area(&ect_early_vm, PAGE_KERNEL, pages);
|
|
if (ret) {
|
|
pr_err("[ECT] : failed to mapping va and pa(%d)\n", ret);
|
|
}
|
|
kfree(pages);
|
|
}
|