Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 8ee6b5b8 authored by Deepak Katragadda's avatar Deepak Katragadda Committed by Gerrit - the friendly Code Review server
Browse files

clk: qcom: clk-cpu-osm: Add support for trustzone enablement of OSM



On SDM845, OSM initialization and enablement will be moved to
trustzone. As part of that, add support in the HLOS OSM clock
driver to detect whether trustzone has enabled OSM and to then
take the necessary actions.

Change-Id: I6d588cf06d293895684f4b22ba7bfa0709f3978e
Signed-off-by: default avatarDeepak Katragadda <dkatraga@codeaurora.org>
parent 5f300da0
Loading
Loading
Loading
Loading
+314 −223
Original line number Diff line number Diff line
@@ -45,6 +45,7 @@
#include "clk-debug.h"

#define OSM_INIT_RATE			300000000UL
#define XO_RATE				19200000UL
#define OSM_TABLE_SIZE			40
#define SINGLE_CORE			1
#define MAX_CLUSTER_CNT			3
@@ -450,6 +451,7 @@ static int clk_osm_acd_auto_local_write_reg(struct clk_osm *c, u32 mask)
}

static bool is_v2;
static bool osm_tz_enabled;

static inline struct clk_osm *to_clk_osm(struct clk_hw *_hw)
{
@@ -544,23 +546,12 @@ static long clk_osm_round_rate(struct clk_hw *hw, unsigned long rate,

static int clk_osm_search_table(struct osm_entry *table, int entries, long rate)
{
	int quad_core_index, single_core_index = 0;
	int core_count;

	for (quad_core_index = 0; quad_core_index < entries;
						quad_core_index++) {
		core_count = CORE_COUNT_VAL(table[quad_core_index].freq_data);
		if (rate == table[quad_core_index].frequency &&
					core_count == SINGLE_CORE) {
			single_core_index = quad_core_index;
			continue;
		}
		if (rate == table[quad_core_index].frequency &&
					core_count == MAX_CORE_COUNT)
			return quad_core_index;
	int index = 0;

	for (index = 0; index < entries; index++) {
		if (rate == table[index].frequency)
			return index;
	}
	if (single_core_index)
		return single_core_index;

	return -EINVAL;
}
@@ -642,7 +633,7 @@ static unsigned long l3_clk_recalc_rate(struct clk_hw *hw,
}


const struct clk_ops clk_ops_l3_osm = {
static struct clk_ops clk_ops_l3_osm = {
	.enable = clk_osm_enable,
	.round_rate = clk_osm_round_rate,
	.list_rate = clk_osm_list_rate,
@@ -2107,6 +2098,49 @@ static int clk_osm_get_lut(struct platform_device *pdev,
	return rc;
}

static int clk_osm_read_lut(struct platform_device *pdev, struct clk_osm *c)
{
	u32 data, src, lval, i, j = OSM_TABLE_SIZE;

	for (i = 0; i < OSM_TABLE_SIZE; i++) {
		data = clk_osm_read_reg(c, FREQ_REG + i * OSM_REG_SIZE);
		src = ((data & GENMASK(31, 30)) >> 30);
		lval = (data & GENMASK(7, 0));

		if (!src)
			c->osm_table[i].frequency = OSM_INIT_RATE;
		else
			c->osm_table[i].frequency = XO_RATE * lval;

		data = clk_osm_read_reg(c, VOLT_REG + i * OSM_REG_SIZE);
		c->osm_table[i].virtual_corner =
					((data & GENMASK(21, 16)) >> 16);
		c->osm_table[i].open_loop_volt = (data & GENMASK(11, 0));

		pr_debug("index=%d freq=%ld virtual_corner=%d open_loop_voltage=%u\n",
			 i, c->osm_table[i].frequency,
			 c->osm_table[i].virtual_corner,
			 c->osm_table[i].open_loop_volt);

		if (i > 0 && j == OSM_TABLE_SIZE && c->osm_table[i].frequency ==
					c->osm_table[i - 1].frequency)
			j = i;
	}

	osm_clks_init[c->cluster_num].rate_max = devm_kcalloc(&pdev->dev,
						 j, sizeof(unsigned long),
						       GFP_KERNEL);
	if (!osm_clks_init[c->cluster_num].rate_max)
		return -ENOMEM;

	for (i = 0; i < j; i++)
		osm_clks_init[c->cluster_num].rate_max[i] =
					c->osm_table[i].frequency;

	c->num_entries = osm_clks_init[c->cluster_num].num_rate_max = j;
	return 0;
}

static int clk_osm_parse_acd_dt_configs(struct platform_device *pdev)
{
	struct device_node *of = pdev->dev.of_node;
@@ -2582,6 +2616,12 @@ static int clk_osm_resources_init(struct platform_device *pdev)
		return -ENOMEM;
	}

	/* Check if OSM has been enabled already by trustzone.  */
	if (readl_relaxed(l3_clk.vbases[OSM_BASE] + ENABLE_REG)) {
		dev_info(&pdev->dev, "OSM has been initialized and enabled by TZ software\n");
		osm_tz_enabled = true;
	}

	res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
						"osm_pwrcl_base");
	if (!res) {
@@ -2615,6 +2655,9 @@ static int clk_osm_resources_init(struct platform_device *pdev)
		return -ENOMEM;
	}

	if (osm_tz_enabled)
		return rc;

	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "l3_pll");
	if (!res) {
		dev_err(&pdev->dev,
@@ -3029,6 +3072,7 @@ static int clk_cpu_osm_driver_probe(struct platform_device *pdev)
		return rc;
	}

	if (!osm_tz_enabled) {
		if (l3_clk.vbases[EFUSE_BASE]) {
			/* Multiple speed-bins are supported */
			pte_efuse = readl_relaxed(l3_clk.vbases[EFUSE_BASE]);
@@ -3070,12 +3114,14 @@ static int clk_cpu_osm_driver_probe(struct platform_device *pdev)

		if (perfcl_clk.vbases[EFUSE_BASE]) {
			/* Multiple speed-bins are supported */
		pte_efuse = readl_relaxed(perfcl_clk.vbases[EFUSE_BASE]);
		perfcl_clk.speedbin = ((pte_efuse >> PERFCL_EFUSE_SHIFT) &
							PERFCL_EFUSE_MASK);
		snprintf(perfclspeedbinstr, ARRAY_SIZE(perfclspeedbinstr),
			 "qcom,perfcl-speedbin%d-v%d", perfcl_clk.speedbin,
							pvs_ver);
			pte_efuse =
				readl_relaxed(perfcl_clk.vbases[EFUSE_BASE]);
			perfcl_clk.speedbin = ((pte_efuse >> PERFCL_EFUSE_SHIFT)
						& PERFCL_EFUSE_MASK);
			snprintf(perfclspeedbinstr,
				ARRAY_SIZE(perfclspeedbinstr),
				"qcom,perfcl-speedbin%d-v%d",
				perfcl_clk.speedbin, pvs_ver);
		}

		dev_info(&pdev->dev, "using perfcl speed bin %u and pvs_ver %d\n",
@@ -3115,7 +3161,6 @@ static int clk_cpu_osm_driver_probe(struct platform_device *pdev)
				rc);
			return rc;
		}

		rc = clk_osm_resolve_open_loop_voltages(&pwrcl_clk);
		if (rc) {
			if (rc == -EPROBE_DEFER)
@@ -3124,7 +3169,6 @@ static int clk_cpu_osm_driver_probe(struct platform_device *pdev)
				rc);
			return rc;
		}

		rc = clk_osm_resolve_open_loop_voltages(&perfcl_clk);
		if (rc) {
			if (rc == -EPROBE_DEFER)
@@ -3138,12 +3182,10 @@ static int clk_cpu_osm_driver_probe(struct platform_device *pdev)
		if (rc)
			dev_info(&pdev->dev,
				"No APM crossover corner programmed for L3\n");

		rc = clk_osm_resolve_crossover_corners(&pwrcl_clk, pdev);
		if (rc)
			dev_info(&pdev->dev,
				"No APM crossover corner programmed for pwrcl_clk\n");

		rc = clk_osm_resolve_crossover_corners(&perfcl_clk, pdev);
		if (rc)
			dev_info(&pdev->dev, "No MEM-ACC crossover corner programmed\n");
@@ -3197,19 +3239,23 @@ static int clk_cpu_osm_driver_probe(struct platform_device *pdev)
		clk_osm_setup_fsms(&pwrcl_clk);
		clk_osm_setup_fsms(&perfcl_clk);

	/* Program VC at which the array power supply needs to be switched */
		/*
		 * Program the VC at which the array power supply
		 * needs to be switched.
		 */
		clk_osm_write_reg(&perfcl_clk, perfcl_clk.apm_threshold_vc,
				APM_CROSSOVER_VC, OSM_BASE);
		if (perfcl_clk.secure_init) {
		clk_osm_write_seq_reg(&perfcl_clk, perfcl_clk.apm_crossover_vc,
				DATA_MEM(77));
			clk_osm_write_seq_reg(&perfcl_clk,
				perfcl_clk.apm_crossover_vc, DATA_MEM(77));
			clk_osm_write_seq_reg(&perfcl_clk,
				(0x39 | (perfcl_clk.apm_threshold_vc << 6)),
				DATA_MEM(111));
		} else {
			scm_io_write(perfcl_clk.pbases[SEQ_BASE] + DATA_MEM(77),
					perfcl_clk.apm_crossover_vc);
		scm_io_write(perfcl_clk.pbases[SEQ_BASE] + DATA_MEM(111),
			scm_io_write(perfcl_clk.pbases[SEQ_BASE] +
								DATA_MEM(111),
				(0x39 | (perfcl_clk.apm_threshold_vc << 6)));
		}

@@ -3226,7 +3272,8 @@ static int clk_cpu_osm_driver_probe(struct platform_device *pdev)
		clk_osm_program_mem_acc_regs(&pwrcl_clk);
		clk_osm_program_mem_acc_regs(&perfcl_clk);

	if (of_property_read_bool(pdev->dev.of_node, "qcom,osm-pll-setup")) {
		if (of_property_read_bool(pdev->dev.of_node,
					"qcom,osm-pll-setup")) {
			clk_osm_setup_cluster_pll(&l3_clk);
			clk_osm_setup_cluster_pll(&pwrcl_clk);
			clk_osm_setup_cluster_pll(&perfcl_clk);
@@ -3237,33 +3284,70 @@ static int clk_cpu_osm_driver_probe(struct platform_device *pdev)
		clk_osm_misc_programming(&pwrcl_clk);
		clk_osm_misc_programming(&perfcl_clk);

		rc = clk_osm_acd_init(&l3_clk);
		if (rc) {
			pr_err("failed to initialize ACD for L3, rc=%d\n", rc);
			goto exit;
		}
		rc = clk_osm_acd_init(&pwrcl_clk);
		if (rc) {
			pr_err("failed to initialize ACD for pwrcl, rc=%d\n",
									rc);
			goto exit;
		}
		rc = clk_osm_acd_init(&perfcl_clk);
		if (rc) {
			pr_err("failed to initialize ACD for perfcl, rc=%d\n",
									rc);
			goto exit;
		}

		pwrcl_clk.per_core_dcvs = perfcl_clk.per_core_dcvs =
			of_property_read_bool(pdev->dev.of_node,
				"qcom,enable-per-core-dcvs");
		if (pwrcl_clk.per_core_dcvs) {
			val = clk_osm_read_reg(&pwrcl_clk, CORE_DCVS_CTRL);
			val |= BIT(0);
		clk_osm_write_reg(&pwrcl_clk, val, CORE_DCVS_CTRL, OSM_BASE);

			clk_osm_write_reg(&pwrcl_clk, val, CORE_DCVS_CTRL,
							OSM_BASE);
			val = clk_osm_read_reg(&perfcl_clk, CORE_DCVS_CTRL);
			val |= BIT(0);
		clk_osm_write_reg(&perfcl_clk, val, CORE_DCVS_CTRL, OSM_BASE);
			clk_osm_write_reg(&perfcl_clk, val, CORE_DCVS_CTRL,
							OSM_BASE);
		}

	rc = clk_osm_acd_init(&l3_clk);
	} else {
		/* OSM has been enabled already by trustzone */
		rc = clk_osm_read_lut(pdev, &l3_clk);
		if (rc) {
		pr_err("failed to initialize ACD for L3, rc=%d\n", rc);
		goto exit;
			dev_err(&pdev->dev, "Unable to read OSM LUT for L3, rc=%d\n",
				rc);
			return rc;
		}
	rc = clk_osm_acd_init(&pwrcl_clk);

		rc = clk_osm_read_lut(pdev, &pwrcl_clk);
		if (rc) {
		pr_err("failed to initialize ACD for pwrcl, rc=%d\n", rc);
		goto exit;
			dev_err(&pdev->dev, "Unable to read OSM LUT for power cluster, rc=%d\n",
				rc);
			return rc;
		}
	rc = clk_osm_acd_init(&perfcl_clk);

		rc = clk_osm_read_lut(pdev, &perfcl_clk);
		if (rc) {
		pr_err("failed to initialize ACD for perfcl, rc=%d\n", rc);
		goto exit;
			dev_err(&pdev->dev, "Unable to read OSM LUT for perf cluster, rc=%d\n",
				rc);
			return rc;
		}

		/* Check if per-core DCVS is enabled/not */
		val = clk_osm_read_reg(&pwrcl_clk, CORE_DCVS_CTRL);
		if (val && BIT(0))
			pwrcl_clk.per_core_dcvs = true;

		val = clk_osm_read_reg(&perfcl_clk, CORE_DCVS_CTRL);
		if (val && BIT(0))
			perfcl_clk.per_core_dcvs = true;

		clk_ops_l3_osm.enable = NULL;
	}

	spin_lock_init(&l3_clk.lock);
@@ -3290,7 +3374,23 @@ static int clk_cpu_osm_driver_probe(struct platform_device *pdev)

	get_online_cpus();

	/* Set the L3 clock to run off GPLL0 and enable OSM for the domain */
	if (!osm_tz_enabled) {
		populate_debugfs_dir(&l3_clk);
		populate_debugfs_dir(&pwrcl_clk);
		populate_debugfs_dir(&perfcl_clk);

		/* Configure default rate to lowest frequency */
		for (i = 0; i < MAX_CORE_COUNT; i++) {
			osm_set_index(&pwrcl_clk, 0, i);
			osm_set_index(&perfcl_clk, 0, i);
		}
	}
	/*
	 * Set the L3 clock to run off GPLL0 and enable OSM for the domain.
	 * In the case that trustzone has already enabled OSM, bring the L3
	 * clock rate to a safe level until the devfreq driver comes up and
	 * votes for its desired frequency.
	 */
	rc = clk_set_rate(l3_clk.hw.clk, OSM_INIT_RATE);
	if (rc) {
		dev_err(&pdev->dev, "Unable to set init rate on L3 cluster, rc=%d\n",
@@ -3303,16 +3403,7 @@ static int clk_cpu_osm_driver_probe(struct platform_device *pdev)
			"clk: Failed to enable cluster1 clock for L3\n");
	udelay(300);

	/* Configure default rate to lowest frequency */
	for (i = 0; i < MAX_CORE_COUNT; i++) {
		osm_set_index(&pwrcl_clk, 0, i);
		osm_set_index(&perfcl_clk, 0, i);
	}

	populate_opp_table(pdev);
	populate_debugfs_dir(&l3_clk);
	populate_debugfs_dir(&pwrcl_clk);
	populate_debugfs_dir(&perfcl_clk);

	of_platform_populate(pdev->dev.of_node, NULL, NULL, &pdev->dev);
	register_cpu_cycle_counter_cb(&cb);