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

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

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

Initial revision

/*	$OpenBSD: ofw_machdep.c,v 1.31 2006/06/17 16:27:55 miod Exp $	*/
/*	$NetBSD: ofw_machdep.c,v 1.1 1996/09/30 16:34:50 ws Exp $	*/

/*
 * Copyright (C) 1996 Wolfgang Solfrank.
 * Copyright (C) 1996 TooLs GmbH.
 * All rights reserved.
 *
 * 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 by TooLs GmbH.
 * 4. The name of TooLs GmbH may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``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 TOOLS GMBH 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/buf.h>
#include <sys/conf.h>
#include <sys/device.h>
#include <sys/disk.h>
#include <sys/disklabel.h>
#include <sys/fcntl.h>
#include <sys/ioctl.h>
#include <sys/malloc.h>
#include <sys/stat.h>
#include <sys/systm.h>

#include <uvm/uvm_extern.h>

#include <machine/powerpc.h>
#include <machine/autoconf.h>

#include <dev/ofw/openfirm.h>

#include <macppc/macppc/ofw_machdep.h>

#include "ukbd.h"
#include "akbd.h"
#include "zstty.h"
#include <dev/usb/ukbdvar.h>
#include <dev/adb/akbdvar.h>
#include <dev/usb/usbdevs.h>

/* XXX, called from asm */
int save_ofw_mapping(void);

void OF_exit(void) __attribute__((__noreturn__));
void OF_boot(char *bootspec) __attribute__((__noreturn__));
void ofw_mem_regions(struct mem_region **memp, struct mem_region **availp);
void ofw_vmon(void);

struct firmware ofw_firmware = {
	ofw_mem_regions,
	OF_exit,
	OF_boot,
	ofw_vmon
#ifdef FW_HAS_PUTC
	ofwcnputc;
#endif
};

#define	OFMEM_REGIONS	32
static struct mem_region OFmem[OFMEM_REGIONS + 1], OFavail[OFMEM_REGIONS + 3];

/*
 * This is called during initppc, before the system is really initialized.
 * It shall provide the total and the available regions of RAM.
 * Both lists must have a zero-size entry as terminator.
 * The available regions need not take the kernel into account, but needs
 * to provide space for two additional entry beyond the terminating one.
 */
void
ofw_mem_regions(struct mem_region **memp, struct mem_region **availp)
{
	int phandle;

	/*
	 * Get memory.
	 */
	if ((phandle = OF_finddevice("/memory")) == -1
	    || OF_getprop(phandle, "reg",
	    OFmem, sizeof OFmem[0] * OFMEM_REGIONS) <= 0
	    || OF_getprop(phandle, "available",
	    OFavail, sizeof OFavail[0] * OFMEM_REGIONS) <= 0)
		panic("no memory?");

	*memp = OFmem;

	/* HACK */
	if (OFmem[0].size == 0) {
		*memp = OFavail;
	}

	*availp = OFavail;
}

typedef void (fwcall_f)(int, int);
extern fwcall_f *fwcall;
fwcall_f fwentry;
extern u_int32_t ofmsr;

void
ofw_vmon()
{
	fwcall = &fwentry;
}

int OF_stdout;
int OF_stdin;

/* code to save and create the necessary mappings for BSD to handle
 * the vm-setup for OpenFirmware
 */

int
save_ofw_mapping()
{
	int chosen;
	int stdout, stdin;

	if ((chosen = OF_finddevice("/chosen")) == -1) {
		return 0;
	}

	if (OF_getprop(chosen, "stdin", &stdin, sizeof stdin) != sizeof stdin) {
		return 0;
	}

	OF_stdin = stdin;
	if (OF_getprop(chosen, "stdout", &stdout, sizeof stdout)
	    != sizeof stdout) {
		return 0;
	}

	if (stdout == 0) {
		/* If the screen is to be console, but not active, open it */
		stdout = OF_open("screen");
	}
	OF_stdout = stdout;

	fw = &ofw_firmware;
	fwcall = &fwentry;
	return 0;
}

