/* 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 #include #include #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