[BACK]Return to cpu.c CVS log [TXT][DIR] Up to [local] / sys / arch / macppc / macppc

File: [local] / sys / arch / macppc / macppc / cpu.c (download)

Revision 1.1, Tue Mar 4 16:07:19 2008 UTC (16 years, 2 months ago) by nbrk
Branch point for: MAIN

Initial revision

/*	$OpenBSD: cpu.c,v 1.43 2007/05/23 23:40:21 kettenis Exp $ */

/*
 * Copyright (c) 1997 Per Fogelstrom
 * Copyright (c) 1997 RTMX Inc
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. All advertising materials mentioning features or use of this software
 *    must display the following acknowledgement:
 *	This product includes software developed under OpenBSD for RTMX Inc
 *	North Carolina, USA, by Per Fogelstrom, Opsycon AB, Sweden.
 * 4. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 *
 */

#include <sys/param.h>
#include <sys/systm.h>
#include <sys/proc.h>
#include <sys/user.h>
#include <sys/device.h>

#include <dev/ofw/openfirm.h>

#include <machine/autoconf.h>
#include <machine/bat.h>
#include <machine/trap.h>

/* only valid on 603(e,ev) and G3, G4 */
#define HID0_DOZE	(1 << (31-8))
#define HID0_NAP	(1 << (31-9))
#define HID0_SLEEP	(1 << (31-10))
#define HID0_DPM	(1 << (31-11))
#define HID0_SGE	(1 << (31-24))
#define HID0_BTIC	(1 << (31-26))
#define HID0_LRSTK	(1 << (31-27))
#define HID0_FOLD	(1 << (31-28))
#define HID0_BHT	(1 << (31-29))

/* SCOM addresses (24-bit) */
#define SCOM_PCR	0x0aa001 /* Power Control Register */
#define SCOM_PSR	0x408001 /* Power Tuning Status Register */

/* SCOMC format */
#define SCOMC_ADDR_SHIFT	8
#define SCOMC_ADDR_MASK		0xffff0000
#define SCOMC_READ		0x00008000

/* Frequency scaling */
#define FREQ_FULL	0
#define FREQ_HALF	1
#define FREQ_QUARTER	2	/* Not supported on IBM 970FX */

/* Power (Tuning) Status Register */
#define PSR_CMD_RECEIVED	0x2000000000000000LL
#define PSR_CMD_COMPLETED	0x1000000000000000LL
#define PSR_FREQ_MASK		0x0300000000000000LL
#define PSR_FREQ_HALF		0x0100000000000000LL

struct cpu_info cpu_info[PPC_MAXPROCS];

char cpu_model[80];
char machine[] = MACHINE;	/* cpu architecture */

/* Definition of the driver for autoconfig. */
int	cpumatch(struct device *, void *, void *);
void	cpuattach(struct device *, struct device *, void *);

struct cfattach cpu_ca = {
	sizeof(struct device), cpumatch, cpuattach
};

struct cfdriver cpu_cd = {
	NULL, "cpu", DV_DULL
};

void ppc64_scale_frequency(u_int);
void (*ppc64_slew_voltage)(u_int);
void ppc64_setperf(int);

void config_l2cr(int);

int
cpumatch(struct device *parent, void *cfdata, void *aux)
{
	struct confargs *ca = aux;
	int *reg = ca->ca_reg;

	/* make sure that we're looking for a CPU. */
	if (strcmp(ca->ca_name, cpu_cd.cd_name) != 0)
		return (0);

	if (reg[0] >= PPC_MAXPROCS)
		return (0);

	return (1);
}

static u_int32_t ppc_curfreq;
static u_int32_t ppc_maxfreq;
int ppc_altivec;


int
ppc_cpuspeed(int *freq)
{
	*freq = ppc_curfreq;

	return (0);
}

static u_int32_t ppc_power_mode_data[2];