#include <dev/pci/pcivar.h>
#include <arch/macppc/pci/vgafb_pcivar.h>
static pcitag_t ofw_make_tag( void *cpv, int bus, int dev, int fnc);

/* ARGSUSED */
static pcitag_t
ofw_make_tag(void *cpv, int bus, int dev, int fnc)
{
        return (bus << 16) | (dev << 11) | (fnc << 8);
}

#define       OFW_PCI_PHYS_HI_BUSMASK         0x00ff0000
#define       OFW_PCI_PHYS_HI_BUSSHIFT        16
#define       OFW_PCI_PHYS_HI_DEVICEMASK      0x0000f800
#define       OFW_PCI_PHYS_HI_DEVICESHIFT     11
#define       OFW_PCI_PHYS_HI_FUNCTIONMASK    0x00000700
#define       OFW_PCI_PHYS_HI_FUNCTIONSHIFT   8

#define pcibus(x) \
	(((x) & OFW_PCI_PHYS_HI_BUSMASK) >> OFW_PCI_PHYS_HI_BUSSHIFT)
#define pcidev(x) \
	(((x) & OFW_PCI_PHYS_HI_DEVICEMASK) >> OFW_PCI_PHYS_HI_DEVICESHIFT)
#define pcifunc(x) \
	(((x) & OFW_PCI_PHYS_HI_FUNCTIONMASK) >> OFW_PCI_PHYS_HI_FUNCTIONSHIFT)


struct ppc_bus_space ppc_membus;
int cons_displaytype=0;
bus_space_tag_t cons_membus = &ppc_membus;
bus_space_handle_t cons_display_mem_h;
bus_space_handle_t cons_display_ctl_h;
int cons_height, cons_width, cons_linebytes, cons_depth;
int cons_display_ofh;
u_int32_t cons_addr;
int cons_brightness;
int cons_backlight_available;

#include "vgafb_pci.h"

struct usb_kbd_ihandles {
        struct usb_kbd_ihandles *next;
	int ihandle;
};

void of_display_console(void);

void
ofwconprobe()
{
	char type[32];
	int stdout_node;

	stdout_node = OF_instance_to_package(OF_stdout);

	/* handle different types of console */

	bzero(type, sizeof(type));
	if (OF_getprop(stdout_node,  "device_type", type, sizeof(type)) == -1) {
		return; /* XXX */
	}
	if (strcmp(type, "display") == 0) {
		of_display_console();
		return;
	}
	if (strcmp(type, "serial") == 0) {
#if NZSTTY > 0
		/* zscnprobe/zscninit do all the required initialization */
		return;
#endif
	}

	OF_stdout = OF_open("screen");
	OF_stdin = OF_open("keyboard");

	/* cross fingers that this works. */
	of_display_console();

	return;
}

#define DEVTREE_UNKNOWN 0
#define DEVTREE_USB	1
#define DEVTREE_ADB	2
int ofw_devtree = DEVTREE_UNKNOWN;

#define OFW_HAVE_USBKBD 1
#define OFW_HAVE_ADBKBD 2
int ofw_have_kbd = 0;

void ofw_recurse_keyboard(int pnode);
void ofw_find_keyboard(void);

