~kris/9p

9hist

617f6d975acf4b1b6060d389fb60de9a33eefbd6 — David du Colombier 25 years ago 7e31ac8
Plan 9 from Bell Labs 2001-06-18
M bitsy/clock.c => bitsy/clock.c +12 -1
@@ 16,12 16,23 @@ typedef struct OSTimer
	ulong	oier;		/* timer interrupt enable register */
} OSTimer;

static OSTimer *timerregs = (OSTimer*)OSTIMERREGS;
OSTimer *timerregs = (OSTimer*)OSTIMERREGS;
static int clockinited;

static void	clockintr(Ureg*, void*);

void
clockpower(int on)
{

	if (on){
		timerregs->ossr |= 1<<0;
		timerregs->oier = 1<<0;
		timerregs->osmr[0] = timerregs->oscr + ClockFreq/HZ;
	}
}

void
clockinit(void)
{
	ulong x;

M bitsy/devµc.c => bitsy/devµc.c +14 -0
@@ 379,6 379,20 @@ static long
	return n;
}

void 
µcpower(int on)
{
	uchar data[16];
	if (on == 0)
		return;
	/* maybe dangerous, not holding the lock */
	data[0]= 2;
	data[1]= 1;
	data[2]= 0x80;
	_sendmsg(0xd, data, 3);
	wakeup(&ctlr.r);
}

Dev µcdevtab = {
	'r',
	"µc",

M bitsy/fns.h => bitsy/fns.h +5 -0
@@ 9,10 9,12 @@ void	dcacheinvalidate(void);
int	cistrcmp(char*, char*);
int	cistrncmp(char*, char*, int);
void	clockinit(void);
void	clockpower(int);
#define	coherence()
#define	dcflush(a, b)
void	delay(int);
void	µdelay(ulong);
void	µcpower(int);
void	dmainit(void);
void	_doze(void);
void	(*doze)(void);


@@ 67,6 69,7 @@ PCMmap*	pcmmap(int, ulong, int, int);
void	pcmunmap(int, PCMmap*);
void	penbutton(int, int);
void	pentrackxy(int x, int y);
void	powerinit(void);
#define	procrestore(p)
void	procsave(Proc*);
void	procsetup(Proc*);


@@ 78,6 81,7 @@ void	rs232power(int);
void	uartspecial(Uart*, int, Queue**, Queue**, int (*)(Queue*, int));
void	sa1110_uartsetup(int);
void	screeninit(void);
void	screenpower(int);
int	screenprint(char*, ...);			/* debugging */
void	serialµcputs(uchar *str, int n);
void	setr13(int, ulong*);


@@ 85,6 89,7 @@ uchar*	tarlookup(uchar*, char*, int*);
void	touser(void*);
void	trapdump(char *tag);
void	trapinit(void);
void	trapresume(void);
int	tas(void*);
int	uartstageoutput(Uart*);
void	uartkick(void*);

M bitsy/io.h => bitsy/io.h +69 -1
@@ 130,7 130,8 @@ struct Uartregs
	ulong	dummyb;
	ulong	status[2];
};
Uartregs *uart3regs;
extern Uartregs *uart3regs;
extern Uartregs *uart1regs;

/* general purpose I/O lines control registers */
typedef struct GPIOregs GPIOregs;


@@ 246,6 247,17 @@ extern MemConfRegs *memconfregs;
/*
 *  power management
 */

/* Power management ops */
enum {
	PCFR_suspend	= 1,

	PCFR_opde	= 1,
	PCFR_fp		= 2,
	PCFR_fs		= 4,
	PCFR_fo		= 8,
};

typedef struct PowerRegs PowerRegs;
struct PowerRegs
{


@@ 259,3 271,59 @@ struct PowerRegs
	ulong	posr;	/* Power manager oscillator status register */
};
extern PowerRegs *powerregs;

/*
 *  reset controller
 */

enum 
{
	RCSR_hwr = 0x00000001,	/* hw reset */
	RCSR_swr = 0x00000002,	/* sw reset */
	RCSR_wdr = 0x00000004,	/* watch dog */
	RCSR_smr = 0x00000008,	/* sleep mode reset */
	RCSR_all = 0x0000000f,
};