void
ppc64_scale_frequency(u_int freq_scale)
{
	u_int64_t psr;
	int s;

	s = ppc_intr_disable();

	/* Clear PCRH and PCR. */
	ppc_mtscomd(0x00000000);
	ppc_mtscomc(SCOM_PCR << SCOMC_ADDR_SHIFT);
	ppc_mtscomd(0x80000000);
	ppc_mtscomc(SCOM_PCR << SCOMC_ADDR_SHIFT);

	/* Set PCR. */
	ppc_mtscomd(ppc_power_mode_data[freq_scale] | 0x80000000);
	ppc_mtscomc(SCOM_PCR << SCOMC_ADDR_SHIFT);

	/* Wait until frequency change is completed. */
	do {
		ppc64_mtscomc((SCOM_PSR << SCOMC_ADDR_SHIFT) | SCOMC_READ);
		psr = ppc64_mfscomd();
		ppc64_mfscomc();
		if (psr & PSR_CMD_COMPLETED)
			break;
		DELAY(100);
	} while (psr & PSR_CMD_RECEIVED);

	if ((psr & PSR_FREQ_MASK) == PSR_FREQ_HALF)
		ppc_curfreq = ppc_maxfreq / 2;
	else
		ppc_curfreq = ppc_maxfreq;

	ppc_intr_enable(s);
}

extern int perflevel;

void
ppc64_setperf(int speed)
{
	if (speed <= 50) {
		if (ppc_curfreq == ppc_maxfreq / 2)
			return;

		ppc64_scale_frequency(FREQ_HALF);
		if (ppc64_slew_voltage)
			ppc64_slew_voltage(FREQ_HALF);
	} else {
		if (ppc_curfreq == ppc_maxfreq)
			return;

		if (ppc64_slew_voltage)
			ppc64_slew_voltage(FREQ_FULL);
		ppc64_scale_frequency(FREQ_FULL);
	}
}

int ppc_proc_is_64b;
extern u_int32_t rfi_inst, rfid_inst, nop_inst;
struct patch {
	u_int32_t *s;
	u_int32_t *e;
};
extern struct patch rfi_start;
extern struct patch nop32_start;
extern struct patch nop64_start;


void
ppc_check_procid()
{
	u_int32_t cpu, pvr;
	u_int32_t *inst;
	struct patch *p;

	pvr = ppc_mfpvr();
	cpu = pvr >> 16;

	switch (cpu) {
	case PPC_CPU_IBM970FX:
	case PPC_CPU_IBM970MP:
		ppc_proc_is_64b = 1;
		for (p = &rfi_start; p->s; p++) {
			for (inst = p->s; inst < p->e; inst++)
				*inst = rfid_inst;
			syncicache(p->s, (p->e - p->s) * sizeof(*p->e));
		}
		for (p = &nop64_start; p->s; p++) {
			for (inst = p->s; inst < p->e; inst++)
				*inst = nop_inst;
			syncicache(p->s, (p->e - p->s) * sizeof(*p->e));
		}

		break;
	default:
		ppc_proc_is_64b = 0;
		for (p = &nop32_start; p->s; p++) {
			for (inst = p->s; inst < p->e; inst++)
				*inst = nop_inst;
			syncicache(p->s, (p->e - p->s) * sizeof(p->e));
		}
	}
}