void
ofw_recurse_keyboard(int pnode)
{
	char name[32];
	int old_devtree;
	int len;
	int node;
	int vendor, product;

	for (node = OF_child(pnode); node != 0; node = OF_peer(node)) {

		len = OF_getprop(node, "name", name, 20);
		if (len == 0)
			continue;
		name[len] = 0;
		if (strcmp(name, "keyboard") == 0) {
			/* found a keyboard node, where is it? */
			if (ofw_devtree == DEVTREE_USB) {
				/*
				 * On some machines, such as PowerBook6,8,
				 * the built-in ADB keyboard and mouse also
				 * appears as an USB device, which we will
				 * ignore.
				 * We need to tell these shadow devices apart
				 * from regular external USB keyboards.
				 */
				if (OF_getprop(pnode, "vendor-id", &vendor,
				    sizeof vendor) != sizeof vendor)
					vendor = 0;
				if (OF_getprop(pnode, "product-id", &product,
				    sizeof product) != sizeof product)
					product = 0;
				if (vendor != USB_VENDOR_APPLE ||
				    product != USB_PRODUCT_APPLE_ADB)
					ofw_have_kbd |= OFW_HAVE_USBKBD;
			} else if (ofw_devtree == DEVTREE_ADB) {
				ofw_have_kbd |= OFW_HAVE_ADBKBD;
			} else {
				/* hid or some other keyboard? igore */
			}
			continue;
		}

		old_devtree = ofw_devtree;

		if (strcmp(name, "adb") == 0) {
			ofw_devtree = DEVTREE_ADB;
		}
		if (strcmp(name, "usb") == 0) {
			ofw_devtree = DEVTREE_USB;
		}

		ofw_recurse_keyboard(node);

		ofw_devtree = old_devtree; /* nest? */
	}
}

void
ofw_find_keyboard()
{
	int stdin_node;
	char iname[32];
	int len;

	stdin_node = OF_instance_to_package(OF_stdin);
	len = OF_getprop(stdin_node, "name", iname, 20);
	iname[len] = 0;
	printf("console in [%s] ", iname);

	/* GRR, apple removed the interface once used for keyboard
	 * detection walk the OFW tree to find keyboards and what type.
	 */

	ofw_recurse_keyboard(OF_peer(0));

	if (ofw_have_kbd == 0) {
		printf("no keyboard found, hoping USB will be present\n");
#if NUKBD > 0
		ukbd_cnattach();
#endif
	}

	if (ofw_have_kbd == (OFW_HAVE_USBKBD | OFW_HAVE_ADBKBD)) {
#if NUKBD > 0
		printf("USB and ADB found, using USB\n");
		ukbd_cnattach();
#else
		ofw_have_kbd = OFW_HAVE_ADBKBD;
#endif
	}
	if (ofw_have_kbd == OFW_HAVE_USBKBD) {
#if NUKBD > 0
		printf("USB found\n");
		ukbd_cnattach();
#endif
	} else if (ofw_have_kbd == OFW_HAVE_ADBKBD) {
#if NAKBD >0
		printf("ADB found\n");
		akbd_cnattach();
#endif
	}
}