typedef struct ResetRegs ResetRegs;
struct ResetRegs
{
	ulong	rsrr;	/* reset controller software reset register */
	ulong	rcsr;	/* reset controller status register */
};
extern ResetRegs *resetregs;

typedef  struct OSTimerRegs OSTimerRegs;
struct OSTimerRegs
{
	ulong	osmr[4];	/* match registers */
	ulong	oscr;		/* counter register */
	ulong	ossr;		/* status register */
	ulong	ower;		/* watchdog enable register */
	ulong	oier;		/* timer interrupt enable register */
};
extern OSTimerRegs* timerregs;

typedef struct Intrregs Intrregs;
struct Intrregs
{
	ulong	icip;	/* pending IRQs */
	ulong	icmr;	/* IRQ mask */
	ulong	iclr;	/* IRQ if bit == 0, FRIQ if 1 */
	ulong	iccr;	/* control register */
	ulong	icfp;	/* pending FIQs */
	ulong	dummy1[3];
	ulong	icpr;	/* pending interrupts */
};
extern Intrregs *intrregs;

typedef struct Gpclkregs Gpclkregs;
struct Gpclkregs
{
	ulong	r0;
	ulong	r1;
	ulong	dummya;
	ulong	r2;
	ulong	r3;
};
extern Gpclkregs *gpclkregs;

M bitsy/l.s => bitsy/l.s +182 -0
@@ 443,6 443,188 @@ TEXT gotolabel(SB), $-4
	MOVW	$1, R0
	RET

/* save the state machine in power_resume[] for an upcoming suspend
 */
TEXT setpowerlabel(SB), $-4
	MOVW	$power_resume+0(SB), R0
	/* svc */				/* power_resume[]: what */
	MOVW		R1, 0(R0)
	MOVW		R2, 4(R0)
	MOVW		R3, 8(R0)
	MOVW		R4, 12(R0)
	MOVW		R5, 16(R0)
	MOVW		R6, 20(R0)
	MOVW		R7, 24(R0)
	MOVW		R8, 28(R0)
	MOVW		R9, 32(R0)
	MOVW		R10,36(R0)
	MOVW		R11,40(R0)
	MOVW		R12,44(R0)
	MOVW		R13,48(R0)
	MOVW		R14,52(R0)
	MOVW		SPSR, R1
	MOVW		R1, 56(R0)
	MOVW		CPSR, R2
	MOVW		R2, 60(R0)
	/* copro */
	MRC		CpMMU, 0, R3, C(CpDAC), C(0x0)
	MOVW		R3, 144(R0)
	MRC		CpMMU, 0, R3, C(CpTTB), C(0x0)
	MOVW		R3, 148(R0)
	MRC		CpMMU, 0, R3, C(CpControl), C(0x0)
	MOVW		R3, 152(R0)
	MRC		CpMMU, 0, R3, C(CpFSR), C(0x0)
	MOVW		R3, 156(R0)
	MRC		CpMMU, 0, R3, C(CpFAR), C(0x0)
	MOVW		R3, 160(R0)
	MRC		CpMMU, 0, R3, C(CpPID), C(0x0)
	MOVW		R3, 164(R0)
	/* irq */
	BIC		$(PsrMask), R2, R3
	ORR		$(PsrDirq|PsrMirq), R3
	MOVW		R3, CPSR
	MOVW		SPSR, R11
	MOVW		R11, 64(R0)
	MOVW		R12, 68(R0)
	MOVW		R13, 72(R0)
	MOVW		R14, 76(R0)
	/* und */
	BIC		$(PsrMask), R2, R3
	ORR		$(PsrDirq|PsrMund), R3
	MOVW		R3, CPSR
	MOVW		SPSR, R11
	MOVW		R11, 80(R0)
	MOVW		R12, 84(R0)
	MOVW		R13, 88(R0)
	MOVW		R14, 92(R0)
	/* abt */
	BIC		$(PsrMask), R2, R3
	ORR		$(PsrDirq|PsrMabt), R3
	MOVW		R3, CPSR
	MOVW		SPSR, R11
	MOVW		R11, 96(R0)
	MOVW		R12, 100(R0)
	MOVW		R13, 104(R0)
	MOVW		R14, 108(R0)
	/* fiq */
	BIC		$(PsrMask), R2, R3
	ORR		$(PsrDirq|PsrMfiq), R3
	MOVW		R3, CPSR
	MOVW		SPSR, R7
	MOVW		R7, 112(R0)
	MOVW		R8, 116(R0)
	MOVW		R9, 120(R0)
	MOVW		R10,124(R0)
	MOVW		R11,128(R0)
	MOVW		R12,132(R0)
	MOVW		R13,136(R0)
	MOVW		R14,140(R0)
	/* done */
	MOVW		R2, CPSR
	MOVW		R1, SPSR
	MOVW		$0, R0
	RET