void
cpuattach(struct device *parent, struct device *dev, void *aux)
{
	struct confargs *ca = aux;
	int *reg = ca->ca_reg;
	u_int32_t cpu, pvr, hid0;
	char name[32];
	int qhandle, phandle;
	u_int32_t clock_freq = 0;
	struct cpu_info *ci;

	ci = &cpu_info[reg[0]];
	ci->ci_cpuid = reg[0];
	ci->ci_intrdepth = -1;
	ci->ci_dev = dev;

	pvr = ppc_mfpvr();
	cpu = pvr >> 16;
	switch (cpu) {
	case PPC_CPU_MPC601:
		snprintf(cpu_model, sizeof(cpu_model), "601");
		break;
	case PPC_CPU_MPC603:
		snprintf(cpu_model, sizeof(cpu_model), "603");
		break;
	case PPC_CPU_MPC604:
		snprintf(cpu_model, sizeof(cpu_model), "604");
		break;
	case PPC_CPU_MPC603e:
		snprintf(cpu_model, sizeof(cpu_model), "603e");
		break;
	case PPC_CPU_MPC603ev:
		snprintf(cpu_model, sizeof(cpu_model), "603ev");
		break;
	case PPC_CPU_MPC750:
		snprintf(cpu_model, sizeof(cpu_model), "750");
		break;
	case PPC_CPU_MPC604ev:
		snprintf(cpu_model, sizeof(cpu_model), "604ev");
		break;
	case PPC_CPU_MPC7400:
		ppc_altivec = 1;
		snprintf(cpu_model, sizeof(cpu_model), "7400");
		break;
	case PPC_CPU_MPC7447A:
		ppc_altivec = 1;
		snprintf(cpu_model, sizeof(cpu_model), "7447A");
		break;
	case PPC_CPU_IBM970FX:
		ppc_altivec = 1;
		snprintf(cpu_model, sizeof(cpu_model), "970FX");
		break;
	case PPC_CPU_IBM750FX:
		snprintf(cpu_model, sizeof(cpu_model), "750FX");
		break;
	case PPC_CPU_MPC7410:
		ppc_altivec = 1;
		snprintf(cpu_model, sizeof(cpu_model), "7410");
		break;
	case PPC_CPU_MPC7450:
		ppc_altivec = 1;
		if ((pvr & 0xf) < 3)
			snprintf(cpu_model, sizeof(cpu_model), "7450");
		 else
			snprintf(cpu_model, sizeof(cpu_model), "7451");
		break;
	case PPC_CPU_MPC7455:
		ppc_altivec = 1;
		snprintf(cpu_model, sizeof(cpu_model), "7455");
		break;
	case PPC_CPU_MPC7457:
		ppc_altivec = 1;
		snprintf(cpu_model, sizeof(cpu_model), "7457");
		break;
	default:
		snprintf(cpu_model, sizeof(cpu_model), "Version %x", cpu);
		break;
	}
	snprintf(cpu_model + strlen(cpu_model),
	    sizeof(cpu_model) - strlen(cpu_model),
	    " (Revision 0x%x)", pvr & 0xffff);
	printf(": %s", cpu_model);

	/* This should only be executed on openfirmware systems... */

	for (qhandle = OF_peer(0); qhandle; qhandle = phandle) {
                if (OF_getprop(qhandle, "device_type", name, sizeof name) >= 0
                    && !strcmp(name, "cpu")
                    && OF_getprop(qhandle, "clock-frequency",
                        &clock_freq, sizeof clock_freq) >= 0)
		{
			break;
		}
                if ((phandle = OF_child(qhandle)))
                        continue;
                while (qhandle) {
                        if ((phandle = OF_peer(qhandle)))
                                break;
                        qhandle = OF_parent(qhandle);
                }
	}

	if (clock_freq != 0) {
		/* Openfirmware stores clock in Hz, not MHz */
		clock_freq /= 1000000;
		printf(": %d MHz", clock_freq);
		ppc_curfreq = ppc_maxfreq = clock_freq;
		cpu_cpuspeed = ppc_cpuspeed;
	}

	if (cpu == PPC_CPU_IBM970FX) {
		u_int64_t psr;
		int s;

		s = ppc_intr_disable();
		ppc64_mtscomc((SCOM_PSR << SCOMC_ADDR_SHIFT) | SCOMC_READ);
		psr = ppc64_mfscomd();
		ppc64_mfscomc();
		ppc_intr_enable(s);

		if ((psr & PSR_FREQ_MASK) == PSR_FREQ_HALF) {
			ppc_curfreq = ppc_maxfreq / 2;
			perflevel = 50;
		}

		if (OF_getprop(qhandle, "power-mode-data",
		    &ppc_power_mode_data, sizeof ppc_power_mode_data) >= 8)
			cpu_setperf = ppc64_setperf;
	}

	/* power savings mode */
	if (ppc_proc_is_64b == 0)
		hid0 = ppc_mfhid0();
	switch (cpu) {
	case PPC_CPU_MPC603:
	case PPC_CPU_MPC603e:
	case PPC_CPU_MPC750:
	case PPC_CPU_MPC7400:
	case PPC_CPU_IBM750FX:
	case PPC_CPU_MPC7410:
		/* select DOZE mode */
		hid0 &= ~(HID0_NAP | HID0_SLEEP);
		hid0 |= HID0_DOZE | HID0_DPM;
		break;
	case PPC_CPU_MPC7447A:
	case PPC_CPU_MPC7450:
	case PPC_CPU_MPC7455:
	case PPC_CPU_MPC7457:
		/* select NAP mode */
		hid0 &= ~(HID0_DOZE | HID0_SLEEP);
		hid0 |= HID0_NAP | HID0_DPM;
		/* try some other flags */
		hid0 |= HID0_SGE | HID0_BTIC;
		hid0 |= HID0_LRSTK | HID0_FOLD | HID0_BHT;
		/* Disable BTIC on 7450 Rev 2.0 or earlier */
		if (cpu == PPC_CPU_MPC7450 && (pvr & 0xffff) < 0x0200)
			hid0 &= ~HID0_BTIC;
		break;
	case PPC_CPU_IBM970FX:
		/* select NAP mode */
		hid0 &= ~(HID0_DOZE | HID0_SLEEP);
		hid0 |= HID0_NAP | HID0_DPM;
		break;
	}
	if (ppc_proc_is_64b == 0)
		ppc_mthid0(hid0);

	/* if processor is G3 or G4, configure l2 cache */
	if (cpu == PPC_CPU_MPC750 || cpu == PPC_CPU_MPC7400 ||
	    cpu == PPC_CPU_IBM750FX || cpu == PPC_CPU_MPC7410 ||
	    cpu == PPC_CPU_MPC7447A || cpu == PPC_CPU_MPC7450 ||
	    cpu == PPC_CPU_MPC7455 || cpu == PPC_CPU_MPC7457) {
		config_l2cr(cpu);
	}
	printf("\n");
}

