brintos

brintos / linux-shallow public Read only

0
0
Text · 12.3 KiB · 7d06c47 Raw
510 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Generic Exynos Bus frequency driver with DEVFREQ Framework4 *5 * Copyright (c) 2016 Samsung Electronics Co., Ltd.6 * Author : Chanwoo Choi <cw00.choi@samsung.com>7 *8 * This driver support Exynos Bus frequency feature by using9 * DEVFREQ framework and is based on drivers/devfreq/exynos/exynos4_bus.c.10 */11 12#include <linux/clk.h>13#include <linux/devfreq.h>14#include <linux/devfreq-event.h>15#include <linux/device.h>16#include <linux/export.h>17#include <linux/module.h>18#include <linux/of.h>19#include <linux/pm_opp.h>20#include <linux/platform_device.h>21#include <linux/regulator/consumer.h>22 23#define DEFAULT_SATURATION_RATIO	4024 25struct exynos_bus {26	struct device *dev;27	struct platform_device *icc_pdev;28 29	struct devfreq *devfreq;30	struct devfreq_event_dev **edev;31	unsigned int edev_count;32	struct mutex lock;33 34	unsigned long curr_freq;35 36	int opp_token;37	struct clk *clk;38	unsigned int ratio;39};40 41/*42 * Control the devfreq-event device to get the current state of bus43 */44#define exynos_bus_ops_edev(ops)				\45static int exynos_bus_##ops(struct exynos_bus *bus)		\46{								\47	int i, ret;						\48								\49	for (i = 0; i < bus->edev_count; i++) {			\50		if (!bus->edev[i])				\51			continue;				\52		ret = devfreq_event_##ops(bus->edev[i]);	\53		if (ret < 0)					\54			return ret;				\55	}							\56								\57	return 0;						\58}59exynos_bus_ops_edev(enable_edev);60exynos_bus_ops_edev(disable_edev);61exynos_bus_ops_edev(set_event);62 63static int exynos_bus_get_event(struct exynos_bus *bus,64				struct devfreq_event_data *edata)65{66	struct devfreq_event_data event_data;67	unsigned long load_count = 0, total_count = 0;68	int i, ret = 0;69 70	for (i = 0; i < bus->edev_count; i++) {71		if (!bus->edev[i])72			continue;73 74		ret = devfreq_event_get_event(bus->edev[i], &event_data);75		if (ret < 0)76			return ret;77 78		if (i == 0 || event_data.load_count > load_count) {79			load_count = event_data.load_count;80			total_count = event_data.total_count;81		}82	}83 84	edata->load_count = load_count;85	edata->total_count = total_count;86 87	return ret;88}89 90/*91 * devfreq function for both simple-ondemand and passive governor92 */93static int exynos_bus_target(struct device *dev, unsigned long *freq, u32 flags)94{95	struct exynos_bus *bus = dev_get_drvdata(dev);96	struct dev_pm_opp *new_opp;97	int ret = 0;98 99	/* Get correct frequency for bus. */100	new_opp = devfreq_recommended_opp(dev, freq, flags);101	if (IS_ERR(new_opp)) {102		dev_err(dev, "failed to get recommended opp instance\n");103		return PTR_ERR(new_opp);104	}105 106	dev_pm_opp_put(new_opp);107 108	/* Change voltage and frequency according to new OPP level */109	mutex_lock(&bus->lock);110	ret = dev_pm_opp_set_rate(dev, *freq);111	if (!ret)112		bus->curr_freq = *freq;113 114	mutex_unlock(&bus->lock);115 116	return ret;117}118 119static int exynos_bus_get_dev_status(struct device *dev,120				     struct devfreq_dev_status *stat)121{122	struct exynos_bus *bus = dev_get_drvdata(dev);123	struct devfreq_event_data edata;124	int ret;125 126	stat->current_frequency = bus->curr_freq;127 128	ret = exynos_bus_get_event(bus, &edata);129	if (ret < 0) {130		dev_err(dev, "failed to get event from devfreq-event devices\n");131		stat->total_time = stat->busy_time = 0;132		goto err;133	}134 135	stat->busy_time = (edata.load_count * 100) / bus->ratio;136	stat->total_time = edata.total_count;137 138	dev_dbg(dev, "Usage of devfreq-event : %lu/%lu\n", stat->busy_time,139							stat->total_time);140 141err:142	ret = exynos_bus_set_event(bus);143	if (ret < 0) {144		dev_err(dev, "failed to set event to devfreq-event devices\n");145		return ret;146	}147 148	return ret;149}150 151static void exynos_bus_exit(struct device *dev)152{153	struct exynos_bus *bus = dev_get_drvdata(dev);154	int ret;155 156	ret = exynos_bus_disable_edev(bus);157	if (ret < 0)158		dev_warn(dev, "failed to disable the devfreq-event devices\n");159 160	platform_device_unregister(bus->icc_pdev);161 162	dev_pm_opp_of_remove_table(dev);163	dev_pm_opp_put_regulators(bus->opp_token);164}165 166static void exynos_bus_passive_exit(struct device *dev)167{168	struct exynos_bus *bus = dev_get_drvdata(dev);169 170	platform_device_unregister(bus->icc_pdev);171 172	dev_pm_opp_of_remove_table(dev);173}174 175static int exynos_bus_parent_parse_of(struct device_node *np,176					struct exynos_bus *bus)177{178	struct device *dev = bus->dev;179	const char *supplies[] = { "vdd", NULL };180	int i, ret, count, size;181 182	ret = dev_pm_opp_set_regulators(dev, supplies);183	if (ret < 0) {184		dev_err(dev, "failed to set regulators %d\n", ret);185		return ret;186	}187 188	bus->opp_token = ret;189 190	/*191	 * Get the devfreq-event devices to get the current utilization of192	 * buses. This raw data will be used in devfreq ondemand governor.193	 */194	count = devfreq_event_get_edev_count(dev, "devfreq-events");195	if (count < 0) {196		dev_err(dev, "failed to get the count of devfreq-event dev\n");197		ret = count;198		goto err_regulator;199	}200	bus->edev_count = count;201 202	size = sizeof(*bus->edev) * count;203	bus->edev = devm_kzalloc(dev, size, GFP_KERNEL);204	if (!bus->edev) {205		ret = -ENOMEM;206		goto err_regulator;207	}208 209	for (i = 0; i < count; i++) {210		bus->edev[i] = devfreq_event_get_edev_by_phandle(dev,211							"devfreq-events", i);212		if (IS_ERR(bus->edev[i])) {213			ret = -EPROBE_DEFER;214			goto err_regulator;215		}216	}217 218	/*219	 * Optionally, Get the saturation ratio according to Exynos SoC220	 * When measuring the utilization of each AXI bus with devfreq-event221	 * devices, the measured real cycle might be much lower than the222	 * total cycle of bus during sampling rate. In result, the devfreq223	 * simple-ondemand governor might not decide to change the current224	 * frequency due to too utilization (= real cycle/total cycle).225	 * So, this property is used to adjust the utilization when calculating226	 * the busy_time in exynos_bus_get_dev_status().227	 */228	if (of_property_read_u32(np, "exynos,saturation-ratio", &bus->ratio))229		bus->ratio = DEFAULT_SATURATION_RATIO;230 231	return 0;232 233err_regulator:234	dev_pm_opp_put_regulators(bus->opp_token);235 236	return ret;237}238 239static int exynos_bus_parse_of(struct device_node *np,240			      struct exynos_bus *bus)241{242	struct device *dev = bus->dev;243	struct dev_pm_opp *opp;244	unsigned long rate;245	int ret;246 247	/* Get the clock to provide each bus with source clock */248	bus->clk = devm_clk_get_enabled(dev, "bus");249	if (IS_ERR(bus->clk))250		return dev_err_probe(dev, PTR_ERR(bus->clk),251				"failed to get bus clock\n");252 253	/* Get the freq and voltage from OPP table to scale the bus freq */254	ret = dev_pm_opp_of_add_table(dev);255	if (ret < 0) {256		dev_err(dev, "failed to get OPP table\n");257		return ret;258	}259 260	rate = clk_get_rate(bus->clk);261 262	opp = devfreq_recommended_opp(dev, &rate, 0);263	if (IS_ERR(opp)) {264		dev_err(dev, "failed to find dev_pm_opp\n");265		ret = PTR_ERR(opp);266		goto err_opp;267	}268	bus->curr_freq = dev_pm_opp_get_freq(opp);269	dev_pm_opp_put(opp);270 271	return 0;272 273err_opp:274	dev_pm_opp_of_remove_table(dev);275 276	return ret;277}278 279static int exynos_bus_profile_init(struct exynos_bus *bus,280				   struct devfreq_dev_profile *profile)281{282	struct device *dev = bus->dev;283	struct devfreq_simple_ondemand_data *ondemand_data;284	int ret;285 286	/* Initialize the struct profile and governor data for parent device */287	profile->polling_ms = 50;288	profile->target = exynos_bus_target;289	profile->get_dev_status = exynos_bus_get_dev_status;290	profile->exit = exynos_bus_exit;291 292	ondemand_data = devm_kzalloc(dev, sizeof(*ondemand_data), GFP_KERNEL);293	if (!ondemand_data)294		return -ENOMEM;295 296	ondemand_data->upthreshold = 40;297	ondemand_data->downdifferential = 5;298 299	/* Add devfreq device to monitor and handle the exynos bus */300	bus->devfreq = devm_devfreq_add_device(dev, profile,301						DEVFREQ_GOV_SIMPLE_ONDEMAND,302						ondemand_data);303	if (IS_ERR(bus->devfreq)) {304		dev_err(dev, "failed to add devfreq device\n");305		return PTR_ERR(bus->devfreq);306	}307 308	/* Register opp_notifier to catch the change of OPP  */309	ret = devm_devfreq_register_opp_notifier(dev, bus->devfreq);310	if (ret < 0) {311		dev_err(dev, "failed to register opp notifier\n");312		return ret;313	}314 315	/*316	 * Enable devfreq-event to get raw data which is used to determine317	 * current bus load.318	 */319	ret = exynos_bus_enable_edev(bus);320	if (ret < 0) {321		dev_err(dev, "failed to enable devfreq-event devices\n");322		return ret;323	}324 325	ret = exynos_bus_set_event(bus);326	if (ret < 0) {327		dev_err(dev, "failed to set event to devfreq-event devices\n");328		goto err_edev;329	}330 331	return 0;332 333err_edev:334	if (exynos_bus_disable_edev(bus))335		dev_warn(dev, "failed to disable the devfreq-event devices\n");336 337	return ret;338}339 340static int exynos_bus_profile_init_passive(struct exynos_bus *bus,341					   struct devfreq_dev_profile *profile)342{343	struct device *dev = bus->dev;344	struct devfreq_passive_data *passive_data;345	struct devfreq *parent_devfreq;346 347	/* Initialize the struct profile and governor data for passive device */348	profile->target = exynos_bus_target;349	profile->exit = exynos_bus_passive_exit;350 351	/* Get the instance of parent devfreq device */352	parent_devfreq = devfreq_get_devfreq_by_phandle(dev, "devfreq", 0);353	if (IS_ERR(parent_devfreq))354		return -EPROBE_DEFER;355 356	passive_data = devm_kzalloc(dev, sizeof(*passive_data), GFP_KERNEL);357	if (!passive_data)358		return -ENOMEM;359 360	passive_data->parent = parent_devfreq;361 362	/* Add devfreq device for exynos bus with passive governor */363	bus->devfreq = devm_devfreq_add_device(dev, profile, DEVFREQ_GOV_PASSIVE,364						passive_data);365	if (IS_ERR(bus->devfreq)) {366		dev_err(dev,367			"failed to add devfreq dev with passive governor\n");368		return PTR_ERR(bus->devfreq);369	}370 371	return 0;372}373 374static int exynos_bus_probe(struct platform_device *pdev)375{376	struct device *dev = &pdev->dev;377	struct device_node *np = dev->of_node, *node;378	struct devfreq_dev_profile *profile;379	struct exynos_bus *bus;380	int ret, max_state;381	unsigned long min_freq, max_freq;382	bool passive = false;383 384	if (!np) {385		dev_err(dev, "failed to find devicetree node\n");386		return -EINVAL;387	}388 389	bus = devm_kzalloc(&pdev->dev, sizeof(*bus), GFP_KERNEL);390	if (!bus)391		return -ENOMEM;392	mutex_init(&bus->lock);393	bus->dev = &pdev->dev;394	platform_set_drvdata(pdev, bus);395 396	profile = devm_kzalloc(dev, sizeof(*profile), GFP_KERNEL);397	if (!profile)398		return -ENOMEM;399 400	node = of_parse_phandle(dev->of_node, "devfreq", 0);401	if (node) {402		of_node_put(node);403		passive = true;404	} else {405		ret = exynos_bus_parent_parse_of(np, bus);406		if (ret < 0)407			return ret;408	}409 410	/* Parse the device-tree to get the resource information */411	ret = exynos_bus_parse_of(np, bus);412	if (ret < 0)413		goto err_reg;414 415	if (passive)416		ret = exynos_bus_profile_init_passive(bus, profile);417	else418		ret = exynos_bus_profile_init(bus, profile);419 420	if (ret < 0)421		goto err;422 423	/* Create child platform device for the interconnect provider */424	if (of_property_present(dev->of_node, "#interconnect-cells")) {425		bus->icc_pdev = platform_device_register_data(426						dev, "exynos-generic-icc",427						PLATFORM_DEVID_AUTO, NULL, 0);428 429		if (IS_ERR(bus->icc_pdev)) {430			ret = PTR_ERR(bus->icc_pdev);431			goto err;432		}433	}434 435	max_state = bus->devfreq->max_state;436	min_freq = (bus->devfreq->freq_table[0] / 1000);437	max_freq = (bus->devfreq->freq_table[max_state - 1] / 1000);438	pr_info("exynos-bus: new bus device registered: %s (%6ld KHz ~ %6ld KHz)\n",439			dev_name(dev), min_freq, max_freq);440 441	return 0;442 443err:444	dev_pm_opp_of_remove_table(dev);445err_reg:446	dev_pm_opp_put_regulators(bus->opp_token);447 448	return ret;449}450 451static void exynos_bus_shutdown(struct platform_device *pdev)452{453	struct exynos_bus *bus = dev_get_drvdata(&pdev->dev);454 455	devfreq_suspend_device(bus->devfreq);456}457 458static int exynos_bus_resume(struct device *dev)459{460	struct exynos_bus *bus = dev_get_drvdata(dev);461	int ret;462 463	ret = exynos_bus_enable_edev(bus);464	if (ret < 0) {465		dev_err(dev, "failed to enable the devfreq-event devices\n");466		return ret;467	}468 469	return 0;470}471 472static int exynos_bus_suspend(struct device *dev)473{474	struct exynos_bus *bus = dev_get_drvdata(dev);475	int ret;476 477	ret = exynos_bus_disable_edev(bus);478	if (ret < 0) {479		dev_err(dev, "failed to disable the devfreq-event devices\n");480		return ret;481	}482 483	return 0;484}485 486static DEFINE_SIMPLE_DEV_PM_OPS(exynos_bus_pm,487				exynos_bus_suspend, exynos_bus_resume);488 489static const struct of_device_id exynos_bus_of_match[] = {490	{ .compatible = "samsung,exynos-bus", },491	{ /* sentinel */ },492};493MODULE_DEVICE_TABLE(of, exynos_bus_of_match);494 495static struct platform_driver exynos_bus_platdrv = {496	.probe		= exynos_bus_probe,497	.shutdown	= exynos_bus_shutdown,498	.driver = {499		.name	= "exynos-bus",500		.pm	= pm_sleep_ptr(&exynos_bus_pm),501		.of_match_table = exynos_bus_of_match,502	},503};504module_platform_driver(exynos_bus_platdrv);505 506MODULE_SOFTDEP("pre: exynos_ppmu");507MODULE_DESCRIPTION("Generic Exynos Bus frequency driver");508MODULE_AUTHOR("Chanwoo Choi <cw00.choi@samsung.com>");509MODULE_LICENSE("GPL v2");510