/* Entered after a resume from suspend state.
 * The bootldr jumps here after a processor reset.
 */ 
TEXT sa1100_power_resume(SB), $-4
	MOVW	$setR12(SB), R12		/* load the SB */
	/* SVC mode, interrupts disabled */
	MOVW	$(PsrDirq|PsrDfiq|PsrMsvc), R1
	MOVW	R1, CPSR
	/* flush caches */
	MCR	CpMMU, 0, R0, C(CpCacheFlush), C(0x7), 0
	/* drain prefetch */
	MOVW	R0,R0						
	MOVW	R0,R0
	MOVW	R0,R0
	MOVW	R0,R0
	/* drain write buffer */
	MCR	CpMMU, 0, R0, C(CpCacheFlush), C(0xa), 4
	/* gotopowerlabel() */
	/* svc */
	MOVW	$power_resume+0(SB), R0
	MOVW	56(R0), R1		/* R1: SPSR, R2: CPSR */
	MOVW	60(R0), R2
	/* copro */
	MOVW		148(R0), R3
	MCR		CpMMU, 0, R3, C(CpTTB), C(0x0)
	MOVW		144(R0), R3
	MCR		CpMMU, 0, R3, C(CpDAC), C(0x0)
	MOVW		152(R0), R3
	MCR		CpMMU, 0, R3, C(CpControl), C(0x0)
	MOVW		156(R0), R3
	MCR		CpMMU, 0, R3, C(CpFSR), C(0x0)
	MOVW		160(R0), R3
	MCR		CpMMU, 0, R3, C(CpFAR), C(0x0)
	MOVW		164(R0), R3
	MCR		CpMMU, 0, R3, C(CpPID), C(0x0)
	MCR		CpMMU, 0, R0, C(CpTLBFlush), C(0x7)
	/* irq */
	BIC	$(PsrMask), R2, R3
	ORR	$(PsrDirq|PsrMirq), R3
	MOVW	R3, CPSR
	MOVW	64(R0), R11
	MOVW	68(R0), R12
	MOVW	72(R0), R13
	MOVW	76(R0), R14
	MOVW	R11, SPSR
	/* und */
	BIC	$(PsrMask), R2, R3
	ORR	$(PsrDirq|PsrMund), R3
	MOVW	R3, CPSR
	MOVW	80(R0), R11
	MOVW	84(R0), R12
	MOVW	88(R0), R13
	MOVW	92(R0), R14
	MOVW	R11, SPSR
	/* abt */
	BIC	$(PsrMask), R2, R3
	ORR	$(PsrDirq|PsrMabt), R3
	MOVW	R3, CPSR
	MOVW	96(R0), R11
	MOVW	100(R0), R12
	MOVW	104(R0), R13
	MOVW	108(R0), R14
	MOVW	R11, SPSR
	/* fiq */
	BIC	$(PsrMask), R2, R3
	ORR	$(PsrDirq|PsrMfiq), R3
	MOVW	R3, CPSR
	MOVW	112(R0), R7
	MOVW	116(R0), R8
	MOVW	120(R0), R9
	MOVW	124(R0), R10
	MOVW	128(R0), R11
	MOVW	132(R0), R12
	MOVW	136(R0), R13
	MOVW	140(R0), R14
	MOVW	R7, SPSR
	/* svc */
	MOVW	56(R0), R1
	MOVW	60(R0), R2
	MOVW	R1, SPSR
	MOVW	R2, CPSR
	MOVW	0(R0), R1
	MOVW	4(R0), R2
	MOVW	8(R0), R3
	MOVW	12(R0),R4
	MOVW	16(R0),R5
	MOVW	20(R0),R6
	MOVW	24(R0),R7
	MOVW	28(R0),R8
	MOVW	32(R0),R9
	MOVW	36(R0),R10
	MOVW	40(R0),R11
	MOVW	44(R0),R12
	MOVW	48(R0),R13
	MOVW	52(R0),R14
	RET
