]> git.lizzy.rs Git - plan9front.git/blob - sys/src/9/bitsy/power.c
merge
[plan9front.git] / sys / src / 9 / bitsy / power.c
1 #include        "u.h"
2 #include        "../port/lib.h"
3 #include        "mem.h"
4 #include        "dat.h"
5 #include        "fns.h"
6 #include        "io.h"
7 #include        "ureg.h"
8 #include        "pool.h"
9
10 /* Power management for the bitsy */
11
12 #define TODFREQ 1000000000LL
13
14 /* saved state during power down. 
15  * it's only used up to 164/4.
16  * it's only used by routines in l.s
17  */
18 ulong   power_state[200/4];
19
20 ulong   resumeaddr[1];
21 Rendez  powerr;
22 ulong   powerflag = 0;  /* set to start power-off sequence */
23
24 extern void     power_resume(void);
25 extern int              setpowerlabel(void);
26 extern void     _start(void);
27 extern Uart     sa1110uart[];
28
29 GPIOregs savedgpioregs;
30 Intrregs savedintrregs;
31
32 #define R(p) ((Uartregs*)((p)->regs))
33
34 uchar *savedtext;
35
36 static void
37 checkflash(void)
38 {
39         ulong *p;
40         ulong s;
41
42         s = 0;
43         for (p = (ulong*)FLASHZERO; p < (ulong*)(FLASHZERO+8*1024*1024); p++)
44                 s += *p;
45         iprint("flash checksum is 0x%lux\n", s);
46 }
47
48 static void
49 checkktext(void)
50 {
51         ulong *p;
52         ulong s;
53
54         s = 0;
55         for (p = (ulong*)_start; p < (ulong*)etext; p++){
56                 if(*p == 0)
57                         iprint("%#p->0\n", p);
58                 if (((ulong)p & 0x1fff) == 0){
59                         iprint("page 0x%lux checksum 0x%lux\n",
60                                 (ulong)(p-1)&~0x1fff, s);
61                         s = 0;
62                 }
63                 s += *p;
64         }
65         iprint("page 0x%lux checksum 0x%lux\n", (ulong)(p-1)&~0x1fff, s);
66 }
67
68 static void
69 checkpagetab(void)
70 {
71         extern ulong l1table;
72         ulong *p;
73         ulong s;
74
75         s = 0;
76         for (p = (ulong*)l1table; p < (ulong*)(l1table+16*1024); p++)
77                 s += *p;
78         iprint("page table checksum is 0x%lux\n", s);
79 }
80
81
82 static void
83 dumpitall(void)
84 {
85         extern ulong l1table;
86
87         iprint("intr: icip %lux iclr %lux iccr %lux icmr %lux\n",
88                 intrregs->icip,
89                 intrregs->iclr, intrregs->iccr, intrregs->icmr );
90         iprint("gpio: lvl %lux dir %lux, re %lux, fe %lux sts %lux alt %lux\n",
91                 gpioregs->level,
92                 gpioregs->direction, gpioregs->rising, gpioregs->falling,
93                 gpioregs->edgestatus, gpioregs->altfunc);
94         iprint("uart1: %lux %lux %lux \nuart3: %lux %lux %lux\n", 
95                 R(&sa1110uart[0])->ctl[0], R(&sa1110uart[0])->status[0], R(&sa1110uart[0])->status[1], 
96                 R(&sa1110uart[1])->ctl[0], R(&sa1110uart[1])->status[0], R(&sa1110uart[1])->status[1]); 
97         iprint("tmr: osmr %lux %lux %lux %lux oscr %lux ossr %lux oier %lux\n",
98                 timerregs->osmr[0], timerregs->osmr[1],
99                 timerregs->osmr[2], timerregs->osmr[3],
100                 timerregs->oscr, timerregs->ossr, timerregs->oier);
101         iprint("dram: mdcnfg %lux mdrefr %lux cas %lux %lux %lux %lux %lux %lux\n",
102                 memconfregs->mdcnfg, memconfregs->mdrefr,
103                 memconfregs->mdcas00, memconfregs->mdcas01,memconfregs->mdcas02,
104                 memconfregs->mdcas20, memconfregs->mdcas21,memconfregs->mdcas22); 
105         iprint("dram: mdcnfg msc %lux %lux %lux mecr %lux\n",
106                 memconfregs->msc0, memconfregs->msc1,memconfregs->msc2,
107                 memconfregs->mecr);
108         iprint("mmu: CpControl %lux CpTTB %lux CpDAC %lux l1table 0x%lux\n",
109                 getcontrol(), getttb(), getdac(), l1table);
110         iprint("powerregs: pmcr %lux pssr %lux pcfr %lux ppcr %lux pwer %lux pspr %lux pgsr %lux posr %lux\n",
111                 powerregs->pmcr, powerregs->pssr, powerregs->pcfr, powerregs->ppcr,
112                 powerregs->pwer, powerregs->pspr, powerregs->pgsr, powerregs->posr);
113         checkpagetab();
114         checkflash();
115         checkktext();
116         iprint("\n\n");
117 }
118
119 static void
120 intrcpy(Intrregs *to, Intrregs *from)
121 {
122         to->iclr = from->iclr;
123         to->iccr = from->iccr;
124         to->icmr = from->icmr;  // interrupts enabled
125 }
126
127 static void
128 gpiosave(GPIOregs *to, GPIOregs *from)
129 {
130         to->level = from->level;
131         to->rising = from->rising;              // gpio intrs enabled
132         to->falling= from->falling;             // gpio intrs enabled
133         to->altfunc = from->altfunc;
134         to->direction = from->direction;
135 }
136
137 static void
138 gpiorestore(GPIOregs *to, GPIOregs *from)
139 {
140         to->direction = from->direction;
141         to->altfunc = from->altfunc;
142         to->set = from->level & 0x0fffffff;
143         to->clear = ~from->level & 0x0fffffff;
144         to->rising = from->rising;              // gpio intrs enabled
145         to->falling= from->falling;             // gpio intrs enabled
146 }
147
148 void    (*restart)(void) = nil;
149
150 static int
151 bitno(ulong x)
152 {
153         int i;
154
155         for(i = 0; i < 8*sizeof(x); i++)
156                 if((1<<i) & x)
157                         break;
158         return i;
159 }
160
161 int
162 powerdown(void *)
163 {
164         return powerflag;
165 }
166
167 void
168 deepsleep(void) {
169         static int power_pl;
170         ulong xsp, xlink;
171 //      ulong mecr;
172         ulong clkd;
173         vlong savedtod;
174         extern void power_resume(void);
175
176         power_pl = splhi();
177         xlink = getcallerpc(&xlink);
178
179         /* Power down */
180         pcmciapower(0);
181         irpower(0);
182         audiopower(0);
183         screenpower(0);
184         µcpower(0);
185         iprint("entering suspend mode, sp = %#p, pc = 0x%lux, psw = 0x%ux\n",
186                 &xsp, xlink, power_pl);
187 //      dumpitall();
188         delay(1000);
189         uartpower(0);
190         rs232power(0);
191         clockpower(0);
192         gpiosave(&savedgpioregs, gpioregs);
193         intrcpy(&savedintrregs, intrregs);
194         cacheflush();
195         delay(50);
196         if(setpowerlabel()){
197                 /* return here with mmu back on */
198                 trapresume();
199
200                 gpiorestore(gpioregs, &savedgpioregs);
201                 delay(50);
202                 intrcpy(intrregs, &savedintrregs);
203                 if(intrregs->icip & (1<<IRQgpio0)){
204                         // don't want to sleep now. clear on/off irq.
205                         gpioregs->edgestatus = (1<<IRQgpio0);
206                         intrregs->icip = (1<<IRQgpio0);
207                 }
208                 clkd = clockpower(1);
209                 gpclkregs->r0 = 1<<0;
210                 todset(savedtod + clkd * TODFREQ, 0LL, 0);
211                 resetsuspendtimer();
212                 rs232power(1);
213                 uartpower(1);
214                 delay(100);
215                 xlink = getcallerpc(&xlink);
216                 iprint("\nresuming execution, sp = %#p, pc = 0x%lux, psw = 0x%ux\n",
217                         &xsp, xlink, splhi());
218 //              dumpitall();
219                 delay(1000);
220 //              irpower(1);
221                 audiopower(1);
222                 µcpower(1);
223                 screenpower(1);
224                 pcmciapower(1);
225                 splx(power_pl);
226                 return;
227         }
228         cacheflush();
229         delay(100);
230         savedtod = todget(nil);
231         power_down();
232         /* no return */
233 }
234
235 void
236 powerkproc(void*)
237 {
238         ulong xlink, xlink1;
239
240         for(;;){
241                 while(powerflag == 0)
242                         sleep(&powerr, powerdown, 0);
243
244                 xlink = getcallerpc(&xlink);
245
246 //              iprint("call deepsleep, pc = 0x%lux, sp = 0x%lux\n", xlink, &xlink);
247                 deepsleep();
248                 xlink1 = getcallerpc(&xlink1);
249
250
251                 delay(2000);
252
253 //              iprint("deepsleep returned, pc = 0x%lux, sp = 0x%lux\n", xlink1, &xlink);
254                 powerflag = 0;
255         }
256 }
257
258 void
259 onoffintr(Ureg* , void*)
260 {
261         int i;
262
263         /* Power down interrupt comes on power button release.
264          * Act only after button has been released a full 100 ms
265          */
266
267         if (powerflag)
268                 return;
269
270         for (i = 0; i < 100; i++) {
271                 delay(1);
272                 if ((gpioregs->level & GPIO_PWR_ON_i) == 0)
273                         return; /* bounced */
274         }
275
276         powerflag = 1;
277         wakeup(&powerr);
278 }
279
280 static void
281 blanktimer(void)
282 {
283         drawactive(0);
284 }
285
286 static ulong suspendtime = 120 * HZ;
287 static int lastsuspend;
288
289 void
290 resetsuspendtimer(void)
291 {
292         suspendtime = 60 * HZ;
293 }
294
295 static void
296 suspendtimer(void)
297 {
298 #ifdef notdef
299         uvlong  now;
300
301         if (suspendtime > 0)
302                 suspendtime--;
303         if (suspendtime == 0){
304                 now = seconds();
305                 if (now < lastsuspend + 10){
306                         resetsuspendtimer();
307                         return;
308                 }
309                 lastsuspend = seconds();
310                 deepsleep();
311                 lastsuspend = seconds();
312                 return;
313         }
314 #endif /* notdef */
315 }
316
317 void
318 powerinit(void)
319 {
320         extern ulong power_magic;
321         extern ulong power_code;
322         extern ulong doze_code;
323         ulong *p, *q, i;
324
325         p = (ulong*)(((ulong)&power_magic + 0x1f) & ~0x1f);
326         q = &power_code;
327         for (i = 0; i < 8; i++)
328                 *p++ = *q++;
329         p = (ulong*)(((ulong)doze + 0x3f) & ~0x1f);
330         q = &doze_code;
331         for (i = 0; i < 3; i++)
332                 *p++ = *q++;
333
334         *resumeaddr = (ulong) power_resume;
335         addclock0link(blanktimer, 1000/HZ);
336         addclock0link(suspendtimer, 1000/HZ);
337         intrenable(GPIOrising, bitno(GPIO_PWR_ON_i), onoffintr, nil, "on/off");
338 }
339
340 void
341 idlehands(void)
342 {
343         char *msgb = "idlehands called with splhi\n";
344         char *msga = "doze returns with splhi\n";
345
346         if(!islo()){
347                 uartputs(msga, strlen(msga));
348                 spllo();
349         }
350         doze();
351         if(!islo()){
352                 uartputs(msgb, strlen(msgb));
353                 spllo();
354         }
355 }
356