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

Commit a9ddac8c authored by Taniya Das's avatar Taniya Das
Browse files

cpufreq: qcom: Update logic to register for GT Limits Management interrupt



EPSS hardware generates the GT interrupt when LMH throttle occurs.
Read back the state register to get the throttled frequency and update
the scheduler accordingly. When the throttle is removed the state
register frequency would move back to the SW voted frequency.

Change-Id: I75fbbab63e88b539bc3314e7c0085b9f6249699c
Signed-off-by: default avatarTaniya Das <tdas@codeaurora.org>
parent 36133525
Loading
Loading
Loading
Loading
+21 −30
Original line number Diff line number Diff line
@@ -23,8 +23,7 @@
#define CORE_COUNT_VAL(val)		(((val) & (GENMASK(18, 16))) >> 16)
#define LUT_ROW_SIZE			32
#define CLK_HW_DIV			2
#define EQ_IRQ_STATUS			BIT(0)
#define LT_IRQ_STATUS			BIT(1)
#define GT_IRQ_STATUS			BIT(2)
#define MAX_FN_SIZE			12
#define LIMITS_POLLING_DELAY_MS		10

@@ -37,7 +36,7 @@ enum {
	REG_VOLT_LUT_TABLE,
	REG_PERF_STATE,
	REG_CYCLE_CNTR,
	REG_LLM_DCVS_VC_VOTE,
	REG_DOMAIN_STATE,
	REG_INTR_EN,
	REG_INTR_CLR,
	REG_INTR_STATUS,
@@ -86,7 +85,7 @@ static const u16 cpufreq_qcom_epss_std_offsets[REG_ARRAY_SIZE] = {
	[REG_VOLT_LUT_TABLE]	= 0x200,
	[REG_PERF_STATE]	= 0x320,
	[REG_CYCLE_CNTR]	= 0x3c4,
	[REG_LLM_DCVS_VC_VOTE]	= 0x024,
	[REG_DOMAIN_STATE]	= 0x020,
	[REG_INTR_EN]		= 0x304,
	[REG_INTR_CLR]		= 0x308,
	[REG_INTR_STATUS]	= 0x30C,
@@ -95,6 +94,8 @@ static const u16 cpufreq_qcom_epss_std_offsets[REG_ARRAY_SIZE] = {
static struct cpufreq_counter qcom_cpufreq_counter[NR_CPUS];
static struct cpufreq_qcom *qcom_freq_domain_map[NR_CPUS];

static unsigned int qcom_cpufreq_hw_get(unsigned int cpu);

static ssize_t dcvsh_freq_limit_show(struct device *dev,
		struct device_attribute *attr, char *buf)
{
@@ -105,48 +106,40 @@ static ssize_t dcvsh_freq_limit_show(struct device *dev,

static unsigned long limits_mitigation_notify(struct cpufreq_qcom *c)
{
	int i;
	u32 max_vc;
	unsigned long freq;

	max_vc = readl_relaxed(c->reg_bases[REG_LLM_DCVS_VC_VOTE]) &
						GENMASK(13, 8);
	freq = readl_relaxed(c->reg_bases[REG_DOMAIN_STATE]) &
				GENMASK(7, 0);
	freq = DIV_ROUND_CLOSEST_ULL(freq * c->xo_rate, 1000);

	for (i = 0; i < lut_max_entries; i++) {
		if (c->table[i].driver_data != max_vc)
			continue;
		else {
			sched_update_cpu_freq_min_max(&c->related_cpus, 0,
					c->table[i].frequency);
			trace_dcvsh_freq(cpumask_first(&c->related_cpus),
						c->table[i].frequency);
			c->dcvsh_freq_limit = c->table[i].frequency;
			return c->table[i].frequency;
		}
	}
	sched_update_cpu_freq_min_max(&c->related_cpus, 0, freq);
	trace_dcvsh_freq(cpumask_first(&c->related_cpus), freq);
	c->dcvsh_freq_limit = freq;

	return 0;
	return freq;
}

static void limits_dcvsh_poll(struct work_struct *work)
{
	struct cpufreq_qcom *c = container_of(work, struct cpufreq_qcom,
						freq_poll_work.work);
	struct cpufreq_policy *policy;
	unsigned long freq_limit;
	unsigned long freq_limit, dcvsh_freq;
	u32 regval, cpu;

	mutex_lock(&c->dcvsh_lock);

	cpu = cpumask_first(&c->related_cpus);
	policy = cpufreq_cpu_get_raw(cpu);

	freq_limit = limits_mitigation_notify(c);
	if (freq_limit != policy->cpuinfo.max_freq || !freq_limit) {

	dcvsh_freq = qcom_cpufreq_hw_get(cpu);

	if (freq_limit != dcvsh_freq) {
		mod_delayed_work(system_highpri_wq, &c->freq_poll_work,
				msecs_to_jiffies(LIMITS_POLLING_DELAY_MS));
	} else {
		regval = readl_relaxed(c->reg_bases[REG_INTR_CLR]);
		regval &= ~LT_IRQ_STATUS;
		regval |= GT_IRQ_STATUS;
		writel_relaxed(regval, c->reg_bases[REG_INTR_CLR]);

		c->is_irq_enabled = true;
@@ -162,7 +155,7 @@ static irqreturn_t dcvsh_handle_isr(int irq, void *data)
	u32 regval;

	regval = readl_relaxed(c->reg_bases[REG_INTR_STATUS]);
	if (!(regval & LT_IRQ_STATUS))
	if (!(regval & GT_IRQ_STATUS))
		return IRQ_HANDLED;

	mutex_lock(&c->dcvsh_lock);
@@ -301,7 +294,7 @@ static int qcom_cpufreq_hw_cpu_init(struct cpufreq_policy *policy)
					"dcvsh-irq-%d", policy->cpu);
		ret = devm_request_threaded_irq(cpu_dev, c->dcvsh_irq, NULL,
			dcvsh_handle_isr, IRQF_TRIGGER_HIGH | IRQF_ONESHOT |
			IRQF_NO_SUSPEND | IRQF_SHARED, c->dcvsh_irq_name, c);
			IRQF_NO_SUSPEND, c->dcvsh_irq_name, c);
		if (ret) {
			dev_err(cpu_dev, "Failed to register irq %d\n", ret);
			return ret;
@@ -309,7 +302,6 @@ static int qcom_cpufreq_hw_cpu_init(struct cpufreq_policy *policy)

		c->is_irq_requested = true;
		c->is_irq_enabled = true;
		writel_relaxed(LT_IRQ_STATUS, c->reg_bases[REG_INTR_EN]);
		c->freq_limit_attr.attr.name = "dcvsh_freq_limit";
		c->freq_limit_attr.show = dcvsh_freq_limit_show;
		c->freq_limit_attr.attr.mode = 0444;
@@ -401,7 +393,6 @@ static int qcom_cpufreq_hw_read_lut(struct platform_device *pdev,
		else
			c->table[i].frequency = c->cpu_hw_rate / 1000;

		c->table[i].driver_data = vc;
		cur_freq = c->table[i].frequency;

		dev_dbg(dev, "index=%d freq=%d, core_count %d\n",