void
of_display_console()
{
#if NVGAFB_PCI > 0
	char name[32];
	int len;
	int stdout_node;
	int display_node;
	int err;
	u_int32_t memtag, iotag;
	struct ppc_pci_chipset pa;
	struct {
		u_int32_t phys_hi, phys_mid, phys_lo;
		u_int32_t size_hi, size_lo;
	} addr [8];

	pa.pc_make_tag = &ofw_make_tag;

	stdout_node = OF_instance_to_package(OF_stdout);
	len = OF_getprop(stdout_node, "name", name, 20);
	name[len] = 0;
	printf("console out [%s]", name);
	cons_displaytype=1;
	cons_display_ofh = OF_stdout;
	err = OF_getprop(stdout_node, "width", &cons_width, 4);
	if ( err != 4) {
		cons_width = 0;
	}
	err = OF_getprop(stdout_node, "linebytes", &cons_linebytes, 4);
	if ( err != 4) {
		cons_linebytes = cons_width;
	}
	err = OF_getprop(stdout_node, "height", &cons_height, 4);
	if ( err != 4) {
		cons_height = 0;
	}
	err = OF_getprop(stdout_node, "depth", &cons_depth, 4);
	if ( err != 4) {
		cons_depth = 0;
	}
	err = OF_getprop(stdout_node, "address", &cons_addr, 4);
	if ( err != 4) {
		OF_interpret("frame-buffer-adr", 1, &cons_addr);
	}

	ofw_find_keyboard();

	display_node = stdout_node;
	len = OF_getprop(stdout_node, "assigned-addresses", addr, sizeof(addr));
	if (len == -1) {
		display_node = OF_parent(stdout_node);
		len = OF_getprop(display_node, "name", name, 20);
		name[len] = 0;

		printf("using parent %s:", name);
		len = OF_getprop(display_node, "assigned-addresses",
			addr, sizeof(addr));
		if (len < sizeof(addr[0])) {
			panic(": no address");
		}
	}

	if (OF_getnodebyname(0, "backlight") != 0)
		cons_backlight_available = 1;

	memtag = ofw_make_tag(NULL, pcibus(addr[0].phys_hi),
		pcidev(addr[0].phys_hi),
		pcifunc(addr[0].phys_hi));
	iotag = ofw_make_tag(NULL, pcibus(addr[1].phys_hi),
		pcidev(addr[1].phys_hi),
		pcifunc(addr[1].phys_hi));

#if 1
	printf(": memaddr %x size %x, ", addr[0].phys_lo, addr[0].size_lo);
	printf(": consaddr %x, ", cons_addr);
	printf(": ioaddr %x, size %x", addr[1].phys_lo, addr[1].size_lo);
	printf(": memtag %x, iotag %x", memtag, iotag);
	printf(": width %d linebytes %d height %d depth %d\n",
		cons_width, cons_linebytes, cons_height, cons_depth);
#endif

	{
		int i;

		cons_membus->bus_base = 0x80000000;
#if 0
		err = bus_space_map( cons_membus, cons_addr, addr[0].size_lo,
			0, &cons_display_mem_h);
		printf("mem map err %x",err);
		bus_space_map( cons_membus, addr[1].phys_lo, addr[1].size_lo,
			0, &cons_display_ctl_h);
#endif

		vgafb_pci_console(cons_membus,
			addr[1].phys_lo, addr[1].size_lo,
			cons_membus,
			cons_addr, addr[0].size_lo,
			&pa, pcibus(addr[1].phys_hi), pcidev(addr[1].phys_hi),
			pcifunc(addr[1].phys_hi));

#if 1
		for (i = 0; i < cons_linebytes * cons_height; i++) {
			bus_space_write_1(cons_membus,
				cons_display_mem_h, i, 0);

		}
#endif
	}

	if (cons_backlight_available == 1)
		of_setbrightness(DEFAULT_BRIGHTNESS);
#endif
}

void
of_setbrightness(int brightness)
{

#if NVGAFB_PCI > 0
	if (cons_backlight_available == 0)
		return;

	if (brightness < MIN_BRIGHTNESS)
		brightness = MIN_BRIGHTNESS;
	else if (brightness > MAX_BRIGHTNESS)
		brightness = MAX_BRIGHTNESS;

	cons_brightness = brightness;

	/*
	 * The OF method is called "set-contrast" but affects brightness.
	 * Don't ask.
	 */
	OF_call_method_1("set-contrast", cons_display_ofh, 1, cons_brightness);

	/* XXX this routine should also save the brightness settings in the nvram */
#endif
}

#include <dev/cons.h>

cons_decl(ofw);

/*
 * Console support functions
 */
void
ofwcnprobe(struct consdev *cd)
{
}

void
ofwcninit(struct consdev *cd)
{
}
void
ofwcnputc(dev_t dev, int c)
{
	char ch = c;

	OF_write(OF_stdout, &ch, 1);
}
int
ofwcngetc(dev_t dev)
{
        unsigned char ch = '\0';
        int l;

        while ((l = OF_read(OF_stdin, &ch, 1)) != 1)
                if (l != -2 && l != 0)
                        return -1;
        return ch;
}

void
ofwcnpollc(dev_t dev, int on)
{
}

struct consdev consdev_ofw = {
        ofwcnprobe,
        ofwcninit,
        ofwcngetc,
        ofwcnputc,
        ofwcnpollc,
        NULL,
};

void
ofwconsinit()
{
	struct consdev *cp;
	cp = &consdev_ofw;
	cn_tab = cp;
}