loop:
	B	loop



/* The first MCR instruction of this function needs to be on a cache-line
 * boundary; to make this happen, it will be copied (in trap.c).

M bitsy/main.c => bitsy/main.c +6 -0
@@ 37,6 37,7 @@ main(void)
	trapinit();
	sa1110_uartsetup(1);
	rs232power(1);
	powerinit();
	dmainit();
	screeninit();
	printinit();	/* from here on, print works, before this we need iprint */


@@ 362,6 363,8 @@ ulong *egpioreg = (ulong*)EGPIOREGS;
PPCregs *ppcregs;
MemConfRegs *memconfregs;
PowerRegs *powerregs;
ResetRegs *resetregs;
OSTimerRegs *timerregs = (OSTimerRegs*)OSTIMERREGS;

/*
 *  configure the machine


@@ 395,6 398,9 @@ machinit(void)

	/* memory configuraton */
	memconfregs = mapspecial(MEMCONFREGS, 32);

	/* reset controller */
	resetregs = mapspecial(RESETREGS, 32);
}



M bitsy/mem.h => bitsy/mem.h +23 -22
@@ 6,23 6,23 @@
 * Sizes
 */
#define	BI2BY		8			/* bits per byte */
#define BI2WD		32			/* bits per word */
#define	BI2WD		32			/* bits per word */
#define	BY2WD		4			/* bytes per word */
#define	BY2V		8			/* bytes per double word */
#define	BY2PG		4096			/* bytes per page */
#define	WD2PG		(BY2PG/BY2WD)		/* words per page */
#define	PGSHIFT		12			/* log(BY2PG) */
#define ROUND(s, sz)	(((s)+(sz-1))&~(sz-1))
#define PGROUND(s)	ROUND(s, BY2PG)
#define	ROUND(s, sz)	(((s)+(sz-1))&~(sz-1))
#define	PGROUND(s)	ROUND(s, BY2PG)
#define	BLOCKALIGN	8

#define	MAXMACH		1			/* max # cpus system can run */
#define	MAXMACH	1			/* max # cpus system can run */

/*
 * Time
 */
#define	HZ		(20)				/* clock frequency */
#define	MS2HZ		(1000/HZ)			/* millisec per clock tick */
#define	MS2HZ	(1000/HZ)		/* millisec per clock tick */
#define	TK2SEC(t)	((t)/HZ)			/* ticks to seconds */
#define	TK2MS(t)	((((ulong)(t))*1000)/HZ)	/* ticks to milliseconds */
#define	MS2TK(t)	((((ulong)(t))*HZ)/1000)	/* milliseconds to ticks */


@@ 41,8 41,8 @@
 *  kernel.  This can be changed by providing a mapping in l.s
 *  before calling main.
 */
#define	UZERO		0			/* base of user address space */
#define	UTZERO		(UZERO+BY2PG)		/* first address in user text */
#define	UZERO		0				/* base of user address space */
#define	UTZERO		(UZERO+BY2PG)	/* first address in user text */
#define	KZERO		0xC0000000		/* base of kernel address space */
#define	KTZERO		0xC0008000		/* first address in kernel text */
#define	EMEMZERO	0x90000000		/* 256 meg for add on memory */


@@ 52,19 52,19 @@
#define	FLASHZERO	0xB0000000		/* 128 meg for flash */
#define	FLASHTOP	0xB8000000		/* ... */
#define	DRAMZERO	0xC0000000		/* 128 meg for dram */
#define DRAMTOP		0xC8000000		/* ... */
#define	DRAMTOP		0xC8000000		/* ... */
#define	UCDRAMZERO	0xC8000000		/* 128 meg for dram (uncached/unbuffered) */
#define UCDRAMTOP	0xD0000000		/* ... */
#define	UCDRAMTOP	0xD0000000		/* ... */
#define	NULLZERO	0xE0000000		/* 128 meg for cache flush zeroes */
#define NULLTOP		0xE8000000		/* ... */
#define	NULLTOP		0xE8000000		/* ... */
#define	USTKTOP		0x2000000		/* byte just beyond user stack */
#define	USTKSIZE	(8*1024*1024)		/* size of user stack */
#define	USTKSIZE		(8*1024*1024)		/* size of user stack */
#define	TSTKTOP		(USTKTOP-USTKSIZE)	/* end of new stack in sysexec */
#define TSTKSIZ 	100
#define MACHADDR	(KZERO+0x00001000)
#define	TSTKSIZ	 	100
#define	MACHADDR	(KZERO+0x00001000)
#define	EVECTORS	0xFFFF0000		/* virt base of exception vectors */

