From: Yadwinder Singh Brar <yadi.brar@xxxxxxxxxxx> This patch adds basic support (only for ARM ASV) for exynos5250 chips which have fused ASV group. Signed-off-by: Yadwinder Singh Brar <yadi.brar@xxxxxxxxxxx> Signed-off-by: Sachin Kamat <sachin.kamat@xxxxxxxxxx> --- drivers/power/asv/Makefile | 2 +- drivers/power/asv/exynos-asv.c | 8 +++ drivers/power/asv/exynos-asv.h | 1 + drivers/power/asv/exynos5250-asv.c | 139 ++++++++++++++++++++++++++++++++++++ 4 files changed, 149 insertions(+), 1 deletion(-) create mode 100644 drivers/power/asv/exynos5250-asv.c diff --git a/drivers/power/asv/Makefile b/drivers/power/asv/Makefile index 9d0e0cc32cb5..a73544445c9a 100644 --- a/drivers/power/asv/Makefile +++ b/drivers/power/asv/Makefile @@ -1,2 +1,2 @@ obj-$(CONFIG_POWER_ASV) += asv.o -obj-$(CONFIG_POWER_EXYNOS_ASV) += exynos-asv.o +obj-$(CONFIG_POWER_EXYNOS_ASV) += exynos-asv.o exynos5250-asv.o diff --git a/drivers/power/asv/exynos-asv.c b/drivers/power/asv/exynos-asv.c index 50efb0b6af85..f2cd04d1ce95 100644 --- a/drivers/power/asv/exynos-asv.c +++ b/drivers/power/asv/exynos-asv.c @@ -46,9 +46,17 @@ static int exynos_asv_probe(struct platform_device *pdev) exynos_asv_info->base = base; /* call SoC specific intialisation routine */ + if (of_machine_is_compatible("samsung,exynos5250")) { + ret = exynos5250_asv_init(exynos_asv_info); + if (ret) { + pr_err("exynos5250_asv_init failed : %d\n", ret); + goto err; + } + } register_asv_member(exynos_asv_info->asv_list, exynos_asv_info->nr_mem); +err: iounmap(base); err_map: of_node_put(chip_id); diff --git a/drivers/power/asv/exynos-asv.h b/drivers/power/asv/exynos-asv.h index 89a1ae8b5e19..a31becb7478f 100644 --- a/drivers/power/asv/exynos-asv.h +++ b/drivers/power/asv/exynos-asv.h @@ -18,4 +18,5 @@ struct exynos_asv_common { void __iomem *base; }; +extern int exynos5250_asv_init(struct exynos_asv_common *exynos_info); #endif /* __EXYNOS_ASV_D_H */ diff --git a/drivers/power/asv/exynos5250-asv.c b/drivers/power/asv/exynos5250-asv.c new file mode 100644 index 000000000000..7746c7d2d987 --- /dev/null +++ b/drivers/power/asv/exynos5250-asv.c @@ -0,0 +1,139 @@ +/* exynos5250 - ASV(Adaptive Supply Voltage) + * + * Copyright (c) 2013 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. +*/ + +#include <linux/err.h> +#include <linux/io.h> +#include <linux/slab.h> +#include <linux/power/asv-driver.h> +#include "exynos-asv.h" + +#define FUSED_SG_OFFSET 3 +#define ORIG_SG_OFFSET 17 +#define ORIG_SG_MASK 0xF +#define MOD_SG_OFFSET 21 +#define MOD_SG_MASK 0x7 + +#define ARM_LEVEL_NR 16 +#define ARM_GRP_NR 12 + +#define CHIP_ID_OFFSET 0x4 + +struct exynos5250_asv_info { + unsigned int package_id; + /* we may need more info as global data */ +}; + +static struct exynos5250_asv_info asv_group __initdata; + +static unsigned int asv_voltage[ARM_LEVEL_NR][ARM_GRP_NR + 1] __initdata = { + { 1700000, 1300000, 1275000, 1275000, 1262500, 1250000, 1225000, + 1212500, 1200000, 1187500, 1175000, 1150000, 1125000 }, /* L0 */ + { 1600000, 1250000, 1225000, 1225000, 1212500, 1200000, 1187500, + 1175000, 1162500, 1150000, 1137500, 1112500, 1100000 }, /* L1 */ + { 1500000, 1225000, 1187500, 1175000, 1162500, 1150000, 1137500, + 1125000, 1112500, 1100000, 1087500, 1075000, 1062500 }, /* L2 */ + { 1400000, 1200000, 1125000, 1125000, 1125000, 1112500, 1100000, + 1087500, 1075000, 1062500, 1050000, 1037500, 1025000 }, /* L3 */ + { 1300000, 1150000, 1100000, 1100000, 1100000, 1087500, 1075000, + 1062500, 1050000, 1037500, 1025000, 1012500, 1000000 }, /* L4 */ + { 1200000, 1125000, 1075000, 1075000, 1062500, 1050000, 1037500, + 1025000, 1012500, 1000000, 987500, 975000, 975000 }, /* L5 */ + { 1100000, 1100000, 1050000, 1050000, 1037500, 1025000, 1012500, + 1000000, 987500, 975000, 962500, 950000, 925000 }, /* L6 */ + { 1000000, 1075000, 1037500, 1037500, 1012500, 1000000, 987500, + 975000, 962500, 950000, 937500, 925000, 912500 }, /* L7 */ + { 900000, 1050000, 1025000, 1012500, 987500, 975000, 962500, + 950000, 937500, 925000, 912500, 912500, 900000 }, /* L8 */ + { 800000, 1025000, 1000000, 987500, 975000, 962500, 950000, + 937500, 925000, 912500, 900000, 900000, 900000 }, /* L9 */ + { 700000, 1012500, 975000, 962500, 950000, 937500, 925000, + 912500, 900000, 900000, 900000, 900000, 900000 }, /* L10 */ + { 600000, 1000000, 962500, 950000, 937500, 925000, 912500, + 900000, 900000, 900000, 900000, 900000, 900000 }, /* L11 */ + { 500000, 975000, 950000, 937500, 925000, 912500, 900000, + 900000, 900000, 900000, 900000, 900000, 887500 }, /* L12 */ + { 400000, 950000, 937500, 925000, 912500, 900000, 900000, + 900000, 900000, 900000, 900000, 887500, 887500 }, /* L13 */ + { 300000, 937500, 925000, 912500, 900000, 900000, 900000, + 900000, 900000, 900000, 887500, 887500, 875000 }, /* L14 */ + { 200000, 925000, 912500, 900000, 900000, 900000, 900000, + 900000, 900000, 887500, 887500, 875000, 875000 }, /* L15 */ +}; + +static int __init exynos5250_get_asv_group(struct asv_info *asv_info) +{ + int exynos_asv_grp; + u32 exynos_orig_sp; + u32 exynos_mod_sp; + u32 package_id = asv_group.package_id; + + /* If ASV group is fused then retrieve it */ + if ((package_id >> FUSED_SG_OFFSET) & 0x1) { + exynos_orig_sp = (package_id >> ORIG_SG_OFFSET) & ORIG_SG_MASK; + exynos_mod_sp = (package_id >> MOD_SG_OFFSET) & MOD_SG_MASK; + + exynos_asv_grp = exynos_orig_sp - exynos_mod_sp; + if (exynos_asv_grp < 0) { + pr_warn("%s: Invalid ASV group: %d\n", __func__, + exynos_asv_grp); + exynos_asv_grp = 0; /* go for default */ + } + } else { + pr_warn("%s: ASV group not fused for : %s\n", __func__, + asv_info->name); + exynos_asv_grp = 0; /* go for default */ + } + + asv_info->asv_grp = exynos_asv_grp; + return 0; +} + +static int __init exynos5250_init_arm_asv_table(struct asv_info *asv_info) +{ + struct asv_freq_table *dvfs_table; + int i, asv_grp = asv_info->asv_grp; + + dvfs_table = kzalloc(sizeof(*dvfs_table) * ARM_LEVEL_NR, GFP_KERNEL); + if (!dvfs_table) + return -ENOMEM; + + for (i = 0; i < ARM_LEVEL_NR; i++) { + dvfs_table[i].freq = asv_voltage[i][0]; + dvfs_table[i].volt = asv_voltage[i][asv_grp + 1]; + } + + asv_info->dvfs_table = dvfs_table; + return 0; +} + +/* TODO: Implement .init_asv callback to set ABB value */ + +static struct asv_ops exynos5250_arm_asv_ops __initdata = { + .get_asv_group = exynos5250_get_asv_group, + .init_asv_table = exynos5250_init_arm_asv_table, +}; + +static struct asv_info exynos5250_asv_member[] __initdata = { + { + .type = ASV_ARM, + .name = "VDD_ARM", + .ops = &exynos5250_arm_asv_ops, + .nr_dvfs_level = ARM_LEVEL_NR, + }, +}; + +int __init exynos5250_asv_init(struct exynos_asv_common *exynos_info) +{ + asv_group.package_id = readl(exynos_info->base + CHIP_ID_OFFSET); + exynos_info->asv_list = exynos5250_asv_member; + exynos_info->nr_mem = ARRAY_SIZE(exynos5250_asv_member); + + return 0; +} -- 1.7.9.5 -- To unsubscribe from this list: send the line "unsubscribe linux-samsung-soc" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html