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

Commit fb6b1392 authored by qctecmdr Service's avatar qctecmdr Service Committed by Gerrit - the friendly Code Review server
Browse files

Merge "devfreq: add CDSP L3 governor"

parents d8d81fbb 28e361b3
Loading
Loading
Loading
Loading
+7 −0
Original line number Diff line number Diff line
@@ -255,6 +255,13 @@ config DEVFREQ_SPDM
	  This driver allows any SPDM based client to vote for bandwidth.
	  Used with the QTI SPDM Hypervisor Governor.

config DEVFREQ_GOV_CDSPL3
	bool "QTI DEVFREQ governor for CDSP L3 requests"
	depends on QCOM_CDSP_RM
	help
	  CDSP resource manager will use this governor to vote for L3 clock
	  for IO-coherent traffic generated from CDSP

source "drivers/devfreq/event/Kconfig"

endif # PM_DEVFREQ
+1 −0
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@ obj-$(CONFIG_DEVFREQ_GOV_QCOM_BW_HWMON) += governor_bw_hwmon.o
obj-$(CONFIG_DEVFREQ_GOV_QCOM_CACHE_HWMON)	+= governor_cache_hwmon.o
obj-$(CONFIG_DEVFREQ_GOV_SPDM_HYP)	+= governor_spdm_bw_hyp.o
obj-$(CONFIG_DEVFREQ_GOV_MEMLAT)       += governor_memlat.o
obj-$(CONFIG_DEVFREQ_GOV_CDSPL3)	+= governor_cdsp_l3.o

# DEVFREQ Drivers
obj-$(CONFIG_ARM_EXYNOS_BUS_DEVFREQ)	+= exynos-bus.o
+166 −0
Original line number Diff line number Diff line
/*
 * Copyright (c) 2018 The Linux Foundation. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 and
 * only version 2 as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the
 * GNU General Public License for more details.
 *
 */

#define pr_fmt(fmt) "governor_cdspl3: " fmt

#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/string.h>
#include <linux/err.h>
#include <linux/devfreq.h>
#include <linux/platform_device.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/soc/qcom/cdsprm.h>

#include "governor.h"

struct cdspl3 {
	struct device_node *of_node;
	struct devfreq *df;
	unsigned int l3_freq_hz;
};

static struct cdspl3 p_me;

static int cdsp_l3_request_callback(unsigned int freq_khz)
{
	if (p_me.df) {
		mutex_lock(&p_me.df->lock);
		p_me.l3_freq_hz = freq_khz * 1000;
		update_devfreq(p_me.df);
		mutex_unlock(&p_me.df->lock);
	} else {
		pr_err("CDSP L3 request for %dKHz not served", freq_khz);
		return -ENODEV;
	}
	return 0;
}

static struct cdsprm_l3 cdsprm = {
	.set_l3_freq = cdsp_l3_request_callback,
};

static int devfreq_get_target_freq(struct devfreq *df,
			unsigned long *freq)
{
	if (freq)
		*freq = (unsigned long)p_me.l3_freq_hz;
	return 0;
}

static int gov_start(struct devfreq *df)
{
	if (p_me.of_node != df->dev.parent->of_node) {
		dev_err(df->dev.parent,
		"Device match error in CDSP L3 frequency governor\n");
		return -ENODEV;
	}
	p_me.df = df;
	p_me.l3_freq_hz = 0;
	/*
	 * Send governor start message to CDSP RM driver
	 */
	cdsprm_register_cdspl3gov(&cdsprm);
	return 0;
}

static int gov_stop(struct devfreq *df)
{
	p_me.df = 0;
	p_me.l3_freq_hz = 0;
	/*
	 * Send governor stop message to CDSP RM driver
	 */
	cdsprm_unregister_cdspl3gov();
	return 0;
}

static int devfreq_event_handler(struct devfreq *df,
			unsigned int event, void *data)
{
	int ret;

	switch (event) {
	case DEVFREQ_GOV_START:
		ret = gov_start(df);
		if (ret)
			return ret;
		dev_info(df->dev.parent,
			"Successfully started CDSP L3 governor\n");
		break;
	case DEVFREQ_GOV_STOP:
		dev_info(df->dev.parent,
			"Received stop CDSP L3 governor event\n");
		ret = gov_stop(df);
		if (ret)
			return ret;
		break;
	default:
		break;
	}
	return 0;
}

static struct devfreq_governor cdsp_l3_gov = {
	.name = "cdspl3",
	.get_target_freq = devfreq_get_target_freq,
	.event_handler = devfreq_event_handler,
};

static int cdsp_l3_driver_probe(struct platform_device *pdev)
{
	struct device *dev = &pdev->dev;
	int ret;

	p_me.of_node = of_parse_phandle(dev->of_node, "qcom,target-dev", 0);
	if (!p_me.of_node) {
		dev_err(dev, "Couldn't find a target device\n");
		return -ENODEV;
	}
	ret = devfreq_add_governor(&cdsp_l3_gov);
	if (ret)
		dev_err(dev, "Failed registering CDSP L3 requests %d\n",
			ret);
	return ret;
}

static const struct of_device_id cdsp_l3_match_table[] = {
	{ .compatible = "qcom,cdsp-l3" },
	{}
};

static struct platform_driver cdsp_l3 = {
	.probe = cdsp_l3_driver_probe,
	.driver = {
		.name = "cdsp-l3",
		.of_match_table = cdsp_l3_match_table,
	}
};

static int __init cdsp_l3_gov_module_init(void)
{
	return platform_driver_register(&cdsp_l3);

}
module_init(cdsp_l3_gov_module_init);

static void __exit cdsp_l3_gov_module_exit(void)
{
	devfreq_remove_governor(&cdsp_l3_gov);
	platform_driver_unregister(&cdsp_l3);
}
module_exit(cdsp_l3_gov_module_exit);
MODULE_LICENSE("GPL v2");