151 lines
4.3 KiB
C
Executable file
151 lines
4.3 KiB
C
Executable file
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
|
/* include/soc/samsung/asv_g_spec.h
|
|
*
|
|
* Copyright (c) 2021 Samsung Electronics Co., Ltd.
|
|
* http://www.samsung.com
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License version 2 as
|
|
* published by the Free Software Foundation.
|
|
*/
|
|
#ifndef __ASV_G_SPEC_H__
|
|
#define __ASV_G_SPEC_H__
|
|
|
|
#include <soc/samsung/ect_parser.h>
|
|
#include <soc/samsung/cal-if.h>
|
|
#include <linux/io.h>
|
|
|
|
#include "../../../drivers/soc/samsung/cal-if/cmucal.h"
|
|
#include "../../../drivers/soc/samsung/cal-if/asv.h"
|
|
//#include "vclk.h"
|
|
|
|
extern struct vclk acpm_vclk_list[];
|
|
extern unsigned int acpm_vclk_size;
|
|
#define get_domain_name(type) (acpm_vclk_list[type].name)
|
|
#define SPEC_STR_SIZE (30)
|
|
|
|
#define asv_g_spec(domain, id, fused_addr, bit_num) \
|
|
static ssize_t show_asv_g_spec_##domain##_fused_volt \
|
|
(struct kobject *kobj, struct kobj_attribute *attr, char *buf) \
|
|
{ \
|
|
return show_asv_g_spec(id, ASV_G_FUSED, buf, fused_addr, bit_num); \
|
|
} \
|
|
static struct kobj_attribute asv_g_spec_##domain##_fused_volt = \
|
|
__ATTR(domain##_fused_volt, 0400, show_asv_g_spec_##domain##_fused_volt, NULL); \
|
|
static ssize_t show_asv_g_spec_##domain##_grp_volt \
|
|
(struct kobject *kobj, struct kobj_attribute *attr, char *buf) \
|
|
{ \
|
|
return show_asv_g_spec(id, ASV_G_GRP, buf, fused_addr, bit_num); \
|
|
} \
|
|
static struct kobj_attribute asv_g_spec_##domain##_grp_volt = \
|
|
__ATTR(domain##_grp_volt, 0400, show_asv_g_spec_##domain##_grp_volt, NULL)
|
|
|
|
#define asv_g_spec_attr(domain) \
|
|
&asv_g_spec_##domain##_fused_volt.attr, \
|
|
&asv_g_spec_##domain##_grp_volt.attr
|
|
|
|
enum spec_volt_type {
|
|
ASV_G_FUSED = 0,
|
|
ASV_G_GRP
|
|
};
|
|
|
|
static ssize_t show_asv_g_spec(int id, enum spec_volt_type type,
|
|
char *buf, unsigned int fused_addr, unsigned int bit_num)
|
|
{
|
|
void *gen_block;
|
|
struct ect_gen_param_table *spec;
|
|
int asv_tbl_ver, asv_grp, tbl_size, j, vtyp_freq, num_lv;
|
|
unsigned int fused_volt = 0, grp_volt = 0, volt;
|
|
struct dvfs_rate_volt rate_volt[48];
|
|
unsigned int *spec_table = NULL;
|
|
ssize_t size = 0, len = 0;
|
|
char spec_str[SPEC_STR_SIZE] = {0, };
|
|
unsigned long fused_val;
|
|
void __iomem *fused_addr_va;
|
|
|
|
if (id >= acpm_vclk_size) {
|
|
pr_err("%s: cannot found dvfs domain: %d\n", __func__, id);
|
|
goto out;
|
|
}
|
|
|
|
gen_block = ect_get_block("GEN");
|
|
if (gen_block == NULL) {
|
|
pr_err("%s: Failed to get gen block from ECT\n", __func__);
|
|
goto out;
|
|
}
|
|
|
|
asv_grp = asv_get_grp(id | ACPM_VCLK_TYPE);
|
|
if (!asv_grp) {
|
|
pr_err("%s: There has no ASV-G information for %s group 0\n",
|
|
__func__, get_domain_name(id));
|
|
goto out;
|
|
}
|
|
|
|
len = snprintf(spec_str, SPEC_STR_SIZE, "SPEC_%s", get_domain_name(id));
|
|
if (len < 0)
|
|
goto out;
|
|
|
|
spec = ect_gen_param_get_table(gen_block, spec_str);
|
|
if (spec == NULL) {
|
|
pr_err("%s: Failed to get spec table from ECT\n", __func__);
|
|
goto out;
|
|
}
|
|
|
|
asv_tbl_ver = asv_get_table_ver();
|
|
for (j = 0; j < spec->num_of_row; j++) {
|
|
spec_table = &spec->parameter[spec->num_of_col * j];
|
|
if (spec_table[0] == asv_tbl_ver) {
|
|
grp_volt = spec_table[asv_grp + 2];
|
|
vtyp_freq = spec_table[1];
|
|
break;
|
|
}
|
|
}
|
|
if (j == spec->num_of_row) {
|
|
pr_err("%s: Do not support ASV-G, asv table version:%d\n", __func__, asv_tbl_ver);
|
|
goto out;
|
|
}
|
|
|
|
if (!grp_volt) {
|
|
pr_err("%s: Failed to get grp volt\n", __func__);
|
|
goto out;
|
|
}
|
|
|
|
num_lv = cal_dfs_get_lv_num(id | ACPM_VCLK_TYPE);
|
|
tbl_size = cal_dfs_get_rate_asv_table(id | ACPM_VCLK_TYPE, rate_volt);
|
|
if (!tbl_size) {
|
|
pr_err("%s: Failed to get asv table\n", __func__);
|
|
goto out;
|
|
}
|
|
|
|
if (fused_addr) {
|
|
if ((fused_addr & 0x9000) == 0x9000) {
|
|
exynos_smc_readsfr((unsigned long)fused_addr, &fused_val);
|
|
} else {
|
|
fused_addr_va = ioremap(fused_addr, 4);
|
|
fused_val = __raw_readl(fused_addr_va);
|
|
iounmap(fused_addr_va);
|
|
}
|
|
|
|
fused_volt = (((unsigned int)fused_val & (0xff << bit_num)) >> bit_num) * 6250;
|
|
} else {
|
|
for (j = 0; j < num_lv; j++) {
|
|
if (rate_volt[j].rate == vtyp_freq) {
|
|
fused_volt = rate_volt[j].volt;
|
|
break;
|
|
}
|
|
}
|
|
if (j == num_lv) {
|
|
pr_err("%s: There has no frequency %d on %d domain\n", __func__,
|
|
vtyp_freq, get_domain_name(id));
|
|
goto out;
|
|
}
|
|
}
|
|
|
|
volt = (type == ASV_G_FUSED) ? fused_volt : grp_volt;
|
|
|
|
size += snprintf(buf + size, PAGE_SIZE, "%d\n", volt);
|
|
out:
|
|
|
|
return size;
|
|
}
|
|
#endif
|