aboutsummaryrefslogtreecommitdiffstats
path: root/recipes-kernel/linux/linux-omap/dvfs/0011-OMAP-Introduce-dependent-voltage-domain-support.patch
blob: 6c4ca2ab97da325be863d4a4a017a930d739f63a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
From b1b41c78d5a19260605fcb259a51ca7cd71c097a Mon Sep 17 00:00:00 2001
From: Thara Gopinath <thara@ti.com>
Date: Fri, 2 Jul 2010 13:06:57 +0530
Subject: [PATCH 11/20] OMAP: Introduce dependent voltage domain support.

There could be dependencies between various voltage domains for
maintaining system performance or hardware limitation reasons
like VDD<X> should be at voltage v1 when VDD<Y> is at voltage v2.
This patch introduce dependent vdd information structures in the
voltage layer which can be used to populate these dependencies
for a voltage domain. This patch also adds support to scale
the dependent vdd and the scalable devices belonging to it
during the scaling of a main vdd through omap_voltage_scale.

Signed-off-by: Thara Gopinath <thara@ti.com>
---
 arch/arm/mach-omap2/voltage.c |  122 +++++++++++++++++++++++++++++++++++++++++
 1 files changed, 122 insertions(+), 0 deletions(-)

diff --git a/arch/arm/mach-omap2/voltage.c b/arch/arm/mach-omap2/voltage.c
index 9adf9d1..c83d968 100644
--- a/arch/arm/mach-omap2/voltage.c
+++ b/arch/arm/mach-omap2/voltage.c
@@ -123,6 +123,36 @@ struct vc_reg_info {
 };
 
 /**
+ * omap_vdd_dep_volt - Table containing the parent vdd voltage and the
+ *			dependent vdd voltage corresponding to it.
+ *
+ * @main_vdd_volt	: The main vdd voltage
+ * @dep_vdd_volt	: The voltage at which the dependent vdd should be
+ *			  when the main vdd is at <main_vdd_volt> voltage
+ */
+struct omap_vdd_dep_volt {
+	u32 main_vdd_volt;
+	u32 dep_vdd_volt;
+};
+
+/**
+ * omap_vdd_dep_info - Dependent vdd info
+ *
+ * @name		: Dependent vdd name
+ * @voltdm		: Dependent vdd pointer
+ * @dep_table		: Table containing the dependent vdd voltage
+ *			  corresponding to every main vdd voltage.
+ * @cur_dep_volt	: The voltage to which dependent vdd should be put
+ *			  to for the current main vdd voltage.
+ */
+struct omap_vdd_dep_info {
+	char *name;
+	struct voltagedomain *voltdm;
+	struct omap_vdd_dep_volt *dep_table;
+	unsigned long cur_dep_volt;
+};
+
+/**
  * struct omap_vdd_user_list - The per vdd user list
  *
  * @dev:	The device asking for the vdd to be set at a particular
@@ -174,11 +204,13 @@ struct omap_vdd_info {
 	struct vp_reg_val vp_reg;
 	struct vc_reg_info vc_reg;
 	struct voltagedomain voltdm;
+	struct omap_vdd_dep_info *dep_vdd_info;
 	struct dentry *debug_dir;
 	spinlock_t user_lock;
 	struct plist_head user_list;
 	struct mutex scaling_mutex;
 	struct list_head dev_list;
+	int nr_dep_vdd;
 	u32 curr_volt;
 	u16 ocp_mod;
 	u8 prm_irqst_reg;
@@ -1160,6 +1192,80 @@ static int __init omap4_vdd_data_configure(struct omap_vdd_info *vdd)
 	return 0;
 }
 
+static int calc_dep_vdd_volt(struct device *dev,
+		struct omap_vdd_info *main_vdd, unsigned long main_volt)
+{
+	struct omap_vdd_dep_info *dep_vdds;
+	int i, ret = 0;
+
+	if (!main_vdd->dep_vdd_info) {
+		pr_debug("%s: No dependent VDD's for vdd_%s\n",
+			__func__, main_vdd->voltdm.name);
+		return 0;
+	}
+
+	dep_vdds = main_vdd->dep_vdd_info;
+
+	for (i = 0; i < main_vdd->nr_dep_vdd; i++) {
+		struct omap_vdd_dep_volt *volt_table = dep_vdds[i].dep_table;
+		int nr_volt = 0;
+		unsigned long dep_volt = 0, act_volt = 0;
+
+		while (volt_table[nr_volt].main_vdd_volt != 0) {
+			if (volt_table[nr_volt].main_vdd_volt == main_volt) {
+				dep_volt = volt_table[nr_volt].dep_vdd_volt;
+				break;
+			}
+			nr_volt++;
+		}
+		if (!dep_volt) {
+			pr_warning("%s: Not able to find a matching volt for"
+				"vdd_%s corresponding to vdd_%s %ld volt\n",
+				__func__, dep_vdds[i].name,
+				main_vdd->voltdm.name, main_volt);
+			ret = -EINVAL;
+			continue;
+		}
+
+		if (!dep_vdds[i].voltdm)
+			dep_vdds[i].voltdm =
+				omap_voltage_domain_lookup(dep_vdds[i].name);
+
+		act_volt = dep_volt;
+
+		/* See if dep_volt is possible for the vdd*/
+		ret = omap_voltage_add_request(dep_vdds[i].voltdm, dev,
+				&act_volt);
+
+		/*
+		 * Currently we do not bother if the dep volt and act volt are
+		 * different. We could add a check if needed.
+		 */
+		dep_vdds[i].cur_dep_volt = act_volt;
+	}
+
+	return ret;
+}
+
+static int scale_dep_vdd(struct omap_vdd_info *main_vdd)
+{
+	struct omap_vdd_dep_info *dep_vdds;
+	int i;
+
+	if (!main_vdd->dep_vdd_info) {
+		pr_debug("%s: No dependent VDD's for vdd_%s\n",
+			__func__, main_vdd->voltdm.name);
+		return 0;
+	}
+
+	dep_vdds = main_vdd->dep_vdd_info;
+
+	for (i = 0; i < main_vdd->nr_dep_vdd; i++)
+		omap_voltage_scale(dep_vdds[i].voltdm,
+				dep_vdds[i].cur_dep_volt);
+	return 0;
+}
+
 /* Public functions */
 /**
  * omap_voltage_get_nom_volt() - Gets the current non-auto-compensated voltage
@@ -1675,6 +1781,8 @@ int omap_voltage_scale(struct voltagedomain *voltdm, unsigned long volt)
 	int is_volt_scaled = 0;
 	struct omap_vdd_info *vdd;
 	struct omap_vdd_dev_list *temp_dev;
+	struct plist_node *node;
+	struct omap_vdd_user_list *user;
 
 	if (!voltdm || IS_ERR(voltdm)) {
 		pr_warning("%s: VDD specified does not exist!\n", __func__);
@@ -1687,6 +1795,17 @@ int omap_voltage_scale(struct voltagedomain *voltdm, unsigned long volt)
 
 	curr_volt = omap_voltage_get_nom_volt(voltdm);
 
+	/* Find the device requesting the voltage scaling */
+	node = plist_first(&vdd->user_list);
+	user = container_of(node, struct omap_vdd_user_list, node);
+
+	/* calculate the voltages for dependent vdd's */
+	if (calc_dep_vdd_volt(user->dev, vdd, volt)) {
+		pr_warning("%s: Error in calculating dependent vdd voltages"
+			"for vdd_%s\n", __func__, voltdm->name);
+		return -EINVAL;
+	}
+
 	if (curr_volt == volt) {
 		is_volt_scaled = 1;
 	} else if (curr_volt < volt) {
@@ -1721,6 +1840,9 @@ int omap_voltage_scale(struct voltagedomain *voltdm, unsigned long volt)
 
 	mutex_unlock(&vdd->scaling_mutex);
 
+	/* Scale dependent vdds */
+	scale_dep_vdd(vdd);
+
 	return 0;
 }
 
-- 
1.6.6.1