blob: a19503e7662db150897b58647fc627bfa253aaba [file] [log] [blame]
Oleg Pereletb906a192017-01-04 09:50:02 -08001/*
2 * Copyright (c) 2014-2017, The Linux Foundation. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 and
6 * only version 2 as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 */
13
14#include <linux/devfreq.h>
15#include <linux/module.h>
16#include "governor.h"
17
18unsigned long (*extern_get_bw)(void) = NULL;
19unsigned long *dev_ab;
20static unsigned long dev_ib;
21
22DEFINE_MUTEX(df_lock);
23static struct devfreq *df;
24
25/*
26 * This function is 'get_target_freq' API for the governor.
27 * It just calls an external function that should be registered
28 * by KGSL driver to get and return a value for frequency.
29 */
30static int devfreq_vbif_get_freq(struct devfreq *df,
31 unsigned long *freq)
32{
33 /* If the IB isn't set yet, check if it should be non-zero. */
34 if (!dev_ib && extern_get_bw) {
35 dev_ib = extern_get_bw();
36 if (dev_ab)
37 *dev_ab = dev_ib / 4;
38 }
39
40 *freq = dev_ib;
41 return 0;
42}
43
44/*
45 * Registers a function to be used to request a frequency
46 * value from legacy vbif based bus bandwidth governor.
47 * This function is called by KGSL driver.
48 */
49void devfreq_vbif_register_callback(void *p)
50{
51 extern_get_bw = p;
52}
53
54int devfreq_vbif_update_bw(unsigned long ib, unsigned long ab)
55{
56 int ret = 0;
57
58 mutex_lock(&df_lock);
59 if (df) {
60 mutex_lock(&df->lock);
61 dev_ib = ib;
62 *dev_ab = ab;
63 ret = update_devfreq(df);
64 mutex_unlock(&df->lock);
65 }
66 mutex_unlock(&df_lock);
67 return ret;
68}
69
70static int devfreq_vbif_ev_handler(struct devfreq *devfreq,
71 unsigned int event, void *data)
72{
73 int ret;
74 struct devfreq_dev_status stat;
75
76 switch (event) {
77 case DEVFREQ_GOV_START:
78 mutex_lock(&df_lock);
79 df = devfreq;
80 if (df->profile->get_dev_status &&
81 !df->profile->get_dev_status(df->dev.parent, &stat) &&
82 stat.private_data)
83 dev_ab = stat.private_data;
84 else
85 pr_warn("Device doesn't take AB votes!\n");
86
87 mutex_unlock(&df_lock);
88
89 ret = devfreq_vbif_update_bw(0, 0);
90 if (ret) {
91 pr_err("Unable to update BW! Gov start failed!\n");
92 return ret;
93 }
94 /*
95 * Normally at this point governors start the polling with
96 * devfreq_monitor_start(df);
97 * This governor doesn't poll, but expect external calls
98 * of its devfreq_vbif_update_bw() function
99 */
100 pr_debug("Enabled MSM VBIF governor\n");
101 break;
102
103 case DEVFREQ_GOV_STOP:
104 mutex_lock(&df_lock);
105 df = NULL;
106 mutex_unlock(&df_lock);
107
108 pr_debug("Disabled MSM VBIF governor\n");
109 break;
110 }
111
112 return 0;
113}
114
115static struct devfreq_governor devfreq_vbif = {
116 .name = "bw_vbif",
117 .get_target_freq = devfreq_vbif_get_freq,
118 .event_handler = devfreq_vbif_ev_handler,
119};
120
121static int __init devfreq_vbif_init(void)
122{
123 return devfreq_add_governor(&devfreq_vbif);
124}
125subsys_initcall(devfreq_vbif_init);
126
127static void __exit devfreq_vbif_exit(void)
128{
129 int ret;
130
131 ret = devfreq_remove_governor(&devfreq_vbif);
132 if (ret)
133 pr_err("%s: failed remove governor %d\n", __func__, ret);
134
135}
136module_exit(devfreq_vbif_exit);
137
138MODULE_DESCRIPTION("VBIF based GPU bus BW voting governor");
139MODULE_LICENSE("GPL v2");
140
141