--- /dev/null
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com/
+ *
+ * Samsung Exynos SoC Adaptive Supply Voltage support
+ */
+
+#include <linux/bitrev.h>
+#include <linux/cpu.h>
+#include <linux/device.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/irqchip.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_fdt.h>
+#include <linux/platform_device.h>
+#include <linux/pm_opp.h>
+
+#include "exynos-chipid.h"
+
+#define EXYNOS5422_ASV_NR 14
+
+#define ARM_DVFS_NR 20
+#define ARM_BIN2_DVFS_NR 17
+
+#define KFC_DVFS_NR 14
+#define KFC_BIN2_DVFS_NR 12
+
+ /* HPM, IDS values to select target group */
+struct asv_limit_entry {
+ unsigned int hpm;
+ unsigned int ids;
+};
+
+struct asv_cluster {
+ unsigned int base_volt;
+ unsigned int dvfs_nr;
+ unsigned int offset_volt_h;
+ unsigned int offset_volt_l;
+ const unsigned int (*asv_table)[EXYNOS5422_ASV_NR + 1];
+};
+
+enum {
+ CLUSTER_ID_ARM,
+ CLUSTER_ID_KFC,
+ CLUSTER_ID_MAX
+};
+
+struct exynos_asv {
+ struct asv_cluster cluster[CLUSTER_ID_MAX];
+ unsigned int bin2;
+ unsigned int special_lot;
+ unsigned int group;
+ unsigned int table;
+};
+
+static struct exynos_asv *exynos_asv = NULL;
+
+static const unsigned int arm_info_table01[ARM_DVFS_NR][EXYNOS5422_ASV_NR + 1] = {
+ { 2100000, 1362500, 1362500, 1350000, 1337500, 1325000, 1312500, 1300000, 1275000, 1262500, 1250000, 1237500, 1225000, 1212500, 1200000 },
+ { 2000000, 1312500, 1312500, 1300000, 1287500, 1275000, 1262500, 1250000, 1237500, 1225000, 1237500, 1225000, 1212500, 1200000, 1187500 },
+ { 1900000, 1250000, 1237500, 1225000, 1212500, 1200000, 1187500, 1175000, 1162500, 1150000, 1162500, 1150000, 1137500, 1125000, 1112500 },
+ { 1800000, 1200000, 1187500, 1175000, 1162500, 1150000, 1137500, 1125000, 1112500, 1100000, 1112500, 1100000, 1087500, 1075000, 1062500 },
+ { 1700000, 1162500, 1150000, 1137500, 1125000, 1112500, 1100000, 1087500, 1075000, 1062500, 1075000, 1062500, 1050000, 1037500, 1025000 },
+ { 1600000, 1125000, 1112500, 1100000, 1087500, 1075000, 1062500, 1050000, 1037500, 1025000, 1037500, 1025000, 1012500, 1000000, 987500 },
+ { 1500000, 1087500, 1075000, 1062500, 1050000, 1037500, 1025000, 1012500, 1000000, 987500, 1000000, 987500, 975000, 962500, 950000 },
+ { 1400000, 1062500, 1050000, 1037500, 1025000, 1012500, 1000000, 987500, 975000, 962500, 975000, 962500, 950000, 937500, 925000 },
+ { 1300000, 1050000, 1037500, 1025000, 1012500, 1000000, 987500, 975000, 962500, 950000, 962500, 950000, 937500, 925000, 912500 },
+ { 1200000, 1025000, 1012500, 1000000, 987500, 975000, 962500, 950000, 937500, 925000, 937500, 925000, 912500, 900000, 900000 },
+ { 1100000, 1000000, 987500, 975000, 962500, 950000, 937500, 925000, 912500, 900000, 900000, 900000, 900000, 900000, 900000 },
+ { 1000000, 975000, 962500, 950000, 937500, 925000, 912500, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000 },
+ { 900000, 950000, 937500, 925000, 912500, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000 },
+ { 800000, 925000, 912500, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000 },
+ { 700000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000 },
+ { 600000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000 },
+ { 500000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000 },
+ { 400000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000 },
+ { 300000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000 },
+ { 200000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000 },
+};
+
+static const unsigned int arm_info_table2[ARM_DVFS_NR][EXYNOS5422_ASV_NR + 1] = {
+ { 2100000, 1362500, 1362500, 1350000, 1337500, 1325000, 1312500, 1300000, 1275000, 1262500, 1250000, 1237500, 1225000, 1212500, 1200000 },
+ { 2000000, 1312500, 1312500, 1312500, 1300000, 1275000, 1262500, 1250000, 1237500, 1225000, 1237500, 1225000, 1212500, 1200000, 1187500 },
+ { 1900000, 1262500, 1250000, 1250000, 1237500, 1212500, 1200000, 1187500, 1175000, 1162500, 1175000, 1162500, 1150000, 1137500, 1125000 },
+ { 1800000, 1212500, 1200000, 1187500, 1175000, 1162500, 1150000, 1137500, 1125000, 1112500, 1125000, 1112500, 1100000, 1087500, 1075000 },
+ { 1700000, 1175000, 1162500, 1150000, 1137500, 1125000, 1112500, 1100000, 1087500, 1075000, 1087500, 1075000, 1062500, 1050000, 1037500 },
+ { 1600000, 1137500, 1125000, 1112500, 1100000, 1087500, 1075000, 1062500, 1050000, 1037500, 1050000, 1037500, 1025000, 1012500, 1000000 },
+ { 1500000, 1100000, 1087500, 1075000, 1062500, 1050000, 1037500, 1025000, 1012500, 1000000, 1012500, 1000000, 987500, 975000, 962500 },
+ { 1400000, 1075000, 1062500, 1050000, 1037500, 1025000, 1012500, 1000000, 987500, 975000, 987500, 975000, 962500, 950000, 937500 },
+ { 1300000, 1050000, 1037500, 1025000, 1012500, 1000000, 987500, 975000, 962500, 950000, 962500, 950000, 937500, 925000, 912500 },
+ { 1200000, 1025000, 1012500, 1000000, 987500, 975000, 962500, 950000, 937500, 925000, 937500, 925000, 912500, 900000, 900000 },
+ { 1100000, 1000000, 987500, 975000, 962500, 950000, 937500, 925000, 912500, 900000, 900000, 900000, 900000, 900000, 900000 },
+ { 1000000, 975000, 962500, 950000, 937500, 925000, 912500, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000 },
+ { 900000, 950000, 937500, 925000, 912500, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000 },
+ { 800000, 925000, 912500, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000 },
+ { 700000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000 },
+ { 600000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000 },
+ { 500000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000 },
+ { 400000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000 },
+ { 300000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000 },
+ { 200000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000 },
+};
+
+static const unsigned int arm_info_table3[ARM_DVFS_NR][EXYNOS5422_ASV_NR + 1] = {
+ { 2100000, 1362500, 1362500, 1350000, 1337500, 1325000, 1312500, 1300000, 1275000, 1262500, 1250000, 1237500, 1225000, 1212500, 1200000 },
+ { 2000000, 1312500, 1312500, 1300000, 1287500, 1275000, 1262500, 1250000, 1237500, 1225000, 1237500, 1225000, 1212500, 1200000, 1187500 },
+ { 1900000, 1262500, 1250000, 1237500, 1225000, 1212500, 1200000, 1187500, 1175000, 1162500, 1175000, 1162500, 1150000, 1137500, 1125000 },
+ { 1800000, 1212500, 1200000, 1187500, 1175000, 1162500, 1150000, 1137500, 1125000, 1112500, 1125000, 1112500, 1100000, 1087500, 1075000 },
+ { 1700000, 1175000, 1162500, 1150000, 1137500, 1125000, 1112500, 1100000, 1087500, 1075000, 1087500, 1075000, 1062500, 1050000, 1037500 },
+ { 1600000, 1137500, 1125000, 1112500, 1100000, 1087500, 1075000, 1062500, 1050000, 1037500, 1050000, 1037500, 1025000, 1012500, 1000000 },
+ { 1500000, 1100000, 1087500, 1075000, 1062500, 1050000, 1037500, 1025000, 1012500, 1000000, 1012500, 1000000, 987500, 975000, 962500 },
+ { 1400000, 1075000, 1062500, 1050000, 1037500, 1025000, 1012500, 1000000, 987500, 975000, 987500, 975000, 962500, 950000, 937500 },
+ { 1300000, 1050000, 1037500, 1025000, 1012500, 1000000, 987500, 975000, 962500, 950000, 962500, 950000, 937500, 925000, 912500 },
+ { 1200000, 1025000, 1012500, 1000000, 987500, 975000, 962500, 950000, 937500, 925000, 937500, 925000, 912500, 900000, 900000 },
+ { 1100000, 1000000, 987500, 975000, 962500, 950000, 937500, 925000, 912500, 900000, 900000, 900000, 900000, 900000, 900000 },
+ { 1000000, 975000, 962500, 950000, 937500, 925000, 912500, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000 },
+ { 900000, 950000, 937500, 925000, 912500, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000 },
+ { 800000, 925000, 912500, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000 },
+ { 700000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000 },
+ { 600000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000 },
+ { 500000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000 },
+ { 400000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000 },
+ { 300000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000 },
+ { 200000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000 },
+};
+
+static const unsigned int arm_info_bin2[ARM_BIN2_DVFS_NR][EXYNOS5422_ASV_NR + 1] = {
+ { 1800000, 1237500, 1225000, 1212500, 1200000, 1187500, 1175000, 1162500, 1150000, 1137500, 1150000, 1137500, 1125000, 1112500, 1100000 },
+ { 1700000, 1200000, 1187500, 1175000, 1162500, 1150000, 1137500, 1125000, 1112500, 1100000, 1112500, 1100000, 1087500, 1075000, 1062500 },
+ { 1600000, 1162500, 1150000, 1137500, 1125000, 1112500, 1100000, 1087500, 1075000, 1062500, 1075000, 1062500, 1050000, 1037500, 1025000 },
+ { 1500000, 1125000, 1112500, 1100000, 1087500, 1075000, 1062500, 1050000, 1037500, 1025000, 1037500, 1025000, 1012500, 1000000, 987500 },
+ { 1400000, 1100000, 1087500, 1075000, 1062500, 1050000, 1037500, 1025000, 1012500, 1000000, 1012500, 1000000, 987500, 975000, 962500 },
+ { 1300000, 1087500, 1075000, 1062500, 1050000, 1037500, 1025000, 1012500, 1000000, 987500, 1000000, 987500, 975000, 962500, 950000 },
+ { 1200000, 1062500, 1050000, 1037500, 1025000, 1012500, 1000000, 987500, 975000, 962500, 975000, 962500, 950000, 937500, 925000 },
+ { 1100000, 1037500, 1025000, 1012500, 1000000, 987500, 975000, 962500, 950000, 937500, 950000, 937500, 925000, 912500, 900000 },
+ { 1000000, 1012500, 1000000, 987500, 975000, 962500, 950000, 937500, 925000, 912500, 925000, 912500, 900000, 900000, 900000 },
+ { 900000, 987500, 975000, 962500, 950000, 937500, 925000, 912500, 900000, 900000, 900000, 900000, 900000, 900000, 900000 },
+ { 800000, 962500, 950000, 937500, 925000, 912500, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000 },
+ { 700000, 937500, 925000, 912500, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000 },
+ { 600000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000 },
+ { 500000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000 },
+ { 400000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000 },
+ { 300000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000 },
+ { 200000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000 },
+};
+
+static const unsigned int kfc_info_table01[KFC_DVFS_NR][EXYNOS5422_ASV_NR + 1] = {
+ { 1500000, 1300000, 1300000, 1300000, 1287500, 1287500, 1287500, 1275000, 1262500, 1250000, 1237500, 1225000, 1212500, 1200000, 1187500 },
+ { 1400000, 1275000, 1262500, 1250000, 1237500, 1225000, 1212500, 1200000, 1187500, 1175000, 1162500, 1150000, 1137500, 1125000, 1112500 },
+ { 1300000, 1225000, 1212500, 1200000, 1187500, 1175000, 1162500, 1150000, 1137500, 1125000, 1112500, 1100000, 1087500, 1075000, 1062500 },
+ { 1200000, 1175000, 1162500, 1150000, 1137500, 1125000, 1112500, 1100000, 1087500, 1075000, 1062500, 1050000, 1037500, 1025000, 1012500 },
+ { 1100000, 1137500, 1125000, 1112500, 1100000, 1087500, 1075000, 1062500, 1050000, 1037500, 1025000, 1012500, 1000000, 987500, 975000 },
+ { 1000000, 1100000, 1087500, 1075000, 1062500, 1050000, 1037500, 1025000, 1012500, 1000000, 987500, 975000, 962500, 950000, 937500 },
+ { 900000, 1062500, 1050000, 1037500, 1025000, 1012500, 1000000, 987500, 975000, 962500, 950000, 937500, 925000, 912500, 900000 },
+ { 800000, 1025000, 1012500, 1000000, 987500, 975000, 962500, 950000, 937500, 925000, 912500, 900000, 900000, 900000, 900000 },
+ { 700000, 987500, 975000, 962500, 950000, 937500, 925000, 912500, 900000, 900000, 900000, 900000, 900000, 900000, 900000 },
+ { 600000, 950000, 937500, 925000, 912500, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000 },
+ { 500000, 912500, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000 },
+ { 400000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000 },
+ { 300000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000 },
+ { 200000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000 },
+};
+
+static const unsigned int kfc_info_table2[KFC_DVFS_NR][EXYNOS5422_ASV_NR + 1] = {
+ { 1500000, 1300000, 1300000, 1300000, 1287500, 1287500, 1287500, 1275000, 1262500, 1250000, 1237500, 1225000, 1212500, 1200000, 1187500 },
+ { 1400000, 1275000, 1262500, 1250000, 1237500, 1225000, 1212500, 1200000, 1187500, 1175000, 1162500, 1150000, 1137500, 1125000, 1112500 },
+ { 1300000, 1225000, 1212500, 1200000, 1187500, 1175000, 1162500, 1150000, 1137500, 1125000, 1112500, 1100000, 1087500, 1075000, 1062500 },
+ { 1200000, 1175000, 1162500, 1150000, 1137500, 1125000, 1112500, 1100000, 1087500, 1075000, 1062500, 1050000, 1037500, 1025000, 1012500 },
+ { 1100000, 1137500, 1125000, 1112500, 1100000, 1087500, 1075000, 1062500, 1050000, 1037500, 1025000, 1012500, 1000000, 987500, 975000 },
+ { 1000000, 1100000, 1087500, 1075000, 1062500, 1050000, 1037500, 1025000, 1012500, 1000000, 987500, 975000, 962500, 950000, 937500 },
+ { 900000, 1062500, 1050000, 1037500, 1025000, 1012500, 1000000, 987500, 975000, 962500, 950000, 937500, 925000, 912500, 900000 },
+ { 800000, 1025000, 1012500, 1000000, 987500, 975000, 962500, 950000, 937500, 925000, 912500, 900000, 900000, 900000, 900000 },
+ { 700000, 987500, 975000, 962500, 950000, 937500, 925000, 912500, 900000, 900000, 900000, 900000, 900000, 900000, 900000 },
+ { 600000, 950000, 937500, 925000, 912500, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000 },
+ { 500000, 912500, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000 },
+ { 400000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000 },
+ { 300000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000 },
+ { 200000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000 },
+};
+
+static const unsigned int kfc_info_table3[KFC_DVFS_NR][EXYNOS5422_ASV_NR + 1] = {
+ { 1500000, 1300000, 1300000, 1300000, 1287500, 1287500, 1287500, 1275000, 1262500, 1250000, 1237500, 1225000, 1212500, 1200000, 1187500 },
+ { 1400000, 1275000, 1262500, 1250000, 1237500, 1225000, 1212500, 1200000, 1187500, 1175000, 1162500, 1150000, 1137500, 1125000, 1112500 },
+ { 1300000, 1225000, 1212500, 1200000, 1187500, 1175000, 1162500, 1150000, 1137500, 1125000, 1112500, 1100000, 1087500, 1075000, 1062500 },
+ { 1200000, 1175000, 1162500, 1150000, 1137500, 1125000, 1112500, 1100000, 1087500, 1075000, 1062500, 1050000, 1037500, 1025000, 1012500 },
+ { 1100000, 1137500, 1125000, 1112500, 1100000, 1087500, 1075000, 1062500, 1050000, 1037500, 1025000, 1012500, 1000000, 987500, 975000 },
+ { 1000000, 1100000, 1087500, 1075000, 1062500, 1050000, 1037500, 1025000, 1012500, 1000000, 987500, 975000, 962500, 950000, 937500 },
+ { 900000, 1062500, 1050000, 1037500, 1025000, 1012500, 1000000, 987500, 975000, 962500, 950000, 937500, 925000, 912500, 900000 },
+ { 800000, 1025000, 1012500, 1000000, 987500, 975000, 962500, 950000, 937500, 925000, 912500, 900000, 900000, 900000, 900000 },
+ { 700000, 987500, 975000, 962500, 950000, 937500, 925000, 912500, 900000, 900000, 900000, 900000, 900000, 900000, 900000 },
+ { 600000, 950000, 937500, 925000, 912500, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000 },
+ { 500000, 912500, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000 },
+ { 400000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000 },
+ { 300000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000 },
+ { 200000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000 },
+};
+
+static const unsigned int kfc_info_bin2[KFC_BIN2_DVFS_NR][EXYNOS5422_ASV_NR + 1] = {
+ { 1300000, 1250000, 1237500, 1225000, 1212500, 1200000, 1187500, 1175000, 1162500, 1150000, 1137500, 1125000, 1112500, 1100000, 1087500 },
+ { 1200000, 1200000, 1187500, 1175000, 1162500, 1150000, 1137500, 1125000, 1112500, 1100000, 1087500, 1075000, 1062500, 1050000, 1037500 },
+ { 1100000, 1162500, 1150000, 1137500, 1125000, 1112500, 1100000, 1087500, 1075000, 1062500, 1050000, 1037500, 1025000, 1012500, 1000000 },
+ { 1000000, 1125000, 1112500, 1100000, 1087500, 1075000, 1062500, 1050000, 1037500, 1025000, 1012500, 1000000, 987500, 975000, 962500 },
+ { 900000, 1087500, 1075000, 1062500, 1050000, 1037500, 1025000, 1012500, 1000000, 987500, 975000, 962500, 950000, 937500, 925000 },
+ { 800000, 1050000, 1037500, 1025000, 1012500, 1000000, 987500, 975000, 962500, 950000, 937500, 925000, 912500, 900000, 900000 },
+ { 700000, 1012500, 1000000, 987500, 975000, 962500, 950000, 937500, 925000, 912500, 900000, 900000, 900000, 900000, 900000 },
+ { 600000, 975000, 962500, 950000, 937500, 925000, 912500, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000 },
+ { 500000, 937500, 925000, 912500, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000 },
+ { 400000, 925000, 912500, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000 },
+ { 300000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000 },
+ { 200000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000 },
+
+};
+
+
+static unsigned int exynos_asv_opp_get_voltage(struct asv_cluster *cluster,
+ unsigned int freq, unsigned int volt)
+{
+ unsigned int i, asv_volt;
+
+ for (i = 0; i < cluster->dvfs_nr; i++) {
+ if (freq == cluster->asv_table[i][0])
+ break;
+ }
+
+ if (i == cluster->dvfs_nr)
+ return 0;
+
+ asv_volt = cluster->asv_table[i][exynos_asv->group + 1];
+
+ if (volt > cluster->base_volt)
+ asv_volt += cluster->offset_volt_h;
+ else
+ asv_volt += cluster->offset_volt_l;
+
+ return asv_volt;
+}
+
+static int exynos_asv_get_bin2(void)
+{
+ unsigned int reg = exynos_chipid_read(EXYNOS_CHIPID_REG_PKG_ID);
+
+ return (reg >> EXYNOS5422_BIN2_OFFSET) & EXYNOS5422_BIN2_MASK;
+}
+
+static bool asv_special_group_check(void)
+{
+ unsigned int reg = exynos_chipid_read(EXYNOS_CHIPID_REG_PKG_ID);
+
+ return (((reg >> EXYNOS5422_USESG_OFFSET) & EXYNOS5422_USESG_MASK)
+ && exynos_asv->bin2 == 0);
+}
+
+static const struct asv_limit_entry exynos5422_asv_limits[EXYNOS5422_ASV_NR] = {
+ { 13, 55 },
+ { 21, 65 },
+ { 25, 69 },
+ { 30, 72 },
+ { 36, 74 },
+ { 43, 76 },
+ { 51, 78 },
+ { 65, 80 },
+ { 81, 82 },
+ { 98, 84 },
+ { 119, 87 },
+ { 135, 89 },
+ { 150, 92 },
+ { 999, 999 },
+};
+
+static int exynos_asv_get_group(struct exynos_asv *exynos_asv)
+{
+ unsigned int pkgid_reg = exynos_chipid_read(EXYNOS_CHIPID_REG_PKG_ID);
+ unsigned int auxi_reg = exynos_chipid_read(EXYNOS_CHIPID_AUX_INFO);
+ int hpm, ids, i;
+
+ if (exynos_asv->special_lot) {
+ u32 sga = (pkgid_reg >> EXYNOS5422_SG_A_OFFSET) &
+ EXYNOS5422_SG_A_MASK;
+
+ u32 sgb = (pkgid_reg >> EXYNOS5422_SG_B_OFFSET) &
+ EXYNOS5422_SG_B_MASK;
+
+ if ((pkgid_reg >> EXYNOS5422_SG_BSIGN_OFFSET) &
+ EXYNOS5422_SG_BSIGN_MASK)
+ return sga + sgb;
+ else
+ return sga - sgb;
+ }
+
+ hpm = (auxi_reg >> EXYNOS5422_TMCB_OFFSET) & EXYNOS5422_TMCB_MASK;
+ ids = (pkgid_reg >> EXYNOS5422_IDS_OFFSET) & EXYNOS5422_IDS_MASK;
+
+ for (i = 0; i < EXYNOS5422_ASV_NR; i++) {
+ if (ids <= exynos5422_asv_limits[i].ids)
+ break;
+ if (hpm <= exynos5422_asv_limits[i].hpm)
+ break;
+ }
+
+ if (i < EXYNOS5422_ASV_NR)
+ return i;
+ else
+ return 0;
+}
+
+static int asv_table_check(void)
+{
+ unsigned int pkg_id_reg = exynos_chipid_read(EXYNOS_CHIPID_REG_PKG_ID);
+
+ return (pkg_id_reg >> EXYNOS5422_TABLE_OFFSET) & EXYNOS5422_TABLE_MASK;
+}
+
+static int exynos5422_offset_voltage(unsigned int index)
+{
+ static const unsigned int offset_table[] = { 12500, 50000, 25000 };
+
+ if (index == 0 || index > 3)
+ return 0;
+
+ return offset_table[index - 1];
+}
+
+static void asv_offset_voltage_setup(void)
+{
+ struct asv_cluster *cluster;
+ unsigned int reg, value;
+
+ if (exynos_asv->bin2) {
+ exynos_asv->cluster[CLUSTER_ID_ARM].dvfs_nr = ARM_BIN2_DVFS_NR;
+ exynos_asv->cluster[CLUSTER_ID_KFC].dvfs_nr = KFC_BIN2_DVFS_NR;
+ } else {
+ exynos_asv->cluster[CLUSTER_ID_ARM].dvfs_nr = ARM_DVFS_NR;
+ exynos_asv->cluster[CLUSTER_ID_KFC].dvfs_nr = KFC_DVFS_NR;
+ }
+
+ reg = exynos_chipid_read(EXYNOS_CHIPID_AUX_INFO);
+
+ /* ARM offset voltage setup */
+ cluster = &exynos_asv->cluster[CLUSTER_ID_ARM];
+
+ cluster->base_volt = 1000000;
+
+ value = (reg >> EXYNOS5422_ARM_UP_OFFSET) & EXYNOS5422_ARM_UP_MASK;
+ cluster->offset_volt_h = exynos5422_offset_voltage(value);
+
+ value = (reg >> EXYNOS5422_ARM_DN_OFFSET) & EXYNOS5422_ARM_DN_MASK;
+ cluster->offset_volt_l = exynos5422_offset_voltage(value);
+
+ /* KFC offset voltage setup */
+ cluster = &exynos_asv->cluster[CLUSTER_ID_KFC];
+
+ cluster->base_volt = 1000000;
+
+ value = (reg >> EXYNOS5422_KFC_UP_OFFSET) & EXYNOS5422_KFC_UP_MASK;
+ cluster->offset_volt_h = exynos5422_offset_voltage(value);
+
+ value = (reg >> EXYNOS5422_KFC_DN_OFFSET) & EXYNOS5422_KFC_DN_MASK;
+ cluster->offset_volt_l = exynos5422_offset_voltage(value);
+}
+
+int exynos_asv_update_opps(struct device *cpu)
+{
+ struct dev_pm_opp *opp;
+ struct asv_cluster *cluster;
+ unsigned int opp_freq;
+ int cpuid = cpu->id;
+ int cluster_id = -1;
+ int i;
+
+ if (of_device_is_compatible(cpu->of_node, "arm,cortex-a7"))
+ cluster_id = CLUSTER_ID_KFC;
+ else if (of_device_is_compatible(cpu->of_node, "arm,cortex-a15"))
+ cluster_id = CLUSTER_ID_ARM;
+
+ if (cluster_id < 0)
+ return -EINVAL;
+
+ cluster = &exynos_asv->cluster[cluster_id];
+
+ for (i = 0; i < cluster->dvfs_nr; i++) {
+ unsigned int new_voltage;
+ unsigned int voltage;
+ int err;
+
+ opp_freq = cluster->asv_table[i][0];
+
+ opp = dev_pm_opp_find_freq_exact(cpu, opp_freq * 1000, true);
+ if (IS_ERR(opp)) {
+ pr_info("%s cpu%d opp%d, freq: %u missing\n",
+ __func__, cpuid, i, opp_freq);
+
+ continue;
+ }
+
+ voltage = dev_pm_opp_get_voltage(opp);
+ new_voltage = exynos_asv_opp_get_voltage(cluster, opp_freq,
+ voltage);
+ dev_pm_opp_put(opp);
+
+ opp_freq *= 1000;
+ dev_pm_opp_remove(cpu, opp_freq);
+
+ err = dev_pm_opp_add(cpu, opp_freq, new_voltage);
+ if (err < 0)
+ pr_err("%s: Failed to add OPP %u Hz/%u uV for cpu%d\n",
+ __func__, opp_freq, new_voltage, cpuid);
+ }
+
+ return 0;
+}
+
+
+static int __init exynos_asv_init(void)
+{
+ const unsigned int (*arm_asv_table)[EXYNOS5422_ASV_NR + 1];
+ const unsigned int (*kfc_asv_table)[EXYNOS5422_ASV_NR + 1];
+ struct opp_table *last_opp_table = NULL;
+ struct device *cpu;
+ int ret, cpuid;
+
+ /* Currently only exynos5800 is supported */
+ if (!of_machine_is_compatible("samsung,exynos5800") &&
+ !of_machine_is_compatible("samsung,exynos5420"))
+ return 0;
+
+ exynos_asv = kmalloc(sizeof(struct exynos_asv), GFP_KERNEL);
+ if (!exynos_asv)
+ return -ENOMEM;
+
+ exynos_asv->bin2 = exynos_asv_get_bin2();
+
+ if (of_machine_is_compatible("hardkernel,odroid-xu3-lite"))
+ exynos_asv->bin2 = true;
+
+ exynos_asv->special_lot = asv_special_group_check();
+ exynos_asv->group = exynos_asv_get_group(exynos_asv);
+ exynos_asv->table = asv_table_check();
+
+ asv_offset_voltage_setup();
+
+ if (exynos_asv->bin2) {
+ arm_asv_table = arm_info_bin2;
+ kfc_asv_table = kfc_info_bin2;
+ } else {
+ switch(exynos_asv->table) {
+ case 2:
+ arm_asv_table = arm_info_table2;
+ kfc_asv_table = kfc_info_table2;
+ break;
+ case 3:
+ arm_asv_table = arm_info_table3;
+ kfc_asv_table = kfc_info_table3;
+ break;
+ default:
+ arm_asv_table = arm_info_table01;
+ kfc_asv_table = kfc_info_table01;
+ break;
+ }
+ }
+
+ exynos_asv->cluster[CLUSTER_ID_ARM].asv_table = arm_asv_table;
+ exynos_asv->cluster[CLUSTER_ID_KFC].asv_table = kfc_asv_table;
+
+ for_each_possible_cpu(cpuid) {
+ struct opp_table *opp_table;
+
+ cpu = get_cpu_device(cpuid);
+ if (!cpu)
+ continue;
+
+ opp_table = dev_pm_opp_get_opp_table(cpu);
+ if (IS_ERR(opp_table))
+ continue;
+
+ if (!last_opp_table || opp_table != last_opp_table) {
+ last_opp_table = opp_table;
+
+ ret = exynos_asv_update_opps(cpu);
+ if (ret < 0)
+ pr_err("%s: Couldn't udate OPPs for cpu%d\n",
+ __func__, cpuid);
+ }
+
+ dev_pm_opp_put_opp_table(opp_table);
+ }
+
+ return 0;
+}
+late_initcall(exynos_asv_init);