summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/clk/qcom/clk-cpu-osm.c66
1 files changed, 56 insertions, 10 deletions
diff --git a/drivers/clk/qcom/clk-cpu-osm.c b/drivers/clk/qcom/clk-cpu-osm.c
index d3914ab5f47c..8bf45f572c5e 100644
--- a/drivers/clk/qcom/clk-cpu-osm.c
+++ b/drivers/clk/qcom/clk-cpu-osm.c
@@ -84,12 +84,14 @@ enum clk_osm_trace_packet_id {
#define VERSION_REG 0x0
#define OSM_TABLE_SIZE 40
+#define MAX_VIRTUAL_CORNER (OSM_TABLE_SIZE - 1)
#define MAX_CLUSTER_CNT 2
#define LLM_SW_OVERRIDE_CNT 3
#define CORE_COUNT_VAL(val) ((val & GENMASK(18, 16)) >> 16)
#define SINGLE_CORE 1
#define MAX_CORE_COUNT 4
#define DEBUG_REG_NUM 3
+#define OSM_SEQ_MINUS_ONE 0xff
#define ENABLE_REG 0x1004
#define INDEX_REG 0x1150
@@ -353,8 +355,10 @@ struct clk_osm {
u32 cluster_num;
u32 irq;
u32 apm_crossover_vc;
+ u32 apm_threshold_pre_vc;
u32 apm_threshold_vc;
u32 mem_acc_crossover_vc;
+ u32 mem_acc_threshold_pre_vc;
u32 mem_acc_threshold_vc;
u32 cycle_counter_reads;
u32 cycle_counter_delay;
@@ -1622,10 +1626,26 @@ static int clk_osm_resolve_crossover_corners(struct clk_osm *c,
if (corner_volt >= apm_threshold) {
c->apm_threshold_vc = c->osm_table[i].virtual_corner;
+ /*
+ * Handle case where VC 0 has open-loop
+ * greater than or equal to APM threshold voltage.
+ */
+ c->apm_threshold_pre_vc = c->apm_threshold_vc ?
+ c->apm_threshold_vc - 1 : OSM_SEQ_MINUS_ONE;
break;
}
}
+ /*
+ * This assumes the OSM table uses corners
+ * 0 to MAX_VIRTUAL_CORNER - 1.
+ */
+ if (!c->apm_threshold_vc &&
+ c->apm_threshold_pre_vc != OSM_SEQ_MINUS_ONE) {
+ c->apm_threshold_vc = MAX_VIRTUAL_CORNER;
+ c->apm_threshold_pre_vc = c->apm_threshold_vc - 1;
+ }
+
/* Determine MEM ACC threshold virtual corner */
if (mem_acc_threshold) {
for (i = 0; i < OSM_TABLE_SIZE; i++) {
@@ -1636,9 +1656,30 @@ static int clk_osm_resolve_crossover_corners(struct clk_osm *c,
if (corner_volt >= mem_acc_threshold) {
c->mem_acc_threshold_vc
= c->osm_table[i].virtual_corner;
+ /*
+ * Handle case where VC 0 has open-loop
+ * greater than or equal to MEM-ACC threshold
+ * voltage.
+ */
+ c->mem_acc_threshold_pre_vc =
+ c->mem_acc_threshold_vc ?
+ c->mem_acc_threshold_vc - 1 :
+ OSM_SEQ_MINUS_ONE;
break;
}
}
+
+ /*
+ * This assumes the OSM table uses corners
+ * 0 to MAX_VIRTUAL_CORNER - 1.
+ */
+ if (!c->mem_acc_threshold_vc && c->mem_acc_threshold_pre_vc
+ != OSM_SEQ_MINUS_ONE) {
+ c->mem_acc_threshold_vc =
+ MAX_VIRTUAL_CORNER;
+ c->mem_acc_threshold_pre_vc =
+ c->mem_acc_threshold_vc - 1;
+ }
}
return 0;
@@ -1989,13 +2030,20 @@ static void clk_osm_program_mem_acc_regs(struct clk_osm *c)
* highest MEM ACC threshold if it is specified instead of the
* fixed mapping in the LUT.
*/
- if (c->mem_acc_threshold_vc) {
- threshold_vc[2] = c->mem_acc_threshold_vc - 1;
+ if (c->mem_acc_threshold_vc || c->mem_acc_threshold_pre_vc
+ == OSM_SEQ_MINUS_ONE) {
+ threshold_vc[2] = c->mem_acc_threshold_pre_vc;
threshold_vc[3] = c->mem_acc_threshold_vc;
- if (threshold_vc[1] >= threshold_vc[2])
- threshold_vc[1] = threshold_vc[2] - 1;
- if (threshold_vc[0] >= threshold_vc[1])
- threshold_vc[0] = threshold_vc[1] - 1;
+
+ if (c->mem_acc_threshold_pre_vc == OSM_SEQ_MINUS_ONE) {
+ threshold_vc[1] = threshold_vc[0] =
+ c->mem_acc_threshold_pre_vc;
+ } else {
+ if (threshold_vc[1] >= threshold_vc[2])
+ threshold_vc[1] = threshold_vc[2] - 1;
+ if (threshold_vc[0] >= threshold_vc[1])
+ threshold_vc[0] = threshold_vc[1] - 1;
+ }
}
scm_io_write(c->pbases[OSM_BASE] + SEQ_REG(55),
@@ -2249,8 +2297,7 @@ static void clk_osm_apm_vc_setup(struct clk_osm *c)
clk_osm_write_reg(c, c->pbases[OSM_BASE] + SEQ_REG(1),
SEQ_REG(8));
clk_osm_write_reg(c, c->apm_threshold_vc, SEQ_REG(15));
- clk_osm_write_reg(c, c->apm_threshold_vc != 0 ?
- c->apm_threshold_vc - 1 : 0xff,
+ clk_osm_write_reg(c, c->apm_threshold_pre_vc,
SEQ_REG(31));
clk_osm_write_reg(c, 0x3b | c->apm_threshold_vc << 6,
SEQ_REG(73));
@@ -2268,8 +2315,7 @@ static void clk_osm_apm_vc_setup(struct clk_osm *c)
scm_io_write(c->pbases[OSM_BASE] + SEQ_REG(15),
c->apm_threshold_vc);
scm_io_write(c->pbases[OSM_BASE] + SEQ_REG(31),
- c->apm_threshold_vc != 0 ?
- c->apm_threshold_vc - 1 : 0xff);
+ c->apm_threshold_pre_vc);
scm_io_write(c->pbases[OSM_BASE] + SEQ_REG(76),
0x39 | c->apm_threshold_vc << 6);
}