added driver framework to prepare for driver unification, fixed USB driver, added...
[rpi-open-firmware.git] / drivers / BCM2708PowerManagement.cc
1 /*
2 * VideoCore4_Drivers
3 * Copyright (c) 2017 Kristina Brooks
4 *
5 * BCM2708 power management driver.
6 */
7
8 #include <drivers/BCM2708PowerManagement.hpp>
9
10 #define PM_UNK_CFG_CLR 0xFFFCFFFF
11
12 PowerManagementDomain* g_BCM2708PowerDomains[kCprPowerDomain_MAX];
13
14 PowerManagementDomain* PowerManagementDomain::getDeviceForDomain(cpr_power_domain_t domain) {
15 if (domain > kCprPowerDomain_MAX-1) {
16 return nullptr;
17 }
18 PowerManagementDomain* pm = g_BCM2708PowerDomains[domain];
19 }
20
21 /***********************************************************************
22 *
23 * Superclass for all power domains.
24 *
25 ***********************************************************************/
26
27 struct BCM2708PowerDomain : PowerManagementDomain {
28 volatile uint32_t* pmReg;
29 uint32_t rstnMask;
30 cpr_power_domain_t powerDomain;
31
32 inline void pmvOr(uint32_t& pmv, uint32_t value) {
33 pmv |= value;
34 *pmReg = pmv;
35 }
36
37 inline void pmvAnd(uint32_t& pmv, uint32_t value) {
38 pmv &= value;
39 *pmReg = pmv;
40 }
41
42 bool waitForPmBit(uint32_t bit) {
43 for (int i = 0; i < 20; i++) {
44 if (*pmReg & bit) {
45 return true;
46 }
47 waitOscTicks();
48 }
49 return false;
50 }
51
52 cpr_power_result_t waitForPOWOK(uint32_t& pmv) {
53 IODriverLog("waiting for POWOK ...");
54
55 for (int i = 1; i < 5; i++) {
56 if (!waitForPmBit(PM_GNRIC_POWOK_SET)) {
57 /* only go up to 3 */
58 if (i == 4) {
59 IODriverLog("timed out waiting for powok!");
60 return kCprPowOkTimeout;
61 }
62
63 pmv = (pmv & PM_UNK_CFG_CLR) | (i << PM_GNRIC_CFG_LSB);
64 IODriverLog("timed out, trying a different cfg value: 0x%X", pmv);
65 *pmReg = pmv;
66 }
67 }
68
69 IODriverLog("got POWOK with CFG=0x%X", *pmReg & PM_GNRIC_CFG_SET);
70 return kCprSuccess;
71 }
72
73 cpr_power_result_t beginPowerUpSequence(uint32_t& pmv) {
74 IODriverLog("starting power up sequence ...");
75 pmvOr(pmv, PM_GNRIC_POWUP_SET);
76 }
77
78 cpr_power_result_t completePowerUpSequence(uint32_t& pmv, bool setPowup = true) {
79 pmvOr(pmv, PM_GNRIC_ISPOW_SET);
80 pmvOr(pmv, PM_GNRIC_MEMREP_SET);
81
82 IODriverLog("waiting for MRDONE ...");
83 if (!waitForPmBit(PM_GNRIC_MRDONE_SET)) {
84 IODriverLog("timed out waiting for MRDONE: 0x%X", *pmReg);
85 return kCprMrDoneTimeout;
86 }
87
88 pmvOr(pmv, PM_GNRIC_ISFUNC_SET);
89
90 return kCprSuccess;
91 }
92
93 virtual cpr_power_result_t powerOn() {
94 uint32_t pmv;
95 cpr_power_result_t res;
96
97 IODriverLog("powering on (rstnMask=0x%X) ...", rstnMask);
98
99 pmv = ((*pmReg & rstnMask) & PM_UNK_CFG_CLR) | PM_PASSWORD;
100 *pmReg = pmv;
101 udelay(15);
102
103 beginPowerUpSequence(pmv);
104
105 res = waitForPOWOK(pmv);
106 if (res != kCprSuccess)
107 return res;
108
109 res = completePowerUpSequence(pmv);
110 if (res != kCprSuccess)
111 return res;
112
113 IODriverLog("domain powered on succesfully");
114
115 return kCprSuccess;
116 }
117
118 virtual void setReset() override {
119 IODriverLog("setting RSTN bits to 0x%X ...", (~rstnMask));
120 *pmReg |= (~rstnMask) | PM_PASSWORD;
121 udelay(300);
122 }
123
124 void waitOscTicks(uint32_t ticks = 2) {
125 CM_OSCCOUNT = CM_PASSWORD | ticks;
126 while(CM_OSCCOUNT != 0);
127 }
128
129 template <typename T>
130 void setPmReg(T regAddr) {
131 pmReg = reinterpret_cast<volatile uint32_t*>(regAddr);
132 }
133
134 void registerPowerDomain(cpr_power_domain_t domain) {
135 g_BCM2708PowerDomains[domain] = this;
136 }
137 };
138
139 /***********************************************************************
140 *
141 * Image power domain.
142 * Contains: PERII (USB), H264, ISP
143 *
144 ***********************************************************************/
145
146 struct BCM2708PowerDomainImage : BCM2708PowerDomain {
147 IODriverConstructor(BCM2708PowerDomainImage);
148
149 virtual void init() override {
150 setName("BCM2708PowerDomainImage");
151 setPmReg(0x7E100108);
152 registerPowerDomain(kCprPowerDomainImage);
153 rstnMask = ~(PM_IMAGE_ISPRSTN_SET | PM_IMAGE_H264RSTN_SET | PM_IMAGE_PERIRSTN_SET);
154 }
155
156 virtual cpr_power_result_t powerOn() {
157 uint32_t pmv;
158 cpr_power_result_t res;
159
160 IODriverLog("powering on, current PM_IMAGE state: 0x%X", PM_IMAGE);
161
162 pmv = *pmReg | 0x10000 | PM_PASSWORD;
163 *pmReg = pmv;
164
165 /*
166 * first sequence has to be done with this CFG.
167 */
168 beginPowerUpSequence(pmv);
169
170 res = waitForPOWOK(pmv);
171 if (res != kCprSuccess)
172 return res;
173
174 IODriverLog("stopping power up sequence ...");
175 pmvAnd(pmv, ~PM_GNRIC_POWUP_SET);
176 pmvOr(pmv, 0x30000); /* CFG */
177
178 /*
179 * now do this all over again with the new CFG.
180 */
181 beginPowerUpSequence(pmv);
182
183 res = waitForPOWOK(pmv);
184 if (res != kCprSuccess)
185 return res;
186
187 res = completePowerUpSequence(pmv);
188 if (res != kCprSuccess)
189 return res;
190
191 BCM2708PowerDomain::stop();
192
193 return kCprSuccess;
194 }
195
196 void resetPeripheralsUngated() {
197 CM_PERIICTL = CM_PASSWORD | CM_PERIICTL_GATE_SET;
198
199 //IODriverLog("vector op call ...");
200 //vector_op_gated();
201
202 CM_PERIICTL = CM_PASSWORD;
203
204 waitOscTicks();
205
206 *pmReg |= CM_PASSWORD | PM_IMAGE_PERIRSTN_SET;
207
208 CM_PERIICTL = CM_PASSWORD | CM_PERIICTL_GATE_SET;
209
210 IODriverLog("done");
211 }
212
213 virtual void start() override {
214 #if 1
215 cpr_power_result_t res = powerOn();
216
217 if (res != kCprSuccess)
218 panic("%s failed to start the image power domain", driverName);
219
220 resetPeripheralsUngated();
221 #else
222 IODriverLog("image_domain_peripherals_init returned: 0x%X", image_domain_peripherals_init());
223 #endif
224
225 IODriverLog("CM_PERIICTL = 0x%X", CM_PERIICTL);
226 IODriverLog("CM_PERIIDIV = 0x%X", CM_PERIIDIV);
227 IODriverLog("PM_IMAGE = 0x%X", PM_IMAGE);
228
229 IODriverLog("started");
230
231 BCM2708PowerDomain::start();
232 }
233 };
234
235 IODriverCreateSingletonInstance(BCM2708PowerDomainImage);
236
237 /***********************************************************************
238 *
239 * USB power domain.
240 *
241 ***********************************************************************/
242
243 struct BCM2708PowerDomainUSB : BCM2708PowerDomain {
244 IODriverConstructor(BCM2708PowerDomainUSB);
245
246 virtual void init() override {
247 setName("BCM2708PowerDomainUSB");
248 setPmReg(&PM_USB);
249 registerPowerDomain(kCprPowerDomainUSB);
250 }
251
252 virtual void stop() override {
253 IODriverLog("stopping ...");
254
255 PM_USB = PM_PASSWORD;
256 udelay(200000);
257
258 IODriverLog("stopped");
259
260 BCM2708PowerDomain::stop();
261 }
262
263 virtual void start() override {
264 IODriverLog("starting ...");
265
266 PM_USB |= PM_PASSWORD | PM_USB_CTRLEN_SET;
267 udelay(600);
268
269 IODriverLog("started");
270
271 BCM2708PowerDomain::start();
272 }
273 };
274
275 IODriverCreateSingletonInstance(BCM2708PowerDomainUSB);
276
277 /***********************************************************************
278 *
279 * ARM power domain.
280 *
281 ***********************************************************************/
282
283 struct BCM2708PowerDomainARM : BCM2708PowerDomain {
284 IODriverConstructor(BCM2708PowerDomainARM);
285
286 virtual void init() override {
287 setName("BCM2708PowerDomainARM");
288 setPmReg(&PM_PROC);
289 rstnMask = PM_PROC_ARMRSTN_CLR;
290 registerPowerDomain(kCprPowerDomainARM);
291 }
292
293 virtual void stop() override {
294 panic("this power domain cannot be stopped");
295 }
296
297 virtual void start() override {
298 IODriverLog("starting ...");
299
300 cpr_power_result_t res = powerOn();
301
302 if (res != kCprSuccess)
303 panic("%s failed to start the ARM power domain", driverName);
304
305 IODriverLog("started");
306
307 BCM2708PowerDomain::start();
308 }
309 };
310
311 IODriverCreateSingletonInstance(BCM2708PowerDomainARM);
312
This page took 0.117243 seconds and 4 git commands to generate.