Lines Matching +full:cpufreq +full:- +full:hw

1 // SPDX-License-Identifier: GPL-2.0
7 #include <linux/cpufreq.h>
49 * Mutex to synchronize between de-init sequence and re-starting LMh
75 dev = get_cpu_device(policy->cpu); in qcom_cpufreq_set_bw()
77 return -ENODEV; in qcom_cpufreq_set_bw()
111 struct qcom_cpufreq_data *data = policy->driver_data; in qcom_cpufreq_hw_target_index()
112 const struct qcom_cpufreq_soc_data *soc_data = data->soc_data; in qcom_cpufreq_hw_target_index()
113 unsigned long freq = policy->freq_table[index].frequency; in qcom_cpufreq_hw_target_index()
116 writel_relaxed(index, data->base + soc_data->reg_perf_state); in qcom_cpufreq_hw_target_index()
118 if (data->per_core_dcvs) in qcom_cpufreq_hw_target_index()
119 for (i = 1; i < cpumask_weight(policy->related_cpus); i++) in qcom_cpufreq_hw_target_index()
120 writel_relaxed(index, data->base + soc_data->reg_perf_state + i * 4); in qcom_cpufreq_hw_target_index()
139 data = policy->driver_data; in qcom_cpufreq_hw_get()
140 soc_data = data->soc_data; in qcom_cpufreq_hw_get()
142 index = readl_relaxed(data->base + soc_data->reg_perf_state); in qcom_cpufreq_hw_get()
143 index = min(index, LUT_MAX_ENTRIES - 1); in qcom_cpufreq_hw_get()
145 return policy->freq_table[index].frequency; in qcom_cpufreq_hw_get()
151 struct qcom_cpufreq_data *data = policy->driver_data; in qcom_cpufreq_hw_fast_switch()
152 const struct qcom_cpufreq_soc_data *soc_data = data->soc_data; in qcom_cpufreq_hw_fast_switch()
156 index = policy->cached_resolved_idx; in qcom_cpufreq_hw_fast_switch()
157 writel_relaxed(index, data->base + soc_data->reg_perf_state); in qcom_cpufreq_hw_fast_switch()
159 if (data->per_core_dcvs) in qcom_cpufreq_hw_fast_switch()
160 for (i = 1; i < cpumask_weight(policy->related_cpus); i++) in qcom_cpufreq_hw_fast_switch()
161 writel_relaxed(index, data->base + soc_data->reg_perf_state + i * 4); in qcom_cpufreq_hw_fast_switch()
163 return policy->freq_table[index].frequency; in qcom_cpufreq_hw_fast_switch()
175 struct qcom_cpufreq_data *drv_data = policy->driver_data; in qcom_cpufreq_hw_read_lut()
176 const struct qcom_cpufreq_soc_data *soc_data = drv_data->soc_data; in qcom_cpufreq_hw_read_lut()
180 return -ENOMEM; in qcom_cpufreq_hw_read_lut()
184 /* Disable all opps and cross-validate against LUT later */ in qcom_cpufreq_hw_read_lut()
194 } else if (ret != -ENODEV) { in qcom_cpufreq_hw_read_lut()
198 policy->fast_switch_possible = true; in qcom_cpufreq_hw_read_lut()
203 data = readl_relaxed(drv_data->base + soc_data->reg_freq_lut + in qcom_cpufreq_hw_read_lut()
204 i * soc_data->lut_row_size); in qcom_cpufreq_hw_read_lut()
209 data = readl_relaxed(drv_data->base + soc_data->reg_volt_lut + in qcom_cpufreq_hw_read_lut()
210 i * soc_data->lut_row_size); in qcom_cpufreq_hw_read_lut()
237 struct cpufreq_frequency_table *prev = &table[i - 1]; in qcom_cpufreq_hw_read_lut()
243 if (prev->frequency == CPUFREQ_ENTRY_INVALID) { in qcom_cpufreq_hw_read_lut()
245 prev->frequency = prev_freq; in qcom_cpufreq_hw_read_lut()
246 prev->flags = CPUFREQ_BOOST_FREQ; in qcom_cpufreq_hw_read_lut()
260 policy->freq_table = table; in qcom_cpufreq_hw_read_lut()
261 dev_pm_opp_set_sharing_cpus(cpu_dev, policy->cpus); in qcom_cpufreq_hw_read_lut()
277 ret = of_parse_phandle_with_args(cpu_np, "qcom,freq-domain", in qcom_get_related_cpus()
278 "#freq-domain-cells", 0, in qcom_get_related_cpus()
293 if (data->soc_data->reg_current_vote) in qcom_lmh_get_throttle_freq()
294 lval = readl_relaxed(data->base + data->soc_data->reg_current_vote) & 0x3ff; in qcom_lmh_get_throttle_freq()
296 lval = readl_relaxed(data->base + data->soc_data->reg_domain_state) & 0xff; in qcom_lmh_get_throttle_freq()
303 struct cpufreq_policy *policy = data->policy; in qcom_lmh_dcvs_notify()
304 int cpu = cpumask_first(policy->related_cpus); in qcom_lmh_dcvs_notify()
316 if (IS_ERR(opp) && PTR_ERR(opp) == -ERANGE) in qcom_lmh_dcvs_notify()
327 freq_qos_update_request(&data->throttle_freq_req, throttled_freq); in qcom_lmh_dcvs_notify()
330 arch_update_thermal_pressure(policy->related_cpus, throttled_freq); in qcom_lmh_dcvs_notify()
336 mutex_lock(&data->throttle_lock); in qcom_lmh_dcvs_notify()
337 if (data->cancel_throttle) in qcom_lmh_dcvs_notify()
341 * If h/w throttled frequency is higher than what cpufreq has requested in qcom_lmh_dcvs_notify()
345 enable_irq(data->throttle_irq); in qcom_lmh_dcvs_notify()
347 mod_delayed_work(system_highpri_wq, &data->throttle_work, in qcom_lmh_dcvs_notify()
351 mutex_unlock(&data->throttle_lock); in qcom_lmh_dcvs_notify()
367 disable_irq_nosync(c_data->throttle_irq); in qcom_lmh_dcvs_handle_irq()
368 schedule_delayed_work(&c_data->throttle_work, 0); in qcom_lmh_dcvs_handle_irq()
370 if (c_data->soc_data->reg_intr_clr) in qcom_lmh_dcvs_handle_irq()
372 c_data->base + c_data->soc_data->reg_intr_clr); in qcom_lmh_dcvs_handle_irq()
399 { .compatible = "qcom,cpufreq-hw", .data = &qcom_soc_data },
400 { .compatible = "qcom,cpufreq-epss", .data = &epss_soc_data },
407 struct qcom_cpufreq_data *data = policy->driver_data; in qcom_cpufreq_hw_lmh_init()
413 * if there is an error, allow cpufreq to be enabled as usual. in qcom_cpufreq_hw_lmh_init()
415 data->throttle_irq = platform_get_irq_optional(pdev, index); in qcom_cpufreq_hw_lmh_init()
416 if (data->throttle_irq == -ENXIO) in qcom_cpufreq_hw_lmh_init()
418 if (data->throttle_irq < 0) in qcom_cpufreq_hw_lmh_init()
419 return data->throttle_irq; in qcom_cpufreq_hw_lmh_init()
421 ret = freq_qos_add_request(&policy->constraints, in qcom_cpufreq_hw_lmh_init()
422 &data->throttle_freq_req, FREQ_QOS_MAX, in qcom_cpufreq_hw_lmh_init()
425 dev_err(&pdev->dev, "Failed to add freq constraint (%d)\n", ret); in qcom_cpufreq_hw_lmh_init()
429 data->cancel_throttle = false; in qcom_cpufreq_hw_lmh_init()
430 data->policy = policy; in qcom_cpufreq_hw_lmh_init()
432 mutex_init(&data->throttle_lock); in qcom_cpufreq_hw_lmh_init()
433 INIT_DEFERRABLE_WORK(&data->throttle_work, qcom_lmh_dcvs_poll); in qcom_cpufreq_hw_lmh_init()
435 snprintf(data->irq_name, sizeof(data->irq_name), "dcvsh-irq-%u", policy->cpu); in qcom_cpufreq_hw_lmh_init()
436 ret = request_threaded_irq(data->throttle_irq, NULL, qcom_lmh_dcvs_handle_irq, in qcom_cpufreq_hw_lmh_init()
437 IRQF_ONESHOT | IRQF_NO_AUTOEN, data->irq_name, data); in qcom_cpufreq_hw_lmh_init()
439 dev_err(&pdev->dev, "Error registering %s: %d\n", data->irq_name, ret); in qcom_cpufreq_hw_lmh_init()
443 ret = irq_set_affinity_and_hint(data->throttle_irq, policy->cpus); in qcom_cpufreq_hw_lmh_init()
445 dev_err(&pdev->dev, "Failed to set CPU affinity of %s[%d]\n", in qcom_cpufreq_hw_lmh_init()
446 data->irq_name, data->throttle_irq); in qcom_cpufreq_hw_lmh_init()
453 struct qcom_cpufreq_data *data = policy->driver_data; in qcom_cpufreq_hw_cpu_online()
457 if (data->throttle_irq <= 0) in qcom_cpufreq_hw_cpu_online()
460 mutex_lock(&data->throttle_lock); in qcom_cpufreq_hw_cpu_online()
461 data->cancel_throttle = false; in qcom_cpufreq_hw_cpu_online()
462 mutex_unlock(&data->throttle_lock); in qcom_cpufreq_hw_cpu_online()
464 ret = irq_set_affinity_and_hint(data->throttle_irq, policy->cpus); in qcom_cpufreq_hw_cpu_online()
466 dev_err(&pdev->dev, "Failed to set CPU affinity of %s[%d]\n", in qcom_cpufreq_hw_cpu_online()
467 data->irq_name, data->throttle_irq); in qcom_cpufreq_hw_cpu_online()
474 struct qcom_cpufreq_data *data = policy->driver_data; in qcom_cpufreq_hw_cpu_offline()
476 if (data->throttle_irq <= 0) in qcom_cpufreq_hw_cpu_offline()
479 mutex_lock(&data->throttle_lock); in qcom_cpufreq_hw_cpu_offline()
480 data->cancel_throttle = true; in qcom_cpufreq_hw_cpu_offline()
481 mutex_unlock(&data->throttle_lock); in qcom_cpufreq_hw_cpu_offline()
483 cancel_delayed_work_sync(&data->throttle_work); in qcom_cpufreq_hw_cpu_offline()
484 irq_set_affinity_and_hint(data->throttle_irq, NULL); in qcom_cpufreq_hw_cpu_offline()
485 disable_irq_nosync(data->throttle_irq); in qcom_cpufreq_hw_cpu_offline()
492 if (data->throttle_irq <= 0) in qcom_cpufreq_hw_lmh_exit()
495 freq_qos_remove_request(&data->throttle_freq_req); in qcom_cpufreq_hw_lmh_exit()
496 free_irq(data->throttle_irq, data); in qcom_cpufreq_hw_lmh_exit()
502 struct device *dev = &pdev->dev; in qcom_cpufreq_hw_cpu_init()
511 cpu_dev = get_cpu_device(policy->cpu); in qcom_cpufreq_hw_cpu_init()
514 policy->cpu); in qcom_cpufreq_hw_cpu_init()
515 return -ENODEV; in qcom_cpufreq_hw_cpu_init()
518 cpu_np = of_cpu_device_node_get(policy->cpu); in qcom_cpufreq_hw_cpu_init()
520 return -EINVAL; in qcom_cpufreq_hw_cpu_init()
522 ret = of_parse_phandle_with_args(cpu_np, "qcom,freq-domain", in qcom_cpufreq_hw_cpu_init()
523 "#freq-domain-cells", 0, &args); in qcom_cpufreq_hw_cpu_init()
533 return -ENODEV; in qcom_cpufreq_hw_cpu_init()
536 if (!request_mem_region(res->start, resource_size(res), res->name)) { in qcom_cpufreq_hw_cpu_init()
538 return -EBUSY; in qcom_cpufreq_hw_cpu_init()
541 base = ioremap(res->start, resource_size(res)); in qcom_cpufreq_hw_cpu_init()
544 ret = -ENOMEM; in qcom_cpufreq_hw_cpu_init()
550 ret = -ENOMEM; in qcom_cpufreq_hw_cpu_init()
554 data->soc_data = of_device_get_match_data(&pdev->dev); in qcom_cpufreq_hw_cpu_init()
555 data->base = base; in qcom_cpufreq_hw_cpu_init()
556 data->res = res; in qcom_cpufreq_hw_cpu_init()
558 /* HW should be in enabled state to proceed */ in qcom_cpufreq_hw_cpu_init()
559 if (!(readl_relaxed(base + data->soc_data->reg_enable) & 0x1)) { in qcom_cpufreq_hw_cpu_init()
560 dev_err(dev, "Domain-%d cpufreq hardware not enabled\n", index); in qcom_cpufreq_hw_cpu_init()
561 ret = -ENODEV; in qcom_cpufreq_hw_cpu_init()
565 if (readl_relaxed(base + data->soc_data->reg_dcvs_ctrl) & 0x1) in qcom_cpufreq_hw_cpu_init()
566 data->per_core_dcvs = true; in qcom_cpufreq_hw_cpu_init()
568 qcom_get_related_cpus(index, policy->cpus); in qcom_cpufreq_hw_cpu_init()
569 if (cpumask_empty(policy->cpus)) { in qcom_cpufreq_hw_cpu_init()
570 dev_err(dev, "Domain-%d failed to get related CPUs\n", index); in qcom_cpufreq_hw_cpu_init()
571 ret = -ENOENT; in qcom_cpufreq_hw_cpu_init()
575 policy->driver_data = data; in qcom_cpufreq_hw_cpu_init()
576 policy->dvfs_possible_from_any_cpu = true; in qcom_cpufreq_hw_cpu_init()
580 dev_err(dev, "Domain-%d failed to read LUT\n", index); in qcom_cpufreq_hw_cpu_init()
587 ret = -ENODEV; in qcom_cpufreq_hw_cpu_init()
607 release_mem_region(res->start, resource_size(res)); in qcom_cpufreq_hw_cpu_init()
613 struct device *cpu_dev = get_cpu_device(policy->cpu); in qcom_cpufreq_hw_cpu_exit()
614 struct qcom_cpufreq_data *data = policy->driver_data; in qcom_cpufreq_hw_cpu_exit()
615 struct resource *res = data->res; in qcom_cpufreq_hw_cpu_exit()
616 void __iomem *base = data->base; in qcom_cpufreq_hw_cpu_exit()
619 dev_pm_opp_of_cpumask_remove_table(policy->related_cpus); in qcom_cpufreq_hw_cpu_exit()
621 kfree(policy->freq_table); in qcom_cpufreq_hw_cpu_exit()
624 release_mem_region(res->start, resource_size(res)); in qcom_cpufreq_hw_cpu_exit()
631 struct qcom_cpufreq_data *data = policy->driver_data; in qcom_cpufreq_ready()
633 if (data->throttle_irq >= 0) in qcom_cpufreq_ready()
634 enable_irq(data->throttle_irq); in qcom_cpufreq_ready()
656 .name = "qcom-cpufreq-hw",
667 clk = clk_get(&pdev->dev, "xo"); in qcom_cpufreq_hw_driver_probe()
674 clk = clk_get(&pdev->dev, "alternate"); in qcom_cpufreq_hw_driver_probe()
686 return -EPROBE_DEFER; in qcom_cpufreq_hw_driver_probe()
694 dev_err(&pdev->dev, "CPUFreq HW driver failed to register\n"); in qcom_cpufreq_hw_driver_probe()
696 dev_dbg(&pdev->dev, "QCOM CPUFreq HW driver initialized\n"); in qcom_cpufreq_hw_driver_probe()
710 .name = "qcom-cpufreq-hw",
727 MODULE_DESCRIPTION("QCOM CPUFREQ HW Driver");