/* L2CR bit definitions */
#define L2CR_L2E        0x80000000 /* 0: L2 enable */
#define L2CR_L2PE       0x40000000 /* 1: L2 data parity enable */
#define L2CR_L2SIZ      0x30000000 /* 2-3: L2 size */
#define  L2SIZ_RESERVED         0x00000000
#define  L2SIZ_256K             0x10000000
#define  L2SIZ_512K             0x20000000
#define  L2SIZ_1M       0x30000000
#define L2CR_L2CLK      0x0e000000 /* 4-6: L2 clock ratio */
#define  L2CLK_DIS              0x00000000 /* disable L2 clock */
#define  L2CLK_10               0x02000000 /* core clock / 1   */
#define  L2CLK_15               0x04000000 /*            / 1.5 */
#define  L2CLK_20               0x08000000 /*            / 2   */
#define  L2CLK_25               0x0a000000 /*            / 2.5 */
#define  L2CLK_30               0x0c000000 /*            / 3   */
#define L2CR_L2RAM      0x01800000 /* 7-8: L2 RAM type */
#define  L2RAM_FLOWTHRU_BURST   0x00000000
#define  L2RAM_PIPELINE_BURST   0x01000000
#define  L2RAM_PIPELINE_LATE    0x01800000
#define L2CR_L2DO       0x00400000 /* 9: L2 data-only.
                                      Setting this bit disables instruction
                                      caching. */
#define L2CR_L2I        0x00200000 /* 10: L2 global invalidate. */
#define L2CR_L2CTL      0x00100000 /* 11: L2 RAM control (ZZ enable).
                                      Enables automatic operation of the
                                      L2ZZ (low-power mode) signal. */
#define L2CR_L2WT       0x00080000 /* 12: L2 write-through. */
#define L2CR_L2TS       0x00040000 /* 13: L2 test support. */
#define L2CR_L2OH       0x00030000 /* 14-15: L2 output hold. */
#define L2CR_L2SL       0x00008000 /* 16: L2 DLL slow. */
#define L2CR_L2DF       0x00004000 /* 17: L2 differential clock. */
#define L2CR_L2BYP      0x00002000 /* 18: L2 DLL bypass. */
#define L2CR_L2IP       0x00000001 /* 31: L2 global invalidate in progress
				       (read only). */
#ifdef L2CR_CONFIG
u_int l2cr_config = L2CR_CONFIG;
#else
u_int l2cr_config = 0;
#endif

/* L3CR bit definitions */
#define   L3CR_L3E                0x80000000 /*  0: L3 enable */
#define   L3CR_L3SIZ              0x10000000 /*  3: L3 size (0=1MB, 1=2MB) */

