diff options
Diffstat (limited to 'os/sa1110/suspend.c')
| -rw-r--r-- | os/sa1110/suspend.c | 161 |
1 files changed, 161 insertions, 0 deletions
diff --git a/os/sa1110/suspend.c b/os/sa1110/suspend.c new file mode 100644 index 00000000..873e23cb --- /dev/null +++ b/os/sa1110/suspend.c @@ -0,0 +1,161 @@ +#include "u.h" +#include "../port/lib.h" +#include "mem.h" +#include "dat.h" +#include "fns.h" +#include "io.h" +#include "ureg.h" + +/* + * Originally written by nemo@gsyc.escet.urjc.es, and + * reworked by forsyth@vitanuova.com + */ +enum { + DEBUG = 0, +}; + +/* + * TO DO: pcmcia, lcd properly + */ + +/* + * it's not clear yet whether we should do it this way, + * or using powerenable/powerdisable + */ +void +chandevpower(int up) +{ + int i; + + if(up){ + for(i=0; devtab[i] != nil; i++) + if(devtab[i]->power != nil) + devtab[i]->power(1); + }else{ + /* power down in reverse order */ + for(i=0; devtab[i] != nil; i++) + ; + while(--i >= 0) + if(devtab[i]->power != nil) + devtab[i]->power(0); + } +} + +static void +dumpitall(void) +{ + iprint("intr: icip %lux iclr %lux iccr %lux icmr %lux\n", + INTRREG->icip, + INTRREG->iclr, INTRREG->iccr, INTRREG->icmr ); + iprint("gpio: lvl %lux dir %lux, re %lux, fe %lux sts %lux alt %lux\n", + GPIOREG->gplr, + GPIOREG->gpdr, GPIOREG->grer, GPIOREG->gfer, + GPIOREG->gpsr, GPIOREG->gafr); + iprint("uart1: %lux %lux %lux\nuart3: %lux %lux %lux\n", + UARTREG(1)->utcr0, UARTREG(1)->utsr0, UARTREG(1)->utsr1, + UARTREG(3)->utcr0, UARTREG(3)->utsr0, UARTREG(3)->utsr1); + iprint("tmr: osmr %lux %lux %lux %lux oscr %lux ossr %lux oier %lux\n", + OSTMRREG->osmr[0], OSTMRREG->osmr[1], + OSTMRREG->osmr[2], OSTMRREG->osmr[3], + OSTMRREG->oscr, OSTMRREG->ossr, OSTMRREG->oier); + iprint("dram: mdcnfg %lux mdrefr %lux cas %lux %lux %lux %lux %lux %lux\n", + MEMCFGREG->mdcnfg, MEMCFGREG->mdrefr, + MEMCFGREG->mdcas0[0], MEMCFGREG->mdcas0[1],MEMCFGREG->mdcas0[2], + MEMCFGREG->mdcas2[0], MEMCFGREG->mdcas2[1],MEMCFGREG->mdcas2[2]); + iprint("dram: mdcnfg msc %lux %lux %lux mecr %lux\n", + MEMCFGREG->msc0, MEMCFGREG->msc1,MEMCFGREG->msc2, + MEMCFGREG->mecr); +} + +static ulong *coreregs[] = { + /* can't trust the bootstrap to put these back */ + &MEMCFGREG->mecr, + &MEMCFGREG->msc0, + &MEMCFGREG->msc1, + &MEMCFGREG->msc2, + + &PPCREG->ppdr, + &PPCREG->ppsr, /* should save? */ + &PPCREG->ppar, + &PPCREG->psdr, + + &GPIOREG->grer, + &GPIOREG->gfer, + &GPIOREG->gafr, + &GPIOREG->gpdr, + /* gplr handled specially */ + + &GPCLKREG->gpclkr1, + &GPCLKREG->gpclkr2, + &GPCLKREG->gpclkr0, + + &OSTMRREG->osmr[0], + &OSTMRREG->osmr[1], + &OSTMRREG->osmr[2], + &OSTMRREG->osmr[3], + &OSTMRREG->oscr, + &OSTMRREG->oier, + /* skip ower */ + + &INTRREG->iclr, + &INTRREG->iccr, + &INTRREG->icmr, /* interrupts enabled */ + + nil, +}; + +static ulong corestate[nelem(coreregs)]; + +void +powersuspend(void) +{ + extern void suspenditall(void); + GpioReg *g; + ulong back = 0x43219990; /* check that the stack's right */ + ulong pwer, gplr; + ulong *rp; + int i, s; + + s = splfhi(); + archpowerdown(); /* sets PMGR and PPC appropriately */ + if(DEBUG) + dumpitall(); + blankscreen(1); + chandevpower(0); + gplr = GPIOREG->gplr; + for(i=0; (rp = coreregs[i]) != nil; i++) + corestate[i] = *rp; + pwer = PMGRREG->pwer; + if(pwer == 0) + pwer = 1<<0; + g = GPIOREG; + g->grer &= pwer; /* just the ones archpowerdown requested */ + g->gfer &= pwer; + g->gedr = g->gedr; + RESETREG->rcsr = 0xF; /* reset all status */ + minidcflush(); + if(DEBUG) + iprint("suspenditall...\n"); + + suspenditall(); /* keep us in suspense */ + + PMGRREG->pspr = 0; + archpowerup(); + trapstacks(); + /* set output latches before gpdr restored */ + GPIOREG->gpsr = gplr; + GPIOREG->gpcr = ~gplr; + for(i=0; (rp = coreregs[i]) != nil; i++) + *rp = corestate[i]; + GPIOREG->gedr = GPIOREG->gedr; /* reset GPIO interrupts (should we?) */ + PMGRREG->pssr = PSSR_ph; /* cancel peripheral hold */ + chandevpower(1); + if(back != 0x43219990){ + iprint("back %8.8lux\n", back); + panic("powersuspend"); + } + blankscreen(0); + if(DEBUG) + dumpitall(); + splx(s); +} |