#define KSTACK		(32*1024)		/* Size of kernel stack */
#define	KSTACK		(16*1024)			/* Size of kernel stack */

/*
 *  Offsets into flash


@@ 97,17 97,18 @@
 *  peripheral control module physical addresses
 */
#define USBREGS		0x80000000	/* serial port 0 - USB */
#define UART1REGS	0x80010000	/* serial port 1 - UART */
#define GPCLKREGS	0x80020060	/* serial port 1 - general purpose clock */
#define UART2REGS	0x80030000	/* serial port 2 - low speed IR */
#define HSSPREGS	0x80040060	/* serial port 2 - high speed IR */
#define UART3REGS	0x80050000	/* serial port 3 - RS232 UART */
#define UART1REGS		0x80010000	/* serial port 1 - UART */
#define GPCLKREGS		0x80020060	/* serial port 1 - general purpose clock */
#define UART2REGS		0x80030000	/* serial port 2 - low speed IR */
#define HSSPREGS		0x80040060	/* serial port 2 - high speed IR */
#define UART3REGS		0x80050000	/* serial port 3 - RS232 UART */
#define MCPREGS		0x80060000	/* serial port 4 - multimedia comm port */
#define SSPREGS		0x80070060	/* serial port 4 - synchronous serial port */
#define OSTIMERREGS	0x90000000	/* operating system timer registers */
#define POWERREGS	0x90020000	/* power management */
#define GPIOREGS	0x90040000	/* 28 general purpose IO pins */
#define INTRREGS	0x90050000	/* interrupt registers */
#define POWERREGS		0x90020000	/* power management */
#define RESETREGS		0x90030000	/* reset controller */
#define GPIOREGS		0x90040000	/* 28 general purpose IO pins */
#define INTRREGS		0x90050000	/* interrupt registers */
#define PPCREGS		0x90060000	/* peripheral pin controller */
#define MEMCONFREGS	0xA0000000	/* memory configuration */
#define LCDREGS		0xB0100000	/* display */

M bitsy/power.c => bitsy/power.c +152 -35
@@ 9,73 9,188 @@

/* Power management for the bitsy */

#ifdef NOTDEF
enum {
	pmcr_sf		= 0,
/* saved state during power down. 
 * it's only used up to 164/4.
 * it's only used by routines in l.s
 */
ulong power_resume[200/4];

	pcfr_opde	= 0,
	pcfr_fp		= 1,
	pcfr_fs		= 2,
	pcfr_fo		= 3,
};
extern void sa1100_power_resume(void);
extern int setpowerlabel(void);


GPIOregs savedgpioregs;
Uartregs saveduart3regs;
Uartregs saveduart1regs;
Intrregs savedintrregs;

jmp_buf power_resume;

static void
onoffintr(Ureg*, void *x)
dumpitall(void)
{
	/* On/off button interrupt */
	int i;
	iprint("intr: icip %lux iclr %lux iccr %lux icmr %lux\n",
		intrregs->icip,
		intrregs->iclr, intrregs->iccr, intrregs->icmr );
	iprint("gpio: lvl %lux dir %lux, re %lux, fe %lux sts %lux alt %lux\n",
		gpioregs->level,
		gpioregs->direction, gpioregs->rising, gpioregs->falling,
		gpioregs->edgestatus, gpioregs->altfunc);
	iprint("uart1: %lux %lux %lux \nuart3: %lux %lux %lux\n", 
		uart1regs->ctl[0], uart1regs->status[0], uart1regs->status[1], 
		uart3regs->ctl[0], uart3regs->status[0], uart3regs->status[1]); 
	iprint("tmr: osmr %lux %lux %lux %lux oscr %lux ossr %lux oier %lux\n",
		timerregs->osmr[0], timerregs->osmr[1],
		timerregs->osmr[2], timerregs->osmr[3],
		timerregs->oscr, timerregs->ossr, timerregs->oier);
	iprint("dram: mdcnfg %lux mdrefr %lux cas %lux %lux %lux %lux %lux %lux\n",
		memconfregs->mdcnfg, memconfregs->mdrefr,
		memconfregs->mdcas00, memconfregs->mdcas01,memconfregs->mdcas02,
		memconfregs->mdcas20, memconfregs->mdcas21,memconfregs->mdcas22); 
	iprint("dram: mdcnfg msc %lux %lux %lux mecr %lux\n",
		memconfregs->msc0, memconfregs->msc1,memconfregs->msc2,
		memconfregs->mecr);

	
}