void
config_l2cr(int cpu)
{
	u_int l2cr, x;

	l2cr = ppc_mfl2cr();

	/*
	 * Configure L2 cache if not enabled.
	 */
	if ((l2cr & L2CR_L2E) == 0 && l2cr_config != 0) {
		l2cr = l2cr_config;
		ppc_mtl2cr(l2cr);

		/* Wait for L2 clock to be stable (640 L2 clocks). */
		delay(100);

		/* Invalidate all L2 contents. */
		l2cr |= L2CR_L2I;
		ppc_mtl2cr(l2cr);
		do {
			x = ppc_mfl2cr();
		} while (x & L2CR_L2IP);

		/* Enable L2 cache. */
		l2cr &= ~L2CR_L2I;
		l2cr |= L2CR_L2E;
		ppc_mtl2cr(l2cr);
	}

	if (l2cr & L2CR_L2E) {
		if (cpu == PPC_CPU_MPC7450 || cpu == PPC_CPU_MPC7455) {
			u_int l3cr;

			printf(": 256KB L2 cache");

			l3cr = ppc_mfl3cr();
			if (l3cr & L3CR_L3E)
				printf(", %cMB L3 cache",
				    l3cr & L3CR_L3SIZ ? '2' : '1');
		} else if (cpu == PPC_CPU_IBM750FX ||
			   cpu == PPC_CPU_MPC7447A || cpu == PPC_CPU_MPC7457)
			printf(": 512KB L2 cache");
		else {
			switch (l2cr & L2CR_L2SIZ) {
			case L2SIZ_256K:
				printf(": 256KB");
				break;
			case L2SIZ_512K:
				printf(": 512KB");
				break;
			case L2SIZ_1M:
				printf(": 1MB");
				break;
			default:
				printf(": unknown size");
			}
			printf(" backside cache");
		}
#if 0
		switch (l2cr & L2CR_L2RAM) {
		case L2RAM_FLOWTHRU_BURST:
			printf(" Flow-through synchronous burst SRAM");
			break;
		case L2RAM_PIPELINE_BURST:
			printf(" Pipelined synchronous burst SRAM");
			break;
		case L2RAM_PIPELINE_LATE:
			printf(" Pipelined synchronous late-write SRAM");
			break;
		default:
			printf(" unknown type");
		}

		if (l2cr & L2CR_L2PE)
			printf(" with parity");
#endif
	} else
		printf(": L2 cache not enabled");
}

#ifdef MULTIPROCESSOR

#define	INTSTK	(8*1024)		/* 8K interrupt stack */

int cpu_spinup(struct device *, struct cpu_info *);
void cpu_hatch(void);
void cpu_spinup_trampoline(void);

struct cpu_hatch_data {
	struct cpu_info *ci;
	int running;
	int hid0;
	int sdr1;
	int tbu, tbl;
};

volatile struct cpu_hatch_data *cpu_hatch_data;
volatile int cpu_hatch_stack;

int
cpu_spinup(struct device *self, struct cpu_info *ci)
{
	volatile struct cpu_hatch_data hatch_data, *h = &hatch_data;
	int i;
	struct pcb *pcb;
	struct pglist mlist;
	struct vm_page *m;
	int error;
	int size = 0;
	char *cp;
	u_char *reset_cpu;

        /*
         * Allocate some contiguous pages for the idle PCB and stack
         * from the lowest 256MB (because bat0 always maps it va == pa).
         */
        size += USPACE;
        size += INTSTK;
        size += 4096;   /* SPILLSTK */

	TAILQ_INIT(&mlist);
	error = uvm_pglistalloc(size, 0x0, 0x10000000, 0, 0, &mlist, 1, 1);
	if (error) {
		printf(": unable to allocate idle stack\n");
		return -1;
	}

	m = TAILQ_FIRST(&mlist);
	cp = (char *)VM_PAGE_TO_PHYS(m);
	bzero(cp, size);

        pcb = (struct pcb *)cp;
        ci->ci_idle_pcb = pcb;
        ci->ci_intstk = cp + USPACE + INTSTK;

        /*
         * Initialize the idle stack pointer, reserving space for an
         * (empty) trapframe (XXX is the trapframe really necessary?)
         */
        pcb->pcb_sp = (paddr_t)pcb + USPACE - sizeof(struct trapframe);
	cpu_hatch_stack = ci->ci_idle_pcb->pcb_sp;

	h->ci = ci;
	h->running = 0;
	h->hid0 = ppc_mfhid0();
	h->sdr1 = ppc_mfsdr1();
	cpu_hatch_data = h;

#ifdef notyet
	ci->ci_lasttb = curcpu()->ci_lasttb;
#endif

	__asm volatile ("sync; isync");

	/* XXX OpenPIC */
	{
		uint64_t tb;

		*(u_int *)EXC_RST = 0x48000002 | (u_int)cpu_spinup_trampoline;
		syncicache((void *)EXC_RST, 0x100);

		h->running = -1;

		/* Start secondary CPU. */
		reset_cpu = mapiodev(0x80000000 + 0x5c, 1);
		*reset_cpu = 0x4;
		__asm volatile ("eieio" ::: "memory");
		*reset_cpu = 0x5;
		__asm volatile ("eieio" ::: "memory");

		/* Sync timebase. */
		tb = ppc_mftb();
		tb += 100000;	/* 3ms @ 33MHz  */

		h->tbu = tb >> 32;
		h->tbl = tb & 0xffffffff;

		while (tb > ppc_mftb())
			;
                __asm volatile ("sync; isync");
                h->running = 0;

                delay(500000);
	}

	printf("cpu%d: timebase %llx\n", cpu_number(), ppc_mftb());

	for (i = 0; i < 0x3fffffff; i++)
		if (h->running) {
			printf("running\n");
			break;
		}

	return 0;
}

