Linux Audio

Check our new training course

Loading...
Note: File does not exist in v5.9.
  1/*
  2 * Copyright (c) 2012 Samsung Electronics Co., Ltd.
  3 *		http://www.samsung.com/
  4 *
  5 * EXYNOS5 INT clock frequency scaling support using DEVFREQ framework
  6 * Based on work done by Jonghwan Choi <jhbird.choi@samsung.com>
  7 * Support for only EXYNOS5250 is present.
  8 *
  9 * This program is free software; you can redistribute it and/or modify
 10 * it under the terms of the GNU General Public License version 2 as
 11 * published by the Free Software Foundation.
 12 *
 13 */
 14
 15#include <linux/module.h>
 16#include <linux/devfreq.h>
 17#include <linux/io.h>
 18#include <linux/pm_opp.h>
 19#include <linux/slab.h>
 20#include <linux/suspend.h>
 21#include <linux/clk.h>
 22#include <linux/delay.h>
 23#include <linux/platform_device.h>
 24#include <linux/pm_qos.h>
 25#include <linux/regulator/consumer.h>
 26#include <linux/of_address.h>
 27#include <linux/of_platform.h>
 28
 29#include "exynos_ppmu.h"
 30
 31#define MAX_SAFEVOLT			1100000 /* 1.10V */
 32/* Assume that the bus is saturated if the utilization is 25% */
 33#define INT_BUS_SATURATION_RATIO	25
 34
 35enum int_level_idx {
 36	LV_0,
 37	LV_1,
 38	LV_2,
 39	LV_3,
 40	LV_4,
 41	_LV_END
 42};
 43
 44enum exynos_ppmu_list {
 45	PPMU_RIGHT,
 46	PPMU_END,
 47};
 48
 49struct busfreq_data_int {
 50	struct device *dev;
 51	struct devfreq *devfreq;
 52	struct regulator *vdd_int;
 53	struct exynos_ppmu ppmu[PPMU_END];
 54	unsigned long curr_freq;
 55	bool disabled;
 56
 57	struct notifier_block pm_notifier;
 58	struct mutex lock;
 59	struct pm_qos_request int_req;
 60	struct clk *int_clk;
 61};
 62
 63struct int_bus_opp_table {
 64	unsigned int idx;
 65	unsigned long clk;
 66	unsigned long volt;
 67};
 68
 69static struct int_bus_opp_table exynos5_int_opp_table[] = {
 70	{LV_0, 266000, 1025000},
 71	{LV_1, 200000, 1025000},
 72	{LV_2, 160000, 1025000},
 73	{LV_3, 133000, 1025000},
 74	{LV_4, 100000, 1025000},
 75	{0, 0, 0},
 76};
 77
 78static void busfreq_mon_reset(struct busfreq_data_int *data)
 79{
 80	unsigned int i;
 81
 82	for (i = PPMU_RIGHT; i < PPMU_END; i++) {
 83		void __iomem *ppmu_base = data->ppmu[i].hw_base;
 84
 85		/* Reset the performance and cycle counters */
 86		exynos_ppmu_reset(ppmu_base);
 87
 88		/* Setup count registers to monitor read/write transactions */
 89		data->ppmu[i].event[PPMU_PMNCNT3] = RDWR_DATA_COUNT;
 90		exynos_ppmu_setevent(ppmu_base, PPMU_PMNCNT3,
 91					data->ppmu[i].event[PPMU_PMNCNT3]);
 92
 93		exynos_ppmu_start(ppmu_base);
 94	}
 95}
 96
 97static void exynos5_read_ppmu(struct busfreq_data_int *data)
 98{
 99	int i, j;
100
101	for (i = PPMU_RIGHT; i < PPMU_END; i++) {
102		void __iomem *ppmu_base = data->ppmu[i].hw_base;
103
104		exynos_ppmu_stop(ppmu_base);
105
106		/* Update local data from PPMU */
107		data->ppmu[i].ccnt = __raw_readl(ppmu_base + PPMU_CCNT);
108
109		for (j = PPMU_PMNCNT0; j < PPMU_PMNCNT_MAX; j++) {
110			if (data->ppmu[i].event[j] == 0)
111				data->ppmu[i].count[j] = 0;
112			else
113				data->ppmu[i].count[j] =
114					exynos_ppmu_read(ppmu_base, j);
115		}
116	}
117
118	busfreq_mon_reset(data);
119}
120
121static int exynos5_int_setvolt(struct busfreq_data_int *data,
122				unsigned long volt)
123{
124	return regulator_set_voltage(data->vdd_int, volt, MAX_SAFEVOLT);
125}
126
127static int exynos5_busfreq_int_target(struct device *dev, unsigned long *_freq,
128			      u32 flags)
129{
130	int err = 0;
131	struct platform_device *pdev = container_of(dev, struct platform_device,
132						    dev);
133	struct busfreq_data_int *data = platform_get_drvdata(pdev);
134	struct dev_pm_opp *opp;
135	unsigned long old_freq, freq;
136	unsigned long volt;
137
138	rcu_read_lock();
139	opp = devfreq_recommended_opp(dev, _freq, flags);
140	if (IS_ERR(opp)) {
141		rcu_read_unlock();
142		dev_err(dev, "%s: Invalid OPP.\n", __func__);
143		return PTR_ERR(opp);
144	}
145
146	freq = dev_pm_opp_get_freq(opp);
147	volt = dev_pm_opp_get_voltage(opp);
148	rcu_read_unlock();
149
150	old_freq = data->curr_freq;
151
152	if (old_freq == freq)
153		return 0;
154
155	dev_dbg(dev, "targeting %lukHz %luuV\n", freq, volt);
156
157	mutex_lock(&data->lock);
158
159	if (data->disabled)
160		goto out;
161
162	if (freq > exynos5_int_opp_table[0].clk)
163		pm_qos_update_request(&data->int_req, freq * 16 / 1000);
164	else
165		pm_qos_update_request(&data->int_req, -1);
166
167	if (old_freq < freq)
168		err = exynos5_int_setvolt(data, volt);
169	if (err)
170		goto out;
171
172	err = clk_set_rate(data->int_clk, freq * 1000);
173
174	if (err)
175		goto out;
176
177	if (old_freq > freq)
178		err = exynos5_int_setvolt(data, volt);
179	if (err)
180		goto out;
181
182	data->curr_freq = freq;
183out:
184	mutex_unlock(&data->lock);
185	return err;
186}
187
188static int exynos5_get_busier_dmc(struct busfreq_data_int *data)
189{
190	int i, j;
191	int busy = 0;
192	unsigned int temp = 0;
193
194	for (i = PPMU_RIGHT; i < PPMU_END; i++) {
195		for (j = PPMU_PMNCNT0; j < PPMU_PMNCNT_MAX; j++) {
196			if (data->ppmu[i].count[j] > temp) {
197				temp = data->ppmu[i].count[j];
198				busy = i;
199			}
200		}
201	}
202
203	return busy;
204}
205
206static int exynos5_int_get_dev_status(struct device *dev,
207				      struct devfreq_dev_status *stat)
208{
209	struct platform_device *pdev = container_of(dev, struct platform_device,
210						    dev);
211	struct busfreq_data_int *data = platform_get_drvdata(pdev);
212	int busier_dmc;
213
214	exynos5_read_ppmu(data);
215	busier_dmc = exynos5_get_busier_dmc(data);
216
217	stat->current_frequency = data->curr_freq;
218
219	/* Number of cycles spent on memory access */
220	stat->busy_time = data->ppmu[busier_dmc].count[PPMU_PMNCNT3];
221	stat->busy_time *= 100 / INT_BUS_SATURATION_RATIO;
222	stat->total_time = data->ppmu[busier_dmc].ccnt;
223
224	return 0;
225}
226static void exynos5_int_exit(struct device *dev)
227{
228	struct platform_device *pdev = container_of(dev, struct platform_device,
229						    dev);
230	struct busfreq_data_int *data = platform_get_drvdata(pdev);
231
232	devfreq_unregister_opp_notifier(dev, data->devfreq);
233}
234
235static struct devfreq_dev_profile exynos5_devfreq_int_profile = {
236	.initial_freq		= 160000,
237	.polling_ms		= 100,
238	.target			= exynos5_busfreq_int_target,
239	.get_dev_status		= exynos5_int_get_dev_status,
240	.exit			= exynos5_int_exit,
241};
242
243static int exynos5250_init_int_tables(struct busfreq_data_int *data)
244{
245	int i, err = 0;
246
247	for (i = LV_0; i < _LV_END; i++) {
248		err = dev_pm_opp_add(data->dev, exynos5_int_opp_table[i].clk,
249				exynos5_int_opp_table[i].volt);
250		if (err) {
251			dev_err(data->dev, "Cannot add opp entries.\n");
252			return err;
253		}
254	}
255
256	return 0;
257}
258
259static int exynos5_busfreq_int_pm_notifier_event(struct notifier_block *this,
260		unsigned long event, void *ptr)
261{
262	struct busfreq_data_int *data = container_of(this,
263					struct busfreq_data_int, pm_notifier);
264	struct dev_pm_opp *opp;
265	unsigned long maxfreq = ULONG_MAX;
266	unsigned long freq;
267	unsigned long volt;
268	int err = 0;
269
270	switch (event) {
271	case PM_SUSPEND_PREPARE:
272		/* Set Fastest and Deactivate DVFS */
273		mutex_lock(&data->lock);
274
275		data->disabled = true;
276
277		rcu_read_lock();
278		opp = dev_pm_opp_find_freq_floor(data->dev, &maxfreq);
279		if (IS_ERR(opp)) {
280			rcu_read_unlock();
281			err = PTR_ERR(opp);
282			goto unlock;
283		}
284		freq = dev_pm_opp_get_freq(opp);
285		volt = dev_pm_opp_get_voltage(opp);
286		rcu_read_unlock();
287
288		err = exynos5_int_setvolt(data, volt);
289		if (err)
290			goto unlock;
291
292		err = clk_set_rate(data->int_clk, freq * 1000);
293
294		if (err)
295			goto unlock;
296
297		data->curr_freq = freq;
298unlock:
299		mutex_unlock(&data->lock);
300		if (err)
301			return NOTIFY_BAD;
302		return NOTIFY_OK;
303	case PM_POST_RESTORE:
304	case PM_POST_SUSPEND:
305		/* Reactivate */
306		mutex_lock(&data->lock);
307		data->disabled = false;
308		mutex_unlock(&data->lock);
309		return NOTIFY_OK;
310	}
311
312	return NOTIFY_DONE;
313}
314
315static int exynos5_busfreq_int_probe(struct platform_device *pdev)
316{
317	struct busfreq_data_int *data;
318	struct dev_pm_opp *opp;
319	struct device *dev = &pdev->dev;
320	struct device_node *np;
321	unsigned long initial_freq;
322	unsigned long initial_volt;
323	int err = 0;
324	int i;
325
326	data = devm_kzalloc(&pdev->dev, sizeof(struct busfreq_data_int),
327				GFP_KERNEL);
328	if (data == NULL) {
329		dev_err(dev, "Cannot allocate memory.\n");
330		return -ENOMEM;
331	}
332
333	np = of_find_compatible_node(NULL, NULL, "samsung,exynos5250-ppmu");
334	if (np == NULL) {
335		pr_err("Unable to find PPMU node\n");
336		return -ENOENT;
337	}
338
339	for (i = PPMU_RIGHT; i < PPMU_END; i++) {
340		/* map PPMU memory region */
341		data->ppmu[i].hw_base = of_iomap(np, i);
342		if (data->ppmu[i].hw_base == NULL) {
343			dev_err(&pdev->dev, "failed to map memory region\n");
344			return -ENOMEM;
345		}
346	}
347	data->pm_notifier.notifier_call = exynos5_busfreq_int_pm_notifier_event;
348	data->dev = dev;
349	mutex_init(&data->lock);
350
351	err = exynos5250_init_int_tables(data);
352	if (err)
353		return err;
354
355	data->vdd_int = devm_regulator_get(dev, "vdd_int");
356	if (IS_ERR(data->vdd_int)) {
357		dev_err(dev, "Cannot get the regulator \"vdd_int\"\n");
358		return PTR_ERR(data->vdd_int);
359	}
360
361	data->int_clk = devm_clk_get(dev, "int_clk");
362	if (IS_ERR(data->int_clk)) {
363		dev_err(dev, "Cannot get clock \"int_clk\"\n");
364		return PTR_ERR(data->int_clk);
365	}
366
367	rcu_read_lock();
368	opp = dev_pm_opp_find_freq_floor(dev,
369			&exynos5_devfreq_int_profile.initial_freq);
370	if (IS_ERR(opp)) {
371		rcu_read_unlock();
372		dev_err(dev, "Invalid initial frequency %lu kHz.\n",
373		       exynos5_devfreq_int_profile.initial_freq);
374		return PTR_ERR(opp);
375	}
376	initial_freq = dev_pm_opp_get_freq(opp);
377	initial_volt = dev_pm_opp_get_voltage(opp);
378	rcu_read_unlock();
379	data->curr_freq = initial_freq;
380
381	err = clk_set_rate(data->int_clk, initial_freq * 1000);
382	if (err) {
383		dev_err(dev, "Failed to set initial frequency\n");
384		return err;
385	}
386
387	err = exynos5_int_setvolt(data, initial_volt);
388	if (err)
389		return err;
390
391	platform_set_drvdata(pdev, data);
392
393	busfreq_mon_reset(data);
394
395	data->devfreq = devfreq_add_device(dev, &exynos5_devfreq_int_profile,
396					   "simple_ondemand", NULL);
397
398	if (IS_ERR(data->devfreq)) {
399		err = PTR_ERR(data->devfreq);
400		goto err_devfreq_add;
401	}
402
403	devfreq_register_opp_notifier(dev, data->devfreq);
404
405	err = register_pm_notifier(&data->pm_notifier);
406	if (err) {
407		dev_err(dev, "Failed to setup pm notifier\n");
408		goto err_devfreq_add;
409	}
410
411	/* TODO: Add a new QOS class for int/mif bus */
412	pm_qos_add_request(&data->int_req, PM_QOS_NETWORK_THROUGHPUT, -1);
413
414	return 0;
415
416err_devfreq_add:
417	devfreq_remove_device(data->devfreq);
418	return err;
419}
420
421static int exynos5_busfreq_int_remove(struct platform_device *pdev)
422{
423	struct busfreq_data_int *data = platform_get_drvdata(pdev);
424
425	pm_qos_remove_request(&data->int_req);
426	unregister_pm_notifier(&data->pm_notifier);
427	devfreq_remove_device(data->devfreq);
428
429	return 0;
430}
431
432static int exynos5_busfreq_int_resume(struct device *dev)
433{
434	struct platform_device *pdev = container_of(dev, struct platform_device,
435						    dev);
436	struct busfreq_data_int *data = platform_get_drvdata(pdev);
437
438	busfreq_mon_reset(data);
439	return 0;
440}
441
442static const struct dev_pm_ops exynos5_busfreq_int_pm = {
443	.resume	= exynos5_busfreq_int_resume,
444};
445
446/* platform device pointer for exynos5 devfreq device. */
447static struct platform_device *exynos5_devfreq_pdev;
448
449static struct platform_driver exynos5_busfreq_int_driver = {
450	.probe		= exynos5_busfreq_int_probe,
451	.remove		= exynos5_busfreq_int_remove,
452	.driver		= {
453		.name		= "exynos5-bus-int",
454		.owner		= THIS_MODULE,
455		.pm		= &exynos5_busfreq_int_pm,
456	},
457};
458
459static int __init exynos5_busfreq_int_init(void)
460{
461	int ret;
462
463	ret = platform_driver_register(&exynos5_busfreq_int_driver);
464	if (ret < 0)
465		goto out;
466
467	exynos5_devfreq_pdev =
468		platform_device_register_simple("exynos5-bus-int", -1, NULL, 0);
469	if (IS_ERR(exynos5_devfreq_pdev)) {
470		ret = PTR_ERR(exynos5_devfreq_pdev);
471		goto out1;
472	}
473
474	return 0;
475out1:
476	platform_driver_unregister(&exynos5_busfreq_int_driver);
477out:
478	return ret;
479}
480late_initcall(exynos5_busfreq_int_init);
481
482static void __exit exynos5_busfreq_int_exit(void)
483{
484	platform_device_unregister(exynos5_devfreq_pdev);
485	platform_driver_unregister(&exynos5_busfreq_int_driver);
486}
487module_exit(exynos5_busfreq_int_exit);
488
489MODULE_LICENSE("GPL");
490MODULE_DESCRIPTION("EXYNOS5 busfreq driver with devfreq framework");