power.c 7.2 KB

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