volatile static int start_secondary_cpu;

void
cpu_boot_secondary_processors(void)
{
	struct cpu_info *ci;
	int i;

	for (i = 0; i < PPC_MAXPROCS; i++) {
		ci = &cpu_info[i];
		if (ci->ci_cpuid == 0)
			continue;
		cpu_spinup(NULL, ci);
	}

	start_secondary_cpu = 1;
	__asm volatile ("sync");
}

void
cpu_hatch(void)
{
	volatile struct cpu_hatch_data *h = cpu_hatch_data;
	int scratch, i;

        /* Initialize timebase. */
        __asm ("mttbl %0; mttbu %0; mttbl %0" :: "r"(0));

	/* Initialize curcpu(). */
	ppc_mtsprg0((u_int)h->ci);

	/* Set PIR . */
	ppc_mtpir(curcpu()->ci_cpuid);

	/*
	 * Initialize BAT registers to unmapped to not generate
	 * overlapping mappings below.
	 */
	ppc_mtibat0u(0);
	ppc_mtibat1u(0);
	ppc_mtibat2u(0);
	ppc_mtibat3u(0);
	ppc_mtdbat0u(0);
	ppc_mtdbat1u(0);
	ppc_mtdbat2u(0);
	ppc_mtdbat3u(0);

	/*
	 * Now setup fixed bat registers
	 *
	 * Note that we still run in real mode, and the BAT
	 * registers were cleared above.
	 */
	/* IBAT0 used for initial 256 MB segment */
	ppc_mtibat0l(battable[0].batl);
	ppc_mtibat0u(battable[0].batu);

	/* DBAT0 used similar */
	ppc_mtdbat0l(battable[0].batl);
	ppc_mtdbat0u(battable[0].batu);

	/*
	 * Initialize segment registers.
	 */
	for (i = 0; i < 16; i++)
		ppc_mtsrin(PPC_KERNEL_SEG0 + i, i << ADDR_SR_SHIFT);

	ppc_mthid0(h->hid0);
	ppc_mtsdr1(h->sdr1);

	/*
	 * Now enable translation (and machine checks/recoverable interrupts).
	 */
	__asm__ volatile ("eieio; mfmsr %0; ori %0,%0,%1; mtmsr %0; sync;isync"
		      : "=r"(scratch) : "K"(PSL_IR|PSL_DR|PSL_ME|PSL_RI));

	/* XXX OpenPIC */
	{
		/* Sync timebase. */
		u_int tbu = h->tbu;
		u_int tbl = h->tbl;
		while (h->running == -1)
			;
                __asm volatile ("sync; isync");
                __asm volatile ("mttbl %0" :: "r"(0));
                __asm volatile ("mttbu %0" :: "r"(tbu));
                __asm volatile ("mttbl %0" :: "r"(tbl));
	}

	ncpus++;
	h->running = 1;
	__asm volatile ("eieio" ::: "memory");

	while (start_secondary_cpu == 0)
		;

	__asm volatile ("sync; isync");

	printf("cpu%d: running\n", cpu_number());
	printf("cpu%d: timebase %llx\n", cpu_number(), ppc_mftb());
#ifdef notyet
	ppc_mtdec(ticks_per_intr);
#endif

	curcpu()->ci_ipending = 0;
	curcpu()->ci_cpl = 0;
}
#endif