static void
intrcpy(Intrregs *to, Intrregs *from)
{
	to->iclr = from->iclr;
	to->iccr = from->iccr;
	to->icmr = from->icmr;	// interrupts enabled
}

static  void
uartcpy(Uartregs *to, Uartregs *from)
{
	to->ctl[0] = from->ctl[0];
//	to->ctl[1] = from->ctl[1];
//	to->ctl[2] = from->ctl[2];
	to->ctl[3] = from->ctl[3];

}

static void
gpiocpy(GPIOregs *to, GPIOregs *from)
{
	to->rising = from->rising;		// gpio intrs enabled
	to->falling= from->falling;		// gpio intrs enabled
	to->altfunc = from->altfunc;
	to->direction = from->direction;
}

static void
sa1100_power_off(void)
{
	/* enable wakeup by µcontroller, on/off switch or real-time clock alarm */
	powerregs->pwer =  1 << IRQrtc | 1 << IRQgpio0 | 1 << IRQgpio1;

	/* clear previous reset status */
	resetregs->rcsr =  RCSR_all;

	/* disable internal oscillator, float CS lines */
	powerregs->pcfr = PCFR_opde | PCFR_fp | PCFR_fs;
	powerregs->pgsr = 0;
	/* set resume address. The loader jumps to it */
	powerregs->pspr = (ulong)sa1100_power_resume;
	/* set lowest clock; delay to avoid resume hangs on fast sa1110 */
	delay(90);
	powerregs->ppcr = 0;
	delay(90);

	/* set all GPIOs to input mode  */
	gpioregs->direction = 0;
	delay(100);
	/* enter sleep mode */
	powerregs->pmcr = PCFR_suspend;
	for(;;);
}

	/* debounce, 50 ms*/
	for (i = 0; i < 50; i++) {
void
onoffintr(Ureg* , void*)
{
	static int power_pl;
	int i;
	for (i = 0; i < 100; i++) {
		delay(1);
		if ((gpioregs->level & GPIO_PWR_ON_i) == 0)
			return;	/* bounced */
	}
	if (i = setjmp(power_resume)) {
		/* power back up */
	power_pl = splhi();
	cachewb();
	delay(500);
	if (setpowerlabel()) {
		mmuinvalidate();
		mmuenable();
		cacheflush();
		trapresume();
		rs232power(1);
		lcdpower(1);
		audiopower(1);
		irpower(1);
		audiopower(1);
		clockpower(1);
		gpclkregs->r0 = 1<<0;
		gpiocpy(gpioregs, &savedgpioregs);
		intrcpy(intrregs, &savedintrregs);
		if (intrregs->icip & (1<<IRQgpio0)){
			// don't want to sleep now. clear on/off irq.
			gpioregs->edgestatus = (1<<IRQgpio0);
			intrregs->icip = (1<<IRQgpio0);
		}
		uartcpy(uart3regs,&saveduart3regs);
		uart3regs->status[0] = uart3regs->status[0];
		uartcpy(uart1regs,&saveduart1regs);
		uart1regs->status[0] = uart1regs->status[0];
		µcpower(1);
		screenpower(1);
		iprint("\nresuming execution\n");
//		dumpitall();
		delay(800);
		splx(power_pl);
		return;
	}
	/* Power down */
	iprint("\nentering suspend mode\n");
	gpiocpy(&savedgpioregs, gpioregs);
	intrcpy(&savedintrregs, intrregs);
	uartcpy(&saveduart3regs, uart3regs);
	uartcpy(&saveduart1regs, uart1regs);
	delay(400);
	clockpower(0);
	irpower(0);
	audiopower(0);
	lcdpower(0);
	screenpower(0);
	µcpower(0);
	rs232power(0);
	sa1100_power_off();
	/* no return */
}

static void
sa1100_power_off(void)


static int
bitno(ulong x)
{
	delay(100);
	splhi();
	/* enable wakeup by µcontroller, on/off switch or real-time clock alarm */
	powerregs->pwer = 0x80000003;
	/* disable internal oscillator, float CS lines */
	powerregs->pcfr = 1<<pcfr_opde | 1<<pcfr_fp | 1<<pcfr_fs;
	/* set lowest clock */
	powerregs->ppcr = 0;
	/* set all GPIOs to input mode */
	gpioregs->direction = 0;
	/* enter sleep mode */
	powerregs->pmcr = 1<<pmcr_sf;
	int i;

	for(i = 0; i < 8*sizeof(x); i++)
		if((1<<i) & x)
			break;
	return i;
}

void
idlehands(void)
powerinit(void)
{
	intrenable(GPIOrising, bitno(GPIO_PWR_ON_i), onoffintr, (void*)0x12344321, "on/off");
}
#endif



void
idlehands(void)
{
#ifdef notdef
	char *msgb = "idlehands called with splhi\n";
	char *msga = "doze returns with splhi\n";



@@ 88,4 203,6 @@ idlehands(void)
		serialputs(msgb, strlen(msgb));
		spllo();
	}
#endif
}


M bitsy/screen.c => bitsy/screen.c +14 -0
@@ 40,6 40,8 @@ struct sa1110fb {
	ushort	pixel[Wid*Ht];		/* Pixel data */
} *framebuf;

short savedpalette[16];	/* saved during suspend mode */

enum {
/* LCD Control Register 0, lcd->lccr0 */
	LEN	=  0,	/*  1 bit */


@@ 208,6 210,18 @@ lcdtweak(Cmdbuf *cmd)
}

void
screenpower(int on)
{
	if (on == 0){
		memmove(savedpalette, framebuf->palette, sizeof framebuf->palette);
		blankscreen(1);
	} else {
		memmove(framebuf->palette, savedpalette, sizeof framebuf->palette);
		blankscreen(0);
	}
}

void
screeninit(void)
{
	int i;

M bitsy/trap.c => bitsy/trap.c +21 -14
@@ 7,18 7,7 @@
#include	"ureg.h"
#include	"../port/error.h"

struct Intrregs
{
	ulong	icip;	/* pending IRQs */
	ulong	icmr;	/* IRQ mask */
	ulong	iclr;	/* IRQ if bit == 0, FRIQ if 1 */
	ulong	iccr;	/* control register */
	ulong	icfp;	/* pending FIQs */
	ulong	dummy1[3];
	ulong	icpr;	/* pending interrupts */
};

struct Intrregs *intrregs;
Intrregs *intrregs;

typedef struct Vctl {
	Vctl*	next;			/* handlers on this vector */


@@ 49,8 38,24 @@ void (*doze)(void);
static void	irq(Ureg*);
static void	gpiointr(Ureg*, void*);

/* recover state after power suspend
 * NB: to help debugging bad suspend code,
 *     I changed some prints below to iprints,
 *     to avoid deadlocks when a panic is being
 *     issued during the suspend/resume handler.
 */
void
trapresume(void)
{
	vpage0 = (Vpage0*)EVECTORS;
	memmove(vpage0->vectors, vectors, sizeof(vpage0->vectors));
	memmove(vpage0->vtable, vtable, sizeof(vpage0->vtable));
	wbflush();
	mappedIvecEnable();
}

/*
 *  set up for exceptioons
 *  set up for exceptions
 */
void
trapinit(void)


@@ 751,8 756,10 @@ _dumpstack(Ureg *ureg)
	ulong *p;
	extern ulong etext;

	if(up == 0)
	if(up == 0){
		print("no current proc\n");
		return;
	}

	print("ktrace /kernel/path %.8lux %.8lux %.8lux\n", ureg->pc, ureg->sp, ureg->r14);
	i = 0;

M bitsy/uartsa1110.c => bitsy/uartsa1110.c +0 -10
@@ 436,16 436,6 @@ serialµcputs(uchar *str, int n)
		;
}

typedef struct Gpclkregs Gpclkregs;
struct Gpclkregs
{
	ulong	r0;
	ulong	r1;
	ulong	dummya;
	ulong	r2;
	ulong	r3;
};

enum
{
	/* gpclk register 0 */