Files
android_kernel_samsung_sm8750/drivers/soc/qcom/cpucp_fast.c
2025-08-12 22:16:57 +02:00

125 lines
2.9 KiB
C
Executable File

// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2024, Qualcomm Innovation Center, Inc. All rights reserved.
*/
#include <linux/cpumask.h>
#include <linux/cpufreq.h>
#include <linux/mailbox_client.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/sched/walt.h>
struct qcom_cpucp_fast {
uint8_t last_cpu;
cpumask_t fast_cpus;
struct mbox_client cl;
struct mbox_chan *ch;
};
#define FAST_MBOX_CPUMASK 0xFF
static struct qcom_cpucp_fast qcom_cpucp_fast;
static inline
struct qcom_cpucp_fast *to_qcom_cpucp_fast_info(struct mbox_client *cl)
{
return container_of(cl, struct qcom_cpucp_fast, cl);
}
static void qcom_cpucp_fast_rx(struct mbox_client *cl, void *msg)
{
struct qcom_cpucp_fast *data = &qcom_cpucp_fast;
uint64_t mbox_rx_data = *((uint64_t *)msg);
uint32_t cpu = mbox_rx_data & FAST_MBOX_CPUMASK;
if (!cpumask_weight(&data->fast_cpus)) {
dev_dbg(cl->dev, "No CPUS are enabled for FAST\n");
return;
}
if (cpumask_test_cpu(cpu, &data->fast_cpus) ||
((cpu == FAST_MBOX_CPUMASK) && (data->last_cpu < nr_cpu_ids))) {
data->last_cpu = cpu;
sched_walt_oscillate(cpu);
}
}
static int qcom_cpucp_fast_probe(struct platform_device *pdev)
{
struct qcom_cpucp_fast *data = &qcom_cpucp_fast;
struct device *dev = &pdev->dev;
struct cpufreq_policy *policy = NULL;
int ret, cpu;
data->cl.dev = dev;
data->cl.rx_callback = qcom_cpucp_fast_rx;
data->ch = mbox_request_channel(&data->cl, 0);
if (IS_ERR(data->ch)) {
ret = PTR_ERR(data->ch);
if (ret != -EPROBE_DEFER) {
dev_err(dev, "Error getting mailbox %d\n", ret);
goto err_ch;
}
}
ret = of_property_read_u32(dev->of_node, "qcom,policy-cpus", &cpu);
if (ret) {
dev_err(dev, "Error getting policy%d CPU: %d\n", cpu, ret);
goto err;
}
if (cpu >= nr_cpu_ids || !cpu_present(cpu)) {
dev_err(dev, "Invalid CPU%d\n", cpu);
goto err;
}
policy = cpufreq_cpu_get(cpu);
if (!policy) {
dev_err(dev, "No policy for CPU:%d. Defer.\n", cpu);
ret = -EPROBE_DEFER;
goto err;
}
cpumask_copy(&data->fast_cpus, policy->related_cpus);
cpufreq_cpu_put(policy);
dev_info(dev, "Probe successful, FAST cpus=0x%lx\n", cpumask_bits(&data->fast_cpus)[0]);
return 0;
err:
mbox_free_channel(data->ch);
err_ch:
return ret;
}
static int qcom_cpucp_fast_remove(struct platform_device *pdev)
{
struct qcom_cpucp_fast *data = &qcom_cpucp_fast;
mbox_free_channel(data->ch);
return 0;
};
static const struct of_device_id qcom_cpucp_fast_match[] = {
{ .compatible = "qcom,cpucp_fast" },
{}
};
MODULE_DEVICE_TABLE(of, qcom_cpucp_fast_match);
static struct platform_driver qcom_cpucp_fast_driver = {
.probe = qcom_cpucp_fast_probe,
.remove = qcom_cpucp_fast_remove,
.driver = {
.name = "qcom-cpucp-fast",
.of_match_table = qcom_cpucp_fast_match,
},
};
module_platform_driver(qcom_cpucp_fast_driver);
MODULE_DESCRIPTION("QCOM CPUCP FAST Driver");
MODULE_LICENSE("GPL");