Commit 536a4c8bb76e77217216bebd40178fb30ac5422b
1 parent
90cdb1c234
Exists in
master
arm: omap: am33x: Move header files to plat/
dvfs.h is required by omap cpufreq driver that lives in drivers folder, so move it to plat/ directory. Also move voltage.h, vc.h & vp.h similarly to have clean header file inclusions Signed-off-by: Afzal Mohammed <afzal@ti.com>
Showing 31 changed files with 525 additions and 550 deletions Inline Diff
- arch/arm/mach-omap2/dvfs.c
- arch/arm/mach-omap2/dvfs.h
- arch/arm/mach-omap2/io.c
- arch/arm/mach-omap2/omap_opp_data.h
- arch/arm/mach-omap2/omap_twl.c
- arch/arm/mach-omap2/opp.c
- arch/arm/mach-omap2/pm.c
- arch/arm/mach-omap2/powerdomain.h
- arch/arm/mach-omap2/prm2xxx_3xxx.c
- arch/arm/mach-omap2/prm44xx.c
- arch/arm/mach-omap2/smartreflex.h
- arch/arm/mach-omap2/sr_device.c
- arch/arm/mach-omap2/vc.c
- arch/arm/mach-omap2/vc.h
- arch/arm/mach-omap2/vc3xxx_data.c
- arch/arm/mach-omap2/vc44xx_data.c
- arch/arm/mach-omap2/voltage.c
- arch/arm/mach-omap2/voltage.h
- arch/arm/mach-omap2/voltagedomains2xxx_data.c
- arch/arm/mach-omap2/voltagedomains33xx_data.c
- arch/arm/mach-omap2/voltagedomains3xxx_data.c
- arch/arm/mach-omap2/voltagedomains44xx_data.c
- arch/arm/mach-omap2/vp.c
- arch/arm/mach-omap2/vp.h
- arch/arm/mach-omap2/vp3xxx_data.c
- arch/arm/mach-omap2/vp44xx_data.c
- arch/arm/plat-omap/include/plat/dvfs.h
- arch/arm/plat-omap/include/plat/vc.h
- arch/arm/plat-omap/include/plat/voltage.h
- arch/arm/plat-omap/include/plat/vp.h
- drivers/cpufreq/omap-cpufreq.c
arch/arm/mach-omap2/dvfs.c
1 | /* | 1 | /* |
2 | * OMAP3/OMAP4 DVFS Management Routines | 2 | * OMAP3/OMAP4 DVFS Management Routines |
3 | * | 3 | * |
4 | * Author: Vishwanath BS <vishwanath.bs@ti.com> | 4 | * Author: Vishwanath BS <vishwanath.bs@ti.com> |
5 | * | 5 | * |
6 | * Copyright (C) 2011 Texas Instruments, Inc. | 6 | * Copyright (C) 2011 Texas Instruments, Inc. |
7 | * Vishwanath BS <vishwanath.bs@ti.com> | 7 | * Vishwanath BS <vishwanath.bs@ti.com> |
8 | * | 8 | * |
9 | * This program is free software; you can redistribute it and/or modify | 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 | 10 | * it under the terms of the GNU General Public License version 2 as |
11 | * published by the Free Software Foundation. | 11 | * published by the Free Software Foundation. |
12 | */ | 12 | */ |
13 | 13 | ||
14 | #include <linux/err.h> | 14 | #include <linux/err.h> |
15 | #include <linux/spinlock.h> | 15 | #include <linux/spinlock.h> |
16 | #include <linux/plist.h> | 16 | #include <linux/plist.h> |
17 | #include <linux/slab.h> | 17 | #include <linux/slab.h> |
18 | #include <linux/opp.h> | 18 | #include <linux/opp.h> |
19 | #include <linux/clk.h> | 19 | #include <linux/clk.h> |
20 | #include <plat/common.h> | 20 | #include <plat/common.h> |
21 | #include <plat/omap_device.h> | 21 | #include <plat/omap_device.h> |
22 | #include <plat/omap_hwmod.h> | 22 | #include <plat/omap_hwmod.h> |
23 | #include <plat/clock.h> | 23 | #include <plat/clock.h> |
24 | #include "dvfs.h" | 24 | #include <plat/dvfs.h> |
25 | #include "smartreflex.h" | 25 | #include "smartreflex.h" |
26 | #include "powerdomain.h" | 26 | #include "powerdomain.h" |
27 | 27 | ||
28 | /** | 28 | /** |
29 | * DOC: Introduction | 29 | * DOC: Introduction |
30 | * ================= | 30 | * ================= |
31 | * DVFS is a technique that uses the optimal operating frequency and voltage to | 31 | * DVFS is a technique that uses the optimal operating frequency and voltage to |
32 | * allow a task to be performed in the required amount of time. | 32 | * allow a task to be performed in the required amount of time. |
33 | * OMAP processors have voltage domains whose voltage can be scaled to | 33 | * OMAP processors have voltage domains whose voltage can be scaled to |
34 | * various levels depending on which the operating frequencies of certain | 34 | * various levels depending on which the operating frequencies of certain |
35 | * devices belonging to the domain will also need to be scaled. This voltage | 35 | * devices belonging to the domain will also need to be scaled. This voltage |
36 | * frequency tuple is known as Operating Performance Point (OPP). A device | 36 | * frequency tuple is known as Operating Performance Point (OPP). A device |
37 | * can have multiple OPP's. Also a voltage domain could be shared between | 37 | * can have multiple OPP's. Also a voltage domain could be shared between |
38 | * multiple devices. Also there could be dependencies between various | 38 | * multiple devices. Also there could be dependencies between various |
39 | * voltage domains for maintaining system performance like VDD<X> | 39 | * voltage domains for maintaining system performance like VDD<X> |
40 | * should be at voltage v1 when VDD<Y> is at voltage v2. | 40 | * should be at voltage v1 when VDD<Y> is at voltage v2. |
41 | * | 41 | * |
42 | * The design of this framework takes into account all the above mentioned | 42 | * The design of this framework takes into account all the above mentioned |
43 | * points. To summarize the basic design of DVFS framework:- | 43 | * points. To summarize the basic design of DVFS framework:- |
44 | * | 44 | * |
45 | * 1. Have device opp tables for each device whose operating frequency can be | 45 | * 1. Have device opp tables for each device whose operating frequency can be |
46 | * scaled. This is easy now due to the existance of hwmod layer which | 46 | * scaled. This is easy now due to the existance of hwmod layer which |
47 | * allow storing of device specific info. The device opp tables contain | 47 | * allow storing of device specific info. The device opp tables contain |
48 | * the opp pairs (frequency voltage tuples), the voltage domain pointer | 48 | * the opp pairs (frequency voltage tuples), the voltage domain pointer |
49 | * to which the device belongs to, the device specific set_rate and | 49 | * to which the device belongs to, the device specific set_rate and |
50 | * get_rate API's which will do the actual scaling of the device frequency | 50 | * get_rate API's which will do the actual scaling of the device frequency |
51 | * and retrieve the current device frequency. | 51 | * and retrieve the current device frequency. |
52 | * 2. Introduce use counting on a per VDD basis. This is to take care multiple | 52 | * 2. Introduce use counting on a per VDD basis. This is to take care multiple |
53 | * requests to scale a VDD. The VDD will be scaled to the maximum of the | 53 | * requests to scale a VDD. The VDD will be scaled to the maximum of the |
54 | * voltages requested. | 54 | * voltages requested. |
55 | * 3. Keep track of all scalable devices belonging to a particular voltage | 55 | * 3. Keep track of all scalable devices belonging to a particular voltage |
56 | * domain the voltage layer. | 56 | * domain the voltage layer. |
57 | * 4. Keep track of frequency requests for each of the device. This will enable | 57 | * 4. Keep track of frequency requests for each of the device. This will enable |
58 | * to scale individual devices to different frequency (even w/o scaling | 58 | * to scale individual devices to different frequency (even w/o scaling |
59 | * voltage aka frequency throttling) | 59 | * voltage aka frequency throttling) |
60 | * 5. Generic dvfs API that can be called by anybody to scale a device opp. | 60 | * 5. Generic dvfs API that can be called by anybody to scale a device opp. |
61 | * This API takes the device pointer and frequency to which the device | 61 | * This API takes the device pointer and frequency to which the device |
62 | * needs to be scaled to. This API then internally finds out the voltage | 62 | * needs to be scaled to. This API then internally finds out the voltage |
63 | * domain to which the device belongs to and the voltage to which the voltage | 63 | * domain to which the device belongs to and the voltage to which the voltage |
64 | * domain needs to be put to for the device to be scaled to the new frequency | 64 | * domain needs to be put to for the device to be scaled to the new frequency |
65 | * from he device opp table. Then this API will add requested frequency into | 65 | * from he device opp table. Then this API will add requested frequency into |
66 | * the corresponding target device frequency list and add voltage request to | 66 | * the corresponding target device frequency list and add voltage request to |
67 | * the corresponding vdd. Subsequently it calls voltage scale function which | 67 | * the corresponding vdd. Subsequently it calls voltage scale function which |
68 | * will find out the highest requested voltage for the given vdd and scales | 68 | * will find out the highest requested voltage for the given vdd and scales |
69 | * the voltage to the required one. It also runs through the list of all | 69 | * the voltage to the required one. It also runs through the list of all |
70 | * scalable devices belonging to this voltage domain and scale them to the | 70 | * scalable devices belonging to this voltage domain and scale them to the |
71 | * appropriate frequencies using the set_rate pointer in the device opp | 71 | * appropriate frequencies using the set_rate pointer in the device opp |
72 | * tables. | 72 | * tables. |
73 | * 6. Handle inter VDD dependecies. | 73 | * 6. Handle inter VDD dependecies. |
74 | * | 74 | * |
75 | * | 75 | * |
76 | * DOC: The Core DVFS data structure: | 76 | * DOC: The Core DVFS data structure: |
77 | * ================================== | 77 | * ================================== |
78 | * Structure Name Example Tree | 78 | * Structure Name Example Tree |
79 | * --------- | 79 | * --------- |
80 | * /|\ +-------------------+ +-------------------+ | 80 | * /|\ +-------------------+ +-------------------+ |
81 | * | |User2 (dev2, freq2)+---\ |User4 (dev4, freq4)+---\ | 81 | * | |User2 (dev2, freq2)+---\ |User4 (dev4, freq4)+---\ |
82 | * | +-------------------+ | +-------------------+ | | 82 | * | +-------------------+ | +-------------------+ | |
83 | * (struct omap_dev_user_list) | | | 83 | * (struct omap_dev_user_list) | | |
84 | * | +-------------------+ | +-------------------+ | | 84 | * | +-------------------+ | +-------------------+ | |
85 | * | |User1 (dev1, freq1)+---| |User3 (dev3, freq3)+---| | 85 | * | |User1 (dev1, freq1)+---| |User3 (dev3, freq3)+---| |
86 | * \|/ +-------------------+ | +-------------------+ | | 86 | * \|/ +-------------------+ | +-------------------+ | |
87 | * --------- | | | 87 | * --------- | | |
88 | * /|\ +------------+------+ +---------------+--+ | 88 | * /|\ +------------+------+ +---------------+--+ |
89 | * | | DEV1 (dev, | | DEV2 (dev) | | 89 | * | | DEV1 (dev, | | DEV2 (dev) | |
90 | * (struct omap_vdd_dev_list)|omap_dev_user_list)| |omap_dev_user_list| | 90 | * (struct omap_vdd_dev_list)|omap_dev_user_list)| |omap_dev_user_list| |
91 | * | +------------+------+ +--+---------------+ | 91 | * | +------------+------+ +--+---------------+ |
92 | * \|/ /|\ /-----+-------------+------> others.. | 92 | * \|/ /|\ /-----+-------------+------> others.. |
93 | * --------- Frequency | | 93 | * --------- Frequency | |
94 | * /|\ +--+------------------+ | 94 | * /|\ +--+------------------+ |
95 | * | | VDD_n | | 95 | * | | VDD_n | |
96 | * | | (omap_vdd_dev_list, | | 96 | * | | (omap_vdd_dev_list, | |
97 | * (struct omap_vdd_dvfs_info)** | omap_vdd_user_list) | | 97 | * (struct omap_vdd_dvfs_info)** | omap_vdd_user_list) | |
98 | * | +--+------------------+ | 98 | * | +--+------------------+ |
99 | * | | (ROOT NODE: omap_dvfs_info_list) | 99 | * | | (ROOT NODE: omap_dvfs_info_list) |
100 | * \|/ | | 100 | * \|/ | |
101 | * --------- Voltage \---+-------------+----------> others.. | 101 | * --------- Voltage \---+-------------+----------> others.. |
102 | * /|\ \|/ +-------+----+ +-----+--------+ | 102 | * /|\ \|/ +-------+----+ +-----+--------+ |
103 | * | | vdd_user2 | | vdd_user3 | | 103 | * | | vdd_user2 | | vdd_user3 | |
104 | * (struct omap_vdd_user_list) | (dev, volt)| | (dev, volt) | | 104 | * (struct omap_vdd_user_list) | (dev, volt)| | (dev, volt) | |
105 | * \|/ +------------+ +--------------+ | 105 | * \|/ +------------+ +--------------+ |
106 | * --------- | 106 | * --------- |
107 | * Key: ** -> Root of the tree. | 107 | * Key: ** -> Root of the tree. |
108 | * NOTE: we use the priority to store the voltage/frequency | 108 | * NOTE: we use the priority to store the voltage/frequency |
109 | * | 109 | * |
110 | * For voltage dependency description, see: struct dependency: | 110 | * For voltage dependency description, see: struct dependency: |
111 | * voltagedomain -> (description of the voltagedomain) | 111 | * voltagedomain -> (description of the voltagedomain) |
112 | * omap_vdd_info -> (vdd information) | 112 | * omap_vdd_info -> (vdd information) |
113 | * omap_vdd_dep_info[]-> (stores array of depedency info) | 113 | * omap_vdd_dep_info[]-> (stores array of depedency info) |
114 | * omap_vdd_dep_volt[] -> (stores array of maps) | 114 | * omap_vdd_dep_volt[] -> (stores array of maps) |
115 | * (main_volt -> dep_volt) (a singular map) | 115 | * (main_volt -> dep_volt) (a singular map) |
116 | */ | 116 | */ |
117 | 117 | ||
118 | /* Macros to give idea about scaling directions */ | 118 | /* Macros to give idea about scaling directions */ |
119 | #define DVFS_VOLT_SCALE_DOWN 0 | 119 | #define DVFS_VOLT_SCALE_DOWN 0 |
120 | #define DVFS_VOLT_SCALE_NONE 1 | 120 | #define DVFS_VOLT_SCALE_NONE 1 |
121 | #define DVFS_VOLT_SCALE_UP 2 | 121 | #define DVFS_VOLT_SCALE_UP 2 |
122 | 122 | ||
123 | /** | 123 | /** |
124 | * struct omap_dev_user_list - Structure maitain userlist per devide | 124 | * struct omap_dev_user_list - Structure maitain userlist per devide |
125 | * @dev: The device requesting for a particular frequency | 125 | * @dev: The device requesting for a particular frequency |
126 | * @node: The list head entry | 126 | * @node: The list head entry |
127 | * | 127 | * |
128 | * Using this structure, user list (requesting dev * and frequency) for | 128 | * Using this structure, user list (requesting dev * and frequency) for |
129 | * each device is maintained. This is how we can have different devices | 129 | * each device is maintained. This is how we can have different devices |
130 | * at different frequencies (to support frequency locking and throttling). | 130 | * at different frequencies (to support frequency locking and throttling). |
131 | * Even if one of the devices in a given vdd has locked it's frequency, | 131 | * Even if one of the devices in a given vdd has locked it's frequency, |
132 | * other's can still scale their frequency using this list. | 132 | * other's can still scale their frequency using this list. |
133 | * If no one has placed a frequency request for a device, then device is | 133 | * If no one has placed a frequency request for a device, then device is |
134 | * set to the frequency from it's opp table. | 134 | * set to the frequency from it's opp table. |
135 | */ | 135 | */ |
136 | struct omap_dev_user_list { | 136 | struct omap_dev_user_list { |
137 | struct device *dev; | 137 | struct device *dev; |
138 | struct plist_node node; | 138 | struct plist_node node; |
139 | }; | 139 | }; |
140 | 140 | ||
141 | /** | 141 | /** |
142 | * struct omap_vdd_dev_list - Device list per vdd | 142 | * struct omap_vdd_dev_list - Device list per vdd |
143 | * @dev: The device belonging to a particular vdd | 143 | * @dev: The device belonging to a particular vdd |
144 | * @node: The list head entry | 144 | * @node: The list head entry |
145 | * @freq_user_list: The list of users for vdd device | 145 | * @freq_user_list: The list of users for vdd device |
146 | * @clk: frequency control clock for this dev | 146 | * @clk: frequency control clock for this dev |
147 | * @user_lock: The lock for plist manipulation | 147 | * @user_lock: The lock for plist manipulation |
148 | */ | 148 | */ |
149 | struct omap_vdd_dev_list { | 149 | struct omap_vdd_dev_list { |
150 | struct device *dev; | 150 | struct device *dev; |
151 | struct list_head node; | 151 | struct list_head node; |
152 | struct plist_head freq_user_list; | 152 | struct plist_head freq_user_list; |
153 | struct clk *clk; | 153 | struct clk *clk; |
154 | spinlock_t user_lock; /* spinlock for plist */ | 154 | spinlock_t user_lock; /* spinlock for plist */ |
155 | }; | 155 | }; |
156 | 156 | ||
157 | /** | 157 | /** |
158 | * struct omap_vdd_user_list - The per vdd user list | 158 | * struct omap_vdd_user_list - The per vdd user list |
159 | * @dev: The device asking for the vdd to be set at a particular | 159 | * @dev: The device asking for the vdd to be set at a particular |
160 | * voltage | 160 | * voltage |
161 | * @node: The list head entry | 161 | * @node: The list head entry |
162 | */ | 162 | */ |
163 | struct omap_vdd_user_list { | 163 | struct omap_vdd_user_list { |
164 | struct device *dev; | 164 | struct device *dev; |
165 | struct plist_node node; | 165 | struct plist_node node; |
166 | }; | 166 | }; |
167 | 167 | ||
168 | /** | 168 | /** |
169 | * struct omap_vdd_dvfs_info - The per vdd dvfs info | 169 | * struct omap_vdd_dvfs_info - The per vdd dvfs info |
170 | * @node: list node for vdd_dvfs_info list | 170 | * @node: list node for vdd_dvfs_info list |
171 | * @user_lock: spinlock for plist operations | 171 | * @user_lock: spinlock for plist operations |
172 | * @vdd_user_list: The vdd user list | 172 | * @vdd_user_list: The vdd user list |
173 | * @voltdm: Voltage domains for which dvfs info stored | 173 | * @voltdm: Voltage domains for which dvfs info stored |
174 | * @dev_list: Device list maintained per domain | 174 | * @dev_list: Device list maintained per domain |
175 | * | 175 | * |
176 | * This is a fundamental structure used to store all the required | 176 | * This is a fundamental structure used to store all the required |
177 | * DVFS related information for a vdd. | 177 | * DVFS related information for a vdd. |
178 | */ | 178 | */ |
179 | struct omap_vdd_dvfs_info { | 179 | struct omap_vdd_dvfs_info { |
180 | struct list_head node; | 180 | struct list_head node; |
181 | 181 | ||
182 | spinlock_t user_lock; /* spin lock */ | 182 | spinlock_t user_lock; /* spin lock */ |
183 | struct plist_head vdd_user_list; | 183 | struct plist_head vdd_user_list; |
184 | struct voltagedomain *voltdm; | 184 | struct voltagedomain *voltdm; |
185 | struct list_head dev_list; | 185 | struct list_head dev_list; |
186 | }; | 186 | }; |
187 | 187 | ||
188 | static LIST_HEAD(omap_dvfs_info_list); | 188 | static LIST_HEAD(omap_dvfs_info_list); |
189 | static DEFINE_MUTEX(omap_dvfs_lock); | 189 | static DEFINE_MUTEX(omap_dvfs_lock); |
190 | 190 | ||
191 | /* Dvfs scale helper function */ | 191 | /* Dvfs scale helper function */ |
192 | static int _dvfs_scale(struct device *req_dev, struct device *target_dev, | 192 | static int _dvfs_scale(struct device *req_dev, struct device *target_dev, |
193 | struct omap_vdd_dvfs_info *tdvfs_info); | 193 | struct omap_vdd_dvfs_info *tdvfs_info); |
194 | 194 | ||
195 | /* Few search functions to traverse and find pointers of interest */ | 195 | /* Few search functions to traverse and find pointers of interest */ |
196 | 196 | ||
197 | /** | 197 | /** |
198 | * _dvfs_info_to_dev() - Locate the parent device associated to dvfs_info | 198 | * _dvfs_info_to_dev() - Locate the parent device associated to dvfs_info |
199 | * @dvfs_info: dvfs_info to search for | 199 | * @dvfs_info: dvfs_info to search for |
200 | * | 200 | * |
201 | * Returns NULL on failure. | 201 | * Returns NULL on failure. |
202 | */ | 202 | */ |
203 | static struct device *_dvfs_info_to_dev(struct omap_vdd_dvfs_info *dvfs_info) | 203 | static struct device *_dvfs_info_to_dev(struct omap_vdd_dvfs_info *dvfs_info) |
204 | { | 204 | { |
205 | struct omap_vdd_dev_list *tmp_dev; | 205 | struct omap_vdd_dev_list *tmp_dev; |
206 | if (IS_ERR_OR_NULL(dvfs_info)) | 206 | if (IS_ERR_OR_NULL(dvfs_info)) |
207 | return NULL; | 207 | return NULL; |
208 | if (list_empty(&dvfs_info->dev_list)) | 208 | if (list_empty(&dvfs_info->dev_list)) |
209 | return NULL; | 209 | return NULL; |
210 | tmp_dev = list_first_entry(&dvfs_info->dev_list, | 210 | tmp_dev = list_first_entry(&dvfs_info->dev_list, |
211 | struct omap_vdd_dev_list, node); | 211 | struct omap_vdd_dev_list, node); |
212 | return tmp_dev->dev; | 212 | return tmp_dev->dev; |
213 | } | 213 | } |
214 | 214 | ||
215 | /** | 215 | /** |
216 | * _dev_to_dvfs_info() - Locate the dvfs_info for a device | 216 | * _dev_to_dvfs_info() - Locate the dvfs_info for a device |
217 | * @dev: dev to search for | 217 | * @dev: dev to search for |
218 | * | 218 | * |
219 | * Returns NULL on failure. | 219 | * Returns NULL on failure. |
220 | */ | 220 | */ |
221 | static struct omap_vdd_dvfs_info *_dev_to_dvfs_info(struct device *dev) | 221 | static struct omap_vdd_dvfs_info *_dev_to_dvfs_info(struct device *dev) |
222 | { | 222 | { |
223 | struct omap_vdd_dvfs_info *dvfs_info; | 223 | struct omap_vdd_dvfs_info *dvfs_info; |
224 | struct omap_vdd_dev_list *temp_dev; | 224 | struct omap_vdd_dev_list *temp_dev; |
225 | 225 | ||
226 | if (IS_ERR_OR_NULL(dev)) | 226 | if (IS_ERR_OR_NULL(dev)) |
227 | return NULL; | 227 | return NULL; |
228 | 228 | ||
229 | list_for_each_entry(dvfs_info, &omap_dvfs_info_list, node) { | 229 | list_for_each_entry(dvfs_info, &omap_dvfs_info_list, node) { |
230 | list_for_each_entry(temp_dev, &dvfs_info->dev_list, node) { | 230 | list_for_each_entry(temp_dev, &dvfs_info->dev_list, node) { |
231 | if (temp_dev->dev == dev) | 231 | if (temp_dev->dev == dev) |
232 | return dvfs_info; | 232 | return dvfs_info; |
233 | } | 233 | } |
234 | } | 234 | } |
235 | 235 | ||
236 | return NULL; | 236 | return NULL; |
237 | } | 237 | } |
238 | 238 | ||
239 | /** | 239 | /** |
240 | * _voltdm_to_dvfs_info() - Locate a dvfs_info given a voltdm pointer | 240 | * _voltdm_to_dvfs_info() - Locate a dvfs_info given a voltdm pointer |
241 | * @voltdm: voltdm to search for | 241 | * @voltdm: voltdm to search for |
242 | * | 242 | * |
243 | * Returns NULL on failure. | 243 | * Returns NULL on failure. |
244 | */ | 244 | */ |
245 | static | 245 | static |
246 | struct omap_vdd_dvfs_info *_voltdm_to_dvfs_info(struct voltagedomain *voltdm) | 246 | struct omap_vdd_dvfs_info *_voltdm_to_dvfs_info(struct voltagedomain *voltdm) |
247 | { | 247 | { |
248 | struct omap_vdd_dvfs_info *dvfs_info; | 248 | struct omap_vdd_dvfs_info *dvfs_info; |
249 | 249 | ||
250 | if (IS_ERR_OR_NULL(voltdm)) | 250 | if (IS_ERR_OR_NULL(voltdm)) |
251 | return NULL; | 251 | return NULL; |
252 | 252 | ||
253 | list_for_each_entry(dvfs_info, &omap_dvfs_info_list, node) { | 253 | list_for_each_entry(dvfs_info, &omap_dvfs_info_list, node) { |
254 | if (dvfs_info->voltdm == voltdm) | 254 | if (dvfs_info->voltdm == voltdm) |
255 | return dvfs_info; | 255 | return dvfs_info; |
256 | } | 256 | } |
257 | 257 | ||
258 | return NULL; | 258 | return NULL; |
259 | } | 259 | } |
260 | 260 | ||
261 | /** | 261 | /** |
262 | * _volt_to_opp() - Find OPP corresponding to a given voltage | 262 | * _volt_to_opp() - Find OPP corresponding to a given voltage |
263 | * @dev: device pointer associated with the OPP list | 263 | * @dev: device pointer associated with the OPP list |
264 | * @volt: voltage to search for in uV | 264 | * @volt: voltage to search for in uV |
265 | * | 265 | * |
266 | * Searches for exact match in the OPP list and returns handle to the matching | 266 | * Searches for exact match in the OPP list and returns handle to the matching |
267 | * OPP if found, else returns ERR_PTR in case of error and should be handled | 267 | * OPP if found, else returns ERR_PTR in case of error and should be handled |
268 | * using IS_ERR. If there are multiple opps with same voltage, it will return | 268 | * using IS_ERR. If there are multiple opps with same voltage, it will return |
269 | * the first available entry. Return pointer should be checked against IS_ERR. | 269 | * the first available entry. Return pointer should be checked against IS_ERR. |
270 | * | 270 | * |
271 | * NOTE: since this uses OPP functions, use under rcu_lock. This function also | 271 | * NOTE: since this uses OPP functions, use under rcu_lock. This function also |
272 | * assumes that the cpufreq table and OPP table are in sync - any modifications | 272 | * assumes that the cpufreq table and OPP table are in sync - any modifications |
273 | * to either should be synchronized. | 273 | * to either should be synchronized. |
274 | */ | 274 | */ |
275 | static struct opp *_volt_to_opp(struct device *dev, unsigned long volt) | 275 | static struct opp *_volt_to_opp(struct device *dev, unsigned long volt) |
276 | { | 276 | { |
277 | struct opp *opp = ERR_PTR(-ENODEV); | 277 | struct opp *opp = ERR_PTR(-ENODEV); |
278 | unsigned long f = 0; | 278 | unsigned long f = 0; |
279 | 279 | ||
280 | do { | 280 | do { |
281 | opp = opp_find_freq_ceil(dev, &f); | 281 | opp = opp_find_freq_ceil(dev, &f); |
282 | if (IS_ERR(opp)) | 282 | if (IS_ERR(opp)) |
283 | break; | 283 | break; |
284 | if (opp_get_voltage(opp) >= volt) | 284 | if (opp_get_voltage(opp) >= volt) |
285 | break; | 285 | break; |
286 | f++; | 286 | f++; |
287 | } while (1); | 287 | } while (1); |
288 | 288 | ||
289 | return opp; | 289 | return opp; |
290 | } | 290 | } |
291 | 291 | ||
292 | /* rest of the helper functions */ | 292 | /* rest of the helper functions */ |
293 | /** | 293 | /** |
294 | * _add_vdd_user() - Add a voltage request | 294 | * _add_vdd_user() - Add a voltage request |
295 | * @dvfs_info: omap_vdd_dvfs_info pointer for the required vdd | 295 | * @dvfs_info: omap_vdd_dvfs_info pointer for the required vdd |
296 | * @dev: device making the request | 296 | * @dev: device making the request |
297 | * @volt: requested voltage in uV | 297 | * @volt: requested voltage in uV |
298 | * | 298 | * |
299 | * Adds the given device's voltage request into corresponding | 299 | * Adds the given device's voltage request into corresponding |
300 | * vdd's omap_vdd_dvfs_info user list (plist). This list is used | 300 | * vdd's omap_vdd_dvfs_info user list (plist). This list is used |
301 | * to find the maximum voltage request for a given vdd. | 301 | * to find the maximum voltage request for a given vdd. |
302 | * | 302 | * |
303 | * Returns 0 on success. | 303 | * Returns 0 on success. |
304 | */ | 304 | */ |
305 | static int _add_vdd_user(struct omap_vdd_dvfs_info *dvfs_info, | 305 | static int _add_vdd_user(struct omap_vdd_dvfs_info *dvfs_info, |
306 | struct device *dev, unsigned long volt) | 306 | struct device *dev, unsigned long volt) |
307 | { | 307 | { |
308 | struct omap_vdd_user_list *user = NULL, *temp_user; | 308 | struct omap_vdd_user_list *user = NULL, *temp_user; |
309 | 309 | ||
310 | if (!dvfs_info || IS_ERR(dvfs_info)) { | 310 | if (!dvfs_info || IS_ERR(dvfs_info)) { |
311 | dev_warn(dev, "%s: VDD specified does not exist!\n", __func__); | 311 | dev_warn(dev, "%s: VDD specified does not exist!\n", __func__); |
312 | return -EINVAL; | 312 | return -EINVAL; |
313 | } | 313 | } |
314 | 314 | ||
315 | spin_lock(&dvfs_info->user_lock); | 315 | spin_lock(&dvfs_info->user_lock); |
316 | plist_for_each_entry(temp_user, &dvfs_info->vdd_user_list, node) { | 316 | plist_for_each_entry(temp_user, &dvfs_info->vdd_user_list, node) { |
317 | if (temp_user->dev == dev) { | 317 | if (temp_user->dev == dev) { |
318 | user = temp_user; | 318 | user = temp_user; |
319 | break; | 319 | break; |
320 | } | 320 | } |
321 | } | 321 | } |
322 | 322 | ||
323 | if (!user) { | 323 | if (!user) { |
324 | user = kzalloc(sizeof(struct omap_vdd_user_list), GFP_ATOMIC); | 324 | user = kzalloc(sizeof(struct omap_vdd_user_list), GFP_ATOMIC); |
325 | if (!user) { | 325 | if (!user) { |
326 | dev_err(dev, | 326 | dev_err(dev, |
327 | "%s: Unable to creat a new user for vdd_%s\n", | 327 | "%s: Unable to creat a new user for vdd_%s\n", |
328 | __func__, dvfs_info->voltdm->name); | 328 | __func__, dvfs_info->voltdm->name); |
329 | spin_unlock(&dvfs_info->user_lock); | 329 | spin_unlock(&dvfs_info->user_lock); |
330 | return -ENOMEM; | 330 | return -ENOMEM; |
331 | } | 331 | } |
332 | user->dev = dev; | 332 | user->dev = dev; |
333 | } else { | 333 | } else { |
334 | plist_del(&user->node, &dvfs_info->vdd_user_list); | 334 | plist_del(&user->node, &dvfs_info->vdd_user_list); |
335 | } | 335 | } |
336 | 336 | ||
337 | plist_node_init(&user->node, volt); | 337 | plist_node_init(&user->node, volt); |
338 | plist_add(&user->node, &dvfs_info->vdd_user_list); | 338 | plist_add(&user->node, &dvfs_info->vdd_user_list); |
339 | 339 | ||
340 | spin_unlock(&dvfs_info->user_lock); | 340 | spin_unlock(&dvfs_info->user_lock); |
341 | return 0; | 341 | return 0; |
342 | } | 342 | } |
343 | 343 | ||
344 | /** | 344 | /** |
345 | * _remove_vdd_user() - Remove a voltage request | 345 | * _remove_vdd_user() - Remove a voltage request |
346 | * @dvfs_info: omap_vdd_dvfs_info pointer for the required vdd | 346 | * @dvfs_info: omap_vdd_dvfs_info pointer for the required vdd |
347 | * @dev: device making the request | 347 | * @dev: device making the request |
348 | * | 348 | * |
349 | * Removes the given device's voltage request from corresponding | 349 | * Removes the given device's voltage request from corresponding |
350 | * vdd's omap_vdd_dvfs_info user list (plist). | 350 | * vdd's omap_vdd_dvfs_info user list (plist). |
351 | * | 351 | * |
352 | * Returns 0 on success. | 352 | * Returns 0 on success. |
353 | */ | 353 | */ |
354 | static int _remove_vdd_user(struct omap_vdd_dvfs_info *dvfs_info, | 354 | static int _remove_vdd_user(struct omap_vdd_dvfs_info *dvfs_info, |
355 | struct device *dev) | 355 | struct device *dev) |
356 | { | 356 | { |
357 | struct omap_vdd_user_list *user = NULL, *temp_user; | 357 | struct omap_vdd_user_list *user = NULL, *temp_user; |
358 | int ret = 0; | 358 | int ret = 0; |
359 | 359 | ||
360 | if (!dvfs_info || IS_ERR(dvfs_info)) { | 360 | if (!dvfs_info || IS_ERR(dvfs_info)) { |
361 | dev_err(dev, "%s: VDD specified does not exist!\n", __func__); | 361 | dev_err(dev, "%s: VDD specified does not exist!\n", __func__); |
362 | return -EINVAL; | 362 | return -EINVAL; |
363 | } | 363 | } |
364 | 364 | ||
365 | spin_lock(&dvfs_info->user_lock); | 365 | spin_lock(&dvfs_info->user_lock); |
366 | plist_for_each_entry(temp_user, &dvfs_info->vdd_user_list, node) { | 366 | plist_for_each_entry(temp_user, &dvfs_info->vdd_user_list, node) { |
367 | if (temp_user->dev == dev) { | 367 | if (temp_user->dev == dev) { |
368 | user = temp_user; | 368 | user = temp_user; |
369 | break; | 369 | break; |
370 | } | 370 | } |
371 | } | 371 | } |
372 | 372 | ||
373 | if (user) | 373 | if (user) |
374 | plist_del(&user->node, &dvfs_info->vdd_user_list); | 374 | plist_del(&user->node, &dvfs_info->vdd_user_list); |
375 | else { | 375 | else { |
376 | dev_err(dev, "%s: Unable to find the user for vdd_%s\n", | 376 | dev_err(dev, "%s: Unable to find the user for vdd_%s\n", |
377 | __func__, dvfs_info->voltdm->name); | 377 | __func__, dvfs_info->voltdm->name); |
378 | ret = -ENOENT; | 378 | ret = -ENOENT; |
379 | } | 379 | } |
380 | 380 | ||
381 | spin_unlock(&dvfs_info->user_lock); | 381 | spin_unlock(&dvfs_info->user_lock); |
382 | kfree(user); | 382 | kfree(user); |
383 | 383 | ||
384 | return ret; | 384 | return ret; |
385 | } | 385 | } |
386 | 386 | ||
387 | /** | 387 | /** |
388 | * _add_freq_request() - Add a requested device frequency | 388 | * _add_freq_request() - Add a requested device frequency |
389 | * @dvfs_info: omap_vdd_dvfs_info pointer for the required vdd | 389 | * @dvfs_info: omap_vdd_dvfs_info pointer for the required vdd |
390 | * @req_dev: device making the request | 390 | * @req_dev: device making the request |
391 | * @target_dev: target device for which frequency request is being made | 391 | * @target_dev: target device for which frequency request is being made |
392 | * @freq: target device frequency | 392 | * @freq: target device frequency |
393 | * | 393 | * |
394 | * This adds a requested frequency into target device's frequency list. | 394 | * This adds a requested frequency into target device's frequency list. |
395 | * | 395 | * |
396 | * Returns 0 on success. | 396 | * Returns 0 on success. |
397 | */ | 397 | */ |
398 | static int _add_freq_request(struct omap_vdd_dvfs_info *dvfs_info, | 398 | static int _add_freq_request(struct omap_vdd_dvfs_info *dvfs_info, |
399 | struct device *req_dev, struct device *target_dev, unsigned long freq) | 399 | struct device *req_dev, struct device *target_dev, unsigned long freq) |
400 | { | 400 | { |
401 | struct omap_dev_user_list *dev_user = NULL, *tmp_user; | 401 | struct omap_dev_user_list *dev_user = NULL, *tmp_user; |
402 | struct omap_vdd_dev_list *temp_dev; | 402 | struct omap_vdd_dev_list *temp_dev; |
403 | 403 | ||
404 | if (!dvfs_info || IS_ERR(dvfs_info)) { | 404 | if (!dvfs_info || IS_ERR(dvfs_info)) { |
405 | dev_warn(target_dev, "%s: VDD specified does not exist!\n", | 405 | dev_warn(target_dev, "%s: VDD specified does not exist!\n", |
406 | __func__); | 406 | __func__); |
407 | return -EINVAL; | 407 | return -EINVAL; |
408 | } | 408 | } |
409 | 409 | ||
410 | list_for_each_entry(temp_dev, &dvfs_info->dev_list, node) { | 410 | list_for_each_entry(temp_dev, &dvfs_info->dev_list, node) { |
411 | if (temp_dev->dev == target_dev) | 411 | if (temp_dev->dev == target_dev) |
412 | break; | 412 | break; |
413 | } | 413 | } |
414 | 414 | ||
415 | if (temp_dev->dev != target_dev) { | 415 | if (temp_dev->dev != target_dev) { |
416 | dev_warn(target_dev, "%s: target_dev does not exist!\n", | 416 | dev_warn(target_dev, "%s: target_dev does not exist!\n", |
417 | __func__); | 417 | __func__); |
418 | return -EINVAL; | 418 | return -EINVAL; |
419 | } | 419 | } |
420 | 420 | ||
421 | spin_lock(&temp_dev->user_lock); | 421 | spin_lock(&temp_dev->user_lock); |
422 | plist_for_each_entry(tmp_user, &temp_dev->freq_user_list, node) { | 422 | plist_for_each_entry(tmp_user, &temp_dev->freq_user_list, node) { |
423 | if (tmp_user->dev == req_dev) { | 423 | if (tmp_user->dev == req_dev) { |
424 | dev_user = tmp_user; | 424 | dev_user = tmp_user; |
425 | break; | 425 | break; |
426 | } | 426 | } |
427 | } | 427 | } |
428 | 428 | ||
429 | if (!dev_user) { | 429 | if (!dev_user) { |
430 | dev_user = kzalloc(sizeof(struct omap_dev_user_list), | 430 | dev_user = kzalloc(sizeof(struct omap_dev_user_list), |
431 | GFP_ATOMIC); | 431 | GFP_ATOMIC); |
432 | if (!dev_user) { | 432 | if (!dev_user) { |
433 | dev_err(target_dev, | 433 | dev_err(target_dev, |
434 | "%s: Unable to creat a new user for vdd_%s\n", | 434 | "%s: Unable to creat a new user for vdd_%s\n", |
435 | __func__, dvfs_info->voltdm->name); | 435 | __func__, dvfs_info->voltdm->name); |
436 | spin_unlock(&temp_dev->user_lock); | 436 | spin_unlock(&temp_dev->user_lock); |
437 | return -ENOMEM; | 437 | return -ENOMEM; |
438 | } | 438 | } |
439 | dev_user->dev = req_dev; | 439 | dev_user->dev = req_dev; |
440 | } else { | 440 | } else { |
441 | plist_del(&dev_user->node, &temp_dev->freq_user_list); | 441 | plist_del(&dev_user->node, &temp_dev->freq_user_list); |
442 | } | 442 | } |
443 | 443 | ||
444 | plist_node_init(&dev_user->node, freq); | 444 | plist_node_init(&dev_user->node, freq); |
445 | plist_add(&dev_user->node, &temp_dev->freq_user_list); | 445 | plist_add(&dev_user->node, &temp_dev->freq_user_list); |
446 | spin_unlock(&temp_dev->user_lock); | 446 | spin_unlock(&temp_dev->user_lock); |
447 | return 0; | 447 | return 0; |
448 | } | 448 | } |
449 | 449 | ||
450 | /** | 450 | /** |
451 | * _remove_freq_request() - Remove the requested device frequency | 451 | * _remove_freq_request() - Remove the requested device frequency |
452 | * | 452 | * |
453 | * @dvfs_info: omap_vdd_dvfs_info pointer for the required vdd | 453 | * @dvfs_info: omap_vdd_dvfs_info pointer for the required vdd |
454 | * @req_dev: device removing the request | 454 | * @req_dev: device removing the request |
455 | * @target_dev: target device from which frequency request is being removed | 455 | * @target_dev: target device from which frequency request is being removed |
456 | * | 456 | * |
457 | * This removes a requested frequency from target device's frequency list. | 457 | * This removes a requested frequency from target device's frequency list. |
458 | * | 458 | * |
459 | * Returns 0 on success. | 459 | * Returns 0 on success. |
460 | */ | 460 | */ |
461 | static int _remove_freq_request(struct omap_vdd_dvfs_info *dvfs_info, | 461 | static int _remove_freq_request(struct omap_vdd_dvfs_info *dvfs_info, |
462 | struct device *req_dev, struct device *target_dev) | 462 | struct device *req_dev, struct device *target_dev) |
463 | { | 463 | { |
464 | struct omap_dev_user_list *dev_user = NULL, *tmp_user; | 464 | struct omap_dev_user_list *dev_user = NULL, *tmp_user; |
465 | int ret = 0; | 465 | int ret = 0; |
466 | struct omap_vdd_dev_list *temp_dev; | 466 | struct omap_vdd_dev_list *temp_dev; |
467 | 467 | ||
468 | if (!dvfs_info || IS_ERR(dvfs_info)) { | 468 | if (!dvfs_info || IS_ERR(dvfs_info)) { |
469 | dev_warn(target_dev, "%s: VDD specified does not exist!\n", | 469 | dev_warn(target_dev, "%s: VDD specified does not exist!\n", |
470 | __func__); | 470 | __func__); |
471 | return -EINVAL; | 471 | return -EINVAL; |
472 | } | 472 | } |
473 | 473 | ||
474 | 474 | ||
475 | list_for_each_entry(temp_dev, &dvfs_info->dev_list, node) { | 475 | list_for_each_entry(temp_dev, &dvfs_info->dev_list, node) { |
476 | if (temp_dev->dev == target_dev) | 476 | if (temp_dev->dev == target_dev) |
477 | break; | 477 | break; |
478 | } | 478 | } |
479 | 479 | ||
480 | if (temp_dev->dev != target_dev) { | 480 | if (temp_dev->dev != target_dev) { |
481 | dev_warn(target_dev, "%s: target_dev does not exist!\n", | 481 | dev_warn(target_dev, "%s: target_dev does not exist!\n", |
482 | __func__); | 482 | __func__); |
483 | return -EINVAL; | 483 | return -EINVAL; |
484 | } | 484 | } |
485 | 485 | ||
486 | spin_lock(&temp_dev->user_lock); | 486 | spin_lock(&temp_dev->user_lock); |
487 | plist_for_each_entry(tmp_user, &temp_dev->freq_user_list, node) { | 487 | plist_for_each_entry(tmp_user, &temp_dev->freq_user_list, node) { |
488 | if (tmp_user->dev == req_dev) { | 488 | if (tmp_user->dev == req_dev) { |
489 | dev_user = tmp_user; | 489 | dev_user = tmp_user; |
490 | break; | 490 | break; |
491 | } | 491 | } |
492 | } | 492 | } |
493 | 493 | ||
494 | if (dev_user) { | 494 | if (dev_user) { |
495 | plist_del(&dev_user->node, &temp_dev->freq_user_list); | 495 | plist_del(&dev_user->node, &temp_dev->freq_user_list); |
496 | } else { | 496 | } else { |
497 | dev_err(target_dev, | 497 | dev_err(target_dev, |
498 | "%s: Unable to remove the user for vdd_%s\n", | 498 | "%s: Unable to remove the user for vdd_%s\n", |
499 | __func__, dvfs_info->voltdm->name); | 499 | __func__, dvfs_info->voltdm->name); |
500 | ret = -EINVAL; | 500 | ret = -EINVAL; |
501 | } | 501 | } |
502 | 502 | ||
503 | spin_unlock(&temp_dev->user_lock); | 503 | spin_unlock(&temp_dev->user_lock); |
504 | kfree(dev_user); | 504 | kfree(dev_user); |
505 | 505 | ||
506 | return ret; | 506 | return ret; |
507 | } | 507 | } |
508 | 508 | ||
509 | /** | 509 | /** |
510 | * _dep_scan_table() - Scan a dependency table and mark for scaling | 510 | * _dep_scan_table() - Scan a dependency table and mark for scaling |
511 | * @dev: device requesting the dependency scan (req_dev) | 511 | * @dev: device requesting the dependency scan (req_dev) |
512 | * @dep_info: dependency information (contains the table) | 512 | * @dep_info: dependency information (contains the table) |
513 | * @main_volt: voltage dependency to search for | 513 | * @main_volt: voltage dependency to search for |
514 | * | 514 | * |
515 | * This runs down the table provided to find the match for main_volt | 515 | * This runs down the table provided to find the match for main_volt |
516 | * provided and sets up a scale request for the dependent domain | 516 | * provided and sets up a scale request for the dependent domain |
517 | * for the dependent voltage. | 517 | * for the dependent voltage. |
518 | * | 518 | * |
519 | * Returns 0 if all went well. | 519 | * Returns 0 if all went well. |
520 | */ | 520 | */ |
521 | static int _dep_scan_table(struct device *dev, | 521 | static int _dep_scan_table(struct device *dev, |
522 | struct omap_vdd_dep_info *dep_info, unsigned long main_volt) | 522 | struct omap_vdd_dep_info *dep_info, unsigned long main_volt) |
523 | { | 523 | { |
524 | struct omap_vdd_dep_volt *dep_table = dep_info->dep_table; | 524 | struct omap_vdd_dep_volt *dep_table = dep_info->dep_table; |
525 | int i; | 525 | int i; |
526 | unsigned long dep_volt = 0; | 526 | unsigned long dep_volt = 0; |
527 | 527 | ||
528 | if (!dep_table) { | 528 | if (!dep_table) { |
529 | dev_err(dev, "%s: deptable not present for vdd%s\n", | 529 | dev_err(dev, "%s: deptable not present for vdd%s\n", |
530 | __func__, dep_info->name); | 530 | __func__, dep_info->name); |
531 | return -EINVAL; | 531 | return -EINVAL; |
532 | } | 532 | } |
533 | 533 | ||
534 | /* Now scan through the the dep table for a match */ | 534 | /* Now scan through the the dep table for a match */ |
535 | for (i = 0; i < dep_info->nr_dep_entries; i++) { | 535 | for (i = 0; i < dep_info->nr_dep_entries; i++) { |
536 | if (dep_table[i].main_vdd_volt == main_volt) { | 536 | if (dep_table[i].main_vdd_volt == main_volt) { |
537 | dep_volt = dep_table[i].dep_vdd_volt; | 537 | dep_volt = dep_table[i].dep_vdd_volt; |
538 | break; | 538 | break; |
539 | } | 539 | } |
540 | } | 540 | } |
541 | if (!dep_volt) { | 541 | if (!dep_volt) { |
542 | dev_warn(dev, "%s: %ld volt map missing in vdd_%s\n", | 542 | dev_warn(dev, "%s: %ld volt map missing in vdd_%s\n", |
543 | __func__, main_volt, dep_info->name); | 543 | __func__, main_volt, dep_info->name); |
544 | return -EINVAL; | 544 | return -EINVAL; |
545 | } | 545 | } |
546 | 546 | ||
547 | /* populate voltdm if it is not present */ | 547 | /* populate voltdm if it is not present */ |
548 | if (!dep_info->_dep_voltdm) { | 548 | if (!dep_info->_dep_voltdm) { |
549 | dep_info->_dep_voltdm = voltdm_lookup(dep_info->name); | 549 | dep_info->_dep_voltdm = voltdm_lookup(dep_info->name); |
550 | if (!dep_info->_dep_voltdm) { | 550 | if (!dep_info->_dep_voltdm) { |
551 | dev_warn(dev, "%s: unable to get vdm%s\n", | 551 | dev_warn(dev, "%s: unable to get vdm%s\n", |
552 | __func__, dep_info->name); | 552 | __func__, dep_info->name); |
553 | return -ENODEV; | 553 | return -ENODEV; |
554 | } | 554 | } |
555 | } | 555 | } |
556 | 556 | ||
557 | /* See if dep_volt is possible for the vdd*/ | 557 | /* See if dep_volt is possible for the vdd*/ |
558 | i = _add_vdd_user(_voltdm_to_dvfs_info(dep_info->_dep_voltdm), | 558 | i = _add_vdd_user(_voltdm_to_dvfs_info(dep_info->_dep_voltdm), |
559 | dev, dep_volt); | 559 | dev, dep_volt); |
560 | if (i) | 560 | if (i) |
561 | dev_err(dev, "%s: Failed to add dep to domain %s volt=%ld\n", | 561 | dev_err(dev, "%s: Failed to add dep to domain %s volt=%ld\n", |
562 | __func__, dep_info->name, dep_volt); | 562 | __func__, dep_info->name, dep_volt); |
563 | return i; | 563 | return i; |
564 | } | 564 | } |
565 | 565 | ||
566 | /** | 566 | /** |
567 | * _dep_scan_domains() - Scan dependency domains for a device | 567 | * _dep_scan_domains() - Scan dependency domains for a device |
568 | * @dev: device requesting the scan | 568 | * @dev: device requesting the scan |
569 | * @vdd: vdd_info corresponding to the device | 569 | * @vdd: vdd_info corresponding to the device |
570 | * @main_volt: voltage to scan for | 570 | * @main_volt: voltage to scan for |
571 | * | 571 | * |
572 | * Since each domain *may* have multiple dependent domains, we scan | 572 | * Since each domain *may* have multiple dependent domains, we scan |
573 | * through each of the dependent domains and invoke _dep_scan_table to | 573 | * through each of the dependent domains and invoke _dep_scan_table to |
574 | * scan each table for dependent domain for dependency scaling. | 574 | * scan each table for dependent domain for dependency scaling. |
575 | * | 575 | * |
576 | * This assumes that the dependent domain information is NULL entry terminated. | 576 | * This assumes that the dependent domain information is NULL entry terminated. |
577 | * Returns 0 if all went well. | 577 | * Returns 0 if all went well. |
578 | */ | 578 | */ |
579 | static int _dep_scan_domains(struct device *dev, | 579 | static int _dep_scan_domains(struct device *dev, |
580 | struct omap_vdd_info *vdd, unsigned long main_volt) | 580 | struct omap_vdd_info *vdd, unsigned long main_volt) |
581 | { | 581 | { |
582 | struct omap_vdd_dep_info *dep_info = vdd->dep_vdd_info; | 582 | struct omap_vdd_dep_info *dep_info = vdd->dep_vdd_info; |
583 | int ret = 0, r; | 583 | int ret = 0, r; |
584 | 584 | ||
585 | if (!dep_info) { | 585 | if (!dep_info) { |
586 | dev_dbg(dev, "%s: No dependent VDD\n", __func__); | 586 | dev_dbg(dev, "%s: No dependent VDD\n", __func__); |
587 | return 0; | 587 | return 0; |
588 | } | 588 | } |
589 | 589 | ||
590 | /* First scan through the mydomain->dep_domain list */ | 590 | /* First scan through the mydomain->dep_domain list */ |
591 | while (dep_info->nr_dep_entries) { | 591 | while (dep_info->nr_dep_entries) { |
592 | r = _dep_scan_table(dev, dep_info, main_volt); | 592 | r = _dep_scan_table(dev, dep_info, main_volt); |
593 | /* Store last failed value */ | 593 | /* Store last failed value */ |
594 | ret = (r) ? r : ret; | 594 | ret = (r) ? r : ret; |
595 | dep_info++; | 595 | dep_info++; |
596 | } | 596 | } |
597 | 597 | ||
598 | return ret; | 598 | return ret; |
599 | } | 599 | } |
600 | 600 | ||
601 | /** | 601 | /** |
602 | * _dep_scale_domains() - Cause a scale of all dependent domains | 602 | * _dep_scale_domains() - Cause a scale of all dependent domains |
603 | * @req_dev: device requesting the scale | 603 | * @req_dev: device requesting the scale |
604 | * @req_vdd: vdd_info corresponding to the requesting device. | 604 | * @req_vdd: vdd_info corresponding to the requesting device. |
605 | * | 605 | * |
606 | * This walks through every dependent domain and triggers a scale | 606 | * This walks through every dependent domain and triggers a scale |
607 | * It is assumed that the corresponding scale handling for the | 607 | * It is assumed that the corresponding scale handling for the |
608 | * domain translates this to freq and voltage scale operations as | 608 | * domain translates this to freq and voltage scale operations as |
609 | * needed. | 609 | * needed. |
610 | * | 610 | * |
611 | * Note: This is uses _dvfs_scale and one should be careful not to | 611 | * Note: This is uses _dvfs_scale and one should be careful not to |
612 | * create a circular depedency (e.g. vdd_mpu->vdd_core->vdd->mpu) | 612 | * create a circular depedency (e.g. vdd_mpu->vdd_core->vdd->mpu) |
613 | * which can create deadlocks. No protection is provided to prevent | 613 | * which can create deadlocks. No protection is provided to prevent |
614 | * this condition and a tree organization is assumed. | 614 | * this condition and a tree organization is assumed. |
615 | * | 615 | * |
616 | * Returns 0 if all went fine. | 616 | * Returns 0 if all went fine. |
617 | */ | 617 | */ |
618 | static int _dep_scale_domains(struct device *req_dev, | 618 | static int _dep_scale_domains(struct device *req_dev, |
619 | struct omap_vdd_info *req_vdd) | 619 | struct omap_vdd_info *req_vdd) |
620 | { | 620 | { |
621 | struct omap_vdd_dep_info *dep_info = req_vdd->dep_vdd_info; | 621 | struct omap_vdd_dep_info *dep_info = req_vdd->dep_vdd_info; |
622 | int ret = 0, r; | 622 | int ret = 0, r; |
623 | 623 | ||
624 | if (!dep_info) { | 624 | if (!dep_info) { |
625 | dev_dbg(req_dev, "%s: No dependent VDD\n", __func__); | 625 | dev_dbg(req_dev, "%s: No dependent VDD\n", __func__); |
626 | return 0; | 626 | return 0; |
627 | } | 627 | } |
628 | 628 | ||
629 | /* First scan through the mydomain->dep_domain list */ | 629 | /* First scan through the mydomain->dep_domain list */ |
630 | while (dep_info->nr_dep_entries) { | 630 | while (dep_info->nr_dep_entries) { |
631 | struct voltagedomain *tvoltdm = dep_info->_dep_voltdm; | 631 | struct voltagedomain *tvoltdm = dep_info->_dep_voltdm; |
632 | 632 | ||
633 | r = 0; | 633 | r = 0; |
634 | /* Scale it only if I have a voltdm mapped up for the dep */ | 634 | /* Scale it only if I have a voltdm mapped up for the dep */ |
635 | if (tvoltdm) { | 635 | if (tvoltdm) { |
636 | struct omap_vdd_dvfs_info *tdvfs_info; | 636 | struct omap_vdd_dvfs_info *tdvfs_info; |
637 | struct device *target_dev; | 637 | struct device *target_dev; |
638 | tdvfs_info = _voltdm_to_dvfs_info(tvoltdm); | 638 | tdvfs_info = _voltdm_to_dvfs_info(tvoltdm); |
639 | if (!tdvfs_info) { | 639 | if (!tdvfs_info) { |
640 | dev_warn(req_dev, "%s: no dvfs_info\n", | 640 | dev_warn(req_dev, "%s: no dvfs_info\n", |
641 | __func__); | 641 | __func__); |
642 | goto next; | 642 | goto next; |
643 | } | 643 | } |
644 | target_dev = _dvfs_info_to_dev(tdvfs_info); | 644 | target_dev = _dvfs_info_to_dev(tdvfs_info); |
645 | if (!target_dev) { | 645 | if (!target_dev) { |
646 | dev_warn(req_dev, "%s: no target_dev\n", | 646 | dev_warn(req_dev, "%s: no target_dev\n", |
647 | __func__); | 647 | __func__); |
648 | goto next; | 648 | goto next; |
649 | } | 649 | } |
650 | r = _dvfs_scale(req_dev, target_dev, tdvfs_info); | 650 | r = _dvfs_scale(req_dev, target_dev, tdvfs_info); |
651 | next: | 651 | next: |
652 | if (r) | 652 | if (r) |
653 | dev_err(req_dev, "%s: dvfs_scale to %s =%d\n", | 653 | dev_err(req_dev, "%s: dvfs_scale to %s =%d\n", |
654 | __func__, dev_name(target_dev), r); | 654 | __func__, dev_name(target_dev), r); |
655 | } | 655 | } |
656 | /* Store last failed value */ | 656 | /* Store last failed value */ |
657 | ret = (r) ? r : ret; | 657 | ret = (r) ? r : ret; |
658 | dep_info++; | 658 | dep_info++; |
659 | } | 659 | } |
660 | 660 | ||
661 | return ret; | 661 | return ret; |
662 | } | 662 | } |
663 | 663 | ||
664 | /** | 664 | /** |
665 | * _dvfs_scale() : Scale the devices associated with a voltage domain | 665 | * _dvfs_scale() : Scale the devices associated with a voltage domain |
666 | * @req_dev: Device requesting the scale | 666 | * @req_dev: Device requesting the scale |
667 | * @target_dev: Device requesting to be scaled | 667 | * @target_dev: Device requesting to be scaled |
668 | * @tdvfs_info: omap_vdd_dvfs_info pointer for the target domain | 668 | * @tdvfs_info: omap_vdd_dvfs_info pointer for the target domain |
669 | * | 669 | * |
670 | * This runs through the list of devices associated with the | 670 | * This runs through the list of devices associated with the |
671 | * voltage domain and scales the device rates to the one requested | 671 | * voltage domain and scales the device rates to the one requested |
672 | * by the user or those corresponding to the new voltage of the | 672 | * by the user or those corresponding to the new voltage of the |
673 | * voltage domain. Target voltage is the highest voltage in the vdd_user_list. | 673 | * voltage domain. Target voltage is the highest voltage in the vdd_user_list. |
674 | * | 674 | * |
675 | * Returns 0 on success else the error value. | 675 | * Returns 0 on success else the error value. |
676 | */ | 676 | */ |
677 | static int _dvfs_scale(struct device *req_dev, struct device *target_dev, | 677 | static int _dvfs_scale(struct device *req_dev, struct device *target_dev, |
678 | struct omap_vdd_dvfs_info *tdvfs_info) | 678 | struct omap_vdd_dvfs_info *tdvfs_info) |
679 | { | 679 | { |
680 | unsigned long curr_volt, new_volt; | 680 | unsigned long curr_volt, new_volt; |
681 | int volt_scale_dir = DVFS_VOLT_SCALE_DOWN; | 681 | int volt_scale_dir = DVFS_VOLT_SCALE_DOWN; |
682 | struct omap_vdd_dev_list *temp_dev; | 682 | struct omap_vdd_dev_list *temp_dev; |
683 | struct plist_node *node; | 683 | struct plist_node *node; |
684 | int ret = 0; | 684 | int ret = 0; |
685 | struct voltagedomain *voltdm; | 685 | struct voltagedomain *voltdm; |
686 | struct omap_vdd_info *vdd; | 686 | struct omap_vdd_info *vdd; |
687 | 687 | ||
688 | voltdm = tdvfs_info->voltdm; | 688 | voltdm = tdvfs_info->voltdm; |
689 | if (IS_ERR_OR_NULL(voltdm)) { | 689 | if (IS_ERR_OR_NULL(voltdm)) { |
690 | dev_err(target_dev, "%s: bad voltdm\n", __func__); | 690 | dev_err(target_dev, "%s: bad voltdm\n", __func__); |
691 | return -EINVAL; | 691 | return -EINVAL; |
692 | } | 692 | } |
693 | vdd = voltdm->vdd; | 693 | vdd = voltdm->vdd; |
694 | 694 | ||
695 | /* Find the highest voltage being requested */ | 695 | /* Find the highest voltage being requested */ |
696 | node = plist_last(&tdvfs_info->vdd_user_list); | 696 | node = plist_last(&tdvfs_info->vdd_user_list); |
697 | new_volt = node->prio; | 697 | new_volt = node->prio; |
698 | 698 | ||
699 | curr_volt = voltdm_get_voltage(voltdm); | 699 | curr_volt = voltdm_get_voltage(voltdm); |
700 | 700 | ||
701 | /* Disable smartreflex module across voltage and frequency scaling */ | 701 | /* Disable smartreflex module across voltage and frequency scaling */ |
702 | omap_sr_disable(voltdm); | 702 | omap_sr_disable(voltdm); |
703 | 703 | ||
704 | if (curr_volt == new_volt) { | 704 | if (curr_volt == new_volt) { |
705 | volt_scale_dir = DVFS_VOLT_SCALE_NONE; | 705 | volt_scale_dir = DVFS_VOLT_SCALE_NONE; |
706 | } else if (curr_volt < new_volt) { | 706 | } else if (curr_volt < new_volt) { |
707 | ret = voltdm_scale(voltdm, new_volt); | 707 | ret = voltdm_scale(voltdm, new_volt); |
708 | if (ret) { | 708 | if (ret) { |
709 | dev_err(target_dev, | 709 | dev_err(target_dev, |
710 | "%s: Unable to scale the %s to %ld volt\n", | 710 | "%s: Unable to scale the %s to %ld volt\n", |
711 | __func__, voltdm->name, new_volt); | 711 | __func__, voltdm->name, new_volt); |
712 | goto out; | 712 | goto out; |
713 | } | 713 | } |
714 | volt_scale_dir = DVFS_VOLT_SCALE_UP; | 714 | volt_scale_dir = DVFS_VOLT_SCALE_UP; |
715 | } | 715 | } |
716 | 716 | ||
717 | /* if we fail scale for dependent domains, go back to prev state */ | 717 | /* if we fail scale for dependent domains, go back to prev state */ |
718 | ret = _dep_scan_domains(target_dev, vdd, new_volt); | 718 | ret = _dep_scan_domains(target_dev, vdd, new_volt); |
719 | if (ret) { | 719 | if (ret) { |
720 | dev_err(target_dev, | 720 | dev_err(target_dev, |
721 | "%s: Error in scan domains for vdd_%s\n", | 721 | "%s: Error in scan domains for vdd_%s\n", |
722 | __func__, voltdm->name); | 722 | __func__, voltdm->name); |
723 | goto fail; | 723 | goto fail; |
724 | } | 724 | } |
725 | 725 | ||
726 | /* unless we are moving down, scale dependents before we shift freq */ | 726 | /* unless we are moving down, scale dependents before we shift freq */ |
727 | if (!(DVFS_VOLT_SCALE_DOWN == volt_scale_dir)) { | 727 | if (!(DVFS_VOLT_SCALE_DOWN == volt_scale_dir)) { |
728 | ret = _dep_scale_domains(target_dev, vdd); | 728 | ret = _dep_scale_domains(target_dev, vdd); |
729 | if (ret) { | 729 | if (ret) { |
730 | dev_err(target_dev, | 730 | dev_err(target_dev, |
731 | "%s: Error(%d)scale dependent with %ld volt\n", | 731 | "%s: Error(%d)scale dependent with %ld volt\n", |
732 | __func__, ret, new_volt); | 732 | __func__, ret, new_volt); |
733 | goto fail; | 733 | goto fail; |
734 | } | 734 | } |
735 | } | 735 | } |
736 | 736 | ||
737 | /* Move all devices in list to the required frequencies */ | 737 | /* Move all devices in list to the required frequencies */ |
738 | list_for_each_entry(temp_dev, &tdvfs_info->dev_list, node) { | 738 | list_for_each_entry(temp_dev, &tdvfs_info->dev_list, node) { |
739 | struct device *dev; | 739 | struct device *dev; |
740 | struct opp *opp; | 740 | struct opp *opp; |
741 | unsigned long freq = 0; | 741 | unsigned long freq = 0; |
742 | int r; | 742 | int r; |
743 | 743 | ||
744 | dev = temp_dev->dev; | 744 | dev = temp_dev->dev; |
745 | if (!plist_head_empty(&temp_dev->freq_user_list)) { | 745 | if (!plist_head_empty(&temp_dev->freq_user_list)) { |
746 | node = plist_last(&temp_dev->freq_user_list); | 746 | node = plist_last(&temp_dev->freq_user_list); |
747 | freq = node->prio; | 747 | freq = node->prio; |
748 | } else { | 748 | } else { |
749 | /* dep domain? we'd probably have a voltage request */ | 749 | /* dep domain? we'd probably have a voltage request */ |
750 | rcu_read_lock(); | 750 | rcu_read_lock(); |
751 | opp = _volt_to_opp(dev, new_volt); | 751 | opp = _volt_to_opp(dev, new_volt); |
752 | if (!IS_ERR(opp)) | 752 | if (!IS_ERR(opp)) |
753 | freq = opp_get_freq(opp); | 753 | freq = opp_get_freq(opp); |
754 | rcu_read_unlock(); | 754 | rcu_read_unlock(); |
755 | if (!freq) | 755 | if (!freq) |
756 | continue; | 756 | continue; |
757 | } | 757 | } |
758 | 758 | ||
759 | if (freq == clk_get_rate(temp_dev->clk)) { | 759 | if (freq == clk_get_rate(temp_dev->clk)) { |
760 | dev_dbg(dev, "%s: Already at the requested" | 760 | dev_dbg(dev, "%s: Already at the requested" |
761 | "rate %ld\n", __func__, freq); | 761 | "rate %ld\n", __func__, freq); |
762 | continue; | 762 | continue; |
763 | } | 763 | } |
764 | 764 | ||
765 | r = clk_set_rate(temp_dev->clk, freq); | 765 | r = clk_set_rate(temp_dev->clk, freq); |
766 | if (r < 0) { | 766 | if (r < 0) { |
767 | dev_err(dev, "%s: clk set rate frq=%ld failed(%d)\n", | 767 | dev_err(dev, "%s: clk set rate frq=%ld failed(%d)\n", |
768 | __func__, freq, r); | 768 | __func__, freq, r); |
769 | ret = r; | 769 | ret = r; |
770 | } | 770 | } |
771 | } | 771 | } |
772 | 772 | ||
773 | if (ret) | 773 | if (ret) |
774 | goto fail; | 774 | goto fail; |
775 | 775 | ||
776 | if (DVFS_VOLT_SCALE_DOWN == volt_scale_dir) { | 776 | if (DVFS_VOLT_SCALE_DOWN == volt_scale_dir) { |
777 | voltdm_scale(voltdm, new_volt); | 777 | voltdm_scale(voltdm, new_volt); |
778 | _dep_scale_domains(target_dev, vdd); | 778 | _dep_scale_domains(target_dev, vdd); |
779 | } | 779 | } |
780 | 780 | ||
781 | /* All clear.. go out gracefully */ | 781 | /* All clear.. go out gracefully */ |
782 | goto out; | 782 | goto out; |
783 | 783 | ||
784 | fail: | 784 | fail: |
785 | pr_warning("%s: domain%s: No clean recovery available! could be bad!\n", | 785 | pr_warning("%s: domain%s: No clean recovery available! could be bad!\n", |
786 | __func__, voltdm->name); | 786 | __func__, voltdm->name); |
787 | out: | 787 | out: |
788 | /* Re-enable Smartreflex module */ | 788 | /* Re-enable Smartreflex module */ |
789 | omap_sr_enable(voltdm); | 789 | omap_sr_enable(voltdm); |
790 | 790 | ||
791 | return ret; | 791 | return ret; |
792 | } | 792 | } |
793 | 793 | ||
794 | /* Public functions */ | 794 | /* Public functions */ |
795 | 795 | ||
796 | /** | 796 | /** |
797 | * omap_device_scale() - Set a new rate at which the device is to operate | 797 | * omap_device_scale() - Set a new rate at which the device is to operate |
798 | * @req_dev: pointer to the device requesting the scaling. | 798 | * @req_dev: pointer to the device requesting the scaling. |
799 | * @target_dev: pointer to the device that is to be scaled | 799 | * @target_dev: pointer to the device that is to be scaled |
800 | * @rate: the rnew rate for the device. | 800 | * @rate: the rnew rate for the device. |
801 | * | 801 | * |
802 | * This API gets the device opp table associated with this device and | 802 | * This API gets the device opp table associated with this device and |
803 | * tries putting the device to the requested rate and the voltage domain | 803 | * tries putting the device to the requested rate and the voltage domain |
804 | * associated with the device to the voltage corresponding to the | 804 | * associated with the device to the voltage corresponding to the |
805 | * requested rate. Since multiple devices can be assocciated with a | 805 | * requested rate. Since multiple devices can be assocciated with a |
806 | * voltage domain this API finds out the possible voltage the | 806 | * voltage domain this API finds out the possible voltage the |
807 | * voltage domain can enter and then decides on the final device | 807 | * voltage domain can enter and then decides on the final device |
808 | * rate. | 808 | * rate. |
809 | * | 809 | * |
810 | * Return 0 on success else the error value | 810 | * Return 0 on success else the error value |
811 | */ | 811 | */ |
812 | int omap_device_scale(struct device *req_dev, struct device *target_dev, | 812 | int omap_device_scale(struct device *req_dev, struct device *target_dev, |
813 | unsigned long rate) | 813 | unsigned long rate) |
814 | { | 814 | { |
815 | struct opp *opp; | 815 | struct opp *opp; |
816 | unsigned long volt, freq = rate; | 816 | unsigned long volt, freq = rate; |
817 | struct omap_vdd_dvfs_info *tdvfs_info; | 817 | struct omap_vdd_dvfs_info *tdvfs_info; |
818 | struct platform_device *pdev; | 818 | struct platform_device *pdev; |
819 | int ret = 0; | 819 | int ret = 0; |
820 | 820 | ||
821 | pdev = container_of(target_dev, struct platform_device, dev); | 821 | pdev = container_of(target_dev, struct platform_device, dev); |
822 | if (IS_ERR_OR_NULL(pdev)) { | 822 | if (IS_ERR_OR_NULL(pdev)) { |
823 | pr_err("%s: pdev is null!\n", __func__); | 823 | pr_err("%s: pdev is null!\n", __func__); |
824 | return -EINVAL; | 824 | return -EINVAL; |
825 | } | 825 | } |
826 | 826 | ||
827 | /* Lock me to ensure cross domain scaling is secure */ | 827 | /* Lock me to ensure cross domain scaling is secure */ |
828 | mutex_lock(&omap_dvfs_lock); | 828 | mutex_lock(&omap_dvfs_lock); |
829 | 829 | ||
830 | rcu_read_lock(); | 830 | rcu_read_lock(); |
831 | opp = opp_find_freq_ceil(target_dev, &freq); | 831 | opp = opp_find_freq_ceil(target_dev, &freq); |
832 | if (IS_ERR(opp)) { | 832 | if (IS_ERR(opp)) { |
833 | rcu_read_unlock(); | 833 | rcu_read_unlock(); |
834 | dev_err(target_dev, "%s: Unable to find OPP for freq%ld\n", | 834 | dev_err(target_dev, "%s: Unable to find OPP for freq%ld\n", |
835 | __func__, rate); | 835 | __func__, rate); |
836 | ret = -ENODEV; | 836 | ret = -ENODEV; |
837 | goto out; | 837 | goto out; |
838 | } | 838 | } |
839 | volt = opp_get_voltage(opp); | 839 | volt = opp_get_voltage(opp); |
840 | rcu_read_unlock(); | 840 | rcu_read_unlock(); |
841 | 841 | ||
842 | tdvfs_info = _dev_to_dvfs_info(target_dev); | 842 | tdvfs_info = _dev_to_dvfs_info(target_dev); |
843 | if (IS_ERR_OR_NULL(tdvfs_info)) { | 843 | if (IS_ERR_OR_NULL(tdvfs_info)) { |
844 | dev_err(target_dev, "%s: (req=%s) no vdd![f=%ld, v=%ld]\n", | 844 | dev_err(target_dev, "%s: (req=%s) no vdd![f=%ld, v=%ld]\n", |
845 | __func__, dev_name(req_dev), freq, volt); | 845 | __func__, dev_name(req_dev), freq, volt); |
846 | ret = -ENODEV; | 846 | ret = -ENODEV; |
847 | goto out; | 847 | goto out; |
848 | } | 848 | } |
849 | 849 | ||
850 | ret = _add_freq_request(tdvfs_info, req_dev, target_dev, freq); | 850 | ret = _add_freq_request(tdvfs_info, req_dev, target_dev, freq); |
851 | if (ret) { | 851 | if (ret) { |
852 | dev_err(target_dev, "%s: freqadd(%s) failed %d[f=%ld, v=%ld]\n", | 852 | dev_err(target_dev, "%s: freqadd(%s) failed %d[f=%ld, v=%ld]\n", |
853 | __func__, dev_name(req_dev), ret, freq, volt); | 853 | __func__, dev_name(req_dev), ret, freq, volt); |
854 | goto out; | 854 | goto out; |
855 | } | 855 | } |
856 | 856 | ||
857 | ret = _add_vdd_user(tdvfs_info, req_dev, volt); | 857 | ret = _add_vdd_user(tdvfs_info, req_dev, volt); |
858 | if (ret) { | 858 | if (ret) { |
859 | dev_err(target_dev, "%s: vddadd(%s) failed %d[f=%ld, v=%ld]\n", | 859 | dev_err(target_dev, "%s: vddadd(%s) failed %d[f=%ld, v=%ld]\n", |
860 | __func__, dev_name(req_dev), ret, freq, volt); | 860 | __func__, dev_name(req_dev), ret, freq, volt); |
861 | _remove_freq_request(tdvfs_info, req_dev, | 861 | _remove_freq_request(tdvfs_info, req_dev, |
862 | target_dev); | 862 | target_dev); |
863 | goto out; | 863 | goto out; |
864 | } | 864 | } |
865 | 865 | ||
866 | /* Do the actual scaling */ | 866 | /* Do the actual scaling */ |
867 | ret = _dvfs_scale(req_dev, target_dev, tdvfs_info); | 867 | ret = _dvfs_scale(req_dev, target_dev, tdvfs_info); |
868 | if (ret) { | 868 | if (ret) { |
869 | dev_err(target_dev, "%s: scale by %s failed %d[f=%ld, v=%ld]\n", | 869 | dev_err(target_dev, "%s: scale by %s failed %d[f=%ld, v=%ld]\n", |
870 | __func__, dev_name(req_dev), ret, freq, volt); | 870 | __func__, dev_name(req_dev), ret, freq, volt); |
871 | _remove_freq_request(tdvfs_info, req_dev, | 871 | _remove_freq_request(tdvfs_info, req_dev, |
872 | target_dev); | 872 | target_dev); |
873 | _remove_vdd_user(tdvfs_info, target_dev); | 873 | _remove_vdd_user(tdvfs_info, target_dev); |
874 | /* Fall through */ | 874 | /* Fall through */ |
875 | } | 875 | } |
876 | /* Fall through */ | 876 | /* Fall through */ |
877 | out: | 877 | out: |
878 | mutex_unlock(&omap_dvfs_lock); | 878 | mutex_unlock(&omap_dvfs_lock); |
879 | return ret; | 879 | return ret; |
880 | } | 880 | } |
881 | EXPORT_SYMBOL(omap_device_scale); | 881 | EXPORT_SYMBOL(omap_device_scale); |
882 | 882 | ||
883 | /** | 883 | /** |
884 | * omap_dvfs_register_device - Add a parent device into dvfs managed list | 884 | * omap_dvfs_register_device - Add a parent device into dvfs managed list |
885 | * @dev: Device to be added | 885 | * @dev: Device to be added |
886 | * @voltdm_name: Name of the voltage domain for the device | 886 | * @voltdm_name: Name of the voltage domain for the device |
887 | * @clk_name: Name of the clock for the device | 887 | * @clk_name: Name of the clock for the device |
888 | * | 888 | * |
889 | * This function adds a given device into user_list of corresponding | 889 | * This function adds a given device into user_list of corresponding |
890 | * vdd's omap_vdd_dvfs_info strucure. This list is traversed to scale | 890 | * vdd's omap_vdd_dvfs_info strucure. This list is traversed to scale |
891 | * frequencies of all the devices on a given vdd. | 891 | * frequencies of all the devices on a given vdd. |
892 | * | 892 | * |
893 | * Returns 0 on success. | 893 | * Returns 0 on success. |
894 | */ | 894 | */ |
895 | int __init omap_dvfs_register_device(struct device *dev, char *voltdm_name, | 895 | int __init omap_dvfs_register_device(struct device *dev, char *voltdm_name, |
896 | char *clk_name) | 896 | char *clk_name) |
897 | { | 897 | { |
898 | struct omap_vdd_dev_list *temp_dev; | 898 | struct omap_vdd_dev_list *temp_dev; |
899 | struct omap_vdd_dvfs_info *dvfs_info; | 899 | struct omap_vdd_dvfs_info *dvfs_info; |
900 | struct clk *clk = NULL; | 900 | struct clk *clk = NULL; |
901 | int ret = 0; | 901 | int ret = 0; |
902 | 902 | ||
903 | if (!voltdm_name) { | 903 | if (!voltdm_name) { |
904 | dev_err(dev, "%s: Bad voltdm name!\n", __func__); | 904 | dev_err(dev, "%s: Bad voltdm name!\n", __func__); |
905 | return -EINVAL; | 905 | return -EINVAL; |
906 | } | 906 | } |
907 | if (!clk_name) { | 907 | if (!clk_name) { |
908 | dev_err(dev, "%s: Bad clk name!\n", __func__); | 908 | dev_err(dev, "%s: Bad clk name!\n", __func__); |
909 | return -EINVAL; | 909 | return -EINVAL; |
910 | } | 910 | } |
911 | 911 | ||
912 | /* Lock me to secure structure changes */ | 912 | /* Lock me to secure structure changes */ |
913 | mutex_lock(&omap_dvfs_lock); | 913 | mutex_lock(&omap_dvfs_lock); |
914 | 914 | ||
915 | dvfs_info = _dev_to_dvfs_info(dev); | 915 | dvfs_info = _dev_to_dvfs_info(dev); |
916 | if (!dvfs_info) { | 916 | if (!dvfs_info) { |
917 | dvfs_info = kzalloc(sizeof(struct omap_vdd_dvfs_info), | 917 | dvfs_info = kzalloc(sizeof(struct omap_vdd_dvfs_info), |
918 | GFP_KERNEL); | 918 | GFP_KERNEL); |
919 | if (!dvfs_info) { | 919 | if (!dvfs_info) { |
920 | dev_warn(dev, "%s: unable to alloc memory!\n", | 920 | dev_warn(dev, "%s: unable to alloc memory!\n", |
921 | __func__); | 921 | __func__); |
922 | ret = -ENOMEM; | 922 | ret = -ENOMEM; |
923 | goto out; | 923 | goto out; |
924 | } | 924 | } |
925 | dvfs_info->voltdm = voltdm_lookup(voltdm_name); | 925 | dvfs_info->voltdm = voltdm_lookup(voltdm_name); |
926 | if (!dvfs_info->voltdm) { | 926 | if (!dvfs_info->voltdm) { |
927 | dev_warn(dev, "%s: unable to find voltdm %s!\n", | 927 | dev_warn(dev, "%s: unable to find voltdm %s!\n", |
928 | __func__, voltdm_name); | 928 | __func__, voltdm_name); |
929 | kfree(dvfs_info); | 929 | kfree(dvfs_info); |
930 | ret = -EINVAL; | 930 | ret = -EINVAL; |
931 | goto out; | 931 | goto out; |
932 | } | 932 | } |
933 | 933 | ||
934 | /* Init the plist */ | 934 | /* Init the plist */ |
935 | spin_lock_init(&dvfs_info->user_lock); | 935 | spin_lock_init(&dvfs_info->user_lock); |
936 | plist_head_init(&dvfs_info->vdd_user_list); | 936 | plist_head_init(&dvfs_info->vdd_user_list); |
937 | 937 | ||
938 | /* Init the device list */ | 938 | /* Init the device list */ |
939 | INIT_LIST_HEAD(&dvfs_info->dev_list); | 939 | INIT_LIST_HEAD(&dvfs_info->dev_list); |
940 | 940 | ||
941 | list_add(&dvfs_info->node, &omap_dvfs_info_list); | 941 | list_add(&dvfs_info->node, &omap_dvfs_info_list); |
942 | } | 942 | } |
943 | 943 | ||
944 | /* If device already added, we dont need to do more.. */ | 944 | /* If device already added, we dont need to do more.. */ |
945 | list_for_each_entry(temp_dev, &dvfs_info->dev_list, node) { | 945 | list_for_each_entry(temp_dev, &dvfs_info->dev_list, node) { |
946 | if (temp_dev->dev == dev) | 946 | if (temp_dev->dev == dev) |
947 | goto out; | 947 | goto out; |
948 | } | 948 | } |
949 | 949 | ||
950 | temp_dev = kzalloc(sizeof(struct omap_vdd_dev_list), GFP_KERNEL); | 950 | temp_dev = kzalloc(sizeof(struct omap_vdd_dev_list), GFP_KERNEL); |
951 | if (!temp_dev) { | 951 | if (!temp_dev) { |
952 | dev_err(dev, "%s: Unable to creat a new device for vdd_%s\n", | 952 | dev_err(dev, "%s: Unable to creat a new device for vdd_%s\n", |
953 | __func__, dvfs_info->voltdm->name); | 953 | __func__, dvfs_info->voltdm->name); |
954 | ret = -ENOMEM; | 954 | ret = -ENOMEM; |
955 | goto out; | 955 | goto out; |
956 | } | 956 | } |
957 | 957 | ||
958 | clk = clk_get(dev, clk_name); | 958 | clk = clk_get(dev, clk_name); |
959 | if (IS_ERR_OR_NULL(clk)) { | 959 | if (IS_ERR_OR_NULL(clk)) { |
960 | dev_warn(dev, "%s: Bad clk pointer!\n", __func__); | 960 | dev_warn(dev, "%s: Bad clk pointer!\n", __func__); |
961 | kfree(temp_dev); | 961 | kfree(temp_dev); |
962 | ret = -EINVAL; | 962 | ret = -EINVAL; |
963 | goto out; | 963 | goto out; |
964 | } | 964 | } |
965 | 965 | ||
966 | /* Initialize priority ordered list */ | 966 | /* Initialize priority ordered list */ |
967 | spin_lock_init(&temp_dev->user_lock); | 967 | spin_lock_init(&temp_dev->user_lock); |
968 | plist_head_init(&temp_dev->freq_user_list); | 968 | plist_head_init(&temp_dev->freq_user_list); |
969 | 969 | ||
970 | temp_dev->dev = dev; | 970 | temp_dev->dev = dev; |
971 | temp_dev->clk = clk; | 971 | temp_dev->clk = clk; |
972 | list_add_tail(&temp_dev->node, &dvfs_info->dev_list); | 972 | list_add_tail(&temp_dev->node, &dvfs_info->dev_list); |
973 | 973 | ||
974 | /* Fall through */ | 974 | /* Fall through */ |
975 | out: | 975 | out: |
976 | mutex_unlock(&omap_dvfs_lock); | 976 | mutex_unlock(&omap_dvfs_lock); |
977 | return ret; | 977 | return ret; |
978 | } | 978 | } |
979 | 979 |
arch/arm/mach-omap2/dvfs.h
1 | /* | File was deleted | |
2 | * OMAP3/OMAP4 DVFS Management Routines | ||
3 | * | ||
4 | * Author: Vishwanath BS <vishwanath.bs@ti.com> | ||
5 | * | ||
6 | * Copyright (C) 2011 Texas Instruments, Inc. | ||
7 | * Vishwanath BS <vishwanath.bs@ti.com> | ||
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 | #ifndef __ARCH_ARM_MACH_OMAP2_DVFS_H | ||
15 | #define __ARCH_ARM_MACH_OMAP2_DVFS_H | ||
16 | #include <plat/omap_hwmod.h> | ||
17 | #include "voltage.h" | ||
18 | |||
19 | #ifdef CONFIG_PM | ||
20 | int omap_dvfs_register_device(struct device *dev, char *voltdm_name, | ||
21 | char *clk_name); | ||
22 | int omap_device_scale(struct device *req_dev, struct device *target_dev, | ||
23 | unsigned long rate); | ||
24 | #else | ||
25 | static inline int omap_dvfs_register_device(struct omap_hwmod *oh, | ||
26 | struct device *dev) | ||
27 | static inline int omap_dvfs_register_device(struct device *dev, | ||
28 | char *voltdm_name, char *clk_name) | ||
29 | { | ||
30 | return -EINVAL; | ||
31 | } | ||
32 | static inline int omap_device_scale(struct device *req_dev, | ||
33 | struct device *target_dev, unsigned long rate) | ||
34 | { | ||
35 | return -EINVAL; | ||
36 | } | ||
37 | #endif | ||
38 | #endif | ||
39 | 1 | /* |
arch/arm/mach-omap2/io.c
1 | /* | 1 | /* |
2 | * linux/arch/arm/mach-omap2/io.c | 2 | * linux/arch/arm/mach-omap2/io.c |
3 | * | 3 | * |
4 | * OMAP2 I/O mapping code | 4 | * OMAP2 I/O mapping code |
5 | * | 5 | * |
6 | * Copyright (C) 2005 Nokia Corporation | 6 | * Copyright (C) 2005 Nokia Corporation |
7 | * Copyright (C) 2007-2009 Texas Instruments | 7 | * Copyright (C) 2007-2009 Texas Instruments |
8 | * | 8 | * |
9 | * Author: | 9 | * Author: |
10 | * Juha Yrjola <juha.yrjola@nokia.com> | 10 | * Juha Yrjola <juha.yrjola@nokia.com> |
11 | * Syed Khasim <x0khasim@ti.com> | 11 | * Syed Khasim <x0khasim@ti.com> |
12 | * | 12 | * |
13 | * Added OMAP4 support - Santosh Shilimkar <santosh.shilimkar@ti.com> | 13 | * Added OMAP4 support - Santosh Shilimkar <santosh.shilimkar@ti.com> |
14 | * | 14 | * |
15 | * This program is free software; you can redistribute it and/or modify | 15 | * This program is free software; you can redistribute it and/or modify |
16 | * it under the terms of the GNU General Public License version 2 as | 16 | * it under the terms of the GNU General Public License version 2 as |
17 | * published by the Free Software Foundation. | 17 | * published by the Free Software Foundation. |
18 | */ | 18 | */ |
19 | 19 | ||
20 | #include <linux/module.h> | 20 | #include <linux/module.h> |
21 | #include <linux/kernel.h> | 21 | #include <linux/kernel.h> |
22 | #include <linux/init.h> | 22 | #include <linux/init.h> |
23 | #include <linux/io.h> | 23 | #include <linux/io.h> |
24 | #include <linux/clk.h> | 24 | #include <linux/clk.h> |
25 | #include <linux/omapfb.h> | 25 | #include <linux/omapfb.h> |
26 | 26 | ||
27 | #include <asm/tlb.h> | 27 | #include <asm/tlb.h> |
28 | 28 | ||
29 | #include <asm/mach/map.h> | 29 | #include <asm/mach/map.h> |
30 | 30 | ||
31 | #include <plat/sram.h> | 31 | #include <plat/sram.h> |
32 | #include <plat/sdrc.h> | 32 | #include <plat/sdrc.h> |
33 | #include <plat/serial.h> | 33 | #include <plat/serial.h> |
34 | 34 | ||
35 | #include "clock2xxx.h" | 35 | #include "clock2xxx.h" |
36 | #include "clock3xxx.h" | 36 | #include "clock3xxx.h" |
37 | #include "clock44xx.h" | 37 | #include "clock44xx.h" |
38 | 38 | ||
39 | #include <plat/common.h> | 39 | #include <plat/common.h> |
40 | #include <plat/omap-pm.h> | 40 | #include <plat/omap-pm.h> |
41 | #include "voltage.h" | 41 | #include <plat/voltage.h> |
42 | #include "powerdomain.h" | 42 | #include "powerdomain.h" |
43 | 43 | ||
44 | #include "clockdomain.h" | 44 | #include "clockdomain.h" |
45 | #include <plat/omap_hwmod.h> | 45 | #include <plat/omap_hwmod.h> |
46 | #include <plat/multi.h> | 46 | #include <plat/multi.h> |
47 | #include <plat/common.h> | 47 | #include <plat/common.h> |
48 | 48 | ||
49 | /* | 49 | /* |
50 | * The machine specific code may provide the extra mapping besides the | 50 | * The machine specific code may provide the extra mapping besides the |
51 | * default mapping provided here. | 51 | * default mapping provided here. |
52 | */ | 52 | */ |
53 | 53 | ||
54 | #ifdef CONFIG_ARCH_OMAP2 | 54 | #ifdef CONFIG_ARCH_OMAP2 |
55 | static struct map_desc omap24xx_io_desc[] __initdata = { | 55 | static struct map_desc omap24xx_io_desc[] __initdata = { |
56 | { | 56 | { |
57 | .virtual = L3_24XX_VIRT, | 57 | .virtual = L3_24XX_VIRT, |
58 | .pfn = __phys_to_pfn(L3_24XX_PHYS), | 58 | .pfn = __phys_to_pfn(L3_24XX_PHYS), |
59 | .length = L3_24XX_SIZE, | 59 | .length = L3_24XX_SIZE, |
60 | .type = MT_DEVICE | 60 | .type = MT_DEVICE |
61 | }, | 61 | }, |
62 | { | 62 | { |
63 | .virtual = L4_24XX_VIRT, | 63 | .virtual = L4_24XX_VIRT, |
64 | .pfn = __phys_to_pfn(L4_24XX_PHYS), | 64 | .pfn = __phys_to_pfn(L4_24XX_PHYS), |
65 | .length = L4_24XX_SIZE, | 65 | .length = L4_24XX_SIZE, |
66 | .type = MT_DEVICE | 66 | .type = MT_DEVICE |
67 | }, | 67 | }, |
68 | }; | 68 | }; |
69 | 69 | ||
70 | #ifdef CONFIG_SOC_OMAP2420 | 70 | #ifdef CONFIG_SOC_OMAP2420 |
71 | static struct map_desc omap242x_io_desc[] __initdata = { | 71 | static struct map_desc omap242x_io_desc[] __initdata = { |
72 | { | 72 | { |
73 | .virtual = DSP_MEM_2420_VIRT, | 73 | .virtual = DSP_MEM_2420_VIRT, |
74 | .pfn = __phys_to_pfn(DSP_MEM_2420_PHYS), | 74 | .pfn = __phys_to_pfn(DSP_MEM_2420_PHYS), |
75 | .length = DSP_MEM_2420_SIZE, | 75 | .length = DSP_MEM_2420_SIZE, |
76 | .type = MT_DEVICE | 76 | .type = MT_DEVICE |
77 | }, | 77 | }, |
78 | { | 78 | { |
79 | .virtual = DSP_IPI_2420_VIRT, | 79 | .virtual = DSP_IPI_2420_VIRT, |
80 | .pfn = __phys_to_pfn(DSP_IPI_2420_PHYS), | 80 | .pfn = __phys_to_pfn(DSP_IPI_2420_PHYS), |
81 | .length = DSP_IPI_2420_SIZE, | 81 | .length = DSP_IPI_2420_SIZE, |
82 | .type = MT_DEVICE | 82 | .type = MT_DEVICE |
83 | }, | 83 | }, |
84 | { | 84 | { |
85 | .virtual = DSP_MMU_2420_VIRT, | 85 | .virtual = DSP_MMU_2420_VIRT, |
86 | .pfn = __phys_to_pfn(DSP_MMU_2420_PHYS), | 86 | .pfn = __phys_to_pfn(DSP_MMU_2420_PHYS), |
87 | .length = DSP_MMU_2420_SIZE, | 87 | .length = DSP_MMU_2420_SIZE, |
88 | .type = MT_DEVICE | 88 | .type = MT_DEVICE |
89 | }, | 89 | }, |
90 | }; | 90 | }; |
91 | 91 | ||
92 | #endif | 92 | #endif |
93 | 93 | ||
94 | #ifdef CONFIG_SOC_OMAP2430 | 94 | #ifdef CONFIG_SOC_OMAP2430 |
95 | static struct map_desc omap243x_io_desc[] __initdata = { | 95 | static struct map_desc omap243x_io_desc[] __initdata = { |
96 | { | 96 | { |
97 | .virtual = L4_WK_243X_VIRT, | 97 | .virtual = L4_WK_243X_VIRT, |
98 | .pfn = __phys_to_pfn(L4_WK_243X_PHYS), | 98 | .pfn = __phys_to_pfn(L4_WK_243X_PHYS), |
99 | .length = L4_WK_243X_SIZE, | 99 | .length = L4_WK_243X_SIZE, |
100 | .type = MT_DEVICE | 100 | .type = MT_DEVICE |
101 | }, | 101 | }, |
102 | { | 102 | { |
103 | .virtual = OMAP243X_GPMC_VIRT, | 103 | .virtual = OMAP243X_GPMC_VIRT, |
104 | .pfn = __phys_to_pfn(OMAP243X_GPMC_PHYS), | 104 | .pfn = __phys_to_pfn(OMAP243X_GPMC_PHYS), |
105 | .length = OMAP243X_GPMC_SIZE, | 105 | .length = OMAP243X_GPMC_SIZE, |
106 | .type = MT_DEVICE | 106 | .type = MT_DEVICE |
107 | }, | 107 | }, |
108 | { | 108 | { |
109 | .virtual = OMAP243X_SDRC_VIRT, | 109 | .virtual = OMAP243X_SDRC_VIRT, |
110 | .pfn = __phys_to_pfn(OMAP243X_SDRC_PHYS), | 110 | .pfn = __phys_to_pfn(OMAP243X_SDRC_PHYS), |
111 | .length = OMAP243X_SDRC_SIZE, | 111 | .length = OMAP243X_SDRC_SIZE, |
112 | .type = MT_DEVICE | 112 | .type = MT_DEVICE |
113 | }, | 113 | }, |
114 | { | 114 | { |
115 | .virtual = OMAP243X_SMS_VIRT, | 115 | .virtual = OMAP243X_SMS_VIRT, |
116 | .pfn = __phys_to_pfn(OMAP243X_SMS_PHYS), | 116 | .pfn = __phys_to_pfn(OMAP243X_SMS_PHYS), |
117 | .length = OMAP243X_SMS_SIZE, | 117 | .length = OMAP243X_SMS_SIZE, |
118 | .type = MT_DEVICE | 118 | .type = MT_DEVICE |
119 | }, | 119 | }, |
120 | }; | 120 | }; |
121 | #endif | 121 | #endif |
122 | #endif | 122 | #endif |
123 | 123 | ||
124 | #ifdef CONFIG_ARCH_OMAP3 | 124 | #ifdef CONFIG_ARCH_OMAP3 |
125 | static struct map_desc omap34xx_io_desc[] __initdata = { | 125 | static struct map_desc omap34xx_io_desc[] __initdata = { |
126 | { | 126 | { |
127 | .virtual = L3_34XX_VIRT, | 127 | .virtual = L3_34XX_VIRT, |
128 | .pfn = __phys_to_pfn(L3_34XX_PHYS), | 128 | .pfn = __phys_to_pfn(L3_34XX_PHYS), |
129 | .length = L3_34XX_SIZE, | 129 | .length = L3_34XX_SIZE, |
130 | .type = MT_DEVICE | 130 | .type = MT_DEVICE |
131 | }, | 131 | }, |
132 | { | 132 | { |
133 | .virtual = L4_34XX_VIRT, | 133 | .virtual = L4_34XX_VIRT, |
134 | .pfn = __phys_to_pfn(L4_34XX_PHYS), | 134 | .pfn = __phys_to_pfn(L4_34XX_PHYS), |
135 | .length = L4_34XX_SIZE, | 135 | .length = L4_34XX_SIZE, |
136 | .type = MT_DEVICE | 136 | .type = MT_DEVICE |
137 | }, | 137 | }, |
138 | { | 138 | { |
139 | .virtual = OMAP34XX_GPMC_VIRT, | 139 | .virtual = OMAP34XX_GPMC_VIRT, |
140 | .pfn = __phys_to_pfn(OMAP34XX_GPMC_PHYS), | 140 | .pfn = __phys_to_pfn(OMAP34XX_GPMC_PHYS), |
141 | .length = OMAP34XX_GPMC_SIZE, | 141 | .length = OMAP34XX_GPMC_SIZE, |
142 | .type = MT_DEVICE | 142 | .type = MT_DEVICE |
143 | }, | 143 | }, |
144 | { | 144 | { |
145 | .virtual = OMAP343X_SMS_VIRT, | 145 | .virtual = OMAP343X_SMS_VIRT, |
146 | .pfn = __phys_to_pfn(OMAP343X_SMS_PHYS), | 146 | .pfn = __phys_to_pfn(OMAP343X_SMS_PHYS), |
147 | .length = OMAP343X_SMS_SIZE, | 147 | .length = OMAP343X_SMS_SIZE, |
148 | .type = MT_DEVICE | 148 | .type = MT_DEVICE |
149 | }, | 149 | }, |
150 | { | 150 | { |
151 | .virtual = OMAP343X_SDRC_VIRT, | 151 | .virtual = OMAP343X_SDRC_VIRT, |
152 | .pfn = __phys_to_pfn(OMAP343X_SDRC_PHYS), | 152 | .pfn = __phys_to_pfn(OMAP343X_SDRC_PHYS), |
153 | .length = OMAP343X_SDRC_SIZE, | 153 | .length = OMAP343X_SDRC_SIZE, |
154 | .type = MT_DEVICE | 154 | .type = MT_DEVICE |
155 | }, | 155 | }, |
156 | { | 156 | { |
157 | .virtual = L4_PER_34XX_VIRT, | 157 | .virtual = L4_PER_34XX_VIRT, |
158 | .pfn = __phys_to_pfn(L4_PER_34XX_PHYS), | 158 | .pfn = __phys_to_pfn(L4_PER_34XX_PHYS), |
159 | .length = L4_PER_34XX_SIZE, | 159 | .length = L4_PER_34XX_SIZE, |
160 | .type = MT_DEVICE | 160 | .type = MT_DEVICE |
161 | }, | 161 | }, |
162 | { | 162 | { |
163 | .virtual = L4_EMU_34XX_VIRT, | 163 | .virtual = L4_EMU_34XX_VIRT, |
164 | .pfn = __phys_to_pfn(L4_EMU_34XX_PHYS), | 164 | .pfn = __phys_to_pfn(L4_EMU_34XX_PHYS), |
165 | .length = L4_EMU_34XX_SIZE, | 165 | .length = L4_EMU_34XX_SIZE, |
166 | .type = MT_DEVICE | 166 | .type = MT_DEVICE |
167 | }, | 167 | }, |
168 | #if defined(CONFIG_DEBUG_LL) && \ | 168 | #if defined(CONFIG_DEBUG_LL) && \ |
169 | (defined(CONFIG_MACH_OMAP_ZOOM2) || defined(CONFIG_MACH_OMAP_ZOOM3)) | 169 | (defined(CONFIG_MACH_OMAP_ZOOM2) || defined(CONFIG_MACH_OMAP_ZOOM3)) |
170 | { | 170 | { |
171 | .virtual = ZOOM_UART_VIRT, | 171 | .virtual = ZOOM_UART_VIRT, |
172 | .pfn = __phys_to_pfn(ZOOM_UART_BASE), | 172 | .pfn = __phys_to_pfn(ZOOM_UART_BASE), |
173 | .length = SZ_1M, | 173 | .length = SZ_1M, |
174 | .type = MT_DEVICE | 174 | .type = MT_DEVICE |
175 | }, | 175 | }, |
176 | #endif | 176 | #endif |
177 | }; | 177 | }; |
178 | #endif | 178 | #endif |
179 | 179 | ||
180 | #ifdef CONFIG_SOC_OMAPTI816X | 180 | #ifdef CONFIG_SOC_OMAPTI816X |
181 | static struct map_desc omapti816x_io_desc[] __initdata = { | 181 | static struct map_desc omapti816x_io_desc[] __initdata = { |
182 | { | 182 | { |
183 | .virtual = L4_34XX_VIRT, | 183 | .virtual = L4_34XX_VIRT, |
184 | .pfn = __phys_to_pfn(L4_34XX_PHYS), | 184 | .pfn = __phys_to_pfn(L4_34XX_PHYS), |
185 | .length = L4_34XX_SIZE, | 185 | .length = L4_34XX_SIZE, |
186 | .type = MT_DEVICE | 186 | .type = MT_DEVICE |
187 | } | 187 | } |
188 | }; | 188 | }; |
189 | #endif | 189 | #endif |
190 | 190 | ||
191 | #ifdef CONFIG_SOC_OMAPAM33XX | 191 | #ifdef CONFIG_SOC_OMAPAM33XX |
192 | static struct map_desc omapam33xx_io_desc[] __initdata = { | 192 | static struct map_desc omapam33xx_io_desc[] __initdata = { |
193 | { | 193 | { |
194 | .virtual = L4_34XX_VIRT, | 194 | .virtual = L4_34XX_VIRT, |
195 | .pfn = __phys_to_pfn(L4_34XX_PHYS), | 195 | .pfn = __phys_to_pfn(L4_34XX_PHYS), |
196 | .length = L4_34XX_SIZE, | 196 | .length = L4_34XX_SIZE, |
197 | .type = MT_DEVICE | 197 | .type = MT_DEVICE |
198 | }, | 198 | }, |
199 | { | 199 | { |
200 | .virtual = L4_WK_AM33XX_VIRT, | 200 | .virtual = L4_WK_AM33XX_VIRT, |
201 | .pfn = __phys_to_pfn(L4_WK_AM33XX_PHYS), | 201 | .pfn = __phys_to_pfn(L4_WK_AM33XX_PHYS), |
202 | .length = L4_WK_AM33XX_SIZE, | 202 | .length = L4_WK_AM33XX_SIZE, |
203 | .type = MT_DEVICE | 203 | .type = MT_DEVICE |
204 | } | 204 | } |
205 | }; | 205 | }; |
206 | #endif | 206 | #endif |
207 | 207 | ||
208 | #ifdef CONFIG_ARCH_OMAP4 | 208 | #ifdef CONFIG_ARCH_OMAP4 |
209 | static struct map_desc omap44xx_io_desc[] __initdata = { | 209 | static struct map_desc omap44xx_io_desc[] __initdata = { |
210 | { | 210 | { |
211 | .virtual = L3_44XX_VIRT, | 211 | .virtual = L3_44XX_VIRT, |
212 | .pfn = __phys_to_pfn(L3_44XX_PHYS), | 212 | .pfn = __phys_to_pfn(L3_44XX_PHYS), |
213 | .length = L3_44XX_SIZE, | 213 | .length = L3_44XX_SIZE, |
214 | .type = MT_DEVICE, | 214 | .type = MT_DEVICE, |
215 | }, | 215 | }, |
216 | { | 216 | { |
217 | .virtual = L4_44XX_VIRT, | 217 | .virtual = L4_44XX_VIRT, |
218 | .pfn = __phys_to_pfn(L4_44XX_PHYS), | 218 | .pfn = __phys_to_pfn(L4_44XX_PHYS), |
219 | .length = L4_44XX_SIZE, | 219 | .length = L4_44XX_SIZE, |
220 | .type = MT_DEVICE, | 220 | .type = MT_DEVICE, |
221 | }, | 221 | }, |
222 | { | 222 | { |
223 | .virtual = OMAP44XX_GPMC_VIRT, | 223 | .virtual = OMAP44XX_GPMC_VIRT, |
224 | .pfn = __phys_to_pfn(OMAP44XX_GPMC_PHYS), | 224 | .pfn = __phys_to_pfn(OMAP44XX_GPMC_PHYS), |
225 | .length = OMAP44XX_GPMC_SIZE, | 225 | .length = OMAP44XX_GPMC_SIZE, |
226 | .type = MT_DEVICE, | 226 | .type = MT_DEVICE, |
227 | }, | 227 | }, |
228 | { | 228 | { |
229 | .virtual = OMAP44XX_EMIF1_VIRT, | 229 | .virtual = OMAP44XX_EMIF1_VIRT, |
230 | .pfn = __phys_to_pfn(OMAP44XX_EMIF1_PHYS), | 230 | .pfn = __phys_to_pfn(OMAP44XX_EMIF1_PHYS), |
231 | .length = OMAP44XX_EMIF1_SIZE, | 231 | .length = OMAP44XX_EMIF1_SIZE, |
232 | .type = MT_DEVICE, | 232 | .type = MT_DEVICE, |
233 | }, | 233 | }, |
234 | { | 234 | { |
235 | .virtual = OMAP44XX_EMIF2_VIRT, | 235 | .virtual = OMAP44XX_EMIF2_VIRT, |
236 | .pfn = __phys_to_pfn(OMAP44XX_EMIF2_PHYS), | 236 | .pfn = __phys_to_pfn(OMAP44XX_EMIF2_PHYS), |
237 | .length = OMAP44XX_EMIF2_SIZE, | 237 | .length = OMAP44XX_EMIF2_SIZE, |
238 | .type = MT_DEVICE, | 238 | .type = MT_DEVICE, |
239 | }, | 239 | }, |
240 | { | 240 | { |
241 | .virtual = OMAP44XX_DMM_VIRT, | 241 | .virtual = OMAP44XX_DMM_VIRT, |
242 | .pfn = __phys_to_pfn(OMAP44XX_DMM_PHYS), | 242 | .pfn = __phys_to_pfn(OMAP44XX_DMM_PHYS), |
243 | .length = OMAP44XX_DMM_SIZE, | 243 | .length = OMAP44XX_DMM_SIZE, |
244 | .type = MT_DEVICE, | 244 | .type = MT_DEVICE, |
245 | }, | 245 | }, |
246 | { | 246 | { |
247 | .virtual = L4_PER_44XX_VIRT, | 247 | .virtual = L4_PER_44XX_VIRT, |
248 | .pfn = __phys_to_pfn(L4_PER_44XX_PHYS), | 248 | .pfn = __phys_to_pfn(L4_PER_44XX_PHYS), |
249 | .length = L4_PER_44XX_SIZE, | 249 | .length = L4_PER_44XX_SIZE, |
250 | .type = MT_DEVICE, | 250 | .type = MT_DEVICE, |
251 | }, | 251 | }, |
252 | { | 252 | { |
253 | .virtual = L4_EMU_44XX_VIRT, | 253 | .virtual = L4_EMU_44XX_VIRT, |
254 | .pfn = __phys_to_pfn(L4_EMU_44XX_PHYS), | 254 | .pfn = __phys_to_pfn(L4_EMU_44XX_PHYS), |
255 | .length = L4_EMU_44XX_SIZE, | 255 | .length = L4_EMU_44XX_SIZE, |
256 | .type = MT_DEVICE, | 256 | .type = MT_DEVICE, |
257 | }, | 257 | }, |
258 | }; | 258 | }; |
259 | #endif | 259 | #endif |
260 | 260 | ||
261 | #ifdef CONFIG_SOC_OMAP2420 | 261 | #ifdef CONFIG_SOC_OMAP2420 |
262 | void __init omap242x_map_common_io(void) | 262 | void __init omap242x_map_common_io(void) |
263 | { | 263 | { |
264 | iotable_init(omap24xx_io_desc, ARRAY_SIZE(omap24xx_io_desc)); | 264 | iotable_init(omap24xx_io_desc, ARRAY_SIZE(omap24xx_io_desc)); |
265 | iotable_init(omap242x_io_desc, ARRAY_SIZE(omap242x_io_desc)); | 265 | iotable_init(omap242x_io_desc, ARRAY_SIZE(omap242x_io_desc)); |
266 | } | 266 | } |
267 | #endif | 267 | #endif |
268 | 268 | ||
269 | #ifdef CONFIG_SOC_OMAP2430 | 269 | #ifdef CONFIG_SOC_OMAP2430 |
270 | void __init omap243x_map_common_io(void) | 270 | void __init omap243x_map_common_io(void) |
271 | { | 271 | { |
272 | iotable_init(omap24xx_io_desc, ARRAY_SIZE(omap24xx_io_desc)); | 272 | iotable_init(omap24xx_io_desc, ARRAY_SIZE(omap24xx_io_desc)); |
273 | iotable_init(omap243x_io_desc, ARRAY_SIZE(omap243x_io_desc)); | 273 | iotable_init(omap243x_io_desc, ARRAY_SIZE(omap243x_io_desc)); |
274 | } | 274 | } |
275 | #endif | 275 | #endif |
276 | 276 | ||
277 | #ifdef CONFIG_ARCH_OMAP3 | 277 | #ifdef CONFIG_ARCH_OMAP3 |
278 | void __init omap34xx_map_common_io(void) | 278 | void __init omap34xx_map_common_io(void) |
279 | { | 279 | { |
280 | iotable_init(omap34xx_io_desc, ARRAY_SIZE(omap34xx_io_desc)); | 280 | iotable_init(omap34xx_io_desc, ARRAY_SIZE(omap34xx_io_desc)); |
281 | } | 281 | } |
282 | #endif | 282 | #endif |
283 | 283 | ||
284 | #ifdef CONFIG_SOC_OMAPTI816X | 284 | #ifdef CONFIG_SOC_OMAPTI816X |
285 | void __init omapti816x_map_common_io(void) | 285 | void __init omapti816x_map_common_io(void) |
286 | { | 286 | { |
287 | iotable_init(omapti816x_io_desc, ARRAY_SIZE(omapti816x_io_desc)); | 287 | iotable_init(omapti816x_io_desc, ARRAY_SIZE(omapti816x_io_desc)); |
288 | } | 288 | } |
289 | #endif | 289 | #endif |
290 | 290 | ||
291 | #ifdef CONFIG_SOC_OMAPAM33XX | 291 | #ifdef CONFIG_SOC_OMAPAM33XX |
292 | void __init omapam33xx_map_common_io(void) | 292 | void __init omapam33xx_map_common_io(void) |
293 | { | 293 | { |
294 | iotable_init(omapam33xx_io_desc, ARRAY_SIZE(omapam33xx_io_desc)); | 294 | iotable_init(omapam33xx_io_desc, ARRAY_SIZE(omapam33xx_io_desc)); |
295 | } | 295 | } |
296 | #endif | 296 | #endif |
297 | 297 | ||
298 | #ifdef CONFIG_ARCH_OMAP4 | 298 | #ifdef CONFIG_ARCH_OMAP4 |
299 | void __init omap44xx_map_common_io(void) | 299 | void __init omap44xx_map_common_io(void) |
300 | { | 300 | { |
301 | iotable_init(omap44xx_io_desc, ARRAY_SIZE(omap44xx_io_desc)); | 301 | iotable_init(omap44xx_io_desc, ARRAY_SIZE(omap44xx_io_desc)); |
302 | } | 302 | } |
303 | #endif | 303 | #endif |
304 | 304 | ||
305 | /* | 305 | /* |
306 | * omap2_init_reprogram_sdrc - reprogram SDRC timing parameters | 306 | * omap2_init_reprogram_sdrc - reprogram SDRC timing parameters |
307 | * | 307 | * |
308 | * Sets the CORE DPLL3 M2 divider to the same value that it's at | 308 | * Sets the CORE DPLL3 M2 divider to the same value that it's at |
309 | * currently. This has the effect of setting the SDRC SDRAM AC timing | 309 | * currently. This has the effect of setting the SDRC SDRAM AC timing |
310 | * registers to the values currently defined by the kernel. Currently | 310 | * registers to the values currently defined by the kernel. Currently |
311 | * only defined for OMAP3; will return 0 if called on OMAP2. Returns | 311 | * only defined for OMAP3; will return 0 if called on OMAP2. Returns |
312 | * -EINVAL if the dpll3_m2_ck cannot be found, 0 if called on OMAP2, | 312 | * -EINVAL if the dpll3_m2_ck cannot be found, 0 if called on OMAP2, |
313 | * or passes along the return value of clk_set_rate(). | 313 | * or passes along the return value of clk_set_rate(). |
314 | */ | 314 | */ |
315 | static int __init _omap2_init_reprogram_sdrc(void) | 315 | static int __init _omap2_init_reprogram_sdrc(void) |
316 | { | 316 | { |
317 | struct clk *dpll3_m2_ck; | 317 | struct clk *dpll3_m2_ck; |
318 | int v = -EINVAL; | 318 | int v = -EINVAL; |
319 | long rate; | 319 | long rate; |
320 | 320 | ||
321 | if (!cpu_is_omap34xx()) | 321 | if (!cpu_is_omap34xx()) |
322 | return 0; | 322 | return 0; |
323 | 323 | ||
324 | dpll3_m2_ck = clk_get(NULL, "dpll3_m2_ck"); | 324 | dpll3_m2_ck = clk_get(NULL, "dpll3_m2_ck"); |
325 | if (IS_ERR(dpll3_m2_ck)) | 325 | if (IS_ERR(dpll3_m2_ck)) |
326 | return -EINVAL; | 326 | return -EINVAL; |
327 | 327 | ||
328 | rate = clk_get_rate(dpll3_m2_ck); | 328 | rate = clk_get_rate(dpll3_m2_ck); |
329 | pr_info("Reprogramming SDRC clock to %ld Hz\n", rate); | 329 | pr_info("Reprogramming SDRC clock to %ld Hz\n", rate); |
330 | v = clk_set_rate(dpll3_m2_ck, rate); | 330 | v = clk_set_rate(dpll3_m2_ck, rate); |
331 | if (v) | 331 | if (v) |
332 | pr_err("dpll3_m2_clk rate change failed: %d\n", v); | 332 | pr_err("dpll3_m2_clk rate change failed: %d\n", v); |
333 | 333 | ||
334 | clk_put(dpll3_m2_ck); | 334 | clk_put(dpll3_m2_ck); |
335 | 335 | ||
336 | return v; | 336 | return v; |
337 | } | 337 | } |
338 | 338 | ||
339 | static int _set_hwmod_postsetup_state(struct omap_hwmod *oh, void *data) | 339 | static int _set_hwmod_postsetup_state(struct omap_hwmod *oh, void *data) |
340 | { | 340 | { |
341 | return omap_hwmod_set_postsetup_state(oh, *(u8 *)data); | 341 | return omap_hwmod_set_postsetup_state(oh, *(u8 *)data); |
342 | } | 342 | } |
343 | 343 | ||
344 | /* See irq.c, omap4-common.c and entry-macro.S */ | 344 | /* See irq.c, omap4-common.c and entry-macro.S */ |
345 | void __iomem *omap_irq_base; | 345 | void __iomem *omap_irq_base; |
346 | 346 | ||
347 | static void __init omap_common_init_early(void) | 347 | static void __init omap_common_init_early(void) |
348 | { | 348 | { |
349 | omap2_check_revision(); | 349 | omap2_check_revision(); |
350 | omap_ioremap_init(); | 350 | omap_ioremap_init(); |
351 | } | 351 | } |
352 | 352 | ||
353 | static void __init omap_hwmod_init_postsetup(void) | 353 | static void __init omap_hwmod_init_postsetup(void) |
354 | { | 354 | { |
355 | u8 postsetup_state; | 355 | u8 postsetup_state; |
356 | 356 | ||
357 | /* Set the default postsetup state for all hwmods */ | 357 | /* Set the default postsetup state for all hwmods */ |
358 | #ifdef CONFIG_PM_RUNTIME | 358 | #ifdef CONFIG_PM_RUNTIME |
359 | postsetup_state = _HWMOD_STATE_IDLE; | 359 | postsetup_state = _HWMOD_STATE_IDLE; |
360 | #else | 360 | #else |
361 | postsetup_state = _HWMOD_STATE_ENABLED; | 361 | postsetup_state = _HWMOD_STATE_ENABLED; |
362 | #endif | 362 | #endif |
363 | omap_hwmod_for_each(_set_hwmod_postsetup_state, &postsetup_state); | 363 | omap_hwmod_for_each(_set_hwmod_postsetup_state, &postsetup_state); |
364 | 364 | ||
365 | /* | 365 | /* |
366 | * Set the default postsetup state for unusual modules (like | 366 | * Set the default postsetup state for unusual modules (like |
367 | * MPU WDT). | 367 | * MPU WDT). |
368 | * | 368 | * |
369 | * The postsetup_state is not actually used until | 369 | * The postsetup_state is not actually used until |
370 | * omap_hwmod_late_init(), so boards that desire full watchdog | 370 | * omap_hwmod_late_init(), so boards that desire full watchdog |
371 | * coverage of kernel initialization can reprogram the | 371 | * coverage of kernel initialization can reprogram the |
372 | * postsetup_state between the calls to | 372 | * postsetup_state between the calls to |
373 | * omap2_init_common_infra() and omap_sdrc_init(). | 373 | * omap2_init_common_infra() and omap_sdrc_init(). |
374 | * | 374 | * |
375 | * XXX ideally we could detect whether the MPU WDT was currently | 375 | * XXX ideally we could detect whether the MPU WDT was currently |
376 | * enabled here and make this conditional | 376 | * enabled here and make this conditional |
377 | */ | 377 | */ |
378 | postsetup_state = _HWMOD_STATE_DISABLED; | 378 | postsetup_state = _HWMOD_STATE_DISABLED; |
379 | omap_hwmod_for_each_by_class("wd_timer", | 379 | omap_hwmod_for_each_by_class("wd_timer", |
380 | _set_hwmod_postsetup_state, | 380 | _set_hwmod_postsetup_state, |
381 | &postsetup_state); | 381 | &postsetup_state); |
382 | 382 | ||
383 | omap_pm_if_early_init(); | 383 | omap_pm_if_early_init(); |
384 | } | 384 | } |
385 | 385 | ||
386 | #ifdef CONFIG_SOC_OMAP2420 | 386 | #ifdef CONFIG_SOC_OMAP2420 |
387 | void __init omap2420_init_early(void) | 387 | void __init omap2420_init_early(void) |
388 | { | 388 | { |
389 | omap2_set_globals_242x(); | 389 | omap2_set_globals_242x(); |
390 | omap_common_init_early(); | 390 | omap_common_init_early(); |
391 | omap2xxx_voltagedomains_init(); | 391 | omap2xxx_voltagedomains_init(); |
392 | omap242x_powerdomains_init(); | 392 | omap242x_powerdomains_init(); |
393 | omap242x_clockdomains_init(); | 393 | omap242x_clockdomains_init(); |
394 | omap2420_hwmod_init(); | 394 | omap2420_hwmod_init(); |
395 | omap_hwmod_init_postsetup(); | 395 | omap_hwmod_init_postsetup(); |
396 | omap2420_clk_init(); | 396 | omap2420_clk_init(); |
397 | } | 397 | } |
398 | #endif | 398 | #endif |
399 | 399 | ||
400 | #ifdef CONFIG_SOC_OMAP2430 | 400 | #ifdef CONFIG_SOC_OMAP2430 |
401 | void __init omap2430_init_early(void) | 401 | void __init omap2430_init_early(void) |
402 | { | 402 | { |
403 | omap2_set_globals_243x(); | 403 | omap2_set_globals_243x(); |
404 | omap_common_init_early(); | 404 | omap_common_init_early(); |
405 | omap2xxx_voltagedomains_init(); | 405 | omap2xxx_voltagedomains_init(); |
406 | omap243x_powerdomains_init(); | 406 | omap243x_powerdomains_init(); |
407 | omap243x_clockdomains_init(); | 407 | omap243x_clockdomains_init(); |
408 | omap2430_hwmod_init(); | 408 | omap2430_hwmod_init(); |
409 | omap_hwmod_init_postsetup(); | 409 | omap_hwmod_init_postsetup(); |
410 | omap2430_clk_init(); | 410 | omap2430_clk_init(); |
411 | } | 411 | } |
412 | #endif | 412 | #endif |
413 | 413 | ||
414 | #ifdef CONFIG_ARCH_OMAP3 | 414 | #ifdef CONFIG_ARCH_OMAP3 |
415 | /* | 415 | /* |
416 | * Currently only board-omap3beagle.c should call this because of the | 416 | * Currently only board-omap3beagle.c should call this because of the |
417 | * same machine_id for 34xx and 36xx beagle.. Will get fixed with DT. | 417 | * same machine_id for 34xx and 36xx beagle.. Will get fixed with DT. |
418 | */ | 418 | */ |
419 | void __init omap3_init_early(void) | 419 | void __init omap3_init_early(void) |
420 | { | 420 | { |
421 | omap2_set_globals_3xxx(); | 421 | omap2_set_globals_3xxx(); |
422 | omap_common_init_early(); | 422 | omap_common_init_early(); |
423 | omap3xxx_voltagedomains_init(); | 423 | omap3xxx_voltagedomains_init(); |
424 | omap3xxx_powerdomains_init(); | 424 | omap3xxx_powerdomains_init(); |
425 | omap3xxx_clockdomains_init(); | 425 | omap3xxx_clockdomains_init(); |
426 | omap3xxx_hwmod_init(); | 426 | omap3xxx_hwmod_init(); |
427 | omap_hwmod_init_postsetup(); | 427 | omap_hwmod_init_postsetup(); |
428 | omap3xxx_clk_init(); | 428 | omap3xxx_clk_init(); |
429 | } | 429 | } |
430 | 430 | ||
431 | void __init omap3430_init_early(void) | 431 | void __init omap3430_init_early(void) |
432 | { | 432 | { |
433 | omap3_init_early(); | 433 | omap3_init_early(); |
434 | } | 434 | } |
435 | 435 | ||
436 | void __init omap35xx_init_early(void) | 436 | void __init omap35xx_init_early(void) |
437 | { | 437 | { |
438 | omap3_init_early(); | 438 | omap3_init_early(); |
439 | } | 439 | } |
440 | 440 | ||
441 | void __init omap3630_init_early(void) | 441 | void __init omap3630_init_early(void) |
442 | { | 442 | { |
443 | omap3_init_early(); | 443 | omap3_init_early(); |
444 | } | 444 | } |
445 | 445 | ||
446 | void __init am35xx_init_early(void) | 446 | void __init am35xx_init_early(void) |
447 | { | 447 | { |
448 | omap3_init_early(); | 448 | omap3_init_early(); |
449 | } | 449 | } |
450 | 450 | ||
451 | void __init ti816x_init_early(void) | 451 | void __init ti816x_init_early(void) |
452 | { | 452 | { |
453 | omap2_set_globals_ti816x(); | 453 | omap2_set_globals_ti816x(); |
454 | omap_common_init_early(); | 454 | omap_common_init_early(); |
455 | omap3xxx_voltagedomains_init(); | 455 | omap3xxx_voltagedomains_init(); |
456 | omap3xxx_powerdomains_init(); | 456 | omap3xxx_powerdomains_init(); |
457 | omap3xxx_clockdomains_init(); | 457 | omap3xxx_clockdomains_init(); |
458 | omap3xxx_hwmod_init(); | 458 | omap3xxx_hwmod_init(); |
459 | omap_hwmod_init_postsetup(); | 459 | omap_hwmod_init_postsetup(); |
460 | omap3xxx_clk_init(); | 460 | omap3xxx_clk_init(); |
461 | } | 461 | } |
462 | #endif | 462 | #endif |
463 | 463 | ||
464 | #ifdef CONFIG_ARCH_OMAP4 | 464 | #ifdef CONFIG_ARCH_OMAP4 |
465 | void __init omap4430_init_early(void) | 465 | void __init omap4430_init_early(void) |
466 | { | 466 | { |
467 | omap2_set_globals_443x(); | 467 | omap2_set_globals_443x(); |
468 | omap_common_init_early(); | 468 | omap_common_init_early(); |
469 | omap44xx_voltagedomains_init(); | 469 | omap44xx_voltagedomains_init(); |
470 | omap44xx_powerdomains_init(); | 470 | omap44xx_powerdomains_init(); |
471 | omap44xx_clockdomains_init(); | 471 | omap44xx_clockdomains_init(); |
472 | omap44xx_hwmod_init(); | 472 | omap44xx_hwmod_init(); |
473 | omap_hwmod_init_postsetup(); | 473 | omap_hwmod_init_postsetup(); |
474 | omap4xxx_clk_init(); | 474 | omap4xxx_clk_init(); |
475 | } | 475 | } |
476 | #endif | 476 | #endif |
477 | 477 | ||
478 | void __init am335x_init_early(void) | 478 | void __init am335x_init_early(void) |
479 | { | 479 | { |
480 | omap2_set_globals_am33xx(); | 480 | omap2_set_globals_am33xx(); |
481 | omap_common_init_early(); | 481 | omap_common_init_early(); |
482 | am33xx_voltagedomains_init(); | 482 | am33xx_voltagedomains_init(); |
483 | am33xx_powerdomains_init(); | 483 | am33xx_powerdomains_init(); |
484 | am33xx_clockdomains_init(); | 484 | am33xx_clockdomains_init(); |
485 | am33xx_hwmod_init(); | 485 | am33xx_hwmod_init(); |
486 | omap_hwmod_init_postsetup(); | 486 | omap_hwmod_init_postsetup(); |
487 | omap3xxx_clk_init(); | 487 | omap3xxx_clk_init(); |
488 | } | 488 | } |
489 | 489 | ||
490 | void __init omap_sdrc_init(struct omap_sdrc_params *sdrc_cs0, | 490 | void __init omap_sdrc_init(struct omap_sdrc_params *sdrc_cs0, |
491 | struct omap_sdrc_params *sdrc_cs1) | 491 | struct omap_sdrc_params *sdrc_cs1) |
492 | { | 492 | { |
493 | omap_sram_init(); | 493 | omap_sram_init(); |
494 | 494 | ||
495 | if (cpu_is_omap24xx() || omap3_has_sdrc()) { | 495 | if (cpu_is_omap24xx() || omap3_has_sdrc()) { |
496 | omap2_sdrc_init(sdrc_cs0, sdrc_cs1); | 496 | omap2_sdrc_init(sdrc_cs0, sdrc_cs1); |
497 | _omap2_init_reprogram_sdrc(); | 497 | _omap2_init_reprogram_sdrc(); |
498 | } | 498 | } |
499 | } | 499 | } |
500 | 500 | ||
501 | /* | 501 | /* |
502 | * NOTE: Please use ioremap + __raw_read/write where possible instead of these | 502 | * NOTE: Please use ioremap + __raw_read/write where possible instead of these |
503 | */ | 503 | */ |
504 | 504 | ||
505 | u8 omap_readb(u32 pa) | 505 | u8 omap_readb(u32 pa) |
506 | { | 506 | { |
507 | return __raw_readb(OMAP2_L4_IO_ADDRESS(pa)); | 507 | return __raw_readb(OMAP2_L4_IO_ADDRESS(pa)); |
508 | } | 508 | } |
509 | EXPORT_SYMBOL(omap_readb); | 509 | EXPORT_SYMBOL(omap_readb); |
510 | 510 | ||
511 | u16 omap_readw(u32 pa) | 511 | u16 omap_readw(u32 pa) |
512 | { | 512 | { |
513 | return __raw_readw(OMAP2_L4_IO_ADDRESS(pa)); | 513 | return __raw_readw(OMAP2_L4_IO_ADDRESS(pa)); |
514 | } | 514 | } |
515 | EXPORT_SYMBOL(omap_readw); | 515 | EXPORT_SYMBOL(omap_readw); |
516 | 516 | ||
517 | u32 omap_readl(u32 pa) | 517 | u32 omap_readl(u32 pa) |
518 | { | 518 | { |
519 | return __raw_readl(OMAP2_L4_IO_ADDRESS(pa)); | 519 | return __raw_readl(OMAP2_L4_IO_ADDRESS(pa)); |
520 | } | 520 | } |
521 | EXPORT_SYMBOL(omap_readl); | 521 | EXPORT_SYMBOL(omap_readl); |
522 | 522 | ||
523 | void omap_writeb(u8 v, u32 pa) | 523 | void omap_writeb(u8 v, u32 pa) |
524 | { | 524 | { |
525 | __raw_writeb(v, OMAP2_L4_IO_ADDRESS(pa)); | 525 | __raw_writeb(v, OMAP2_L4_IO_ADDRESS(pa)); |
526 | } | 526 | } |
527 | EXPORT_SYMBOL(omap_writeb); | 527 | EXPORT_SYMBOL(omap_writeb); |
528 | 528 | ||
529 | void omap_writew(u16 v, u32 pa) | 529 | void omap_writew(u16 v, u32 pa) |
530 | { | 530 | { |
531 | __raw_writew(v, OMAP2_L4_IO_ADDRESS(pa)); | 531 | __raw_writew(v, OMAP2_L4_IO_ADDRESS(pa)); |
532 | } | 532 | } |
533 | EXPORT_SYMBOL(omap_writew); | 533 | EXPORT_SYMBOL(omap_writew); |
534 | 534 | ||
535 | void omap_writel(u32 v, u32 pa) | 535 | void omap_writel(u32 v, u32 pa) |
536 | { | 536 | { |
537 | __raw_writel(v, OMAP2_L4_IO_ADDRESS(pa)); | 537 | __raw_writel(v, OMAP2_L4_IO_ADDRESS(pa)); |
538 | } | 538 | } |
539 | EXPORT_SYMBOL(omap_writel); | 539 | EXPORT_SYMBOL(omap_writel); |
540 | 540 |
arch/arm/mach-omap2/omap_opp_data.h
1 | /* | 1 | /* |
2 | * OMAP SoC specific OPP Data helpers | 2 | * OMAP SoC specific OPP Data helpers |
3 | * | 3 | * |
4 | * Copyright (C) 2009-2010 Texas Instruments Incorporated - http://www.ti.com/ | 4 | * Copyright (C) 2009-2010 Texas Instruments Incorporated - http://www.ti.com/ |
5 | * Nishanth Menon | 5 | * Nishanth Menon |
6 | * Kevin Hilman | 6 | * Kevin Hilman |
7 | * Copyright (C) 2010 Nokia Corporation. | 7 | * Copyright (C) 2010 Nokia Corporation. |
8 | * Eduardo Valentin | 8 | * Eduardo Valentin |
9 | * | 9 | * |
10 | * This program is free software; you can redistribute it and/or modify | 10 | * This program is free software; you can redistribute it and/or modify |
11 | * it under the terms of the GNU General Public License version 2 as | 11 | * it under the terms of the GNU General Public License version 2 as |
12 | * published by the Free Software Foundation. | 12 | * published by the Free Software Foundation. |
13 | * | 13 | * |
14 | * This program is distributed "as is" WITHOUT ANY WARRANTY of any | 14 | * This program is distributed "as is" WITHOUT ANY WARRANTY of any |
15 | * kind, whether express or implied; without even the implied warranty | 15 | * kind, whether express or implied; without even the implied warranty |
16 | * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 16 | * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
17 | * GNU General Public License for more details. | 17 | * GNU General Public License for more details. |
18 | */ | 18 | */ |
19 | #ifndef __ARCH_ARM_MACH_OMAP2_OMAP_OPP_DATA_H | 19 | #ifndef __ARCH_ARM_MACH_OMAP2_OMAP_OPP_DATA_H |
20 | #define __ARCH_ARM_MACH_OMAP2_OMAP_OPP_DATA_H | 20 | #define __ARCH_ARM_MACH_OMAP2_OMAP_OPP_DATA_H |
21 | 21 | ||
22 | #include <plat/omap_hwmod.h> | 22 | #include <plat/omap_hwmod.h> |
23 | #include <plat/voltage.h> | ||
23 | 24 | ||
24 | #include "voltage.h" | ||
25 | 25 | ||
26 | /* | 26 | /* |
27 | * *BIG FAT WARNING*: | 27 | * *BIG FAT WARNING*: |
28 | * USE the following ONLY in opp data initialization common to an SoC. | 28 | * USE the following ONLY in opp data initialization common to an SoC. |
29 | * DO NOT USE these in board files/pm core etc. | 29 | * DO NOT USE these in board files/pm core etc. |
30 | */ | 30 | */ |
31 | 31 | ||
32 | /** | 32 | /** |
33 | * struct omap_opp_def - OMAP OPP Definition | 33 | * struct omap_opp_def - OMAP OPP Definition |
34 | * @hwmod_name: Name of the hwmod for this domain | 34 | * @hwmod_name: Name of the hwmod for this domain |
35 | * @freq: Frequency in hertz corresponding to this OPP | 35 | * @freq: Frequency in hertz corresponding to this OPP |
36 | * @u_volt: Nominal voltage in microvolts corresponding to this OPP | 36 | * @u_volt: Nominal voltage in microvolts corresponding to this OPP |
37 | * @default_available: True/false - is this OPP available by default | 37 | * @default_available: True/false - is this OPP available by default |
38 | * | 38 | * |
39 | * OMAP SOCs have a standard set of tuples consisting of frequency and voltage | 39 | * OMAP SOCs have a standard set of tuples consisting of frequency and voltage |
40 | * pairs that the device will support per voltage domain. This is called | 40 | * pairs that the device will support per voltage domain. This is called |
41 | * Operating Points or OPP. The actual definitions of OMAP Operating Points | 41 | * Operating Points or OPP. The actual definitions of OMAP Operating Points |
42 | * varies over silicon within the same family of devices. For a specific | 42 | * varies over silicon within the same family of devices. For a specific |
43 | * domain, you can have a set of {frequency, voltage} pairs and this is denoted | 43 | * domain, you can have a set of {frequency, voltage} pairs and this is denoted |
44 | * by an array of omap_opp_def. As the kernel boots and more information is | 44 | * by an array of omap_opp_def. As the kernel boots and more information is |
45 | * available, a set of these are activated based on the precise nature of | 45 | * available, a set of these are activated based on the precise nature of |
46 | * device the kernel boots up on. It is interesting to remember that each IP | 46 | * device the kernel boots up on. It is interesting to remember that each IP |
47 | * which belongs to a voltage domain may define their own set of OPPs on top | 47 | * which belongs to a voltage domain may define their own set of OPPs on top |
48 | * of this - but this is handled by the appropriate driver. | 48 | * of this - but this is handled by the appropriate driver. |
49 | */ | 49 | */ |
50 | struct omap_opp_def { | 50 | struct omap_opp_def { |
51 | char *hwmod_name; | 51 | char *hwmod_name; |
52 | char *voltdm_name; | 52 | char *voltdm_name; |
53 | char *clk_name; | 53 | char *clk_name; |
54 | 54 | ||
55 | unsigned long freq; | 55 | unsigned long freq; |
56 | unsigned long u_volt; | 56 | unsigned long u_volt; |
57 | 57 | ||
58 | bool default_available; | 58 | bool default_available; |
59 | }; | 59 | }; |
60 | 60 | ||
61 | /* | 61 | /* |
62 | * Initialization wrapper used to define an OPP for OMAP variants. | 62 | * Initialization wrapper used to define an OPP for OMAP variants. |
63 | */ | 63 | */ |
64 | #define OPP_INITIALIZER(_hwmod_name, _clk_name, _voltdm_name, _enabled, _freq, _uv) \ | 64 | #define OPP_INITIALIZER(_hwmod_name, _clk_name, _voltdm_name, _enabled, _freq, _uv) \ |
65 | { \ | 65 | { \ |
66 | .hwmod_name = _hwmod_name, \ | 66 | .hwmod_name = _hwmod_name, \ |
67 | .clk_name = _clk_name, \ | 67 | .clk_name = _clk_name, \ |
68 | .voltdm_name = _voltdm_name, \ | 68 | .voltdm_name = _voltdm_name, \ |
69 | .default_available = _enabled, \ | 69 | .default_available = _enabled, \ |
70 | .freq = _freq, \ | 70 | .freq = _freq, \ |
71 | .u_volt = _uv, \ | 71 | .u_volt = _uv, \ |
72 | } | 72 | } |
73 | 73 | ||
74 | /* | 74 | /* |
75 | * Initialization wrapper used to define SmartReflex process data | 75 | * Initialization wrapper used to define SmartReflex process data |
76 | * XXX Is this needed? Just use C99 initializers in data files? | 76 | * XXX Is this needed? Just use C99 initializers in data files? |
77 | */ | 77 | */ |
78 | #define VOLT_DATA_DEFINE(_v_nom, _efuse_offs, _errminlimit, _errgain) \ | 78 | #define VOLT_DATA_DEFINE(_v_nom, _efuse_offs, _errminlimit, _errgain) \ |
79 | { \ | 79 | { \ |
80 | .volt_nominal = _v_nom, \ | 80 | .volt_nominal = _v_nom, \ |
81 | .sr_efuse_offs = _efuse_offs, \ | 81 | .sr_efuse_offs = _efuse_offs, \ |
82 | .sr_errminlimit = _errminlimit, \ | 82 | .sr_errminlimit = _errminlimit, \ |
83 | .vp_errgain = _errgain \ | 83 | .vp_errgain = _errgain \ |
84 | } | 84 | } |
85 | 85 | ||
86 | /* Use this to initialize the default table */ | 86 | /* Use this to initialize the default table */ |
87 | extern int __init omap_init_opp_table(struct omap_opp_def *opp_def, | 87 | extern int __init omap_init_opp_table(struct omap_opp_def *opp_def, |
88 | u32 opp_def_size); | 88 | u32 opp_def_size); |
89 | 89 | ||
90 | 90 | ||
91 | extern struct omap_volt_data omap34xx_vddmpu_volt_data[]; | 91 | extern struct omap_volt_data omap34xx_vddmpu_volt_data[]; |
92 | extern struct omap_volt_data omap34xx_vddcore_volt_data[]; | 92 | extern struct omap_volt_data omap34xx_vddcore_volt_data[]; |
93 | extern struct omap_vdd_dep_info omap34xx_vddmpu_dep_info[]; | 93 | extern struct omap_vdd_dep_info omap34xx_vddmpu_dep_info[]; |
94 | extern struct omap_volt_data omap36xx_vddmpu_volt_data[]; | 94 | extern struct omap_volt_data omap36xx_vddmpu_volt_data[]; |
95 | extern struct omap_volt_data omap36xx_vddcore_volt_data[]; | 95 | extern struct omap_volt_data omap36xx_vddcore_volt_data[]; |
96 | extern struct omap_vdd_dep_info omap36xx_vddmpu_dep_info[]; | 96 | extern struct omap_vdd_dep_info omap36xx_vddmpu_dep_info[]; |
97 | 97 | ||
98 | extern struct omap_volt_data omap44xx_vdd_mpu_volt_data[]; | 98 | extern struct omap_volt_data omap44xx_vdd_mpu_volt_data[]; |
99 | extern struct omap_volt_data omap44xx_vdd_iva_volt_data[]; | 99 | extern struct omap_volt_data omap44xx_vdd_iva_volt_data[]; |
100 | extern struct omap_volt_data omap44xx_vdd_core_volt_data[]; | 100 | extern struct omap_volt_data omap44xx_vdd_core_volt_data[]; |
101 | 101 | ||
102 | extern struct omap_vdd_dep_info omap443x_vddmpu_dep_info[]; | 102 | extern struct omap_vdd_dep_info omap443x_vddmpu_dep_info[]; |
103 | extern struct omap_vdd_dep_info omap443x_vddiva_dep_info[]; | 103 | extern struct omap_vdd_dep_info omap443x_vddiva_dep_info[]; |
104 | 104 | ||
105 | #endif /* __ARCH_ARM_MACH_OMAP2_OMAP_OPP_DATA_H */ | 105 | #endif /* __ARCH_ARM_MACH_OMAP2_OMAP_OPP_DATA_H */ |
arch/arm/mach-omap2/omap_twl.c
1 | /** | 1 | /** |
2 | * OMAP and TWL PMIC specific intializations. | 2 | * OMAP and TWL PMIC specific intializations. |
3 | * | 3 | * |
4 | * Copyright (C) 2010 Texas Instruments Incorporated. | 4 | * Copyright (C) 2010 Texas Instruments Incorporated. |
5 | * Thara Gopinath | 5 | * Thara Gopinath |
6 | * Copyright (C) 2009 Texas Instruments Incorporated. | 6 | * Copyright (C) 2009 Texas Instruments Incorporated. |
7 | * Nishanth Menon | 7 | * Nishanth Menon |
8 | * Copyright (C) 2009 Nokia Corporation | 8 | * Copyright (C) 2009 Nokia Corporation |
9 | * Paul Walmsley | 9 | * Paul Walmsley |
10 | * | 10 | * |
11 | * This program is free software; you can redistribute it and/or modify | 11 | * This program is free software; you can redistribute it and/or modify |
12 | * it under the terms of the GNU General Public License version 2 as | 12 | * it under the terms of the GNU General Public License version 2 as |
13 | * published by the Free Software Foundation. | 13 | * published by the Free Software Foundation. |
14 | */ | 14 | */ |
15 | 15 | ||
16 | #include <linux/err.h> | 16 | #include <linux/err.h> |
17 | #include <linux/io.h> | 17 | #include <linux/io.h> |
18 | #include <linux/kernel.h> | 18 | #include <linux/kernel.h> |
19 | #include <linux/i2c/twl.h> | 19 | #include <linux/i2c/twl.h> |
20 | #include <plat/voltage.h> | ||
20 | 21 | ||
21 | #include "voltage.h" | ||
22 | 22 | ||
23 | #include "pm.h" | 23 | #include "pm.h" |
24 | 24 | ||
25 | #define OMAP3_SRI2C_SLAVE_ADDR 0x12 | 25 | #define OMAP3_SRI2C_SLAVE_ADDR 0x12 |
26 | #define OMAP3_VDD_MPU_SR_CONTROL_REG 0x00 | 26 | #define OMAP3_VDD_MPU_SR_CONTROL_REG 0x00 |
27 | #define OMAP3_VDD_CORE_SR_CONTROL_REG 0x01 | 27 | #define OMAP3_VDD_CORE_SR_CONTROL_REG 0x01 |
28 | #define OMAP3_VP_CONFIG_ERROROFFSET 0x00 | 28 | #define OMAP3_VP_CONFIG_ERROROFFSET 0x00 |
29 | #define OMAP3_VP_VSTEPMIN_VSTEPMIN 0x1 | 29 | #define OMAP3_VP_VSTEPMIN_VSTEPMIN 0x1 |
30 | #define OMAP3_VP_VSTEPMAX_VSTEPMAX 0x04 | 30 | #define OMAP3_VP_VSTEPMAX_VSTEPMAX 0x04 |
31 | #define OMAP3_VP_VLIMITTO_TIMEOUT_US 200 | 31 | #define OMAP3_VP_VLIMITTO_TIMEOUT_US 200 |
32 | 32 | ||
33 | #define OMAP3430_VP1_VLIMITTO_VDDMIN 0x14 | 33 | #define OMAP3430_VP1_VLIMITTO_VDDMIN 0x14 |
34 | #define OMAP3430_VP1_VLIMITTO_VDDMAX 0x42 | 34 | #define OMAP3430_VP1_VLIMITTO_VDDMAX 0x42 |
35 | #define OMAP3430_VP2_VLIMITTO_VDDMIN 0x18 | 35 | #define OMAP3430_VP2_VLIMITTO_VDDMIN 0x18 |
36 | #define OMAP3430_VP2_VLIMITTO_VDDMAX 0x2c | 36 | #define OMAP3430_VP2_VLIMITTO_VDDMAX 0x2c |
37 | 37 | ||
38 | #define OMAP3630_VP1_VLIMITTO_VDDMIN 0x18 | 38 | #define OMAP3630_VP1_VLIMITTO_VDDMIN 0x18 |
39 | #define OMAP3630_VP1_VLIMITTO_VDDMAX 0x3c | 39 | #define OMAP3630_VP1_VLIMITTO_VDDMAX 0x3c |
40 | #define OMAP3630_VP2_VLIMITTO_VDDMIN 0x18 | 40 | #define OMAP3630_VP2_VLIMITTO_VDDMIN 0x18 |
41 | #define OMAP3630_VP2_VLIMITTO_VDDMAX 0x30 | 41 | #define OMAP3630_VP2_VLIMITTO_VDDMAX 0x30 |
42 | 42 | ||
43 | #define OMAP4_SRI2C_SLAVE_ADDR 0x12 | 43 | #define OMAP4_SRI2C_SLAVE_ADDR 0x12 |
44 | #define OMAP4_VDD_MPU_SR_VOLT_REG 0x55 | 44 | #define OMAP4_VDD_MPU_SR_VOLT_REG 0x55 |
45 | #define OMAP4_VDD_MPU_SR_CMD_REG 0x56 | 45 | #define OMAP4_VDD_MPU_SR_CMD_REG 0x56 |
46 | #define OMAP4_VDD_IVA_SR_VOLT_REG 0x5B | 46 | #define OMAP4_VDD_IVA_SR_VOLT_REG 0x5B |
47 | #define OMAP4_VDD_IVA_SR_CMD_REG 0x5C | 47 | #define OMAP4_VDD_IVA_SR_CMD_REG 0x5C |
48 | #define OMAP4_VDD_CORE_SR_VOLT_REG 0x61 | 48 | #define OMAP4_VDD_CORE_SR_VOLT_REG 0x61 |
49 | #define OMAP4_VDD_CORE_SR_CMD_REG 0x62 | 49 | #define OMAP4_VDD_CORE_SR_CMD_REG 0x62 |
50 | 50 | ||
51 | #define OMAP4_VP_CONFIG_ERROROFFSET 0x00 | 51 | #define OMAP4_VP_CONFIG_ERROROFFSET 0x00 |
52 | #define OMAP4_VP_VSTEPMIN_VSTEPMIN 0x01 | 52 | #define OMAP4_VP_VSTEPMIN_VSTEPMIN 0x01 |
53 | #define OMAP4_VP_VSTEPMAX_VSTEPMAX 0x04 | 53 | #define OMAP4_VP_VSTEPMAX_VSTEPMAX 0x04 |
54 | #define OMAP4_VP_VLIMITTO_TIMEOUT_US 200 | 54 | #define OMAP4_VP_VLIMITTO_TIMEOUT_US 200 |
55 | 55 | ||
56 | #define OMAP4_VP_MPU_VLIMITTO_VDDMIN 0xA | 56 | #define OMAP4_VP_MPU_VLIMITTO_VDDMIN 0xA |
57 | #define OMAP4_VP_MPU_VLIMITTO_VDDMAX 0x39 | 57 | #define OMAP4_VP_MPU_VLIMITTO_VDDMAX 0x39 |
58 | #define OMAP4_VP_IVA_VLIMITTO_VDDMIN 0xA | 58 | #define OMAP4_VP_IVA_VLIMITTO_VDDMIN 0xA |
59 | #define OMAP4_VP_IVA_VLIMITTO_VDDMAX 0x2D | 59 | #define OMAP4_VP_IVA_VLIMITTO_VDDMAX 0x2D |
60 | #define OMAP4_VP_CORE_VLIMITTO_VDDMIN 0xA | 60 | #define OMAP4_VP_CORE_VLIMITTO_VDDMIN 0xA |
61 | #define OMAP4_VP_CORE_VLIMITTO_VDDMAX 0x28 | 61 | #define OMAP4_VP_CORE_VLIMITTO_VDDMAX 0x28 |
62 | 62 | ||
63 | static bool is_offset_valid; | 63 | static bool is_offset_valid; |
64 | static u8 smps_offset; | 64 | static u8 smps_offset; |
65 | /* | 65 | /* |
66 | * Flag to ensure Smartreflex bit in TWL | 66 | * Flag to ensure Smartreflex bit in TWL |
67 | * being cleared in board file is not overwritten. | 67 | * being cleared in board file is not overwritten. |
68 | */ | 68 | */ |
69 | static bool __initdata twl_sr_enable_autoinit; | 69 | static bool __initdata twl_sr_enable_autoinit; |
70 | 70 | ||
71 | #define TWL4030_DCDC_GLOBAL_CFG 0x06 | 71 | #define TWL4030_DCDC_GLOBAL_CFG 0x06 |
72 | #define REG_SMPS_OFFSET 0xE0 | 72 | #define REG_SMPS_OFFSET 0xE0 |
73 | #define SMARTREFLEX_ENABLE BIT(3) | 73 | #define SMARTREFLEX_ENABLE BIT(3) |
74 | 74 | ||
75 | static unsigned long twl4030_vsel_to_uv(const u8 vsel) | 75 | static unsigned long twl4030_vsel_to_uv(const u8 vsel) |
76 | { | 76 | { |
77 | return (((vsel * 125) + 6000)) * 100; | 77 | return (((vsel * 125) + 6000)) * 100; |
78 | } | 78 | } |
79 | 79 | ||
80 | static u8 twl4030_uv_to_vsel(unsigned long uv) | 80 | static u8 twl4030_uv_to_vsel(unsigned long uv) |
81 | { | 81 | { |
82 | return DIV_ROUND_UP(uv - 600000, 12500); | 82 | return DIV_ROUND_UP(uv - 600000, 12500); |
83 | } | 83 | } |
84 | 84 | ||
85 | static unsigned long twl6030_vsel_to_uv(const u8 vsel) | 85 | static unsigned long twl6030_vsel_to_uv(const u8 vsel) |
86 | { | 86 | { |
87 | /* | 87 | /* |
88 | * In TWL6030 depending on the value of SMPS_OFFSET | 88 | * In TWL6030 depending on the value of SMPS_OFFSET |
89 | * efuse register the voltage range supported in | 89 | * efuse register the voltage range supported in |
90 | * standard mode can be either between 0.6V - 1.3V or | 90 | * standard mode can be either between 0.6V - 1.3V or |
91 | * 0.7V - 1.4V. In TWL6030 ES1.0 SMPS_OFFSET efuse | 91 | * 0.7V - 1.4V. In TWL6030 ES1.0 SMPS_OFFSET efuse |
92 | * is programmed to all 0's where as starting from | 92 | * is programmed to all 0's where as starting from |
93 | * TWL6030 ES1.1 the efuse is programmed to 1 | 93 | * TWL6030 ES1.1 the efuse is programmed to 1 |
94 | */ | 94 | */ |
95 | if (!is_offset_valid) { | 95 | if (!is_offset_valid) { |
96 | twl_i2c_read_u8(TWL6030_MODULE_ID0, &smps_offset, | 96 | twl_i2c_read_u8(TWL6030_MODULE_ID0, &smps_offset, |
97 | REG_SMPS_OFFSET); | 97 | REG_SMPS_OFFSET); |
98 | is_offset_valid = true; | 98 | is_offset_valid = true; |
99 | } | 99 | } |
100 | 100 | ||
101 | if (!vsel) | 101 | if (!vsel) |
102 | return 0; | 102 | return 0; |
103 | /* | 103 | /* |
104 | * There is no specific formula for voltage to vsel | 104 | * There is no specific formula for voltage to vsel |
105 | * conversion above 1.3V. There are special hardcoded | 105 | * conversion above 1.3V. There are special hardcoded |
106 | * values for voltages above 1.3V. Currently we are | 106 | * values for voltages above 1.3V. Currently we are |
107 | * hardcoding only for 1.35 V which is used for 1GH OPP for | 107 | * hardcoding only for 1.35 V which is used for 1GH OPP for |
108 | * OMAP4430. | 108 | * OMAP4430. |
109 | */ | 109 | */ |
110 | if (vsel == 0x3A) | 110 | if (vsel == 0x3A) |
111 | return 1350000; | 111 | return 1350000; |
112 | 112 | ||
113 | if (smps_offset & 0x8) | 113 | if (smps_offset & 0x8) |
114 | return ((((vsel - 1) * 1266) + 70900)) * 10; | 114 | return ((((vsel - 1) * 1266) + 70900)) * 10; |
115 | else | 115 | else |
116 | return ((((vsel - 1) * 1266) + 60770)) * 10; | 116 | return ((((vsel - 1) * 1266) + 60770)) * 10; |
117 | } | 117 | } |
118 | 118 | ||
119 | static u8 twl6030_uv_to_vsel(unsigned long uv) | 119 | static u8 twl6030_uv_to_vsel(unsigned long uv) |
120 | { | 120 | { |
121 | /* | 121 | /* |
122 | * In TWL6030 depending on the value of SMPS_OFFSET | 122 | * In TWL6030 depending on the value of SMPS_OFFSET |
123 | * efuse register the voltage range supported in | 123 | * efuse register the voltage range supported in |
124 | * standard mode can be either between 0.6V - 1.3V or | 124 | * standard mode can be either between 0.6V - 1.3V or |
125 | * 0.7V - 1.4V. In TWL6030 ES1.0 SMPS_OFFSET efuse | 125 | * 0.7V - 1.4V. In TWL6030 ES1.0 SMPS_OFFSET efuse |
126 | * is programmed to all 0's where as starting from | 126 | * is programmed to all 0's where as starting from |
127 | * TWL6030 ES1.1 the efuse is programmed to 1 | 127 | * TWL6030 ES1.1 the efuse is programmed to 1 |
128 | */ | 128 | */ |
129 | if (!is_offset_valid) { | 129 | if (!is_offset_valid) { |
130 | twl_i2c_read_u8(TWL6030_MODULE_ID0, &smps_offset, | 130 | twl_i2c_read_u8(TWL6030_MODULE_ID0, &smps_offset, |
131 | REG_SMPS_OFFSET); | 131 | REG_SMPS_OFFSET); |
132 | is_offset_valid = true; | 132 | is_offset_valid = true; |
133 | } | 133 | } |
134 | 134 | ||
135 | if (!uv) | 135 | if (!uv) |
136 | return 0x00; | 136 | return 0x00; |
137 | /* | 137 | /* |
138 | * There is no specific formula for voltage to vsel | 138 | * There is no specific formula for voltage to vsel |
139 | * conversion above 1.3V. There are special hardcoded | 139 | * conversion above 1.3V. There are special hardcoded |
140 | * values for voltages above 1.3V. Currently we are | 140 | * values for voltages above 1.3V. Currently we are |
141 | * hardcoding only for 1.35 V which is used for 1GH OPP for | 141 | * hardcoding only for 1.35 V which is used for 1GH OPP for |
142 | * OMAP4430. | 142 | * OMAP4430. |
143 | */ | 143 | */ |
144 | if (uv > twl6030_vsel_to_uv(0x39)) { | 144 | if (uv > twl6030_vsel_to_uv(0x39)) { |
145 | if (uv == 1350000) | 145 | if (uv == 1350000) |
146 | return 0x3A; | 146 | return 0x3A; |
147 | pr_err("%s:OUT OF RANGE! non mapped vsel for %ld Vs max %ld\n", | 147 | pr_err("%s:OUT OF RANGE! non mapped vsel for %ld Vs max %ld\n", |
148 | __func__, uv, twl6030_vsel_to_uv(0x39)); | 148 | __func__, uv, twl6030_vsel_to_uv(0x39)); |
149 | return 0x3A; | 149 | return 0x3A; |
150 | } | 150 | } |
151 | 151 | ||
152 | if (smps_offset & 0x8) | 152 | if (smps_offset & 0x8) |
153 | return DIV_ROUND_UP(uv - 709000, 12660) + 1; | 153 | return DIV_ROUND_UP(uv - 709000, 12660) + 1; |
154 | else | 154 | else |
155 | return DIV_ROUND_UP(uv - 607700, 12660) + 1; | 155 | return DIV_ROUND_UP(uv - 607700, 12660) + 1; |
156 | } | 156 | } |
157 | 157 | ||
158 | static struct omap_voltdm_pmic omap3_mpu_pmic = { | 158 | static struct omap_voltdm_pmic omap3_mpu_pmic = { |
159 | .slew_rate = 4000, | 159 | .slew_rate = 4000, |
160 | .step_size = 12500, | 160 | .step_size = 12500, |
161 | .on_volt = 1200000, | 161 | .on_volt = 1200000, |
162 | .onlp_volt = 1000000, | 162 | .onlp_volt = 1000000, |
163 | .ret_volt = 975000, | 163 | .ret_volt = 975000, |
164 | .off_volt = 600000, | 164 | .off_volt = 600000, |
165 | .volt_setup_time = 0xfff, | 165 | .volt_setup_time = 0xfff, |
166 | .vp_erroroffset = OMAP3_VP_CONFIG_ERROROFFSET, | 166 | .vp_erroroffset = OMAP3_VP_CONFIG_ERROROFFSET, |
167 | .vp_vstepmin = OMAP3_VP_VSTEPMIN_VSTEPMIN, | 167 | .vp_vstepmin = OMAP3_VP_VSTEPMIN_VSTEPMIN, |
168 | .vp_vstepmax = OMAP3_VP_VSTEPMAX_VSTEPMAX, | 168 | .vp_vstepmax = OMAP3_VP_VSTEPMAX_VSTEPMAX, |
169 | .vp_vddmin = OMAP3430_VP1_VLIMITTO_VDDMIN, | 169 | .vp_vddmin = OMAP3430_VP1_VLIMITTO_VDDMIN, |
170 | .vp_vddmax = OMAP3430_VP1_VLIMITTO_VDDMAX, | 170 | .vp_vddmax = OMAP3430_VP1_VLIMITTO_VDDMAX, |
171 | .vp_timeout_us = OMAP3_VP_VLIMITTO_TIMEOUT_US, | 171 | .vp_timeout_us = OMAP3_VP_VLIMITTO_TIMEOUT_US, |
172 | .i2c_slave_addr = OMAP3_SRI2C_SLAVE_ADDR, | 172 | .i2c_slave_addr = OMAP3_SRI2C_SLAVE_ADDR, |
173 | .volt_reg_addr = OMAP3_VDD_MPU_SR_CONTROL_REG, | 173 | .volt_reg_addr = OMAP3_VDD_MPU_SR_CONTROL_REG, |
174 | .i2c_high_speed = true, | 174 | .i2c_high_speed = true, |
175 | .vsel_to_uv = twl4030_vsel_to_uv, | 175 | .vsel_to_uv = twl4030_vsel_to_uv, |
176 | .uv_to_vsel = twl4030_uv_to_vsel, | 176 | .uv_to_vsel = twl4030_uv_to_vsel, |
177 | }; | 177 | }; |
178 | 178 | ||
179 | static struct omap_voltdm_pmic omap3_core_pmic = { | 179 | static struct omap_voltdm_pmic omap3_core_pmic = { |
180 | .slew_rate = 4000, | 180 | .slew_rate = 4000, |
181 | .step_size = 12500, | 181 | .step_size = 12500, |
182 | .on_volt = 1200000, | 182 | .on_volt = 1200000, |
183 | .onlp_volt = 1000000, | 183 | .onlp_volt = 1000000, |
184 | .ret_volt = 975000, | 184 | .ret_volt = 975000, |
185 | .off_volt = 600000, | 185 | .off_volt = 600000, |
186 | .volt_setup_time = 0xfff, | 186 | .volt_setup_time = 0xfff, |
187 | .vp_erroroffset = OMAP3_VP_CONFIG_ERROROFFSET, | 187 | .vp_erroroffset = OMAP3_VP_CONFIG_ERROROFFSET, |
188 | .vp_vstepmin = OMAP3_VP_VSTEPMIN_VSTEPMIN, | 188 | .vp_vstepmin = OMAP3_VP_VSTEPMIN_VSTEPMIN, |
189 | .vp_vstepmax = OMAP3_VP_VSTEPMAX_VSTEPMAX, | 189 | .vp_vstepmax = OMAP3_VP_VSTEPMAX_VSTEPMAX, |
190 | .vp_vddmin = OMAP3430_VP2_VLIMITTO_VDDMIN, | 190 | .vp_vddmin = OMAP3430_VP2_VLIMITTO_VDDMIN, |
191 | .vp_vddmax = OMAP3430_VP2_VLIMITTO_VDDMAX, | 191 | .vp_vddmax = OMAP3430_VP2_VLIMITTO_VDDMAX, |
192 | .vp_timeout_us = OMAP3_VP_VLIMITTO_TIMEOUT_US, | 192 | .vp_timeout_us = OMAP3_VP_VLIMITTO_TIMEOUT_US, |
193 | .i2c_slave_addr = OMAP3_SRI2C_SLAVE_ADDR, | 193 | .i2c_slave_addr = OMAP3_SRI2C_SLAVE_ADDR, |
194 | .volt_reg_addr = OMAP3_VDD_CORE_SR_CONTROL_REG, | 194 | .volt_reg_addr = OMAP3_VDD_CORE_SR_CONTROL_REG, |
195 | .i2c_high_speed = true, | 195 | .i2c_high_speed = true, |
196 | .vsel_to_uv = twl4030_vsel_to_uv, | 196 | .vsel_to_uv = twl4030_vsel_to_uv, |
197 | .uv_to_vsel = twl4030_uv_to_vsel, | 197 | .uv_to_vsel = twl4030_uv_to_vsel, |
198 | }; | 198 | }; |
199 | 199 | ||
200 | static struct omap_voltdm_pmic omap4_mpu_pmic = { | 200 | static struct omap_voltdm_pmic omap4_mpu_pmic = { |
201 | .slew_rate = 4000, | 201 | .slew_rate = 4000, |
202 | .step_size = 12660, | 202 | .step_size = 12660, |
203 | .on_volt = 1375000, | 203 | .on_volt = 1375000, |
204 | .onlp_volt = 1375000, | 204 | .onlp_volt = 1375000, |
205 | .ret_volt = 830000, | 205 | .ret_volt = 830000, |
206 | .off_volt = 0, | 206 | .off_volt = 0, |
207 | .volt_setup_time = 0, | 207 | .volt_setup_time = 0, |
208 | .vp_erroroffset = OMAP4_VP_CONFIG_ERROROFFSET, | 208 | .vp_erroroffset = OMAP4_VP_CONFIG_ERROROFFSET, |
209 | .vp_vstepmin = OMAP4_VP_VSTEPMIN_VSTEPMIN, | 209 | .vp_vstepmin = OMAP4_VP_VSTEPMIN_VSTEPMIN, |
210 | .vp_vstepmax = OMAP4_VP_VSTEPMAX_VSTEPMAX, | 210 | .vp_vstepmax = OMAP4_VP_VSTEPMAX_VSTEPMAX, |
211 | .vp_vddmin = OMAP4_VP_MPU_VLIMITTO_VDDMIN, | 211 | .vp_vddmin = OMAP4_VP_MPU_VLIMITTO_VDDMIN, |
212 | .vp_vddmax = OMAP4_VP_MPU_VLIMITTO_VDDMAX, | 212 | .vp_vddmax = OMAP4_VP_MPU_VLIMITTO_VDDMAX, |
213 | .vp_timeout_us = OMAP4_VP_VLIMITTO_TIMEOUT_US, | 213 | .vp_timeout_us = OMAP4_VP_VLIMITTO_TIMEOUT_US, |
214 | .i2c_slave_addr = OMAP4_SRI2C_SLAVE_ADDR, | 214 | .i2c_slave_addr = OMAP4_SRI2C_SLAVE_ADDR, |
215 | .volt_reg_addr = OMAP4_VDD_MPU_SR_VOLT_REG, | 215 | .volt_reg_addr = OMAP4_VDD_MPU_SR_VOLT_REG, |
216 | .cmd_reg_addr = OMAP4_VDD_MPU_SR_CMD_REG, | 216 | .cmd_reg_addr = OMAP4_VDD_MPU_SR_CMD_REG, |
217 | .i2c_high_speed = true, | 217 | .i2c_high_speed = true, |
218 | .vsel_to_uv = twl6030_vsel_to_uv, | 218 | .vsel_to_uv = twl6030_vsel_to_uv, |
219 | .uv_to_vsel = twl6030_uv_to_vsel, | 219 | .uv_to_vsel = twl6030_uv_to_vsel, |
220 | }; | 220 | }; |
221 | 221 | ||
222 | static struct omap_voltdm_pmic omap4_iva_pmic = { | 222 | static struct omap_voltdm_pmic omap4_iva_pmic = { |
223 | .slew_rate = 4000, | 223 | .slew_rate = 4000, |
224 | .step_size = 12660, | 224 | .step_size = 12660, |
225 | .on_volt = 1188000, | 225 | .on_volt = 1188000, |
226 | .onlp_volt = 1188000, | 226 | .onlp_volt = 1188000, |
227 | .ret_volt = 830000, | 227 | .ret_volt = 830000, |
228 | .off_volt = 0, | 228 | .off_volt = 0, |
229 | .volt_setup_time = 0, | 229 | .volt_setup_time = 0, |
230 | .vp_erroroffset = OMAP4_VP_CONFIG_ERROROFFSET, | 230 | .vp_erroroffset = OMAP4_VP_CONFIG_ERROROFFSET, |
231 | .vp_vstepmin = OMAP4_VP_VSTEPMIN_VSTEPMIN, | 231 | .vp_vstepmin = OMAP4_VP_VSTEPMIN_VSTEPMIN, |
232 | .vp_vstepmax = OMAP4_VP_VSTEPMAX_VSTEPMAX, | 232 | .vp_vstepmax = OMAP4_VP_VSTEPMAX_VSTEPMAX, |
233 | .vp_vddmin = OMAP4_VP_IVA_VLIMITTO_VDDMIN, | 233 | .vp_vddmin = OMAP4_VP_IVA_VLIMITTO_VDDMIN, |
234 | .vp_vddmax = OMAP4_VP_IVA_VLIMITTO_VDDMAX, | 234 | .vp_vddmax = OMAP4_VP_IVA_VLIMITTO_VDDMAX, |
235 | .vp_timeout_us = OMAP4_VP_VLIMITTO_TIMEOUT_US, | 235 | .vp_timeout_us = OMAP4_VP_VLIMITTO_TIMEOUT_US, |
236 | .i2c_slave_addr = OMAP4_SRI2C_SLAVE_ADDR, | 236 | .i2c_slave_addr = OMAP4_SRI2C_SLAVE_ADDR, |
237 | .volt_reg_addr = OMAP4_VDD_IVA_SR_VOLT_REG, | 237 | .volt_reg_addr = OMAP4_VDD_IVA_SR_VOLT_REG, |
238 | .cmd_reg_addr = OMAP4_VDD_IVA_SR_CMD_REG, | 238 | .cmd_reg_addr = OMAP4_VDD_IVA_SR_CMD_REG, |
239 | .i2c_high_speed = true, | 239 | .i2c_high_speed = true, |
240 | .vsel_to_uv = twl6030_vsel_to_uv, | 240 | .vsel_to_uv = twl6030_vsel_to_uv, |
241 | .uv_to_vsel = twl6030_uv_to_vsel, | 241 | .uv_to_vsel = twl6030_uv_to_vsel, |
242 | }; | 242 | }; |
243 | 243 | ||
244 | static struct omap_voltdm_pmic omap4_core_pmic = { | 244 | static struct omap_voltdm_pmic omap4_core_pmic = { |
245 | .slew_rate = 4000, | 245 | .slew_rate = 4000, |
246 | .step_size = 12660, | 246 | .step_size = 12660, |
247 | .on_volt = 1200000, | 247 | .on_volt = 1200000, |
248 | .onlp_volt = 1200000, | 248 | .onlp_volt = 1200000, |
249 | .ret_volt = 830000, | 249 | .ret_volt = 830000, |
250 | .off_volt = 0, | 250 | .off_volt = 0, |
251 | .volt_setup_time = 0, | 251 | .volt_setup_time = 0, |
252 | .vp_erroroffset = OMAP4_VP_CONFIG_ERROROFFSET, | 252 | .vp_erroroffset = OMAP4_VP_CONFIG_ERROROFFSET, |
253 | .vp_vstepmin = OMAP4_VP_VSTEPMIN_VSTEPMIN, | 253 | .vp_vstepmin = OMAP4_VP_VSTEPMIN_VSTEPMIN, |
254 | .vp_vstepmax = OMAP4_VP_VSTEPMAX_VSTEPMAX, | 254 | .vp_vstepmax = OMAP4_VP_VSTEPMAX_VSTEPMAX, |
255 | .vp_vddmin = OMAP4_VP_CORE_VLIMITTO_VDDMIN, | 255 | .vp_vddmin = OMAP4_VP_CORE_VLIMITTO_VDDMIN, |
256 | .vp_vddmax = OMAP4_VP_CORE_VLIMITTO_VDDMAX, | 256 | .vp_vddmax = OMAP4_VP_CORE_VLIMITTO_VDDMAX, |
257 | .vp_timeout_us = OMAP4_VP_VLIMITTO_TIMEOUT_US, | 257 | .vp_timeout_us = OMAP4_VP_VLIMITTO_TIMEOUT_US, |
258 | .i2c_slave_addr = OMAP4_SRI2C_SLAVE_ADDR, | 258 | .i2c_slave_addr = OMAP4_SRI2C_SLAVE_ADDR, |
259 | .volt_reg_addr = OMAP4_VDD_CORE_SR_VOLT_REG, | 259 | .volt_reg_addr = OMAP4_VDD_CORE_SR_VOLT_REG, |
260 | .cmd_reg_addr = OMAP4_VDD_CORE_SR_CMD_REG, | 260 | .cmd_reg_addr = OMAP4_VDD_CORE_SR_CMD_REG, |
261 | .vsel_to_uv = twl6030_vsel_to_uv, | 261 | .vsel_to_uv = twl6030_vsel_to_uv, |
262 | .uv_to_vsel = twl6030_uv_to_vsel, | 262 | .uv_to_vsel = twl6030_uv_to_vsel, |
263 | }; | 263 | }; |
264 | 264 | ||
265 | int __init omap4_twl_init(void) | 265 | int __init omap4_twl_init(void) |
266 | { | 266 | { |
267 | struct voltagedomain *voltdm; | 267 | struct voltagedomain *voltdm; |
268 | 268 | ||
269 | if (!cpu_is_omap44xx()) | 269 | if (!cpu_is_omap44xx()) |
270 | return -ENODEV; | 270 | return -ENODEV; |
271 | 271 | ||
272 | voltdm = voltdm_lookup("mpu"); | 272 | voltdm = voltdm_lookup("mpu"); |
273 | omap_voltage_register_pmic(voltdm, &omap4_mpu_pmic); | 273 | omap_voltage_register_pmic(voltdm, &omap4_mpu_pmic); |
274 | 274 | ||
275 | voltdm = voltdm_lookup("iva"); | 275 | voltdm = voltdm_lookup("iva"); |
276 | omap_voltage_register_pmic(voltdm, &omap4_iva_pmic); | 276 | omap_voltage_register_pmic(voltdm, &omap4_iva_pmic); |
277 | 277 | ||
278 | voltdm = voltdm_lookup("core"); | 278 | voltdm = voltdm_lookup("core"); |
279 | omap_voltage_register_pmic(voltdm, &omap4_core_pmic); | 279 | omap_voltage_register_pmic(voltdm, &omap4_core_pmic); |
280 | 280 | ||
281 | return 0; | 281 | return 0; |
282 | } | 282 | } |
283 | 283 | ||
284 | int __init omap3_twl_init(void) | 284 | int __init omap3_twl_init(void) |
285 | { | 285 | { |
286 | struct voltagedomain *voltdm; | 286 | struct voltagedomain *voltdm; |
287 | 287 | ||
288 | if (!cpu_is_omap34xx() || cpu_is_am33xx()) | 288 | if (!cpu_is_omap34xx() || cpu_is_am33xx()) |
289 | return -ENODEV; | 289 | return -ENODEV; |
290 | 290 | ||
291 | if (cpu_is_omap3630()) { | 291 | if (cpu_is_omap3630()) { |
292 | omap3_mpu_pmic.vp_vddmin = OMAP3630_VP1_VLIMITTO_VDDMIN; | 292 | omap3_mpu_pmic.vp_vddmin = OMAP3630_VP1_VLIMITTO_VDDMIN; |
293 | omap3_mpu_pmic.vp_vddmax = OMAP3630_VP1_VLIMITTO_VDDMAX; | 293 | omap3_mpu_pmic.vp_vddmax = OMAP3630_VP1_VLIMITTO_VDDMAX; |
294 | omap3_core_pmic.vp_vddmin = OMAP3630_VP2_VLIMITTO_VDDMIN; | 294 | omap3_core_pmic.vp_vddmin = OMAP3630_VP2_VLIMITTO_VDDMIN; |
295 | omap3_core_pmic.vp_vddmax = OMAP3630_VP2_VLIMITTO_VDDMAX; | 295 | omap3_core_pmic.vp_vddmax = OMAP3630_VP2_VLIMITTO_VDDMAX; |
296 | } | 296 | } |
297 | 297 | ||
298 | /* | 298 | /* |
299 | * The smartreflex bit on twl4030 specifies if the setting of voltage | 299 | * The smartreflex bit on twl4030 specifies if the setting of voltage |
300 | * is done over the I2C_SR path. Since this setting is independent of | 300 | * is done over the I2C_SR path. Since this setting is independent of |
301 | * the actual usage of smartreflex AVS module, we enable TWL SR bit | 301 | * the actual usage of smartreflex AVS module, we enable TWL SR bit |
302 | * by default irrespective of whether smartreflex AVS module is enabled | 302 | * by default irrespective of whether smartreflex AVS module is enabled |
303 | * on the OMAP side or not. This is because without this bit enabled, | 303 | * on the OMAP side or not. This is because without this bit enabled, |
304 | * the voltage scaling through vp forceupdate/bypass mechanism of | 304 | * the voltage scaling through vp forceupdate/bypass mechanism of |
305 | * voltage scaling will not function on TWL over I2C_SR. | 305 | * voltage scaling will not function on TWL over I2C_SR. |
306 | */ | 306 | */ |
307 | if (!twl_sr_enable_autoinit) | 307 | if (!twl_sr_enable_autoinit) |
308 | omap3_twl_set_sr_bit(true); | 308 | omap3_twl_set_sr_bit(true); |
309 | 309 | ||
310 | voltdm = voltdm_lookup("mpu_iva"); | 310 | voltdm = voltdm_lookup("mpu_iva"); |
311 | omap_voltage_register_pmic(voltdm, &omap3_mpu_pmic); | 311 | omap_voltage_register_pmic(voltdm, &omap3_mpu_pmic); |
312 | 312 | ||
313 | voltdm = voltdm_lookup("core"); | 313 | voltdm = voltdm_lookup("core"); |
314 | omap_voltage_register_pmic(voltdm, &omap3_core_pmic); | 314 | omap_voltage_register_pmic(voltdm, &omap3_core_pmic); |
315 | 315 | ||
316 | return 0; | 316 | return 0; |
317 | } | 317 | } |
318 | 318 | ||
319 | /** | 319 | /** |
320 | * omap3_twl_set_sr_bit() - Set/Clear SR bit on TWL | 320 | * omap3_twl_set_sr_bit() - Set/Clear SR bit on TWL |
321 | * @enable: enable SR mode in twl or not | 321 | * @enable: enable SR mode in twl or not |
322 | * | 322 | * |
323 | * If 'enable' is true, enables Smartreflex bit on TWL 4030 to make sure | 323 | * If 'enable' is true, enables Smartreflex bit on TWL 4030 to make sure |
324 | * voltage scaling through OMAP SR works. Else, the smartreflex bit | 324 | * voltage scaling through OMAP SR works. Else, the smartreflex bit |
325 | * on twl4030 is cleared as there are platforms which use OMAP3 and T2 but | 325 | * on twl4030 is cleared as there are platforms which use OMAP3 and T2 but |
326 | * use Synchronized Scaling Hardware Strategy (ENABLE_VMODE=1) and Direct | 326 | * use Synchronized Scaling Hardware Strategy (ENABLE_VMODE=1) and Direct |
327 | * Strategy Software Scaling Mode (ENABLE_VMODE=0), for setting the voltages, | 327 | * Strategy Software Scaling Mode (ENABLE_VMODE=0), for setting the voltages, |
328 | * in those scenarios this bit is to be cleared (enable = false). | 328 | * in those scenarios this bit is to be cleared (enable = false). |
329 | * | 329 | * |
330 | * Returns 0 on success, error is returned if I2C read/write fails. | 330 | * Returns 0 on success, error is returned if I2C read/write fails. |
331 | */ | 331 | */ |
332 | int __init omap3_twl_set_sr_bit(bool enable) | 332 | int __init omap3_twl_set_sr_bit(bool enable) |
333 | { | 333 | { |
334 | u8 temp; | 334 | u8 temp; |
335 | int ret; | 335 | int ret; |
336 | if (twl_sr_enable_autoinit) | 336 | if (twl_sr_enable_autoinit) |
337 | pr_warning("%s: unexpected multiple calls\n", __func__); | 337 | pr_warning("%s: unexpected multiple calls\n", __func__); |
338 | 338 | ||
339 | ret = twl_i2c_read_u8(TWL4030_MODULE_PM_RECEIVER, &temp, | 339 | ret = twl_i2c_read_u8(TWL4030_MODULE_PM_RECEIVER, &temp, |
340 | TWL4030_DCDC_GLOBAL_CFG); | 340 | TWL4030_DCDC_GLOBAL_CFG); |
341 | if (ret) | 341 | if (ret) |
342 | goto err; | 342 | goto err; |
343 | 343 | ||
344 | if (enable) | 344 | if (enable) |
345 | temp |= SMARTREFLEX_ENABLE; | 345 | temp |= SMARTREFLEX_ENABLE; |
346 | else | 346 | else |
347 | temp &= ~SMARTREFLEX_ENABLE; | 347 | temp &= ~SMARTREFLEX_ENABLE; |
348 | 348 | ||
349 | ret = twl_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, temp, | 349 | ret = twl_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, temp, |
350 | TWL4030_DCDC_GLOBAL_CFG); | 350 | TWL4030_DCDC_GLOBAL_CFG); |
351 | if (!ret) { | 351 | if (!ret) { |
352 | twl_sr_enable_autoinit = true; | 352 | twl_sr_enable_autoinit = true; |
353 | return 0; | 353 | return 0; |
354 | } | 354 | } |
355 | err: | 355 | err: |
356 | pr_err("%s: Error access to TWL4030 (%d)\n", __func__, ret); | 356 | pr_err("%s: Error access to TWL4030 (%d)\n", __func__, ret); |
357 | return ret; | 357 | return ret; |
358 | } | 358 | } |
arch/arm/mach-omap2/opp.c
1 | /* | 1 | /* |
2 | * OMAP SoC specific OPP wrapper function | 2 | * OMAP SoC specific OPP wrapper function |
3 | * | 3 | * |
4 | * Copyright (C) 2009-2010 Texas Instruments Incorporated - http://www.ti.com/ | 4 | * Copyright (C) 2009-2010 Texas Instruments Incorporated - http://www.ti.com/ |
5 | * Nishanth Menon | 5 | * Nishanth Menon |
6 | * Kevin Hilman | 6 | * Kevin Hilman |
7 | * Copyright (C) 2010 Nokia Corporation. | 7 | * Copyright (C) 2010 Nokia Corporation. |
8 | * Eduardo Valentin | 8 | * Eduardo Valentin |
9 | * | 9 | * |
10 | * This program is free software; you can redistribute it and/or modify | 10 | * This program is free software; you can redistribute it and/or modify |
11 | * it under the terms of the GNU General Public License version 2 as | 11 | * it under the terms of the GNU General Public License version 2 as |
12 | * published by the Free Software Foundation. | 12 | * published by the Free Software Foundation. |
13 | * | 13 | * |
14 | * This program is distributed "as is" WITHOUT ANY WARRANTY of any | 14 | * This program is distributed "as is" WITHOUT ANY WARRANTY of any |
15 | * kind, whether express or implied; without even the implied warranty | 15 | * kind, whether express or implied; without even the implied warranty |
16 | * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 16 | * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
17 | * GNU General Public License for more details. | 17 | * GNU General Public License for more details. |
18 | */ | 18 | */ |
19 | #include <linux/module.h> | 19 | #include <linux/module.h> |
20 | #include <linux/opp.h> | 20 | #include <linux/opp.h> |
21 | 21 | ||
22 | #include <plat/omap_device.h> | 22 | #include <plat/omap_device.h> |
23 | #include <plat/dvfs.h> | ||
23 | 24 | ||
24 | #include "omap_opp_data.h" | 25 | #include "omap_opp_data.h" |
25 | #include "dvfs.h" | ||
26 | 26 | ||
27 | /* Temp variable to allow multiple calls */ | 27 | /* Temp variable to allow multiple calls */ |
28 | static u8 __initdata omap_table_init; | 28 | static u8 __initdata omap_table_init; |
29 | 29 | ||
30 | /** | 30 | /** |
31 | * omap_init_opp_table() - Initialize opp table as per the CPU type | 31 | * omap_init_opp_table() - Initialize opp table as per the CPU type |
32 | * @opp_def: opp default list for this silicon | 32 | * @opp_def: opp default list for this silicon |
33 | * @opp_def_size: number of opp entries for this silicon | 33 | * @opp_def_size: number of opp entries for this silicon |
34 | * | 34 | * |
35 | * Register the initial OPP table with the OPP library based on the CPU | 35 | * Register the initial OPP table with the OPP library based on the CPU |
36 | * type. This is meant to be used only by SoC specific registration. | 36 | * type. This is meant to be used only by SoC specific registration. |
37 | */ | 37 | */ |
38 | int __init omap_init_opp_table(struct omap_opp_def *opp_def, | 38 | int __init omap_init_opp_table(struct omap_opp_def *opp_def, |
39 | u32 opp_def_size) | 39 | u32 opp_def_size) |
40 | { | 40 | { |
41 | int i, r; | 41 | int i, r; |
42 | 42 | ||
43 | if (!opp_def || !opp_def_size) { | 43 | if (!opp_def || !opp_def_size) { |
44 | pr_err("%s: invalid params!\n", __func__); | 44 | pr_err("%s: invalid params!\n", __func__); |
45 | return -EINVAL; | 45 | return -EINVAL; |
46 | } | 46 | } |
47 | 47 | ||
48 | /* | 48 | /* |
49 | * Initialize only if not already initialized even if the previous | 49 | * Initialize only if not already initialized even if the previous |
50 | * call failed, because, no reason we'd succeed again. | 50 | * call failed, because, no reason we'd succeed again. |
51 | */ | 51 | */ |
52 | if (omap_table_init) | 52 | if (omap_table_init) |
53 | return -EEXIST; | 53 | return -EEXIST; |
54 | omap_table_init = 1; | 54 | omap_table_init = 1; |
55 | 55 | ||
56 | /* Lets now register with OPP library */ | 56 | /* Lets now register with OPP library */ |
57 | for (i = 0; i < opp_def_size; i++) { | 57 | for (i = 0; i < opp_def_size; i++) { |
58 | struct omap_hwmod *oh; | 58 | struct omap_hwmod *oh; |
59 | struct device *dev; | 59 | struct device *dev; |
60 | 60 | ||
61 | if (!opp_def->hwmod_name) { | 61 | if (!opp_def->hwmod_name) { |
62 | pr_err("%s: NULL name of omap_hwmod, failing [%d].\n", | 62 | pr_err("%s: NULL name of omap_hwmod, failing [%d].\n", |
63 | __func__, i); | 63 | __func__, i); |
64 | return -EINVAL; | 64 | return -EINVAL; |
65 | } | 65 | } |
66 | oh = omap_hwmod_lookup(opp_def->hwmod_name); | 66 | oh = omap_hwmod_lookup(opp_def->hwmod_name); |
67 | if (!oh || !oh->od) { | 67 | if (!oh || !oh->od) { |
68 | pr_warn("%s: no hwmod or odev for %s, [%d] " | 68 | pr_warn("%s: no hwmod or odev for %s, [%d] " |
69 | "cannot add OPPs.\n", __func__, | 69 | "cannot add OPPs.\n", __func__, |
70 | opp_def->hwmod_name, i); | 70 | opp_def->hwmod_name, i); |
71 | return -EINVAL; | 71 | return -EINVAL; |
72 | } | 72 | } |
73 | dev = &oh->od->pdev->dev; | 73 | dev = &oh->od->pdev->dev; |
74 | 74 | ||
75 | r = opp_add(dev, opp_def->freq, opp_def->u_volt); | 75 | r = opp_add(dev, opp_def->freq, opp_def->u_volt); |
76 | if (r) { | 76 | if (r) { |
77 | dev_err(dev, "%s: add OPP %ld failed for %s [%d] " | 77 | dev_err(dev, "%s: add OPP %ld failed for %s [%d] " |
78 | "result=%d\n", | 78 | "result=%d\n", |
79 | __func__, opp_def->freq, | 79 | __func__, opp_def->freq, |
80 | opp_def->hwmod_name, i, r); | 80 | opp_def->hwmod_name, i, r); |
81 | } else { | 81 | } else { |
82 | if (!opp_def->default_available) | 82 | if (!opp_def->default_available) |
83 | r = opp_disable(dev, opp_def->freq); | 83 | r = opp_disable(dev, opp_def->freq); |
84 | if (r) | 84 | if (r) |
85 | dev_err(dev, "%s: disable %ld failed for %s " | 85 | dev_err(dev, "%s: disable %ld failed for %s " |
86 | "[%d] result=%d\n", | 86 | "[%d] result=%d\n", |
87 | __func__, opp_def->freq, | 87 | __func__, opp_def->freq, |
88 | opp_def->hwmod_name, i, r); | 88 | opp_def->hwmod_name, i, r); |
89 | 89 | ||
90 | r = omap_dvfs_register_device(dev, | 90 | r = omap_dvfs_register_device(dev, |
91 | opp_def->voltdm_name, opp_def->clk_name); | 91 | opp_def->voltdm_name, opp_def->clk_name); |
92 | if (r) | 92 | if (r) |
93 | dev_err(dev, "%s:%s:err dvfs register %d %d\n", | 93 | dev_err(dev, "%s:%s:err dvfs register %d %d\n", |
94 | __func__, opp_def->hwmod_name, r, i); | 94 | __func__, opp_def->hwmod_name, r, i); |
95 | } | 95 | } |
96 | opp_def++; | 96 | opp_def++; |
97 | } | 97 | } |
98 | 98 | ||
99 | return 0; | 99 | return 0; |
100 | } | 100 | } |
arch/arm/mach-omap2/pm.c
1 | /* | 1 | /* |
2 | * pm.c - Common OMAP2+ power management-related code | 2 | * pm.c - Common OMAP2+ power management-related code |
3 | * | 3 | * |
4 | * Copyright (C) 2010 Texas Instruments, Inc. | 4 | * Copyright (C) 2010 Texas Instruments, Inc. |
5 | * Copyright (C) 2010 Nokia Corporation | 5 | * Copyright (C) 2010 Nokia Corporation |
6 | * | 6 | * |
7 | * This program is free software; you can redistribute it and/or modify | 7 | * This program is free software; you can redistribute it and/or modify |
8 | * it under the terms of the GNU General Public License version 2 as | 8 | * it under the terms of the GNU General Public License version 2 as |
9 | * published by the Free Software Foundation. | 9 | * published by the Free Software Foundation. |
10 | */ | 10 | */ |
11 | 11 | ||
12 | #include <linux/kernel.h> | 12 | #include <linux/kernel.h> |
13 | #include <linux/init.h> | 13 | #include <linux/init.h> |
14 | #include <linux/io.h> | 14 | #include <linux/io.h> |
15 | #include <linux/err.h> | 15 | #include <linux/err.h> |
16 | #include <linux/opp.h> | 16 | #include <linux/opp.h> |
17 | 17 | ||
18 | #include <plat/omap-pm.h> | 18 | #include <plat/omap-pm.h> |
19 | #include <plat/omap_device.h> | 19 | #include <plat/omap_device.h> |
20 | #include <plat/common.h> | 20 | #include <plat/common.h> |
21 | #include <plat/voltage.h> | ||
21 | 22 | ||
22 | #include "voltage.h" | ||
23 | #include "powerdomain.h" | 23 | #include "powerdomain.h" |
24 | #include "clockdomain.h" | 24 | #include "clockdomain.h" |
25 | #include "pm.h" | 25 | #include "pm.h" |
26 | 26 | ||
27 | static struct omap_device_pm_latency *pm_lats; | 27 | static struct omap_device_pm_latency *pm_lats; |
28 | 28 | ||
29 | static int _init_omap_device(char *name) | 29 | static int _init_omap_device(char *name) |
30 | { | 30 | { |
31 | struct omap_hwmod *oh; | 31 | struct omap_hwmod *oh; |
32 | struct platform_device *pdev; | 32 | struct platform_device *pdev; |
33 | 33 | ||
34 | oh = omap_hwmod_lookup(name); | 34 | oh = omap_hwmod_lookup(name); |
35 | if (WARN(!oh, "%s: could not find omap_hwmod for %s\n", | 35 | if (WARN(!oh, "%s: could not find omap_hwmod for %s\n", |
36 | __func__, name)) | 36 | __func__, name)) |
37 | return -ENODEV; | 37 | return -ENODEV; |
38 | 38 | ||
39 | pdev = omap_device_build(oh->name, 0, oh, NULL, 0, pm_lats, 0, false); | 39 | pdev = omap_device_build(oh->name, 0, oh, NULL, 0, pm_lats, 0, false); |
40 | if (WARN(IS_ERR(pdev), "%s: could not build omap_device for %s\n", | 40 | if (WARN(IS_ERR(pdev), "%s: could not build omap_device for %s\n", |
41 | __func__, name)) | 41 | __func__, name)) |
42 | return -ENODEV; | 42 | return -ENODEV; |
43 | 43 | ||
44 | return 0; | 44 | return 0; |
45 | } | 45 | } |
46 | 46 | ||
47 | /* | 47 | /* |
48 | * Build omap_devices for processors and bus. | 48 | * Build omap_devices for processors and bus. |
49 | */ | 49 | */ |
50 | static void omap2_init_processor_devices(void) | 50 | static void omap2_init_processor_devices(void) |
51 | { | 51 | { |
52 | _init_omap_device("mpu"); | 52 | _init_omap_device("mpu"); |
53 | if (omap3_has_iva()) | 53 | if (omap3_has_iva()) |
54 | _init_omap_device("iva"); | 54 | _init_omap_device("iva"); |
55 | 55 | ||
56 | if (cpu_is_omap44xx()) { | 56 | if (cpu_is_omap44xx()) { |
57 | _init_omap_device("l3_main_1"); | 57 | _init_omap_device("l3_main_1"); |
58 | _init_omap_device("dsp"); | 58 | _init_omap_device("dsp"); |
59 | _init_omap_device("iva"); | 59 | _init_omap_device("iva"); |
60 | } else { | 60 | } else { |
61 | _init_omap_device("l3_main"); | 61 | _init_omap_device("l3_main"); |
62 | } | 62 | } |
63 | } | 63 | } |
64 | 64 | ||
65 | /* Types of sleep_switch used in omap_set_pwrdm_state */ | 65 | /* Types of sleep_switch used in omap_set_pwrdm_state */ |
66 | #define FORCEWAKEUP_SWITCH 0 | 66 | #define FORCEWAKEUP_SWITCH 0 |
67 | #define LOWPOWERSTATE_SWITCH 1 | 67 | #define LOWPOWERSTATE_SWITCH 1 |
68 | 68 | ||
69 | /* | 69 | /* |
70 | * This sets pwrdm state (other than mpu & core. Currently only ON & | 70 | * This sets pwrdm state (other than mpu & core. Currently only ON & |
71 | * RET are supported. | 71 | * RET are supported. |
72 | */ | 72 | */ |
73 | int omap_set_pwrdm_state(struct powerdomain *pwrdm, u32 state) | 73 | int omap_set_pwrdm_state(struct powerdomain *pwrdm, u32 state) |
74 | { | 74 | { |
75 | u32 cur_state; | 75 | u32 cur_state; |
76 | int sleep_switch = -1; | 76 | int sleep_switch = -1; |
77 | int ret = 0; | 77 | int ret = 0; |
78 | int hwsup = 0; | 78 | int hwsup = 0; |
79 | 79 | ||
80 | if (pwrdm == NULL || IS_ERR(pwrdm)) | 80 | if (pwrdm == NULL || IS_ERR(pwrdm)) |
81 | return -EINVAL; | 81 | return -EINVAL; |
82 | 82 | ||
83 | while (!(pwrdm->pwrsts & (1 << state))) { | 83 | while (!(pwrdm->pwrsts & (1 << state))) { |
84 | if (state == PWRDM_POWER_OFF) | 84 | if (state == PWRDM_POWER_OFF) |
85 | return ret; | 85 | return ret; |
86 | state--; | 86 | state--; |
87 | } | 87 | } |
88 | 88 | ||
89 | cur_state = pwrdm_read_next_pwrst(pwrdm); | 89 | cur_state = pwrdm_read_next_pwrst(pwrdm); |
90 | if (cur_state == state) | 90 | if (cur_state == state) |
91 | return ret; | 91 | return ret; |
92 | 92 | ||
93 | if (pwrdm_read_pwrst(pwrdm) < PWRDM_POWER_ON) { | 93 | if (pwrdm_read_pwrst(pwrdm) < PWRDM_POWER_ON) { |
94 | if ((pwrdm_read_pwrst(pwrdm) > state) && | 94 | if ((pwrdm_read_pwrst(pwrdm) > state) && |
95 | (pwrdm->flags & PWRDM_HAS_LOWPOWERSTATECHANGE)) { | 95 | (pwrdm->flags & PWRDM_HAS_LOWPOWERSTATECHANGE)) { |
96 | sleep_switch = LOWPOWERSTATE_SWITCH; | 96 | sleep_switch = LOWPOWERSTATE_SWITCH; |
97 | } else { | 97 | } else { |
98 | hwsup = clkdm_in_hwsup(pwrdm->pwrdm_clkdms[0]); | 98 | hwsup = clkdm_in_hwsup(pwrdm->pwrdm_clkdms[0]); |
99 | clkdm_wakeup(pwrdm->pwrdm_clkdms[0]); | 99 | clkdm_wakeup(pwrdm->pwrdm_clkdms[0]); |
100 | sleep_switch = FORCEWAKEUP_SWITCH; | 100 | sleep_switch = FORCEWAKEUP_SWITCH; |
101 | } | 101 | } |
102 | } | 102 | } |
103 | 103 | ||
104 | ret = pwrdm_set_next_pwrst(pwrdm, state); | 104 | ret = pwrdm_set_next_pwrst(pwrdm, state); |
105 | if (ret) { | 105 | if (ret) { |
106 | pr_err("%s: unable to set state of powerdomain: %s\n", | 106 | pr_err("%s: unable to set state of powerdomain: %s\n", |
107 | __func__, pwrdm->name); | 107 | __func__, pwrdm->name); |
108 | goto err; | 108 | goto err; |
109 | } | 109 | } |
110 | 110 | ||
111 | switch (sleep_switch) { | 111 | switch (sleep_switch) { |
112 | case FORCEWAKEUP_SWITCH: | 112 | case FORCEWAKEUP_SWITCH: |
113 | if (hwsup) | 113 | if (hwsup) |
114 | clkdm_allow_idle(pwrdm->pwrdm_clkdms[0]); | 114 | clkdm_allow_idle(pwrdm->pwrdm_clkdms[0]); |
115 | else | 115 | else |
116 | clkdm_sleep(pwrdm->pwrdm_clkdms[0]); | 116 | clkdm_sleep(pwrdm->pwrdm_clkdms[0]); |
117 | break; | 117 | break; |
118 | case LOWPOWERSTATE_SWITCH: | 118 | case LOWPOWERSTATE_SWITCH: |
119 | pwrdm_set_lowpwrstchange(pwrdm); | 119 | pwrdm_set_lowpwrstchange(pwrdm); |
120 | break; | 120 | break; |
121 | default: | 121 | default: |
122 | return ret; | 122 | return ret; |
123 | } | 123 | } |
124 | 124 | ||
125 | pwrdm_state_switch(pwrdm); | 125 | pwrdm_state_switch(pwrdm); |
126 | err: | 126 | err: |
127 | return ret; | 127 | return ret; |
128 | } | 128 | } |
129 | 129 | ||
130 | /* | 130 | /* |
131 | * This API is to be called during init to set the various voltage | 131 | * This API is to be called during init to set the various voltage |
132 | * domains to the voltage as per the opp table. Typically we boot up | 132 | * domains to the voltage as per the opp table. Typically we boot up |
133 | * at the nominal voltage. So this function finds out the rate of | 133 | * at the nominal voltage. So this function finds out the rate of |
134 | * the clock associated with the voltage domain, finds out the correct | 134 | * the clock associated with the voltage domain, finds out the correct |
135 | * opp entry and sets the voltage domain to the voltage specified | 135 | * opp entry and sets the voltage domain to the voltage specified |
136 | * in the opp entry | 136 | * in the opp entry |
137 | */ | 137 | */ |
138 | static int __init omap2_set_init_voltage(char *vdd_name, char *clk_name, | 138 | static int __init omap2_set_init_voltage(char *vdd_name, char *clk_name, |
139 | const char *oh_name) | 139 | const char *oh_name) |
140 | { | 140 | { |
141 | struct voltagedomain *voltdm; | 141 | struct voltagedomain *voltdm; |
142 | struct clk *clk; | 142 | struct clk *clk; |
143 | struct opp *opp; | 143 | struct opp *opp; |
144 | struct device *dev; | 144 | struct device *dev; |
145 | unsigned long freq_cur, freq_valid, bootup_volt; | 145 | unsigned long freq_cur, freq_valid, bootup_volt; |
146 | int ret = -EINVAL; | 146 | int ret = -EINVAL; |
147 | 147 | ||
148 | dev = omap_device_get_by_hwmod_name(oh_name); | 148 | dev = omap_device_get_by_hwmod_name(oh_name); |
149 | if (IS_ERR(dev)) { | 149 | if (IS_ERR(dev)) { |
150 | pr_err("%s: Unable to get dev pointer for hwmod %s\n", | 150 | pr_err("%s: Unable to get dev pointer for hwmod %s\n", |
151 | __func__, oh_name); | 151 | __func__, oh_name); |
152 | goto exit; | 152 | goto exit; |
153 | } | 153 | } |
154 | 154 | ||
155 | voltdm = voltdm_lookup(vdd_name); | 155 | voltdm = voltdm_lookup(vdd_name); |
156 | if (IS_ERR(voltdm)) { | 156 | if (IS_ERR(voltdm)) { |
157 | pr_err("%s: unable to get vdd pointer for vdd_%s\n", | 157 | pr_err("%s: unable to get vdd pointer for vdd_%s\n", |
158 | __func__, vdd_name); | 158 | __func__, vdd_name); |
159 | goto exit; | 159 | goto exit; |
160 | } | 160 | } |
161 | 161 | ||
162 | clk = clk_get(NULL, clk_name); | 162 | clk = clk_get(NULL, clk_name); |
163 | if (IS_ERR(clk)) { | 163 | if (IS_ERR(clk)) { |
164 | pr_err("%s: unable to get clk %s\n", __func__, clk_name); | 164 | pr_err("%s: unable to get clk %s\n", __func__, clk_name); |
165 | goto exit; | 165 | goto exit; |
166 | } | 166 | } |
167 | 167 | ||
168 | freq_cur = clk->rate; | 168 | freq_cur = clk->rate; |
169 | freq_valid = freq_cur; | 169 | freq_valid = freq_cur; |
170 | 170 | ||
171 | rcu_read_lock(); | 171 | rcu_read_lock(); |
172 | opp = opp_find_freq_ceil(dev, &freq_valid); | 172 | opp = opp_find_freq_ceil(dev, &freq_valid); |
173 | if (IS_ERR(opp)) { | 173 | if (IS_ERR(opp)) { |
174 | opp = opp_find_freq_floor(dev, &freq_valid); | 174 | opp = opp_find_freq_floor(dev, &freq_valid); |
175 | if (IS_ERR(opp)) { | 175 | if (IS_ERR(opp)) { |
176 | rcu_read_unlock(); | 176 | rcu_read_unlock(); |
177 | pr_err("%s: no boot OPP match for %ld on vdd_%s\n", | 177 | pr_err("%s: no boot OPP match for %ld on vdd_%s\n", |
178 | __func__, freq_cur, vdd_name); | 178 | __func__, freq_cur, vdd_name); |
179 | ret = -ENOENT; | 179 | ret = -ENOENT; |
180 | goto exit_ck; | 180 | goto exit_ck; |
181 | } | 181 | } |
182 | } | 182 | } |
183 | 183 | ||
184 | bootup_volt = opp_get_voltage(opp); | 184 | bootup_volt = opp_get_voltage(opp); |
185 | rcu_read_unlock(); | 185 | rcu_read_unlock(); |
186 | if (!bootup_volt) { | 186 | if (!bootup_volt) { |
187 | pr_err("%s: unable to find voltage corresponding " | 187 | pr_err("%s: unable to find voltage corresponding " |
188 | "to the bootup OPP for vdd_%s\n", __func__, vdd_name); | 188 | "to the bootup OPP for vdd_%s\n", __func__, vdd_name); |
189 | ret = -ENOENT; | 189 | ret = -ENOENT; |
190 | goto exit_ck; | 190 | goto exit_ck; |
191 | } | 191 | } |
192 | 192 | ||
193 | /* | 193 | /* |
194 | * Frequency and Voltage have to be sequenced: if we move from | 194 | * Frequency and Voltage have to be sequenced: if we move from |
195 | * a lower frequency to higher frequency, raise voltage, followed by | 195 | * a lower frequency to higher frequency, raise voltage, followed by |
196 | * frequency, and vice versa. we assume that the voltage at boot | 196 | * frequency, and vice versa. we assume that the voltage at boot |
197 | * is the required voltage for the frequency it was set for. | 197 | * is the required voltage for the frequency it was set for. |
198 | * NOTE: | 198 | * NOTE: |
199 | * we can check the frequency, but there is numerous ways to set | 199 | * we can check the frequency, but there is numerous ways to set |
200 | * voltage. We play the safe path and just set the voltage. | 200 | * voltage. We play the safe path and just set the voltage. |
201 | */ | 201 | */ |
202 | 202 | ||
203 | if (freq_cur < freq_valid) { | 203 | if (freq_cur < freq_valid) { |
204 | ret = voltdm_scale(voltdm, bootup_volt); | 204 | ret = voltdm_scale(voltdm, bootup_volt); |
205 | if (ret) { | 205 | if (ret) { |
206 | pr_err("%s: Fail set voltage-%s(f=%ld v=%ld)on vdd%s\n", | 206 | pr_err("%s: Fail set voltage-%s(f=%ld v=%ld)on vdd%s\n", |
207 | __func__, vdd_name, freq_valid, | 207 | __func__, vdd_name, freq_valid, |
208 | bootup_volt, vdd_name); | 208 | bootup_volt, vdd_name); |
209 | goto exit_ck; | 209 | goto exit_ck; |
210 | } | 210 | } |
211 | } | 211 | } |
212 | 212 | ||
213 | /* Set freq only if there is a difference in freq */ | 213 | /* Set freq only if there is a difference in freq */ |
214 | if (freq_valid != freq_cur) { | 214 | if (freq_valid != freq_cur) { |
215 | ret = clk_set_rate(clk, freq_valid); | 215 | ret = clk_set_rate(clk, freq_valid); |
216 | if (ret) { | 216 | if (ret) { |
217 | pr_err("%s: Fail set clk-%s(f=%ld v=%ld)on vdd%s\n", | 217 | pr_err("%s: Fail set clk-%s(f=%ld v=%ld)on vdd%s\n", |
218 | __func__, clk_name, freq_valid, | 218 | __func__, clk_name, freq_valid, |
219 | bootup_volt, vdd_name); | 219 | bootup_volt, vdd_name); |
220 | goto exit_ck; | 220 | goto exit_ck; |
221 | } | 221 | } |
222 | } | 222 | } |
223 | 223 | ||
224 | if (freq_cur >= freq_valid) { | 224 | if (freq_cur >= freq_valid) { |
225 | ret = voltdm_scale(voltdm, bootup_volt); | 225 | ret = voltdm_scale(voltdm, bootup_volt); |
226 | if (ret) { | 226 | if (ret) { |
227 | pr_err("%s: Fail set voltage-%s(f=%ld v=%ld)on vdd%s\n", | 227 | pr_err("%s: Fail set voltage-%s(f=%ld v=%ld)on vdd%s\n", |
228 | __func__, clk_name, freq_valid, | 228 | __func__, clk_name, freq_valid, |
229 | bootup_volt, vdd_name); | 229 | bootup_volt, vdd_name); |
230 | goto exit_ck; | 230 | goto exit_ck; |
231 | } | 231 | } |
232 | } | 232 | } |
233 | 233 | ||
234 | ret = 0; | 234 | ret = 0; |
235 | exit_ck: | 235 | exit_ck: |
236 | clk_put(clk); | 236 | clk_put(clk); |
237 | 237 | ||
238 | if (!ret) | 238 | if (!ret) |
239 | return 0; | 239 | return 0; |
240 | 240 | ||
241 | exit: | 241 | exit: |
242 | pr_err("%s: unable to set vdd_%s\n", __func__, vdd_name); | 242 | pr_err("%s: unable to set vdd_%s\n", __func__, vdd_name); |
243 | return -EINVAL; | 243 | return -EINVAL; |
244 | } | 244 | } |
245 | 245 | ||
246 | static void __init omap3_init_voltages(void) | 246 | static void __init omap3_init_voltages(void) |
247 | { | 247 | { |
248 | if (!cpu_is_omap34xx()) | 248 | if (!cpu_is_omap34xx()) |
249 | return; | 249 | return; |
250 | 250 | ||
251 | omap2_set_init_voltage("mpu_iva", "dpll1_ck", "mpu"); | 251 | omap2_set_init_voltage("mpu_iva", "dpll1_ck", "mpu"); |
252 | omap2_set_init_voltage("core", "l3_ick", "l3_main"); | 252 | omap2_set_init_voltage("core", "l3_ick", "l3_main"); |
253 | } | 253 | } |
254 | 254 | ||
255 | static void __init omap4_init_voltages(void) | 255 | static void __init omap4_init_voltages(void) |
256 | { | 256 | { |
257 | if (!cpu_is_omap44xx()) | 257 | if (!cpu_is_omap44xx()) |
258 | return; | 258 | return; |
259 | 259 | ||
260 | omap2_set_init_voltage("mpu", "dpll_mpu_ck", "mpu"); | 260 | omap2_set_init_voltage("mpu", "dpll_mpu_ck", "mpu"); |
261 | omap2_set_init_voltage("core", "l3_div_ck", "l3_main_1"); | 261 | omap2_set_init_voltage("core", "l3_div_ck", "l3_main_1"); |
262 | omap2_set_init_voltage("iva", "dpll_iva_m5x2_ck", "iva"); | 262 | omap2_set_init_voltage("iva", "dpll_iva_m5x2_ck", "iva"); |
263 | } | 263 | } |
264 | 264 | ||
265 | static int __init omap2_common_pm_init(void) | 265 | static int __init omap2_common_pm_init(void) |
266 | { | 266 | { |
267 | if (!of_have_populated_dt()) | 267 | if (!of_have_populated_dt()) |
268 | omap2_init_processor_devices(); | 268 | omap2_init_processor_devices(); |
269 | omap_pm_if_init(); | 269 | omap_pm_if_init(); |
270 | 270 | ||
271 | return 0; | 271 | return 0; |
272 | } | 272 | } |
273 | postcore_initcall(omap2_common_pm_init); | 273 | postcore_initcall(omap2_common_pm_init); |
274 | 274 | ||
275 | static int __init omap2_common_pm_late_init(void) | 275 | static int __init omap2_common_pm_late_init(void) |
276 | { | 276 | { |
277 | /* Init the OMAP TWL parameters */ | 277 | /* Init the OMAP TWL parameters */ |
278 | omap3_twl_init(); | 278 | omap3_twl_init(); |
279 | omap4_twl_init(); | 279 | omap4_twl_init(); |
280 | 280 | ||
281 | /* Init the voltage layer */ | 281 | /* Init the voltage layer */ |
282 | omap_voltage_late_init(); | 282 | omap_voltage_late_init(); |
283 | 283 | ||
284 | /* Initialize the voltages */ | 284 | /* Initialize the voltages */ |
285 | omap3_init_voltages(); | 285 | omap3_init_voltages(); |
286 | omap4_init_voltages(); | 286 | omap4_init_voltages(); |
287 | 287 | ||
288 | /* Smartreflex device init */ | 288 | /* Smartreflex device init */ |
289 | omap_devinit_smartreflex(); | 289 | omap_devinit_smartreflex(); |
290 | 290 | ||
291 | return 0; | 291 | return 0; |
292 | } | 292 | } |
293 | late_initcall(omap2_common_pm_late_init); | 293 | late_initcall(omap2_common_pm_late_init); |
arch/arm/mach-omap2/powerdomain.h
1 | /* | 1 | /* |
2 | * OMAP2/3/4 powerdomain control | 2 | * OMAP2/3/4 powerdomain control |
3 | * | 3 | * |
4 | * Copyright (C) 2007-2008, 2010 Texas Instruments, Inc. | 4 | * Copyright (C) 2007-2008, 2010 Texas Instruments, Inc. |
5 | * Copyright (C) 2007-2011 Nokia Corporation | 5 | * Copyright (C) 2007-2011 Nokia Corporation |
6 | * | 6 | * |
7 | * Paul Walmsley | 7 | * Paul Walmsley |
8 | * | 8 | * |
9 | * This program is free software; you can redistribute it and/or modify | 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 | 10 | * it under the terms of the GNU General Public License version 2 as |
11 | * published by the Free Software Foundation. | 11 | * published by the Free Software Foundation. |
12 | * | 12 | * |
13 | * XXX This should be moved to the mach-omap2/ directory at the earliest | 13 | * XXX This should be moved to the mach-omap2/ directory at the earliest |
14 | * opportunity. | 14 | * opportunity. |
15 | */ | 15 | */ |
16 | 16 | ||
17 | #ifndef __ARCH_ARM_MACH_OMAP2_POWERDOMAIN_H | 17 | #ifndef __ARCH_ARM_MACH_OMAP2_POWERDOMAIN_H |
18 | #define __ARCH_ARM_MACH_OMAP2_POWERDOMAIN_H | 18 | #define __ARCH_ARM_MACH_OMAP2_POWERDOMAIN_H |
19 | 19 | ||
20 | #include <linux/types.h> | 20 | #include <linux/types.h> |
21 | #include <linux/list.h> | 21 | #include <linux/list.h> |
22 | 22 | ||
23 | #include <linux/atomic.h> | 23 | #include <linux/atomic.h> |
24 | 24 | ||
25 | #include <plat/cpu.h> | 25 | #include <plat/cpu.h> |
26 | #include <plat/voltage.h> | ||
26 | 27 | ||
27 | #include "voltage.h" | ||
28 | 28 | ||
29 | /* Powerdomain basic power states */ | 29 | /* Powerdomain basic power states */ |
30 | #define PWRDM_POWER_OFF 0x0 | 30 | #define PWRDM_POWER_OFF 0x0 |
31 | #define PWRDM_POWER_RET 0x1 | 31 | #define PWRDM_POWER_RET 0x1 |
32 | #define PWRDM_POWER_INACTIVE 0x2 | 32 | #define PWRDM_POWER_INACTIVE 0x2 |
33 | #define PWRDM_POWER_ON 0x3 | 33 | #define PWRDM_POWER_ON 0x3 |
34 | 34 | ||
35 | #define PWRDM_MAX_PWRSTS 4 | 35 | #define PWRDM_MAX_PWRSTS 4 |
36 | 36 | ||
37 | /* Powerdomain allowable state bitfields */ | 37 | /* Powerdomain allowable state bitfields */ |
38 | #define PWRSTS_ON (1 << PWRDM_POWER_ON) | 38 | #define PWRSTS_ON (1 << PWRDM_POWER_ON) |
39 | #define PWRSTS_INACTIVE (1 << PWRDM_POWER_INACTIVE) | 39 | #define PWRSTS_INACTIVE (1 << PWRDM_POWER_INACTIVE) |
40 | #define PWRSTS_RET (1 << PWRDM_POWER_RET) | 40 | #define PWRSTS_RET (1 << PWRDM_POWER_RET) |
41 | #define PWRSTS_OFF (1 << PWRDM_POWER_OFF) | 41 | #define PWRSTS_OFF (1 << PWRDM_POWER_OFF) |
42 | 42 | ||
43 | #define PWRSTS_OFF_ON (PWRSTS_OFF | PWRSTS_ON) | 43 | #define PWRSTS_OFF_ON (PWRSTS_OFF | PWRSTS_ON) |
44 | #define PWRSTS_OFF_RET (PWRSTS_OFF | PWRSTS_RET) | 44 | #define PWRSTS_OFF_RET (PWRSTS_OFF | PWRSTS_RET) |
45 | #define PWRSTS_RET_ON (PWRSTS_RET | PWRSTS_ON) | 45 | #define PWRSTS_RET_ON (PWRSTS_RET | PWRSTS_ON) |
46 | #define PWRSTS_OFF_RET_ON (PWRSTS_OFF_RET | PWRSTS_ON) | 46 | #define PWRSTS_OFF_RET_ON (PWRSTS_OFF_RET | PWRSTS_ON) |
47 | 47 | ||
48 | 48 | ||
49 | /* Powerdomain flags */ | 49 | /* Powerdomain flags */ |
50 | #define PWRDM_HAS_HDWR_SAR (1 << 0) /* hardware save-and-restore support */ | 50 | #define PWRDM_HAS_HDWR_SAR (1 << 0) /* hardware save-and-restore support */ |
51 | #define PWRDM_HAS_MPU_QUIRK (1 << 1) /* MPU pwr domain has MEM bank 0 bits | 51 | #define PWRDM_HAS_MPU_QUIRK (1 << 1) /* MPU pwr domain has MEM bank 0 bits |
52 | * in MEM bank 1 position. This is | 52 | * in MEM bank 1 position. This is |
53 | * true for OMAP3430 | 53 | * true for OMAP3430 |
54 | */ | 54 | */ |
55 | #define PWRDM_HAS_LOWPOWERSTATECHANGE (1 << 2) /* | 55 | #define PWRDM_HAS_LOWPOWERSTATECHANGE (1 << 2) /* |
56 | * support to transition from a | 56 | * support to transition from a |
57 | * sleep state to a lower sleep | 57 | * sleep state to a lower sleep |
58 | * state without waking up the | 58 | * state without waking up the |
59 | * powerdomain | 59 | * powerdomain |
60 | */ | 60 | */ |
61 | 61 | ||
62 | /* | 62 | /* |
63 | * Number of memory banks that are power-controllable. On OMAP4430, the | 63 | * Number of memory banks that are power-controllable. On OMAP4430, the |
64 | * maximum is 5. | 64 | * maximum is 5. |
65 | */ | 65 | */ |
66 | #define PWRDM_MAX_MEM_BANKS 5 | 66 | #define PWRDM_MAX_MEM_BANKS 5 |
67 | 67 | ||
68 | /* | 68 | /* |
69 | * Maximum number of clockdomains that can be associated with a powerdomain. | 69 | * Maximum number of clockdomains that can be associated with a powerdomain. |
70 | * CORE powerdomain on OMAP4 is the worst case | 70 | * CORE powerdomain on OMAP4 is the worst case |
71 | */ | 71 | */ |
72 | #define PWRDM_MAX_CLKDMS 11 | 72 | #define PWRDM_MAX_CLKDMS 11 |
73 | 73 | ||
74 | /* XXX A completely arbitrary number. What is reasonable here? */ | 74 | /* XXX A completely arbitrary number. What is reasonable here? */ |
75 | #define PWRDM_TRANSITION_BAILOUT 100000 | 75 | #define PWRDM_TRANSITION_BAILOUT 100000 |
76 | 76 | ||
77 | struct clockdomain; | 77 | struct clockdomain; |
78 | struct powerdomain; | 78 | struct powerdomain; |
79 | 79 | ||
80 | /** | 80 | /** |
81 | * struct powerdomain - OMAP powerdomain | 81 | * struct powerdomain - OMAP powerdomain |
82 | * @name: Powerdomain name | 82 | * @name: Powerdomain name |
83 | * @voltdm: voltagedomain containing this powerdomain | 83 | * @voltdm: voltagedomain containing this powerdomain |
84 | * @prcm_offs: the address offset from CM_BASE/PRM_BASE | 84 | * @prcm_offs: the address offset from CM_BASE/PRM_BASE |
85 | * @prcm_partition: (OMAP4 only) the PRCM partition ID containing @prcm_offs | 85 | * @prcm_partition: (OMAP4 only) the PRCM partition ID containing @prcm_offs |
86 | * @pwrsts: Possible powerdomain power states | 86 | * @pwrsts: Possible powerdomain power states |
87 | * @pwrsts_logic_ret: Possible logic power states when pwrdm in RETENTION | 87 | * @pwrsts_logic_ret: Possible logic power states when pwrdm in RETENTION |
88 | * @flags: Powerdomain flags | 88 | * @flags: Powerdomain flags |
89 | * @banks: Number of software-controllable memory banks in this powerdomain | 89 | * @banks: Number of software-controllable memory banks in this powerdomain |
90 | * @pwrsts_mem_ret: Possible memory bank pwrstates when pwrdm in RETENTION | 90 | * @pwrsts_mem_ret: Possible memory bank pwrstates when pwrdm in RETENTION |
91 | * @pwrsts_mem_on: Possible memory bank pwrstates when pwrdm in ON | 91 | * @pwrsts_mem_on: Possible memory bank pwrstates when pwrdm in ON |
92 | * @pwrdm_clkdms: Clockdomains in this powerdomain | 92 | * @pwrdm_clkdms: Clockdomains in this powerdomain |
93 | * @node: list_head linking all powerdomains | 93 | * @node: list_head linking all powerdomains |
94 | * @voltdm_node: list_head linking all powerdomains in a voltagedomain | 94 | * @voltdm_node: list_head linking all powerdomains in a voltagedomain |
95 | * @state: | 95 | * @state: |
96 | * @state_counter: | 96 | * @state_counter: |
97 | * @timer: | 97 | * @timer: |
98 | * @state_timer: | 98 | * @state_timer: |
99 | * | 99 | * |
100 | * @prcm_partition possible values are defined in mach-omap2/prcm44xx.h. | 100 | * @prcm_partition possible values are defined in mach-omap2/prcm44xx.h. |
101 | */ | 101 | */ |
102 | struct powerdomain { | 102 | struct powerdomain { |
103 | const char *name; | 103 | const char *name; |
104 | union { | 104 | union { |
105 | const char *name; | 105 | const char *name; |
106 | struct voltagedomain *ptr; | 106 | struct voltagedomain *ptr; |
107 | } voltdm; | 107 | } voltdm; |
108 | const s16 prcm_offs; | 108 | const s16 prcm_offs; |
109 | const u8 pwrsts; | 109 | const u8 pwrsts; |
110 | const u8 pwrsts_logic_ret; | 110 | const u8 pwrsts_logic_ret; |
111 | const u8 flags; | 111 | const u8 flags; |
112 | const u8 banks; | 112 | const u8 banks; |
113 | const u8 pwrsts_mem_ret[PWRDM_MAX_MEM_BANKS]; | 113 | const u8 pwrsts_mem_ret[PWRDM_MAX_MEM_BANKS]; |
114 | const u8 pwrsts_mem_on[PWRDM_MAX_MEM_BANKS]; | 114 | const u8 pwrsts_mem_on[PWRDM_MAX_MEM_BANKS]; |
115 | const u8 prcm_partition; | 115 | const u8 prcm_partition; |
116 | struct clockdomain *pwrdm_clkdms[PWRDM_MAX_CLKDMS]; | 116 | struct clockdomain *pwrdm_clkdms[PWRDM_MAX_CLKDMS]; |
117 | struct list_head node; | 117 | struct list_head node; |
118 | struct list_head voltdm_node; | 118 | struct list_head voltdm_node; |
119 | int state; | 119 | int state; |
120 | unsigned state_counter[PWRDM_MAX_PWRSTS]; | 120 | unsigned state_counter[PWRDM_MAX_PWRSTS]; |
121 | unsigned ret_logic_off_counter; | 121 | unsigned ret_logic_off_counter; |
122 | unsigned ret_mem_off_counter[PWRDM_MAX_MEM_BANKS]; | 122 | unsigned ret_mem_off_counter[PWRDM_MAX_MEM_BANKS]; |
123 | 123 | ||
124 | #ifdef CONFIG_PM_DEBUG | 124 | #ifdef CONFIG_PM_DEBUG |
125 | s64 timer; | 125 | s64 timer; |
126 | s64 state_timer[PWRDM_MAX_PWRSTS]; | 126 | s64 state_timer[PWRDM_MAX_PWRSTS]; |
127 | #endif | 127 | #endif |
128 | }; | 128 | }; |
129 | 129 | ||
130 | /** | 130 | /** |
131 | * struct pwrdm_ops - Arch specific function implementations | 131 | * struct pwrdm_ops - Arch specific function implementations |
132 | * @pwrdm_set_next_pwrst: Set the target power state for a pd | 132 | * @pwrdm_set_next_pwrst: Set the target power state for a pd |
133 | * @pwrdm_read_next_pwrst: Read the target power state set for a pd | 133 | * @pwrdm_read_next_pwrst: Read the target power state set for a pd |
134 | * @pwrdm_read_pwrst: Read the current power state of a pd | 134 | * @pwrdm_read_pwrst: Read the current power state of a pd |
135 | * @pwrdm_read_prev_pwrst: Read the prev power state entered by the pd | 135 | * @pwrdm_read_prev_pwrst: Read the prev power state entered by the pd |
136 | * @pwrdm_set_logic_retst: Set the logic state in RET for a pd | 136 | * @pwrdm_set_logic_retst: Set the logic state in RET for a pd |
137 | * @pwrdm_set_mem_onst: Set the Memory state in ON for a pd | 137 | * @pwrdm_set_mem_onst: Set the Memory state in ON for a pd |
138 | * @pwrdm_set_mem_retst: Set the Memory state in RET for a pd | 138 | * @pwrdm_set_mem_retst: Set the Memory state in RET for a pd |
139 | * @pwrdm_read_logic_pwrst: Read the current logic state of a pd | 139 | * @pwrdm_read_logic_pwrst: Read the current logic state of a pd |
140 | * @pwrdm_read_prev_logic_pwrst: Read the previous logic state entered by a pd | 140 | * @pwrdm_read_prev_logic_pwrst: Read the previous logic state entered by a pd |
141 | * @pwrdm_read_logic_retst: Read the logic state in RET for a pd | 141 | * @pwrdm_read_logic_retst: Read the logic state in RET for a pd |
142 | * @pwrdm_read_mem_pwrst: Read the current memory state of a pd | 142 | * @pwrdm_read_mem_pwrst: Read the current memory state of a pd |
143 | * @pwrdm_read_prev_mem_pwrst: Read the previous memory state entered by a pd | 143 | * @pwrdm_read_prev_mem_pwrst: Read the previous memory state entered by a pd |
144 | * @pwrdm_read_mem_retst: Read the memory state in RET for a pd | 144 | * @pwrdm_read_mem_retst: Read the memory state in RET for a pd |
145 | * @pwrdm_clear_all_prev_pwrst: Clear all previous power states logged for a pd | 145 | * @pwrdm_clear_all_prev_pwrst: Clear all previous power states logged for a pd |
146 | * @pwrdm_enable_hdwr_sar: Enable Hardware Save-Restore feature for the pd | 146 | * @pwrdm_enable_hdwr_sar: Enable Hardware Save-Restore feature for the pd |
147 | * @pwrdm_disable_hdwr_sar: Disable Hardware Save-Restore feature for a pd | 147 | * @pwrdm_disable_hdwr_sar: Disable Hardware Save-Restore feature for a pd |
148 | * @pwrdm_set_lowpwrstchange: Enable pd transitions from a shallow to deep sleep | 148 | * @pwrdm_set_lowpwrstchange: Enable pd transitions from a shallow to deep sleep |
149 | * @pwrdm_wait_transition: Wait for a pd state transition to complete | 149 | * @pwrdm_wait_transition: Wait for a pd state transition to complete |
150 | */ | 150 | */ |
151 | struct pwrdm_ops { | 151 | struct pwrdm_ops { |
152 | int (*pwrdm_set_next_pwrst)(struct powerdomain *pwrdm, u8 pwrst); | 152 | int (*pwrdm_set_next_pwrst)(struct powerdomain *pwrdm, u8 pwrst); |
153 | int (*pwrdm_read_next_pwrst)(struct powerdomain *pwrdm); | 153 | int (*pwrdm_read_next_pwrst)(struct powerdomain *pwrdm); |
154 | int (*pwrdm_read_pwrst)(struct powerdomain *pwrdm); | 154 | int (*pwrdm_read_pwrst)(struct powerdomain *pwrdm); |
155 | int (*pwrdm_read_prev_pwrst)(struct powerdomain *pwrdm); | 155 | int (*pwrdm_read_prev_pwrst)(struct powerdomain *pwrdm); |
156 | int (*pwrdm_set_logic_retst)(struct powerdomain *pwrdm, u8 pwrst); | 156 | int (*pwrdm_set_logic_retst)(struct powerdomain *pwrdm, u8 pwrst); |
157 | int (*pwrdm_set_mem_onst)(struct powerdomain *pwrdm, u8 bank, u8 pwrst); | 157 | int (*pwrdm_set_mem_onst)(struct powerdomain *pwrdm, u8 bank, u8 pwrst); |
158 | int (*pwrdm_set_mem_retst)(struct powerdomain *pwrdm, u8 bank, u8 pwrst); | 158 | int (*pwrdm_set_mem_retst)(struct powerdomain *pwrdm, u8 bank, u8 pwrst); |
159 | int (*pwrdm_read_logic_pwrst)(struct powerdomain *pwrdm); | 159 | int (*pwrdm_read_logic_pwrst)(struct powerdomain *pwrdm); |
160 | int (*pwrdm_read_prev_logic_pwrst)(struct powerdomain *pwrdm); | 160 | int (*pwrdm_read_prev_logic_pwrst)(struct powerdomain *pwrdm); |
161 | int (*pwrdm_read_logic_retst)(struct powerdomain *pwrdm); | 161 | int (*pwrdm_read_logic_retst)(struct powerdomain *pwrdm); |
162 | int (*pwrdm_read_mem_pwrst)(struct powerdomain *pwrdm, u8 bank); | 162 | int (*pwrdm_read_mem_pwrst)(struct powerdomain *pwrdm, u8 bank); |
163 | int (*pwrdm_read_prev_mem_pwrst)(struct powerdomain *pwrdm, u8 bank); | 163 | int (*pwrdm_read_prev_mem_pwrst)(struct powerdomain *pwrdm, u8 bank); |
164 | int (*pwrdm_read_mem_retst)(struct powerdomain *pwrdm, u8 bank); | 164 | int (*pwrdm_read_mem_retst)(struct powerdomain *pwrdm, u8 bank); |
165 | int (*pwrdm_clear_all_prev_pwrst)(struct powerdomain *pwrdm); | 165 | int (*pwrdm_clear_all_prev_pwrst)(struct powerdomain *pwrdm); |
166 | int (*pwrdm_enable_hdwr_sar)(struct powerdomain *pwrdm); | 166 | int (*pwrdm_enable_hdwr_sar)(struct powerdomain *pwrdm); |
167 | int (*pwrdm_disable_hdwr_sar)(struct powerdomain *pwrdm); | 167 | int (*pwrdm_disable_hdwr_sar)(struct powerdomain *pwrdm); |
168 | int (*pwrdm_set_lowpwrstchange)(struct powerdomain *pwrdm); | 168 | int (*pwrdm_set_lowpwrstchange)(struct powerdomain *pwrdm); |
169 | int (*pwrdm_wait_transition)(struct powerdomain *pwrdm); | 169 | int (*pwrdm_wait_transition)(struct powerdomain *pwrdm); |
170 | }; | 170 | }; |
171 | 171 | ||
172 | int pwrdm_register_platform_funcs(struct pwrdm_ops *custom_funcs); | 172 | int pwrdm_register_platform_funcs(struct pwrdm_ops *custom_funcs); |
173 | int pwrdm_register_pwrdms(struct powerdomain **pwrdm_list); | 173 | int pwrdm_register_pwrdms(struct powerdomain **pwrdm_list); |
174 | int pwrdm_complete_init(void); | 174 | int pwrdm_complete_init(void); |
175 | 175 | ||
176 | struct powerdomain *pwrdm_lookup(const char *name); | 176 | struct powerdomain *pwrdm_lookup(const char *name); |
177 | 177 | ||
178 | int pwrdm_for_each(int (*fn)(struct powerdomain *pwrdm, void *user), | 178 | int pwrdm_for_each(int (*fn)(struct powerdomain *pwrdm, void *user), |
179 | void *user); | 179 | void *user); |
180 | int pwrdm_for_each_nolock(int (*fn)(struct powerdomain *pwrdm, void *user), | 180 | int pwrdm_for_each_nolock(int (*fn)(struct powerdomain *pwrdm, void *user), |
181 | void *user); | 181 | void *user); |
182 | 182 | ||
183 | int pwrdm_add_clkdm(struct powerdomain *pwrdm, struct clockdomain *clkdm); | 183 | int pwrdm_add_clkdm(struct powerdomain *pwrdm, struct clockdomain *clkdm); |
184 | int pwrdm_del_clkdm(struct powerdomain *pwrdm, struct clockdomain *clkdm); | 184 | int pwrdm_del_clkdm(struct powerdomain *pwrdm, struct clockdomain *clkdm); |
185 | int pwrdm_for_each_clkdm(struct powerdomain *pwrdm, | 185 | int pwrdm_for_each_clkdm(struct powerdomain *pwrdm, |
186 | int (*fn)(struct powerdomain *pwrdm, | 186 | int (*fn)(struct powerdomain *pwrdm, |
187 | struct clockdomain *clkdm)); | 187 | struct clockdomain *clkdm)); |
188 | struct voltagedomain *pwrdm_get_voltdm(struct powerdomain *pwrdm); | 188 | struct voltagedomain *pwrdm_get_voltdm(struct powerdomain *pwrdm); |
189 | 189 | ||
190 | int pwrdm_get_mem_bank_count(struct powerdomain *pwrdm); | 190 | int pwrdm_get_mem_bank_count(struct powerdomain *pwrdm); |
191 | 191 | ||
192 | int pwrdm_set_next_pwrst(struct powerdomain *pwrdm, u8 pwrst); | 192 | int pwrdm_set_next_pwrst(struct powerdomain *pwrdm, u8 pwrst); |
193 | int pwrdm_read_next_pwrst(struct powerdomain *pwrdm); | 193 | int pwrdm_read_next_pwrst(struct powerdomain *pwrdm); |
194 | int pwrdm_read_pwrst(struct powerdomain *pwrdm); | 194 | int pwrdm_read_pwrst(struct powerdomain *pwrdm); |
195 | int pwrdm_read_prev_pwrst(struct powerdomain *pwrdm); | 195 | int pwrdm_read_prev_pwrst(struct powerdomain *pwrdm); |
196 | int pwrdm_clear_all_prev_pwrst(struct powerdomain *pwrdm); | 196 | int pwrdm_clear_all_prev_pwrst(struct powerdomain *pwrdm); |
197 | 197 | ||
198 | int pwrdm_set_logic_retst(struct powerdomain *pwrdm, u8 pwrst); | 198 | int pwrdm_set_logic_retst(struct powerdomain *pwrdm, u8 pwrst); |
199 | int pwrdm_set_mem_onst(struct powerdomain *pwrdm, u8 bank, u8 pwrst); | 199 | int pwrdm_set_mem_onst(struct powerdomain *pwrdm, u8 bank, u8 pwrst); |
200 | int pwrdm_set_mem_retst(struct powerdomain *pwrdm, u8 bank, u8 pwrst); | 200 | int pwrdm_set_mem_retst(struct powerdomain *pwrdm, u8 bank, u8 pwrst); |
201 | 201 | ||
202 | int pwrdm_read_logic_pwrst(struct powerdomain *pwrdm); | 202 | int pwrdm_read_logic_pwrst(struct powerdomain *pwrdm); |
203 | int pwrdm_read_prev_logic_pwrst(struct powerdomain *pwrdm); | 203 | int pwrdm_read_prev_logic_pwrst(struct powerdomain *pwrdm); |
204 | int pwrdm_read_logic_retst(struct powerdomain *pwrdm); | 204 | int pwrdm_read_logic_retst(struct powerdomain *pwrdm); |
205 | int pwrdm_read_mem_pwrst(struct powerdomain *pwrdm, u8 bank); | 205 | int pwrdm_read_mem_pwrst(struct powerdomain *pwrdm, u8 bank); |
206 | int pwrdm_read_prev_mem_pwrst(struct powerdomain *pwrdm, u8 bank); | 206 | int pwrdm_read_prev_mem_pwrst(struct powerdomain *pwrdm, u8 bank); |
207 | int pwrdm_read_mem_retst(struct powerdomain *pwrdm, u8 bank); | 207 | int pwrdm_read_mem_retst(struct powerdomain *pwrdm, u8 bank); |
208 | 208 | ||
209 | int pwrdm_enable_hdwr_sar(struct powerdomain *pwrdm); | 209 | int pwrdm_enable_hdwr_sar(struct powerdomain *pwrdm); |
210 | int pwrdm_disable_hdwr_sar(struct powerdomain *pwrdm); | 210 | int pwrdm_disable_hdwr_sar(struct powerdomain *pwrdm); |
211 | bool pwrdm_has_hdwr_sar(struct powerdomain *pwrdm); | 211 | bool pwrdm_has_hdwr_sar(struct powerdomain *pwrdm); |
212 | 212 | ||
213 | int pwrdm_wait_transition(struct powerdomain *pwrdm); | 213 | int pwrdm_wait_transition(struct powerdomain *pwrdm); |
214 | 214 | ||
215 | int pwrdm_state_switch(struct powerdomain *pwrdm); | 215 | int pwrdm_state_switch(struct powerdomain *pwrdm); |
216 | int pwrdm_clkdm_state_switch(struct clockdomain *clkdm); | 216 | int pwrdm_clkdm_state_switch(struct clockdomain *clkdm); |
217 | int pwrdm_pre_transition(void); | 217 | int pwrdm_pre_transition(void); |
218 | int pwrdm_post_transition(void); | 218 | int pwrdm_post_transition(void); |
219 | int pwrdm_set_lowpwrstchange(struct powerdomain *pwrdm); | 219 | int pwrdm_set_lowpwrstchange(struct powerdomain *pwrdm); |
220 | int pwrdm_get_context_loss_count(struct powerdomain *pwrdm); | 220 | int pwrdm_get_context_loss_count(struct powerdomain *pwrdm); |
221 | bool pwrdm_can_ever_lose_context(struct powerdomain *pwrdm); | 221 | bool pwrdm_can_ever_lose_context(struct powerdomain *pwrdm); |
222 | 222 | ||
223 | extern void omap242x_powerdomains_init(void); | 223 | extern void omap242x_powerdomains_init(void); |
224 | extern void omap243x_powerdomains_init(void); | 224 | extern void omap243x_powerdomains_init(void); |
225 | extern void omap3xxx_powerdomains_init(void); | 225 | extern void omap3xxx_powerdomains_init(void); |
226 | extern void am33xx_powerdomains_init(void); | 226 | extern void am33xx_powerdomains_init(void); |
227 | extern void omap44xx_powerdomains_init(void); | 227 | extern void omap44xx_powerdomains_init(void); |
228 | 228 | ||
229 | extern struct pwrdm_ops omap2_pwrdm_operations; | 229 | extern struct pwrdm_ops omap2_pwrdm_operations; |
230 | extern struct pwrdm_ops omap3_pwrdm_operations; | 230 | extern struct pwrdm_ops omap3_pwrdm_operations; |
231 | extern struct pwrdm_ops am33xx_pwrdm_operations; | 231 | extern struct pwrdm_ops am33xx_pwrdm_operations; |
232 | extern struct pwrdm_ops omap4_pwrdm_operations; | 232 | extern struct pwrdm_ops omap4_pwrdm_operations; |
233 | 233 | ||
234 | /* Common Internal functions used across OMAP rev's */ | 234 | /* Common Internal functions used across OMAP rev's */ |
235 | extern u32 omap2_pwrdm_get_mem_bank_onstate_mask(u8 bank); | 235 | extern u32 omap2_pwrdm_get_mem_bank_onstate_mask(u8 bank); |
236 | extern u32 omap2_pwrdm_get_mem_bank_retst_mask(u8 bank); | 236 | extern u32 omap2_pwrdm_get_mem_bank_retst_mask(u8 bank); |
237 | extern u32 omap2_pwrdm_get_mem_bank_stst_mask(u8 bank); | 237 | extern u32 omap2_pwrdm_get_mem_bank_stst_mask(u8 bank); |
238 | 238 | ||
239 | extern struct powerdomain wkup_omap2_pwrdm; | 239 | extern struct powerdomain wkup_omap2_pwrdm; |
240 | extern struct powerdomain gfx_omap2_pwrdm; | 240 | extern struct powerdomain gfx_omap2_pwrdm; |
241 | 241 | ||
242 | 242 | ||
243 | #endif | 243 | #endif |
arch/arm/mach-omap2/prm2xxx_3xxx.c
1 | /* | 1 | /* |
2 | * OMAP2/3 PRM module functions | 2 | * OMAP2/3 PRM module functions |
3 | * | 3 | * |
4 | * Copyright (C) 2010 Texas Instruments, Inc. | 4 | * Copyright (C) 2010 Texas Instruments, Inc. |
5 | * Copyright (C) 2010 Nokia Corporation | 5 | * Copyright (C) 2010 Nokia Corporation |
6 | * Benoรฎt Cousson | 6 | * Benoรฎt Cousson |
7 | * Paul Walmsley | 7 | * Paul Walmsley |
8 | * | 8 | * |
9 | * This program is free software; you can redistribute it and/or modify | 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 | 10 | * it under the terms of the GNU General Public License version 2 as |
11 | * published by the Free Software Foundation. | 11 | * published by the Free Software Foundation. |
12 | */ | 12 | */ |
13 | 13 | ||
14 | #include <linux/kernel.h> | 14 | #include <linux/kernel.h> |
15 | #include <linux/errno.h> | 15 | #include <linux/errno.h> |
16 | #include <linux/err.h> | 16 | #include <linux/err.h> |
17 | #include <linux/io.h> | 17 | #include <linux/io.h> |
18 | 18 | ||
19 | #include <plat/common.h> | 19 | #include <plat/common.h> |
20 | #include <plat/cpu.h> | 20 | #include <plat/cpu.h> |
21 | #include <plat/prcm.h> | 21 | #include <plat/prcm.h> |
22 | 22 | #include <plat/vp.h> | |
23 | #include "vp.h" | ||
24 | 23 | ||
25 | #include "prm2xxx_3xxx.h" | 24 | #include "prm2xxx_3xxx.h" |
26 | #include "cm2xxx_3xxx.h" | 25 | #include "cm2xxx_3xxx.h" |
27 | #include "prm-regbits-24xx.h" | 26 | #include "prm-regbits-24xx.h" |
28 | #include "prm-regbits-34xx.h" | 27 | #include "prm-regbits-34xx.h" |
29 | 28 | ||
30 | u32 omap2_prm_read_mod_reg(s16 module, u16 idx) | 29 | u32 omap2_prm_read_mod_reg(s16 module, u16 idx) |
31 | { | 30 | { |
32 | return __raw_readl(prm_base + module + idx); | 31 | return __raw_readl(prm_base + module + idx); |
33 | } | 32 | } |
34 | 33 | ||
35 | void omap2_prm_write_mod_reg(u32 val, s16 module, u16 idx) | 34 | void omap2_prm_write_mod_reg(u32 val, s16 module, u16 idx) |
36 | { | 35 | { |
37 | __raw_writel(val, prm_base + module + idx); | 36 | __raw_writel(val, prm_base + module + idx); |
38 | } | 37 | } |
39 | 38 | ||
40 | /* Read-modify-write a register in a PRM module. Caller must lock */ | 39 | /* Read-modify-write a register in a PRM module. Caller must lock */ |
41 | u32 omap2_prm_rmw_mod_reg_bits(u32 mask, u32 bits, s16 module, s16 idx) | 40 | u32 omap2_prm_rmw_mod_reg_bits(u32 mask, u32 bits, s16 module, s16 idx) |
42 | { | 41 | { |
43 | u32 v; | 42 | u32 v; |
44 | 43 | ||
45 | v = omap2_prm_read_mod_reg(module, idx); | 44 | v = omap2_prm_read_mod_reg(module, idx); |
46 | v &= ~mask; | 45 | v &= ~mask; |
47 | v |= bits; | 46 | v |= bits; |
48 | omap2_prm_write_mod_reg(v, module, idx); | 47 | omap2_prm_write_mod_reg(v, module, idx); |
49 | 48 | ||
50 | return v; | 49 | return v; |
51 | } | 50 | } |
52 | 51 | ||
53 | /* Read a PRM register, AND it, and shift the result down to bit 0 */ | 52 | /* Read a PRM register, AND it, and shift the result down to bit 0 */ |
54 | u32 omap2_prm_read_mod_bits_shift(s16 domain, s16 idx, u32 mask) | 53 | u32 omap2_prm_read_mod_bits_shift(s16 domain, s16 idx, u32 mask) |
55 | { | 54 | { |
56 | u32 v; | 55 | u32 v; |
57 | 56 | ||
58 | v = omap2_prm_read_mod_reg(domain, idx); | 57 | v = omap2_prm_read_mod_reg(domain, idx); |
59 | v &= mask; | 58 | v &= mask; |
60 | v >>= __ffs(mask); | 59 | v >>= __ffs(mask); |
61 | 60 | ||
62 | return v; | 61 | return v; |
63 | } | 62 | } |
64 | 63 | ||
65 | u32 omap2_prm_set_mod_reg_bits(u32 bits, s16 module, s16 idx) | 64 | u32 omap2_prm_set_mod_reg_bits(u32 bits, s16 module, s16 idx) |
66 | { | 65 | { |
67 | return omap2_prm_rmw_mod_reg_bits(bits, bits, module, idx); | 66 | return omap2_prm_rmw_mod_reg_bits(bits, bits, module, idx); |
68 | } | 67 | } |
69 | 68 | ||
70 | u32 omap2_prm_clear_mod_reg_bits(u32 bits, s16 module, s16 idx) | 69 | u32 omap2_prm_clear_mod_reg_bits(u32 bits, s16 module, s16 idx) |
71 | { | 70 | { |
72 | return omap2_prm_rmw_mod_reg_bits(bits, 0x0, module, idx); | 71 | return omap2_prm_rmw_mod_reg_bits(bits, 0x0, module, idx); |
73 | } | 72 | } |
74 | 73 | ||
75 | 74 | ||
76 | /** | 75 | /** |
77 | * omap2_prm_is_hardreset_asserted - read the HW reset line state of | 76 | * omap2_prm_is_hardreset_asserted - read the HW reset line state of |
78 | * submodules contained in the hwmod module | 77 | * submodules contained in the hwmod module |
79 | * @prm_mod: PRM submodule base (e.g. CORE_MOD) | 78 | * @prm_mod: PRM submodule base (e.g. CORE_MOD) |
80 | * @shift: register bit shift corresponding to the reset line to check | 79 | * @shift: register bit shift corresponding to the reset line to check |
81 | * | 80 | * |
82 | * Returns 1 if the (sub)module hardreset line is currently asserted, | 81 | * Returns 1 if the (sub)module hardreset line is currently asserted, |
83 | * 0 if the (sub)module hardreset line is not currently asserted, or | 82 | * 0 if the (sub)module hardreset line is not currently asserted, or |
84 | * -EINVAL if called while running on a non-OMAP2/3 chip. | 83 | * -EINVAL if called while running on a non-OMAP2/3 chip. |
85 | */ | 84 | */ |
86 | int omap2_prm_is_hardreset_asserted(s16 prm_mod, u8 shift) | 85 | int omap2_prm_is_hardreset_asserted(s16 prm_mod, u8 shift) |
87 | { | 86 | { |
88 | if (!(cpu_is_omap24xx() || cpu_is_omap34xx())) | 87 | if (!(cpu_is_omap24xx() || cpu_is_omap34xx())) |
89 | return -EINVAL; | 88 | return -EINVAL; |
90 | 89 | ||
91 | return omap2_prm_read_mod_bits_shift(prm_mod, OMAP2_RM_RSTCTRL, | 90 | return omap2_prm_read_mod_bits_shift(prm_mod, OMAP2_RM_RSTCTRL, |
92 | (1 << shift)); | 91 | (1 << shift)); |
93 | } | 92 | } |
94 | 93 | ||
95 | /** | 94 | /** |
96 | * omap2_prm_assert_hardreset - assert the HW reset line of a submodule | 95 | * omap2_prm_assert_hardreset - assert the HW reset line of a submodule |
97 | * @prm_mod: PRM submodule base (e.g. CORE_MOD) | 96 | * @prm_mod: PRM submodule base (e.g. CORE_MOD) |
98 | * @shift: register bit shift corresponding to the reset line to assert | 97 | * @shift: register bit shift corresponding to the reset line to assert |
99 | * | 98 | * |
100 | * Some IPs like dsp or iva contain processors that require an HW | 99 | * Some IPs like dsp or iva contain processors that require an HW |
101 | * reset line to be asserted / deasserted in order to fully enable the | 100 | * reset line to be asserted / deasserted in order to fully enable the |
102 | * IP. These modules may have multiple hard-reset lines that reset | 101 | * IP. These modules may have multiple hard-reset lines that reset |
103 | * different 'submodules' inside the IP block. This function will | 102 | * different 'submodules' inside the IP block. This function will |
104 | * place the submodule into reset. Returns 0 upon success or -EINVAL | 103 | * place the submodule into reset. Returns 0 upon success or -EINVAL |
105 | * upon an argument error. | 104 | * upon an argument error. |
106 | */ | 105 | */ |
107 | int omap2_prm_assert_hardreset(s16 prm_mod, u8 shift) | 106 | int omap2_prm_assert_hardreset(s16 prm_mod, u8 shift) |
108 | { | 107 | { |
109 | u32 mask; | 108 | u32 mask; |
110 | 109 | ||
111 | if (!(cpu_is_omap24xx() || cpu_is_omap34xx())) | 110 | if (!(cpu_is_omap24xx() || cpu_is_omap34xx())) |
112 | return -EINVAL; | 111 | return -EINVAL; |
113 | 112 | ||
114 | mask = 1 << shift; | 113 | mask = 1 << shift; |
115 | omap2_prm_rmw_mod_reg_bits(mask, mask, prm_mod, OMAP2_RM_RSTCTRL); | 114 | omap2_prm_rmw_mod_reg_bits(mask, mask, prm_mod, OMAP2_RM_RSTCTRL); |
116 | 115 | ||
117 | return 0; | 116 | return 0; |
118 | } | 117 | } |
119 | 118 | ||
120 | /** | 119 | /** |
121 | * omap2_prm_deassert_hardreset - deassert a submodule hardreset line and wait | 120 | * omap2_prm_deassert_hardreset - deassert a submodule hardreset line and wait |
122 | * @prm_mod: PRM submodule base (e.g. CORE_MOD) | 121 | * @prm_mod: PRM submodule base (e.g. CORE_MOD) |
123 | * @rst_shift: register bit shift corresponding to the reset line to deassert | 122 | * @rst_shift: register bit shift corresponding to the reset line to deassert |
124 | * @st_shift: register bit shift for the status of the deasserted submodule | 123 | * @st_shift: register bit shift for the status of the deasserted submodule |
125 | * | 124 | * |
126 | * Some IPs like dsp or iva contain processors that require an HW | 125 | * Some IPs like dsp or iva contain processors that require an HW |
127 | * reset line to be asserted / deasserted in order to fully enable the | 126 | * reset line to be asserted / deasserted in order to fully enable the |
128 | * IP. These modules may have multiple hard-reset lines that reset | 127 | * IP. These modules may have multiple hard-reset lines that reset |
129 | * different 'submodules' inside the IP block. This function will | 128 | * different 'submodules' inside the IP block. This function will |
130 | * take the submodule out of reset and wait until the PRCM indicates | 129 | * take the submodule out of reset and wait until the PRCM indicates |
131 | * that the reset has completed before returning. Returns 0 upon success or | 130 | * that the reset has completed before returning. Returns 0 upon success or |
132 | * -EINVAL upon an argument error, -EEXIST if the submodule was already out | 131 | * -EINVAL upon an argument error, -EEXIST if the submodule was already out |
133 | * of reset, or -EBUSY if the submodule did not exit reset promptly. | 132 | * of reset, or -EBUSY if the submodule did not exit reset promptly. |
134 | */ | 133 | */ |
135 | int omap2_prm_deassert_hardreset(s16 prm_mod, u8 rst_shift, u8 st_shift) | 134 | int omap2_prm_deassert_hardreset(s16 prm_mod, u8 rst_shift, u8 st_shift) |
136 | { | 135 | { |
137 | u32 rst, st; | 136 | u32 rst, st; |
138 | int c; | 137 | int c; |
139 | 138 | ||
140 | if (!(cpu_is_omap24xx() || cpu_is_omap34xx())) | 139 | if (!(cpu_is_omap24xx() || cpu_is_omap34xx())) |
141 | return -EINVAL; | 140 | return -EINVAL; |
142 | 141 | ||
143 | rst = 1 << rst_shift; | 142 | rst = 1 << rst_shift; |
144 | st = 1 << st_shift; | 143 | st = 1 << st_shift; |
145 | 144 | ||
146 | /* Check the current status to avoid de-asserting the line twice */ | 145 | /* Check the current status to avoid de-asserting the line twice */ |
147 | if (omap2_prm_read_mod_bits_shift(prm_mod, OMAP2_RM_RSTCTRL, rst) == 0) | 146 | if (omap2_prm_read_mod_bits_shift(prm_mod, OMAP2_RM_RSTCTRL, rst) == 0) |
148 | return -EEXIST; | 147 | return -EEXIST; |
149 | 148 | ||
150 | /* Clear the reset status by writing 1 to the status bit */ | 149 | /* Clear the reset status by writing 1 to the status bit */ |
151 | omap2_prm_rmw_mod_reg_bits(0xffffffff, st, prm_mod, OMAP2_RM_RSTST); | 150 | omap2_prm_rmw_mod_reg_bits(0xffffffff, st, prm_mod, OMAP2_RM_RSTST); |
152 | /* de-assert the reset control line */ | 151 | /* de-assert the reset control line */ |
153 | omap2_prm_rmw_mod_reg_bits(rst, 0, prm_mod, OMAP2_RM_RSTCTRL); | 152 | omap2_prm_rmw_mod_reg_bits(rst, 0, prm_mod, OMAP2_RM_RSTCTRL); |
154 | /* wait the status to be set */ | 153 | /* wait the status to be set */ |
155 | omap_test_timeout(omap2_prm_read_mod_bits_shift(prm_mod, OMAP2_RM_RSTST, | 154 | omap_test_timeout(omap2_prm_read_mod_bits_shift(prm_mod, OMAP2_RM_RSTST, |
156 | st), | 155 | st), |
157 | MAX_MODULE_HARDRESET_WAIT, c); | 156 | MAX_MODULE_HARDRESET_WAIT, c); |
158 | 157 | ||
159 | return (c == MAX_MODULE_HARDRESET_WAIT) ? -EBUSY : 0; | 158 | return (c == MAX_MODULE_HARDRESET_WAIT) ? -EBUSY : 0; |
160 | } | 159 | } |
161 | 160 | ||
162 | /* PRM VP */ | 161 | /* PRM VP */ |
163 | 162 | ||
164 | /* | 163 | /* |
165 | * struct omap3_vp - OMAP3 VP register access description. | 164 | * struct omap3_vp - OMAP3 VP register access description. |
166 | * @tranxdone_status: VP_TRANXDONE_ST bitmask in PRM_IRQSTATUS_MPU reg | 165 | * @tranxdone_status: VP_TRANXDONE_ST bitmask in PRM_IRQSTATUS_MPU reg |
167 | */ | 166 | */ |
168 | struct omap3_vp { | 167 | struct omap3_vp { |
169 | u32 tranxdone_status; | 168 | u32 tranxdone_status; |
170 | }; | 169 | }; |
171 | 170 | ||
172 | static struct omap3_vp omap3_vp[] = { | 171 | static struct omap3_vp omap3_vp[] = { |
173 | [OMAP3_VP_VDD_MPU_ID] = { | 172 | [OMAP3_VP_VDD_MPU_ID] = { |
174 | .tranxdone_status = OMAP3430_VP1_TRANXDONE_ST_MASK, | 173 | .tranxdone_status = OMAP3430_VP1_TRANXDONE_ST_MASK, |
175 | }, | 174 | }, |
176 | [OMAP3_VP_VDD_CORE_ID] = { | 175 | [OMAP3_VP_VDD_CORE_ID] = { |
177 | .tranxdone_status = OMAP3430_VP2_TRANXDONE_ST_MASK, | 176 | .tranxdone_status = OMAP3430_VP2_TRANXDONE_ST_MASK, |
178 | }, | 177 | }, |
179 | }; | 178 | }; |
180 | 179 | ||
181 | #define MAX_VP_ID ARRAY_SIZE(omap3_vp); | 180 | #define MAX_VP_ID ARRAY_SIZE(omap3_vp); |
182 | 181 | ||
183 | u32 omap3_prm_vp_check_txdone(u8 vp_id) | 182 | u32 omap3_prm_vp_check_txdone(u8 vp_id) |
184 | { | 183 | { |
185 | struct omap3_vp *vp = &omap3_vp[vp_id]; | 184 | struct omap3_vp *vp = &omap3_vp[vp_id]; |
186 | u32 irqstatus; | 185 | u32 irqstatus; |
187 | 186 | ||
188 | irqstatus = omap2_prm_read_mod_reg(OCP_MOD, | 187 | irqstatus = omap2_prm_read_mod_reg(OCP_MOD, |
189 | OMAP3_PRM_IRQSTATUS_MPU_OFFSET); | 188 | OMAP3_PRM_IRQSTATUS_MPU_OFFSET); |
190 | return irqstatus & vp->tranxdone_status; | 189 | return irqstatus & vp->tranxdone_status; |
191 | } | 190 | } |
192 | 191 | ||
193 | void omap3_prm_vp_clear_txdone(u8 vp_id) | 192 | void omap3_prm_vp_clear_txdone(u8 vp_id) |
194 | { | 193 | { |
195 | struct omap3_vp *vp = &omap3_vp[vp_id]; | 194 | struct omap3_vp *vp = &omap3_vp[vp_id]; |
196 | 195 | ||
197 | omap2_prm_write_mod_reg(vp->tranxdone_status, | 196 | omap2_prm_write_mod_reg(vp->tranxdone_status, |
198 | OCP_MOD, OMAP3_PRM_IRQSTATUS_MPU_OFFSET); | 197 | OCP_MOD, OMAP3_PRM_IRQSTATUS_MPU_OFFSET); |
199 | } | 198 | } |
200 | 199 | ||
201 | u32 omap3_prm_vcvp_read(u8 offset) | 200 | u32 omap3_prm_vcvp_read(u8 offset) |
202 | { | 201 | { |
203 | return omap2_prm_read_mod_reg(OMAP3430_GR_MOD, offset); | 202 | return omap2_prm_read_mod_reg(OMAP3430_GR_MOD, offset); |
204 | } | 203 | } |
205 | 204 | ||
206 | void omap3_prm_vcvp_write(u32 val, u8 offset) | 205 | void omap3_prm_vcvp_write(u32 val, u8 offset) |
207 | { | 206 | { |
208 | omap2_prm_write_mod_reg(val, OMAP3430_GR_MOD, offset); | 207 | omap2_prm_write_mod_reg(val, OMAP3430_GR_MOD, offset); |
209 | } | 208 | } |
210 | 209 | ||
211 | u32 omap3_prm_vcvp_rmw(u32 mask, u32 bits, u8 offset) | 210 | u32 omap3_prm_vcvp_rmw(u32 mask, u32 bits, u8 offset) |
212 | { | 211 | { |
213 | return omap2_prm_rmw_mod_reg_bits(mask, bits, OMAP3430_GR_MOD, offset); | 212 | return omap2_prm_rmw_mod_reg_bits(mask, bits, OMAP3430_GR_MOD, offset); |
214 | } | 213 | } |
215 | 214 |
arch/arm/mach-omap2/prm44xx.c
1 | /* | 1 | /* |
2 | * OMAP4 PRM module functions | 2 | * OMAP4 PRM module functions |
3 | * | 3 | * |
4 | * Copyright (C) 2011 Texas Instruments, Inc. | 4 | * Copyright (C) 2011 Texas Instruments, Inc. |
5 | * Copyright (C) 2010 Nokia Corporation | 5 | * Copyright (C) 2010 Nokia Corporation |
6 | * Benoรฎt Cousson | 6 | * Benoรฎt Cousson |
7 | * Paul Walmsley | 7 | * Paul Walmsley |
8 | * | 8 | * |
9 | * This program is free software; you can redistribute it and/or modify | 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 | 10 | * it under the terms of the GNU General Public License version 2 as |
11 | * published by the Free Software Foundation. | 11 | * published by the Free Software Foundation. |
12 | */ | 12 | */ |
13 | 13 | ||
14 | #include <linux/kernel.h> | 14 | #include <linux/kernel.h> |
15 | #include <linux/delay.h> | 15 | #include <linux/delay.h> |
16 | #include <linux/errno.h> | 16 | #include <linux/errno.h> |
17 | #include <linux/err.h> | 17 | #include <linux/err.h> |
18 | #include <linux/io.h> | 18 | #include <linux/io.h> |
19 | 19 | ||
20 | #include <plat/common.h> | 20 | #include <plat/common.h> |
21 | #include <plat/cpu.h> | 21 | #include <plat/cpu.h> |
22 | #include <plat/prcm.h> | 22 | #include <plat/prcm.h> |
23 | #include <plat/vp.h> | ||
23 | 24 | ||
24 | #include "vp.h" | ||
25 | #include "prm44xx.h" | 25 | #include "prm44xx.h" |
26 | #include "prm-regbits-44xx.h" | 26 | #include "prm-regbits-44xx.h" |
27 | #include "prcm44xx.h" | 27 | #include "prcm44xx.h" |
28 | #include "prminst44xx.h" | 28 | #include "prminst44xx.h" |
29 | 29 | ||
30 | /* PRM low-level functions */ | 30 | /* PRM low-level functions */ |
31 | 31 | ||
32 | /* Read a register in a CM/PRM instance in the PRM module */ | 32 | /* Read a register in a CM/PRM instance in the PRM module */ |
33 | u32 omap4_prm_read_inst_reg(s16 inst, u16 reg) | 33 | u32 omap4_prm_read_inst_reg(s16 inst, u16 reg) |
34 | { | 34 | { |
35 | return __raw_readl(OMAP44XX_PRM_REGADDR(inst, reg)); | 35 | return __raw_readl(OMAP44XX_PRM_REGADDR(inst, reg)); |
36 | } | 36 | } |
37 | 37 | ||
38 | /* Write into a register in a CM/PRM instance in the PRM module */ | 38 | /* Write into a register in a CM/PRM instance in the PRM module */ |
39 | void omap4_prm_write_inst_reg(u32 val, s16 inst, u16 reg) | 39 | void omap4_prm_write_inst_reg(u32 val, s16 inst, u16 reg) |
40 | { | 40 | { |
41 | __raw_writel(val, OMAP44XX_PRM_REGADDR(inst, reg)); | 41 | __raw_writel(val, OMAP44XX_PRM_REGADDR(inst, reg)); |
42 | } | 42 | } |
43 | 43 | ||
44 | /* Read-modify-write a register in a PRM module. Caller must lock */ | 44 | /* Read-modify-write a register in a PRM module. Caller must lock */ |
45 | u32 omap4_prm_rmw_inst_reg_bits(u32 mask, u32 bits, s16 inst, s16 reg) | 45 | u32 omap4_prm_rmw_inst_reg_bits(u32 mask, u32 bits, s16 inst, s16 reg) |
46 | { | 46 | { |
47 | u32 v; | 47 | u32 v; |
48 | 48 | ||
49 | v = omap4_prm_read_inst_reg(inst, reg); | 49 | v = omap4_prm_read_inst_reg(inst, reg); |
50 | v &= ~mask; | 50 | v &= ~mask; |
51 | v |= bits; | 51 | v |= bits; |
52 | omap4_prm_write_inst_reg(v, inst, reg); | 52 | omap4_prm_write_inst_reg(v, inst, reg); |
53 | 53 | ||
54 | return v; | 54 | return v; |
55 | } | 55 | } |
56 | 56 | ||
57 | /* PRM VP */ | 57 | /* PRM VP */ |
58 | 58 | ||
59 | /* | 59 | /* |
60 | * struct omap4_vp - OMAP4 VP register access description. | 60 | * struct omap4_vp - OMAP4 VP register access description. |
61 | * @irqstatus_mpu: offset to IRQSTATUS_MPU register for VP | 61 | * @irqstatus_mpu: offset to IRQSTATUS_MPU register for VP |
62 | * @tranxdone_status: VP_TRANXDONE_ST bitmask in PRM_IRQSTATUS_MPU reg | 62 | * @tranxdone_status: VP_TRANXDONE_ST bitmask in PRM_IRQSTATUS_MPU reg |
63 | */ | 63 | */ |
64 | struct omap4_vp { | 64 | struct omap4_vp { |
65 | u32 irqstatus_mpu; | 65 | u32 irqstatus_mpu; |
66 | u32 tranxdone_status; | 66 | u32 tranxdone_status; |
67 | }; | 67 | }; |
68 | 68 | ||
69 | static struct omap4_vp omap4_vp[] = { | 69 | static struct omap4_vp omap4_vp[] = { |
70 | [OMAP4_VP_VDD_MPU_ID] = { | 70 | [OMAP4_VP_VDD_MPU_ID] = { |
71 | .irqstatus_mpu = OMAP4_PRM_IRQSTATUS_MPU_2_OFFSET, | 71 | .irqstatus_mpu = OMAP4_PRM_IRQSTATUS_MPU_2_OFFSET, |
72 | .tranxdone_status = OMAP4430_VP_MPU_TRANXDONE_ST_MASK, | 72 | .tranxdone_status = OMAP4430_VP_MPU_TRANXDONE_ST_MASK, |
73 | }, | 73 | }, |
74 | [OMAP4_VP_VDD_IVA_ID] = { | 74 | [OMAP4_VP_VDD_IVA_ID] = { |
75 | .irqstatus_mpu = OMAP4_PRM_IRQSTATUS_MPU_OFFSET, | 75 | .irqstatus_mpu = OMAP4_PRM_IRQSTATUS_MPU_OFFSET, |
76 | .tranxdone_status = OMAP4430_VP_IVA_TRANXDONE_ST_MASK, | 76 | .tranxdone_status = OMAP4430_VP_IVA_TRANXDONE_ST_MASK, |
77 | }, | 77 | }, |
78 | [OMAP4_VP_VDD_CORE_ID] = { | 78 | [OMAP4_VP_VDD_CORE_ID] = { |
79 | .irqstatus_mpu = OMAP4_PRM_IRQSTATUS_MPU_OFFSET, | 79 | .irqstatus_mpu = OMAP4_PRM_IRQSTATUS_MPU_OFFSET, |
80 | .tranxdone_status = OMAP4430_VP_CORE_TRANXDONE_ST_MASK, | 80 | .tranxdone_status = OMAP4430_VP_CORE_TRANXDONE_ST_MASK, |
81 | }, | 81 | }, |
82 | }; | 82 | }; |
83 | 83 | ||
84 | u32 omap4_prm_vp_check_txdone(u8 vp_id) | 84 | u32 omap4_prm_vp_check_txdone(u8 vp_id) |
85 | { | 85 | { |
86 | struct omap4_vp *vp = &omap4_vp[vp_id]; | 86 | struct omap4_vp *vp = &omap4_vp[vp_id]; |
87 | u32 irqstatus; | 87 | u32 irqstatus; |
88 | 88 | ||
89 | irqstatus = omap4_prminst_read_inst_reg(OMAP4430_PRM_PARTITION, | 89 | irqstatus = omap4_prminst_read_inst_reg(OMAP4430_PRM_PARTITION, |
90 | OMAP4430_PRM_OCP_SOCKET_INST, | 90 | OMAP4430_PRM_OCP_SOCKET_INST, |
91 | vp->irqstatus_mpu); | 91 | vp->irqstatus_mpu); |
92 | return irqstatus & vp->tranxdone_status; | 92 | return irqstatus & vp->tranxdone_status; |
93 | } | 93 | } |
94 | 94 | ||
95 | void omap4_prm_vp_clear_txdone(u8 vp_id) | 95 | void omap4_prm_vp_clear_txdone(u8 vp_id) |
96 | { | 96 | { |
97 | struct omap4_vp *vp = &omap4_vp[vp_id]; | 97 | struct omap4_vp *vp = &omap4_vp[vp_id]; |
98 | 98 | ||
99 | omap4_prminst_write_inst_reg(vp->tranxdone_status, | 99 | omap4_prminst_write_inst_reg(vp->tranxdone_status, |
100 | OMAP4430_PRM_PARTITION, | 100 | OMAP4430_PRM_PARTITION, |
101 | OMAP4430_PRM_OCP_SOCKET_INST, | 101 | OMAP4430_PRM_OCP_SOCKET_INST, |
102 | vp->irqstatus_mpu); | 102 | vp->irqstatus_mpu); |
103 | }; | 103 | }; |
104 | 104 | ||
105 | u32 omap4_prm_vcvp_read(u8 offset) | 105 | u32 omap4_prm_vcvp_read(u8 offset) |
106 | { | 106 | { |
107 | return omap4_prminst_read_inst_reg(OMAP4430_PRM_PARTITION, | 107 | return omap4_prminst_read_inst_reg(OMAP4430_PRM_PARTITION, |
108 | OMAP4430_PRM_DEVICE_INST, offset); | 108 | OMAP4430_PRM_DEVICE_INST, offset); |
109 | } | 109 | } |
110 | 110 | ||
111 | void omap4_prm_vcvp_write(u32 val, u8 offset) | 111 | void omap4_prm_vcvp_write(u32 val, u8 offset) |
112 | { | 112 | { |
113 | omap4_prminst_write_inst_reg(val, OMAP4430_PRM_PARTITION, | 113 | omap4_prminst_write_inst_reg(val, OMAP4430_PRM_PARTITION, |
114 | OMAP4430_PRM_DEVICE_INST, offset); | 114 | OMAP4430_PRM_DEVICE_INST, offset); |
115 | } | 115 | } |
116 | 116 | ||
117 | u32 omap4_prm_vcvp_rmw(u32 mask, u32 bits, u8 offset) | 117 | u32 omap4_prm_vcvp_rmw(u32 mask, u32 bits, u8 offset) |
118 | { | 118 | { |
119 | return omap4_prminst_rmw_inst_reg_bits(mask, bits, | 119 | return omap4_prminst_rmw_inst_reg_bits(mask, bits, |
120 | OMAP4430_PRM_PARTITION, | 120 | OMAP4430_PRM_PARTITION, |
121 | OMAP4430_PRM_DEVICE_INST, | 121 | OMAP4430_PRM_DEVICE_INST, |
122 | offset); | 122 | offset); |
123 | } | 123 | } |
arch/arm/mach-omap2/smartreflex.h
1 | /* | 1 | /* |
2 | * OMAP Smartreflex Defines and Routines | 2 | * OMAP Smartreflex Defines and Routines |
3 | * | 3 | * |
4 | * Author: Thara Gopinath <thara@ti.com> | 4 | * Author: Thara Gopinath <thara@ti.com> |
5 | * | 5 | * |
6 | * Copyright (C) 2010 Texas Instruments, Inc. | 6 | * Copyright (C) 2010 Texas Instruments, Inc. |
7 | * Thara Gopinath <thara@ti.com> | 7 | * Thara Gopinath <thara@ti.com> |
8 | * | 8 | * |
9 | * Copyright (C) 2008 Nokia Corporation | 9 | * Copyright (C) 2008 Nokia Corporation |
10 | * Kalle Jokiniemi | 10 | * Kalle Jokiniemi |
11 | * | 11 | * |
12 | * Copyright (C) 2007 Texas Instruments, Inc. | 12 | * Copyright (C) 2007 Texas Instruments, Inc. |
13 | * Lesly A M <x0080970@ti.com> | 13 | * Lesly A M <x0080970@ti.com> |
14 | * | 14 | * |
15 | * This program is free software; you can redistribute it and/or modify | 15 | * This program is free software; you can redistribute it and/or modify |
16 | * it under the terms of the GNU General Public License version 2 as | 16 | * it under the terms of the GNU General Public License version 2 as |
17 | * published by the Free Software Foundation. | 17 | * published by the Free Software Foundation. |
18 | */ | 18 | */ |
19 | 19 | ||
20 | #ifndef __ASM_ARM_OMAP_SMARTREFLEX_H | 20 | #ifndef __ASM_ARM_OMAP_SMARTREFLEX_H |
21 | #define __ASM_ARM_OMAP_SMARTREFLEX_H | 21 | #define __ASM_ARM_OMAP_SMARTREFLEX_H |
22 | 22 | ||
23 | #include <linux/platform_device.h> | 23 | #include <linux/platform_device.h> |
24 | #include <plat/voltage.h> | ||
24 | 25 | ||
25 | #include "voltage.h" | ||
26 | 26 | ||
27 | /* | 27 | /* |
28 | * Different Smartreflex IPs version. The v1 is the 65nm version used in | 28 | * Different Smartreflex IPs version. The v1 is the 65nm version used in |
29 | * OMAP3430. The v2 is the update for the 45nm version of the IP | 29 | * OMAP3430. The v2 is the update for the 45nm version of the IP |
30 | * used in OMAP3630 and OMAP4430 | 30 | * used in OMAP3630 and OMAP4430 |
31 | */ | 31 | */ |
32 | #define SR_TYPE_V1 1 | 32 | #define SR_TYPE_V1 1 |
33 | #define SR_TYPE_V2 2 | 33 | #define SR_TYPE_V2 2 |
34 | 34 | ||
35 | /* SMART REFLEX REG ADDRESS OFFSET */ | 35 | /* SMART REFLEX REG ADDRESS OFFSET */ |
36 | #define SRCONFIG 0x00 | 36 | #define SRCONFIG 0x00 |
37 | #define SRSTATUS 0x04 | 37 | #define SRSTATUS 0x04 |
38 | #define SENVAL 0x08 | 38 | #define SENVAL 0x08 |
39 | #define SENMIN 0x0C | 39 | #define SENMIN 0x0C |
40 | #define SENMAX 0x10 | 40 | #define SENMAX 0x10 |
41 | #define SENAVG 0x14 | 41 | #define SENAVG 0x14 |
42 | #define AVGWEIGHT 0x18 | 42 | #define AVGWEIGHT 0x18 |
43 | #define NVALUERECIPROCAL 0x1c | 43 | #define NVALUERECIPROCAL 0x1c |
44 | #define SENERROR_V1 0x20 | 44 | #define SENERROR_V1 0x20 |
45 | #define ERRCONFIG_V1 0x24 | 45 | #define ERRCONFIG_V1 0x24 |
46 | #define IRQ_EOI 0x20 | 46 | #define IRQ_EOI 0x20 |
47 | #define IRQSTATUS_RAW 0x24 | 47 | #define IRQSTATUS_RAW 0x24 |
48 | #define IRQSTATUS 0x28 | 48 | #define IRQSTATUS 0x28 |
49 | #define IRQENABLE_SET 0x2C | 49 | #define IRQENABLE_SET 0x2C |
50 | #define IRQENABLE_CLR 0x30 | 50 | #define IRQENABLE_CLR 0x30 |
51 | #define SENERROR_V2 0x34 | 51 | #define SENERROR_V2 0x34 |
52 | #define ERRCONFIG_V2 0x38 | 52 | #define ERRCONFIG_V2 0x38 |
53 | 53 | ||
54 | /* Bit/Shift Positions */ | 54 | /* Bit/Shift Positions */ |
55 | 55 | ||
56 | /* SRCONFIG */ | 56 | /* SRCONFIG */ |
57 | #define SRCONFIG_ACCUMDATA_SHIFT 22 | 57 | #define SRCONFIG_ACCUMDATA_SHIFT 22 |
58 | #define SRCONFIG_SRCLKLENGTH_SHIFT 12 | 58 | #define SRCONFIG_SRCLKLENGTH_SHIFT 12 |
59 | #define SRCONFIG_SENNENABLE_V1_SHIFT 5 | 59 | #define SRCONFIG_SENNENABLE_V1_SHIFT 5 |
60 | #define SRCONFIG_SENPENABLE_V1_SHIFT 3 | 60 | #define SRCONFIG_SENPENABLE_V1_SHIFT 3 |
61 | #define SRCONFIG_SENNENABLE_V2_SHIFT 1 | 61 | #define SRCONFIG_SENNENABLE_V2_SHIFT 1 |
62 | #define SRCONFIG_SENPENABLE_V2_SHIFT 0 | 62 | #define SRCONFIG_SENPENABLE_V2_SHIFT 0 |
63 | #define SRCONFIG_CLKCTRL_SHIFT 0 | 63 | #define SRCONFIG_CLKCTRL_SHIFT 0 |
64 | 64 | ||
65 | #define SRCONFIG_ACCUMDATA_MASK (0x3ff << 22) | 65 | #define SRCONFIG_ACCUMDATA_MASK (0x3ff << 22) |
66 | 66 | ||
67 | #define SRCONFIG_SRENABLE BIT(11) | 67 | #define SRCONFIG_SRENABLE BIT(11) |
68 | #define SRCONFIG_SENENABLE BIT(10) | 68 | #define SRCONFIG_SENENABLE BIT(10) |
69 | #define SRCONFIG_ERRGEN_EN BIT(9) | 69 | #define SRCONFIG_ERRGEN_EN BIT(9) |
70 | #define SRCONFIG_MINMAXAVG_EN BIT(8) | 70 | #define SRCONFIG_MINMAXAVG_EN BIT(8) |
71 | #define SRCONFIG_DELAYCTRL BIT(2) | 71 | #define SRCONFIG_DELAYCTRL BIT(2) |
72 | 72 | ||
73 | /* AVGWEIGHT */ | 73 | /* AVGWEIGHT */ |
74 | #define AVGWEIGHT_SENPAVGWEIGHT_SHIFT 2 | 74 | #define AVGWEIGHT_SENPAVGWEIGHT_SHIFT 2 |
75 | #define AVGWEIGHT_SENNAVGWEIGHT_SHIFT 0 | 75 | #define AVGWEIGHT_SENNAVGWEIGHT_SHIFT 0 |
76 | 76 | ||
77 | /* NVALUERECIPROCAL */ | 77 | /* NVALUERECIPROCAL */ |
78 | #define NVALUERECIPROCAL_SENPGAIN_SHIFT 20 | 78 | #define NVALUERECIPROCAL_SENPGAIN_SHIFT 20 |
79 | #define NVALUERECIPROCAL_SENNGAIN_SHIFT 16 | 79 | #define NVALUERECIPROCAL_SENNGAIN_SHIFT 16 |
80 | #define NVALUERECIPROCAL_RNSENP_SHIFT 8 | 80 | #define NVALUERECIPROCAL_RNSENP_SHIFT 8 |
81 | #define NVALUERECIPROCAL_RNSENN_SHIFT 0 | 81 | #define NVALUERECIPROCAL_RNSENN_SHIFT 0 |
82 | 82 | ||
83 | /* ERRCONFIG */ | 83 | /* ERRCONFIG */ |
84 | #define ERRCONFIG_ERRWEIGHT_SHIFT 16 | 84 | #define ERRCONFIG_ERRWEIGHT_SHIFT 16 |
85 | #define ERRCONFIG_ERRMAXLIMIT_SHIFT 8 | 85 | #define ERRCONFIG_ERRMAXLIMIT_SHIFT 8 |
86 | #define ERRCONFIG_ERRMINLIMIT_SHIFT 0 | 86 | #define ERRCONFIG_ERRMINLIMIT_SHIFT 0 |
87 | 87 | ||
88 | #define SR_ERRWEIGHT_MASK (0x07 << 16) | 88 | #define SR_ERRWEIGHT_MASK (0x07 << 16) |
89 | #define SR_ERRMAXLIMIT_MASK (0xff << 8) | 89 | #define SR_ERRMAXLIMIT_MASK (0xff << 8) |
90 | #define SR_ERRMINLIMIT_MASK (0xff << 0) | 90 | #define SR_ERRMINLIMIT_MASK (0xff << 0) |
91 | 91 | ||
92 | #define ERRCONFIG_VPBOUNDINTEN_V1 BIT(31) | 92 | #define ERRCONFIG_VPBOUNDINTEN_V1 BIT(31) |
93 | #define ERRCONFIG_VPBOUNDINTST_V1 BIT(30) | 93 | #define ERRCONFIG_VPBOUNDINTST_V1 BIT(30) |
94 | #define ERRCONFIG_MCUACCUMINTEN BIT(29) | 94 | #define ERRCONFIG_MCUACCUMINTEN BIT(29) |
95 | #define ERRCONFIG_MCUACCUMINTST BIT(28) | 95 | #define ERRCONFIG_MCUACCUMINTST BIT(28) |
96 | #define ERRCONFIG_MCUVALIDINTEN BIT(27) | 96 | #define ERRCONFIG_MCUVALIDINTEN BIT(27) |
97 | #define ERRCONFIG_MCUVALIDINTST BIT(26) | 97 | #define ERRCONFIG_MCUVALIDINTST BIT(26) |
98 | #define ERRCONFIG_MCUBOUNDINTEN BIT(25) | 98 | #define ERRCONFIG_MCUBOUNDINTEN BIT(25) |
99 | #define ERRCONFIG_MCUBOUNDINTST BIT(24) | 99 | #define ERRCONFIG_MCUBOUNDINTST BIT(24) |
100 | #define ERRCONFIG_MCUDISACKINTEN BIT(23) | 100 | #define ERRCONFIG_MCUDISACKINTEN BIT(23) |
101 | #define ERRCONFIG_VPBOUNDINTST_V2 BIT(23) | 101 | #define ERRCONFIG_VPBOUNDINTST_V2 BIT(23) |
102 | #define ERRCONFIG_MCUDISACKINTST BIT(22) | 102 | #define ERRCONFIG_MCUDISACKINTST BIT(22) |
103 | #define ERRCONFIG_VPBOUNDINTEN_V2 BIT(22) | 103 | #define ERRCONFIG_VPBOUNDINTEN_V2 BIT(22) |
104 | 104 | ||
105 | #define ERRCONFIG_STATUS_V1_MASK (ERRCONFIG_VPBOUNDINTST_V1 | \ | 105 | #define ERRCONFIG_STATUS_V1_MASK (ERRCONFIG_VPBOUNDINTST_V1 | \ |
106 | ERRCONFIG_MCUACCUMINTST | \ | 106 | ERRCONFIG_MCUACCUMINTST | \ |
107 | ERRCONFIG_MCUVALIDINTST | \ | 107 | ERRCONFIG_MCUVALIDINTST | \ |
108 | ERRCONFIG_MCUBOUNDINTST | \ | 108 | ERRCONFIG_MCUBOUNDINTST | \ |
109 | ERRCONFIG_MCUDISACKINTST) | 109 | ERRCONFIG_MCUDISACKINTST) |
110 | /* IRQSTATUS */ | 110 | /* IRQSTATUS */ |
111 | #define IRQSTATUS_MCUACCUMINT BIT(3) | 111 | #define IRQSTATUS_MCUACCUMINT BIT(3) |
112 | #define IRQSTATUS_MCVALIDINT BIT(2) | 112 | #define IRQSTATUS_MCVALIDINT BIT(2) |
113 | #define IRQSTATUS_MCBOUNDSINT BIT(1) | 113 | #define IRQSTATUS_MCBOUNDSINT BIT(1) |
114 | #define IRQSTATUS_MCUDISABLEACKINT BIT(0) | 114 | #define IRQSTATUS_MCUDISABLEACKINT BIT(0) |
115 | 115 | ||
116 | /* IRQENABLE_SET and IRQENABLE_CLEAR */ | 116 | /* IRQENABLE_SET and IRQENABLE_CLEAR */ |
117 | #define IRQENABLE_MCUACCUMINT BIT(3) | 117 | #define IRQENABLE_MCUACCUMINT BIT(3) |
118 | #define IRQENABLE_MCUVALIDINT BIT(2) | 118 | #define IRQENABLE_MCUVALIDINT BIT(2) |
119 | #define IRQENABLE_MCUBOUNDSINT BIT(1) | 119 | #define IRQENABLE_MCUBOUNDSINT BIT(1) |
120 | #define IRQENABLE_MCUDISABLEACKINT BIT(0) | 120 | #define IRQENABLE_MCUDISABLEACKINT BIT(0) |
121 | 121 | ||
122 | /* Common Bit values */ | 122 | /* Common Bit values */ |
123 | 123 | ||
124 | #define SRCLKLENGTH_12MHZ_SYSCLK 0x3c | 124 | #define SRCLKLENGTH_12MHZ_SYSCLK 0x3c |
125 | #define SRCLKLENGTH_13MHZ_SYSCLK 0x41 | 125 | #define SRCLKLENGTH_13MHZ_SYSCLK 0x41 |
126 | #define SRCLKLENGTH_19MHZ_SYSCLK 0x60 | 126 | #define SRCLKLENGTH_19MHZ_SYSCLK 0x60 |
127 | #define SRCLKLENGTH_26MHZ_SYSCLK 0x82 | 127 | #define SRCLKLENGTH_26MHZ_SYSCLK 0x82 |
128 | #define SRCLKLENGTH_38MHZ_SYSCLK 0xC0 | 128 | #define SRCLKLENGTH_38MHZ_SYSCLK 0xC0 |
129 | 129 | ||
130 | /* | 130 | /* |
131 | * 3430 specific values. Maybe these should be passed from board file or | 131 | * 3430 specific values. Maybe these should be passed from board file or |
132 | * pmic structures. | 132 | * pmic structures. |
133 | */ | 133 | */ |
134 | #define OMAP3430_SR_ACCUMDATA 0x1f4 | 134 | #define OMAP3430_SR_ACCUMDATA 0x1f4 |
135 | 135 | ||
136 | #define OMAP3430_SR1_SENPAVGWEIGHT 0x03 | 136 | #define OMAP3430_SR1_SENPAVGWEIGHT 0x03 |
137 | #define OMAP3430_SR1_SENNAVGWEIGHT 0x03 | 137 | #define OMAP3430_SR1_SENNAVGWEIGHT 0x03 |
138 | 138 | ||
139 | #define OMAP3430_SR2_SENPAVGWEIGHT 0x01 | 139 | #define OMAP3430_SR2_SENPAVGWEIGHT 0x01 |
140 | #define OMAP3430_SR2_SENNAVGWEIGHT 0x01 | 140 | #define OMAP3430_SR2_SENNAVGWEIGHT 0x01 |
141 | 141 | ||
142 | #define OMAP3430_SR_ERRWEIGHT 0x04 | 142 | #define OMAP3430_SR_ERRWEIGHT 0x04 |
143 | #define OMAP3430_SR_ERRMAXLIMIT 0x02 | 143 | #define OMAP3430_SR_ERRMAXLIMIT 0x02 |
144 | 144 | ||
145 | /** | 145 | /** |
146 | * struct omap_sr_pmic_data - Strucutre to be populated by pmic code to pass | 146 | * struct omap_sr_pmic_data - Strucutre to be populated by pmic code to pass |
147 | * pmic specific info to smartreflex driver | 147 | * pmic specific info to smartreflex driver |
148 | * | 148 | * |
149 | * @sr_pmic_init: API to initialize smartreflex on the PMIC side. | 149 | * @sr_pmic_init: API to initialize smartreflex on the PMIC side. |
150 | */ | 150 | */ |
151 | struct omap_sr_pmic_data { | 151 | struct omap_sr_pmic_data { |
152 | void (*sr_pmic_init) (void); | 152 | void (*sr_pmic_init) (void); |
153 | }; | 153 | }; |
154 | 154 | ||
155 | #ifdef CONFIG_OMAP_SMARTREFLEX | 155 | #ifdef CONFIG_OMAP_SMARTREFLEX |
156 | /* | 156 | /* |
157 | * The smart reflex driver supports CLASS1 CLASS2 and CLASS3 SR. | 157 | * The smart reflex driver supports CLASS1 CLASS2 and CLASS3 SR. |
158 | * The smartreflex class driver should pass the class type. | 158 | * The smartreflex class driver should pass the class type. |
159 | * Should be used to populate the class_type field of the | 159 | * Should be used to populate the class_type field of the |
160 | * omap_smartreflex_class_data structure. | 160 | * omap_smartreflex_class_data structure. |
161 | */ | 161 | */ |
162 | #define SR_CLASS1 0x1 | 162 | #define SR_CLASS1 0x1 |
163 | #define SR_CLASS2 0x2 | 163 | #define SR_CLASS2 0x2 |
164 | #define SR_CLASS3 0x3 | 164 | #define SR_CLASS3 0x3 |
165 | 165 | ||
166 | /** | 166 | /** |
167 | * struct omap_sr_class_data - Smartreflex class driver info | 167 | * struct omap_sr_class_data - Smartreflex class driver info |
168 | * | 168 | * |
169 | * @enable: API to enable a particular class smaartreflex. | 169 | * @enable: API to enable a particular class smaartreflex. |
170 | * @disable: API to disable a particular class smartreflex. | 170 | * @disable: API to disable a particular class smartreflex. |
171 | * @configure: API to configure a particular class smartreflex. | 171 | * @configure: API to configure a particular class smartreflex. |
172 | * @notify: API to notify the class driver about an event in SR. | 172 | * @notify: API to notify the class driver about an event in SR. |
173 | * Not needed for class3. | 173 | * Not needed for class3. |
174 | * @notify_flags: specify the events to be notified to the class driver | 174 | * @notify_flags: specify the events to be notified to the class driver |
175 | * @class_type: specify which smartreflex class. | 175 | * @class_type: specify which smartreflex class. |
176 | * Can be used by the SR driver to take any class | 176 | * Can be used by the SR driver to take any class |
177 | * based decisions. | 177 | * based decisions. |
178 | */ | 178 | */ |
179 | struct omap_sr_class_data { | 179 | struct omap_sr_class_data { |
180 | int (*enable)(struct voltagedomain *voltdm); | 180 | int (*enable)(struct voltagedomain *voltdm); |
181 | int (*disable)(struct voltagedomain *voltdm, int is_volt_reset); | 181 | int (*disable)(struct voltagedomain *voltdm, int is_volt_reset); |
182 | int (*configure)(struct voltagedomain *voltdm); | 182 | int (*configure)(struct voltagedomain *voltdm); |
183 | int (*notify)(struct voltagedomain *voltdm, u32 status); | 183 | int (*notify)(struct voltagedomain *voltdm, u32 status); |
184 | u8 notify_flags; | 184 | u8 notify_flags; |
185 | u8 class_type; | 185 | u8 class_type; |
186 | }; | 186 | }; |
187 | 187 | ||
188 | /** | 188 | /** |
189 | * struct omap_sr_nvalue_table - Smartreflex n-target value info | 189 | * struct omap_sr_nvalue_table - Smartreflex n-target value info |
190 | * | 190 | * |
191 | * @efuse_offs: The offset of the efuse where n-target values are stored. | 191 | * @efuse_offs: The offset of the efuse where n-target values are stored. |
192 | * @nvalue: The n-target value. | 192 | * @nvalue: The n-target value. |
193 | */ | 193 | */ |
194 | struct omap_sr_nvalue_table { | 194 | struct omap_sr_nvalue_table { |
195 | u32 efuse_offs; | 195 | u32 efuse_offs; |
196 | u32 nvalue; | 196 | u32 nvalue; |
197 | }; | 197 | }; |
198 | 198 | ||
199 | /** | 199 | /** |
200 | * struct omap_sr_data - Smartreflex platform data. | 200 | * struct omap_sr_data - Smartreflex platform data. |
201 | * | 201 | * |
202 | * @ip_type: Smartreflex IP type. | 202 | * @ip_type: Smartreflex IP type. |
203 | * @senp_mod: SENPENABLE value for the sr | 203 | * @senp_mod: SENPENABLE value for the sr |
204 | * @senn_mod: SENNENABLE value for sr | 204 | * @senn_mod: SENNENABLE value for sr |
205 | * @nvalue_count: Number of distinct nvalues in the nvalue table | 205 | * @nvalue_count: Number of distinct nvalues in the nvalue table |
206 | * @enable_on_init: whether this sr module needs to enabled at | 206 | * @enable_on_init: whether this sr module needs to enabled at |
207 | * boot up or not. | 207 | * boot up or not. |
208 | * @nvalue_table: table containing the efuse offsets and nvalues | 208 | * @nvalue_table: table containing the efuse offsets and nvalues |
209 | * corresponding to them. | 209 | * corresponding to them. |
210 | * @voltdm: Pointer to the voltage domain associated with the SR | 210 | * @voltdm: Pointer to the voltage domain associated with the SR |
211 | */ | 211 | */ |
212 | struct omap_sr_data { | 212 | struct omap_sr_data { |
213 | int ip_type; | 213 | int ip_type; |
214 | u32 senp_mod; | 214 | u32 senp_mod; |
215 | u32 senn_mod; | 215 | u32 senn_mod; |
216 | int nvalue_count; | 216 | int nvalue_count; |
217 | bool enable_on_init; | 217 | bool enable_on_init; |
218 | struct omap_sr_nvalue_table *nvalue_table; | 218 | struct omap_sr_nvalue_table *nvalue_table; |
219 | struct voltagedomain *voltdm; | 219 | struct voltagedomain *voltdm; |
220 | }; | 220 | }; |
221 | 221 | ||
222 | /* Smartreflex module enable/disable interface */ | 222 | /* Smartreflex module enable/disable interface */ |
223 | void omap_sr_enable(struct voltagedomain *voltdm); | 223 | void omap_sr_enable(struct voltagedomain *voltdm); |
224 | void omap_sr_disable(struct voltagedomain *voltdm); | 224 | void omap_sr_disable(struct voltagedomain *voltdm); |
225 | void omap_sr_disable_reset_volt(struct voltagedomain *voltdm); | 225 | void omap_sr_disable_reset_volt(struct voltagedomain *voltdm); |
226 | 226 | ||
227 | /* API to register the pmic specific data with the smartreflex driver. */ | 227 | /* API to register the pmic specific data with the smartreflex driver. */ |
228 | void omap_sr_register_pmic(struct omap_sr_pmic_data *pmic_data); | 228 | void omap_sr_register_pmic(struct omap_sr_pmic_data *pmic_data); |
229 | 229 | ||
230 | /* Smartreflex driver hooks to be called from Smartreflex class driver */ | 230 | /* Smartreflex driver hooks to be called from Smartreflex class driver */ |
231 | int sr_enable(struct voltagedomain *voltdm, unsigned long volt); | 231 | int sr_enable(struct voltagedomain *voltdm, unsigned long volt); |
232 | void sr_disable(struct voltagedomain *voltdm); | 232 | void sr_disable(struct voltagedomain *voltdm); |
233 | int sr_configure_errgen(struct voltagedomain *voltdm); | 233 | int sr_configure_errgen(struct voltagedomain *voltdm); |
234 | int sr_configure_minmax(struct voltagedomain *voltdm); | 234 | int sr_configure_minmax(struct voltagedomain *voltdm); |
235 | 235 | ||
236 | /* API to register the smartreflex class driver with the smartreflex driver */ | 236 | /* API to register the smartreflex class driver with the smartreflex driver */ |
237 | int sr_register_class(struct omap_sr_class_data *class_data); | 237 | int sr_register_class(struct omap_sr_class_data *class_data); |
238 | #else | 238 | #else |
239 | static inline void omap_sr_enable(struct voltagedomain *voltdm) {} | 239 | static inline void omap_sr_enable(struct voltagedomain *voltdm) {} |
240 | static inline void omap_sr_disable(struct voltagedomain *voltdm) {} | 240 | static inline void omap_sr_disable(struct voltagedomain *voltdm) {} |
241 | static inline void omap_sr_disable_reset_volt( | 241 | static inline void omap_sr_disable_reset_volt( |
242 | struct voltagedomain *voltdm) {} | 242 | struct voltagedomain *voltdm) {} |
243 | static inline void omap_sr_register_pmic( | 243 | static inline void omap_sr_register_pmic( |
244 | struct omap_sr_pmic_data *pmic_data) {} | 244 | struct omap_sr_pmic_data *pmic_data) {} |
245 | #endif | 245 | #endif |
246 | #endif | 246 | #endif |
arch/arm/mach-omap2/sr_device.c
1 | /* | 1 | /* |
2 | * OMAP3/OMAP4 smartreflex device file | 2 | * OMAP3/OMAP4 smartreflex device file |
3 | * | 3 | * |
4 | * Author: Thara Gopinath <thara@ti.com> | 4 | * Author: Thara Gopinath <thara@ti.com> |
5 | * | 5 | * |
6 | * Based originally on code from smartreflex.c | 6 | * Based originally on code from smartreflex.c |
7 | * Copyright (C) 2010 Texas Instruments, Inc. | 7 | * Copyright (C) 2010 Texas Instruments, Inc. |
8 | * Thara Gopinath <thara@ti.com> | 8 | * Thara Gopinath <thara@ti.com> |
9 | * | 9 | * |
10 | * Copyright (C) 2008 Nokia Corporation | 10 | * Copyright (C) 2008 Nokia Corporation |
11 | * Kalle Jokiniemi | 11 | * Kalle Jokiniemi |
12 | * | 12 | * |
13 | * Copyright (C) 2007 Texas Instruments, Inc. | 13 | * Copyright (C) 2007 Texas Instruments, Inc. |
14 | * Lesly A M <x0080970@ti.com> | 14 | * Lesly A M <x0080970@ti.com> |
15 | * | 15 | * |
16 | * This program is free software; you can redistribute it and/or modify | 16 | * This program is free software; you can redistribute it and/or modify |
17 | * it under the terms of the GNU General Public License version 2 as | 17 | * it under the terms of the GNU General Public License version 2 as |
18 | * published by the Free Software Foundation. | 18 | * published by the Free Software Foundation. |
19 | */ | 19 | */ |
20 | 20 | ||
21 | #include <linux/err.h> | 21 | #include <linux/err.h> |
22 | #include <linux/slab.h> | 22 | #include <linux/slab.h> |
23 | #include <linux/io.h> | 23 | #include <linux/io.h> |
24 | 24 | ||
25 | #include <plat/omap_device.h> | 25 | #include <plat/omap_device.h> |
26 | #include <plat/voltage.h> | ||
26 | 27 | ||
27 | #include "smartreflex.h" | 28 | #include "smartreflex.h" |
28 | #include "voltage.h" | ||
29 | #include "control.h" | 29 | #include "control.h" |
30 | #include "pm.h" | 30 | #include "pm.h" |
31 | 31 | ||
32 | static bool sr_enable_on_init; | 32 | static bool sr_enable_on_init; |
33 | 33 | ||
34 | /* Read EFUSE values from control registers for OMAP3430 */ | 34 | /* Read EFUSE values from control registers for OMAP3430 */ |
35 | static void __init sr_set_nvalues(struct omap_volt_data *volt_data, | 35 | static void __init sr_set_nvalues(struct omap_volt_data *volt_data, |
36 | struct omap_sr_data *sr_data) | 36 | struct omap_sr_data *sr_data) |
37 | { | 37 | { |
38 | struct omap_sr_nvalue_table *nvalue_table; | 38 | struct omap_sr_nvalue_table *nvalue_table; |
39 | int i, count = 0; | 39 | int i, count = 0; |
40 | 40 | ||
41 | while (volt_data[count].volt_nominal) | 41 | while (volt_data[count].volt_nominal) |
42 | count++; | 42 | count++; |
43 | 43 | ||
44 | nvalue_table = kzalloc(sizeof(struct omap_sr_nvalue_table)*count, | 44 | nvalue_table = kzalloc(sizeof(struct omap_sr_nvalue_table)*count, |
45 | GFP_KERNEL); | 45 | GFP_KERNEL); |
46 | 46 | ||
47 | for (i = 0; i < count; i++) { | 47 | for (i = 0; i < count; i++) { |
48 | u32 v; | 48 | u32 v; |
49 | /* | 49 | /* |
50 | * In OMAP4 the efuse registers are 24 bit aligned. | 50 | * In OMAP4 the efuse registers are 24 bit aligned. |
51 | * A __raw_readl will fail for non-32 bit aligned address | 51 | * A __raw_readl will fail for non-32 bit aligned address |
52 | * and hence the 8-bit read and shift. | 52 | * and hence the 8-bit read and shift. |
53 | */ | 53 | */ |
54 | if (cpu_is_omap44xx()) { | 54 | if (cpu_is_omap44xx()) { |
55 | u16 offset = volt_data[i].sr_efuse_offs; | 55 | u16 offset = volt_data[i].sr_efuse_offs; |
56 | 56 | ||
57 | v = omap_ctrl_readb(offset) | | 57 | v = omap_ctrl_readb(offset) | |
58 | omap_ctrl_readb(offset + 1) << 8 | | 58 | omap_ctrl_readb(offset + 1) << 8 | |
59 | omap_ctrl_readb(offset + 2) << 16; | 59 | omap_ctrl_readb(offset + 2) << 16; |
60 | } else { | 60 | } else { |
61 | v = omap_ctrl_readl(volt_data[i].sr_efuse_offs); | 61 | v = omap_ctrl_readl(volt_data[i].sr_efuse_offs); |
62 | } | 62 | } |
63 | 63 | ||
64 | nvalue_table[i].efuse_offs = volt_data[i].sr_efuse_offs; | 64 | nvalue_table[i].efuse_offs = volt_data[i].sr_efuse_offs; |
65 | nvalue_table[i].nvalue = v; | 65 | nvalue_table[i].nvalue = v; |
66 | } | 66 | } |
67 | 67 | ||
68 | sr_data->nvalue_table = nvalue_table; | 68 | sr_data->nvalue_table = nvalue_table; |
69 | sr_data->nvalue_count = count; | 69 | sr_data->nvalue_count = count; |
70 | } | 70 | } |
71 | 71 | ||
72 | static int sr_dev_init(struct omap_hwmod *oh, void *user) | 72 | static int sr_dev_init(struct omap_hwmod *oh, void *user) |
73 | { | 73 | { |
74 | struct omap_sr_data *sr_data; | 74 | struct omap_sr_data *sr_data; |
75 | struct platform_device *pdev; | 75 | struct platform_device *pdev; |
76 | struct omap_volt_data *volt_data; | 76 | struct omap_volt_data *volt_data; |
77 | char *name = "smartreflex"; | 77 | char *name = "smartreflex"; |
78 | static int i; | 78 | static int i; |
79 | 79 | ||
80 | sr_data = kzalloc(sizeof(struct omap_sr_data), GFP_KERNEL); | 80 | sr_data = kzalloc(sizeof(struct omap_sr_data), GFP_KERNEL); |
81 | if (!sr_data) { | 81 | if (!sr_data) { |
82 | pr_err("%s: Unable to allocate memory for %s sr_data.Error!\n", | 82 | pr_err("%s: Unable to allocate memory for %s sr_data.Error!\n", |
83 | __func__, oh->name); | 83 | __func__, oh->name); |
84 | return -ENOMEM; | 84 | return -ENOMEM; |
85 | } | 85 | } |
86 | 86 | ||
87 | if (!oh->vdd_name) { | 87 | if (!oh->vdd_name) { |
88 | pr_err("%s: No voltage domain specified for %s." | 88 | pr_err("%s: No voltage domain specified for %s." |
89 | "Cannot initialize\n", __func__, oh->name); | 89 | "Cannot initialize\n", __func__, oh->name); |
90 | goto exit; | 90 | goto exit; |
91 | } | 91 | } |
92 | 92 | ||
93 | sr_data->ip_type = oh->class->rev; | 93 | sr_data->ip_type = oh->class->rev; |
94 | sr_data->senn_mod = 0x1; | 94 | sr_data->senn_mod = 0x1; |
95 | sr_data->senp_mod = 0x1; | 95 | sr_data->senp_mod = 0x1; |
96 | 96 | ||
97 | sr_data->voltdm = voltdm_lookup(oh->vdd_name); | 97 | sr_data->voltdm = voltdm_lookup(oh->vdd_name); |
98 | if (IS_ERR(sr_data->voltdm)) { | 98 | if (IS_ERR(sr_data->voltdm)) { |
99 | pr_err("%s: Unable to get voltage domain pointer for VDD %s\n", | 99 | pr_err("%s: Unable to get voltage domain pointer for VDD %s\n", |
100 | __func__, oh->vdd_name); | 100 | __func__, oh->vdd_name); |
101 | goto exit; | 101 | goto exit; |
102 | } | 102 | } |
103 | 103 | ||
104 | omap_voltage_get_volttable(sr_data->voltdm, &volt_data); | 104 | omap_voltage_get_volttable(sr_data->voltdm, &volt_data); |
105 | if (!volt_data) { | 105 | if (!volt_data) { |
106 | pr_warning("%s: No Voltage table registerd fo VDD%d." | 106 | pr_warning("%s: No Voltage table registerd fo VDD%d." |
107 | "Something really wrong\n\n", __func__, i + 1); | 107 | "Something really wrong\n\n", __func__, i + 1); |
108 | goto exit; | 108 | goto exit; |
109 | } | 109 | } |
110 | 110 | ||
111 | sr_set_nvalues(volt_data, sr_data); | 111 | sr_set_nvalues(volt_data, sr_data); |
112 | 112 | ||
113 | sr_data->enable_on_init = sr_enable_on_init; | 113 | sr_data->enable_on_init = sr_enable_on_init; |
114 | 114 | ||
115 | pdev = omap_device_build(name, i, oh, sr_data, sizeof(*sr_data), | 115 | pdev = omap_device_build(name, i, oh, sr_data, sizeof(*sr_data), |
116 | NULL, 0, 0); | 116 | NULL, 0, 0); |
117 | if (IS_ERR(pdev)) | 117 | if (IS_ERR(pdev)) |
118 | pr_warning("%s: Could not build omap_device for %s: %s.\n\n", | 118 | pr_warning("%s: Could not build omap_device for %s: %s.\n\n", |
119 | __func__, name, oh->name); | 119 | __func__, name, oh->name); |
120 | exit: | 120 | exit: |
121 | i++; | 121 | i++; |
122 | kfree(sr_data); | 122 | kfree(sr_data); |
123 | return 0; | 123 | return 0; |
124 | } | 124 | } |
125 | 125 | ||
126 | /* | 126 | /* |
127 | * API to be called from board files to enable smartreflex | 127 | * API to be called from board files to enable smartreflex |
128 | * autocompensation at init. | 128 | * autocompensation at init. |
129 | */ | 129 | */ |
130 | void __init omap_enable_smartreflex_on_init(void) | 130 | void __init omap_enable_smartreflex_on_init(void) |
131 | { | 131 | { |
132 | sr_enable_on_init = true; | 132 | sr_enable_on_init = true; |
133 | } | 133 | } |
134 | 134 | ||
135 | int __init omap_devinit_smartreflex(void) | 135 | int __init omap_devinit_smartreflex(void) |
136 | { | 136 | { |
137 | return omap_hwmod_for_each_by_class("smartreflex", sr_dev_init, NULL); | 137 | return omap_hwmod_for_each_by_class("smartreflex", sr_dev_init, NULL); |
138 | } | 138 | } |
arch/arm/mach-omap2/vc.c
1 | /* | 1 | /* |
2 | * OMAP Voltage Controller (VC) interface | 2 | * OMAP Voltage Controller (VC) interface |
3 | * | 3 | * |
4 | * Copyright (C) 2011 Texas Instruments, Inc. | 4 | * Copyright (C) 2011 Texas Instruments, Inc. |
5 | * | 5 | * |
6 | * This file is licensed under the terms of the GNU General Public | 6 | * This file is licensed under the terms of the GNU General Public |
7 | * License version 2. This program is licensed "as is" without any | 7 | * License version 2. This program is licensed "as is" without any |
8 | * warranty of any kind, whether express or implied. | 8 | * warranty of any kind, whether express or implied. |
9 | */ | 9 | */ |
10 | #include <linux/kernel.h> | 10 | #include <linux/kernel.h> |
11 | #include <linux/delay.h> | 11 | #include <linux/delay.h> |
12 | #include <linux/init.h> | 12 | #include <linux/init.h> |
13 | 13 | ||
14 | #include <plat/cpu.h> | 14 | #include <plat/cpu.h> |
15 | #include <plat/voltage.h> | ||
16 | #include <plat/vc.h> | ||
15 | 17 | ||
16 | #include "voltage.h" | ||
17 | #include "vc.h" | ||
18 | #include "prm-regbits-34xx.h" | 18 | #include "prm-regbits-34xx.h" |
19 | #include "prm-regbits-44xx.h" | 19 | #include "prm-regbits-44xx.h" |
20 | #include "prm44xx.h" | 20 | #include "prm44xx.h" |
21 | 21 | ||
22 | /** | 22 | /** |
23 | * struct omap_vc_channel_cfg - describe the cfg_channel bitfield | 23 | * struct omap_vc_channel_cfg - describe the cfg_channel bitfield |
24 | * @sa: bit for slave address | 24 | * @sa: bit for slave address |
25 | * @rav: bit for voltage configuration register | 25 | * @rav: bit for voltage configuration register |
26 | * @rac: bit for command configuration register | 26 | * @rac: bit for command configuration register |
27 | * @racen: enable bit for RAC | 27 | * @racen: enable bit for RAC |
28 | * @cmd: bit for command value set selection | 28 | * @cmd: bit for command value set selection |
29 | * | 29 | * |
30 | * Channel configuration bits, common for OMAP3+ | 30 | * Channel configuration bits, common for OMAP3+ |
31 | * OMAP3 register: PRM_VC_CH_CONF | 31 | * OMAP3 register: PRM_VC_CH_CONF |
32 | * OMAP4 register: PRM_VC_CFG_CHANNEL | 32 | * OMAP4 register: PRM_VC_CFG_CHANNEL |
33 | * OMAP5 register: PRM_VC_SMPS_<voltdm>_CONFIG | 33 | * OMAP5 register: PRM_VC_SMPS_<voltdm>_CONFIG |
34 | */ | 34 | */ |
35 | struct omap_vc_channel_cfg { | 35 | struct omap_vc_channel_cfg { |
36 | u8 sa; | 36 | u8 sa; |
37 | u8 rav; | 37 | u8 rav; |
38 | u8 rac; | 38 | u8 rac; |
39 | u8 racen; | 39 | u8 racen; |
40 | u8 cmd; | 40 | u8 cmd; |
41 | }; | 41 | }; |
42 | 42 | ||
43 | static struct omap_vc_channel_cfg vc_default_channel_cfg = { | 43 | static struct omap_vc_channel_cfg vc_default_channel_cfg = { |
44 | .sa = BIT(0), | 44 | .sa = BIT(0), |
45 | .rav = BIT(1), | 45 | .rav = BIT(1), |
46 | .rac = BIT(2), | 46 | .rac = BIT(2), |
47 | .racen = BIT(3), | 47 | .racen = BIT(3), |
48 | .cmd = BIT(4), | 48 | .cmd = BIT(4), |
49 | }; | 49 | }; |
50 | 50 | ||
51 | /* | 51 | /* |
52 | * On OMAP3+, all VC channels have the above default bitfield | 52 | * On OMAP3+, all VC channels have the above default bitfield |
53 | * configuration, except the OMAP4 MPU channel. This appears | 53 | * configuration, except the OMAP4 MPU channel. This appears |
54 | * to be a freak accident as every other VC channel has the | 54 | * to be a freak accident as every other VC channel has the |
55 | * default configuration, thus creating a mutant channel config. | 55 | * default configuration, thus creating a mutant channel config. |
56 | */ | 56 | */ |
57 | static struct omap_vc_channel_cfg vc_mutant_channel_cfg = { | 57 | static struct omap_vc_channel_cfg vc_mutant_channel_cfg = { |
58 | .sa = BIT(0), | 58 | .sa = BIT(0), |
59 | .rav = BIT(2), | 59 | .rav = BIT(2), |
60 | .rac = BIT(3), | 60 | .rac = BIT(3), |
61 | .racen = BIT(4), | 61 | .racen = BIT(4), |
62 | .cmd = BIT(1), | 62 | .cmd = BIT(1), |
63 | }; | 63 | }; |
64 | 64 | ||
65 | static struct omap_vc_channel_cfg *vc_cfg_bits; | 65 | static struct omap_vc_channel_cfg *vc_cfg_bits; |
66 | #define CFG_CHANNEL_MASK 0x1f | 66 | #define CFG_CHANNEL_MASK 0x1f |
67 | 67 | ||
68 | /** | 68 | /** |
69 | * omap_vc_config_channel - configure VC channel to PMIC mappings | 69 | * omap_vc_config_channel - configure VC channel to PMIC mappings |
70 | * @voltdm: pointer to voltagdomain defining the desired VC channel | 70 | * @voltdm: pointer to voltagdomain defining the desired VC channel |
71 | * | 71 | * |
72 | * Configures the VC channel to PMIC mappings for the following | 72 | * Configures the VC channel to PMIC mappings for the following |
73 | * PMIC settings | 73 | * PMIC settings |
74 | * - i2c slave address (SA) | 74 | * - i2c slave address (SA) |
75 | * - voltage configuration address (RAV) | 75 | * - voltage configuration address (RAV) |
76 | * - command configuration address (RAC) and enable bit (RACEN) | 76 | * - command configuration address (RAC) and enable bit (RACEN) |
77 | * - command values for ON, ONLP, RET and OFF (CMD) | 77 | * - command values for ON, ONLP, RET and OFF (CMD) |
78 | * | 78 | * |
79 | * This function currently only allows flexible configuration of the | 79 | * This function currently only allows flexible configuration of the |
80 | * non-default channel. Starting with OMAP4, there are more than 2 | 80 | * non-default channel. Starting with OMAP4, there are more than 2 |
81 | * channels, with one defined as the default (on OMAP4, it's MPU.) | 81 | * channels, with one defined as the default (on OMAP4, it's MPU.) |
82 | * Only the non-default channel can be configured. | 82 | * Only the non-default channel can be configured. |
83 | */ | 83 | */ |
84 | static int omap_vc_config_channel(struct voltagedomain *voltdm) | 84 | static int omap_vc_config_channel(struct voltagedomain *voltdm) |
85 | { | 85 | { |
86 | struct omap_vc_channel *vc = voltdm->vc; | 86 | struct omap_vc_channel *vc = voltdm->vc; |
87 | 87 | ||
88 | /* | 88 | /* |
89 | * For default channel, the only configurable bit is RACEN. | 89 | * For default channel, the only configurable bit is RACEN. |
90 | * All others must stay at zero (see function comment above.) | 90 | * All others must stay at zero (see function comment above.) |
91 | */ | 91 | */ |
92 | if (vc->flags & OMAP_VC_CHANNEL_DEFAULT) | 92 | if (vc->flags & OMAP_VC_CHANNEL_DEFAULT) |
93 | vc->cfg_channel &= vc_cfg_bits->racen; | 93 | vc->cfg_channel &= vc_cfg_bits->racen; |
94 | 94 | ||
95 | voltdm->rmw(CFG_CHANNEL_MASK << vc->cfg_channel_sa_shift, | 95 | voltdm->rmw(CFG_CHANNEL_MASK << vc->cfg_channel_sa_shift, |
96 | vc->cfg_channel << vc->cfg_channel_sa_shift, | 96 | vc->cfg_channel << vc->cfg_channel_sa_shift, |
97 | vc->cfg_channel_reg); | 97 | vc->cfg_channel_reg); |
98 | 98 | ||
99 | return 0; | 99 | return 0; |
100 | } | 100 | } |
101 | 101 | ||
102 | /* Voltage scale and accessory APIs */ | 102 | /* Voltage scale and accessory APIs */ |
103 | int omap_vc_pre_scale(struct voltagedomain *voltdm, | 103 | int omap_vc_pre_scale(struct voltagedomain *voltdm, |
104 | unsigned long target_volt, | 104 | unsigned long target_volt, |
105 | u8 *target_vsel, u8 *current_vsel) | 105 | u8 *target_vsel, u8 *current_vsel) |
106 | { | 106 | { |
107 | struct omap_vc_channel *vc = voltdm->vc; | 107 | struct omap_vc_channel *vc = voltdm->vc; |
108 | u32 vc_cmdval; | 108 | u32 vc_cmdval; |
109 | 109 | ||
110 | /* Check if sufficient pmic info is available for this vdd */ | 110 | /* Check if sufficient pmic info is available for this vdd */ |
111 | if (!voltdm->pmic) { | 111 | if (!voltdm->pmic) { |
112 | pr_err("%s: Insufficient pmic info to scale the vdd_%s\n", | 112 | pr_err("%s: Insufficient pmic info to scale the vdd_%s\n", |
113 | __func__, voltdm->name); | 113 | __func__, voltdm->name); |
114 | return -EINVAL; | 114 | return -EINVAL; |
115 | } | 115 | } |
116 | 116 | ||
117 | if (!voltdm->pmic->uv_to_vsel) { | 117 | if (!voltdm->pmic->uv_to_vsel) { |
118 | pr_err("%s: PMIC function to convert voltage in uV to" | 118 | pr_err("%s: PMIC function to convert voltage in uV to" |
119 | "vsel not registered. Hence unable to scale voltage" | 119 | "vsel not registered. Hence unable to scale voltage" |
120 | "for vdd_%s\n", __func__, voltdm->name); | 120 | "for vdd_%s\n", __func__, voltdm->name); |
121 | return -ENODATA; | 121 | return -ENODATA; |
122 | } | 122 | } |
123 | 123 | ||
124 | if (!voltdm->read || !voltdm->write) { | 124 | if (!voltdm->read || !voltdm->write) { |
125 | pr_err("%s: No read/write API for accessing vdd_%s regs\n", | 125 | pr_err("%s: No read/write API for accessing vdd_%s regs\n", |
126 | __func__, voltdm->name); | 126 | __func__, voltdm->name); |
127 | return -EINVAL; | 127 | return -EINVAL; |
128 | } | 128 | } |
129 | 129 | ||
130 | *target_vsel = voltdm->pmic->uv_to_vsel(target_volt); | 130 | *target_vsel = voltdm->pmic->uv_to_vsel(target_volt); |
131 | *current_vsel = voltdm->pmic->uv_to_vsel(voltdm->nominal_volt); | 131 | *current_vsel = voltdm->pmic->uv_to_vsel(voltdm->nominal_volt); |
132 | 132 | ||
133 | /* Setting the ON voltage to the new target voltage */ | 133 | /* Setting the ON voltage to the new target voltage */ |
134 | vc_cmdval = voltdm->read(vc->cmdval_reg); | 134 | vc_cmdval = voltdm->read(vc->cmdval_reg); |
135 | vc_cmdval &= ~vc->common->cmd_on_mask; | 135 | vc_cmdval &= ~vc->common->cmd_on_mask; |
136 | vc_cmdval |= (*target_vsel << vc->common->cmd_on_shift); | 136 | vc_cmdval |= (*target_vsel << vc->common->cmd_on_shift); |
137 | voltdm->write(vc_cmdval, vc->cmdval_reg); | 137 | voltdm->write(vc_cmdval, vc->cmdval_reg); |
138 | 138 | ||
139 | omap_vp_update_errorgain(voltdm, target_volt); | 139 | omap_vp_update_errorgain(voltdm, target_volt); |
140 | 140 | ||
141 | return 0; | 141 | return 0; |
142 | } | 142 | } |
143 | 143 | ||
144 | void omap_vc_post_scale(struct voltagedomain *voltdm, | 144 | void omap_vc_post_scale(struct voltagedomain *voltdm, |
145 | unsigned long target_volt, | 145 | unsigned long target_volt, |
146 | u8 target_vsel, u8 current_vsel) | 146 | u8 target_vsel, u8 current_vsel) |
147 | { | 147 | { |
148 | u32 smps_steps = 0, smps_delay = 0; | 148 | u32 smps_steps = 0, smps_delay = 0; |
149 | 149 | ||
150 | smps_steps = abs(target_vsel - current_vsel); | 150 | smps_steps = abs(target_vsel - current_vsel); |
151 | /* SMPS slew rate / step size. 2us added as buffer. */ | 151 | /* SMPS slew rate / step size. 2us added as buffer. */ |
152 | smps_delay = ((smps_steps * voltdm->pmic->step_size) / | 152 | smps_delay = ((smps_steps * voltdm->pmic->step_size) / |
153 | voltdm->pmic->slew_rate) + 2; | 153 | voltdm->pmic->slew_rate) + 2; |
154 | udelay(smps_delay); | 154 | udelay(smps_delay); |
155 | } | 155 | } |
156 | 156 | ||
157 | /* vc_bypass_scale - VC bypass method of voltage scaling */ | 157 | /* vc_bypass_scale - VC bypass method of voltage scaling */ |
158 | int omap_vc_bypass_scale(struct voltagedomain *voltdm, | 158 | int omap_vc_bypass_scale(struct voltagedomain *voltdm, |
159 | unsigned long target_volt) | 159 | unsigned long target_volt) |
160 | { | 160 | { |
161 | struct omap_vc_channel *vc = voltdm->vc; | 161 | struct omap_vc_channel *vc = voltdm->vc; |
162 | u32 loop_cnt = 0, retries_cnt = 0; | 162 | u32 loop_cnt = 0, retries_cnt = 0; |
163 | u32 vc_valid, vc_bypass_val_reg, vc_bypass_value; | 163 | u32 vc_valid, vc_bypass_val_reg, vc_bypass_value; |
164 | u8 target_vsel, current_vsel; | 164 | u8 target_vsel, current_vsel; |
165 | int ret; | 165 | int ret; |
166 | 166 | ||
167 | ret = omap_vc_pre_scale(voltdm, target_volt, &target_vsel, ¤t_vsel); | 167 | ret = omap_vc_pre_scale(voltdm, target_volt, &target_vsel, ¤t_vsel); |
168 | if (ret) | 168 | if (ret) |
169 | return ret; | 169 | return ret; |
170 | 170 | ||
171 | vc_valid = vc->common->valid; | 171 | vc_valid = vc->common->valid; |
172 | vc_bypass_val_reg = vc->common->bypass_val_reg; | 172 | vc_bypass_val_reg = vc->common->bypass_val_reg; |
173 | vc_bypass_value = (target_vsel << vc->common->data_shift) | | 173 | vc_bypass_value = (target_vsel << vc->common->data_shift) | |
174 | (vc->volt_reg_addr << vc->common->regaddr_shift) | | 174 | (vc->volt_reg_addr << vc->common->regaddr_shift) | |
175 | (vc->i2c_slave_addr << vc->common->slaveaddr_shift); | 175 | (vc->i2c_slave_addr << vc->common->slaveaddr_shift); |
176 | 176 | ||
177 | voltdm->write(vc_bypass_value, vc_bypass_val_reg); | 177 | voltdm->write(vc_bypass_value, vc_bypass_val_reg); |
178 | voltdm->write(vc_bypass_value | vc_valid, vc_bypass_val_reg); | 178 | voltdm->write(vc_bypass_value | vc_valid, vc_bypass_val_reg); |
179 | 179 | ||
180 | vc_bypass_value = voltdm->read(vc_bypass_val_reg); | 180 | vc_bypass_value = voltdm->read(vc_bypass_val_reg); |
181 | /* | 181 | /* |
182 | * Loop till the bypass command is acknowledged from the SMPS. | 182 | * Loop till the bypass command is acknowledged from the SMPS. |
183 | * NOTE: This is legacy code. The loop count and retry count needs | 183 | * NOTE: This is legacy code. The loop count and retry count needs |
184 | * to be revisited. | 184 | * to be revisited. |
185 | */ | 185 | */ |
186 | while (!(vc_bypass_value & vc_valid)) { | 186 | while (!(vc_bypass_value & vc_valid)) { |
187 | loop_cnt++; | 187 | loop_cnt++; |
188 | 188 | ||
189 | if (retries_cnt > 10) { | 189 | if (retries_cnt > 10) { |
190 | pr_warning("%s: Retry count exceeded\n", __func__); | 190 | pr_warning("%s: Retry count exceeded\n", __func__); |
191 | return -ETIMEDOUT; | 191 | return -ETIMEDOUT; |
192 | } | 192 | } |
193 | 193 | ||
194 | if (loop_cnt > 50) { | 194 | if (loop_cnt > 50) { |
195 | retries_cnt++; | 195 | retries_cnt++; |
196 | loop_cnt = 0; | 196 | loop_cnt = 0; |
197 | udelay(10); | 197 | udelay(10); |
198 | } | 198 | } |
199 | vc_bypass_value = voltdm->read(vc_bypass_val_reg); | 199 | vc_bypass_value = voltdm->read(vc_bypass_val_reg); |
200 | } | 200 | } |
201 | 201 | ||
202 | omap_vc_post_scale(voltdm, target_volt, target_vsel, current_vsel); | 202 | omap_vc_post_scale(voltdm, target_volt, target_vsel, current_vsel); |
203 | return 0; | 203 | return 0; |
204 | } | 204 | } |
205 | 205 | ||
206 | static void __init omap3_vfsm_init(struct voltagedomain *voltdm) | 206 | static void __init omap3_vfsm_init(struct voltagedomain *voltdm) |
207 | { | 207 | { |
208 | /* | 208 | /* |
209 | * Voltage Manager FSM parameters init | 209 | * Voltage Manager FSM parameters init |
210 | * XXX This data should be passed in from the board file | 210 | * XXX This data should be passed in from the board file |
211 | */ | 211 | */ |
212 | voltdm->write(OMAP3_CLKSETUP, OMAP3_PRM_CLKSETUP_OFFSET); | 212 | voltdm->write(OMAP3_CLKSETUP, OMAP3_PRM_CLKSETUP_OFFSET); |
213 | voltdm->write(OMAP3_VOLTOFFSET, OMAP3_PRM_VOLTOFFSET_OFFSET); | 213 | voltdm->write(OMAP3_VOLTOFFSET, OMAP3_PRM_VOLTOFFSET_OFFSET); |
214 | voltdm->write(OMAP3_VOLTSETUP2, OMAP3_PRM_VOLTSETUP2_OFFSET); | 214 | voltdm->write(OMAP3_VOLTSETUP2, OMAP3_PRM_VOLTSETUP2_OFFSET); |
215 | } | 215 | } |
216 | 216 | ||
217 | static void __init omap3_vc_init_channel(struct voltagedomain *voltdm) | 217 | static void __init omap3_vc_init_channel(struct voltagedomain *voltdm) |
218 | { | 218 | { |
219 | static bool is_initialized; | 219 | static bool is_initialized; |
220 | 220 | ||
221 | if (is_initialized) | 221 | if (is_initialized) |
222 | return; | 222 | return; |
223 | 223 | ||
224 | omap3_vfsm_init(voltdm); | 224 | omap3_vfsm_init(voltdm); |
225 | 225 | ||
226 | is_initialized = true; | 226 | is_initialized = true; |
227 | } | 227 | } |
228 | 228 | ||
229 | 229 | ||
230 | /* OMAP4 specific voltage init functions */ | 230 | /* OMAP4 specific voltage init functions */ |
231 | static void __init omap4_vc_init_channel(struct voltagedomain *voltdm) | 231 | static void __init omap4_vc_init_channel(struct voltagedomain *voltdm) |
232 | { | 232 | { |
233 | static bool is_initialized; | 233 | static bool is_initialized; |
234 | u32 vc_val; | 234 | u32 vc_val; |
235 | 235 | ||
236 | if (is_initialized) | 236 | if (is_initialized) |
237 | return; | 237 | return; |
238 | 238 | ||
239 | /* XXX These are magic numbers and do not belong! */ | 239 | /* XXX These are magic numbers and do not belong! */ |
240 | vc_val = (0x60 << OMAP4430_SCLL_SHIFT | 0x26 << OMAP4430_SCLH_SHIFT); | 240 | vc_val = (0x60 << OMAP4430_SCLL_SHIFT | 0x26 << OMAP4430_SCLH_SHIFT); |
241 | voltdm->write(vc_val, OMAP4_PRM_VC_CFG_I2C_CLK_OFFSET); | 241 | voltdm->write(vc_val, OMAP4_PRM_VC_CFG_I2C_CLK_OFFSET); |
242 | 242 | ||
243 | is_initialized = true; | 243 | is_initialized = true; |
244 | } | 244 | } |
245 | 245 | ||
246 | /** | 246 | /** |
247 | * omap_vc_i2c_init - initialize I2C interface to PMIC | 247 | * omap_vc_i2c_init - initialize I2C interface to PMIC |
248 | * @voltdm: voltage domain containing VC data | 248 | * @voltdm: voltage domain containing VC data |
249 | * | 249 | * |
250 | * Use PMIC supplied seetings for I2C high-speed mode and | 250 | * Use PMIC supplied seetings for I2C high-speed mode and |
251 | * master code (if set) and program the VC I2C configuration | 251 | * master code (if set) and program the VC I2C configuration |
252 | * register. | 252 | * register. |
253 | * | 253 | * |
254 | * The VC I2C configuration is common to all VC channels, | 254 | * The VC I2C configuration is common to all VC channels, |
255 | * so this function only configures I2C for the first VC | 255 | * so this function only configures I2C for the first VC |
256 | * channel registers. All other VC channels will use the | 256 | * channel registers. All other VC channels will use the |
257 | * same configuration. | 257 | * same configuration. |
258 | */ | 258 | */ |
259 | static void __init omap_vc_i2c_init(struct voltagedomain *voltdm) | 259 | static void __init omap_vc_i2c_init(struct voltagedomain *voltdm) |
260 | { | 260 | { |
261 | struct omap_vc_channel *vc = voltdm->vc; | 261 | struct omap_vc_channel *vc = voltdm->vc; |
262 | static bool initialized; | 262 | static bool initialized; |
263 | static bool i2c_high_speed; | 263 | static bool i2c_high_speed; |
264 | u8 mcode; | 264 | u8 mcode; |
265 | 265 | ||
266 | if (initialized) { | 266 | if (initialized) { |
267 | if (voltdm->pmic->i2c_high_speed != i2c_high_speed) | 267 | if (voltdm->pmic->i2c_high_speed != i2c_high_speed) |
268 | pr_warn("%s: I2C config for all channels must match.", | 268 | pr_warn("%s: I2C config for all channels must match.", |
269 | __func__); | 269 | __func__); |
270 | return; | 270 | return; |
271 | } | 271 | } |
272 | 272 | ||
273 | i2c_high_speed = voltdm->pmic->i2c_high_speed; | 273 | i2c_high_speed = voltdm->pmic->i2c_high_speed; |
274 | if (i2c_high_speed) | 274 | if (i2c_high_speed) |
275 | voltdm->rmw(vc->common->i2c_cfg_hsen_mask, | 275 | voltdm->rmw(vc->common->i2c_cfg_hsen_mask, |
276 | vc->common->i2c_cfg_hsen_mask, | 276 | vc->common->i2c_cfg_hsen_mask, |
277 | vc->common->i2c_cfg_reg); | 277 | vc->common->i2c_cfg_reg); |
278 | 278 | ||
279 | mcode = voltdm->pmic->i2c_mcode; | 279 | mcode = voltdm->pmic->i2c_mcode; |
280 | if (mcode) | 280 | if (mcode) |
281 | voltdm->rmw(vc->common->i2c_mcode_mask, | 281 | voltdm->rmw(vc->common->i2c_mcode_mask, |
282 | mcode << __ffs(vc->common->i2c_mcode_mask), | 282 | mcode << __ffs(vc->common->i2c_mcode_mask), |
283 | vc->common->i2c_cfg_reg); | 283 | vc->common->i2c_cfg_reg); |
284 | 284 | ||
285 | initialized = true; | 285 | initialized = true; |
286 | } | 286 | } |
287 | 287 | ||
288 | void __init omap_vc_init_channel(struct voltagedomain *voltdm) | 288 | void __init omap_vc_init_channel(struct voltagedomain *voltdm) |
289 | { | 289 | { |
290 | struct omap_vc_channel *vc = voltdm->vc; | 290 | struct omap_vc_channel *vc = voltdm->vc; |
291 | u8 on_vsel, onlp_vsel, ret_vsel, off_vsel; | 291 | u8 on_vsel, onlp_vsel, ret_vsel, off_vsel; |
292 | u32 val; | 292 | u32 val; |
293 | 293 | ||
294 | if (!voltdm->pmic || !voltdm->pmic->uv_to_vsel) { | 294 | if (!voltdm->pmic || !voltdm->pmic->uv_to_vsel) { |
295 | pr_err("%s: PMIC info requried to configure vc for" | 295 | pr_err("%s: PMIC info requried to configure vc for" |
296 | "vdd_%s not populated.Hence cannot initialize vc\n", | 296 | "vdd_%s not populated.Hence cannot initialize vc\n", |
297 | __func__, voltdm->name); | 297 | __func__, voltdm->name); |
298 | return; | 298 | return; |
299 | } | 299 | } |
300 | 300 | ||
301 | if (!voltdm->read || !voltdm->write) { | 301 | if (!voltdm->read || !voltdm->write) { |
302 | pr_err("%s: No read/write API for accessing vdd_%s regs\n", | 302 | pr_err("%s: No read/write API for accessing vdd_%s regs\n", |
303 | __func__, voltdm->name); | 303 | __func__, voltdm->name); |
304 | return; | 304 | return; |
305 | } | 305 | } |
306 | 306 | ||
307 | vc->cfg_channel = 0; | 307 | vc->cfg_channel = 0; |
308 | if (vc->flags & OMAP_VC_CHANNEL_CFG_MUTANT) | 308 | if (vc->flags & OMAP_VC_CHANNEL_CFG_MUTANT) |
309 | vc_cfg_bits = &vc_mutant_channel_cfg; | 309 | vc_cfg_bits = &vc_mutant_channel_cfg; |
310 | else | 310 | else |
311 | vc_cfg_bits = &vc_default_channel_cfg; | 311 | vc_cfg_bits = &vc_default_channel_cfg; |
312 | 312 | ||
313 | /* get PMIC/board specific settings */ | 313 | /* get PMIC/board specific settings */ |
314 | vc->i2c_slave_addr = voltdm->pmic->i2c_slave_addr; | 314 | vc->i2c_slave_addr = voltdm->pmic->i2c_slave_addr; |
315 | vc->volt_reg_addr = voltdm->pmic->volt_reg_addr; | 315 | vc->volt_reg_addr = voltdm->pmic->volt_reg_addr; |
316 | vc->cmd_reg_addr = voltdm->pmic->cmd_reg_addr; | 316 | vc->cmd_reg_addr = voltdm->pmic->cmd_reg_addr; |
317 | vc->setup_time = voltdm->pmic->volt_setup_time; | 317 | vc->setup_time = voltdm->pmic->volt_setup_time; |
318 | 318 | ||
319 | /* Configure the i2c slave address for this VC */ | 319 | /* Configure the i2c slave address for this VC */ |
320 | voltdm->rmw(vc->smps_sa_mask, | 320 | voltdm->rmw(vc->smps_sa_mask, |
321 | vc->i2c_slave_addr << __ffs(vc->smps_sa_mask), | 321 | vc->i2c_slave_addr << __ffs(vc->smps_sa_mask), |
322 | vc->smps_sa_reg); | 322 | vc->smps_sa_reg); |
323 | vc->cfg_channel |= vc_cfg_bits->sa; | 323 | vc->cfg_channel |= vc_cfg_bits->sa; |
324 | 324 | ||
325 | /* | 325 | /* |
326 | * Configure the PMIC register addresses. | 326 | * Configure the PMIC register addresses. |
327 | */ | 327 | */ |
328 | voltdm->rmw(vc->smps_volra_mask, | 328 | voltdm->rmw(vc->smps_volra_mask, |
329 | vc->volt_reg_addr << __ffs(vc->smps_volra_mask), | 329 | vc->volt_reg_addr << __ffs(vc->smps_volra_mask), |
330 | vc->smps_volra_reg); | 330 | vc->smps_volra_reg); |
331 | vc->cfg_channel |= vc_cfg_bits->rav; | 331 | vc->cfg_channel |= vc_cfg_bits->rav; |
332 | 332 | ||
333 | if (vc->cmd_reg_addr) { | 333 | if (vc->cmd_reg_addr) { |
334 | voltdm->rmw(vc->smps_cmdra_mask, | 334 | voltdm->rmw(vc->smps_cmdra_mask, |
335 | vc->cmd_reg_addr << __ffs(vc->smps_cmdra_mask), | 335 | vc->cmd_reg_addr << __ffs(vc->smps_cmdra_mask), |
336 | vc->smps_cmdra_reg); | 336 | vc->smps_cmdra_reg); |
337 | vc->cfg_channel |= vc_cfg_bits->rac | vc_cfg_bits->racen; | 337 | vc->cfg_channel |= vc_cfg_bits->rac | vc_cfg_bits->racen; |
338 | } | 338 | } |
339 | 339 | ||
340 | /* Set up the on, inactive, retention and off voltage */ | 340 | /* Set up the on, inactive, retention and off voltage */ |
341 | on_vsel = voltdm->pmic->uv_to_vsel(voltdm->pmic->on_volt); | 341 | on_vsel = voltdm->pmic->uv_to_vsel(voltdm->pmic->on_volt); |
342 | onlp_vsel = voltdm->pmic->uv_to_vsel(voltdm->pmic->onlp_volt); | 342 | onlp_vsel = voltdm->pmic->uv_to_vsel(voltdm->pmic->onlp_volt); |
343 | ret_vsel = voltdm->pmic->uv_to_vsel(voltdm->pmic->ret_volt); | 343 | ret_vsel = voltdm->pmic->uv_to_vsel(voltdm->pmic->ret_volt); |
344 | off_vsel = voltdm->pmic->uv_to_vsel(voltdm->pmic->off_volt); | 344 | off_vsel = voltdm->pmic->uv_to_vsel(voltdm->pmic->off_volt); |
345 | val = ((on_vsel << vc->common->cmd_on_shift) | | 345 | val = ((on_vsel << vc->common->cmd_on_shift) | |
346 | (onlp_vsel << vc->common->cmd_onlp_shift) | | 346 | (onlp_vsel << vc->common->cmd_onlp_shift) | |
347 | (ret_vsel << vc->common->cmd_ret_shift) | | 347 | (ret_vsel << vc->common->cmd_ret_shift) | |
348 | (off_vsel << vc->common->cmd_off_shift)); | 348 | (off_vsel << vc->common->cmd_off_shift)); |
349 | voltdm->write(val, vc->cmdval_reg); | 349 | voltdm->write(val, vc->cmdval_reg); |
350 | vc->cfg_channel |= vc_cfg_bits->cmd; | 350 | vc->cfg_channel |= vc_cfg_bits->cmd; |
351 | 351 | ||
352 | /* Channel configuration */ | 352 | /* Channel configuration */ |
353 | omap_vc_config_channel(voltdm); | 353 | omap_vc_config_channel(voltdm); |
354 | 354 | ||
355 | /* Configure the setup times */ | 355 | /* Configure the setup times */ |
356 | voltdm->rmw(voltdm->vfsm->voltsetup_mask, | 356 | voltdm->rmw(voltdm->vfsm->voltsetup_mask, |
357 | vc->setup_time << __ffs(voltdm->vfsm->voltsetup_mask), | 357 | vc->setup_time << __ffs(voltdm->vfsm->voltsetup_mask), |
358 | voltdm->vfsm->voltsetup_reg); | 358 | voltdm->vfsm->voltsetup_reg); |
359 | 359 | ||
360 | omap_vc_i2c_init(voltdm); | 360 | omap_vc_i2c_init(voltdm); |
361 | 361 | ||
362 | if (cpu_is_omap34xx()) | 362 | if (cpu_is_omap34xx()) |
363 | omap3_vc_init_channel(voltdm); | 363 | omap3_vc_init_channel(voltdm); |
364 | else if (cpu_is_omap44xx()) | 364 | else if (cpu_is_omap44xx()) |
365 | omap4_vc_init_channel(voltdm); | 365 | omap4_vc_init_channel(voltdm); |
366 | } | 366 | } |
arch/arm/mach-omap2/vc.h
1 | /* | File was deleted | |
2 | * OMAP3/4 Voltage Controller (VC) structure and macro definitions | ||
3 | * | ||
4 | * Copyright (C) 2007, 2010 Texas Instruments, Inc. | ||
5 | * Rajendra Nayak <rnayak@ti.com> | ||
6 | * Lesly A M <x0080970@ti.com> | ||
7 | * Thara Gopinath <thara@ti.com> | ||
8 | * | ||
9 | * Copyright (C) 2008, 2011 Nokia Corporation | ||
10 | * Kalle Jokiniemi | ||
11 | * Paul Walmsley | ||
12 | * | ||
13 | * This program is free software; you can redistribute it and/or | ||
14 | * modify it under the terms of the GNU General Public License version | ||
15 | * 2 as published by the Free Software Foundation. | ||
16 | */ | ||
17 | #ifndef __ARCH_ARM_MACH_OMAP2_VC_H | ||
18 | #define __ARCH_ARM_MACH_OMAP2_VC_H | ||
19 | |||
20 | #include <linux/kernel.h> | ||
21 | |||
22 | struct voltagedomain; | ||
23 | |||
24 | /** | ||
25 | * struct omap_vc_common - per-VC register/bitfield data | ||
26 | * @cmd_on_mask: ON bitmask in PRM_VC_CMD_VAL* register | ||
27 | * @valid: VALID bitmask in PRM_VC_BYPASS_VAL register | ||
28 | * @bypass_val_reg: Offset of PRM_VC_BYPASS_VAL reg from PRM start | ||
29 | * @data_shift: DATA field shift in PRM_VC_BYPASS_VAL register | ||
30 | * @slaveaddr_shift: SLAVEADDR field shift in PRM_VC_BYPASS_VAL register | ||
31 | * @regaddr_shift: REGADDR field shift in PRM_VC_BYPASS_VAL register | ||
32 | * @cmd_on_shift: ON field shift in PRM_VC_CMD_VAL_* register | ||
33 | * @cmd_onlp_shift: ONLP field shift in PRM_VC_CMD_VAL_* register | ||
34 | * @cmd_ret_shift: RET field shift in PRM_VC_CMD_VAL_* register | ||
35 | * @cmd_off_shift: OFF field shift in PRM_VC_CMD_VAL_* register | ||
36 | * @i2c_cfg_reg: I2C configuration register offset | ||
37 | * @i2c_cfg_hsen_mask: high-speed mode bit field mask in I2C config register | ||
38 | * @i2c_mcode_mask: MCODE field mask for I2C config register | ||
39 | * | ||
40 | * XXX One of cmd_on_mask and cmd_on_shift are not needed | ||
41 | * XXX VALID should probably be a shift, not a mask | ||
42 | */ | ||
43 | struct omap_vc_common { | ||
44 | u32 cmd_on_mask; | ||
45 | u32 valid; | ||
46 | u8 bypass_val_reg; | ||
47 | u8 data_shift; | ||
48 | u8 slaveaddr_shift; | ||
49 | u8 regaddr_shift; | ||
50 | u8 cmd_on_shift; | ||
51 | u8 cmd_onlp_shift; | ||
52 | u8 cmd_ret_shift; | ||
53 | u8 cmd_off_shift; | ||
54 | u8 i2c_cfg_reg; | ||
55 | u8 i2c_cfg_hsen_mask; | ||
56 | u8 i2c_mcode_mask; | ||
57 | }; | ||
58 | |||
59 | /* omap_vc_channel.flags values */ | ||
60 | #define OMAP_VC_CHANNEL_DEFAULT BIT(0) | ||
61 | #define OMAP_VC_CHANNEL_CFG_MUTANT BIT(1) | ||
62 | |||
63 | /** | ||
64 | * struct omap_vc_channel - VC per-instance data | ||
65 | * @i2c_slave_addr: I2C slave address of PMIC for this VC channel | ||
66 | * @volt_reg_addr: voltage configuration register address | ||
67 | * @cmd_reg_addr: command configuration register address | ||
68 | * @setup_time: setup time (in sys_clk cycles) of regulator for this channel | ||
69 | * @cfg_channel: current value of VC channel configuration register | ||
70 | * @i2c_high_speed: whether or not to use I2C high-speed mode | ||
71 | * | ||
72 | * @common: pointer to VC common data for this platform | ||
73 | * @smps_sa_mask: i2c slave address bitmask in the PRM_VC_SMPS_SA register | ||
74 | * @smps_volra_mask: VOLRA* bitmask in the PRM_VC_VOL_RA register | ||
75 | * @smps_cmdra_mask: CMDRA* bitmask in the PRM_VC_CMD_RA register | ||
76 | * @cmdval_reg: register for on/ret/off voltage level values for this channel | ||
77 | * @smps_sa_reg: Offset of PRM_VC_SMPS_SA reg from PRM start | ||
78 | * @smps_volra_reg: Offset of PRM_VC_SMPS_VOL_RA reg from PRM start | ||
79 | * @smps_cmdra_reg: Offset of PRM_VC_SMPS_CMD_RA reg from PRM start | ||
80 | * @cfg_channel_reg: VC channel configuration register | ||
81 | * @cfg_channel_sa_shift: bit shift for slave address cfg_channel register | ||
82 | * @flags: VC channel-specific flags (optional) | ||
83 | */ | ||
84 | struct omap_vc_channel { | ||
85 | /* channel state */ | ||
86 | u16 i2c_slave_addr; | ||
87 | u16 volt_reg_addr; | ||
88 | u16 cmd_reg_addr; | ||
89 | u16 setup_time; | ||
90 | u8 cfg_channel; | ||
91 | bool i2c_high_speed; | ||
92 | |||
93 | /* register access data */ | ||
94 | const struct omap_vc_common *common; | ||
95 | u32 smps_sa_mask; | ||
96 | u32 smps_volra_mask; | ||
97 | u32 smps_cmdra_mask; | ||
98 | u8 cmdval_reg; | ||
99 | u8 smps_sa_reg; | ||
100 | u8 smps_volra_reg; | ||
101 | u8 smps_cmdra_reg; | ||
102 | u8 cfg_channel_reg; | ||
103 | u8 cfg_channel_sa_shift; | ||
104 | u8 flags; | ||
105 | }; | ||
106 | |||
107 | extern struct omap_vc_channel omap3_vc_mpu; | ||
108 | extern struct omap_vc_channel omap3_vc_core; | ||
109 | |||
110 | extern struct omap_vc_channel omap4_vc_mpu; | ||
111 | extern struct omap_vc_channel omap4_vc_iva; | ||
112 | extern struct omap_vc_channel omap4_vc_core; | ||
113 | |||
114 | void omap_vc_init_channel(struct voltagedomain *voltdm); | ||
115 | int omap_vc_pre_scale(struct voltagedomain *voltdm, | ||
116 | unsigned long target_volt, | ||
117 | u8 *target_vsel, u8 *current_vsel); | ||
118 | void omap_vc_post_scale(struct voltagedomain *voltdm, | ||
119 | unsigned long target_volt, | ||
120 | u8 target_vsel, u8 current_vsel); | ||
121 | int omap_vc_bypass_scale(struct voltagedomain *voltdm, | ||
122 | unsigned long target_volt); | ||
123 | |||
124 | #endif | ||
125 | 1 | /* | |
126 | 2 | * OMAP3/4 Voltage Controller (VC) structure and macro definitions |
arch/arm/mach-omap2/vc3xxx_data.c
1 | /* | 1 | /* |
2 | * OMAP3 Voltage Controller (VC) data | 2 | * OMAP3 Voltage Controller (VC) data |
3 | * | 3 | * |
4 | * Copyright (C) 2007, 2010 Texas Instruments, Inc. | 4 | * Copyright (C) 2007, 2010 Texas Instruments, Inc. |
5 | * Rajendra Nayak <rnayak@ti.com> | 5 | * Rajendra Nayak <rnayak@ti.com> |
6 | * Lesly A M <x0080970@ti.com> | 6 | * Lesly A M <x0080970@ti.com> |
7 | * Thara Gopinath <thara@ti.com> | 7 | * Thara Gopinath <thara@ti.com> |
8 | * | 8 | * |
9 | * Copyright (C) 2008, 2011 Nokia Corporation | 9 | * Copyright (C) 2008, 2011 Nokia Corporation |
10 | * Kalle Jokiniemi | 10 | * Kalle Jokiniemi |
11 | * Paul Walmsley | 11 | * Paul Walmsley |
12 | * | 12 | * |
13 | * This program is free software; you can redistribute it and/or modify | 13 | * This program is free software; you can redistribute it and/or modify |
14 | * it under the terms of the GNU General Public License version 2 as | 14 | * it under the terms of the GNU General Public License version 2 as |
15 | * published by the Free Software Foundation. | 15 | * published by the Free Software Foundation. |
16 | */ | 16 | */ |
17 | #include <linux/io.h> | 17 | #include <linux/io.h> |
18 | #include <linux/err.h> | 18 | #include <linux/err.h> |
19 | #include <linux/init.h> | 19 | #include <linux/init.h> |
20 | 20 | ||
21 | #include <plat/common.h> | 21 | #include <plat/common.h> |
22 | #include <plat/voltage.h> | ||
23 | #include <plat/vc.h> | ||
22 | 24 | ||
23 | #include "prm-regbits-34xx.h" | 25 | #include "prm-regbits-34xx.h" |
24 | #include "voltage.h" | ||
25 | |||
26 | #include "vc.h" | ||
27 | 26 | ||
28 | /* | 27 | /* |
29 | * VC data common to 34xx/36xx chips | 28 | * VC data common to 34xx/36xx chips |
30 | * XXX This stuff presumably belongs in the vc3xxx.c or vc.c file. | 29 | * XXX This stuff presumably belongs in the vc3xxx.c or vc.c file. |
31 | */ | 30 | */ |
32 | static struct omap_vc_common omap3_vc_common = { | 31 | static struct omap_vc_common omap3_vc_common = { |
33 | .bypass_val_reg = OMAP3_PRM_VC_BYPASS_VAL_OFFSET, | 32 | .bypass_val_reg = OMAP3_PRM_VC_BYPASS_VAL_OFFSET, |
34 | .data_shift = OMAP3430_DATA_SHIFT, | 33 | .data_shift = OMAP3430_DATA_SHIFT, |
35 | .slaveaddr_shift = OMAP3430_SLAVEADDR_SHIFT, | 34 | .slaveaddr_shift = OMAP3430_SLAVEADDR_SHIFT, |
36 | .regaddr_shift = OMAP3430_REGADDR_SHIFT, | 35 | .regaddr_shift = OMAP3430_REGADDR_SHIFT, |
37 | .valid = OMAP3430_VALID_MASK, | 36 | .valid = OMAP3430_VALID_MASK, |
38 | .cmd_on_shift = OMAP3430_VC_CMD_ON_SHIFT, | 37 | .cmd_on_shift = OMAP3430_VC_CMD_ON_SHIFT, |
39 | .cmd_on_mask = OMAP3430_VC_CMD_ON_MASK, | 38 | .cmd_on_mask = OMAP3430_VC_CMD_ON_MASK, |
40 | .cmd_onlp_shift = OMAP3430_VC_CMD_ONLP_SHIFT, | 39 | .cmd_onlp_shift = OMAP3430_VC_CMD_ONLP_SHIFT, |
41 | .cmd_ret_shift = OMAP3430_VC_CMD_RET_SHIFT, | 40 | .cmd_ret_shift = OMAP3430_VC_CMD_RET_SHIFT, |
42 | .cmd_off_shift = OMAP3430_VC_CMD_OFF_SHIFT, | 41 | .cmd_off_shift = OMAP3430_VC_CMD_OFF_SHIFT, |
43 | .i2c_cfg_hsen_mask = OMAP3430_HSEN_MASK, | 42 | .i2c_cfg_hsen_mask = OMAP3430_HSEN_MASK, |
44 | .i2c_cfg_reg = OMAP3_PRM_VC_I2C_CFG_OFFSET, | 43 | .i2c_cfg_reg = OMAP3_PRM_VC_I2C_CFG_OFFSET, |
45 | .i2c_mcode_mask = OMAP3430_MCODE_MASK, | 44 | .i2c_mcode_mask = OMAP3430_MCODE_MASK, |
46 | }; | 45 | }; |
47 | 46 | ||
48 | struct omap_vc_channel omap3_vc_mpu = { | 47 | struct omap_vc_channel omap3_vc_mpu = { |
49 | .common = &omap3_vc_common, | 48 | .common = &omap3_vc_common, |
50 | .smps_sa_reg = OMAP3_PRM_VC_SMPS_SA_OFFSET, | 49 | .smps_sa_reg = OMAP3_PRM_VC_SMPS_SA_OFFSET, |
51 | .smps_volra_reg = OMAP3_PRM_VC_SMPS_VOL_RA_OFFSET, | 50 | .smps_volra_reg = OMAP3_PRM_VC_SMPS_VOL_RA_OFFSET, |
52 | .smps_cmdra_reg = OMAP3_PRM_VC_SMPS_CMD_RA_OFFSET, | 51 | .smps_cmdra_reg = OMAP3_PRM_VC_SMPS_CMD_RA_OFFSET, |
53 | .cfg_channel_reg = OMAP3_PRM_VC_CH_CONF_OFFSET, | 52 | .cfg_channel_reg = OMAP3_PRM_VC_CH_CONF_OFFSET, |
54 | .cmdval_reg = OMAP3_PRM_VC_CMD_VAL_0_OFFSET, | 53 | .cmdval_reg = OMAP3_PRM_VC_CMD_VAL_0_OFFSET, |
55 | .smps_sa_mask = OMAP3430_PRM_VC_SMPS_SA_SA0_MASK, | 54 | .smps_sa_mask = OMAP3430_PRM_VC_SMPS_SA_SA0_MASK, |
56 | .smps_volra_mask = OMAP3430_VOLRA0_MASK, | 55 | .smps_volra_mask = OMAP3430_VOLRA0_MASK, |
57 | .smps_cmdra_mask = OMAP3430_CMDRA0_MASK, | 56 | .smps_cmdra_mask = OMAP3430_CMDRA0_MASK, |
58 | .cfg_channel_sa_shift = OMAP3430_PRM_VC_SMPS_SA_SA0_SHIFT, | 57 | .cfg_channel_sa_shift = OMAP3430_PRM_VC_SMPS_SA_SA0_SHIFT, |
59 | }; | 58 | }; |
60 | 59 | ||
61 | struct omap_vc_channel omap3_vc_core = { | 60 | struct omap_vc_channel omap3_vc_core = { |
62 | .common = &omap3_vc_common, | 61 | .common = &omap3_vc_common, |
63 | .smps_sa_reg = OMAP3_PRM_VC_SMPS_SA_OFFSET, | 62 | .smps_sa_reg = OMAP3_PRM_VC_SMPS_SA_OFFSET, |
64 | .smps_volra_reg = OMAP3_PRM_VC_SMPS_VOL_RA_OFFSET, | 63 | .smps_volra_reg = OMAP3_PRM_VC_SMPS_VOL_RA_OFFSET, |
65 | .smps_cmdra_reg = OMAP3_PRM_VC_SMPS_CMD_RA_OFFSET, | 64 | .smps_cmdra_reg = OMAP3_PRM_VC_SMPS_CMD_RA_OFFSET, |
66 | .cfg_channel_reg = OMAP3_PRM_VC_CH_CONF_OFFSET, | 65 | .cfg_channel_reg = OMAP3_PRM_VC_CH_CONF_OFFSET, |
67 | .cmdval_reg = OMAP3_PRM_VC_CMD_VAL_1_OFFSET, | 66 | .cmdval_reg = OMAP3_PRM_VC_CMD_VAL_1_OFFSET, |
68 | .smps_sa_mask = OMAP3430_PRM_VC_SMPS_SA_SA1_MASK, | 67 | .smps_sa_mask = OMAP3430_PRM_VC_SMPS_SA_SA1_MASK, |
69 | .smps_volra_mask = OMAP3430_VOLRA1_MASK, | 68 | .smps_volra_mask = OMAP3430_VOLRA1_MASK, |
70 | .smps_cmdra_mask = OMAP3430_CMDRA1_MASK, | 69 | .smps_cmdra_mask = OMAP3430_CMDRA1_MASK, |
71 | .cfg_channel_sa_shift = OMAP3430_PRM_VC_SMPS_SA_SA1_SHIFT, | 70 | .cfg_channel_sa_shift = OMAP3430_PRM_VC_SMPS_SA_SA1_SHIFT, |
arch/arm/mach-omap2/vc44xx_data.c
1 | /* | 1 | /* |
2 | * OMAP4 Voltage Controller (VC) data | 2 | * OMAP4 Voltage Controller (VC) data |
3 | * | 3 | * |
4 | * Copyright (C) 2007, 2010 Texas Instruments, Inc. | 4 | * Copyright (C) 2007, 2010 Texas Instruments, Inc. |
5 | * Rajendra Nayak <rnayak@ti.com> | 5 | * Rajendra Nayak <rnayak@ti.com> |
6 | * Lesly A M <x0080970@ti.com> | 6 | * Lesly A M <x0080970@ti.com> |
7 | * Thara Gopinath <thara@ti.com> | 7 | * Thara Gopinath <thara@ti.com> |
8 | * | 8 | * |
9 | * Copyright (C) 2008, 2011 Nokia Corporation | 9 | * Copyright (C) 2008, 2011 Nokia Corporation |
10 | * Kalle Jokiniemi | 10 | * Kalle Jokiniemi |
11 | * Paul Walmsley | 11 | * Paul Walmsley |
12 | * | 12 | * |
13 | * This program is free software; you can redistribute it and/or modify | 13 | * This program is free software; you can redistribute it and/or modify |
14 | * it under the terms of the GNU General Public License version 2 as | 14 | * it under the terms of the GNU General Public License version 2 as |
15 | * published by the Free Software Foundation. | 15 | * published by the Free Software Foundation. |
16 | */ | 16 | */ |
17 | #include <linux/io.h> | 17 | #include <linux/io.h> |
18 | #include <linux/err.h> | 18 | #include <linux/err.h> |
19 | #include <linux/init.h> | 19 | #include <linux/init.h> |
20 | 20 | ||
21 | #include <plat/common.h> | 21 | #include <plat/common.h> |
22 | #include <plat/vc.h> | ||
22 | 23 | ||
23 | #include "prm44xx.h" | 24 | #include "prm44xx.h" |
24 | #include "prm-regbits-44xx.h" | 25 | #include "prm-regbits-44xx.h" |
25 | #include "voltage.h" | 26 | #include "voltage.h" |
26 | |||
27 | #include "vc.h" | ||
28 | 27 | ||
29 | /* | 28 | /* |
30 | * VC data common to 44xx chips | 29 | * VC data common to 44xx chips |
31 | * XXX This stuff presumably belongs in the vc3xxx.c or vc.c file. | 30 | * XXX This stuff presumably belongs in the vc3xxx.c or vc.c file. |
32 | */ | 31 | */ |
33 | static const struct omap_vc_common omap4_vc_common = { | 32 | static const struct omap_vc_common omap4_vc_common = { |
34 | .bypass_val_reg = OMAP4_PRM_VC_VAL_BYPASS_OFFSET, | 33 | .bypass_val_reg = OMAP4_PRM_VC_VAL_BYPASS_OFFSET, |
35 | .data_shift = OMAP4430_DATA_SHIFT, | 34 | .data_shift = OMAP4430_DATA_SHIFT, |
36 | .slaveaddr_shift = OMAP4430_SLAVEADDR_SHIFT, | 35 | .slaveaddr_shift = OMAP4430_SLAVEADDR_SHIFT, |
37 | .regaddr_shift = OMAP4430_REGADDR_SHIFT, | 36 | .regaddr_shift = OMAP4430_REGADDR_SHIFT, |
38 | .valid = OMAP4430_VALID_MASK, | 37 | .valid = OMAP4430_VALID_MASK, |
39 | .cmd_on_shift = OMAP4430_ON_SHIFT, | 38 | .cmd_on_shift = OMAP4430_ON_SHIFT, |
40 | .cmd_on_mask = OMAP4430_ON_MASK, | 39 | .cmd_on_mask = OMAP4430_ON_MASK, |
41 | .cmd_onlp_shift = OMAP4430_ONLP_SHIFT, | 40 | .cmd_onlp_shift = OMAP4430_ONLP_SHIFT, |
42 | .cmd_ret_shift = OMAP4430_RET_SHIFT, | 41 | .cmd_ret_shift = OMAP4430_RET_SHIFT, |
43 | .cmd_off_shift = OMAP4430_OFF_SHIFT, | 42 | .cmd_off_shift = OMAP4430_OFF_SHIFT, |
44 | .i2c_cfg_reg = OMAP4_PRM_VC_CFG_I2C_MODE_OFFSET, | 43 | .i2c_cfg_reg = OMAP4_PRM_VC_CFG_I2C_MODE_OFFSET, |
45 | .i2c_cfg_hsen_mask = OMAP4430_HSMODEEN_MASK, | 44 | .i2c_cfg_hsen_mask = OMAP4430_HSMODEEN_MASK, |
46 | .i2c_mcode_mask = OMAP4430_HSMCODE_MASK, | 45 | .i2c_mcode_mask = OMAP4430_HSMCODE_MASK, |
47 | }; | 46 | }; |
48 | 47 | ||
49 | /* VC instance data for each controllable voltage line */ | 48 | /* VC instance data for each controllable voltage line */ |
50 | struct omap_vc_channel omap4_vc_mpu = { | 49 | struct omap_vc_channel omap4_vc_mpu = { |
51 | .flags = OMAP_VC_CHANNEL_DEFAULT | OMAP_VC_CHANNEL_CFG_MUTANT, | 50 | .flags = OMAP_VC_CHANNEL_DEFAULT | OMAP_VC_CHANNEL_CFG_MUTANT, |
52 | .common = &omap4_vc_common, | 51 | .common = &omap4_vc_common, |
53 | .smps_sa_reg = OMAP4_PRM_VC_SMPS_SA_OFFSET, | 52 | .smps_sa_reg = OMAP4_PRM_VC_SMPS_SA_OFFSET, |
54 | .smps_volra_reg = OMAP4_PRM_VC_VAL_SMPS_RA_VOL_OFFSET, | 53 | .smps_volra_reg = OMAP4_PRM_VC_VAL_SMPS_RA_VOL_OFFSET, |
55 | .smps_cmdra_reg = OMAP4_PRM_VC_VAL_SMPS_RA_CMD_OFFSET, | 54 | .smps_cmdra_reg = OMAP4_PRM_VC_VAL_SMPS_RA_CMD_OFFSET, |
56 | .cfg_channel_reg = OMAP4_PRM_VC_CFG_CHANNEL_OFFSET, | 55 | .cfg_channel_reg = OMAP4_PRM_VC_CFG_CHANNEL_OFFSET, |
57 | .cmdval_reg = OMAP4_PRM_VC_VAL_CMD_VDD_MPU_L_OFFSET, | 56 | .cmdval_reg = OMAP4_PRM_VC_VAL_CMD_VDD_MPU_L_OFFSET, |
58 | .smps_sa_mask = OMAP4430_SA_VDD_MPU_L_PRM_VC_SMPS_SA_MASK, | 57 | .smps_sa_mask = OMAP4430_SA_VDD_MPU_L_PRM_VC_SMPS_SA_MASK, |
59 | .smps_volra_mask = OMAP4430_VOLRA_VDD_MPU_L_MASK, | 58 | .smps_volra_mask = OMAP4430_VOLRA_VDD_MPU_L_MASK, |
60 | .smps_cmdra_mask = OMAP4430_CMDRA_VDD_MPU_L_MASK, | 59 | .smps_cmdra_mask = OMAP4430_CMDRA_VDD_MPU_L_MASK, |
61 | .cfg_channel_sa_shift = OMAP4430_SA_VDD_MPU_L_SHIFT, | 60 | .cfg_channel_sa_shift = OMAP4430_SA_VDD_MPU_L_SHIFT, |
62 | }; | 61 | }; |
63 | 62 | ||
64 | struct omap_vc_channel omap4_vc_iva = { | 63 | struct omap_vc_channel omap4_vc_iva = { |
65 | .common = &omap4_vc_common, | 64 | .common = &omap4_vc_common, |
66 | .smps_sa_reg = OMAP4_PRM_VC_SMPS_SA_OFFSET, | 65 | .smps_sa_reg = OMAP4_PRM_VC_SMPS_SA_OFFSET, |
67 | .smps_volra_reg = OMAP4_PRM_VC_VAL_SMPS_RA_VOL_OFFSET, | 66 | .smps_volra_reg = OMAP4_PRM_VC_VAL_SMPS_RA_VOL_OFFSET, |
68 | .smps_cmdra_reg = OMAP4_PRM_VC_VAL_SMPS_RA_CMD_OFFSET, | 67 | .smps_cmdra_reg = OMAP4_PRM_VC_VAL_SMPS_RA_CMD_OFFSET, |
69 | .cfg_channel_reg = OMAP4_PRM_VC_CFG_CHANNEL_OFFSET, | 68 | .cfg_channel_reg = OMAP4_PRM_VC_CFG_CHANNEL_OFFSET, |
70 | .cmdval_reg = OMAP4_PRM_VC_VAL_CMD_VDD_IVA_L_OFFSET, | 69 | .cmdval_reg = OMAP4_PRM_VC_VAL_CMD_VDD_IVA_L_OFFSET, |
71 | .smps_sa_mask = OMAP4430_SA_VDD_IVA_L_PRM_VC_SMPS_SA_MASK, | 70 | .smps_sa_mask = OMAP4430_SA_VDD_IVA_L_PRM_VC_SMPS_SA_MASK, |
72 | .smps_volra_mask = OMAP4430_VOLRA_VDD_IVA_L_MASK, | 71 | .smps_volra_mask = OMAP4430_VOLRA_VDD_IVA_L_MASK, |
73 | .smps_cmdra_mask = OMAP4430_CMDRA_VDD_IVA_L_MASK, | 72 | .smps_cmdra_mask = OMAP4430_CMDRA_VDD_IVA_L_MASK, |
74 | .cfg_channel_sa_shift = OMAP4430_SA_VDD_IVA_L_SHIFT, | 73 | .cfg_channel_sa_shift = OMAP4430_SA_VDD_IVA_L_SHIFT, |
75 | }; | 74 | }; |
76 | 75 | ||
77 | struct omap_vc_channel omap4_vc_core = { | 76 | struct omap_vc_channel omap4_vc_core = { |
78 | .common = &omap4_vc_common, | 77 | .common = &omap4_vc_common, |
79 | .smps_sa_reg = OMAP4_PRM_VC_SMPS_SA_OFFSET, | 78 | .smps_sa_reg = OMAP4_PRM_VC_SMPS_SA_OFFSET, |
80 | .smps_volra_reg = OMAP4_PRM_VC_VAL_SMPS_RA_VOL_OFFSET, | 79 | .smps_volra_reg = OMAP4_PRM_VC_VAL_SMPS_RA_VOL_OFFSET, |
81 | .smps_cmdra_reg = OMAP4_PRM_VC_VAL_SMPS_RA_CMD_OFFSET, | 80 | .smps_cmdra_reg = OMAP4_PRM_VC_VAL_SMPS_RA_CMD_OFFSET, |
82 | .cfg_channel_reg = OMAP4_PRM_VC_CFG_CHANNEL_OFFSET, | 81 | .cfg_channel_reg = OMAP4_PRM_VC_CFG_CHANNEL_OFFSET, |
83 | .cmdval_reg = OMAP4_PRM_VC_VAL_CMD_VDD_CORE_L_OFFSET, | 82 | .cmdval_reg = OMAP4_PRM_VC_VAL_CMD_VDD_CORE_L_OFFSET, |
84 | .smps_sa_mask = OMAP4430_SA_VDD_CORE_L_0_6_MASK, | 83 | .smps_sa_mask = OMAP4430_SA_VDD_CORE_L_0_6_MASK, |
85 | .smps_volra_mask = OMAP4430_VOLRA_VDD_CORE_L_MASK, | 84 | .smps_volra_mask = OMAP4430_VOLRA_VDD_CORE_L_MASK, |
86 | .smps_cmdra_mask = OMAP4430_CMDRA_VDD_CORE_L_MASK, | 85 | .smps_cmdra_mask = OMAP4430_CMDRA_VDD_CORE_L_MASK, |
87 | .cfg_channel_sa_shift = OMAP4430_SA_VDD_CORE_L_SHIFT, | 86 | .cfg_channel_sa_shift = OMAP4430_SA_VDD_CORE_L_SHIFT, |
88 | }; | 87 | }; |
89 | 88 |
arch/arm/mach-omap2/voltage.c
1 | /* | 1 | /* |
2 | * OMAP3/OMAP4 Voltage Management Routines | 2 | * OMAP3/OMAP4 Voltage Management Routines |
3 | * | 3 | * |
4 | * Author: Thara Gopinath <thara@ti.com> | 4 | * Author: Thara Gopinath <thara@ti.com> |
5 | * | 5 | * |
6 | * Copyright (C) 2007 Texas Instruments, Inc. | 6 | * Copyright (C) 2007 Texas Instruments, Inc. |
7 | * Rajendra Nayak <rnayak@ti.com> | 7 | * Rajendra Nayak <rnayak@ti.com> |
8 | * Lesly A M <x0080970@ti.com> | 8 | * Lesly A M <x0080970@ti.com> |
9 | * | 9 | * |
10 | * Copyright (C) 2008, 2011 Nokia Corporation | 10 | * Copyright (C) 2008, 2011 Nokia Corporation |
11 | * Kalle Jokiniemi | 11 | * Kalle Jokiniemi |
12 | * Paul Walmsley | 12 | * Paul Walmsley |
13 | * | 13 | * |
14 | * Copyright (C) 2010 Texas Instruments, Inc. | 14 | * Copyright (C) 2010 Texas Instruments, Inc. |
15 | * Thara Gopinath <thara@ti.com> | 15 | * Thara Gopinath <thara@ti.com> |
16 | * | 16 | * |
17 | * This program is free software; you can redistribute it and/or modify | 17 | * This program is free software; you can redistribute it and/or modify |
18 | * it under the terms of the GNU General Public License version 2 as | 18 | * it under the terms of the GNU General Public License version 2 as |
19 | * published by the Free Software Foundation. | 19 | * published by the Free Software Foundation. |
20 | */ | 20 | */ |
21 | 21 | ||
22 | #include <linux/delay.h> | 22 | #include <linux/delay.h> |
23 | #include <linux/io.h> | 23 | #include <linux/io.h> |
24 | #include <linux/err.h> | 24 | #include <linux/err.h> |
25 | #include <linux/debugfs.h> | 25 | #include <linux/debugfs.h> |
26 | #include <linux/slab.h> | 26 | #include <linux/slab.h> |
27 | #include <linux/clk.h> | 27 | #include <linux/clk.h> |
28 | 28 | ||
29 | #include <plat/common.h> | 29 | #include <plat/common.h> |
30 | #include <plat/voltage.h> | ||
31 | #include <plat/vc.h> | ||
32 | #include <plat/vp.h> | ||
30 | 33 | ||
31 | #include "prm-regbits-34xx.h" | 34 | #include "prm-regbits-34xx.h" |
32 | #include "prm-regbits-44xx.h" | 35 | #include "prm-regbits-44xx.h" |
33 | #include "prm44xx.h" | 36 | #include "prm44xx.h" |
34 | #include "prcm44xx.h" | 37 | #include "prcm44xx.h" |
35 | #include "prminst44xx.h" | 38 | #include "prminst44xx.h" |
36 | #include "control.h" | 39 | #include "control.h" |
37 | 40 | ||
38 | #include "voltage.h" | ||
39 | #include "powerdomain.h" | 41 | #include "powerdomain.h" |
40 | |||
41 | #include "vc.h" | ||
42 | #include "vp.h" | ||
43 | 42 | ||
44 | static LIST_HEAD(voltdm_list); | 43 | static LIST_HEAD(voltdm_list); |
45 | 44 | ||
46 | /* Public functions */ | 45 | /* Public functions */ |
47 | /** | 46 | /** |
48 | * voltdm_get_voltage() - Gets the current non-auto-compensated voltage | 47 | * voltdm_get_voltage() - Gets the current non-auto-compensated voltage |
49 | * @voltdm: pointer to the voltdm for which current voltage info is needed | 48 | * @voltdm: pointer to the voltdm for which current voltage info is needed |
50 | * | 49 | * |
51 | * API to get the current non-auto-compensated voltage for a voltage domain. | 50 | * API to get the current non-auto-compensated voltage for a voltage domain. |
52 | * Returns 0 in case of error else returns the current voltage. | 51 | * Returns 0 in case of error else returns the current voltage. |
53 | */ | 52 | */ |
54 | unsigned long voltdm_get_voltage(struct voltagedomain *voltdm) | 53 | unsigned long voltdm_get_voltage(struct voltagedomain *voltdm) |
55 | { | 54 | { |
56 | if (!voltdm || IS_ERR(voltdm)) { | 55 | if (!voltdm || IS_ERR(voltdm)) { |
57 | pr_warning("%s: VDD specified does not exist!\n", __func__); | 56 | pr_warning("%s: VDD specified does not exist!\n", __func__); |
58 | return 0; | 57 | return 0; |
59 | } | 58 | } |
60 | 59 | ||
61 | return voltdm->nominal_volt; | 60 | return voltdm->nominal_volt; |
62 | } | 61 | } |
63 | 62 | ||
64 | /** | 63 | /** |
65 | * voltdm_scale() - API to scale voltage of a particular voltage domain. | 64 | * voltdm_scale() - API to scale voltage of a particular voltage domain. |
66 | * @voltdm: pointer to the voltage domain which is to be scaled. | 65 | * @voltdm: pointer to the voltage domain which is to be scaled. |
67 | * @target_volt: The target voltage of the voltage domain | 66 | * @target_volt: The target voltage of the voltage domain |
68 | * | 67 | * |
69 | * This API should be called by the kernel to do the voltage scaling | 68 | * This API should be called by the kernel to do the voltage scaling |
70 | * for a particular voltage domain during DVFS. | 69 | * for a particular voltage domain during DVFS. |
71 | */ | 70 | */ |
72 | int voltdm_scale(struct voltagedomain *voltdm, | 71 | int voltdm_scale(struct voltagedomain *voltdm, |
73 | unsigned long target_volt) | 72 | unsigned long target_volt) |
74 | { | 73 | { |
75 | int ret; | 74 | int ret; |
76 | 75 | ||
77 | if (!voltdm || IS_ERR(voltdm)) { | 76 | if (!voltdm || IS_ERR(voltdm)) { |
78 | pr_warning("%s: VDD specified does not exist!\n", __func__); | 77 | pr_warning("%s: VDD specified does not exist!\n", __func__); |
79 | return -EINVAL; | 78 | return -EINVAL; |
80 | } | 79 | } |
81 | 80 | ||
82 | if (!voltdm->scale) { | 81 | if (!voltdm->scale) { |
83 | pr_err("%s: No voltage scale API registered for vdd_%s\n", | 82 | pr_err("%s: No voltage scale API registered for vdd_%s\n", |
84 | __func__, voltdm->name); | 83 | __func__, voltdm->name); |
85 | return -ENODATA; | 84 | return -ENODATA; |
86 | } | 85 | } |
87 | 86 | ||
88 | ret = voltdm->scale(voltdm, target_volt); | 87 | ret = voltdm->scale(voltdm, target_volt); |
89 | if (!ret) | 88 | if (!ret) |
90 | voltdm->nominal_volt = target_volt; | 89 | voltdm->nominal_volt = target_volt; |
91 | 90 | ||
92 | return ret; | 91 | return ret; |
93 | } | 92 | } |
94 | 93 | ||
95 | /** | 94 | /** |
96 | * voltdm_reset() - Resets the voltage of a particular voltage domain | 95 | * voltdm_reset() - Resets the voltage of a particular voltage domain |
97 | * to that of the current OPP. | 96 | * to that of the current OPP. |
98 | * @voltdm: pointer to the voltage domain whose voltage is to be reset. | 97 | * @voltdm: pointer to the voltage domain whose voltage is to be reset. |
99 | * | 98 | * |
100 | * This API finds out the correct voltage the voltage domain is supposed | 99 | * This API finds out the correct voltage the voltage domain is supposed |
101 | * to be at and resets the voltage to that level. Should be used especially | 100 | * to be at and resets the voltage to that level. Should be used especially |
102 | * while disabling any voltage compensation modules. | 101 | * while disabling any voltage compensation modules. |
103 | */ | 102 | */ |
104 | void voltdm_reset(struct voltagedomain *voltdm) | 103 | void voltdm_reset(struct voltagedomain *voltdm) |
105 | { | 104 | { |
106 | unsigned long target_volt; | 105 | unsigned long target_volt; |
107 | 106 | ||
108 | if (!voltdm || IS_ERR(voltdm)) { | 107 | if (!voltdm || IS_ERR(voltdm)) { |
109 | pr_warning("%s: VDD specified does not exist!\n", __func__); | 108 | pr_warning("%s: VDD specified does not exist!\n", __func__); |
110 | return; | 109 | return; |
111 | } | 110 | } |
112 | 111 | ||
113 | target_volt = voltdm_get_voltage(voltdm); | 112 | target_volt = voltdm_get_voltage(voltdm); |
114 | if (!target_volt) { | 113 | if (!target_volt) { |
115 | pr_err("%s: unable to find current voltage for vdd_%s\n", | 114 | pr_err("%s: unable to find current voltage for vdd_%s\n", |
116 | __func__, voltdm->name); | 115 | __func__, voltdm->name); |
117 | return; | 116 | return; |
118 | } | 117 | } |
119 | 118 | ||
120 | voltdm_scale(voltdm, target_volt); | 119 | voltdm_scale(voltdm, target_volt); |
121 | } | 120 | } |
122 | 121 | ||
123 | /** | 122 | /** |
124 | * omap_voltage_get_volttable() - API to get the voltage table associated with a | 123 | * omap_voltage_get_volttable() - API to get the voltage table associated with a |
125 | * particular voltage domain. | 124 | * particular voltage domain. |
126 | * @voltdm: pointer to the VDD for which the voltage table is required | 125 | * @voltdm: pointer to the VDD for which the voltage table is required |
127 | * @volt_data: the voltage table for the particular vdd which is to be | 126 | * @volt_data: the voltage table for the particular vdd which is to be |
128 | * populated by this API | 127 | * populated by this API |
129 | * | 128 | * |
130 | * This API populates the voltage table associated with a VDD into the | 129 | * This API populates the voltage table associated with a VDD into the |
131 | * passed parameter pointer. Returns the count of distinct voltages | 130 | * passed parameter pointer. Returns the count of distinct voltages |
132 | * supported by this vdd. | 131 | * supported by this vdd. |
133 | * | 132 | * |
134 | */ | 133 | */ |
135 | void omap_voltage_get_volttable(struct voltagedomain *voltdm, | 134 | void omap_voltage_get_volttable(struct voltagedomain *voltdm, |
136 | struct omap_volt_data **volt_data) | 135 | struct omap_volt_data **volt_data) |
137 | { | 136 | { |
138 | if (!voltdm || IS_ERR(voltdm)) { | 137 | if (!voltdm || IS_ERR(voltdm)) { |
139 | pr_warning("%s: VDD specified does not exist!\n", __func__); | 138 | pr_warning("%s: VDD specified does not exist!\n", __func__); |
140 | return; | 139 | return; |
141 | } | 140 | } |
142 | 141 | ||
143 | *volt_data = voltdm->volt_data; | 142 | *volt_data = voltdm->volt_data; |
144 | } | 143 | } |
145 | 144 | ||
146 | /** | 145 | /** |
147 | * omap_voltage_get_voltdata() - API to get the voltage table entry for a | 146 | * omap_voltage_get_voltdata() - API to get the voltage table entry for a |
148 | * particular voltage | 147 | * particular voltage |
149 | * @voltdm: pointer to the VDD whose voltage table has to be searched | 148 | * @voltdm: pointer to the VDD whose voltage table has to be searched |
150 | * @volt: the voltage to be searched in the voltage table | 149 | * @volt: the voltage to be searched in the voltage table |
151 | * | 150 | * |
152 | * This API searches through the voltage table for the required voltage | 151 | * This API searches through the voltage table for the required voltage |
153 | * domain and tries to find a matching entry for the passed voltage volt. | 152 | * domain and tries to find a matching entry for the passed voltage volt. |
154 | * If a matching entry is found volt_data is populated with that entry. | 153 | * If a matching entry is found volt_data is populated with that entry. |
155 | * This API searches only through the non-compensated voltages int the | 154 | * This API searches only through the non-compensated voltages int the |
156 | * voltage table. | 155 | * voltage table. |
157 | * Returns pointer to the voltage table entry corresponding to volt on | 156 | * Returns pointer to the voltage table entry corresponding to volt on |
158 | * success. Returns -ENODATA if no voltage table exisits for the passed voltage | 157 | * success. Returns -ENODATA if no voltage table exisits for the passed voltage |
159 | * domain or if there is no matching entry. | 158 | * domain or if there is no matching entry. |
160 | */ | 159 | */ |
161 | struct omap_volt_data *omap_voltage_get_voltdata(struct voltagedomain *voltdm, | 160 | struct omap_volt_data *omap_voltage_get_voltdata(struct voltagedomain *voltdm, |
162 | unsigned long volt) | 161 | unsigned long volt) |
163 | { | 162 | { |
164 | int i; | 163 | int i; |
165 | 164 | ||
166 | if (!voltdm || IS_ERR(voltdm)) { | 165 | if (!voltdm || IS_ERR(voltdm)) { |
167 | pr_warning("%s: VDD specified does not exist!\n", __func__); | 166 | pr_warning("%s: VDD specified does not exist!\n", __func__); |
168 | return ERR_PTR(-EINVAL); | 167 | return ERR_PTR(-EINVAL); |
169 | } | 168 | } |
170 | 169 | ||
171 | if (!voltdm->volt_data) { | 170 | if (!voltdm->volt_data) { |
172 | pr_warning("%s: voltage table does not exist for vdd_%s\n", | 171 | pr_warning("%s: voltage table does not exist for vdd_%s\n", |
173 | __func__, voltdm->name); | 172 | __func__, voltdm->name); |
174 | return ERR_PTR(-ENODATA); | 173 | return ERR_PTR(-ENODATA); |
175 | } | 174 | } |
176 | 175 | ||
177 | for (i = 0; voltdm->volt_data[i].volt_nominal != 0; i++) { | 176 | for (i = 0; voltdm->volt_data[i].volt_nominal != 0; i++) { |
178 | if (voltdm->volt_data[i].volt_nominal == volt) | 177 | if (voltdm->volt_data[i].volt_nominal == volt) |
179 | return &voltdm->volt_data[i]; | 178 | return &voltdm->volt_data[i]; |
180 | } | 179 | } |
181 | 180 | ||
182 | pr_notice("%s: Unable to match the current voltage with the voltage" | 181 | pr_notice("%s: Unable to match the current voltage with the voltage" |
183 | "table for vdd_%s\n", __func__, voltdm->name); | 182 | "table for vdd_%s\n", __func__, voltdm->name); |
184 | 183 | ||
185 | return ERR_PTR(-ENODATA); | 184 | return ERR_PTR(-ENODATA); |
186 | } | 185 | } |
187 | 186 | ||
188 | /** | 187 | /** |
189 | * omap_voltage_register_pmic() - API to register PMIC specific data | 188 | * omap_voltage_register_pmic() - API to register PMIC specific data |
190 | * @voltdm: pointer to the VDD for which the PMIC specific data is | 189 | * @voltdm: pointer to the VDD for which the PMIC specific data is |
191 | * to be registered | 190 | * to be registered |
192 | * @pmic: the structure containing pmic info | 191 | * @pmic: the structure containing pmic info |
193 | * | 192 | * |
194 | * This API is to be called by the SOC/PMIC file to specify the | 193 | * This API is to be called by the SOC/PMIC file to specify the |
195 | * pmic specific info as present in omap_voltdm_pmic structure. | 194 | * pmic specific info as present in omap_voltdm_pmic structure. |
196 | */ | 195 | */ |
197 | int omap_voltage_register_pmic(struct voltagedomain *voltdm, | 196 | int omap_voltage_register_pmic(struct voltagedomain *voltdm, |
198 | struct omap_voltdm_pmic *pmic) | 197 | struct omap_voltdm_pmic *pmic) |
199 | { | 198 | { |
200 | if (!voltdm || IS_ERR(voltdm)) { | 199 | if (!voltdm || IS_ERR(voltdm)) { |
201 | pr_warning("%s: VDD specified does not exist!\n", __func__); | 200 | pr_warning("%s: VDD specified does not exist!\n", __func__); |
202 | return -EINVAL; | 201 | return -EINVAL; |
203 | } | 202 | } |
204 | 203 | ||
205 | voltdm->pmic = pmic; | 204 | voltdm->pmic = pmic; |
206 | 205 | ||
207 | return 0; | 206 | return 0; |
208 | } | 207 | } |
209 | 208 | ||
210 | /** | 209 | /** |
211 | * omap_change_voltscale_method() - API to change the voltage scaling method. | 210 | * omap_change_voltscale_method() - API to change the voltage scaling method. |
212 | * @voltdm: pointer to the VDD whose voltage scaling method | 211 | * @voltdm: pointer to the VDD whose voltage scaling method |
213 | * has to be changed. | 212 | * has to be changed. |
214 | * @voltscale_method: the method to be used for voltage scaling. | 213 | * @voltscale_method: the method to be used for voltage scaling. |
215 | * | 214 | * |
216 | * This API can be used by the board files to change the method of voltage | 215 | * This API can be used by the board files to change the method of voltage |
217 | * scaling between vpforceupdate and vcbypass. The parameter values are | 216 | * scaling between vpforceupdate and vcbypass. The parameter values are |
218 | * defined in voltage.h | 217 | * defined in voltage.h |
219 | */ | 218 | */ |
220 | void omap_change_voltscale_method(struct voltagedomain *voltdm, | 219 | void omap_change_voltscale_method(struct voltagedomain *voltdm, |
221 | int voltscale_method) | 220 | int voltscale_method) |
222 | { | 221 | { |
223 | if (!voltdm || IS_ERR(voltdm)) { | 222 | if (!voltdm || IS_ERR(voltdm)) { |
224 | pr_warning("%s: VDD specified does not exist!\n", __func__); | 223 | pr_warning("%s: VDD specified does not exist!\n", __func__); |
225 | return; | 224 | return; |
226 | } | 225 | } |
227 | 226 | ||
228 | switch (voltscale_method) { | 227 | switch (voltscale_method) { |
229 | case VOLTSCALE_VPFORCEUPDATE: | 228 | case VOLTSCALE_VPFORCEUPDATE: |
230 | voltdm->scale = omap_vp_forceupdate_scale; | 229 | voltdm->scale = omap_vp_forceupdate_scale; |
231 | return; | 230 | return; |
232 | case VOLTSCALE_VCBYPASS: | 231 | case VOLTSCALE_VCBYPASS: |
233 | voltdm->scale = omap_vc_bypass_scale; | 232 | voltdm->scale = omap_vc_bypass_scale; |
234 | return; | 233 | return; |
235 | default: | 234 | default: |
236 | pr_warning("%s: Trying to change the method of voltage scaling" | 235 | pr_warning("%s: Trying to change the method of voltage scaling" |
237 | "to an unsupported one!\n", __func__); | 236 | "to an unsupported one!\n", __func__); |
238 | } | 237 | } |
239 | } | 238 | } |
240 | 239 | ||
241 | /** | 240 | /** |
242 | * omap_voltage_late_init() - Init the various voltage parameters | 241 | * omap_voltage_late_init() - Init the various voltage parameters |
243 | * | 242 | * |
244 | * This API is to be called in the later stages of the | 243 | * This API is to be called in the later stages of the |
245 | * system boot to init the voltage controller and | 244 | * system boot to init the voltage controller and |
246 | * voltage processors. | 245 | * voltage processors. |
247 | */ | 246 | */ |
248 | int __init omap_voltage_late_init(void) | 247 | int __init omap_voltage_late_init(void) |
249 | { | 248 | { |
250 | struct voltagedomain *voltdm; | 249 | struct voltagedomain *voltdm; |
251 | 250 | ||
252 | if (list_empty(&voltdm_list)) { | 251 | if (list_empty(&voltdm_list)) { |
253 | pr_err("%s: Voltage driver support not added\n", | 252 | pr_err("%s: Voltage driver support not added\n", |
254 | __func__); | 253 | __func__); |
255 | return -EINVAL; | 254 | return -EINVAL; |
256 | } | 255 | } |
257 | 256 | ||
258 | list_for_each_entry(voltdm, &voltdm_list, node) { | 257 | list_for_each_entry(voltdm, &voltdm_list, node) { |
259 | struct clk *sys_ck; | 258 | struct clk *sys_ck; |
260 | 259 | ||
261 | if (!voltdm->scalable) | 260 | if (!voltdm->scalable) |
262 | continue; | 261 | continue; |
263 | 262 | ||
264 | sys_ck = clk_get(NULL, voltdm->sys_clk.name); | 263 | sys_ck = clk_get(NULL, voltdm->sys_clk.name); |
265 | if (IS_ERR(sys_ck)) { | 264 | if (IS_ERR(sys_ck)) { |
266 | pr_warning("%s: Could not get sys clk.\n", __func__); | 265 | pr_warning("%s: Could not get sys clk.\n", __func__); |
267 | return -EINVAL; | 266 | return -EINVAL; |
268 | } | 267 | } |
269 | voltdm->sys_clk.rate = clk_get_rate(sys_ck); | 268 | voltdm->sys_clk.rate = clk_get_rate(sys_ck); |
270 | WARN_ON(!voltdm->sys_clk.rate); | 269 | WARN_ON(!voltdm->sys_clk.rate); |
271 | clk_put(sys_ck); | 270 | clk_put(sys_ck); |
272 | 271 | ||
273 | if (voltdm->vc) { | 272 | if (voltdm->vc) { |
274 | voltdm->scale = omap_vc_bypass_scale; | 273 | voltdm->scale = omap_vc_bypass_scale; |
275 | omap_vc_init_channel(voltdm); | 274 | omap_vc_init_channel(voltdm); |
276 | } | 275 | } |
277 | 276 | ||
278 | if (voltdm->vp) { | 277 | if (voltdm->vp) { |
279 | voltdm->scale = omap_vp_forceupdate_scale; | 278 | voltdm->scale = omap_vp_forceupdate_scale; |
280 | omap_vp_init(voltdm); | 279 | omap_vp_init(voltdm); |
281 | } | 280 | } |
282 | } | 281 | } |
283 | 282 | ||
284 | return 0; | 283 | return 0; |
285 | } | 284 | } |
286 | 285 | ||
287 | static struct voltagedomain *_voltdm_lookup(const char *name) | 286 | static struct voltagedomain *_voltdm_lookup(const char *name) |
288 | { | 287 | { |
289 | struct voltagedomain *voltdm, *temp_voltdm; | 288 | struct voltagedomain *voltdm, *temp_voltdm; |
290 | 289 | ||
291 | voltdm = NULL; | 290 | voltdm = NULL; |
292 | 291 | ||
293 | list_for_each_entry(temp_voltdm, &voltdm_list, node) { | 292 | list_for_each_entry(temp_voltdm, &voltdm_list, node) { |
294 | if (!strcmp(name, temp_voltdm->name)) { | 293 | if (!strcmp(name, temp_voltdm->name)) { |
295 | voltdm = temp_voltdm; | 294 | voltdm = temp_voltdm; |
296 | break; | 295 | break; |
297 | } | 296 | } |
298 | } | 297 | } |
299 | 298 | ||
300 | return voltdm; | 299 | return voltdm; |
301 | } | 300 | } |
302 | 301 | ||
303 | /** | 302 | /** |
304 | * voltdm_add_pwrdm - add a powerdomain to a voltagedomain | 303 | * voltdm_add_pwrdm - add a powerdomain to a voltagedomain |
305 | * @voltdm: struct voltagedomain * to add the powerdomain to | 304 | * @voltdm: struct voltagedomain * to add the powerdomain to |
306 | * @pwrdm: struct powerdomain * to associate with a voltagedomain | 305 | * @pwrdm: struct powerdomain * to associate with a voltagedomain |
307 | * | 306 | * |
308 | * Associate the powerdomain @pwrdm with a voltagedomain @voltdm. This | 307 | * Associate the powerdomain @pwrdm with a voltagedomain @voltdm. This |
309 | * enables the use of voltdm_for_each_pwrdm(). Returns -EINVAL if | 308 | * enables the use of voltdm_for_each_pwrdm(). Returns -EINVAL if |
310 | * presented with invalid pointers; -ENOMEM if memory could not be allocated; | 309 | * presented with invalid pointers; -ENOMEM if memory could not be allocated; |
311 | * or 0 upon success. | 310 | * or 0 upon success. |
312 | */ | 311 | */ |
313 | int voltdm_add_pwrdm(struct voltagedomain *voltdm, struct powerdomain *pwrdm) | 312 | int voltdm_add_pwrdm(struct voltagedomain *voltdm, struct powerdomain *pwrdm) |
314 | { | 313 | { |
315 | if (!voltdm || !pwrdm) | 314 | if (!voltdm || !pwrdm) |
316 | return -EINVAL; | 315 | return -EINVAL; |
317 | 316 | ||
318 | pr_debug("voltagedomain: associating powerdomain %s with voltagedomain " | 317 | pr_debug("voltagedomain: associating powerdomain %s with voltagedomain " |
319 | "%s\n", pwrdm->name, voltdm->name); | 318 | "%s\n", pwrdm->name, voltdm->name); |
320 | 319 | ||
321 | list_add(&pwrdm->voltdm_node, &voltdm->pwrdm_list); | 320 | list_add(&pwrdm->voltdm_node, &voltdm->pwrdm_list); |
322 | 321 | ||
323 | return 0; | 322 | return 0; |
324 | } | 323 | } |
325 | 324 | ||
326 | /** | 325 | /** |
327 | * voltdm_for_each_pwrdm - call function for each pwrdm in a voltdm | 326 | * voltdm_for_each_pwrdm - call function for each pwrdm in a voltdm |
328 | * @voltdm: struct voltagedomain * to iterate over | 327 | * @voltdm: struct voltagedomain * to iterate over |
329 | * @fn: callback function * | 328 | * @fn: callback function * |
330 | * | 329 | * |
331 | * Call the supplied function @fn for each powerdomain in the | 330 | * Call the supplied function @fn for each powerdomain in the |
332 | * voltagedomain @voltdm. Returns -EINVAL if presented with invalid | 331 | * voltagedomain @voltdm. Returns -EINVAL if presented with invalid |
333 | * pointers; or passes along the last return value of the callback | 332 | * pointers; or passes along the last return value of the callback |
334 | * function, which should be 0 for success or anything else to | 333 | * function, which should be 0 for success or anything else to |
335 | * indicate failure. | 334 | * indicate failure. |
336 | */ | 335 | */ |
337 | int voltdm_for_each_pwrdm(struct voltagedomain *voltdm, | 336 | int voltdm_for_each_pwrdm(struct voltagedomain *voltdm, |
338 | int (*fn)(struct voltagedomain *voltdm, | 337 | int (*fn)(struct voltagedomain *voltdm, |
339 | struct powerdomain *pwrdm)) | 338 | struct powerdomain *pwrdm)) |
340 | { | 339 | { |
341 | struct powerdomain *pwrdm; | 340 | struct powerdomain *pwrdm; |
342 | int ret = 0; | 341 | int ret = 0; |
343 | 342 | ||
344 | if (!fn) | 343 | if (!fn) |
345 | return -EINVAL; | 344 | return -EINVAL; |
346 | 345 | ||
347 | list_for_each_entry(pwrdm, &voltdm->pwrdm_list, voltdm_node) | 346 | list_for_each_entry(pwrdm, &voltdm->pwrdm_list, voltdm_node) |
348 | ret = (*fn)(voltdm, pwrdm); | 347 | ret = (*fn)(voltdm, pwrdm); |
349 | 348 | ||
350 | return ret; | 349 | return ret; |
351 | } | 350 | } |
352 | 351 | ||
353 | /** | 352 | /** |
354 | * voltdm_for_each - call function on each registered voltagedomain | 353 | * voltdm_for_each - call function on each registered voltagedomain |
355 | * @fn: callback function * | 354 | * @fn: callback function * |
356 | * | 355 | * |
357 | * Call the supplied function @fn for each registered voltagedomain. | 356 | * Call the supplied function @fn for each registered voltagedomain. |
358 | * The callback function @fn can return anything but 0 to bail out | 357 | * The callback function @fn can return anything but 0 to bail out |
359 | * early from the iterator. Returns the last return value of the | 358 | * early from the iterator. Returns the last return value of the |
360 | * callback function, which should be 0 for success or anything else | 359 | * callback function, which should be 0 for success or anything else |
361 | * to indicate failure; or -EINVAL if the function pointer is null. | 360 | * to indicate failure; or -EINVAL if the function pointer is null. |
362 | */ | 361 | */ |
363 | int voltdm_for_each(int (*fn)(struct voltagedomain *voltdm, void *user), | 362 | int voltdm_for_each(int (*fn)(struct voltagedomain *voltdm, void *user), |
364 | void *user) | 363 | void *user) |
365 | { | 364 | { |
366 | struct voltagedomain *temp_voltdm; | 365 | struct voltagedomain *temp_voltdm; |
367 | int ret = 0; | 366 | int ret = 0; |
368 | 367 | ||
369 | if (!fn) | 368 | if (!fn) |
370 | return -EINVAL; | 369 | return -EINVAL; |
371 | 370 | ||
372 | list_for_each_entry(temp_voltdm, &voltdm_list, node) { | 371 | list_for_each_entry(temp_voltdm, &voltdm_list, node) { |
373 | ret = (*fn)(temp_voltdm, user); | 372 | ret = (*fn)(temp_voltdm, user); |
374 | if (ret) | 373 | if (ret) |
375 | break; | 374 | break; |
376 | } | 375 | } |
377 | 376 | ||
378 | return ret; | 377 | return ret; |
379 | } | 378 | } |
380 | 379 | ||
381 | static int _voltdm_register(struct voltagedomain *voltdm) | 380 | static int _voltdm_register(struct voltagedomain *voltdm) |
382 | { | 381 | { |
383 | if (!voltdm || !voltdm->name) | 382 | if (!voltdm || !voltdm->name) |
384 | return -EINVAL; | 383 | return -EINVAL; |
385 | 384 | ||
386 | INIT_LIST_HEAD(&voltdm->pwrdm_list); | 385 | INIT_LIST_HEAD(&voltdm->pwrdm_list); |
387 | list_add(&voltdm->node, &voltdm_list); | 386 | list_add(&voltdm->node, &voltdm_list); |
388 | 387 | ||
389 | pr_debug("voltagedomain: registered %s\n", voltdm->name); | 388 | pr_debug("voltagedomain: registered %s\n", voltdm->name); |
390 | 389 | ||
391 | return 0; | 390 | return 0; |
392 | } | 391 | } |
393 | 392 | ||
394 | /** | 393 | /** |
395 | * voltdm_lookup - look up a voltagedomain by name, return a pointer | 394 | * voltdm_lookup - look up a voltagedomain by name, return a pointer |
396 | * @name: name of voltagedomain | 395 | * @name: name of voltagedomain |
397 | * | 396 | * |
398 | * Find a registered voltagedomain by its name @name. Returns a pointer | 397 | * Find a registered voltagedomain by its name @name. Returns a pointer |
399 | * to the struct voltagedomain if found, or NULL otherwise. | 398 | * to the struct voltagedomain if found, or NULL otherwise. |
400 | */ | 399 | */ |
401 | struct voltagedomain *voltdm_lookup(const char *name) | 400 | struct voltagedomain *voltdm_lookup(const char *name) |
402 | { | 401 | { |
403 | struct voltagedomain *voltdm ; | 402 | struct voltagedomain *voltdm ; |
404 | 403 | ||
405 | if (!name) | 404 | if (!name) |
406 | return NULL; | 405 | return NULL; |
407 | 406 | ||
408 | voltdm = _voltdm_lookup(name); | 407 | voltdm = _voltdm_lookup(name); |
409 | 408 | ||
410 | return voltdm; | 409 | return voltdm; |
411 | } | 410 | } |
412 | 411 | ||
413 | /** | 412 | /** |
414 | * voltdm_init - set up the voltagedomain layer | 413 | * voltdm_init - set up the voltagedomain layer |
415 | * @voltdm_list: array of struct voltagedomain pointers to register | 414 | * @voltdm_list: array of struct voltagedomain pointers to register |
416 | * | 415 | * |
417 | * Loop through the array of voltagedomains @voltdm_list, registering all | 416 | * Loop through the array of voltagedomains @voltdm_list, registering all |
418 | * that are available on the current CPU. If voltdm_list is supplied | 417 | * that are available on the current CPU. If voltdm_list is supplied |
419 | * and not null, all of the referenced voltagedomains will be | 418 | * and not null, all of the referenced voltagedomains will be |
420 | * registered. No return value. | 419 | * registered. No return value. |
421 | */ | 420 | */ |
422 | void voltdm_init(struct voltagedomain **voltdms) | 421 | void voltdm_init(struct voltagedomain **voltdms) |
423 | { | 422 | { |
424 | struct voltagedomain **v; | 423 | struct voltagedomain **v; |
425 | 424 | ||
426 | if (voltdms) { | 425 | if (voltdms) { |
427 | for (v = voltdms; *v; v++) | 426 | for (v = voltdms; *v; v++) |
428 | _voltdm_register(*v); | 427 | _voltdm_register(*v); |
arch/arm/mach-omap2/voltage.h
1 | /* | File was deleted | |
2 | * OMAP Voltage Management Routines | ||
3 | * | ||
4 | * Author: Thara Gopinath <thara@ti.com> | ||
5 | * | ||
6 | * Copyright (C) 2009 Texas Instruments, Inc. | ||
7 | * Thara Gopinath <thara@ti.com> | ||
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 | #ifndef __ARCH_ARM_MACH_OMAP2_VOLTAGE_H | ||
15 | #define __ARCH_ARM_MACH_OMAP2_VOLTAGE_H | ||
16 | |||
17 | #include <linux/err.h> | ||
18 | |||
19 | #include "vc.h" | ||
20 | #include "vp.h" | ||
21 | |||
22 | struct powerdomain; | ||
23 | |||
24 | /* XXX document */ | ||
25 | #define VOLTSCALE_VPFORCEUPDATE 1 | ||
26 | #define VOLTSCALE_VCBYPASS 2 | ||
27 | |||
28 | /* | ||
29 | * OMAP3 GENERIC setup times. Revisit to see if these needs to be | ||
30 | * passed from board or PMIC file | ||
31 | */ | ||
32 | #define OMAP3_CLKSETUP 0xff | ||
33 | #define OMAP3_VOLTOFFSET 0xff | ||
34 | #define OMAP3_VOLTSETUP2 0xff | ||
35 | |||
36 | struct omap_vdd_info; | ||
37 | |||
38 | /** | ||
39 | * struct omap_vfsm_instance - per-voltage manager FSM register/bitfield | ||
40 | * data | ||
41 | * @voltsetup_mask: SETUP_TIME* bitmask in the PRM_VOLTSETUP* register | ||
42 | * @voltsetup_reg: register offset of PRM_VOLTSETUP from PRM base | ||
43 | * | ||
44 | * XXX What about VOLTOFFSET/VOLTCTRL? | ||
45 | */ | ||
46 | struct omap_vfsm_instance { | ||
47 | u32 voltsetup_mask; | ||
48 | u8 voltsetup_reg; | ||
49 | }; | ||
50 | |||
51 | /** | ||
52 | * struct voltagedomain - omap voltage domain global structure. | ||
53 | * @name: Name of the voltage domain which can be used as a unique identifier. | ||
54 | * @scalable: Whether or not this voltage domain is scalable | ||
55 | * @node: list_head linking all voltage domains | ||
56 | * @pwrdm_list: list_head linking all powerdomains in this voltagedomain | ||
57 | * @vc: pointer to VC channel associated with this voltagedomain | ||
58 | * @vp: pointer to VP associated with this voltagedomain | ||
59 | * @read: read a VC/VP register | ||
60 | * @write: write a VC/VP register | ||
61 | * @read: read-modify-write a VC/VP register | ||
62 | * @sys_clk: system clock name/frequency, used for various timing calculations | ||
63 | * @scale: function used to scale the voltage of the voltagedomain | ||
64 | * @nominal_volt: current nominal voltage for this voltage domain | ||
65 | * @volt_data: voltage table having the distinct voltages supported | ||
66 | * by the domain and other associated per voltage data. | ||
67 | */ | ||
68 | struct voltagedomain { | ||
69 | char *name; | ||
70 | bool scalable; | ||
71 | struct list_head node; | ||
72 | struct list_head pwrdm_list; | ||
73 | struct omap_vc_channel *vc; | ||
74 | const struct omap_vfsm_instance *vfsm; | ||
75 | struct omap_vp_instance *vp; | ||
76 | struct omap_voltdm_pmic *pmic; | ||
77 | |||
78 | /* VC/VP register access functions: SoC specific */ | ||
79 | u32 (*read) (u8 offset); | ||
80 | void (*write) (u32 val, u8 offset); | ||
81 | u32 (*rmw)(u32 mask, u32 bits, u8 offset); | ||
82 | |||
83 | union { | ||
84 | const char *name; | ||
85 | u32 rate; | ||
86 | } sys_clk; | ||
87 | |||
88 | int (*scale) (struct voltagedomain *voltdm, | ||
89 | unsigned long target_volt); | ||
90 | |||
91 | u32 nominal_volt; | ||
92 | struct omap_volt_data *volt_data; | ||
93 | struct omap_vdd_info *vdd; | ||
94 | struct dentry *debug_dir; | ||
95 | }; | ||
96 | |||
97 | /** | ||
98 | * struct omap_volt_data - Omap voltage specific data. | ||
99 | * @voltage_nominal: The possible voltage value in uV | ||
100 | * @sr_efuse_offs: The offset of the efuse register(from system | ||
101 | * control module base address) from where to read | ||
102 | * the n-target value for the smartreflex module. | ||
103 | * @sr_errminlimit: Error min limit value for smartreflex. This value | ||
104 | * differs at differnet opp and thus is linked | ||
105 | * with voltage. | ||
106 | * @vp_errorgain: Error gain value for the voltage processor. This | ||
107 | * field also differs according to the voltage/opp. | ||
108 | */ | ||
109 | struct omap_volt_data { | ||
110 | u32 volt_nominal; | ||
111 | u32 sr_efuse_offs; | ||
112 | u8 sr_errminlimit; | ||
113 | u8 vp_errgain; | ||
114 | }; | ||
115 | |||
116 | /** | ||
117 | * struct omap_voltdm_pmic - PMIC specific data required by voltage driver. | ||
118 | * @slew_rate: PMIC slew rate (in uv/us) | ||
119 | * @step_size: PMIC voltage step size (in uv) | ||
120 | * @i2c_slave_addr: I2C slave address of PMIC | ||
121 | * @volt_reg_addr: voltage configuration register address | ||
122 | * @cmd_reg_addr: command (on, on-LP, ret, off) configuration register address | ||
123 | * @i2c_high_speed: whether VC uses I2C high-speed mode to PMIC | ||
124 | * @i2c_mcode: master code value for I2C high-speed preamble transmission | ||
125 | * @vsel_to_uv: PMIC API to convert vsel value to actual voltage in uV. | ||
126 | * @uv_to_vsel: PMIC API to convert voltage in uV to vsel value. | ||
127 | */ | ||
128 | struct omap_voltdm_pmic { | ||
129 | int slew_rate; | ||
130 | int step_size; | ||
131 | u32 on_volt; | ||
132 | u32 onlp_volt; | ||
133 | u32 ret_volt; | ||
134 | u32 off_volt; | ||
135 | u16 volt_setup_time; | ||
136 | u16 i2c_slave_addr; | ||
137 | u16 volt_reg_addr; | ||
138 | u16 cmd_reg_addr; | ||
139 | u8 vp_erroroffset; | ||
140 | u8 vp_vstepmin; | ||
141 | u8 vp_vstepmax; | ||
142 | u8 vp_vddmin; | ||
143 | u8 vp_vddmax; | ||
144 | u8 vp_timeout_us; | ||
145 | bool i2c_high_speed; | ||
146 | u8 i2c_mcode; | ||
147 | unsigned long (*vsel_to_uv) (const u8 vsel); | ||
148 | u8 (*uv_to_vsel) (unsigned long uV); | ||
149 | }; | ||
150 | |||
151 | /** | ||
152 | * struct omap_vdd_dep_volt - Map table for voltage dependencies | ||
153 | * @main_vdd_volt : The main vdd voltage | ||
154 | * @dep_vdd_volt : The voltage at which the dependent vdd should be | ||
155 | * when the main vdd is at <main_vdd_volt> voltage | ||
156 | * | ||
157 | * Table containing the parent vdd voltage and the dependent vdd voltage | ||
158 | * corresponding to it. | ||
159 | */ | ||
160 | struct omap_vdd_dep_volt { | ||
161 | u32 main_vdd_volt; | ||
162 | u32 dep_vdd_volt; | ||
163 | }; | ||
164 | |||
165 | /** | ||
166 | * struct omap_vdd_dep_info - Dependent vdd info | ||
167 | * @name : Dependent vdd name | ||
168 | * @_dep_voltdm : internal structure meant to prevent multiple lookups | ||
169 | * @dep_table : Table containing the dependent vdd voltage | ||
170 | * corresponding to every main vdd voltage. | ||
171 | * @nr_dep_entries : number of dependency voltage entries | ||
172 | */ | ||
173 | struct omap_vdd_dep_info { | ||
174 | char *name; | ||
175 | struct voltagedomain *_dep_voltdm; | ||
176 | struct omap_vdd_dep_volt *dep_table; | ||
177 | int nr_dep_entries; | ||
178 | }; | ||
179 | |||
180 | /** | ||
181 | * omap_vdd_info - Per Voltage Domain info | ||
182 | * | ||
183 | * @volt_data : voltage table having the distinct voltages supported | ||
184 | * by the domain and other associated per voltage data. | ||
185 | * @dep_vdd_info : Array ending with a 0 terminator for dependency | ||
186 | * voltage information. | ||
187 | */ | ||
188 | struct omap_vdd_info { | ||
189 | struct omap_volt_data *volt_data; | ||
190 | struct omap_vdd_dep_info *dep_vdd_info; | ||
191 | }; | ||
192 | |||
193 | void omap_voltage_get_volttable(struct voltagedomain *voltdm, | ||
194 | struct omap_volt_data **volt_data); | ||
195 | struct omap_volt_data *omap_voltage_get_voltdata(struct voltagedomain *voltdm, | ||
196 | unsigned long volt); | ||
197 | int omap_voltage_register_pmic(struct voltagedomain *voltdm, | ||
198 | struct omap_voltdm_pmic *pmic); | ||
199 | void omap_change_voltscale_method(struct voltagedomain *voltdm, | ||
200 | int voltscale_method); | ||
201 | int omap_voltage_late_init(void); | ||
202 | |||
203 | extern void omap2xxx_voltagedomains_init(void); | ||
204 | extern void omap3xxx_voltagedomains_init(void); | ||
205 | extern void am33xx_voltagedomains_init(void); | ||
206 | extern void omap44xx_voltagedomains_init(void); | ||
207 | |||
208 | struct voltagedomain *voltdm_lookup(const char *name); | ||
209 | void voltdm_init(struct voltagedomain **voltdm_list); | ||
210 | int voltdm_add_pwrdm(struct voltagedomain *voltdm, struct powerdomain *pwrdm); | ||
211 | int voltdm_for_each(int (*fn)(struct voltagedomain *voltdm, void *user), | ||
212 | void *user); | ||
213 | int voltdm_for_each_pwrdm(struct voltagedomain *voltdm, | ||
214 | int (*fn)(struct voltagedomain *voltdm, | ||
215 | struct powerdomain *pwrdm)); | ||
216 | int voltdm_scale(struct voltagedomain *voltdm, unsigned long target_volt); | ||
217 | void voltdm_reset(struct voltagedomain *voltdm); | ||
218 | unsigned long voltdm_get_voltage(struct voltagedomain *voltdm); | ||
219 | #endif | ||
220 | 1 | /* |
arch/arm/mach-omap2/voltagedomains2xxx_data.c
1 | /* | 1 | /* |
2 | * OMAP3 voltage domain data | 2 | * OMAP3 voltage domain data |
3 | * | 3 | * |
4 | * Copyright (C) 2011 Texas Instruments, Inc. | 4 | * Copyright (C) 2011 Texas Instruments, Inc. |
5 | * | 5 | * |
6 | * This program is free software; you can redistribute it and/or modify | 6 | * This program is free software; you can redistribute it and/or modify |
7 | * it under the terms of the GNU General Public License version 2 as | 7 | * it under the terms of the GNU General Public License version 2 as |
8 | * published by the Free Software Foundation. | 8 | * published by the Free Software Foundation. |
9 | */ | 9 | */ |
10 | #include <linux/kernel.h> | 10 | #include <linux/kernel.h> |
11 | #include <linux/init.h> | 11 | #include <linux/init.h> |
12 | #include <plat/voltage.h> | ||
12 | 13 | ||
13 | #include "voltage.h" | ||
14 | 14 | ||
15 | static struct voltagedomain omap2_voltdm_core = { | 15 | static struct voltagedomain omap2_voltdm_core = { |
16 | .name = "core", | 16 | .name = "core", |
17 | }; | 17 | }; |
18 | 18 | ||
19 | static struct voltagedomain omap2_voltdm_wkup = { | 19 | static struct voltagedomain omap2_voltdm_wkup = { |
20 | .name = "wakeup", | 20 | .name = "wakeup", |
21 | }; | 21 | }; |
22 | 22 | ||
23 | static struct voltagedomain *voltagedomains_omap2[] __initdata = { | 23 | static struct voltagedomain *voltagedomains_omap2[] __initdata = { |
24 | &omap2_voltdm_core, | 24 | &omap2_voltdm_core, |
25 | &omap2_voltdm_wkup, | 25 | &omap2_voltdm_wkup, |
26 | NULL, | 26 | NULL, |
27 | }; | 27 | }; |
28 | 28 | ||
29 | void __init omap2xxx_voltagedomains_init(void) | 29 | void __init omap2xxx_voltagedomains_init(void) |
30 | { | 30 | { |
31 | voltdm_init(voltagedomains_omap2); | 31 | voltdm_init(voltagedomains_omap2); |
32 | } | 32 | } |
arch/arm/mach-omap2/voltagedomains33xx_data.c
1 | /* | 1 | /* |
2 | * AM33XX voltage domain data | 2 | * AM33XX voltage domain data |
3 | * | 3 | * |
4 | * Copyright (C) 2011 Texas Instruments, Inc. | 4 | * Copyright (C) 2011 Texas Instruments, Inc. |
5 | * | 5 | * |
6 | * This program is free software; you can redistribute it and/or modify | 6 | * This program is free software; you can redistribute it and/or modify |
7 | * it under the terms of the GNU General Public License version 2 as | 7 | * it under the terms of the GNU General Public License version 2 as |
8 | * published by the Free Software Foundation. | 8 | * published by the Free Software Foundation. |
9 | */ | 9 | */ |
10 | #include <linux/kernel.h> | 10 | #include <linux/kernel.h> |
11 | #include <linux/init.h> | 11 | #include <linux/init.h> |
12 | 12 | ||
13 | #include "voltage.h" | 13 | #include <plat/voltage.h> |
14 | 14 | ||
15 | static struct voltagedomain am33xx_voltdm_mpu = { | 15 | static struct voltagedomain am33xx_voltdm_mpu = { |
16 | .name = "mpu", | 16 | .name = "mpu", |
17 | }; | 17 | }; |
18 | 18 | ||
19 | static struct voltagedomain am33xx_voltdm_core = { | 19 | static struct voltagedomain am33xx_voltdm_core = { |
20 | .name = "core", | 20 | .name = "core", |
21 | }; | 21 | }; |
22 | 22 | ||
23 | static struct voltagedomain am33xx_voltdm_rtc = { | 23 | static struct voltagedomain am33xx_voltdm_rtc = { |
24 | .name = "rtc", | 24 | .name = "rtc", |
25 | }; | 25 | }; |
26 | 26 | ||
27 | static struct voltagedomain *voltagedomains_am33xx[] __initdata = { | 27 | static struct voltagedomain *voltagedomains_am33xx[] __initdata = { |
28 | &am33xx_voltdm_mpu, | 28 | &am33xx_voltdm_mpu, |
29 | &am33xx_voltdm_core, | 29 | &am33xx_voltdm_core, |
30 | &am33xx_voltdm_rtc, | 30 | &am33xx_voltdm_rtc, |
31 | NULL, | 31 | NULL, |
32 | }; | 32 | }; |
33 | 33 | ||
34 | void __init am33xx_voltagedomains_init(void) | 34 | void __init am33xx_voltagedomains_init(void) |
35 | { | 35 | { |
36 | voltdm_init(voltagedomains_am33xx); | 36 | voltdm_init(voltagedomains_am33xx); |
37 | } | 37 | } |
38 | 38 |
arch/arm/mach-omap2/voltagedomains3xxx_data.c
1 | /* | 1 | /* |
2 | * OMAP3 voltage domain data | 2 | * OMAP3 voltage domain data |
3 | * | 3 | * |
4 | * Copyright (C) 2007, 2010 Texas Instruments, Inc. | 4 | * Copyright (C) 2007, 2010 Texas Instruments, Inc. |
5 | * Rajendra Nayak <rnayak@ti.com> | 5 | * Rajendra Nayak <rnayak@ti.com> |
6 | * Lesly A M <x0080970@ti.com> | 6 | * Lesly A M <x0080970@ti.com> |
7 | * Thara Gopinath <thara@ti.com> | 7 | * Thara Gopinath <thara@ti.com> |
8 | * | 8 | * |
9 | * Copyright (C) 2008, 2011 Nokia Corporation | 9 | * Copyright (C) 2008, 2011 Nokia Corporation |
10 | * Kalle Jokiniemi | 10 | * Kalle Jokiniemi |
11 | * Paul Walmsley | 11 | * Paul Walmsley |
12 | * | 12 | * |
13 | * This program is free software; you can redistribute it and/or modify | 13 | * This program is free software; you can redistribute it and/or modify |
14 | * it under the terms of the GNU General Public License version 2 as | 14 | * it under the terms of the GNU General Public License version 2 as |
15 | * published by the Free Software Foundation. | 15 | * published by the Free Software Foundation. |
16 | */ | 16 | */ |
17 | #include <linux/kernel.h> | 17 | #include <linux/kernel.h> |
18 | #include <linux/err.h> | 18 | #include <linux/err.h> |
19 | #include <linux/init.h> | 19 | #include <linux/init.h> |
20 | 20 | ||
21 | #include <plat/common.h> | 21 | #include <plat/common.h> |
22 | #include <plat/cpu.h> | 22 | #include <plat/cpu.h> |
23 | #include <plat/voltage.h> | ||
24 | #include <plat/vc.h> | ||
25 | #include <plat/vp.h> | ||
23 | 26 | ||
24 | #include "prm-regbits-34xx.h" | 27 | #include "prm-regbits-34xx.h" |
25 | #include "omap_opp_data.h" | 28 | #include "omap_opp_data.h" |
26 | #include "voltage.h" | ||
27 | #include "vc.h" | ||
28 | #include "vp.h" | ||
29 | 29 | ||
30 | /* | 30 | /* |
31 | * VDD data | 31 | * VDD data |
32 | */ | 32 | */ |
33 | 33 | ||
34 | static const struct omap_vfsm_instance omap3_vdd1_vfsm = { | 34 | static const struct omap_vfsm_instance omap3_vdd1_vfsm = { |
35 | .voltsetup_reg = OMAP3_PRM_VOLTSETUP1_OFFSET, | 35 | .voltsetup_reg = OMAP3_PRM_VOLTSETUP1_OFFSET, |
36 | .voltsetup_mask = OMAP3430_SETUP_TIME1_MASK, | 36 | .voltsetup_mask = OMAP3430_SETUP_TIME1_MASK, |
37 | }; | 37 | }; |
38 | 38 | ||
39 | static struct omap_vdd_info omap3_vdd1_info; | 39 | static struct omap_vdd_info omap3_vdd1_info; |
40 | 40 | ||
41 | static const struct omap_vfsm_instance omap3_vdd2_vfsm = { | 41 | static const struct omap_vfsm_instance omap3_vdd2_vfsm = { |
42 | .voltsetup_reg = OMAP3_PRM_VOLTSETUP1_OFFSET, | 42 | .voltsetup_reg = OMAP3_PRM_VOLTSETUP1_OFFSET, |
43 | .voltsetup_mask = OMAP3430_SETUP_TIME2_MASK, | 43 | .voltsetup_mask = OMAP3430_SETUP_TIME2_MASK, |
44 | }; | 44 | }; |
45 | 45 | ||
46 | static struct voltagedomain omap3_voltdm_mpu = { | 46 | static struct voltagedomain omap3_voltdm_mpu = { |
47 | .name = "mpu_iva", | 47 | .name = "mpu_iva", |
48 | .scalable = true, | 48 | .scalable = true, |
49 | .read = omap3_prm_vcvp_read, | 49 | .read = omap3_prm_vcvp_read, |
50 | .write = omap3_prm_vcvp_write, | 50 | .write = omap3_prm_vcvp_write, |
51 | .rmw = omap3_prm_vcvp_rmw, | 51 | .rmw = omap3_prm_vcvp_rmw, |
52 | .vc = &omap3_vc_mpu, | 52 | .vc = &omap3_vc_mpu, |
53 | .vfsm = &omap3_vdd1_vfsm, | 53 | .vfsm = &omap3_vdd1_vfsm, |
54 | .vp = &omap3_vp_mpu, | 54 | .vp = &omap3_vp_mpu, |
55 | .vdd = &omap3_vdd1_info, | 55 | .vdd = &omap3_vdd1_info, |
56 | }; | 56 | }; |
57 | 57 | ||
58 | static struct omap_vdd_info omap3_vdd2_info; | 58 | static struct omap_vdd_info omap3_vdd2_info; |
59 | 59 | ||
60 | static struct voltagedomain omap3_voltdm_core = { | 60 | static struct voltagedomain omap3_voltdm_core = { |
61 | .name = "core", | 61 | .name = "core", |
62 | .scalable = true, | 62 | .scalable = true, |
63 | .read = omap3_prm_vcvp_read, | 63 | .read = omap3_prm_vcvp_read, |
64 | .write = omap3_prm_vcvp_write, | 64 | .write = omap3_prm_vcvp_write, |
65 | .rmw = omap3_prm_vcvp_rmw, | 65 | .rmw = omap3_prm_vcvp_rmw, |
66 | .vc = &omap3_vc_core, | 66 | .vc = &omap3_vc_core, |
67 | .vfsm = &omap3_vdd2_vfsm, | 67 | .vfsm = &omap3_vdd2_vfsm, |
68 | .vp = &omap3_vp_core, | 68 | .vp = &omap3_vp_core, |
69 | .vdd = &omap3_vdd2_info, | 69 | .vdd = &omap3_vdd2_info, |
70 | }; | 70 | }; |
71 | 71 | ||
72 | static struct voltagedomain omap3_voltdm_wkup = { | 72 | static struct voltagedomain omap3_voltdm_wkup = { |
73 | .name = "wakeup", | 73 | .name = "wakeup", |
74 | }; | 74 | }; |
75 | 75 | ||
76 | static struct voltagedomain *voltagedomains_omap3[] __initdata = { | 76 | static struct voltagedomain *voltagedomains_omap3[] __initdata = { |
77 | &omap3_voltdm_mpu, | 77 | &omap3_voltdm_mpu, |
78 | &omap3_voltdm_core, | 78 | &omap3_voltdm_core, |
79 | &omap3_voltdm_wkup, | 79 | &omap3_voltdm_wkup, |
80 | NULL, | 80 | NULL, |
81 | }; | 81 | }; |
82 | 82 | ||
83 | static const char *sys_clk_name __initdata = "sys_ck"; | 83 | static const char *sys_clk_name __initdata = "sys_ck"; |
84 | 84 | ||
85 | void __init omap3xxx_voltagedomains_init(void) | 85 | void __init omap3xxx_voltagedomains_init(void) |
86 | { | 86 | { |
87 | struct voltagedomain *voltdm; | 87 | struct voltagedomain *voltdm; |
88 | int i; | 88 | int i; |
89 | 89 | ||
90 | /* | 90 | /* |
91 | * XXX Will depend on the process, validation, and binning | 91 | * XXX Will depend on the process, validation, and binning |
92 | * for the currently-running IC | 92 | * for the currently-running IC |
93 | */ | 93 | */ |
94 | if (cpu_is_omap3630()) { | 94 | if (cpu_is_omap3630()) { |
95 | omap3_voltdm_mpu.volt_data = omap36xx_vddmpu_volt_data; | 95 | omap3_voltdm_mpu.volt_data = omap36xx_vddmpu_volt_data; |
96 | omap3_voltdm_core.volt_data = omap36xx_vddcore_volt_data; | 96 | omap3_voltdm_core.volt_data = omap36xx_vddcore_volt_data; |
97 | omap3_vdd1_info.dep_vdd_info = omap36xx_vddmpu_dep_info; | 97 | omap3_vdd1_info.dep_vdd_info = omap36xx_vddmpu_dep_info; |
98 | } else { | 98 | } else { |
99 | omap3_voltdm_mpu.volt_data = omap34xx_vddmpu_volt_data; | 99 | omap3_voltdm_mpu.volt_data = omap34xx_vddmpu_volt_data; |
100 | omap3_voltdm_core.volt_data = omap34xx_vddcore_volt_data; | 100 | omap3_voltdm_core.volt_data = omap34xx_vddcore_volt_data; |
101 | omap3_vdd1_info.dep_vdd_info = omap34xx_vddmpu_dep_info; | 101 | omap3_vdd1_info.dep_vdd_info = omap34xx_vddmpu_dep_info; |
102 | } | 102 | } |
103 | 103 | ||
104 | for (i = 0; voltdm = voltagedomains_omap3[i], voltdm; i++) | 104 | for (i = 0; voltdm = voltagedomains_omap3[i], voltdm; i++) |
105 | voltdm->sys_clk.name = sys_clk_name; | 105 | voltdm->sys_clk.name = sys_clk_name; |
106 | 106 |
arch/arm/mach-omap2/voltagedomains44xx_data.c
1 | /* | 1 | /* |
2 | * OMAP3/OMAP4 Voltage Management Routines | 2 | * OMAP3/OMAP4 Voltage Management Routines |
3 | * | 3 | * |
4 | * Author: Thara Gopinath <thara@ti.com> | 4 | * Author: Thara Gopinath <thara@ti.com> |
5 | * | 5 | * |
6 | * Copyright (C) 2007 Texas Instruments, Inc. | 6 | * Copyright (C) 2007 Texas Instruments, Inc. |
7 | * Rajendra Nayak <rnayak@ti.com> | 7 | * Rajendra Nayak <rnayak@ti.com> |
8 | * Lesly A M <x0080970@ti.com> | 8 | * Lesly A M <x0080970@ti.com> |
9 | * | 9 | * |
10 | * Copyright (C) 2008 Nokia Corporation | 10 | * Copyright (C) 2008 Nokia Corporation |
11 | * Kalle Jokiniemi | 11 | * Kalle Jokiniemi |
12 | * | 12 | * |
13 | * Copyright (C) 2010 Texas Instruments, Inc. | 13 | * Copyright (C) 2010 Texas Instruments, Inc. |
14 | * Thara Gopinath <thara@ti.com> | 14 | * Thara Gopinath <thara@ti.com> |
15 | * | 15 | * |
16 | * This program is free software; you can redistribute it and/or modify | 16 | * This program is free software; you can redistribute it and/or modify |
17 | * it under the terms of the GNU General Public License version 2 as | 17 | * it under the terms of the GNU General Public License version 2 as |
18 | * published by the Free Software Foundation. | 18 | * published by the Free Software Foundation. |
19 | */ | 19 | */ |
20 | #include <linux/kernel.h> | 20 | #include <linux/kernel.h> |
21 | #include <linux/err.h> | 21 | #include <linux/err.h> |
22 | #include <linux/init.h> | 22 | #include <linux/init.h> |
23 | 23 | ||
24 | #include <plat/common.h> | 24 | #include <plat/common.h> |
25 | #include <plat/vc.h> | ||
26 | #include <plat/vp.h> | ||
25 | 27 | ||
26 | #include "prm-regbits-44xx.h" | 28 | #include "prm-regbits-44xx.h" |
27 | #include "prm44xx.h" | 29 | #include "prm44xx.h" |
28 | #include "prcm44xx.h" | 30 | #include "prcm44xx.h" |
29 | #include "prminst44xx.h" | 31 | #include "prminst44xx.h" |
30 | #include "voltage.h" | 32 | #include "voltage.h" |
31 | #include "omap_opp_data.h" | 33 | #include "omap_opp_data.h" |
32 | #include "vc.h" | ||
33 | #include "vp.h" | ||
34 | 34 | ||
35 | static const struct omap_vfsm_instance omap4_vdd_mpu_vfsm = { | 35 | static const struct omap_vfsm_instance omap4_vdd_mpu_vfsm = { |
36 | .voltsetup_reg = OMAP4_PRM_VOLTSETUP_MPU_RET_SLEEP_OFFSET, | 36 | .voltsetup_reg = OMAP4_PRM_VOLTSETUP_MPU_RET_SLEEP_OFFSET, |
37 | }; | 37 | }; |
38 | static struct omap_vdd_info omap4_vdd_mpu_info; | 38 | static struct omap_vdd_info omap4_vdd_mpu_info; |
39 | 39 | ||
40 | 40 | ||
41 | static const struct omap_vfsm_instance omap4_vdd_iva_vfsm = { | 41 | static const struct omap_vfsm_instance omap4_vdd_iva_vfsm = { |
42 | .voltsetup_reg = OMAP4_PRM_VOLTSETUP_IVA_RET_SLEEP_OFFSET, | 42 | .voltsetup_reg = OMAP4_PRM_VOLTSETUP_IVA_RET_SLEEP_OFFSET, |
43 | }; | 43 | }; |
44 | static struct omap_vdd_info omap4_vdd_iva_info; | 44 | static struct omap_vdd_info omap4_vdd_iva_info; |
45 | 45 | ||
46 | static const struct omap_vfsm_instance omap4_vdd_core_vfsm = { | 46 | static const struct omap_vfsm_instance omap4_vdd_core_vfsm = { |
47 | .voltsetup_reg = OMAP4_PRM_VOLTSETUP_CORE_RET_SLEEP_OFFSET, | 47 | .voltsetup_reg = OMAP4_PRM_VOLTSETUP_CORE_RET_SLEEP_OFFSET, |
48 | }; | 48 | }; |
49 | static struct omap_vdd_info omap4_vdd_core_info; | 49 | static struct omap_vdd_info omap4_vdd_core_info; |
50 | 50 | ||
51 | static struct voltagedomain omap4_voltdm_mpu = { | 51 | static struct voltagedomain omap4_voltdm_mpu = { |
52 | .name = "mpu", | 52 | .name = "mpu", |
53 | .scalable = true, | 53 | .scalable = true, |
54 | .read = omap4_prm_vcvp_read, | 54 | .read = omap4_prm_vcvp_read, |
55 | .write = omap4_prm_vcvp_write, | 55 | .write = omap4_prm_vcvp_write, |
56 | .rmw = omap4_prm_vcvp_rmw, | 56 | .rmw = omap4_prm_vcvp_rmw, |
57 | .vc = &omap4_vc_mpu, | 57 | .vc = &omap4_vc_mpu, |
58 | .vfsm = &omap4_vdd_mpu_vfsm, | 58 | .vfsm = &omap4_vdd_mpu_vfsm, |
59 | .vp = &omap4_vp_mpu, | 59 | .vp = &omap4_vp_mpu, |
60 | .vdd = &omap4_vdd_mpu_info, | 60 | .vdd = &omap4_vdd_mpu_info, |
61 | }; | 61 | }; |
62 | 62 | ||
63 | static struct voltagedomain omap4_voltdm_iva = { | 63 | static struct voltagedomain omap4_voltdm_iva = { |
64 | .name = "iva", | 64 | .name = "iva", |
65 | .scalable = true, | 65 | .scalable = true, |
66 | .read = omap4_prm_vcvp_read, | 66 | .read = omap4_prm_vcvp_read, |
67 | .write = omap4_prm_vcvp_write, | 67 | .write = omap4_prm_vcvp_write, |
68 | .rmw = omap4_prm_vcvp_rmw, | 68 | .rmw = omap4_prm_vcvp_rmw, |
69 | .vc = &omap4_vc_iva, | 69 | .vc = &omap4_vc_iva, |
70 | .vfsm = &omap4_vdd_iva_vfsm, | 70 | .vfsm = &omap4_vdd_iva_vfsm, |
71 | .vp = &omap4_vp_iva, | 71 | .vp = &omap4_vp_iva, |
72 | .vdd = &omap4_vdd_iva_info, | 72 | .vdd = &omap4_vdd_iva_info, |
73 | }; | 73 | }; |
74 | 74 | ||
75 | static struct voltagedomain omap4_voltdm_core = { | 75 | static struct voltagedomain omap4_voltdm_core = { |
76 | .name = "core", | 76 | .name = "core", |
77 | .scalable = true, | 77 | .scalable = true, |
78 | .read = omap4_prm_vcvp_read, | 78 | .read = omap4_prm_vcvp_read, |
79 | .write = omap4_prm_vcvp_write, | 79 | .write = omap4_prm_vcvp_write, |
80 | .rmw = omap4_prm_vcvp_rmw, | 80 | .rmw = omap4_prm_vcvp_rmw, |
81 | .vc = &omap4_vc_core, | 81 | .vc = &omap4_vc_core, |
82 | .vfsm = &omap4_vdd_core_vfsm, | 82 | .vfsm = &omap4_vdd_core_vfsm, |
83 | .vp = &omap4_vp_core, | 83 | .vp = &omap4_vp_core, |
84 | .vdd = &omap4_vdd_core_info, | 84 | .vdd = &omap4_vdd_core_info, |
85 | }; | 85 | }; |
86 | 86 | ||
87 | static struct voltagedomain omap4_voltdm_wkup = { | 87 | static struct voltagedomain omap4_voltdm_wkup = { |
88 | .name = "wakeup", | 88 | .name = "wakeup", |
89 | }; | 89 | }; |
90 | 90 | ||
91 | static struct voltagedomain *voltagedomains_omap4[] __initdata = { | 91 | static struct voltagedomain *voltagedomains_omap4[] __initdata = { |
92 | &omap4_voltdm_mpu, | 92 | &omap4_voltdm_mpu, |
93 | &omap4_voltdm_iva, | 93 | &omap4_voltdm_iva, |
94 | &omap4_voltdm_core, | 94 | &omap4_voltdm_core, |
95 | &omap4_voltdm_wkup, | 95 | &omap4_voltdm_wkup, |
96 | NULL, | 96 | NULL, |
97 | }; | 97 | }; |
98 | 98 | ||
99 | static const char *sys_clk_name __initdata = "sys_clkin_ck"; | 99 | static const char *sys_clk_name __initdata = "sys_clkin_ck"; |
100 | 100 | ||
101 | void __init omap44xx_voltagedomains_init(void) | 101 | void __init omap44xx_voltagedomains_init(void) |
102 | { | 102 | { |
103 | struct voltagedomain *voltdm; | 103 | struct voltagedomain *voltdm; |
104 | int i; | 104 | int i; |
105 | 105 | ||
106 | /* | 106 | /* |
107 | * XXX Will depend on the process, validation, and binning | 107 | * XXX Will depend on the process, validation, and binning |
108 | * for the currently-running IC | 108 | * for the currently-running IC |
109 | */ | 109 | */ |
110 | omap4_voltdm_mpu.volt_data = omap44xx_vdd_mpu_volt_data; | 110 | omap4_voltdm_mpu.volt_data = omap44xx_vdd_mpu_volt_data; |
111 | omap4_vdd_mpu_info.dep_vdd_info = omap443x_vddmpu_dep_info; | 111 | omap4_vdd_mpu_info.dep_vdd_info = omap443x_vddmpu_dep_info; |
112 | 112 | ||
113 | omap4_voltdm_iva.volt_data = omap44xx_vdd_iva_volt_data; | 113 | omap4_voltdm_iva.volt_data = omap44xx_vdd_iva_volt_data; |
114 | omap4_vdd_iva_info.dep_vdd_info = omap443x_vddiva_dep_info; | 114 | omap4_vdd_iva_info.dep_vdd_info = omap443x_vddiva_dep_info; |
115 | 115 | ||
116 | omap4_voltdm_core.volt_data = omap44xx_vdd_core_volt_data; | 116 | omap4_voltdm_core.volt_data = omap44xx_vdd_core_volt_data; |
117 | 117 | ||
118 | for (i = 0; voltdm = voltagedomains_omap4[i], voltdm; i++) | 118 | for (i = 0; voltdm = voltagedomains_omap4[i], voltdm; i++) |
119 | voltdm->sys_clk.name = sys_clk_name; | 119 | voltdm->sys_clk.name = sys_clk_name; |
120 | 120 | ||
121 | voltdm_init(voltagedomains_omap4); | 121 | voltdm_init(voltagedomains_omap4); |
arch/arm/mach-omap2/vp.c
1 | #include <linux/kernel.h> | 1 | #include <linux/kernel.h> |
2 | #include <linux/init.h> | 2 | #include <linux/init.h> |
3 | 3 | ||
4 | #include <plat/common.h> | 4 | #include <plat/common.h> |
5 | #include <plat/voltage.h> | ||
6 | #include <plat/vp.h> | ||
5 | 7 | ||
6 | #include "voltage.h" | ||
7 | #include "vp.h" | ||
8 | #include "prm-regbits-34xx.h" | 8 | #include "prm-regbits-34xx.h" |
9 | #include "prm-regbits-44xx.h" | 9 | #include "prm-regbits-44xx.h" |
10 | #include "prm44xx.h" | 10 | #include "prm44xx.h" |
11 | 11 | ||
12 | static u32 _vp_set_init_voltage(struct voltagedomain *voltdm, u32 volt) | 12 | static u32 _vp_set_init_voltage(struct voltagedomain *voltdm, u32 volt) |
13 | { | 13 | { |
14 | struct omap_vp_instance *vp = voltdm->vp; | 14 | struct omap_vp_instance *vp = voltdm->vp; |
15 | u32 vpconfig; | 15 | u32 vpconfig; |
16 | char vsel; | 16 | char vsel; |
17 | 17 | ||
18 | vsel = voltdm->pmic->uv_to_vsel(volt); | 18 | vsel = voltdm->pmic->uv_to_vsel(volt); |
19 | 19 | ||
20 | vpconfig = voltdm->read(vp->vpconfig); | 20 | vpconfig = voltdm->read(vp->vpconfig); |
21 | vpconfig &= ~(vp->common->vpconfig_initvoltage_mask | | 21 | vpconfig &= ~(vp->common->vpconfig_initvoltage_mask | |
22 | vp->common->vpconfig_forceupdate | | 22 | vp->common->vpconfig_forceupdate | |
23 | vp->common->vpconfig_initvdd); | 23 | vp->common->vpconfig_initvdd); |
24 | vpconfig |= vsel << __ffs(vp->common->vpconfig_initvoltage_mask); | 24 | vpconfig |= vsel << __ffs(vp->common->vpconfig_initvoltage_mask); |
25 | voltdm->write(vpconfig, vp->vpconfig); | 25 | voltdm->write(vpconfig, vp->vpconfig); |
26 | 26 | ||
27 | /* Trigger initVDD value copy to voltage processor */ | 27 | /* Trigger initVDD value copy to voltage processor */ |
28 | voltdm->write((vpconfig | vp->common->vpconfig_initvdd), | 28 | voltdm->write((vpconfig | vp->common->vpconfig_initvdd), |
29 | vp->vpconfig); | 29 | vp->vpconfig); |
30 | 30 | ||
31 | /* Clear initVDD copy trigger bit */ | 31 | /* Clear initVDD copy trigger bit */ |
32 | voltdm->write(vpconfig, vp->vpconfig); | 32 | voltdm->write(vpconfig, vp->vpconfig); |
33 | 33 | ||
34 | return vpconfig; | 34 | return vpconfig; |
35 | } | 35 | } |
36 | 36 | ||
37 | /* Generic voltage init functions */ | 37 | /* Generic voltage init functions */ |
38 | void __init omap_vp_init(struct voltagedomain *voltdm) | 38 | void __init omap_vp_init(struct voltagedomain *voltdm) |
39 | { | 39 | { |
40 | struct omap_vp_instance *vp = voltdm->vp; | 40 | struct omap_vp_instance *vp = voltdm->vp; |
41 | u32 val, sys_clk_rate, timeout, waittime; | 41 | u32 val, sys_clk_rate, timeout, waittime; |
42 | u32 vddmin, vddmax, vstepmin, vstepmax; | 42 | u32 vddmin, vddmax, vstepmin, vstepmax; |
43 | 43 | ||
44 | if (!voltdm->read || !voltdm->write) { | 44 | if (!voltdm->read || !voltdm->write) { |
45 | pr_err("%s: No read/write API for accessing vdd_%s regs\n", | 45 | pr_err("%s: No read/write API for accessing vdd_%s regs\n", |
46 | __func__, voltdm->name); | 46 | __func__, voltdm->name); |
47 | return; | 47 | return; |
48 | } | 48 | } |
49 | 49 | ||
50 | vp->enabled = false; | 50 | vp->enabled = false; |
51 | 51 | ||
52 | /* Divide to avoid overflow */ | 52 | /* Divide to avoid overflow */ |
53 | sys_clk_rate = voltdm->sys_clk.rate / 1000; | 53 | sys_clk_rate = voltdm->sys_clk.rate / 1000; |
54 | 54 | ||
55 | timeout = (sys_clk_rate * voltdm->pmic->vp_timeout_us) / 1000; | 55 | timeout = (sys_clk_rate * voltdm->pmic->vp_timeout_us) / 1000; |
56 | vddmin = voltdm->pmic->vp_vddmin; | 56 | vddmin = voltdm->pmic->vp_vddmin; |
57 | vddmax = voltdm->pmic->vp_vddmax; | 57 | vddmax = voltdm->pmic->vp_vddmax; |
58 | 58 | ||
59 | waittime = ((voltdm->pmic->step_size / voltdm->pmic->slew_rate) * | 59 | waittime = ((voltdm->pmic->step_size / voltdm->pmic->slew_rate) * |
60 | sys_clk_rate) / 1000; | 60 | sys_clk_rate) / 1000; |
61 | vstepmin = voltdm->pmic->vp_vstepmin; | 61 | vstepmin = voltdm->pmic->vp_vstepmin; |
62 | vstepmax = voltdm->pmic->vp_vstepmax; | 62 | vstepmax = voltdm->pmic->vp_vstepmax; |
63 | 63 | ||
64 | /* | 64 | /* |
65 | * VP_CONFIG: error gain is not set here, it will be updated | 65 | * VP_CONFIG: error gain is not set here, it will be updated |
66 | * on each scale, based on OPP. | 66 | * on each scale, based on OPP. |
67 | */ | 67 | */ |
68 | val = (voltdm->pmic->vp_erroroffset << | 68 | val = (voltdm->pmic->vp_erroroffset << |
69 | __ffs(voltdm->vp->common->vpconfig_erroroffset_mask)) | | 69 | __ffs(voltdm->vp->common->vpconfig_erroroffset_mask)) | |
70 | vp->common->vpconfig_timeouten; | 70 | vp->common->vpconfig_timeouten; |
71 | voltdm->write(val, vp->vpconfig); | 71 | voltdm->write(val, vp->vpconfig); |
72 | 72 | ||
73 | /* VSTEPMIN */ | 73 | /* VSTEPMIN */ |
74 | val = (waittime << vp->common->vstepmin_smpswaittimemin_shift) | | 74 | val = (waittime << vp->common->vstepmin_smpswaittimemin_shift) | |
75 | (vstepmin << vp->common->vstepmin_stepmin_shift); | 75 | (vstepmin << vp->common->vstepmin_stepmin_shift); |
76 | voltdm->write(val, vp->vstepmin); | 76 | voltdm->write(val, vp->vstepmin); |
77 | 77 | ||
78 | /* VSTEPMAX */ | 78 | /* VSTEPMAX */ |
79 | val = (vstepmax << vp->common->vstepmax_stepmax_shift) | | 79 | val = (vstepmax << vp->common->vstepmax_stepmax_shift) | |
80 | (waittime << vp->common->vstepmax_smpswaittimemax_shift); | 80 | (waittime << vp->common->vstepmax_smpswaittimemax_shift); |
81 | voltdm->write(val, vp->vstepmax); | 81 | voltdm->write(val, vp->vstepmax); |
82 | 82 | ||
83 | /* VLIMITTO */ | 83 | /* VLIMITTO */ |
84 | val = (vddmax << vp->common->vlimitto_vddmax_shift) | | 84 | val = (vddmax << vp->common->vlimitto_vddmax_shift) | |
85 | (vddmin << vp->common->vlimitto_vddmin_shift) | | 85 | (vddmin << vp->common->vlimitto_vddmin_shift) | |
86 | (timeout << vp->common->vlimitto_timeout_shift); | 86 | (timeout << vp->common->vlimitto_timeout_shift); |
87 | voltdm->write(val, vp->vlimitto); | 87 | voltdm->write(val, vp->vlimitto); |
88 | } | 88 | } |
89 | 89 | ||
90 | int omap_vp_update_errorgain(struct voltagedomain *voltdm, | 90 | int omap_vp_update_errorgain(struct voltagedomain *voltdm, |
91 | unsigned long target_volt) | 91 | unsigned long target_volt) |
92 | { | 92 | { |
93 | struct omap_volt_data *volt_data; | 93 | struct omap_volt_data *volt_data; |
94 | 94 | ||
95 | if (!voltdm->vp) | 95 | if (!voltdm->vp) |
96 | return -EINVAL; | 96 | return -EINVAL; |
97 | 97 | ||
98 | /* Get volt_data corresponding to target_volt */ | 98 | /* Get volt_data corresponding to target_volt */ |
99 | volt_data = omap_voltage_get_voltdata(voltdm, target_volt); | 99 | volt_data = omap_voltage_get_voltdata(voltdm, target_volt); |
100 | if (IS_ERR(volt_data)) | 100 | if (IS_ERR(volt_data)) |
101 | return -EINVAL; | 101 | return -EINVAL; |
102 | 102 | ||
103 | /* Setting vp errorgain based on the voltage */ | 103 | /* Setting vp errorgain based on the voltage */ |
104 | voltdm->rmw(voltdm->vp->common->vpconfig_errorgain_mask, | 104 | voltdm->rmw(voltdm->vp->common->vpconfig_errorgain_mask, |
105 | volt_data->vp_errgain << | 105 | volt_data->vp_errgain << |
106 | __ffs(voltdm->vp->common->vpconfig_errorgain_mask), | 106 | __ffs(voltdm->vp->common->vpconfig_errorgain_mask), |
107 | voltdm->vp->vpconfig); | 107 | voltdm->vp->vpconfig); |
108 | 108 | ||
109 | return 0; | 109 | return 0; |
110 | } | 110 | } |
111 | 111 | ||
112 | /* VP force update method of voltage scaling */ | 112 | /* VP force update method of voltage scaling */ |
113 | int omap_vp_forceupdate_scale(struct voltagedomain *voltdm, | 113 | int omap_vp_forceupdate_scale(struct voltagedomain *voltdm, |
114 | unsigned long target_volt) | 114 | unsigned long target_volt) |
115 | { | 115 | { |
116 | struct omap_vp_instance *vp = voltdm->vp; | 116 | struct omap_vp_instance *vp = voltdm->vp; |
117 | u32 vpconfig; | 117 | u32 vpconfig; |
118 | u8 target_vsel, current_vsel; | 118 | u8 target_vsel, current_vsel; |
119 | int ret, timeout = 0; | 119 | int ret, timeout = 0; |
120 | 120 | ||
121 | ret = omap_vc_pre_scale(voltdm, target_volt, &target_vsel, ¤t_vsel); | 121 | ret = omap_vc_pre_scale(voltdm, target_volt, &target_vsel, ¤t_vsel); |
122 | if (ret) | 122 | if (ret) |
123 | return ret; | 123 | return ret; |
124 | 124 | ||
125 | /* | 125 | /* |
126 | * Clear all pending TransactionDone interrupt/status. Typical latency | 126 | * Clear all pending TransactionDone interrupt/status. Typical latency |
127 | * is <3us | 127 | * is <3us |
128 | */ | 128 | */ |
129 | while (timeout++ < VP_TRANXDONE_TIMEOUT) { | 129 | while (timeout++ < VP_TRANXDONE_TIMEOUT) { |
130 | vp->common->ops->clear_txdone(vp->id); | 130 | vp->common->ops->clear_txdone(vp->id); |
131 | if (!vp->common->ops->check_txdone(vp->id)) | 131 | if (!vp->common->ops->check_txdone(vp->id)) |
132 | break; | 132 | break; |
133 | udelay(1); | 133 | udelay(1); |
134 | } | 134 | } |
135 | if (timeout >= VP_TRANXDONE_TIMEOUT) { | 135 | if (timeout >= VP_TRANXDONE_TIMEOUT) { |
136 | pr_warning("%s: vdd_%s TRANXDONE timeout exceeded." | 136 | pr_warning("%s: vdd_%s TRANXDONE timeout exceeded." |
137 | "Voltage change aborted", __func__, voltdm->name); | 137 | "Voltage change aborted", __func__, voltdm->name); |
138 | return -ETIMEDOUT; | 138 | return -ETIMEDOUT; |
139 | } | 139 | } |
140 | 140 | ||
141 | vpconfig = _vp_set_init_voltage(voltdm, target_volt); | 141 | vpconfig = _vp_set_init_voltage(voltdm, target_volt); |
142 | 142 | ||
143 | /* Force update of voltage */ | 143 | /* Force update of voltage */ |
144 | voltdm->write(vpconfig | vp->common->vpconfig_forceupdate, | 144 | voltdm->write(vpconfig | vp->common->vpconfig_forceupdate, |
145 | voltdm->vp->vpconfig); | 145 | voltdm->vp->vpconfig); |
146 | 146 | ||
147 | /* | 147 | /* |
148 | * Wait for TransactionDone. Typical latency is <200us. | 148 | * Wait for TransactionDone. Typical latency is <200us. |
149 | * Depends on SMPSWAITTIMEMIN/MAX and voltage change | 149 | * Depends on SMPSWAITTIMEMIN/MAX and voltage change |
150 | */ | 150 | */ |
151 | timeout = 0; | 151 | timeout = 0; |
152 | omap_test_timeout(vp->common->ops->check_txdone(vp->id), | 152 | omap_test_timeout(vp->common->ops->check_txdone(vp->id), |
153 | VP_TRANXDONE_TIMEOUT, timeout); | 153 | VP_TRANXDONE_TIMEOUT, timeout); |
154 | if (timeout >= VP_TRANXDONE_TIMEOUT) | 154 | if (timeout >= VP_TRANXDONE_TIMEOUT) |
155 | pr_err("%s: vdd_%s TRANXDONE timeout exceeded." | 155 | pr_err("%s: vdd_%s TRANXDONE timeout exceeded." |
156 | "TRANXDONE never got set after the voltage update\n", | 156 | "TRANXDONE never got set after the voltage update\n", |
157 | __func__, voltdm->name); | 157 | __func__, voltdm->name); |
158 | 158 | ||
159 | omap_vc_post_scale(voltdm, target_volt, target_vsel, current_vsel); | 159 | omap_vc_post_scale(voltdm, target_volt, target_vsel, current_vsel); |
160 | 160 | ||
161 | /* | 161 | /* |
162 | * Disable TransactionDone interrupt , clear all status, clear | 162 | * Disable TransactionDone interrupt , clear all status, clear |
163 | * control registers | 163 | * control registers |
164 | */ | 164 | */ |
165 | timeout = 0; | 165 | timeout = 0; |
166 | while (timeout++ < VP_TRANXDONE_TIMEOUT) { | 166 | while (timeout++ < VP_TRANXDONE_TIMEOUT) { |
167 | vp->common->ops->clear_txdone(vp->id); | 167 | vp->common->ops->clear_txdone(vp->id); |
168 | if (!vp->common->ops->check_txdone(vp->id)) | 168 | if (!vp->common->ops->check_txdone(vp->id)) |
169 | break; | 169 | break; |
170 | udelay(1); | 170 | udelay(1); |
171 | } | 171 | } |
172 | 172 | ||
173 | if (timeout >= VP_TRANXDONE_TIMEOUT) | 173 | if (timeout >= VP_TRANXDONE_TIMEOUT) |
174 | pr_warning("%s: vdd_%s TRANXDONE timeout exceeded while trying" | 174 | pr_warning("%s: vdd_%s TRANXDONE timeout exceeded while trying" |
175 | "to clear the TRANXDONE status\n", | 175 | "to clear the TRANXDONE status\n", |
176 | __func__, voltdm->name); | 176 | __func__, voltdm->name); |
177 | 177 | ||
178 | /* Clear force bit */ | 178 | /* Clear force bit */ |
179 | voltdm->write(vpconfig, vp->vpconfig); | 179 | voltdm->write(vpconfig, vp->vpconfig); |
180 | 180 | ||
181 | return 0; | 181 | return 0; |
182 | } | 182 | } |
183 | 183 | ||
184 | /** | 184 | /** |
185 | * omap_vp_enable() - API to enable a particular VP | 185 | * omap_vp_enable() - API to enable a particular VP |
186 | * @voltdm: pointer to the VDD whose VP is to be enabled. | 186 | * @voltdm: pointer to the VDD whose VP is to be enabled. |
187 | * | 187 | * |
188 | * This API enables a particular voltage processor. Needed by the smartreflex | 188 | * This API enables a particular voltage processor. Needed by the smartreflex |
189 | * class drivers. | 189 | * class drivers. |
190 | */ | 190 | */ |
191 | void omap_vp_enable(struct voltagedomain *voltdm) | 191 | void omap_vp_enable(struct voltagedomain *voltdm) |
192 | { | 192 | { |
193 | struct omap_vp_instance *vp; | 193 | struct omap_vp_instance *vp; |
194 | u32 vpconfig, volt; | 194 | u32 vpconfig, volt; |
195 | 195 | ||
196 | if (!voltdm || IS_ERR(voltdm)) { | 196 | if (!voltdm || IS_ERR(voltdm)) { |
197 | pr_warning("%s: VDD specified does not exist!\n", __func__); | 197 | pr_warning("%s: VDD specified does not exist!\n", __func__); |
198 | return; | 198 | return; |
199 | } | 199 | } |
200 | 200 | ||
201 | vp = voltdm->vp; | 201 | vp = voltdm->vp; |
202 | if (!voltdm->read || !voltdm->write) { | 202 | if (!voltdm->read || !voltdm->write) { |
203 | pr_err("%s: No read/write API for accessing vdd_%s regs\n", | 203 | pr_err("%s: No read/write API for accessing vdd_%s regs\n", |
204 | __func__, voltdm->name); | 204 | __func__, voltdm->name); |
205 | return; | 205 | return; |
206 | } | 206 | } |
207 | 207 | ||
208 | /* If VP is already enabled, do nothing. Return */ | 208 | /* If VP is already enabled, do nothing. Return */ |
209 | if (vp->enabled) | 209 | if (vp->enabled) |
210 | return; | 210 | return; |
211 | 211 | ||
212 | volt = voltdm_get_voltage(voltdm); | 212 | volt = voltdm_get_voltage(voltdm); |
213 | if (!volt) { | 213 | if (!volt) { |
214 | pr_warning("%s: unable to find current voltage for %s\n", | 214 | pr_warning("%s: unable to find current voltage for %s\n", |
215 | __func__, voltdm->name); | 215 | __func__, voltdm->name); |
216 | return; | 216 | return; |
217 | } | 217 | } |
218 | 218 | ||
219 | vpconfig = _vp_set_init_voltage(voltdm, volt); | 219 | vpconfig = _vp_set_init_voltage(voltdm, volt); |
220 | 220 | ||
221 | /* Enable VP */ | 221 | /* Enable VP */ |
222 | vpconfig |= vp->common->vpconfig_vpenable; | 222 | vpconfig |= vp->common->vpconfig_vpenable; |
223 | voltdm->write(vpconfig, vp->vpconfig); | 223 | voltdm->write(vpconfig, vp->vpconfig); |
224 | 224 | ||
225 | vp->enabled = true; | 225 | vp->enabled = true; |
226 | } | 226 | } |
227 | 227 | ||
228 | /** | 228 | /** |
229 | * omap_vp_disable() - API to disable a particular VP | 229 | * omap_vp_disable() - API to disable a particular VP |
230 | * @voltdm: pointer to the VDD whose VP is to be disabled. | 230 | * @voltdm: pointer to the VDD whose VP is to be disabled. |
231 | * | 231 | * |
232 | * This API disables a particular voltage processor. Needed by the smartreflex | 232 | * This API disables a particular voltage processor. Needed by the smartreflex |
233 | * class drivers. | 233 | * class drivers. |
234 | */ | 234 | */ |
235 | void omap_vp_disable(struct voltagedomain *voltdm) | 235 | void omap_vp_disable(struct voltagedomain *voltdm) |
236 | { | 236 | { |
237 | struct omap_vp_instance *vp; | 237 | struct omap_vp_instance *vp; |
238 | u32 vpconfig; | 238 | u32 vpconfig; |
239 | int timeout; | 239 | int timeout; |
240 | 240 | ||
241 | if (!voltdm || IS_ERR(voltdm)) { | 241 | if (!voltdm || IS_ERR(voltdm)) { |
242 | pr_warning("%s: VDD specified does not exist!\n", __func__); | 242 | pr_warning("%s: VDD specified does not exist!\n", __func__); |
243 | return; | 243 | return; |
244 | } | 244 | } |
245 | 245 | ||
246 | vp = voltdm->vp; | 246 | vp = voltdm->vp; |
247 | if (!voltdm->read || !voltdm->write) { | 247 | if (!voltdm->read || !voltdm->write) { |
248 | pr_err("%s: No read/write API for accessing vdd_%s regs\n", | 248 | pr_err("%s: No read/write API for accessing vdd_%s regs\n", |
249 | __func__, voltdm->name); | 249 | __func__, voltdm->name); |
250 | return; | 250 | return; |
251 | } | 251 | } |
252 | 252 | ||
253 | /* If VP is already disabled, do nothing. Return */ | 253 | /* If VP is already disabled, do nothing. Return */ |
254 | if (!vp->enabled) { | 254 | if (!vp->enabled) { |
255 | pr_warning("%s: Trying to disable VP for vdd_%s when" | 255 | pr_warning("%s: Trying to disable VP for vdd_%s when" |
256 | "it is already disabled\n", __func__, voltdm->name); | 256 | "it is already disabled\n", __func__, voltdm->name); |
257 | return; | 257 | return; |
258 | } | 258 | } |
259 | 259 | ||
260 | /* Disable VP */ | 260 | /* Disable VP */ |
261 | vpconfig = voltdm->read(vp->vpconfig); | 261 | vpconfig = voltdm->read(vp->vpconfig); |
262 | vpconfig &= ~vp->common->vpconfig_vpenable; | 262 | vpconfig &= ~vp->common->vpconfig_vpenable; |
263 | voltdm->write(vpconfig, vp->vpconfig); | 263 | voltdm->write(vpconfig, vp->vpconfig); |
264 | 264 | ||
265 | /* | 265 | /* |
266 | * Wait for VP idle Typical latency is <2us. Maximum latency is ~100us | 266 | * Wait for VP idle Typical latency is <2us. Maximum latency is ~100us |
267 | */ | 267 | */ |
268 | omap_test_timeout((voltdm->read(vp->vstatus)), | 268 | omap_test_timeout((voltdm->read(vp->vstatus)), |
269 | VP_IDLE_TIMEOUT, timeout); | 269 | VP_IDLE_TIMEOUT, timeout); |
270 | 270 | ||
271 | if (timeout >= VP_IDLE_TIMEOUT) | 271 | if (timeout >= VP_IDLE_TIMEOUT) |
272 | pr_warning("%s: vdd_%s idle timedout\n", | 272 | pr_warning("%s: vdd_%s idle timedout\n", |
273 | __func__, voltdm->name); | 273 | __func__, voltdm->name); |
274 | 274 | ||
275 | vp->enabled = false; | 275 | vp->enabled = false; |
276 | 276 | ||
277 | return; | 277 | return; |
arch/arm/mach-omap2/vp.h
1 | /* | File was deleted | |
2 | * OMAP3/4 Voltage Processor (VP) structure and macro definitions | ||
3 | * | ||
4 | * Copyright (C) 2007, 2010 Texas Instruments, Inc. | ||
5 | * Rajendra Nayak <rnayak@ti.com> | ||
6 | * Lesly A M <x0080970@ti.com> | ||
7 | * Thara Gopinath <thara@ti.com> | ||
8 | * | ||
9 | * Copyright (C) 2008, 2011 Nokia Corporation | ||
10 | * Kalle Jokiniemi | ||
11 | * Paul Walmsley | ||
12 | * | ||
13 | * This program is free software; you can redistribute it and/or | ||
14 | * modify it under the terms of the GNU General Public License version | ||
15 | * 2 as published by the Free Software Foundation. | ||
16 | */ | ||
17 | #ifndef __ARCH_ARM_MACH_OMAP2_VP_H | ||
18 | #define __ARCH_ARM_MACH_OMAP2_VP_H | ||
19 | |||
20 | #include <linux/kernel.h> | ||
21 | |||
22 | struct voltagedomain; | ||
23 | |||
24 | /* | ||
25 | * Voltage Processor (VP) identifiers | ||
26 | */ | ||
27 | #define OMAP3_VP_VDD_MPU_ID 0 | ||
28 | #define OMAP3_VP_VDD_CORE_ID 1 | ||
29 | #define OMAP4_VP_VDD_CORE_ID 0 | ||
30 | #define OMAP4_VP_VDD_IVA_ID 1 | ||
31 | #define OMAP4_VP_VDD_MPU_ID 2 | ||
32 | |||
33 | /* XXX document */ | ||
34 | #define VP_IDLE_TIMEOUT 200 | ||
35 | #define VP_TRANXDONE_TIMEOUT 300 | ||
36 | |||
37 | /** | ||
38 | * struct omap_vp_ops - per-VP operations | ||
39 | * @check_txdone: check for VP transaction done | ||
40 | * @clear_txdone: clear VP transaction done status | ||
41 | */ | ||
42 | struct omap_vp_ops { | ||
43 | u32 (*check_txdone)(u8 vp_id); | ||
44 | void (*clear_txdone)(u8 vp_id); | ||
45 | }; | ||
46 | |||
47 | /** | ||
48 | * struct omap_vp_common - register data common to all VDDs | ||
49 | * @vpconfig_erroroffset_mask: ERROROFFSET bitmask in the PRM_VP*_CONFIG reg | ||
50 | * @vpconfig_errorgain_mask: ERRORGAIN bitmask in the PRM_VP*_CONFIG reg | ||
51 | * @vpconfig_initvoltage_mask: INITVOLTAGE bitmask in the PRM_VP*_CONFIG reg | ||
52 | * @vpconfig_timeouten: TIMEOUT bitmask in the PRM_VP*_CONFIG reg | ||
53 | * @vpconfig_initvdd: INITVDD bitmask in the PRM_VP*_CONFIG reg | ||
54 | * @vpconfig_forceupdate: FORCEUPDATE bitmask in the PRM_VP*_CONFIG reg | ||
55 | * @vpconfig_vpenable: VPENABLE bitmask in the PRM_VP*_CONFIG reg | ||
56 | * @vpconfig_erroroffset_shift: ERROROFFSET field shift in PRM_VP*_CONFIG reg | ||
57 | * @vpconfig_errorgain_shift: ERRORGAIN field shift in PRM_VP*_CONFIG reg | ||
58 | * @vpconfig_initvoltage_shift: INITVOLTAGE field shift in PRM_VP*_CONFIG reg | ||
59 | * @vstepmin_stepmin_shift: VSTEPMIN field shift in the PRM_VP*_VSTEPMIN reg | ||
60 | * @vstepmin_smpswaittimemin_shift: SMPSWAITTIMEMIN field shift in PRM_VP*_VSTEPMIN reg | ||
61 | * @vstepmax_stepmax_shift: VSTEPMAX field shift in the PRM_VP*_VSTEPMAX reg | ||
62 | * @vstepmax_smpswaittimemax_shift: SMPSWAITTIMEMAX field shift in PRM_VP*_VSTEPMAX reg | ||
63 | * @vlimitto_vddmin_shift: VDDMIN field shift in PRM_VP*_VLIMITTO reg | ||
64 | * @vlimitto_vddmax_shift: VDDMAX field shift in PRM_VP*_VLIMITTO reg | ||
65 | * @vlimitto_timeout_shift: TIMEOUT field shift in PRM_VP*_VLIMITTO reg | ||
66 | * @vpvoltage_mask: VPVOLTAGE field mask in PRM_VP*_VOLTAGE reg | ||
67 | */ | ||
68 | struct omap_vp_common { | ||
69 | u32 vpconfig_erroroffset_mask; | ||
70 | u32 vpconfig_errorgain_mask; | ||
71 | u32 vpconfig_initvoltage_mask; | ||
72 | u8 vpconfig_timeouten; | ||
73 | u8 vpconfig_initvdd; | ||
74 | u8 vpconfig_forceupdate; | ||
75 | u8 vpconfig_vpenable; | ||
76 | u8 vstepmin_stepmin_shift; | ||
77 | u8 vstepmin_smpswaittimemin_shift; | ||
78 | u8 vstepmax_stepmax_shift; | ||
79 | u8 vstepmax_smpswaittimemax_shift; | ||
80 | u8 vlimitto_vddmin_shift; | ||
81 | u8 vlimitto_vddmax_shift; | ||
82 | u8 vlimitto_timeout_shift; | ||
83 | u8 vpvoltage_mask; | ||
84 | |||
85 | const struct omap_vp_ops *ops; | ||
86 | }; | ||
87 | |||
88 | /** | ||
89 | * struct omap_vp_instance - VP register offsets (per-VDD) | ||
90 | * @common: pointer to struct omap_vp_common * for this SoC | ||
91 | * @vpconfig: PRM_VP*_CONFIG reg offset from PRM start | ||
92 | * @vstepmin: PRM_VP*_VSTEPMIN reg offset from PRM start | ||
93 | * @vlimitto: PRM_VP*_VLIMITTO reg offset from PRM start | ||
94 | * @vstatus: PRM_VP*_VSTATUS reg offset from PRM start | ||
95 | * @voltage: PRM_VP*_VOLTAGE reg offset from PRM start | ||
96 | * @id: Unique identifier for VP instance. | ||
97 | * @enabled: flag to keep track of whether vp is enabled or not | ||
98 | * | ||
99 | * XXX vp_common is probably not needed since it is per-SoC | ||
100 | */ | ||
101 | struct omap_vp_instance { | ||
102 | const struct omap_vp_common *common; | ||
103 | u8 vpconfig; | ||
104 | u8 vstepmin; | ||
105 | u8 vstepmax; | ||
106 | u8 vlimitto; | ||
107 | u8 vstatus; | ||
108 | u8 voltage; | ||
109 | u8 id; | ||
110 | bool enabled; | ||
111 | }; | ||
112 | |||
113 | extern struct omap_vp_instance omap3_vp_mpu; | ||
114 | extern struct omap_vp_instance omap3_vp_core; | ||
115 | |||
116 | extern struct omap_vp_instance omap4_vp_mpu; | ||
117 | extern struct omap_vp_instance omap4_vp_iva; | ||
118 | extern struct omap_vp_instance omap4_vp_core; | ||
119 | |||
120 | void omap_vp_init(struct voltagedomain *voltdm); | ||
121 | void omap_vp_enable(struct voltagedomain *voltdm); | ||
122 | void omap_vp_disable(struct voltagedomain *voltdm); | ||
123 | int omap_vp_forceupdate_scale(struct voltagedomain *voltdm, | ||
124 | unsigned long target_volt); | ||
125 | int omap_vp_update_errorgain(struct voltagedomain *voltdm, | ||
126 | unsigned long target_volt); | ||
127 | |||
128 | #endif | ||
129 | 1 | /* |
arch/arm/mach-omap2/vp3xxx_data.c
1 | /* | 1 | /* |
2 | * OMAP3 Voltage Processor (VP) data | 2 | * OMAP3 Voltage Processor (VP) data |
3 | * | 3 | * |
4 | * Copyright (C) 2007, 2010 Texas Instruments, Inc. | 4 | * Copyright (C) 2007, 2010 Texas Instruments, Inc. |
5 | * Rajendra Nayak <rnayak@ti.com> | 5 | * Rajendra Nayak <rnayak@ti.com> |
6 | * Lesly A M <x0080970@ti.com> | 6 | * Lesly A M <x0080970@ti.com> |
7 | * Thara Gopinath <thara@ti.com> | 7 | * Thara Gopinath <thara@ti.com> |
8 | * | 8 | * |
9 | * Copyright (C) 2008, 2011 Nokia Corporation | 9 | * Copyright (C) 2008, 2011 Nokia Corporation |
10 | * Kalle Jokiniemi | 10 | * Kalle Jokiniemi |
11 | * Paul Walmsley | 11 | * Paul Walmsley |
12 | * | 12 | * |
13 | * This program is free software; you can redistribute it and/or modify | 13 | * This program is free software; you can redistribute it and/or modify |
14 | * it under the terms of the GNU General Public License version 2 as | 14 | * it under the terms of the GNU General Public License version 2 as |
15 | * published by the Free Software Foundation. | 15 | * published by the Free Software Foundation. |
16 | */ | 16 | */ |
17 | 17 | ||
18 | #include <linux/io.h> | 18 | #include <linux/io.h> |
19 | #include <linux/err.h> | 19 | #include <linux/err.h> |
20 | #include <linux/init.h> | 20 | #include <linux/init.h> |
21 | 21 | ||
22 | #include <plat/common.h> | 22 | #include <plat/common.h> |
23 | #include <plat/voltage.h> | ||
24 | #include <plat/vp.h> | ||
23 | 25 | ||
24 | #include "prm-regbits-34xx.h" | 26 | #include "prm-regbits-34xx.h" |
25 | #include "voltage.h" | ||
26 | 27 | ||
27 | #include "vp.h" | ||
28 | #include "prm2xxx_3xxx.h" | 28 | #include "prm2xxx_3xxx.h" |
29 | 29 | ||
30 | static const struct omap_vp_ops omap3_vp_ops = { | 30 | static const struct omap_vp_ops omap3_vp_ops = { |
31 | .check_txdone = omap3_prm_vp_check_txdone, | 31 | .check_txdone = omap3_prm_vp_check_txdone, |
32 | .clear_txdone = omap3_prm_vp_clear_txdone, | 32 | .clear_txdone = omap3_prm_vp_clear_txdone, |
33 | }; | 33 | }; |
34 | 34 | ||
35 | /* | 35 | /* |
36 | * VP data common to 34xx/36xx chips | 36 | * VP data common to 34xx/36xx chips |
37 | * XXX This stuff presumably belongs in the vp3xxx.c or vp.c file. | 37 | * XXX This stuff presumably belongs in the vp3xxx.c or vp.c file. |
38 | */ | 38 | */ |
39 | static const struct omap_vp_common omap3_vp_common = { | 39 | static const struct omap_vp_common omap3_vp_common = { |
40 | .vpconfig_erroroffset_mask = OMAP3430_ERROROFFSET_MASK, | 40 | .vpconfig_erroroffset_mask = OMAP3430_ERROROFFSET_MASK, |
41 | .vpconfig_errorgain_mask = OMAP3430_ERRORGAIN_MASK, | 41 | .vpconfig_errorgain_mask = OMAP3430_ERRORGAIN_MASK, |
42 | .vpconfig_initvoltage_mask = OMAP3430_INITVOLTAGE_MASK, | 42 | .vpconfig_initvoltage_mask = OMAP3430_INITVOLTAGE_MASK, |
43 | .vpconfig_timeouten = OMAP3430_TIMEOUTEN_MASK, | 43 | .vpconfig_timeouten = OMAP3430_TIMEOUTEN_MASK, |
44 | .vpconfig_initvdd = OMAP3430_INITVDD_MASK, | 44 | .vpconfig_initvdd = OMAP3430_INITVDD_MASK, |
45 | .vpconfig_forceupdate = OMAP3430_FORCEUPDATE_MASK, | 45 | .vpconfig_forceupdate = OMAP3430_FORCEUPDATE_MASK, |
46 | .vpconfig_vpenable = OMAP3430_VPENABLE_MASK, | 46 | .vpconfig_vpenable = OMAP3430_VPENABLE_MASK, |
47 | .vstepmin_smpswaittimemin_shift = OMAP3430_SMPSWAITTIMEMIN_SHIFT, | 47 | .vstepmin_smpswaittimemin_shift = OMAP3430_SMPSWAITTIMEMIN_SHIFT, |
48 | .vstepmax_smpswaittimemax_shift = OMAP3430_SMPSWAITTIMEMAX_SHIFT, | 48 | .vstepmax_smpswaittimemax_shift = OMAP3430_SMPSWAITTIMEMAX_SHIFT, |
49 | .vstepmin_stepmin_shift = OMAP3430_VSTEPMIN_SHIFT, | 49 | .vstepmin_stepmin_shift = OMAP3430_VSTEPMIN_SHIFT, |
50 | .vstepmax_stepmax_shift = OMAP3430_VSTEPMAX_SHIFT, | 50 | .vstepmax_stepmax_shift = OMAP3430_VSTEPMAX_SHIFT, |
51 | .vlimitto_vddmin_shift = OMAP3430_VDDMIN_SHIFT, | 51 | .vlimitto_vddmin_shift = OMAP3430_VDDMIN_SHIFT, |
52 | .vlimitto_vddmax_shift = OMAP3430_VDDMAX_SHIFT, | 52 | .vlimitto_vddmax_shift = OMAP3430_VDDMAX_SHIFT, |
53 | .vlimitto_timeout_shift = OMAP3430_TIMEOUT_SHIFT, | 53 | .vlimitto_timeout_shift = OMAP3430_TIMEOUT_SHIFT, |
54 | .vpvoltage_mask = OMAP3430_VPVOLTAGE_MASK, | 54 | .vpvoltage_mask = OMAP3430_VPVOLTAGE_MASK, |
55 | 55 | ||
56 | .ops = &omap3_vp_ops, | 56 | .ops = &omap3_vp_ops, |
57 | }; | 57 | }; |
58 | 58 | ||
59 | struct omap_vp_instance omap3_vp_mpu = { | 59 | struct omap_vp_instance omap3_vp_mpu = { |
60 | .id = OMAP3_VP_VDD_MPU_ID, | 60 | .id = OMAP3_VP_VDD_MPU_ID, |
61 | .common = &omap3_vp_common, | 61 | .common = &omap3_vp_common, |
62 | .vpconfig = OMAP3_PRM_VP1_CONFIG_OFFSET, | 62 | .vpconfig = OMAP3_PRM_VP1_CONFIG_OFFSET, |
63 | .vstepmin = OMAP3_PRM_VP1_VSTEPMIN_OFFSET, | 63 | .vstepmin = OMAP3_PRM_VP1_VSTEPMIN_OFFSET, |
64 | .vstepmax = OMAP3_PRM_VP1_VSTEPMAX_OFFSET, | 64 | .vstepmax = OMAP3_PRM_VP1_VSTEPMAX_OFFSET, |
65 | .vlimitto = OMAP3_PRM_VP1_VLIMITTO_OFFSET, | 65 | .vlimitto = OMAP3_PRM_VP1_VLIMITTO_OFFSET, |
66 | .vstatus = OMAP3_PRM_VP1_STATUS_OFFSET, | 66 | .vstatus = OMAP3_PRM_VP1_STATUS_OFFSET, |
67 | .voltage = OMAP3_PRM_VP1_VOLTAGE_OFFSET, | 67 | .voltage = OMAP3_PRM_VP1_VOLTAGE_OFFSET, |
68 | }; | 68 | }; |
69 | 69 | ||
70 | struct omap_vp_instance omap3_vp_core = { | 70 | struct omap_vp_instance omap3_vp_core = { |
71 | .id = OMAP3_VP_VDD_CORE_ID, | 71 | .id = OMAP3_VP_VDD_CORE_ID, |
72 | .common = &omap3_vp_common, | 72 | .common = &omap3_vp_common, |
73 | .vpconfig = OMAP3_PRM_VP2_CONFIG_OFFSET, | 73 | .vpconfig = OMAP3_PRM_VP2_CONFIG_OFFSET, |
74 | .vstepmin = OMAP3_PRM_VP2_VSTEPMIN_OFFSET, | 74 | .vstepmin = OMAP3_PRM_VP2_VSTEPMIN_OFFSET, |
75 | .vstepmax = OMAP3_PRM_VP2_VSTEPMAX_OFFSET, | 75 | .vstepmax = OMAP3_PRM_VP2_VSTEPMAX_OFFSET, |
76 | .vlimitto = OMAP3_PRM_VP2_VLIMITTO_OFFSET, | 76 | .vlimitto = OMAP3_PRM_VP2_VLIMITTO_OFFSET, |
77 | .vstatus = OMAP3_PRM_VP2_STATUS_OFFSET, | 77 | .vstatus = OMAP3_PRM_VP2_STATUS_OFFSET, |
78 | .voltage = OMAP3_PRM_VP2_VOLTAGE_OFFSET, | 78 | .voltage = OMAP3_PRM_VP2_VOLTAGE_OFFSET, |
arch/arm/mach-omap2/vp44xx_data.c
1 | /* | 1 | /* |
2 | * OMAP3 Voltage Processor (VP) data | 2 | * OMAP3 Voltage Processor (VP) data |
3 | * | 3 | * |
4 | * Copyright (C) 2007, 2010 Texas Instruments, Inc. | 4 | * Copyright (C) 2007, 2010 Texas Instruments, Inc. |
5 | * Rajendra Nayak <rnayak@ti.com> | 5 | * Rajendra Nayak <rnayak@ti.com> |
6 | * Lesly A M <x0080970@ti.com> | 6 | * Lesly A M <x0080970@ti.com> |
7 | * Thara Gopinath <thara@ti.com> | 7 | * Thara Gopinath <thara@ti.com> |
8 | * | 8 | * |
9 | * Copyright (C) 2008, 2011 Nokia Corporation | 9 | * Copyright (C) 2008, 2011 Nokia Corporation |
10 | * Kalle Jokiniemi | 10 | * Kalle Jokiniemi |
11 | * Paul Walmsley | 11 | * Paul Walmsley |
12 | * | 12 | * |
13 | * This program is free software; you can redistribute it and/or modify | 13 | * This program is free software; you can redistribute it and/or modify |
14 | * it under the terms of the GNU General Public License version 2 as | 14 | * it under the terms of the GNU General Public License version 2 as |
15 | * published by the Free Software Foundation. | 15 | * published by the Free Software Foundation. |
16 | */ | 16 | */ |
17 | 17 | ||
18 | #include <linux/io.h> | 18 | #include <linux/io.h> |
19 | #include <linux/err.h> | 19 | #include <linux/err.h> |
20 | #include <linux/init.h> | 20 | #include <linux/init.h> |
21 | 21 | ||
22 | #include <plat/common.h> | 22 | #include <plat/common.h> |
23 | #include <plat/voltage.h> | ||
24 | #include <plat/vp.h> | ||
23 | 25 | ||
24 | #include "prm44xx.h" | 26 | #include "prm44xx.h" |
25 | #include "prm-regbits-44xx.h" | 27 | #include "prm-regbits-44xx.h" |
26 | #include "voltage.h" | ||
27 | |||
28 | #include "vp.h" | ||
29 | 28 | ||
30 | static const struct omap_vp_ops omap4_vp_ops = { | 29 | static const struct omap_vp_ops omap4_vp_ops = { |
31 | .check_txdone = omap4_prm_vp_check_txdone, | 30 | .check_txdone = omap4_prm_vp_check_txdone, |
32 | .clear_txdone = omap4_prm_vp_clear_txdone, | 31 | .clear_txdone = omap4_prm_vp_clear_txdone, |
33 | }; | 32 | }; |
34 | 33 | ||
35 | /* | 34 | /* |
36 | * VP data common to 44xx chips | 35 | * VP data common to 44xx chips |
37 | * XXX This stuff presumably belongs in the vp44xx.c or vp.c file. | 36 | * XXX This stuff presumably belongs in the vp44xx.c or vp.c file. |
38 | */ | 37 | */ |
39 | static const struct omap_vp_common omap4_vp_common = { | 38 | static const struct omap_vp_common omap4_vp_common = { |
40 | .vpconfig_erroroffset_mask = OMAP4430_ERROROFFSET_MASK, | 39 | .vpconfig_erroroffset_mask = OMAP4430_ERROROFFSET_MASK, |
41 | .vpconfig_errorgain_mask = OMAP4430_ERRORGAIN_MASK, | 40 | .vpconfig_errorgain_mask = OMAP4430_ERRORGAIN_MASK, |
42 | .vpconfig_initvoltage_mask = OMAP4430_INITVOLTAGE_MASK, | 41 | .vpconfig_initvoltage_mask = OMAP4430_INITVOLTAGE_MASK, |
43 | .vpconfig_timeouten = OMAP4430_TIMEOUTEN_MASK, | 42 | .vpconfig_timeouten = OMAP4430_TIMEOUTEN_MASK, |
44 | .vpconfig_initvdd = OMAP4430_INITVDD_MASK, | 43 | .vpconfig_initvdd = OMAP4430_INITVDD_MASK, |
45 | .vpconfig_forceupdate = OMAP4430_FORCEUPDATE_MASK, | 44 | .vpconfig_forceupdate = OMAP4430_FORCEUPDATE_MASK, |
46 | .vpconfig_vpenable = OMAP4430_VPENABLE_MASK, | 45 | .vpconfig_vpenable = OMAP4430_VPENABLE_MASK, |
47 | .vstepmin_smpswaittimemin_shift = OMAP4430_SMPSWAITTIMEMIN_SHIFT, | 46 | .vstepmin_smpswaittimemin_shift = OMAP4430_SMPSWAITTIMEMIN_SHIFT, |
48 | .vstepmax_smpswaittimemax_shift = OMAP4430_SMPSWAITTIMEMAX_SHIFT, | 47 | .vstepmax_smpswaittimemax_shift = OMAP4430_SMPSWAITTIMEMAX_SHIFT, |
49 | .vstepmin_stepmin_shift = OMAP4430_VSTEPMIN_SHIFT, | 48 | .vstepmin_stepmin_shift = OMAP4430_VSTEPMIN_SHIFT, |
50 | .vstepmax_stepmax_shift = OMAP4430_VSTEPMAX_SHIFT, | 49 | .vstepmax_stepmax_shift = OMAP4430_VSTEPMAX_SHIFT, |
51 | .vlimitto_vddmin_shift = OMAP4430_VDDMIN_SHIFT, | 50 | .vlimitto_vddmin_shift = OMAP4430_VDDMIN_SHIFT, |
52 | .vlimitto_vddmax_shift = OMAP4430_VDDMAX_SHIFT, | 51 | .vlimitto_vddmax_shift = OMAP4430_VDDMAX_SHIFT, |
53 | .vlimitto_timeout_shift = OMAP4430_TIMEOUT_SHIFT, | 52 | .vlimitto_timeout_shift = OMAP4430_TIMEOUT_SHIFT, |
54 | .vpvoltage_mask = OMAP4430_VPVOLTAGE_MASK, | 53 | .vpvoltage_mask = OMAP4430_VPVOLTAGE_MASK, |
55 | .ops = &omap4_vp_ops, | 54 | .ops = &omap4_vp_ops, |
56 | }; | 55 | }; |
57 | 56 | ||
58 | struct omap_vp_instance omap4_vp_mpu = { | 57 | struct omap_vp_instance omap4_vp_mpu = { |
59 | .id = OMAP4_VP_VDD_MPU_ID, | 58 | .id = OMAP4_VP_VDD_MPU_ID, |
60 | .common = &omap4_vp_common, | 59 | .common = &omap4_vp_common, |
61 | .vpconfig = OMAP4_PRM_VP_MPU_CONFIG_OFFSET, | 60 | .vpconfig = OMAP4_PRM_VP_MPU_CONFIG_OFFSET, |
62 | .vstepmin = OMAP4_PRM_VP_MPU_VSTEPMIN_OFFSET, | 61 | .vstepmin = OMAP4_PRM_VP_MPU_VSTEPMIN_OFFSET, |
63 | .vstepmax = OMAP4_PRM_VP_MPU_VSTEPMAX_OFFSET, | 62 | .vstepmax = OMAP4_PRM_VP_MPU_VSTEPMAX_OFFSET, |
64 | .vlimitto = OMAP4_PRM_VP_MPU_VLIMITTO_OFFSET, | 63 | .vlimitto = OMAP4_PRM_VP_MPU_VLIMITTO_OFFSET, |
65 | .vstatus = OMAP4_PRM_VP_MPU_STATUS_OFFSET, | 64 | .vstatus = OMAP4_PRM_VP_MPU_STATUS_OFFSET, |
66 | .voltage = OMAP4_PRM_VP_MPU_VOLTAGE_OFFSET, | 65 | .voltage = OMAP4_PRM_VP_MPU_VOLTAGE_OFFSET, |
67 | }; | 66 | }; |
68 | 67 | ||
69 | struct omap_vp_instance omap4_vp_iva = { | 68 | struct omap_vp_instance omap4_vp_iva = { |
70 | .id = OMAP4_VP_VDD_IVA_ID, | 69 | .id = OMAP4_VP_VDD_IVA_ID, |
71 | .common = &omap4_vp_common, | 70 | .common = &omap4_vp_common, |
72 | .vpconfig = OMAP4_PRM_VP_IVA_CONFIG_OFFSET, | 71 | .vpconfig = OMAP4_PRM_VP_IVA_CONFIG_OFFSET, |
73 | .vstepmin = OMAP4_PRM_VP_IVA_VSTEPMIN_OFFSET, | 72 | .vstepmin = OMAP4_PRM_VP_IVA_VSTEPMIN_OFFSET, |
74 | .vstepmax = OMAP4_PRM_VP_IVA_VSTEPMAX_OFFSET, | 73 | .vstepmax = OMAP4_PRM_VP_IVA_VSTEPMAX_OFFSET, |
75 | .vlimitto = OMAP4_PRM_VP_IVA_VLIMITTO_OFFSET, | 74 | .vlimitto = OMAP4_PRM_VP_IVA_VLIMITTO_OFFSET, |
76 | .vstatus = OMAP4_PRM_VP_IVA_STATUS_OFFSET, | 75 | .vstatus = OMAP4_PRM_VP_IVA_STATUS_OFFSET, |
77 | .voltage = OMAP4_PRM_VP_IVA_VOLTAGE_OFFSET, | 76 | .voltage = OMAP4_PRM_VP_IVA_VOLTAGE_OFFSET, |
78 | }; | 77 | }; |
79 | 78 | ||
80 | struct omap_vp_instance omap4_vp_core = { | 79 | struct omap_vp_instance omap4_vp_core = { |
81 | .id = OMAP4_VP_VDD_CORE_ID, | 80 | .id = OMAP4_VP_VDD_CORE_ID, |
82 | .common = &omap4_vp_common, | 81 | .common = &omap4_vp_common, |
83 | .vpconfig = OMAP4_PRM_VP_CORE_CONFIG_OFFSET, | 82 | .vpconfig = OMAP4_PRM_VP_CORE_CONFIG_OFFSET, |
84 | .vstepmin = OMAP4_PRM_VP_CORE_VSTEPMIN_OFFSET, | 83 | .vstepmin = OMAP4_PRM_VP_CORE_VSTEPMIN_OFFSET, |
85 | .vstepmax = OMAP4_PRM_VP_CORE_VSTEPMAX_OFFSET, | 84 | .vstepmax = OMAP4_PRM_VP_CORE_VSTEPMAX_OFFSET, |
86 | .vlimitto = OMAP4_PRM_VP_CORE_VLIMITTO_OFFSET, | 85 | .vlimitto = OMAP4_PRM_VP_CORE_VLIMITTO_OFFSET, |
87 | .vstatus = OMAP4_PRM_VP_CORE_STATUS_OFFSET, | 86 | .vstatus = OMAP4_PRM_VP_CORE_STATUS_OFFSET, |
88 | .voltage = OMAP4_PRM_VP_CORE_VOLTAGE_OFFSET, | 87 | .voltage = OMAP4_PRM_VP_CORE_VOLTAGE_OFFSET, |
arch/arm/plat-omap/include/plat/dvfs.h
File was created | 1 | /* | |
2 | * OMAP3/OMAP4 DVFS Management Routines | ||
3 | * | ||
4 | * Author: Vishwanath BS <vishwanath.bs@ti.com> | ||
5 | * | ||
6 | * Copyright (C) 2011 Texas Instruments, Inc. | ||
7 | * Vishwanath BS <vishwanath.bs@ti.com> | ||
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 | #ifndef __ARCH_ARM_MACH_OMAP2_DVFS_H | ||
15 | #define __ARCH_ARM_MACH_OMAP2_DVFS_H | ||
16 | #include <plat/omap_hwmod.h> | ||
17 | #include <plat/voltage.h> | ||
18 | |||
19 | #ifdef CONFIG_PM | ||
20 | int omap_dvfs_register_device(struct device *dev, char *voltdm_name, | ||
21 | char *clk_name); | ||
22 | int omap_device_scale(struct device *req_dev, struct device *target_dev, | ||
23 | unsigned long rate); | ||
24 | #else | ||
25 | static inline int omap_dvfs_register_device(struct omap_hwmod *oh, | ||
26 | struct device *dev) | ||
27 | static inline int omap_dvfs_register_device(struct device *dev, | ||
28 | char *voltdm_name, char *clk_name) | ||
29 | { | ||
30 | return -EINVAL; | ||
31 | } | ||
32 | static inline int omap_device_scale(struct device *req_dev, | ||
33 | struct device *target_dev, unsigned long rate) | ||
34 | { | ||
35 | return -EINVAL; | ||
36 | } | ||
37 | #endif | ||
38 | #endif | ||
39 |
arch/arm/plat-omap/include/plat/vc.h
File was created | 1 | /* | |
2 | * OMAP3/4 Voltage Controller (VC) structure and macro definitions | ||
3 | * | ||
4 | * Copyright (C) 2007, 2010 Texas Instruments, Inc. | ||
5 | * Rajendra Nayak <rnayak@ti.com> | ||
6 | * Lesly A M <x0080970@ti.com> | ||
7 | * Thara Gopinath <thara@ti.com> | ||
8 | * | ||
9 | * Copyright (C) 2008, 2011 Nokia Corporation | ||
10 | * Kalle Jokiniemi | ||
11 | * Paul Walmsley | ||
12 | * | ||
13 | * This program is free software; you can redistribute it and/or | ||
14 | * modify it under the terms of the GNU General Public License version | ||
15 | * 2 as published by the Free Software Foundation. | ||
16 | */ | ||
17 | #ifndef __ARCH_ARM_MACH_OMAP2_VC_H | ||
18 | #define __ARCH_ARM_MACH_OMAP2_VC_H | ||
19 | |||
20 | #include <linux/kernel.h> | ||
21 | |||
22 | struct voltagedomain; | ||
23 | |||
24 | /** | ||
25 | * struct omap_vc_common - per-VC register/bitfield data | ||
26 | * @cmd_on_mask: ON bitmask in PRM_VC_CMD_VAL* register | ||
27 | * @valid: VALID bitmask in PRM_VC_BYPASS_VAL register | ||
28 | * @bypass_val_reg: Offset of PRM_VC_BYPASS_VAL reg from PRM start | ||
29 | * @data_shift: DATA field shift in PRM_VC_BYPASS_VAL register | ||
30 | * @slaveaddr_shift: SLAVEADDR field shift in PRM_VC_BYPASS_VAL register | ||
31 | * @regaddr_shift: REGADDR field shift in PRM_VC_BYPASS_VAL register | ||
32 | * @cmd_on_shift: ON field shift in PRM_VC_CMD_VAL_* register | ||
33 | * @cmd_onlp_shift: ONLP field shift in PRM_VC_CMD_VAL_* register | ||
34 | * @cmd_ret_shift: RET field shift in PRM_VC_CMD_VAL_* register | ||
35 | * @cmd_off_shift: OFF field shift in PRM_VC_CMD_VAL_* register | ||
36 | * @i2c_cfg_reg: I2C configuration register offset | ||
37 | * @i2c_cfg_hsen_mask: high-speed mode bit field mask in I2C config register | ||
38 | * @i2c_mcode_mask: MCODE field mask for I2C config register | ||
39 | * | ||
40 | * XXX One of cmd_on_mask and cmd_on_shift are not needed | ||
41 | * XXX VALID should probably be a shift, not a mask | ||
42 | */ | ||
43 | struct omap_vc_common { | ||
44 | u32 cmd_on_mask; | ||
45 | u32 valid; | ||
46 | u8 bypass_val_reg; | ||
47 | u8 data_shift; | ||
48 | u8 slaveaddr_shift; | ||
49 | u8 regaddr_shift; | ||
50 | u8 cmd_on_shift; | ||
51 | u8 cmd_onlp_shift; | ||
52 | u8 cmd_ret_shift; | ||
53 | u8 cmd_off_shift; | ||
54 | u8 i2c_cfg_reg; | ||
55 | u8 i2c_cfg_hsen_mask; | ||
56 | u8 i2c_mcode_mask; | ||
57 | }; | ||
58 | |||
59 | /* omap_vc_channel.flags values */ | ||
60 | #define OMAP_VC_CHANNEL_DEFAULT BIT(0) | ||
61 | #define OMAP_VC_CHANNEL_CFG_MUTANT BIT(1) | ||
62 | |||
63 | /** | ||
64 | * struct omap_vc_channel - VC per-instance data | ||
65 | * @i2c_slave_addr: I2C slave address of PMIC for this VC channel | ||
66 | * @volt_reg_addr: voltage configuration register address | ||
67 | * @cmd_reg_addr: command configuration register address | ||
68 | * @setup_time: setup time (in sys_clk cycles) of regulator for this channel | ||
69 | * @cfg_channel: current value of VC channel configuration register | ||
70 | * @i2c_high_speed: whether or not to use I2C high-speed mode | ||
71 | * | ||
72 | * @common: pointer to VC common data for this platform | ||
73 | * @smps_sa_mask: i2c slave address bitmask in the PRM_VC_SMPS_SA register | ||
74 | * @smps_volra_mask: VOLRA* bitmask in the PRM_VC_VOL_RA register | ||
75 | * @smps_cmdra_mask: CMDRA* bitmask in the PRM_VC_CMD_RA register | ||
76 | * @cmdval_reg: register for on/ret/off voltage level values for this channel | ||
77 | * @smps_sa_reg: Offset of PRM_VC_SMPS_SA reg from PRM start | ||
78 | * @smps_volra_reg: Offset of PRM_VC_SMPS_VOL_RA reg from PRM start | ||
79 | * @smps_cmdra_reg: Offset of PRM_VC_SMPS_CMD_RA reg from PRM start | ||
80 | * @cfg_channel_reg: VC channel configuration register | ||
81 | * @cfg_channel_sa_shift: bit shift for slave address cfg_channel register | ||
82 | * @flags: VC channel-specific flags (optional) | ||
83 | */ | ||
84 | struct omap_vc_channel { | ||
85 | /* channel state */ | ||
86 | u16 i2c_slave_addr; | ||
87 | u16 volt_reg_addr; | ||
88 | u16 cmd_reg_addr; | ||
89 | u16 setup_time; | ||
90 | u8 cfg_channel; | ||
91 | bool i2c_high_speed; | ||
92 | |||
93 | /* register access data */ | ||
94 | const struct omap_vc_common *common; | ||
95 | u32 smps_sa_mask; | ||
96 | u32 smps_volra_mask; | ||
97 | u32 smps_cmdra_mask; | ||
98 | u8 cmdval_reg; | ||
99 | u8 smps_sa_reg; | ||
100 | u8 smps_volra_reg; | ||
101 | u8 smps_cmdra_reg; | ||
102 | u8 cfg_channel_reg; | ||
103 | u8 cfg_channel_sa_shift; | ||
104 | u8 flags; | ||
105 | }; | ||
106 | |||
107 | extern struct omap_vc_channel omap3_vc_mpu; | ||
108 | extern struct omap_vc_channel omap3_vc_core; | ||
109 | |||
110 | extern struct omap_vc_channel omap4_vc_mpu; | ||
111 | extern struct omap_vc_channel omap4_vc_iva; | ||
112 | extern struct omap_vc_channel omap4_vc_core; | ||
113 | |||
114 | void omap_vc_init_channel(struct voltagedomain *voltdm); | ||
115 | int omap_vc_pre_scale(struct voltagedomain *voltdm, | ||
116 | unsigned long target_volt, | ||
117 | u8 *target_vsel, u8 *current_vsel); | ||
118 | void omap_vc_post_scale(struct voltagedomain *voltdm, | ||
119 | unsigned long target_volt, | ||
120 | u8 target_vsel, u8 current_vsel); | ||
121 | int omap_vc_bypass_scale(struct voltagedomain *voltdm, | ||
122 | unsigned long target_volt); | ||
123 | |||
124 | #endif | ||
125 |
arch/arm/plat-omap/include/plat/voltage.h
1 | /* | 1 | /* |
2 | * OMAP Voltage Management Routines | 2 | * OMAP Voltage Management Routines |
3 | * | 3 | * |
4 | * Copyright (C) 2011, Texas Instruments, Inc. | 4 | * Author: Thara Gopinath <thara@ti.com> |
5 | * | 5 | * |
6 | * Copyright (C) 2009 Texas Instruments, Inc. | ||
7 | * Thara Gopinath <thara@ti.com> | ||
8 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | 9 | * This program is free software; you can redistribute it and/or modify |
7 | * it under the terms of the GNU General Public License version 2 as | 10 | * it under the terms of the GNU General Public License version 2 as |
8 | * published by the Free Software Foundation. | 11 | * published by the Free Software Foundation. |
9 | */ | 12 | */ |
10 | 13 | ||
11 | #ifndef __ARCH_ARM_OMAP_VOLTAGE_H | 14 | #ifndef __ARCH_ARM_OMAP_VOLTAGE_H |
12 | #define __ARCH_ARM_OMAP_VOLTAGE_H | 15 | #define __ARCH_ARM_OMAP_VOLTAGE_H |
13 | 16 | ||
14 | struct voltagedomain; | 17 | #include <linux/err.h> |
15 | 18 | ||
19 | #include <plat/vc.h> | ||
20 | #include <plat/vp.h> | ||
21 | |||
22 | struct powerdomain; | ||
23 | |||
24 | /* XXX document */ | ||
25 | #define VOLTSCALE_VPFORCEUPDATE 1 | ||
26 | #define VOLTSCALE_VCBYPASS 2 | ||
27 | |||
28 | /* | ||
29 | * OMAP3 GENERIC setup times. Revisit to see if these needs to be | ||
30 | * passed from board or PMIC file | ||
31 | */ | ||
32 | #define OMAP3_CLKSETUP 0xff | ||
33 | #define OMAP3_VOLTOFFSET 0xff | ||
34 | #define OMAP3_VOLTSETUP2 0xff | ||
35 | |||
36 | struct omap_vdd_info; | ||
37 | |||
38 | /** | ||
39 | * struct omap_vfsm_instance - per-voltage manager FSM register/bitfield | ||
40 | * data | ||
41 | * @voltsetup_mask: SETUP_TIME* bitmask in the PRM_VOLTSETUP* register | ||
42 | * @voltsetup_reg: register offset of PRM_VOLTSETUP from PRM base | ||
43 | * | ||
44 | * XXX What about VOLTOFFSET/VOLTCTRL? | ||
45 | */ | ||
46 | struct omap_vfsm_instance { | ||
47 | u32 voltsetup_mask; | ||
48 | u8 voltsetup_reg; | ||
49 | }; | ||
50 | |||
51 | /** | ||
52 | * struct voltagedomain - omap voltage domain global structure. | ||
53 | * @name: Name of the voltage domain which can be used as a unique identifier. | ||
54 | * @scalable: Whether or not this voltage domain is scalable | ||
55 | * @node: list_head linking all voltage domains | ||
56 | * @pwrdm_list: list_head linking all powerdomains in this voltagedomain | ||
57 | * @vc: pointer to VC channel associated with this voltagedomain | ||
58 | * @vp: pointer to VP associated with this voltagedomain | ||
59 | * @read: read a VC/VP register | ||
60 | * @write: write a VC/VP register | ||
61 | * @read: read-modify-write a VC/VP register | ||
62 | * @sys_clk: system clock name/frequency, used for various timing calculations | ||
63 | * @scale: function used to scale the voltage of the voltagedomain | ||
64 | * @nominal_volt: current nominal voltage for this voltage domain | ||
65 | * @volt_data: voltage table having the distinct voltages supported | ||
66 | * by the domain and other associated per voltage data. | ||
67 | */ | ||
68 | struct voltagedomain { | ||
69 | char *name; | ||
70 | bool scalable; | ||
71 | struct list_head node; | ||
72 | struct list_head pwrdm_list; | ||
73 | struct omap_vc_channel *vc; | ||
74 | const struct omap_vfsm_instance *vfsm; | ||
75 | struct omap_vp_instance *vp; | ||
76 | struct omap_voltdm_pmic *pmic; | ||
77 | |||
78 | /* VC/VP register access functions: SoC specific */ | ||
79 | u32 (*read) (u8 offset); | ||
80 | void (*write) (u32 val, u8 offset); | ||
81 | u32 (*rmw)(u32 mask, u32 bits, u8 offset); | ||
82 | |||
83 | union { | ||
84 | const char *name; | ||
85 | u32 rate; | ||
86 | } sys_clk; | ||
87 | |||
88 | int (*scale) (struct voltagedomain *voltdm, | ||
89 | unsigned long target_volt); | ||
90 | |||
91 | u32 nominal_volt; | ||
92 | struct omap_volt_data *volt_data; | ||
93 | struct omap_vdd_info *vdd; | ||
94 | struct dentry *debug_dir; | ||
95 | }; | ||
96 | |||
97 | /** | ||
98 | * struct omap_volt_data - Omap voltage specific data. | ||
99 | * @voltage_nominal: The possible voltage value in uV | ||
100 | * @sr_efuse_offs: The offset of the efuse register(from system | ||
101 | * control module base address) from where to read | ||
102 | * the n-target value for the smartreflex module. | ||
103 | * @sr_errminlimit: Error min limit value for smartreflex. This value | ||
104 | * differs at differnet opp and thus is linked | ||
105 | * with voltage. | ||
106 | * @vp_errorgain: Error gain value for the voltage processor. This | ||
107 | * field also differs according to the voltage/opp. | ||
108 | */ | ||
109 | struct omap_volt_data { | ||
110 | u32 volt_nominal; | ||
111 | u32 sr_efuse_offs; | ||
112 | u8 sr_errminlimit; | ||
113 | u8 vp_errgain; | ||
114 | }; | ||
115 | |||
116 | /** | ||
117 | * struct omap_voltdm_pmic - PMIC specific data required by voltage driver. | ||
118 | * @slew_rate: PMIC slew rate (in uv/us) | ||
119 | * @step_size: PMIC voltage step size (in uv) | ||
120 | * @i2c_slave_addr: I2C slave address of PMIC | ||
121 | * @volt_reg_addr: voltage configuration register address | ||
122 | * @cmd_reg_addr: command (on, on-LP, ret, off) configuration register address | ||
123 | * @i2c_high_speed: whether VC uses I2C high-speed mode to PMIC | ||
124 | * @i2c_mcode: master code value for I2C high-speed preamble transmission | ||
125 | * @vsel_to_uv: PMIC API to convert vsel value to actual voltage in uV. | ||
126 | * @uv_to_vsel: PMIC API to convert voltage in uV to vsel value. | ||
127 | */ | ||
128 | struct omap_voltdm_pmic { | ||
129 | int slew_rate; | ||
130 | int step_size; | ||
131 | u32 on_volt; | ||
132 | u32 onlp_volt; | ||
133 | u32 ret_volt; | ||
134 | u32 off_volt; | ||
135 | u16 volt_setup_time; | ||
136 | u16 i2c_slave_addr; | ||
137 | u16 volt_reg_addr; | ||
138 | u16 cmd_reg_addr; | ||
139 | u8 vp_erroroffset; | ||
140 | u8 vp_vstepmin; | ||
141 | u8 vp_vstepmax; | ||
142 | u8 vp_vddmin; | ||
143 | u8 vp_vddmax; | ||
144 | u8 vp_timeout_us; | ||
145 | bool i2c_high_speed; | ||
146 | u8 i2c_mcode; | ||
147 | unsigned long (*vsel_to_uv) (const u8 vsel); | ||
148 | u8 (*uv_to_vsel) (unsigned long uV); | ||
149 | }; | ||
150 | |||
151 | /** | ||
152 | * struct omap_vdd_dep_volt - Map table for voltage dependencies | ||
153 | * @main_vdd_volt : The main vdd voltage | ||
154 | * @dep_vdd_volt : The voltage at which the dependent vdd should be | ||
155 | * when the main vdd is at <main_vdd_volt> voltage | ||
156 | * | ||
157 | * Table containing the parent vdd voltage and the dependent vdd voltage | ||
158 | * corresponding to it. | ||
159 | */ | ||
160 | struct omap_vdd_dep_volt { | ||
161 | u32 main_vdd_volt; | ||
162 | u32 dep_vdd_volt; | ||
163 | }; | ||
164 | |||
165 | /** | ||
166 | * struct omap_vdd_dep_info - Dependent vdd info | ||
167 | * @name : Dependent vdd name | ||
168 | * @_dep_voltdm : internal structure meant to prevent multiple lookups | ||
169 | * @dep_table : Table containing the dependent vdd voltage | ||
170 | * corresponding to every main vdd voltage. | ||
171 | * @nr_dep_entries : number of dependency voltage entries | ||
172 | */ | ||
173 | struct omap_vdd_dep_info { | ||
174 | char *name; | ||
175 | struct voltagedomain *_dep_voltdm; | ||
176 | struct omap_vdd_dep_volt *dep_table; | ||
177 | int nr_dep_entries; | ||
178 | }; | ||
179 | |||
180 | /** | ||
181 | * omap_vdd_info - Per Voltage Domain info | ||
182 | * | ||
183 | * @volt_data : voltage table having the distinct voltages supported | ||
184 | * by the domain and other associated per voltage data. | ||
185 | * @dep_vdd_info : Array ending with a 0 terminator for dependency | ||
186 | * voltage information. | ||
187 | */ | ||
188 | struct omap_vdd_info { | ||
189 | struct omap_volt_data *volt_data; | ||
190 | struct omap_vdd_dep_info *dep_vdd_info; | ||
191 | }; | ||
192 | |||
193 | void omap_voltage_get_volttable(struct voltagedomain *voltdm, | ||
194 | struct omap_volt_data **volt_data); | ||
195 | struct omap_volt_data *omap_voltage_get_voltdata(struct voltagedomain *voltdm, | ||
196 | unsigned long volt); | ||
197 | int omap_voltage_register_pmic(struct voltagedomain *voltdm, | ||
198 | struct omap_voltdm_pmic *pmic); | ||
199 | void omap_change_voltscale_method(struct voltagedomain *voltdm, | ||
200 | int voltscale_method); | ||
201 | int omap_voltage_late_init(void); | ||
202 | |||
203 | extern void omap2xxx_voltagedomains_init(void); | ||
204 | extern void omap3xxx_voltagedomains_init(void); | ||
205 | extern void am33xx_voltagedomains_init(void); | ||
206 | extern void omap44xx_voltagedomains_init(void); | ||
207 | |||
16 | struct voltagedomain *voltdm_lookup(const char *name); | 208 | struct voltagedomain *voltdm_lookup(const char *name); |
209 | void voltdm_init(struct voltagedomain **voltdm_list); | ||
210 | int voltdm_add_pwrdm(struct voltagedomain *voltdm, struct powerdomain *pwrdm); | ||
211 | int voltdm_for_each(int (*fn)(struct voltagedomain *voltdm, void *user), | ||
212 | void *user); | ||
213 | int voltdm_for_each_pwrdm(struct voltagedomain *voltdm, | ||
214 | int (*fn)(struct voltagedomain *voltdm, | ||
215 | struct powerdomain *pwrdm)); | ||
17 | int voltdm_scale(struct voltagedomain *voltdm, unsigned long target_volt); | 216 | int voltdm_scale(struct voltagedomain *voltdm, unsigned long target_volt); |
217 | void voltdm_reset(struct voltagedomain *voltdm); | ||
18 | unsigned long voltdm_get_voltage(struct voltagedomain *voltdm); | 218 | unsigned long voltdm_get_voltage(struct voltagedomain *voltdm); |
19 | |||
20 | #endif | 219 | #endif |
arch/arm/plat-omap/include/plat/vp.h
File was created | 1 | /* | |
2 | * OMAP3/4 Voltage Processor (VP) structure and macro definitions | ||
3 | * | ||
4 | * Copyright (C) 2007, 2010 Texas Instruments, Inc. | ||
5 | * Rajendra Nayak <rnayak@ti.com> | ||
6 | * Lesly A M <x0080970@ti.com> | ||
7 | * Thara Gopinath <thara@ti.com> | ||
8 | * | ||
9 | * Copyright (C) 2008, 2011 Nokia Corporation | ||
10 | * Kalle Jokiniemi | ||
11 | * Paul Walmsley | ||
12 | * | ||
13 | * This program is free software; you can redistribute it and/or | ||
14 | * modify it under the terms of the GNU General Public License version | ||
15 | * 2 as published by the Free Software Foundation. | ||
16 | */ | ||
17 | #ifndef __ARCH_ARM_MACH_OMAP2_VP_H | ||
18 | #define __ARCH_ARM_MACH_OMAP2_VP_H | ||
19 | |||
20 | #include <linux/kernel.h> | ||
21 | |||
22 | struct voltagedomain; | ||
23 | |||
24 | /* | ||
25 | * Voltage Processor (VP) identifiers | ||
26 | */ | ||
27 | #define OMAP3_VP_VDD_MPU_ID 0 | ||
28 | #define OMAP3_VP_VDD_CORE_ID 1 | ||
29 | #define OMAP4_VP_VDD_CORE_ID 0 | ||
30 | #define OMAP4_VP_VDD_IVA_ID 1 | ||
31 | #define OMAP4_VP_VDD_MPU_ID 2 | ||
32 | |||
33 | /* XXX document */ | ||
34 | #define VP_IDLE_TIMEOUT 200 | ||
35 | #define VP_TRANXDONE_TIMEOUT 300 | ||
36 | |||
37 | /** | ||
38 | * struct omap_vp_ops - per-VP operations | ||
39 | * @check_txdone: check for VP transaction done | ||
40 | * @clear_txdone: clear VP transaction done status | ||
41 | */ | ||
42 | struct omap_vp_ops { | ||
43 | u32 (*check_txdone)(u8 vp_id); | ||
44 | void (*clear_txdone)(u8 vp_id); | ||
45 | }; | ||
46 | |||
47 | /** | ||
48 | * struct omap_vp_common - register data common to all VDDs | ||
49 | * @vpconfig_erroroffset_mask: ERROROFFSET bitmask in the PRM_VP*_CONFIG reg | ||
50 | * @vpconfig_errorgain_mask: ERRORGAIN bitmask in the PRM_VP*_CONFIG reg | ||
51 | * @vpconfig_initvoltage_mask: INITVOLTAGE bitmask in the PRM_VP*_CONFIG reg | ||
52 | * @vpconfig_timeouten: TIMEOUT bitmask in the PRM_VP*_CONFIG reg | ||
53 | * @vpconfig_initvdd: INITVDD bitmask in the PRM_VP*_CONFIG reg | ||
54 | * @vpconfig_forceupdate: FORCEUPDATE bitmask in the PRM_VP*_CONFIG reg | ||
55 | * @vpconfig_vpenable: VPENABLE bitmask in the PRM_VP*_CONFIG reg | ||
56 | * @vpconfig_erroroffset_shift: ERROROFFSET field shift in PRM_VP*_CONFIG reg | ||
57 | * @vpconfig_errorgain_shift: ERRORGAIN field shift in PRM_VP*_CONFIG reg | ||
58 | * @vpconfig_initvoltage_shift: INITVOLTAGE field shift in PRM_VP*_CONFIG reg | ||
59 | * @vstepmin_stepmin_shift: VSTEPMIN field shift in the PRM_VP*_VSTEPMIN reg | ||
60 | * @vstepmin_smpswaittimemin_shift: SMPSWAITTIMEMIN field shift in PRM_VP*_VSTEPMIN reg | ||
61 | * @vstepmax_stepmax_shift: VSTEPMAX field shift in the PRM_VP*_VSTEPMAX reg | ||
62 | * @vstepmax_smpswaittimemax_shift: SMPSWAITTIMEMAX field shift in PRM_VP*_VSTEPMAX reg | ||
63 | * @vlimitto_vddmin_shift: VDDMIN field shift in PRM_VP*_VLIMITTO reg | ||
64 | * @vlimitto_vddmax_shift: VDDMAX field shift in PRM_VP*_VLIMITTO reg | ||
65 | * @vlimitto_timeout_shift: TIMEOUT field shift in PRM_VP*_VLIMITTO reg | ||
66 | * @vpvoltage_mask: VPVOLTAGE field mask in PRM_VP*_VOLTAGE reg | ||
67 | */ | ||
68 | struct omap_vp_common { | ||
69 | u32 vpconfig_erroroffset_mask; | ||
70 | u32 vpconfig_errorgain_mask; | ||
71 | u32 vpconfig_initvoltage_mask; | ||
72 | u8 vpconfig_timeouten; | ||
73 | u8 vpconfig_initvdd; | ||
74 | u8 vpconfig_forceupdate; | ||
75 | u8 vpconfig_vpenable; | ||
76 | u8 vstepmin_stepmin_shift; | ||
77 | u8 vstepmin_smpswaittimemin_shift; | ||
78 | u8 vstepmax_stepmax_shift; | ||
79 | u8 vstepmax_smpswaittimemax_shift; | ||
80 | u8 vlimitto_vddmin_shift; | ||
81 | u8 vlimitto_vddmax_shift; | ||
82 | u8 vlimitto_timeout_shift; | ||
83 | u8 vpvoltage_mask; | ||
84 | |||
85 | const struct omap_vp_ops *ops; | ||
86 | }; | ||
87 | |||
88 | /** | ||
89 | * struct omap_vp_instance - VP register offsets (per-VDD) | ||
90 | * @common: pointer to struct omap_vp_common * for this SoC | ||
91 | * @vpconfig: PRM_VP*_CONFIG reg offset from PRM start | ||
92 | * @vstepmin: PRM_VP*_VSTEPMIN reg offset from PRM start | ||
93 | * @vlimitto: PRM_VP*_VLIMITTO reg offset from PRM start | ||
94 | * @vstatus: PRM_VP*_VSTATUS reg offset from PRM start | ||
95 | * @voltage: PRM_VP*_VOLTAGE reg offset from PRM start | ||
96 | * @id: Unique identifier for VP instance. | ||
97 | * @enabled: flag to keep track of whether vp is enabled or not | ||
98 | * | ||
99 | * XXX vp_common is probably not needed since it is per-SoC | ||
100 | */ | ||
101 | struct omap_vp_instance { | ||
102 | const struct omap_vp_common *common; | ||
103 | u8 vpconfig; | ||
104 | u8 vstepmin; | ||
105 | u8 vstepmax; | ||
106 | u8 vlimitto; | ||
107 | u8 vstatus; | ||
108 | u8 voltage; | ||
109 | u8 id; | ||
110 | bool enabled; | ||
111 | }; | ||
112 | |||
113 | extern struct omap_vp_instance omap3_vp_mpu; | ||
114 | extern struct omap_vp_instance omap3_vp_core; | ||
115 | |||
116 | extern struct omap_vp_instance omap4_vp_mpu; | ||
117 | extern struct omap_vp_instance omap4_vp_iva; | ||
118 | extern struct omap_vp_instance omap4_vp_core; | ||
119 | |||
120 | void omap_vp_init(struct voltagedomain *voltdm); | ||
121 | void omap_vp_enable(struct voltagedomain *voltdm); | ||
122 | void omap_vp_disable(struct voltagedomain *voltdm); | ||
123 | int omap_vp_forceupdate_scale(struct voltagedomain *voltdm, | ||
124 | unsigned long target_volt); | ||
125 | int omap_vp_update_errorgain(struct voltagedomain *voltdm, | ||
126 | unsigned long target_volt); | ||
127 | |||
128 | #endif | ||
129 |
drivers/cpufreq/omap-cpufreq.c
1 | /* | 1 | /* |
2 | * CPU frequency scaling for OMAP using OPP information | 2 | * CPU frequency scaling for OMAP using OPP information |
3 | * | 3 | * |
4 | * Copyright (C) 2005 Nokia Corporation | 4 | * Copyright (C) 2005 Nokia Corporation |
5 | * Written by Tony Lindgren <tony@atomide.com> | 5 | * Written by Tony Lindgren <tony@atomide.com> |
6 | * | 6 | * |
7 | * Based on cpu-sa1110.c, Copyright (C) 2001 Russell King | 7 | * Based on cpu-sa1110.c, Copyright (C) 2001 Russell King |
8 | * | 8 | * |
9 | * Copyright (C) 2007-2011 Texas Instruments, Inc. | 9 | * Copyright (C) 2007-2011 Texas Instruments, Inc. |
10 | * - OMAP3/4 support by Rajendra Nayak, Santosh Shilimkar | 10 | * - OMAP3/4 support by Rajendra Nayak, Santosh Shilimkar |
11 | * | 11 | * |
12 | * This program is free software; you can redistribute it and/or modify | 12 | * This program is free software; you can redistribute it and/or modify |
13 | * it under the terms of the GNU General Public License version 2 as | 13 | * it under the terms of the GNU General Public License version 2 as |
14 | * published by the Free Software Foundation. | 14 | * published by the Free Software Foundation. |
15 | */ | 15 | */ |
16 | #include <linux/types.h> | 16 | #include <linux/types.h> |
17 | #include <linux/kernel.h> | 17 | #include <linux/kernel.h> |
18 | #include <linux/sched.h> | 18 | #include <linux/sched.h> |
19 | #include <linux/cpufreq.h> | 19 | #include <linux/cpufreq.h> |
20 | #include <linux/delay.h> | 20 | #include <linux/delay.h> |
21 | #include <linux/init.h> | 21 | #include <linux/init.h> |
22 | #include <linux/err.h> | 22 | #include <linux/err.h> |
23 | #include <linux/clk.h> | 23 | #include <linux/clk.h> |
24 | #include <linux/io.h> | 24 | #include <linux/io.h> |
25 | #include <linux/opp.h> | 25 | #include <linux/opp.h> |
26 | #include <linux/cpu.h> | 26 | #include <linux/cpu.h> |
27 | 27 | ||
28 | #include <asm/system.h> | 28 | #include <asm/system.h> |
29 | #include <asm/smp_plat.h> | 29 | #include <asm/smp_plat.h> |
30 | #include <asm/cpu.h> | 30 | #include <asm/cpu.h> |
31 | 31 | ||
32 | #include <plat/clock.h> | 32 | #include <plat/clock.h> |
33 | #include <plat/omap-pm.h> | 33 | #include <plat/omap-pm.h> |
34 | #include <plat/omap_device.h> | 34 | #include <plat/omap_device.h> |
35 | #include <plat/common.h> | 35 | #include <plat/common.h> |
36 | #include <plat/dvfs.h> | ||
36 | 37 | ||
37 | #include <mach/hardware.h> | 38 | #include <mach/hardware.h> |
38 | 39 | ||
39 | #ifdef CONFIG_SMP | 40 | #ifdef CONFIG_SMP |
40 | struct lpj_info { | 41 | struct lpj_info { |
41 | unsigned long ref; | 42 | unsigned long ref; |
42 | unsigned int freq; | 43 | unsigned int freq; |
43 | }; | 44 | }; |
44 | 45 | ||
45 | static DEFINE_PER_CPU(struct lpj_info, lpj_ref); | 46 | static DEFINE_PER_CPU(struct lpj_info, lpj_ref); |
46 | static struct lpj_info global_lpj_ref; | 47 | static struct lpj_info global_lpj_ref; |
47 | #endif | 48 | #endif |
48 | 49 | ||
49 | static struct cpufreq_frequency_table *freq_table; | 50 | static struct cpufreq_frequency_table *freq_table; |
50 | static atomic_t freq_table_users = ATOMIC_INIT(0); | 51 | static atomic_t freq_table_users = ATOMIC_INIT(0); |
51 | static struct clk *mpu_clk; | 52 | static struct clk *mpu_clk; |
52 | static char *mpu_clk_name; | 53 | static char *mpu_clk_name; |
53 | static struct device *mpu_dev; | 54 | static struct device *mpu_dev; |
54 | 55 | ||
55 | static int omap_verify_speed(struct cpufreq_policy *policy) | 56 | static int omap_verify_speed(struct cpufreq_policy *policy) |
56 | { | 57 | { |
57 | if (!freq_table) | 58 | if (!freq_table) |
58 | return -EINVAL; | 59 | return -EINVAL; |
59 | return cpufreq_frequency_table_verify(policy, freq_table); | 60 | return cpufreq_frequency_table_verify(policy, freq_table); |
60 | } | 61 | } |
61 | 62 | ||
62 | static unsigned int omap_getspeed(unsigned int cpu) | 63 | static unsigned int omap_getspeed(unsigned int cpu) |
63 | { | 64 | { |
64 | unsigned long rate; | 65 | unsigned long rate; |
65 | 66 | ||
66 | if (cpu >= NR_CPUS) | 67 | if (cpu >= NR_CPUS) |
67 | return 0; | 68 | return 0; |
68 | 69 | ||
69 | rate = clk_get_rate(mpu_clk) / 1000; | 70 | rate = clk_get_rate(mpu_clk) / 1000; |
70 | return rate; | 71 | return rate; |
71 | } | 72 | } |
72 | 73 | ||
73 | static int omap_target(struct cpufreq_policy *policy, | 74 | static int omap_target(struct cpufreq_policy *policy, |
74 | unsigned int target_freq, | 75 | unsigned int target_freq, |
75 | unsigned int relation) | 76 | unsigned int relation) |
76 | { | 77 | { |
77 | unsigned int i; | 78 | unsigned int i; |
78 | int ret = 0; | 79 | int ret = 0; |
79 | struct cpufreq_freqs freqs; | 80 | struct cpufreq_freqs freqs; |
80 | 81 | ||
81 | if (!freq_table) { | 82 | if (!freq_table) { |
82 | dev_err(mpu_dev, "%s: cpu%d: no freq table!\n", __func__, | 83 | dev_err(mpu_dev, "%s: cpu%d: no freq table!\n", __func__, |
83 | policy->cpu); | 84 | policy->cpu); |
84 | return -EINVAL; | 85 | return -EINVAL; |
85 | } | 86 | } |
86 | 87 | ||
87 | ret = cpufreq_frequency_table_target(policy, freq_table, target_freq, | 88 | ret = cpufreq_frequency_table_target(policy, freq_table, target_freq, |
88 | relation, &i); | 89 | relation, &i); |
89 | if (ret) { | 90 | if (ret) { |
90 | dev_dbg(mpu_dev, "%s: cpu%d: no freq match for %d(ret=%d)\n", | 91 | dev_dbg(mpu_dev, "%s: cpu%d: no freq match for %d(ret=%d)\n", |
91 | __func__, policy->cpu, target_freq, ret); | 92 | __func__, policy->cpu, target_freq, ret); |
92 | return ret; | 93 | return ret; |
93 | } | 94 | } |
94 | freqs.new = freq_table[i].frequency; | 95 | freqs.new = freq_table[i].frequency; |
95 | if (!freqs.new) { | 96 | if (!freqs.new) { |
96 | dev_err(mpu_dev, "%s: cpu%d: no match for freq %d\n", __func__, | 97 | dev_err(mpu_dev, "%s: cpu%d: no match for freq %d\n", __func__, |
97 | policy->cpu, target_freq); | 98 | policy->cpu, target_freq); |
98 | return -EINVAL; | 99 | return -EINVAL; |
99 | } | 100 | } |
100 | 101 | ||
101 | freqs.old = omap_getspeed(policy->cpu); | 102 | freqs.old = omap_getspeed(policy->cpu); |
102 | freqs.cpu = policy->cpu; | 103 | freqs.cpu = policy->cpu; |
103 | 104 | ||
104 | if (freqs.old == freqs.new && policy->cur == freqs.new) | 105 | if (freqs.old == freqs.new && policy->cur == freqs.new) |
105 | return ret; | 106 | return ret; |
106 | 107 | ||
107 | /* notifiers */ | 108 | /* notifiers */ |
108 | for_each_cpu(i, policy->cpus) { | 109 | for_each_cpu(i, policy->cpus) { |
109 | freqs.cpu = i; | 110 | freqs.cpu = i; |
110 | cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); | 111 | cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); |
111 | } | 112 | } |
112 | 113 | ||
113 | #ifdef CONFIG_CPU_FREQ_DEBUG | 114 | #ifdef CONFIG_CPU_FREQ_DEBUG |
114 | pr_info("cpufreq-omap: transition: %u --> %u\n", freqs.old, freqs.new); | 115 | pr_info("cpufreq-omap: transition: %u --> %u\n", freqs.old, freqs.new); |
115 | #endif | 116 | #endif |
116 | 117 | ||
117 | ret = clk_set_rate(mpu_clk, freqs.new * 1000); | 118 | ret = clk_set_rate(mpu_clk, freqs.new * 1000); |
118 | freqs.new = omap_getspeed(policy->cpu); | 119 | freqs.new = omap_getspeed(policy->cpu); |
119 | 120 | ||
120 | #ifdef CONFIG_SMP | 121 | #ifdef CONFIG_SMP |
121 | /* | 122 | /* |
122 | * Note that loops_per_jiffy is not updated on SMP systems in | 123 | * Note that loops_per_jiffy is not updated on SMP systems in |
123 | * cpufreq driver. So, update the per-CPU loops_per_jiffy value | 124 | * cpufreq driver. So, update the per-CPU loops_per_jiffy value |
124 | * on frequency transition. We need to update all dependent CPUs. | 125 | * on frequency transition. We need to update all dependent CPUs. |
125 | */ | 126 | */ |
126 | for_each_cpu(i, policy->cpus) { | 127 | for_each_cpu(i, policy->cpus) { |
127 | struct lpj_info *lpj = &per_cpu(lpj_ref, i); | 128 | struct lpj_info *lpj = &per_cpu(lpj_ref, i); |
128 | if (!lpj->freq) { | 129 | if (!lpj->freq) { |
129 | lpj->ref = per_cpu(cpu_data, i).loops_per_jiffy; | 130 | lpj->ref = per_cpu(cpu_data, i).loops_per_jiffy; |
130 | lpj->freq = freqs.old; | 131 | lpj->freq = freqs.old; |
131 | } | 132 | } |
132 | 133 | ||
133 | per_cpu(cpu_data, i).loops_per_jiffy = | 134 | per_cpu(cpu_data, i).loops_per_jiffy = |
134 | cpufreq_scale(lpj->ref, lpj->freq, freqs.new); | 135 | cpufreq_scale(lpj->ref, lpj->freq, freqs.new); |
135 | } | 136 | } |
136 | 137 | ||
137 | /* And don't forget to adjust the global one */ | 138 | /* And don't forget to adjust the global one */ |
138 | if (!global_lpj_ref.freq) { | 139 | if (!global_lpj_ref.freq) { |
139 | global_lpj_ref.ref = loops_per_jiffy; | 140 | global_lpj_ref.ref = loops_per_jiffy; |
140 | global_lpj_ref.freq = freqs.old; | 141 | global_lpj_ref.freq = freqs.old; |
141 | } | 142 | } |
142 | loops_per_jiffy = cpufreq_scale(global_lpj_ref.ref, global_lpj_ref.freq, | 143 | loops_per_jiffy = cpufreq_scale(global_lpj_ref.ref, global_lpj_ref.freq, |
143 | freqs.new); | 144 | freqs.new); |
144 | #endif | 145 | #endif |
145 | 146 | ||
146 | /* notifiers */ | 147 | /* notifiers */ |
147 | for_each_cpu(i, policy->cpus) { | 148 | for_each_cpu(i, policy->cpus) { |
148 | freqs.cpu = i; | 149 | freqs.cpu = i; |
149 | cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); | 150 | cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); |
150 | } | 151 | } |
151 | 152 | ||
152 | return ret; | 153 | return ret; |
153 | } | 154 | } |
154 | 155 | ||
155 | static inline void freq_table_free(void) | 156 | static inline void freq_table_free(void) |
156 | { | 157 | { |
157 | if (atomic_dec_and_test(&freq_table_users)) | 158 | if (atomic_dec_and_test(&freq_table_users)) |
158 | opp_free_cpufreq_table(mpu_dev, &freq_table); | 159 | opp_free_cpufreq_table(mpu_dev, &freq_table); |
159 | } | 160 | } |
160 | 161 | ||
161 | static int __cpuinit omap_cpu_init(struct cpufreq_policy *policy) | 162 | static int __cpuinit omap_cpu_init(struct cpufreq_policy *policy) |
162 | { | 163 | { |
163 | int result = 0; | 164 | int result = 0; |
164 | 165 | ||
165 | mpu_clk = clk_get(NULL, mpu_clk_name); | 166 | mpu_clk = clk_get(NULL, mpu_clk_name); |
166 | if (IS_ERR(mpu_clk)) | 167 | if (IS_ERR(mpu_clk)) |
167 | return PTR_ERR(mpu_clk); | 168 | return PTR_ERR(mpu_clk); |
168 | 169 | ||
169 | if (policy->cpu >= NR_CPUS) { | 170 | if (policy->cpu >= NR_CPUS) { |
170 | result = -EINVAL; | 171 | result = -EINVAL; |
171 | goto fail_ck; | 172 | goto fail_ck; |
172 | } | 173 | } |
173 | 174 | ||
174 | policy->cur = policy->min = policy->max = omap_getspeed(policy->cpu); | 175 | policy->cur = policy->min = policy->max = omap_getspeed(policy->cpu); |
175 | 176 | ||
176 | if (atomic_inc_return(&freq_table_users) == 1) | 177 | if (atomic_inc_return(&freq_table_users) == 1) |
177 | result = opp_init_cpufreq_table(mpu_dev, &freq_table); | 178 | result = opp_init_cpufreq_table(mpu_dev, &freq_table); |
178 | 179 | ||
179 | if (result) { | 180 | if (result) { |
180 | dev_err(mpu_dev, "%s: cpu%d: failed creating freq table[%d]\n", | 181 | dev_err(mpu_dev, "%s: cpu%d: failed creating freq table[%d]\n", |
181 | __func__, policy->cpu, result); | 182 | __func__, policy->cpu, result); |
182 | goto fail_ck; | 183 | goto fail_ck; |
183 | } | 184 | } |
184 | 185 | ||
185 | result = cpufreq_frequency_table_cpuinfo(policy, freq_table); | 186 | result = cpufreq_frequency_table_cpuinfo(policy, freq_table); |
186 | if (result) | 187 | if (result) |
187 | goto fail_table; | 188 | goto fail_table; |
188 | 189 | ||
189 | cpufreq_frequency_table_get_attr(freq_table, policy->cpu); | 190 | cpufreq_frequency_table_get_attr(freq_table, policy->cpu); |
190 | 191 | ||
191 | policy->min = policy->cpuinfo.min_freq; | 192 | policy->min = policy->cpuinfo.min_freq; |
192 | policy->max = policy->cpuinfo.max_freq; | 193 | policy->max = policy->cpuinfo.max_freq; |
193 | policy->cur = omap_getspeed(policy->cpu); | 194 | policy->cur = omap_getspeed(policy->cpu); |
194 | 195 | ||
195 | /* | 196 | /* |
196 | * On OMAP SMP configuartion, both processors share the voltage | 197 | * On OMAP SMP configuartion, both processors share the voltage |
197 | * and clock. So both CPUs needs to be scaled together and hence | 198 | * and clock. So both CPUs needs to be scaled together and hence |
198 | * needs software co-ordination. Use cpufreq affected_cpus | 199 | * needs software co-ordination. Use cpufreq affected_cpus |
199 | * interface to handle this scenario. Additional is_smp() check | 200 | * interface to handle this scenario. Additional is_smp() check |
200 | * is to keep SMP_ON_UP build working. | 201 | * is to keep SMP_ON_UP build working. |
201 | */ | 202 | */ |
202 | if (is_smp()) { | 203 | if (is_smp()) { |
203 | policy->shared_type = CPUFREQ_SHARED_TYPE_ANY; | 204 | policy->shared_type = CPUFREQ_SHARED_TYPE_ANY; |
204 | cpumask_setall(policy->cpus); | 205 | cpumask_setall(policy->cpus); |
205 | } | 206 | } |
206 | 207 | ||
207 | /* FIXME: what's the actual transition time? */ | 208 | /* FIXME: what's the actual transition time? */ |
208 | policy->cpuinfo.transition_latency = 300 * 1000; | 209 | policy->cpuinfo.transition_latency = 300 * 1000; |
209 | 210 | ||
210 | return 0; | 211 | return 0; |
211 | 212 | ||
212 | fail_table: | 213 | fail_table: |
213 | freq_table_free(); | 214 | freq_table_free(); |
214 | fail_ck: | 215 | fail_ck: |
215 | clk_put(mpu_clk); | 216 | clk_put(mpu_clk); |
216 | return result; | 217 | return result; |
217 | } | 218 | } |
218 | 219 | ||
219 | static int omap_cpu_exit(struct cpufreq_policy *policy) | 220 | static int omap_cpu_exit(struct cpufreq_policy *policy) |
220 | { | 221 | { |
221 | freq_table_free(); | 222 | freq_table_free(); |
222 | clk_put(mpu_clk); | 223 | clk_put(mpu_clk); |
223 | return 0; | 224 | return 0; |
224 | } | 225 | } |
225 | 226 | ||
226 | static struct freq_attr *omap_cpufreq_attr[] = { | 227 | static struct freq_attr *omap_cpufreq_attr[] = { |
227 | &cpufreq_freq_attr_scaling_available_freqs, | 228 | &cpufreq_freq_attr_scaling_available_freqs, |
228 | NULL, | 229 | NULL, |
229 | }; | 230 | }; |
230 | 231 | ||
231 | static struct cpufreq_driver omap_driver = { | 232 | static struct cpufreq_driver omap_driver = { |
232 | .flags = CPUFREQ_STICKY, | 233 | .flags = CPUFREQ_STICKY, |
233 | .verify = omap_verify_speed, | 234 | .verify = omap_verify_speed, |
234 | .target = omap_target, | 235 | .target = omap_target, |
235 | .get = omap_getspeed, | 236 | .get = omap_getspeed, |
236 | .init = omap_cpu_init, | 237 | .init = omap_cpu_init, |
237 | .exit = omap_cpu_exit, | 238 | .exit = omap_cpu_exit, |
238 | .name = "omap", | 239 | .name = "omap", |
239 | .attr = omap_cpufreq_attr, | 240 | .attr = omap_cpufreq_attr, |
240 | }; | 241 | }; |
241 | 242 | ||
242 | static int __init omap_cpufreq_init(void) | 243 | static int __init omap_cpufreq_init(void) |
243 | { | 244 | { |
244 | if (cpu_is_omap24xx()) | 245 | if (cpu_is_omap24xx()) |
245 | mpu_clk_name = "virt_prcm_set"; | 246 | mpu_clk_name = "virt_prcm_set"; |
246 | else if (cpu_is_omap34xx()) | 247 | else if (cpu_is_omap34xx()) |
247 | mpu_clk_name = "dpll1_ck"; | 248 | mpu_clk_name = "dpll1_ck"; |
248 | else if (cpu_is_omap44xx()) | 249 | else if (cpu_is_omap44xx()) |
249 | mpu_clk_name = "dpll_mpu_ck"; | 250 | mpu_clk_name = "dpll_mpu_ck"; |
250 | 251 | ||
251 | if (!mpu_clk_name) { | 252 | if (!mpu_clk_name) { |
252 | pr_err("%s: unsupported Silicon?\n", __func__); | 253 | pr_err("%s: unsupported Silicon?\n", __func__); |
253 | return -EINVAL; | 254 | return -EINVAL; |
254 | } | 255 | } |
255 | 256 | ||
256 | mpu_dev = omap_device_get_by_hwmod_name("mpu"); | 257 | mpu_dev = omap_device_get_by_hwmod_name("mpu"); |
257 | if (!mpu_dev) { | 258 | if (!mpu_dev) { |
258 | pr_warning("%s: unable to get the mpu device\n", __func__); | 259 | pr_warning("%s: unable to get the mpu device\n", __func__); |
259 | return -EINVAL; | 260 | return -EINVAL; |
260 | } | 261 | } |
261 | 262 | ||
262 | return cpufreq_register_driver(&omap_driver); | 263 | return cpufreq_register_driver(&omap_driver); |
263 | } | 264 | } |
264 | 265 | ||
265 | static void __exit omap_cpufreq_exit(void) | 266 | static void __exit omap_cpufreq_exit(void) |
266 | { | 267 | { |
267 | cpufreq_unregister_driver(&omap_driver); | 268 | cpufreq_unregister_driver(&omap_driver); |
268 | } | 269 | } |
269 | 270 | ||
270 | MODULE_DESCRIPTION("cpufreq driver for OMAP SoCs"); | 271 | MODULE_DESCRIPTION("cpufreq driver for OMAP SoCs"); |
271 | MODULE_LICENSE("GPL"); | 272 | MODULE_LICENSE("GPL"); |
272 | module_init(omap_cpufreq_init); | 273 | module_init(omap_cpufreq_init); |
273 | module_exit(omap_cpufreq_exit); | 274 | module_exit(omap_cpufreq_exit); |
274 | 275 |