VERSION = 2
PATCHLEVEL = 2
SUBLEVEL = 17
-EXTRAVERSION = pre2
+EXTRAVERSION = pre3
ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ -e s/arm.*/arm/ -e s/sa110/arm/)
OBJECTS := head.o misc.o ../coffboot/zlib.o
CFLAGS = -O2 -DSTDC_HEADERS -fno-builtin -I$(TOPDIR)/include
+ifeq ($(CONFIG_SMP),y)
+CFLAGS += -D__SMP__
+endif
OBJCOPY = $(CROSS_COMPILE)objcopy
OBJCOPY_ARGS = -O elf32-powerpc
#
# Paul Mackerras January 1997
-HOSTCC = gcc
HOSTCFLAGS = -O -I$(TOPDIR)/include
CC = $(CROSS_COMPILE)gcc
LD = $(CROSS_COMPILE)ld
-CFLAGS = -O -fno-builtin -I$(TOPDIR)/include
+CFLAGS = $(CPPFLAGS) -O -fno-builtin
OBJCOPY = $(CROSS_COMPILE)objcopy
-OBJCOPY_ARGS = -O aixcoff-rs6000 -R .stab -R .stabstr -R .comment \
- --add-section=image=vmlinux.gz
-LD_ARGS = -e _start -T ld.script -Ttext 500000 -Tdata 510000 -Bstatic
+OBJCOPY_ARGS = -O aixcoff-rs6000 -R .stab -R .stabstr -R .comment
+COFF_LD_ARGS = -e _start -T ld.script -Ttext 500000 -Tdata 510000 -Bstatic
+CHRP_LD_ARGS = -Ttext 0x00400000
GZ = gzip -9
-OBJS = crt0.o start.o main.o misc.o string.o zlib.o
+COFFOBJS = coffcrt0.o start.o coffmain.o misc.o string.o zlib.o image.o
+CHRPOBJS = crt0.o start.o chrpmain.o misc.o string.o zlib.o image.o
LIBS = $(TOPDIR)/lib/lib.a
-ifeq ($(CONFIG_ALL_PPC),y)
-# yes, we want to build pmac stuff
-CONFIG_PMAC = y
-endif
-
ifeq ($(CONFIG_PPC64),y)
MSIZE=.64
else
MSIZE=
endif
+ifeq ($(CONFIG_ALL_PPC),y)
+# yes, we want to build pmac stuff
+CONFIG_PMAC = y
+endif
+
ifeq ($(CONFIG_SMP),y)
TFTPIMAGE=/tftpboot/zImage.pmac.smp$(MSIZE)
else
hack-coff: hack-coff.c
$(HOSTCC) $(HOSTCFLAGS) -o hack-coff hack-coff.c
+znetboot: vmlinux.coff zImage vmlinux.elf
+ cp vmlinux.coff $(TFTPIMAGE)
+ cp vmlinux.elf $(TFTPIMAGE).elf
+
+znetboot.initrd: vmlinux.coff.initrd
+ cp vmlinux.coff.initrd $(TFTPIMAGE)
+ cp vmlinux.elf.initrd $(TFTPIMAGE).elf
+
floppy: zImage
# mount -t hfs /dev/fd0 /mnt
# cp vmlinux.coff /mnt
# umount /mnt
-znetboot: vmlinux.coff
- cp vmlinux.coff $(TFTPIMAGE)
+coffboot: $(COFFOBJS) no_initrd.o ld.script
+ $(LD) -o $@ $(COFF_LD_ARGS) $(COFFOBJS) no_initrd.o $(LIBS)
-znetboot.initrd: vmlinux.coff.initrd
- cp vmlinux.coff.initrd $(TFTPIMAGE)
+coffboot.initrd: $(COFFOBJS) initrd.o ld.script
+ $(LD) -o $@ $(COFF_LD_ARGS) $(COFFOBJS) initrd.o $(LIBS)
-coffboot: $(OBJS) ld.script
- $(LD) -o coffboot $(LD_ARGS) $(OBJS) $(LIBS)
+piggyback: piggyback.c
+ $(HOSTCC) $(HOSTCFLAGS) -DKERNELBASE=$(KERNELBASE) -o piggyback piggyback.c
-zImage: vmlinux.coff
+mknote: mknote.c
+ $(HOSTCC) $(HOSTCFLAGS) -o mknote mknote.c
-zImage.initrd: vmlinux.coff.initrd
+image.o: piggyback vmlinux.gz
+ ./piggyback image < vmlinux.gz | $(AS) -o image.o
-vmlinux.coff: coffboot hack-coff vmlinux.gz
+initrd.o: ramdisk.image.gz piggyback
+ ./piggyback initrd < ramdisk.image.gz | $(AS) -o initrd.o
+
+vmlinux.coff: coffboot hack-coff
$(OBJCOPY) $(OBJCOPY_ARGS) coffboot $@
./hack-coff $@
ln -sf vmlinux.coff zImage
-vmlinux.coff.initrd: coffboot hack-coff vmlinux.gz ramdisk.image.gz
- $(OBJCOPY) $(OBJCOPY_ARGS) --add-section=initrd=ramdisk.image.gz \
- coffboot $@
+vmlinux.coff.initrd: coffboot.initrd hack-coff
+ $(OBJCOPY) $(OBJCOPY_ARGS) coffboot $@
./hack-coff $@
+vmlinux.elf: $(CHRPOBJS) no_initrd.o mknote
+ $(LD) $(CHRP_LD_ARGS) -o $@ $(CHRPOBJS) no_initrd.o $(LIBS)
+ ./mknote > note
+ $(OBJCOPY) $@ $@ --add-section=.note=note -R .comment
+
+vmlinux.elf.initrd: $(CHRPOBJS) initrd.o mknote
+ $(LD) $(CHRP_LD_ARGS) -o $@ $(CHRPOBJS) initrd.o $(LIBS)
+ ./mknote > note
+ $(OBJCOPY) $@ $@ --add-section=.note=note -R .comment
+
+micoffboot: dummy.o
+ $(LD) -o $@ $(COFF_LD_ARGS) dummy.o $(LIBS)
+
+miboot.image: micoffboot hack-coff
+ $(OBJCOPY) $(OBJCOPY_ARGS) --add-section=image=vmlinux.gz micoffboot $@
+ ./hack-coff $@
+
+miboot.image.initrd: micoffboot hack-coff
+ $(OBJCOPY) $(OBJCOPY_ARGS) --add-section=image=vmlinux.gz \
+ --add-section=initrd=ramdisk.image.gz micoffboot $@
+ ./hack-coff $@
+
+zImage: vmlinux.coff vmlinux.elf miboot.image
+
+zImage.initrd: vmlinux.coff.initrd vmlinux.elf.initrd miboot.image.initrd
+
else
znetboot: vmlinux.gz
znetboot.initrd: vmlinux.gz
+miboot.image: vmlinux.gz
+
+miboot.image.initrd: vmlinux.gz
+
coffboot: vmlinux.gz
zImage: vmlinux.gz
clean:
rm -f hack-coff coffboot zImage vmlinux.coff vmlinux.gz
+ rm -f mknote piggyback vmlinux.elf note
fastdep:
--- /dev/null
+/*
+ * Copyright (C) Paul Mackerras 1997.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+#include "nonstdio.h"
+#include "zlib.h"
+
+extern void *finddevice(const char *);
+extern int getprop(void *, const char *, void *, int);
+void gunzip(void *, int, unsigned char *, int *);
+void stop_imac_ethernet(void);
+void stop_imac_usb(void);
+
+#define get_16be(x) (*(unsigned short *)(x))
+#define get_32be(x) (*(unsigned *)(x))
+
+#define RAM_START 0x00000000
+#define RAM_END (8<<20)
+
+#define PROG_START 0x00010000
+
+char *avail_ram;
+char *end_avail;
+
+extern char _end[];
+extern char image_data[];
+extern int image_len;
+extern char initrd_data[];
+extern int initrd_len;
+
+
+boot(int a1, int a2, void *prom)
+{
+ int ns, oh, i;
+ unsigned sa, len;
+ void *dst;
+ unsigned char *im;
+ unsigned initrd_start, initrd_size;
+ extern char _start;
+
+ printf("chrpboot starting: loaded at 0x%x\n", &_start);
+ if (initrd_len) {
+ initrd_size = initrd_len;
+ initrd_start = (RAM_END - initrd_size) & ~0xFFF;
+ a1 = initrd_start;
+ a2 = initrd_size;
+ claim(initrd_start, RAM_END - initrd_start, 0);
+ printf("initial ramdisk moving 0x%x <- 0x%x (%x bytes)\n",
+ initrd_start, initrd_data, initrd_size);
+ memcpy((char *)initrd_start, initrd_data, initrd_size);
+ }
+ im = image_data;
+ len = image_len;
+ /* claim 3MB starting at PROG_START */
+ claim(PROG_START, 3 << 20, 0);
+ dst = (void *) PROG_START;
+ if (im[0] == 0x1f && im[1] == 0x8b) {
+ /* claim 512kB for scratch space */
+ avail_ram = (char *) claim(0, 512 << 10, 0x10);
+ end_avail = avail_ram + (512 << 10);
+ printf("avail_ram = %x\n", avail_ram);
+ printf("gunzipping (0x%x <- 0x%x:0x%0x)...", dst, im, im+len);
+ gunzip(dst, 3 << 20, im, &len);
+ printf("done %u bytes\n", len);
+ } else {
+ memmove(dst, im, len);
+ }
+
+ flush_cache(dst, len);
+ stop_imac_ethernet();
+ stop_imac_usb();
+
+ sa = (unsigned long)PROG_START;
+ printf("start address = 0x%x\n", sa);
+
+ (*(void (*)())sa)(a1, a2, prom);
+
+ printf("returned?\n");
+
+ pause();
+}
+
+#define eieio() asm volatile("eieio");
+
+void stop_imac_ethernet(void)
+{
+ void *macio, *enet;
+ unsigned int macio_addr[5], enet_reg[6];
+ int len;
+ volatile unsigned int *dbdma;
+
+ macio = finddevice("/pci/mac-io");
+ enet = finddevice("/pci/mac-io/ethernet");
+ if (macio == NULL || enet == NULL)
+ return;
+ len = getprop(macio, "assigned-addresses", macio_addr, sizeof(macio_addr));
+ if (len != sizeof(macio_addr))
+ return;
+ len = getprop(enet, "reg", enet_reg, sizeof(enet_reg));
+ if (len != sizeof(enet_reg))
+ return;
+ printf("macio base %x, dma at %x & %x\n",
+ macio_addr[2], enet_reg[2], enet_reg[4]);
+
+ /* hope this is mapped... */
+ dbdma = (volatile unsigned int *) (macio_addr[2] + enet_reg[2]);
+ *dbdma = 0x80; /* clear the RUN bit */
+ eieio();
+ dbdma = (volatile unsigned int *) (macio_addr[2] + enet_reg[4]);
+ *dbdma = 0x80; /* clear the RUN bit */
+ eieio();
+}
+
+void stop_imac_usb(void)
+{
+ void *usb;
+ unsigned int usb_addr[5];
+ int len;
+ volatile unsigned int *usb_ctrl;
+
+ usb = finddevice("/pci/usb");
+ if (usb == NULL)
+ return;
+ len = getprop(usb, "assigned-addresses", usb_addr, sizeof(usb_addr));
+ if (len != sizeof(usb_addr))
+ return;
+ printf("usb base %x\n", usb_addr[2]);
+
+ usb_ctrl = (volatile unsigned int *) (usb_addr[2] + 8);
+ *usb_ctrl = 0x01000000; /* cpu_to_le32(1) */
+ eieio();
+}
+
+void *zalloc(void *x, unsigned items, unsigned size)
+{
+ void *p = avail_ram;
+
+ size *= items;
+ size = (size + 7) & -8;
+ avail_ram += size;
+ if (avail_ram > end_avail) {
+ printf("oops... out of memory\n");
+ pause();
+ }
+ return p;
+}
+
+void zfree(void *x, void *addr, unsigned nb)
+{
+}
+
+#define HEAD_CRC 2
+#define EXTRA_FIELD 4
+#define ORIG_NAME 8
+#define COMMENT 0x10
+#define RESERVED 0xe0
+
+#define DEFLATED 8
+
+void gunzip(void *dst, int dstlen, unsigned char *src, int *lenp)
+{
+ z_stream s;
+ int r, i, flags;
+
+ /* skip header */
+ i = 10;
+ flags = src[3];
+ if (src[2] != DEFLATED || (flags & RESERVED) != 0) {
+ printf("bad gzipped data\n");
+ exit();
+ }
+ if ((flags & EXTRA_FIELD) != 0)
+ i = 12 + src[10] + (src[11] << 8);
+ if ((flags & ORIG_NAME) != 0)
+ while (src[i++] != 0)
+ ;
+ if ((flags & COMMENT) != 0)
+ while (src[i++] != 0)
+ ;
+ if ((flags & HEAD_CRC) != 0)
+ i += 2;
+ if (i >= *lenp) {
+ printf("gunzip: ran out of data in header\n");
+ exit();
+ }
+
+ s.zalloc = zalloc;
+ s.zfree = zfree;
+ r = inflateInit2(&s, -MAX_WBITS);
+ if (r != Z_OK) {
+ printf("inflateInit2 returned %d\n", r);
+ exit();
+ }
+ s.next_in = src + i;
+ s.avail_in = *lenp - i;
+ s.next_out = dst;
+ s.avail_out = dstlen;
+ r = inflate(&s, Z_FINISH);
+ if (r != Z_OK && r != Z_STREAM_END) {
+ printf("inflate returned %d msg: %s\n", r, s.msg);
+ exit();
+ }
+ *lenp = s.next_out - (unsigned char *) dst;
+ inflateEnd(&s);
+}
--- /dev/null
+/*
+ * Copyright (C) Paul Mackerras 1997.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+ .text
+ .globl _start
+_start:
+ .long __start,0,0
+
+ .globl __start
+__start:
+ lis 9,_start@h
+ lis 8,_etext@ha
+ addi 8,8,_etext@l
+1: dcbf 0,9
+ icbi 0,9
+ addi 9,9,0x20
+ cmplwi 0,9,8
+ blt 1b
+ b start
--- /dev/null
+/*
+ * Copyright (C) Paul Mackerras 1997.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+#include "nonstdio.h"
+#include "zlib.h"
+
+extern void *finddevice(const char *);
+extern int getprop(void *, const char *, void *, int);
+extern char *claim(unsigned, unsigned, unsigned);
+void gunzip(void *, int, unsigned char *, int *);
+
+#define get_16be(x) (*(unsigned short *)(x))
+#define get_32be(x) (*(unsigned *)(x))
+
+#define RAM_START 0xc0000000
+#define PROG_START RAM_START
+#define RAM_END (RAM_START + 0x800000) /* only 8M mapped with BATs */
+
+char *avail_ram;
+char *end_avail;
+
+extern char _start[], _end[];
+extern char image_data[];
+extern int image_len;
+extern char initrd_data[];
+extern int initrd_len;
+
+
+boot(int a1, int a2, void *prom)
+{
+ int ns, oh, i;
+ unsigned sa, len;
+ void *dst;
+ unsigned char *im;
+ unsigned initrd_start, initrd_size;
+
+ printf("coffboot starting: loaded at 0x%x\n", _start);
+ setup_bats(RAM_START);
+ if (initrd_len) {
+ initrd_size = initrd_len;
+ initrd_start = (RAM_END - initrd_size) & ~0xFFF;
+ a1 = initrd_start;
+ a2 = initrd_size;
+ claim(initrd_start - RAM_START, RAM_END - initrd_start, 0);
+ printf("initial ramdisk moving 0x%x <- 0x%x (%x bytes)\n",
+ initrd_start, initrd_data, initrd_size);
+ memcpy((char *)initrd_start, initrd_data, initrd_size);
+ }
+ im = image_data;
+ len = image_len;
+ /* claim 3MB starting at 0 */
+ claim(0, 3 << 20, 0);
+ dst = (void *) RAM_START;
+ if (im[0] == 0x1f && im[1] == 0x8b) {
+ /* claim 512kB for scratch space */
+ avail_ram = claim(0, 512 << 10, 0x10) + RAM_START;
+ end_avail = avail_ram + (512 << 10);
+ printf("avail_ram = %x\n", avail_ram);
+ printf("gunzipping (0x%x <- 0x%x:0x%0x)...", dst, im, im+len);
+ gunzip(dst, 3 << 20, im, &len);
+ printf("done %u bytes\n", len);
+ } else {
+ memmove(dst, im, len);
+ }
+
+ flush_cache(dst, len);
+
+ sa = (unsigned long)PROG_START;
+ printf("start address = 0x%x\n", sa);
+
+#if 0
+ pause();
+#endif
+ (*(void (*)())sa)(a1, a2, prom);
+
+ printf("returned?\n");
+
+ pause();
+}
+
+void *zalloc(void *x, unsigned items, unsigned size)
+{
+ void *p = avail_ram;
+
+ size *= items;
+ size = (size + 7) & -8;
+ avail_ram += size;
+ if (avail_ram > end_avail) {
+ printf("oops... out of memory\n");
+ pause();
+ }
+ return p;
+}
+
+void zfree(void *x, void *addr, unsigned nb)
+{
+}
+
+#define HEAD_CRC 2
+#define EXTRA_FIELD 4
+#define ORIG_NAME 8
+#define COMMENT 0x10
+#define RESERVED 0xe0
+
+#define DEFLATED 8
+
+void gunzip(void *dst, int dstlen, unsigned char *src, int *lenp)
+{
+ z_stream s;
+ int r, i, flags;
+
+ /* skip header */
+ i = 10;
+ flags = src[3];
+ if (src[2] != DEFLATED || (flags & RESERVED) != 0) {
+ printf("bad gzipped data\n");
+ exit();
+ }
+ if ((flags & EXTRA_FIELD) != 0)
+ i = 12 + src[10] + (src[11] << 8);
+ if ((flags & ORIG_NAME) != 0)
+ while (src[i++] != 0)
+ ;
+ if ((flags & COMMENT) != 0)
+ while (src[i++] != 0)
+ ;
+ if ((flags & HEAD_CRC) != 0)
+ i += 2;
+ if (i >= *lenp) {
+ printf("gunzip: ran out of data in header\n");
+ exit();
+ }
+
+ s.zalloc = zalloc;
+ s.zfree = zfree;
+ r = inflateInit2(&s, -MAX_WBITS);
+ if (r != Z_OK) {
+ printf("inflateInit2 returned %d\n", r);
+ exit();
+ }
+ s.next_in = src + i;
+ s.avail_in = *lenp - i;
+ s.next_out = dst;
+ s.avail_out = dstlen;
+ r = inflate(&s, Z_FINISH);
+ if (r != Z_OK && r != Z_STREAM_END) {
+ printf("inflate returned %d msg: %s\n", r, s.msg);
+ exit();
+ }
+ *lenp = s.next_out - (unsigned char *) dst;
+ inflateEnd(&s);
+}
.text
.globl _start
_start:
- .long __start,0,0
-
- .globl __start
-__start:
lis 9,_start@h
lis 8,_etext@ha
addi 8,8,_etext@l
*/
.globl setup_bats
setup_bats:
- mr 4,3
- mfpvr 3
- rlwinm 3,3,16,16,31 /* r3 = 1 for 601, 4 for 604 */
- cmpi 0,3,1
+ mfpvr 5
+ rlwinm 5,5,16,16,31 /* r3 = 1 for 601, 4 for 604 */
+ cmpi 0,5,1
+ li 0,0
bne 4f
- ori 4,4,4 /* set up BAT registers for 601 */
- li 5,0x7f
- mtibatu 3,4
- mtibatl 3,5
- isync
- blr
-4: ori 4,4,0xfe /* set up BAT registers for 604 */
- li 5,2
- mtdbatl 3,5
- mtdbatu 3,4
- mtibatl 3,5
- mtibatu 3,4
+ mtibatl 3,0 /* invalidate BAT first */
+ ori 3,3,4 /* set up BAT registers for 601 */
+ li 4,0x7f
+ mtibatu 3,3
+ mtibatl 3,4
+ b 5f
+4: mtdbatu 3,0 /* invalidate BATs first */
+ mtibatu 3,0
+ ori 3,3,0xff /* set up BAT registers for 604 */
+ li 4,2
+ mtdbatl 3,4
+ mtdbatu 3,3
+ mtibatl 3,4
+ mtibatu 3,3
+5: sync
isync
blr
--- /dev/null
+/*
+ * Copyright (C) Cort Dougan 1999.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ * Generate a note section as per the CHRP specification.
+ *
+ */
+
+#include <stdio.h>
+
+#define PL(x) printf("%c%c%c%c", ((x)>>24)&0xff, ((x)>>16)&0xff, ((x)>>8)&0xff, (x)&0xff );
+
+int main(void)
+{
+/* header */
+ /* namesz */
+ PL(strlen("PowerPC")+1);
+ /* descrsz */
+ PL(6*4);
+ /* type */
+ PL(0x1275);
+ /* name */
+ printf("PowerPC"); printf("%c", 0);
+
+/* descriptor */
+ /* real-mode */
+ PL(0xffffffff);
+ /* real-base */
+ PL(0x00c00000);
+ /* real-size */
+ PL(0xffffffff);
+ /* virt-base */
+ PL(0xffffffff);
+ /* virt-size */
+ PL(0xffffffff);
+ /* load-base */
+ PL(0x4000);
+ return 0;
+}
--- /dev/null
+char initrd_data[1];
+int initrd_len = 0;
--- /dev/null
+#include <stdio.h>
+
+extern long ce_exec_config[];
+
+main(int argc, char *argv[])
+{
+ int i, cnt, pos, len;
+ unsigned int cksum, val;
+ unsigned char *lp;
+ unsigned char buf[8192];
+ if (argc != 2)
+ {
+ fprintf(stderr, "usage: %s name <in-file >out-file\n",
+ argv[0]);
+ exit(1);
+ }
+ fprintf(stdout, "#\n");
+ fprintf(stdout, "# Miscellaneous data structures:\n");
+ fprintf(stdout, "# WARNING - this file is automatically generated!\n");
+ fprintf(stdout, "#\n");
+ fprintf(stdout, "\n");
+ fprintf(stdout, "\t.data\n");
+ fprintf(stdout, "\t.globl %s_data\n", argv[1]);
+ fprintf(stdout, "%s_data:\n", argv[1]);
+ pos = 0;
+ cksum = 0;
+ while ((len = read(0, buf, sizeof(buf))) > 0)
+ {
+ cnt = 0;
+ lp = (unsigned char *)buf;
+ len = (len + 3) & ~3; /* Round up to longwords */
+ for (i = 0; i < len; i += 4)
+ {
+ if (cnt == 0)
+ {
+ fprintf(stdout, "\t.long\t");
+ }
+ fprintf(stdout, "0x%02X%02X%02X%02X", lp[0], lp[1], lp[2], lp[3]);
+ val = *(unsigned long *)lp;
+ cksum ^= val;
+ lp += 4;
+ if (++cnt == 4)
+ {
+ cnt = 0;
+ fprintf(stdout, " # %x \n", pos+i-12);
+ fflush(stdout);
+ } else
+ {
+ fprintf(stdout, ",");
+ }
+ }
+ if (cnt)
+ {
+ fprintf(stdout, "0\n");
+ }
+ pos += len;
+ }
+ fprintf(stdout, "\t.globl %s_len\n", argv[1]);
+ fprintf(stdout, "%s_len:\t.long\t0x%x\n", argv[1], pos);
+ fflush(stdout);
+ fclose(stdout);
+ fprintf(stderr, "cksum = %x\n", cksum);
+ exit(0);
+}
+
if (getprop(chosen_handle, "stdin", &stdin, sizeof(stdin)) != 4)
exit();
- coffboot(a1, a2, promptr);
+ boot(a1, a2, promptr);
for (;;)
exit();
}
return args.actual;
}
+int writestring(void *f, char *ptr, int nb)
+{
+ int w = 0, i;
+ char *ret = "\r";
+
+ for (i = 0; i < nb; ++i) {
+ if (ptr[i] == '\n') {
+ if (i > w) {
+ write(f, ptr + w, i - w);
+ w = i;
+ }
+ write(f, ret, 1);
+ }
+ }
+ if (w < nb)
+ write(f, ptr + w, nb - w);
+ return nb;
+}
+
int
read(void *handle, void *ptr, int nb)
{
return args.phandle;
}
+void *
+claim(unsigned int virt, unsigned int size, unsigned int align)
+{
+ struct prom_args {
+ char *service;
+ int nargs;
+ int nret;
+ unsigned int virt;
+ unsigned int size;
+ unsigned int align;
+ void *ret;
+ } args;
+
+ args.service = "claim";
+ args.nargs = 3;
+ args.nret = 1;
+ args.virt = virt;
+ args.size = size;
+ args.align = align;
+ (*prom)(&args);
+ return args.ret;
+}
+
int
getprop(void *phandle, const char *name, void *buf, int buflen)
{
{
char ch = c;
- if (c == '\n')
- putc('\r', f);
- return write(f, &ch, 1) == 1? c: -1;
+ return writestring(f, &ch, 1) == 1? c: -1;
}
int
{
int n = strlen(str);
- return write(f, str, n) == n? 0: -1;
+ return writestring(f, str, n) == n? 0: -1;
}
int
case 1:
return ch;
case -1:
- printk("read(stdin) returned -1\r\n");
+ printk("read(stdin) returned -1\n");
return -1;
}
}
va_start(args, fmt);
n = vsprintf(sprint_buf, fmt, args);
va_end(args);
- write(stdout, sprint_buf, n);
+ writestring(stdout, sprint_buf, n);
}
int
va_start(args, fmt);
n = vsprintf(sprint_buf, fmt, args);
va_end(args);
- write(stdout, sprint_buf, n);
+ writestring(stdout, sprint_buf, n);
return n;
}
#
-# Automatically generated by make menuconfig: don't edit
+# Automatically generated make config: don't edit
#
#
#
CONFIG_PPC=y
CONFIG_6xx=y
+# CONFIG_PPC64 is not set
# CONFIG_8xx is not set
-# CONFIG_PMAC is not set
+CONFIG_PMAC=y
# CONFIG_PREP is not set
# CONFIG_CHRP is not set
-CONFIG_ALL_PPC=y
+# CONFIG_ALL_PPC is not set
# CONFIG_APUS is not set
-# CONFIG_GEMINI is not set
# CONFIG_MBX is not set
# CONFIG_SMP is not set
+CONFIG_MACH_SPECIFIC=y
CONFIG_6xx=y
#
#
CONFIG_EXPERIMENTAL=y
CONFIG_MODULES=y
-CONFIG_MODVERSIONS=y
+# CONFIG_MODVERSIONS is not set
CONFIG_KMOD=y
CONFIG_PCI=y
# CONFIG_PCI_QUIRKS is not set
# CONFIG_BSD_PROCESS_ACCT is not set
CONFIG_BINFMT_ELF=y
CONFIG_KERNEL_ELF=y
-# CONFIG_BINFMT_MISC is not set
+CONFIG_BINFMT_MISC=m
# CONFIG_BINFMT_JAVA is not set
-# CONFIG_PARPORT is not set
-CONFIG_VGA_CONSOLE=y
+CONFIG_PARPORT=m
+# CONFIG_PARPORT_PC is not set
+# CONFIG_VGA_CONSOLE is not set
CONFIG_FB=y
CONFIG_FB_COMPAT_XPMAC=y
CONFIG_PMAC_PBOOK=y
# CONFIG_TOTALMP is not set
CONFIG_BOOTX_TEXT=y
# CONFIG_MOTOROLA_HOTSWAP is not set
-# CONFIG_CMDLINE_BOOL is not set
#
# Plug and Play support
#
# Block devices
#
-CONFIG_BLK_DEV_FD=y
+# CONFIG_BLK_DEV_FD is not set
CONFIG_BLK_DEV_IDE=y
+
+#
+# Please see Documentation/ide.txt for help/info on IDE drives
+#
# CONFIG_BLK_DEV_HD_IDE is not set
CONFIG_BLK_DEV_IDEDISK=y
CONFIG_BLK_DEV_IDECD=y
# CONFIG_BLK_DEV_IDESCSI is not set
# CONFIG_BLK_DEV_CMD640 is not set
# CONFIG_BLK_DEV_RZ1000 is not set
-# CONFIG_BLK_DEV_IDEPCI is not set
-CONFIG_BLK_DEV_SL82C105=y
+CONFIG_BLK_DEV_IDEPCI=y
+CONFIG_BLK_DEV_IDEDMA=y
+# CONFIG_BLK_DEV_OFFBOARD is not set
+CONFIG_IDEDMA_AUTO=y
+# CONFIG_BLK_DEV_OPTI621 is not set
+# CONFIG_BLK_DEV_TRM290 is not set
+# CONFIG_BLK_DEV_NS87415 is not set
+# CONFIG_BLK_DEV_VIA82C586 is not set
+CONFIG_BLK_DEV_CMD646=y
+# CONFIG_BLK_DEV_SL82C105 is not set
CONFIG_BLK_DEV_IDE_PMAC=y
CONFIG_BLK_DEV_IDEDMA_PMAC=y
CONFIG_BLK_DEV_IDEDMA=y
CONFIG_PMAC_IDEDMA_AUTO=y
# CONFIG_IDE_CHIPSETS is not set
+
+#
+# Additional Block Devices
+#
CONFIG_BLK_DEV_LOOP=y
# CONFIG_BLK_DEV_NBD is not set
# CONFIG_BLK_DEV_MD is not set
CONFIG_BLK_DEV_INITRD=y
# CONFIG_BLK_DEV_XD is not set
# CONFIG_BLK_DEV_DAC960 is not set
-CONFIG_PARIDE_PARPORT=y
+CONFIG_PARIDE_PARPORT=m
# CONFIG_PARIDE is not set
# CONFIG_BLK_CPQ_DA is not set
# CONFIG_BLK_DEV_HD is not set
# CONFIG_NET_IPGRE is not set
# CONFIG_IP_MROUTE is not set
CONFIG_IP_ALIAS=y
-CONFIG_SYN_COOKIES=y
+# CONFIG_SYN_COOKIES is not set
+
+#
+# (it is safe to leave these untouched)
+#
CONFIG_INET_RARP=y
CONFIG_SKB_LARGE=y
# CONFIG_IPV6 is not set
+
+#
+#
+#
# CONFIG_IPX is not set
CONFIG_ATALK=m
# CONFIG_X25 is not set
# SCSI support
#
CONFIG_SCSI=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
CONFIG_BLK_DEV_SD=y
CONFIG_CHR_DEV_ST=y
CONFIG_BLK_DEV_SR=y
CONFIG_BLK_DEV_SR_VENDOR=y
-CONFIG_CHR_DEV_SG=y
+# CONFIG_CHR_DEV_SG is not set
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
# CONFIG_SCSI_MULTI_LUN is not set
CONFIG_SCSI_CONSTANTS=y
# CONFIG_SCSI_LOGGING is not set
CONFIG_AIC7XXX_CMDS_PER_DEVICE=8
CONFIG_AIC7XXX_PROC_STATS=y
CONFIG_AIC7XXX_RESET_DELAY=15
-# CONFIG_SCSI_IPS is not set
# CONFIG_SCSI_ADVANSYS is not set
# CONFIG_SCSI_IN2000 is not set
# CONFIG_SCSI_AM53C974 is not set
# CONFIG_SCSI_GENERIC_NCR5380 is not set
# CONFIG_SCSI_INITIO is not set
# CONFIG_SCSI_INIA100 is not set
+# CONFIG_SCSI_PPA is not set
+# CONFIG_SCSI_IMM is not set
# CONFIG_SCSI_NCR53C406A is not set
# CONFIG_SCSI_SYM53C416 is not set
-# CONFIG_SCSI_SIM710 is not set
# CONFIG_SCSI_NCR53C7xx is not set
-# CONFIG_SCSI_NCR53C8XX is not set
+CONFIG_SCSI_NCR53C8XX=y
CONFIG_SCSI_SYM53C8XX=y
CONFIG_SCSI_NCR53C8XX_DEFAULT_TAGS=8
CONFIG_SCSI_NCR53C8XX_MAX_TAGS=32
# CONFIG_SCSI_NCR53C8XX_PROFILE is not set
# CONFIG_SCSI_NCR53C8XX_IOMAPPED is not set
# CONFIG_SCSI_NCR53C8XX_PQS_PDS is not set
-# CONFIG_SCSI_NCR53C8XX_SYMBIOS_COMPAT is not set
+CONFIG_SCSI_NCR53C8XX_SYMBIOS_COMPAT=y
# CONFIG_SCSI_PAS16 is not set
# CONFIG_SCSI_PCI2000 is not set
# CONFIG_SCSI_PCI2220I is not set
CONFIG_NET_ETHERNET=y
CONFIG_MACE=y
CONFIG_BMAC=y
-# CONFIG_NCR885E is not set
+CONFIG_GMAC=y
# CONFIG_NET_VENDOR_3COM is not set
# CONFIG_LANCE is not set
# CONFIG_NET_VENDOR_SMC is not set
# CONFIG_NET_VENDOR_RACAL is not set
# CONFIG_RTL8139 is not set
+# CONFIG_SIS900 is not set
# CONFIG_YELLOWFIN is not set
# CONFIG_NET_ISA is not set
CONFIG_NET_EISA=y
-CONFIG_PCNET32=y
+# CONFIG_PCNET32 is not set
# CONFIG_ACENIC is not set
# CONFIG_AC3200 is not set
# CONFIG_APRICOT is not set
# CONFIG_CS89x0 is not set
-# CONFIG_DM9102 is not set
CONFIG_DE4X5=y
# CONFIG_DEC_ELCP is not set
# CONFIG_DGRS is not set
# CONFIG_NE2K_PCI is not set
# CONFIG_TLAN is not set
# CONFIG_VIA_RHINE is not set
-# CONFIG_SIS900 is not set
# CONFIG_ES3210 is not set
# CONFIG_EPIC100 is not set
# CONFIG_ZNET is not set
# CONFIG_LTPC is not set
# CONFIG_COPS is not set
# CONFIG_IPDDP is not set
+# CONFIG_PLIP is not set
CONFIG_PPP=y
+
+#
+# CCP compressors for PPP are only built as modules.
+#
# CONFIG_SLIP is not set
# CONFIG_NET_RADIO is not set
# CONFIG_HOSTESS_SV11 is not set
# CONFIG_COSA is not set
# CONFIG_SEALEVEL_4021 is not set
-# CONFIG_COMX is not set
# CONFIG_DLCI is not set
-# CONFIG_SBNI is not set
#
# Amateur Radio support
CONFIG_FB_CONTROL=y
CONFIG_FB_PLATINUM=y
CONFIG_FB_VALKYRIE=y
+CONFIG_FB_ATY=y
+CONFIG_FB_ATY128=y
CONFIG_FB_IMSTT=y
CONFIG_FB_CT65550=y
# CONFIG_FB_S3TRIO is not set
-CONFIG_FB_MATROX=y
-# CONFIG_FB_MATROX_MILLENIUM is not set
-CONFIG_FB_MATROX_MYSTIQUE=y
-CONFIG_FB_MATROX_G100=y
-# CONFIG_FB_MATROX_MULTIHEAD is not set
+# CONFIG_FB_MATROX is not set
CONFIG_FB_ATY=y
# CONFIG_FB_VIRTUAL is not set
# CONFIG_FBCON_ADVANCED is not set
#
CONFIG_VT=y
CONFIG_VT_CONSOLE=y
-CONFIG_SERIAL=m
+# CONFIG_SERIAL is not set
# CONFIG_SERIAL_EXTENDED is not set
# CONFIG_SERIAL_NONSTANDARD is not set
CONFIG_UNIX98_PTYS=y
CONFIG_UNIX98_PTY_COUNT=256
-CONFIG_MOUSE=y
-
-#
-# Mice
-#
-# CONFIG_ATIXL_BUSMOUSE is not set
-# CONFIG_BUSMOUSE is not set
-# CONFIG_MS_BUSMOUSE is not set
-CONFIG_PSMOUSE=y
-# CONFIG_82C710_MOUSE is not set
-# CONFIG_PC110_PAD is not set
+# CONFIG_PRINTER is not set
+# CONFIG_MOUSE is not set
# CONFIG_QIC02_TAPE is not set
# CONFIG_WATCHDOG is not set
CONFIG_NVRAM=y
# CONFIG_ADFS_FS is not set
# CONFIG_AFFS_FS is not set
CONFIG_HFS_FS=y
-CONFIG_FAT_FS=y
-CONFIG_MSDOS_FS=y
+CONFIG_FAT_FS=m
+CONFIG_MSDOS_FS=m
# CONFIG_UMSDOS_FS is not set
-CONFIG_VFAT_FS=y
+CONFIG_VFAT_FS=m
CONFIG_ISO9660_FS=y
# CONFIG_JOLIET is not set
# CONFIG_MINIX_FS is not set
# CONFIG_NLS_ISO8859_8 is not set
# CONFIG_NLS_ISO8859_9 is not set
# CONFIG_NLS_ISO8859_14 is not set
-# CONFIG_NLS_ISO8859_15 is not set
+CONFIG_NLS_ISO8859_15=y
# CONFIG_NLS_KOI8_R is not set
#
#
CONFIG_SOUND=y
CONFIG_DMASOUND=y
-# CONFIG_SOUND_CMPCI is not set
# CONFIG_SOUND_ES1370 is not set
# CONFIG_SOUND_ES1371 is not set
-# CONFIG_SOUND_MAESTRO is not set
# CONFIG_SOUND_ESSSOLO1 is not set
# CONFIG_SOUND_SONICVIBES is not set
# CONFIG_SOUND_MSNDCLAS is not set
# CONFIG_SOUND_MSNDPIN is not set
-CONFIG_SOUND_OSS=y
-# CONFIG_SOUND_DMAP is not set
-# CONFIG_SOUND_PAS is not set
-# CONFIG_SOUND_SB is not set
-# CONFIG_SOUND_GUS is not set
-# CONFIG_SOUND_MPU401 is not set
-# CONFIG_SOUND_PSS is not set
-# CONFIG_SOUND_MSS is not set
-# CONFIG_SOUND_SSCAPE is not set
-# CONFIG_SOUND_TRIX is not set
-# CONFIG_SOUND_VIA82CXXX is not set
-# CONFIG_SOUND_MAD16 is not set
-# CONFIG_SOUND_WAVEFRONT is not set
-CONFIG_SOUND_CS4232=m
-# CONFIG_SOUND_OPL3SA2 is not set
-# CONFIG_SOUND_MAUI is not set
-# CONFIG_SOUND_SGALAXY is not set
-# CONFIG_SOUND_AD1816 is not set
-# CONFIG_SOUND_OPL3SA1 is not set
-# CONFIG_SOUND_SOFTOSS is not set
-# CONFIG_SOUND_YM3812 is not set
-# CONFIG_SOUND_VMIDI is not set
-# CONFIG_SOUND_UART6850 is not set
-# CONFIG_SOUND_NM256 is not set
-
-#
-# Additional low level sound drivers
-#
-# CONFIG_LOWLEVEL_SOUND is not set
+# CONFIG_SOUND_OSS is not set
#
# Kernel hacking
comment 'Platform support'
define_bool CONFIG_PPC y
choice 'Processor type' \
- "6xx/7xx CONFIG_6xx \
+ "6xx/7xx/7400 CONFIG_6xx \
860/821 CONFIG_8xx" 6xx/7xx
choice 'Machine Type' \
MBX CONFIG_MBX" PowerMac
bool 'Symmetric multi-processing support' CONFIG_SMP
+
+if [ "$CONFIG_6xx" = "y" ]; then
+ bool 'Altivec (G4) support' CONFIG_ALTIVEC
+fi
+
if [ "$CONFIG_ALL_PPC" != "y" ];then
define_bool CONFIG_MACH_SPECIFIC y
fi
bool 'Support for VGA Console' CONFIG_VGA_CONSOLE
bool 'Support for frame buffer devices' CONFIG_FB
-if [ "$CONFIG_FB" = "y" ]; then
- bool 'Backward compatibility mode for Xpmac' CONFIG_FB_COMPAT_XPMAC
-fi
bool 'Power management support for Apple PowerBooks' CONFIG_PMAC_PBOOK
bool 'Support for PowerMac keyboard' CONFIG_MAC_KEYBOARD
source net/ax25/Config.in
+source net/irda/Config.in
+
mainmenu_option next_comment
comment 'ISDN subsystem'
#
-# Automatically generated by make menuconfig: don't edit
+# Automatically generated make config: don't edit
#
#
#
CONFIG_PPC=y
CONFIG_6xx=y
+# CONFIG_PPC64 is not set
# CONFIG_8xx is not set
-# CONFIG_PMAC is not set
+CONFIG_PMAC=y
# CONFIG_PREP is not set
# CONFIG_CHRP is not set
-CONFIG_ALL_PPC=y
+# CONFIG_ALL_PPC is not set
# CONFIG_APUS is not set
-# CONFIG_GEMINI is not set
# CONFIG_MBX is not set
# CONFIG_SMP is not set
+CONFIG_MACH_SPECIFIC=y
CONFIG_6xx=y
#
#
CONFIG_EXPERIMENTAL=y
CONFIG_MODULES=y
-CONFIG_MODVERSIONS=y
+# CONFIG_MODVERSIONS is not set
CONFIG_KMOD=y
CONFIG_PCI=y
# CONFIG_PCI_QUIRKS is not set
# CONFIG_BSD_PROCESS_ACCT is not set
CONFIG_BINFMT_ELF=y
CONFIG_KERNEL_ELF=y
-# CONFIG_BINFMT_MISC is not set
+CONFIG_BINFMT_MISC=m
# CONFIG_BINFMT_JAVA is not set
-# CONFIG_PARPORT is not set
-CONFIG_VGA_CONSOLE=y
+CONFIG_PARPORT=m
+# CONFIG_PARPORT_PC is not set
+# CONFIG_VGA_CONSOLE is not set
CONFIG_FB=y
CONFIG_FB_COMPAT_XPMAC=y
CONFIG_PMAC_PBOOK=y
# CONFIG_TOTALMP is not set
CONFIG_BOOTX_TEXT=y
# CONFIG_MOTOROLA_HOTSWAP is not set
-# CONFIG_CMDLINE_BOOL is not set
#
# Plug and Play support
#
# Block devices
#
-CONFIG_BLK_DEV_FD=y
+# CONFIG_BLK_DEV_FD is not set
CONFIG_BLK_DEV_IDE=y
+
+#
+# Please see Documentation/ide.txt for help/info on IDE drives
+#
# CONFIG_BLK_DEV_HD_IDE is not set
CONFIG_BLK_DEV_IDEDISK=y
CONFIG_BLK_DEV_IDECD=y
# CONFIG_BLK_DEV_IDESCSI is not set
# CONFIG_BLK_DEV_CMD640 is not set
# CONFIG_BLK_DEV_RZ1000 is not set
-# CONFIG_BLK_DEV_IDEPCI is not set
-CONFIG_BLK_DEV_SL82C105=y
+CONFIG_BLK_DEV_IDEPCI=y
+CONFIG_BLK_DEV_IDEDMA=y
+# CONFIG_BLK_DEV_OFFBOARD is not set
+CONFIG_IDEDMA_AUTO=y
+# CONFIG_BLK_DEV_OPTI621 is not set
+# CONFIG_BLK_DEV_TRM290 is not set
+# CONFIG_BLK_DEV_NS87415 is not set
+# CONFIG_BLK_DEV_VIA82C586 is not set
+CONFIG_BLK_DEV_CMD646=y
+# CONFIG_BLK_DEV_SL82C105 is not set
CONFIG_BLK_DEV_IDE_PMAC=y
CONFIG_BLK_DEV_IDEDMA_PMAC=y
CONFIG_BLK_DEV_IDEDMA=y
CONFIG_PMAC_IDEDMA_AUTO=y
# CONFIG_IDE_CHIPSETS is not set
+
+#
+# Additional Block Devices
+#
CONFIG_BLK_DEV_LOOP=y
# CONFIG_BLK_DEV_NBD is not set
# CONFIG_BLK_DEV_MD is not set
CONFIG_BLK_DEV_INITRD=y
# CONFIG_BLK_DEV_XD is not set
# CONFIG_BLK_DEV_DAC960 is not set
-CONFIG_PARIDE_PARPORT=y
+CONFIG_PARIDE_PARPORT=m
# CONFIG_PARIDE is not set
# CONFIG_BLK_CPQ_DA is not set
# CONFIG_BLK_DEV_HD is not set
# CONFIG_NET_IPGRE is not set
# CONFIG_IP_MROUTE is not set
CONFIG_IP_ALIAS=y
-CONFIG_SYN_COOKIES=y
+# CONFIG_SYN_COOKIES is not set
+
+#
+# (it is safe to leave these untouched)
+#
CONFIG_INET_RARP=y
CONFIG_SKB_LARGE=y
# CONFIG_IPV6 is not set
+
+#
+#
+#
# CONFIG_IPX is not set
CONFIG_ATALK=m
# CONFIG_X25 is not set
# SCSI support
#
CONFIG_SCSI=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
CONFIG_BLK_DEV_SD=y
CONFIG_CHR_DEV_ST=y
CONFIG_BLK_DEV_SR=y
CONFIG_BLK_DEV_SR_VENDOR=y
-CONFIG_CHR_DEV_SG=y
+# CONFIG_CHR_DEV_SG is not set
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
# CONFIG_SCSI_MULTI_LUN is not set
CONFIG_SCSI_CONSTANTS=y
# CONFIG_SCSI_LOGGING is not set
CONFIG_AIC7XXX_CMDS_PER_DEVICE=8
CONFIG_AIC7XXX_PROC_STATS=y
CONFIG_AIC7XXX_RESET_DELAY=15
-# CONFIG_SCSI_IPS is not set
# CONFIG_SCSI_ADVANSYS is not set
# CONFIG_SCSI_IN2000 is not set
# CONFIG_SCSI_AM53C974 is not set
# CONFIG_SCSI_GENERIC_NCR5380 is not set
# CONFIG_SCSI_INITIO is not set
# CONFIG_SCSI_INIA100 is not set
+# CONFIG_SCSI_PPA is not set
+# CONFIG_SCSI_IMM is not set
# CONFIG_SCSI_NCR53C406A is not set
# CONFIG_SCSI_SYM53C416 is not set
-# CONFIG_SCSI_SIM710 is not set
# CONFIG_SCSI_NCR53C7xx is not set
-# CONFIG_SCSI_NCR53C8XX is not set
+CONFIG_SCSI_NCR53C8XX=y
CONFIG_SCSI_SYM53C8XX=y
CONFIG_SCSI_NCR53C8XX_DEFAULT_TAGS=8
CONFIG_SCSI_NCR53C8XX_MAX_TAGS=32
# CONFIG_SCSI_NCR53C8XX_PROFILE is not set
# CONFIG_SCSI_NCR53C8XX_IOMAPPED is not set
# CONFIG_SCSI_NCR53C8XX_PQS_PDS is not set
-# CONFIG_SCSI_NCR53C8XX_SYMBIOS_COMPAT is not set
+CONFIG_SCSI_NCR53C8XX_SYMBIOS_COMPAT=y
# CONFIG_SCSI_PAS16 is not set
# CONFIG_SCSI_PCI2000 is not set
# CONFIG_SCSI_PCI2220I is not set
CONFIG_NET_ETHERNET=y
CONFIG_MACE=y
CONFIG_BMAC=y
-# CONFIG_NCR885E is not set
+CONFIG_GMAC=y
# CONFIG_NET_VENDOR_3COM is not set
# CONFIG_LANCE is not set
# CONFIG_NET_VENDOR_SMC is not set
# CONFIG_NET_VENDOR_RACAL is not set
# CONFIG_RTL8139 is not set
+# CONFIG_SIS900 is not set
# CONFIG_YELLOWFIN is not set
# CONFIG_NET_ISA is not set
CONFIG_NET_EISA=y
-CONFIG_PCNET32=y
+# CONFIG_PCNET32 is not set
# CONFIG_ACENIC is not set
# CONFIG_AC3200 is not set
# CONFIG_APRICOT is not set
# CONFIG_CS89x0 is not set
-# CONFIG_DM9102 is not set
CONFIG_DE4X5=y
# CONFIG_DEC_ELCP is not set
# CONFIG_DGRS is not set
# CONFIG_NE2K_PCI is not set
# CONFIG_TLAN is not set
# CONFIG_VIA_RHINE is not set
-# CONFIG_SIS900 is not set
# CONFIG_ES3210 is not set
# CONFIG_EPIC100 is not set
# CONFIG_ZNET is not set
# CONFIG_LTPC is not set
# CONFIG_COPS is not set
# CONFIG_IPDDP is not set
+# CONFIG_PLIP is not set
CONFIG_PPP=y
+
+#
+# CCP compressors for PPP are only built as modules.
+#
# CONFIG_SLIP is not set
# CONFIG_NET_RADIO is not set
# CONFIG_HOSTESS_SV11 is not set
# CONFIG_COSA is not set
# CONFIG_SEALEVEL_4021 is not set
-# CONFIG_COMX is not set
# CONFIG_DLCI is not set
-# CONFIG_SBNI is not set
#
# Amateur Radio support
CONFIG_FB_CONTROL=y
CONFIG_FB_PLATINUM=y
CONFIG_FB_VALKYRIE=y
+CONFIG_FB_ATY=y
+CONFIG_FB_ATY128=y
CONFIG_FB_IMSTT=y
CONFIG_FB_CT65550=y
# CONFIG_FB_S3TRIO is not set
-CONFIG_FB_MATROX=y
-# CONFIG_FB_MATROX_MILLENIUM is not set
-CONFIG_FB_MATROX_MYSTIQUE=y
-CONFIG_FB_MATROX_G100=y
-# CONFIG_FB_MATROX_MULTIHEAD is not set
+# CONFIG_FB_MATROX is not set
CONFIG_FB_ATY=y
# CONFIG_FB_VIRTUAL is not set
# CONFIG_FBCON_ADVANCED is not set
#
CONFIG_VT=y
CONFIG_VT_CONSOLE=y
-CONFIG_SERIAL=m
+# CONFIG_SERIAL is not set
# CONFIG_SERIAL_EXTENDED is not set
# CONFIG_SERIAL_NONSTANDARD is not set
CONFIG_UNIX98_PTYS=y
CONFIG_UNIX98_PTY_COUNT=256
-CONFIG_MOUSE=y
-
-#
-# Mice
-#
-# CONFIG_ATIXL_BUSMOUSE is not set
-# CONFIG_BUSMOUSE is not set
-# CONFIG_MS_BUSMOUSE is not set
-CONFIG_PSMOUSE=y
-# CONFIG_82C710_MOUSE is not set
-# CONFIG_PC110_PAD is not set
+# CONFIG_PRINTER is not set
+# CONFIG_MOUSE is not set
# CONFIG_QIC02_TAPE is not set
# CONFIG_WATCHDOG is not set
CONFIG_NVRAM=y
# CONFIG_ADFS_FS is not set
# CONFIG_AFFS_FS is not set
CONFIG_HFS_FS=y
-CONFIG_FAT_FS=y
-CONFIG_MSDOS_FS=y
+CONFIG_FAT_FS=m
+CONFIG_MSDOS_FS=m
# CONFIG_UMSDOS_FS is not set
-CONFIG_VFAT_FS=y
+CONFIG_VFAT_FS=m
CONFIG_ISO9660_FS=y
# CONFIG_JOLIET is not set
# CONFIG_MINIX_FS is not set
# CONFIG_NLS_ISO8859_8 is not set
# CONFIG_NLS_ISO8859_9 is not set
# CONFIG_NLS_ISO8859_14 is not set
-# CONFIG_NLS_ISO8859_15 is not set
+CONFIG_NLS_ISO8859_15=y
# CONFIG_NLS_KOI8_R is not set
#
#
CONFIG_SOUND=y
CONFIG_DMASOUND=y
-# CONFIG_SOUND_CMPCI is not set
# CONFIG_SOUND_ES1370 is not set
# CONFIG_SOUND_ES1371 is not set
-# CONFIG_SOUND_MAESTRO is not set
# CONFIG_SOUND_ESSSOLO1 is not set
# CONFIG_SOUND_SONICVIBES is not set
# CONFIG_SOUND_MSNDCLAS is not set
# CONFIG_SOUND_MSNDPIN is not set
-CONFIG_SOUND_OSS=y
-# CONFIG_SOUND_DMAP is not set
-# CONFIG_SOUND_PAS is not set
-# CONFIG_SOUND_SB is not set
-# CONFIG_SOUND_GUS is not set
-# CONFIG_SOUND_MPU401 is not set
-# CONFIG_SOUND_PSS is not set
-# CONFIG_SOUND_MSS is not set
-# CONFIG_SOUND_SSCAPE is not set
-# CONFIG_SOUND_TRIX is not set
-# CONFIG_SOUND_VIA82CXXX is not set
-# CONFIG_SOUND_MAD16 is not set
-# CONFIG_SOUND_WAVEFRONT is not set
-CONFIG_SOUND_CS4232=m
-# CONFIG_SOUND_OPL3SA2 is not set
-# CONFIG_SOUND_MAUI is not set
-# CONFIG_SOUND_SGALAXY is not set
-# CONFIG_SOUND_AD1816 is not set
-# CONFIG_SOUND_OPL3SA1 is not set
-# CONFIG_SOUND_SOFTOSS is not set
-# CONFIG_SOUND_YM3812 is not set
-# CONFIG_SOUND_VMIDI is not set
-# CONFIG_SOUND_UART6850 is not set
-# CONFIG_SOUND_NM256 is not set
-
-#
-# Additional low level sound drivers
-#
-# CONFIG_LOWLEVEL_SOUND is not set
+# CONFIG_SOUND_OSS is not set
#
# Kernel hacking
#
# Note 2! The CFLAGS definitions are now in the main makefile...
+# Once a gas that groks -mvec is generally available, we'll use it...
.S.o:
+#ifdef CONFIG_ALTIVEC
+# $(CC) $(CFLAGS) -D__ASSEMBLY__ -Wa,-mvec -c $< -o $*.o
+#else
$(CC) $(CFLAGS) -D__ASSEMBLY__ -c $< -o $*.o
+#endif
O_TARGET := kernel.o
OX_OBJS := ppc_ksyms.o setup.o
+#include <linux/config.h>
#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/kernel.h>
ppc_md.kbd_init_hw = pckbd_init_hw;
#ifdef CONFIG_MAGIC_SYSRQ
ppc_md.kbd_sysrq_xlate = pckbd_sysrq_xlate;
+ ppc_md.SYSRQ_KEY = 0x54;
#endif
}
else
ppc_md.kbd_init_hw = mackbd_init_hw;
#ifdef CONFIG_MAGIC_SYSRQ
ppc_md.kbd_sysrq_xlate = mackbd_sysrq_xlate;
+ ppc_md.SYSRQ_KEY = 0x69;
#endif
}
#else
ppc_md.kbd_init_hw = pckbd_init_hw;
#ifdef CONFIG_MAGIC_SYSRQ
ppc_md.kbd_sysrq_xlate = pckbd_sysrq_xlate;
+ ppc_md.SYSRQ_KEY = 0x54;
#endif
#endif
#endif
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*
+ * BenH: Changed implementation to work on multiple registers
+ * polarity is also taken into account. Removed delay (now
+ * responsibility of the caller). Added spinlocks.
+ *
*/
#include <linux/types.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/kernel.h>
#include <linux/sched.h>
+#include <linux/spinlock.h>
#include <asm/errno.h>
#include <asm/ohare.h>
+#include <asm/heathrow.h>
#include <asm/io.h>
#include <asm/prom.h>
#include <asm/feature.h>
-#define MAX_FEATURE_REGS 2
#undef DEBUG_FEATURE
-static u32 feature_bits_pbook[] = {
- 0, /* FEATURE_null */
- OH_SCC_RESET, /* FEATURE_Serial_reset */
- OH_SCC_ENABLE, /* FEATURE_Serial_enable */
- OH_SCCA_IO, /* FEATURE_Serial_IO_A */
- OH_SCCB_IO, /* FEATURE_Serial_IO_B */
- OH_FLOPPY_ENABLE, /* FEATURE_SWIM3_enable */
- OH_MESH_ENABLE, /* FEATURE_MESH_enable */
- OH_IDE_ENABLE, /* FEATURE_IDE_enable */
- OH_VIA_ENABLE, /* FEATURE_VIA_enable */
- OH_IDECD_POWER, /* FEATURE_CD_power */
- OH_BAY_RESET, /* FEATURE_Mediabay_reset */
- OH_BAY_ENABLE, /* FEATURE_Mediabay_enable */
- OH_BAY_PCI_ENABLE, /* FEATURE_Mediabay_PCI_enable */
- OH_BAY_IDE_ENABLE, /* FEATURE_Mediabay_IDE_enable */
- OH_BAY_FLOPPY_ENABLE, /* FEATURE_Mediabay_floppy_enable */
- 0, /* FEATURE_BMac_reset */
- 0, /* FEATURE_BMac_IO_enable */
- 0, /* FEATURE_Modem_Reset -> guess... */
- OH_IDE_POWER, /* FEATURE_IDE_DiskPower -> guess... */
- OH_IDE_RESET /* FEATURE_IDE_Reset (0 based) -> guess... */
+#define MAX_FEATURE_CONTROLLERS 2
+#define MAX_FEATURE_OFFSET 0x50
+#define FREG(c,r) (&(((c)->reg)[(r)>>2]))
+
+typedef struct feature_bit {
+ int reg; /* reg. offset from mac-io base */
+ unsigned int polarity; /* 0 = normal, 1 = inverse */
+ unsigned int mask; /* bit mask */
+} fbit;
+
+/* I don't have an OHare machine to test with, so I left those as they
+ * were. Someone with such a machine chould check out what OF says and
+ * try too see if they match the heathrow ones and should be changed too
+ */
+static fbit feature_bits_ohare_pbook[] = {
+ {0x38,0,0}, /* FEATURE_null */
+ {0x38,0,OH_SCC_RESET}, /* FEATURE_Serial_reset */
+ {0x38,0,OH_SCC_ENABLE}, /* FEATURE_Serial_enable */
+ {0x38,0,OH_SCCA_IO}, /* FEATURE_Serial_IO_A */
+ {0x38,0,OH_SCCB_IO}, /* FEATURE_Serial_IO_B */
+ {0x38,0,OH_FLOPPY_ENABLE}, /* FEATURE_SWIM3_enable */
+ {0x38,0,OH_MESH_ENABLE}, /* FEATURE_MESH_enable */
+ {0x38,0,OH_IDE0_ENABLE}, /* FEATURE_IDE0_enable */
+ {0x38,1,OH_IDE0_RESET_N}, /* FEATURE_IDE0_reset */
+ {0x38,0,OH_IOBUS_ENABLE}, /* FEATURE_IOBUS_enable */
+ {0x38,1,OH_BAY_RESET_N}, /* FEATURE_Mediabay_reset */
+ {0x38,1,OH_BAY_POWER_N}, /* FEATURE_Mediabay_power */
+ {0x38,0,OH_BAY_PCI_ENABLE}, /* FEATURE_Mediabay_PCI_enable */
+ {0x38,0,OH_BAY_IDE_ENABLE}, /* FEATURE_IDE1_enable */
+ {0x38,1,OH_IDE1_RESET_N}, /* FEATURE_IDE1_reset */
+ {0x38,0,OH_BAY_FLOPPY_ENABLE}, /* FEATURE_Mediabay_floppy_enable */
+ {0x38,0,0}, /* FEATURE_BMac_reset */
+ {0x38,0,0}, /* FEATURE_BMac_IO_enable */
+ {0x38,0,0}, /* FEATURE_Modem_power */
+ {0x38,0,0}, /* FEATURE_Slow_SCC_PCLK */
+ {0x38,0,0}, /* FEATURE_Sound_Power */
+ {0x38,0,0}, /* FEATURE_Sound_CLK_Enable */
+ {0x38,0,0}, /* FEATURE_IDE2_enable */
+ {0x38,0,0}, /* FEATURE_IDE2_reset */
+ {0x38,0,0}, /* FEATURE_Mediabay_IDE_switch */
+ {0x38,0,0}, /* FEATURE_Mediabay_content */
};
-/* assume these are the same as the ohare until proven otherwise */
-static u32 feature_bits_heathrow[] = {
- 0, /* FEATURE_null */
- OH_SCC_RESET, /* FEATURE_Serial_reset */
- OH_SCC_ENABLE, /* FEATURE_Serial_enable */
- OH_SCCA_IO, /* FEATURE_Serial_IO_A */
- OH_SCCB_IO, /* FEATURE_Serial_IO_B */
- OH_FLOPPY_ENABLE, /* FEATURE_SWIM3_enable */
- OH_MESH_ENABLE, /* FEATURE_MESH_enable */
- OH_IDE_ENABLE, /* FEATURE_IDE_enable */
- OH_VIA_ENABLE, /* FEATURE_VIA_enable */
- OH_IDECD_POWER, /* FEATURE_CD_power */
- OH_BAY_RESET, /* FEATURE_Mediabay_reset */
- OH_BAY_ENABLE, /* FEATURE_Mediabay_enable */
- OH_BAY_PCI_ENABLE, /* FEATURE_Mediabay_PCI_enable */
- OH_BAY_IDE_ENABLE, /* FEATURE_Mediabay_IDE_enable */
- OH_BAY_FLOPPY_ENABLE, /* FEATURE_Mediabay_floppy_enable */
- 0x80000000, /* FEATURE_BMac_reset */
- 0x60000000, /* FEATURE_BMac_IO_enable */
- 0x02000000, /* FEATURE_Modem_Reset -> guess...*/
- OH_IDE_POWER, /* FEATURE_IDE_DiskPower -> guess... */
- OH_IDE_RESET /* FEATURE_IDE_Reset (0 based) -> guess... */
+/* Those bits are from a PowerBook. It's possible that desktop machines
+ * based on heathrow need a different definition or some bits removed
+ */
+static fbit feature_bits_heathrow[] = {
+ {0x38,0,0}, /* FEATURE_null */
+ {0x38,0,HRW_RESET_SCC}, /* FEATURE_Serial_reset */
+ {0x38,0,HRW_SCC_ENABLE}, /* FEATURE_Serial_enable */
+ {0x38,0,HRW_SCCA_IO}, /* FEATURE_Serial_IO_A */
+ {0x38,0,HRW_SCCB_IO}, /* FEATURE_Serial_IO_B */
+ {0x38,0,HRW_SWIM_ENABLE}, /* FEATURE_SWIM3_enable */
+ {0x38,0,HRW_MESH_ENABLE}, /* FEATURE_MESH_enable */
+ {0x38,0,HRW_IDE0_ENABLE}, /* FEATURE_IDE0_enable */
+ {0x38,1,HRW_IDE0_RESET_N}, /* FEATURE_IDE0_reset */
+ {0x38,0,HRW_IOBUS_ENABLE}, /* FEATURE_IOBUS_enable */
+ {0x38,1,HRW_BAY_RESET_N}, /* FEATURE_Mediabay_reset */
+ {0x38,1,HRW_BAY_POWER_N}, /* FEATURE_Mediabay_power */
+ {0x38,0,HRW_BAY_PCI_ENABLE}, /* FEATURE_Mediabay_PCI_enable */
+ {0x38,0,HRW_BAY_IDE_ENABLE}, /* FEATURE_IDE1_enable */
+ {0x38,1,HRW_IDE1_RESET_N}, /* FEATURE_IDE1_reset */
+ {0x38,0,HRW_BAY_FLOPPY_ENABLE}, /* FEATURE_Mediabay_floppy_enable */
+ {0x38,0,HRW_BMAC_RESET}, /* FEATURE_BMac_reset */
+ {0x38,0,HRW_BMAC_IO_ENABLE}, /* FEATURE_BMac_IO_enable */
+ {0x38,1,HRW_MODEM_POWER_N}, /* FEATURE_Modem_power */
+ {0x38,0,HRW_SLOW_SCC_PCLK}, /* FEATURE_Slow_SCC_PCLK */
+ {0x38,1,HRW_SOUND_POWER_N}, /* FEATURE_Sound_Power */
+ {0x38,0,HRW_SOUND_CLK_ENABLE}, /* FEATURE_Sound_CLK_Enable */
+ {0x38,0,0}, /* FEATURE_IDE2_enable */
+ {0x38,0,0}, /* FEATURE_IDE2_reset */
+ {0x38,0,0}, /* FEATURE_Mediabay_IDE_switch */
+ {0x38,0,0}, /* FEATURE_Mediabay_content */
+};
+
+/*
+ * Those bits are from a 1999 G3 PowerBook, with a paddington chip.
+ * Mostly the same as the heathrow.
+ */
+static fbit feature_bits_paddington[] = {
+ {0x38,0,0}, /* FEATURE_null */
+ {0x38,0,0}, /* FEATURE_Serial_reset */
+ {0x38,0,HRW_SCC_ENABLE}, /* FEATURE_Serial_enable */
+ {0x38,0,HRW_SCCA_IO}, /* FEATURE_Serial_IO_A */
+ {0x38,0,HRW_SCCB_IO}, /* FEATURE_Serial_IO_B */
+ {0x38,0,HRW_SWIM_ENABLE}, /* FEATURE_SWIM3_enable */
+ {0x38,0,HRW_MESH_ENABLE}, /* FEATURE_MESH_enable */
+ {0x38,0,HRW_IDE0_ENABLE}, /* FEATURE_IDE0_enable */
+ {0x38,1,HRW_IDE0_RESET_N}, /* FEATURE_IDE0_reset */
+ {0x38,0,HRW_IOBUS_ENABLE}, /* FEATURE_IOBUS_enable */
+ {0x38,1,HRW_BAY_RESET_N}, /* FEATURE_Mediabay_reset */
+ {0x38,1,HRW_BAY_POWER_N}, /* FEATURE_Mediabay_power */
+ {0x38,0,HRW_BAY_PCI_ENABLE}, /* FEATURE_Mediabay_PCI_enable */
+ {0x38,0,HRW_BAY_IDE_ENABLE}, /* FEATURE_IDE1_enable */
+ {0x38,1,HRW_IDE1_RESET_N}, /* FEATURE_IDE1_reset */
+ {0x38,0,HRW_BAY_FLOPPY_ENABLE}, /* FEATURE_Mediabay_floppy_enable */
+ {0x38,0,HRW_BMAC_RESET}, /* FEATURE_BMac_reset */
+ {0x38,0,HRW_BMAC_IO_ENABLE}, /* FEATURE_BMac_IO_enable */
+ {0x38,1,PADD_MODEM_POWER_N}, /* FEATURE_Modem_power */
+ {0x38,0,HRW_SLOW_SCC_PCLK}, /* FEATURE_Slow_SCC_PCLK */
+ {0x38,1,HRW_SOUND_POWER_N}, /* FEATURE_Sound_Power */
+ {0x38,0,HRW_SOUND_CLK_ENABLE}, /* FEATURE_Sound_CLK_Enable */
+ {0x38,0,0}, /* FEATURE_IDE2_enable */
+ {0x38,0,0}, /* FEATURE_IDE2_reset */
+ {0x38,0,0}, /* FEATURE_Mediabay_IDE_switch */
+ {0x38,0,0}, /* FEATURE_Mediabay_content */
+};
+
+/* Those bits are for Core99 machines (iBook,G4,iMacSL/DV,Pismo,...).
+ */
+static fbit feature_bits_keylargo[] = {
+ {0x38,0,0}, /* FEATURE_null */
+ {0x38,0,0}, /* FEATURE_Serial_reset */
+ {0x38,0,0x00000054}, /* FEATURE_Serial_enable */
+ {0x38,0,0}, /* FEATURE_Serial_IO_A */
+ {0x38,0,0}, /* FEATURE_Serial_IO_B */
+ {0x38,0,0}, /* FEATURE_SWIM3_enable */
+ {0x38,0,0}, /* FEATURE_MESH_enable */
+ {0x3c,0,0}, /* FEATURE_IDE0_enable */
+ {0x3c,1,0x01000000}, /* FEATURE_IDE0_reset */
+ {0x38,0,0}, /* FEATURE_IOBUS_enable */
+ {0x34,1,0x00000200}, /* FEATURE_Mediabay_reset */
+ {0x34,1,0x00000400}, /* FEATURE_Mediabay_power */
+ {0x38,0,0}, /* FEATURE_Mediabay_PCI_enable */
+ {0x3c,0,0x0}, /* FEATURE_IDE1_enable */
+ {0x3c,1,0x08000000}, /* FEATURE_IDE1_reset */
+ {0x38,0,0}, /* FEATURE_Mediabay_floppy_enable */
+ {0x38,0,0}, /* FEATURE_BMac_reset */
+ {0x38,0,0}, /* FEATURE_BMac_IO_enable */
+ {0x40,1,0x02000000}, /* FEATURE_Modem_power */
+ {0x38,0,0}, /* FEATURE_Slow_SCC_PCLK */
+ {0x38,0,0}, /* FEATURE_Sound_Power */
+ {0x38,0,0}, /* FEATURE_Sound_CLK_Enable */
+ {0x38,0,0}, /* FEATURE_IDE2_enable */
+ {0x3c,1,0x40000000}, /* FEATURE_IDE2_reset */
+ {0x34,0,0x00001000}, /* FEATURE_Mediabay_IDE_switch */
+ {0x34,0,0x00000100}, /* FEATURE_Mediabay_content */
};
/* definition of a feature controller object */
-struct feature_controller
-{
- u32* bits;
+struct feature_controller {
+ fbit* bits;
volatile u32* reg;
struct device_node* device;
+ spinlock_t lock;
};
/* static functions */
static void
-feature_add_controller(struct device_node *controller_device, u32* bits);
+feature_add_controller(struct device_node *controller_device, fbit* bits);
-static int
+static struct feature_controller*
feature_lookup_controller(struct device_node *device);
/* static varialbles */
-static struct feature_controller controllers[MAX_FEATURE_REGS];
+static struct feature_controller controllers[MAX_FEATURE_CONTROLLERS];
static int controller_count = 0;
struct device_node *np;
np = find_devices("mac-io");
- while (np != NULL)
- {
- feature_add_controller(np, feature_bits_heathrow);
+ while (np != NULL) {
+ /* KeyLargo contains several (5 ?) FCR registers in mac-io,
+ * plus some gpio's which could eventually be handled here.
+ */
+ if (device_is_compatible(np, "Keylargo")) {
+ feature_add_controller(np, feature_bits_keylargo);
+ } else if (device_is_compatible(np, "paddington")) {
+ feature_add_controller(np, feature_bits_paddington);
+ } else {
+ feature_add_controller(np, feature_bits_heathrow);
+ }
np = np->next;
}
if (controller_count == 0)
{
np = find_devices("ohare");
- if (np)
- {
+ if (np) {
if (find_devices("via-pmu") != NULL)
- feature_add_controller(np, feature_bits_pbook);
+ feature_add_controller(np, feature_bits_ohare_pbook);
else
/* else not sure; maybe this is a Starmax? */
feature_add_controller(np, NULL);
if (controller_count)
printk(KERN_INFO "Registered %d feature controller(s)\n", controller_count);
+
+#ifdef CONFIG_PMAC_PBOOK
+#ifdef CONFIG_DMASOUND_MODULE
+ /* On PowerBooks, we disable the sound chip when dmasound is a module */
+ if (controller_count && find_devices("via-pmu") != NULL) {
+ feature_clear(controllers[0].device, FEATURE_Sound_power);
+ feature_clear(controllers[0].device, FEATURE_Sound_CLK_enable);
+ }
+#endif
+#endif
}
static void
-feature_add_controller(struct device_node *controller_device, u32* bits)
+feature_add_controller(struct device_node *controller_device, fbit* bits)
{
struct feature_controller* controller;
- if (controller_count >= MAX_FEATURE_REGS)
- {
+ if (controller_count >= MAX_FEATURE_CONTROLLERS) {
printk(KERN_INFO "Feature controller %s skipped(MAX:%d)\n",
- controller_device->full_name, MAX_FEATURE_REGS);
+ controller_device->full_name, MAX_FEATURE_CONTROLLERS);
return;
}
controller = &controllers[controller_count];
}
controller->reg = (volatile u32 *)ioremap(
- controller_device->addrs[0].address + OHARE_FEATURE_REG, 4);
+ controller_device->addrs[0].address, MAX_FEATURE_OFFSET);
if (bits == NULL) {
printk(KERN_INFO "Twiddling the magic ohare bits\n");
- out_le32(controller->reg, STARMAX_FEATURES);
+ out_le32(FREG(controller,OHARE_FEATURE_REG), STARMAX_FEATURES);
return;
}
+ spin_lock_init(&controller->lock);
+
controller_count++;
}
-static int
+static struct feature_controller*
feature_lookup_controller(struct device_node *device)
{
int i;
if (device == NULL)
- return -EINVAL;
+ return NULL;
while(device)
{
for (i=0; i<controller_count; i++)
if (device == controllers[i].device)
- return i;
+ return &controllers[i];
device = device->parent;
}
device->name);
#endif
- return -ENODEV;
+ return NULL;
}
int
feature_set(struct device_node* device, enum system_feature f)
{
- int controller;
- unsigned long flags;
+ struct feature_controller* controller;
+ unsigned long flags;
+ unsigned long value;
+ fbit* bit;
if (f >= FEATURE_last)
return -EINVAL;
controller = feature_lookup_controller(device);
- if (controller < 0)
- return controller;
+ if (!controller)
+ return -ENODEV;
+ bit = &controller->bits[f];
+ if (!bit->mask)
+ return -EINVAL;
#ifdef DEBUG_FEATURE
printk("feature: <%s> setting feature %d in controller @0x%x\n",
- device->name, (int)f, (unsigned int)controllers[controller].reg);
+ device->name, (int)f, (unsigned int)controller->reg);
#endif
- save_flags(flags);
- cli();
- out_le32( controllers[controller].reg,
- in_le32(controllers[controller].reg) |
- controllers[controller].bits[f]);
- (void)in_le32(controllers[controller].reg);
- restore_flags(flags);
- udelay(10);
+ spin_lock_irqsave(&controller->lock, flags);
+ value = in_le32(FREG(controller, bit->reg));
+ value = bit->polarity ? (value & ~bit->mask) : (value | bit->mask);
+ out_le32(FREG(controller, bit->reg), value);
+ (void)in_le32(FREG(controller, bit->reg));
+ spin_unlock_irqrestore(&controller->lock, flags);
return 0;
}
int
feature_clear(struct device_node* device, enum system_feature f)
{
- int controller;
- unsigned long flags;
+ struct feature_controller* controller;
+ unsigned long flags;
+ unsigned long value;
+ fbit* bit;
if (f >= FEATURE_last)
return -EINVAL;
controller = feature_lookup_controller(device);
- if (controller < 0)
- return controller;
+ if (!controller)
+ return -ENODEV;
+ bit = &controller->bits[f];
+ if (!bit->mask)
+ return -EINVAL;
#ifdef DEBUG_FEATURE
printk("feature: <%s> clearing feature %d in controller @0x%x\n",
- device->name, (int)f, (unsigned int)controllers[controller].reg);
+ device->name, (int)f, (unsigned int)controller->reg);
#endif
- save_flags(flags);
- cli();
- out_le32( controllers[controller].reg,
- in_le32(controllers[controller].reg) &
- ~(controllers[controller].bits[f]));
- (void)in_le32(controllers[controller].reg);
- restore_flags(flags);
- udelay(10);
+ spin_lock_irqsave(&controller->lock, flags);
+ value = in_le32(FREG(controller, bit->reg));
+ value = bit->polarity ? (value | bit->mask) : (value & ~bit->mask);
+ out_le32(FREG(controller, bit->reg), value);
+ (void)in_le32(FREG(controller, bit->reg));
+ spin_unlock_irqrestore(&controller->lock, flags);
return 0;
}
int
feature_test(struct device_node* device, enum system_feature f)
{
- int controller;
+ struct feature_controller* controller;
+ unsigned long value;
+ fbit* bit;
if (f >= FEATURE_last)
return -EINVAL;
controller = feature_lookup_controller(device);
- if (controller < 0)
- return controller;
+ if (!controller)
+ return -ENODEV;
+ bit = &controller->bits[f];
+ if (!bit->mask)
+ return -EINVAL;
- return (in_le32(controllers[controller].reg) &
- controllers[controller].bits[f]) != 0;
+#ifdef DEBUG_FEATURE
+ printk("feature: <%s> clearing feature %d in controller @0x%x\n",
+ device->name, (int)f, (unsigned int)controller->reg);
+#endif
+ /* If one feature contains several bits, all of them must be set
+ * for value to be true, or all of them must be 0 if polarity is
+ * inverse
+ */
+ value = (in_le32(FREG(controller, bit->reg)) & bit->mask);
+ return bit->polarity ? (value == 0) : (value == bit->mask);
}
* Copyright (C) 1996 Paul Mackerras.
* MPC8xx modifications Copyright (C) 1997 Dan Malek (dmalek@jlc.net).
* Amiga/APUS changes by Jesper Skov (jskov@cygnus.co.uk).
+ * AltiVec additions by Kumar Gala (kumar.gala@motorola.com).
*
* This file contains the low-level support and setup for the
* PowerPC platform, including trap and interrupt dispatch.
#define REST_16FPRS(n, base) REST_8FPRS(n, base); REST_8FPRS(n+8, base)
#define REST_32FPRS(n, base) REST_16FPRS(n, base); REST_16FPRS(n+16, base)
+/*
+ * Once a version of gas that understands the AltiVec instructions
+ * is freely available, we can do this the normal way... - paulus
+ */
+#define LVX(r,a,b) .long (31<<26)+((r)<<21)+((a)<<16)+((b)<<11)+(103<<1)
+#define STVX(r,a,b) .long (31<<26)+((r)<<21)+((a)<<16)+((b)<<11)+(231<<1)
+#define MFVSCR(r) .long (4<<26)+((r)<<11)+(770<<1)
+#define MTVSCR(r) .long (4<<26)+((r)<<11)+(802<<1)
+
+#define SAVE_VR(n,b,base) li b,TSS_VR0+(16*(n)); STVX(n,b,base)
+#define SAVE_2VR(n,b,base) SAVE_VR(n,b,base); SAVE_VR(n+1,b,base)
+#define SAVE_4VR(n,b,base) SAVE_2VR(n,b,base); SAVE_2VR(n+2,b,base)
+#define SAVE_8VR(n,b,base) SAVE_4VR(n,b,base); SAVE_4VR(n+4,b,base)
+#define SAVE_16VR(n,b,base) SAVE_8VR(n,b,base); SAVE_8VR(n+8,b,base)
+#define SAVE_32VR(n,b,base) SAVE_16VR(n,b,base); SAVE_16VR(n+16,b,base)
+#define REST_VR(n,b,base) li b,TSS_VR0+(16*(n)); LVX(n,b,base)
+#define REST_2VR(n,b,base) REST_VR(n,b,base); REST_VR(n+1,b,base)
+#define REST_4VR(n,b,base) REST_2VR(n,b,base); REST_2VR(n+2,b,base)
+#define REST_8VR(n,b,base) REST_4VR(n,b,base); REST_4VR(n+4,b,base)
+#define REST_16VR(n,b,base) REST_8VR(n,b,base); REST_8VR(n+8,b,base)
+#define REST_32VR(n,b,base) REST_16VR(n,b,base); REST_16VR(n+16,b,base)
+
#define SYNC \
sync; \
isync
STD_EXCEPTION(0xd00, SingleStep, SingleStepException)
STD_EXCEPTION(0xe00, Trap_0e, UnknownException)
+
+#ifndef CONFIG_ALTIVEC
STD_EXCEPTION(0xf00, Trap_0f, UnknownException)
+#else
+/*
+ * The Altivec unavailable trap is at 0x0f20. Foo.
+ * We effectively remap it to 0x3000.
+ */
+ . = 0xf00
+ b Trap_0f
+trap_0f_cont:
+ addi r3,r1,STACK_FRAME_OVERHEAD
+ li r20,MSR_KERNEL
+ bl transfer_to_handler
+ .long UnknownException
+ .long int_return
+
+ . = 0xf20
+ b AltiVecUnavailable
+#endif /* CONFIG_ALTIVEC */
#ifndef CONFIG_8xx
/*
STD_EXCEPTION(0x2f00, Trap_2f, UnknownException)
. = 0x3000
-#else
+#ifdef CONFIG_ALTIVEC
+AltiVecUnavailable:
+ EXCEPTION_PROLOG
+ bne load_up_altivec /* if from user, just load it up */
+ li r20,MSR_KERNEL
+ bl transfer_to_handler /* if from kernel, take a trap */
+ .long KernelAltiVec
+ .long int_return
+
+/* here are the bits of trap 0xf00 which got displaced */
+Trap_0f:
+ EXCEPTION_PROLOG
+ b trap_0f_cont
+#endif /* CONFIG_ALTIVEC */
+
+#else /* CONFIG_8xx */
. = 0x2000
-#endif
+#endif /* CONFIG_8xx */
/*
* This code finishes saving the registers to the exception frame
REST_GPR(20, r21)
REST_2GPRS(22, r21)
lwz r21,GPR21(r21)
+ sync
rfi
#ifdef __SMP__
#endif /* __SMP__ */
blr
+#ifdef CONFIG_ALTIVEC
+/* Note that the AltiVec support is closely modeled after the FP
+ * support. Changes to one are likely to be applicable to the
+ * other! */
+load_up_altivec:
+/*
+ * Disable AltiVec for the task which had AltiVec previously,
+ * and save its AltiVec registers in its thread_struct.
+ * Enables AltiVec for use in the kernel on return.
+ * On SMP we know the AltiVec units are free, since we give it up every
+ * switch. -- Kumar
+ */
+ mfmsr r5
+ oris r5,r5,MSR_VEC@h
+ SYNC
+ mtmsr r5 /* enable use of AltiVec now */
+ SYNC
+/*
+ * For SMP, we don't do lazy AltiVec switching because it just gets too
+ * horrendously complex, especially when a task switches from one CPU
+ * to another. Instead we call giveup_altivec in switch_to.
+ */
+#ifndef __SMP__
+#ifndef CONFIG_APUS
+ lis r6,-KERNELBASE@h
+#else
+ lis r6,CYBERBASEp@h
+ lwz r6,0(r6)
+#endif
+ addis r3,r6,last_task_used_altivec@ha
+ lwz r4,last_task_used_altivec@l(r3)
+ cmpi 0,r4,0
+ beq 1f
+ add r4,r4,r6
+ addi r4,r4,TSS /* want TSS of last_task_used_altivec */
+ SAVE_32VR(0,r20,r4)
+ MFVSCR(vr0)
+ li r20,TSS_VSCR
+ STVX(vr0,r20,r4)
+ lwz r5,PT_REGS(r4)
+ add r5,r5,r6
+ lwz r4,_MSR-STACK_FRAME_OVERHEAD(r5)
+ lis r20,MSR_VEC@h
+ andc r4,r4,r20 /* disable altivec for previous task */
+ stw r4,_MSR-STACK_FRAME_OVERHEAD(r5)
+1:
+#endif /* __SMP__ */
+ /* enable use of AltiVec after return */
+ oris r23,r23,MSR_VEC@h
+ mfspr r5,SPRG3 /* current task's TSS (phys) */
+ li r20,TSS_VSCR
+ LVX(vr0,r20,r5)
+ MTVSCR(vr0)
+ REST_32VR(0,r20,r5)
+#ifndef __SMP__
+ subi r4,r5,TSS
+ sub r4,r4,r6
+ stw r4,last_task_used_altivec@l(r3)
+#endif /* __SMP__ */
+ /* restore registers and return */
+ lwz r3,_CCR(r21)
+ lwz r4,_LINK(r21)
+ mtcrf 0xff,r3
+ mtlr r4
+ REST_GPR(1, r21)
+ REST_4GPRS(3, r21)
+ /* we haven't used ctr or xer */
+ mtspr SRR1,r23
+ mtspr SRR0,r22
+ REST_GPR(20, r21)
+ REST_2GPRS(22, r21)
+ lwz r21,GPR21(r21)
+ SYNC
+ rfi
+
+/*
+ * AltiVec unavailable trap from kernel - print a message, but let
+ * the task use AltiVec in the kernel until it returns to user mode.
+ */
+KernelAltiVec:
+ lwz r3,_MSR(r1)
+ oris r3,r3,MSR_VEC@h
+ stw r3,_MSR(r1) /* enable use of AltiVec after return */
+ lis r3,87f@h
+ ori r3,r3,87f@l
+ mr r4,r2 /* current */
+ lwz r5,_NIP(r1)
+ bl printk
+ b int_return
+87: .string "AltiVec used in kernel (task=%p, pc=%x) \n"
+ .align 4
+
+/*
+ * giveup_altivec(tsk)
+ * Disable AltiVec for the task given as the argument,
+ * and save the AltiVec registers in its thread_struct.
+ * Enables AltiVec for use in the kernel on return.
+ */
+
+ .globl giveup_altivec
+giveup_altivec:
+ mfmsr r5
+ oris r5,r5,MSR_VEC@h
+ SYNC
+ mtmsr r5 /* enable use of AltiVec now */
+ SYNC
+ cmpi 0,r3,0
+ beqlr- /* if no previous owner, done */
+ addi r3,r3,TSS /* want TSS of task */
+ lwz r5,PT_REGS(r3)
+ cmpi 0,r5,0
+ SAVE_32VR(0, r4, r3)
+ MFVSCR(vr0)
+ li r4,TSS_VSCR
+ STVX(vr0, r4, r3)
+ beq 1f
+ lwz r4,_MSR-STACK_FRAME_OVERHEAD(r5)
+ lis r3,MSR_VEC@h
+ andc r4,r4,r3 /* disable AltiVec for previous task */
+ stw r4,_MSR-STACK_FRAME_OVERHEAD(r5)
+1:
+#ifndef __SMP__
+ li r5,0
+ lis r4,last_task_used_altivec@ha
+ stw r5,last_task_used_altivec@l(r4)
+#endif /* __SMP__ */
+ blr
+#endif /* CONFIG_ALTIVEC */
+
#else /* CONFIG_8xx */
.globl giveup_fpu
giveup_fpu:
addi r9,r9,0x6f58 /* translate source addr */
cmpw r31,r9 /* (we have to on chrp) */
beq 7f
-#if 0 // still needed ? breaks on me if I don't disable this
- rlwinm r4,r4,0,8,31 /* translate source address */
- add r4,r4,r3 /* to region mapped with BATs */
-#endif
7: addis r9,r26,klimit@ha /* fetch klimit */
lwz r25,klimit@l(r9)
addis r25,r25,-KERNELBASE@h
cmpi 0,r9,4 /* check for 604 */
cmpi 1,r9,9 /* or 604e */
cmpi 2,r9,10 /* or mach5 */
+ cmpi 3,r9,8 /* check for 750 (G3) */
+ cmpi 4,r9,12 /* or 7400 (G4) */
cror 2,2,6
cror 2,2,10
bne 4f
ori r11,r11,HID0_SIED|HID0_BHTE /* for 604[e], enable */
bne 2,5f
ori r11,r11,HID0_BTCD
-5: mtspr HID0,r11 /* superscalar exec & br history tbl */
+ b 5f
4:
+ cror 14,14,18
+ bne 3,6f
+ ori r11,r11,HID0_SGE|HID0_BHTE|HID0_BTIC|HID0_ABE /* for g3/g4, enable */
+ li r3,0
+ mtspr ICTC,r3
+5: mtspr HID0,r11 /* superscalar exec & br history tbl */
+6:
#endif /* CONFIG_8xx */
#ifdef __SMP__
/* if we're the second cpu stack and r2 are different
li r3,MSR_KERNEL & ~(MSR_IR|MSR_DR)
mtspr SRR0,r4
mtspr SRR1,r3
+ SYNC
rfi
/* Load up the kernel context */
2:
- SYNC /* Force all PTE updates to finish */
tlbia /* Clear all TLB entries */
sync /* wait for tlbia/tlbie to finish */
#ifdef __SMP__
#endif /* __SMP__ */
mtspr SRR0,r3
mtspr SRR1,r4
+ SYNC
rfi /* enable MMU and jump to start_kernel */
/*
mflr r20 /* Return to switch caller */
mfmsr r22
li r0,MSR_FP /* Disable floating-point */
+#ifdef CONFIG_ALTIVEC
+ oris r0,r0,MSR_VEC@h
+#endif /* CONFIG_ALTIVEC */
andc r22,r22,r0
stw r20,_NIP(r1)
stw r22,_MSR(r1)
bdnz 1b
blr
+/*
+ * Copy a whole page. We use the dcbz instruction on the destination
+ * to reduce memory traffic (it eliminates the unnecessary reads of
+ * the destination into cache). This requires that the destination
+ * is cacheable.
+ */
+_GLOBAL(copy_page)
+ li r0,4096/CACHE_LINE_SIZE
+ mtctr r0
+ addi r3,r3,-4
+ addi r4,r4,-4
+ li r5,4
+1: dcbz r5,r3
+ lwz r6,4(r4)
+ lwz r7,8(r4)
+ lwz r8,12(r4)
+ lwzu r9,16(r4)
+ stw r6,4(r3)
+ stw r7,8(r3)
+ stw r8,12(r3)
+ stwu r9,16(r3)
+ lwz r6,4(r4)
+ lwz r7,8(r4)
+ lwz r8,12(r4)
+ lwzu r9,16(r4)
+ stw r6,4(r3)
+ stw r7,8(r3)
+ stw r8,12(r3)
+ stwu r9,16(r3)
+ bdnz 1b
+ blr
+
/*
* Flush entries from the hash table with VSIDs in the range
* given.
mtspr SPRG2,r7
mtspr SRR0,r8
mtspr SRR1,r9
+ SYNC
rfi
1: addis r9,r1,-KERNELBASE@h
lwz r8,20(r9) /* get return address */
mtspr SPRG2,r0
mtspr SRR0,r8
mtspr SRR1,r9
+ SYNC
rfi /* return to caller */
#endif /* CONFIG_8xx */
struct irqdesc {
struct irqaction *action;
struct hw_interrupt_type *ctl;
+ int level;
};
extern struct irqdesc irq_desc[NR_IRQS];
ppc_md.kbd_init_hw = pckbd_init_hw;
#ifdef CONFIG_MAGIC_SYSRQ
ppc_md.kbd_sysrq_xlate = pckbd_sysrq_xlate;
+ ppc_md.SYSRQ_KEY = 0x54;
#endif
#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
_GLOBAL(_get_PVR)
mfspr r3,PVR
blr
+
+_GLOBAL(_get_HID0)
+ mfspr r3,HID0
+ blr
+
+_GLOBAL(_get_ICTC)
+ mfspr r3,ICTC
+ blr
+
+_GLOBAL(_set_ICTC)
+ mtspr ICTC,r3
+ blr
+
+
/*
L2CR functions
Copyright © 1997-1998 by PowerLogix R & D, Inc.
rlwinm r4,r4,16,16,31
cmplwi r4,0x0008
beq thisIs750
+ cmplwi r4,0x000c
+ beq thisIs750
li r3,-1
blr
mfspr r3,PVR
rlwinm r3,r3,16,16,31
cmplwi r3,0x0008
+ beq 1f
+ cmplwi r3,0x000c
li r3,0
bnelr
-
+1:
/* Return the L2CR contents */
mfspr r3,L2CR
blr
* #defines from the assembly-language output.
*/
-#include <stddef.h>
+#include <linux/config.h>
#include <linux/signal.h>
#include <linux/sched.h>
#include <linux/kernel.h>
DEFINE(NEED_RESCHED, offsetof(struct task_struct, need_resched));
DEFINE(TSS_FPR0, offsetof(struct thread_struct, fpr[0]));
DEFINE(TSS_FPSCR, offsetof(struct thread_struct, fpscr));
+#ifdef CONFIG_ALTIVEC
+ DEFINE(TSS_VR0, offsetof(struct thread_struct, vr[0]));
+ DEFINE(TSS_VRSAVE, offsetof(struct thread_struct, vrsave));
+ DEFINE(TSS_VSCR, offsetof(struct thread_struct, vscr));
+#endif /* CONFIG_ALTIVEC */
+
/* Interrupt register frame */
DEFINE(TASK_UNION_SIZE, sizeof(union task_union));
DEFINE(STACK_FRAME_OVERHEAD, STACK_FRAME_OVERHEAD);
*
* Fixed up IPI and restructured a bit
* Cort Dougan <cort@ppc.kernel.org>
+ *
+ * Added initialisation code for Apple Core99 machines, tweaked a few things
+ * to avoid bogus interrupts and to make sure the disable function exits with
+ * the interrupt actually masked.
+ * Benjamin Herrenschmidt <bh40@calva.net>
+ * Todo: map interrupts to all available CPUs after the ack round
*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file COPYING in the main directory of this archive
#include <asm/io.h>
#include <asm/irq.h>
#include "open_pic.h"
+#ifdef __powerpc__
+#include <asm/prom.h>
+#endif
#define REGISTER_DEBUG
#undef REGISTER_DEBUG
+#ifdef __powerpc__
+extern int use_of_interrupt_tree;
+#endif
+
volatile struct OpenPIC *OpenPIC = NULL;
u_int OpenPIC_NumInitSenses __initdata = 0;
u_char *OpenPIC_InitSenses __initdata = NULL;
* I/O functions
*/
#ifdef __i386__
-static inline u_int ld_le32(volatile u_int *addr)
+static inline u_int in_le32(volatile u_int *addr)
{
return *addr;
}
{
u_int val;
- val = ld_le32(addr);
+ val = in_le32(addr);
#ifdef REGISTER_DEBUG
printk("openpic_read(0x%08x) = 0x%08x\n", (u_int)addr, val);
#endif
{
openpic_setfield(addr, OPENPIC_MASK);
/* wait until it's not in use */
+ /* BenH: Is this code really enough ? I would rather check the result
+ * and eventually retry ...
+ */
while (openpic_read(addr) & OPENPIC_ACTIVITY);
openpic_writefield(addr, mask | OPENPIC_MASK, field | OPENPIC_MASK);
}
/*
* Initialize the OpenPIC
*/
+
+/* PoweMac note:
+ *
+ * With BootX, we consider the controller as beeing already initialized by MacOS
+ * and we only mask out interrupts.
+ * With OF booting, we initialize the interrupts that we find in the device tree,
+ * other ones are just masked out.
+ * Note: We might want to adjust priorities too.
+ */
+
__initfunc(void openpic_init(int main_pic))
{
u_int t, i;
OPENPIC_FEATURE_LAST_SOURCE_SHIFT) + 1;
printk("OpenPIC Version %s (%d CPUs and %d IRQ sources) at %p\n", version,
NumProcessors, NumSources, OpenPIC);
- timerfreq = openpic_read(&OpenPIC->Global.Timer_Frequency);
- printk("OpenPIC timer frequency is ");
- if (timerfreq)
- printk("%d Hz\n", timerfreq);
- else
- printk("not set\n");
-
+ /* Apple's OpenPIC is an IBM MPIC without the timer. */
+ if (_machine != _MACH_Pmac) {
+ timerfreq = openpic_read(&OpenPIC->Global.Timer_Frequency);
+ printk("OpenPIC timer frequency is ");
+ if (timerfreq)
+ printk("%d Hz\n", timerfreq);
+ else
+ printk("not set\n");
+ }
+
if ( main_pic )
{
/* Initialize timer interrupts */
/* Initialize IPI interrupts */
for (i = 0; i < OPENPIC_NUM_IPI; i++) {
- openpic_initipi(i, 10, OPENPIC_VEC_IPI+i);
+ openpic_initipi(i, 0/*10*/, OPENPIC_VEC_IPI+i);
}
- /* Initialize external interrupts */
- for (i = 0; i < NumSources; i++) {
- /* Enabled, Priority 8 */
- openpic_initirq(i, 8, open_pic.irq_offset+i, 0,
- i < OpenPIC_NumInitSenses ? OpenPIC_InitSenses[i] : 1);
- /* Processor 0 */
- openpic_mapirq(i, 1<<0);
+ if (_machine != _MACH_Pmac) {
+ /* Initialize external interrupts */
+ for (i = 0; i < NumSources; i++) {
+ /* Enabled, Priority 8 */
+ openpic_initirq(i, 8, open_pic.irq_offset+i, 0,
+ i < OpenPIC_NumInitSenses ? OpenPIC_InitSenses[i] : 1);
+ /* Processor 0 */
+ openpic_mapirq(i, 1<<0);
+ }
+ } else {
+ /* Prevent any interrupt from occuring during initialisation.
+ * Hum... I beleive this is not necessary, Apple does that in
+ * Darwin's PowerExpress code.
+ */
+ openpic_set_priority(0, 0xf);
+
+ /* First disable all interrupts and map them to CPU 0 */
+ for (i = 0; i < NumSources; i++) {
+ openpic_disable_irq(i);
+ openpic_mapirq(i, 1<<0);
+ }
+
+ /* If we use the device tree, then lookup all interrupts and
+ * initialize them according to sense infos found in the tree
+ */
+ if (use_of_interrupt_tree) {
+ struct device_node* np = find_all_nodes();
+ while(np) {
+ int j, pri;
+ pri = strcmp(np->name, "programmer-switch") ? 2 : 7;
+ for (j=0;j<np->n_intrs;j++) {
+ openpic_initirq( np->intrs[j].line,
+ pri,
+ np->intrs[j].line,
+ np->intrs[j].sense,
+ np->intrs[j].sense);
+ irq_desc[np->intrs[j].line].level = np->intrs[j].sense;
+ }
+ np = np->next;
+ }
+ } else {
+ /* Fixme: read level value from controller */
+ printk("openpic: WARNING, openpic running without interrupt tree\n");
+ }
}
-
+
/* Initialize the spurious interrupt */
openpic_set_spurious(OPENPIC_VEC_SPURIOUS);
/* Gemini has no i8259 */
- if ( _machine != _MACH_gemini )
- {
+ if (( _machine != _MACH_gemini ) && (_machine != _MACH_Pmac)) {
/* SIOint (8259 cascade) is special */
openpic_initirq(0, 8, open_pic.irq_offset, 1, 1);
openpic_mapirq(0, 1<<0);
}
openpic_set_priority(0, 0);
openpic_disable_8259_pass_through();
+
+ /* We ack pending interrupts to avoid blocking them */
+ if (_machine == _MACH_Pmac) {
+ for (i = 0; i < NumSources; i++) {
+ (void)openpic_irq(0);
+ openpic_eoi(0);
+ }
+ }
}
}
{
check_arg_cpu(cpu);
openpic_write(&OpenPIC->THIS_CPU.EOI, 0);
+ (void)openpic_read(&OpenPIC->THIS_CPU.EOI);
}
{
check_arg_irq(irq);
openpic_clearfield(&OpenPIC->Source[irq].Vector_Priority, OPENPIC_MASK);
+ /* make sure mask gets to controller before we return to user */
+ do {
+ mb();
+ } while(openpic_readfield(&OpenPIC->Source[irq].Vector_Priority,
+ OPENPIC_MASK));
}
void openpic_disable_irq(u_int irq)
{
check_arg_irq(irq);
openpic_setfield(&OpenPIC->Source[irq].Vector_Priority, OPENPIC_MASK);
+ /* make sure mask gets to controller before we return to user */
+ do {
+ mb();
+ } while(!openpic_readfield(&OpenPIC->Source[irq].Vector_Priority,
+ OPENPIC_MASK));
}
/*
check_arg_vec(vec);
openpic_safe_writefield(&OpenPIC->Source[irq].Vector_Priority,
OPENPIC_PRIORITY_MASK | OPENPIC_VECTOR_MASK |
- OPENPIC_SENSE_POLARITY | OPENPIC_SENSE_LEVEL,
+ OPENPIC_POLARITY_MASK | OPENPIC_SENSE_MASK,
(pri << OPENPIC_PRIORITY_SHIFT) | vec |
- (pol ? OPENPIC_SENSE_POLARITY : 0) |
- (sense ? OPENPIC_SENSE_LEVEL : 0));
+ (pol ? OPENPIC_POLARITY_POSITIVE :
+ OPENPIC_POLARITY_NEGATIVE) |
+ (sense ? OPENPIC_SENSE_LEVEL : OPENPIC_SENSE_EDGE));
}
/*
for (; node != 0;node = node->sibling) {
class_code = (unsigned int *) get_property(node, "class-code", 0);
- if((*class_code >> 8) == PCI_CLASS_BRIDGE_PCI)
+ if(class_code && (*class_code >> 8) == PCI_CLASS_BRIDGE_PCI)
fix_intr(node->child, dev);
reg = (unsigned int *) get_property(node, "reg", 0);
if (reg == 0 || ((reg[0] >> 8) & 0xff) != dev->devfn)
struct bridge_data **bridges, *bridge_list;
static int max_bus;
+struct uninorth_data {
+ struct device_node* node;
+ volatile unsigned int* cfg_addr;
+ volatile unsigned int* cfg_data;
+};
+
+static struct uninorth_data uninorth_bridges[3];
+static int uninorth_count;
+static int uninorth_default = -1;
+
+
+
static void add_bridges(struct device_node *dev, unsigned long *mem_ptr);
/*
return 0;
}
+/* This function only works for bus 0, uni-N uses a different mecanism for
+ * other busses (see below)
+ */
+#define UNI_N_CFA0(devfn, off) \
+ ((1 << (unsigned long)PCI_SLOT(dev_fn)) \
+ | (((unsigned long)PCI_FUNC(dev_fn)) << 8) \
+ | (((unsigned long)(off)) & 0xFCUL))
+
+/* This one is for type 1 config accesses */
+#define UNI_N_CFA1(bus, devfn, off) \
+ ((((unsigned long)(bus)) << 16) \
+ |(((unsigned long)(devfn)) << 8) \
+ |(((unsigned long)(off)) & 0xFCUL) \
+ |1UL)
+
+
+/* We should really use RTAS here, unfortunately, it's not available with BootX.
+ * (one more reason for writing a beautiful OF booter). I'll do the RTAS stuff
+ * later, once I have something that works enough with BootX.
+ */
+__pmac static
+unsigned int
+uni_north_access_data(unsigned char bus, unsigned char dev_fn,
+ unsigned char offset)
+{
+ struct device_node *node, *bridge_node;
+ int bridge = uninorth_default;
+ unsigned int caddr;
+
+ if (bus == 0) {
+ if (PCI_SLOT(dev_fn) < 11) {
+ return 0;
+ }
+ /* We look for the OF device corresponding to this bus/devfn pair. If we
+ * don't find it, we default to the external PCI */
+ bridge_node = NULL;
+ node = find_pci_device_OFnode(bus, dev_fn & 0xf8);
+ if (node) {
+ /* note: we don't stop on the first occurence since we need to go
+ * up to the root bridge */
+ do {
+ if (!strcmp(node->type, "pci"))
+ bridge_node = node;
+ node=node->parent;
+ } while (node);
+ }
+ if (bridge_node) {
+ int i;
+ for (i=0;i<uninorth_count;i++)
+ if (uninorth_bridges[i].node == bridge_node) {
+ bridge = i;
+ break;
+ }
+ }
+ caddr = UNI_N_CFA0(dev_fn, offset);
+ } else
+ caddr = UNI_N_CFA1(bus, dev_fn, offset);
+
+ if (bridge == -1) {
+ printk(KERN_WARNING "pmac_pci: no default bridge !\n");
+ return 0;
+ }
+
+ /* Uninorth will return garbage if we don't read back the value ! */
+ out_le32(uninorth_bridges[bridge].cfg_addr, caddr);
+ (void)in_le32(uninorth_bridges[bridge].cfg_addr);
+ /* Yes, offset is & 7, not & 3 ! */
+ return (unsigned int)(uninorth_bridges[bridge].cfg_data) + (offset & 0x07);
+}
+
+__pmac
+int uni_pcibios_read_config_byte(unsigned char bus, unsigned char dev_fn,
+ unsigned char offset, unsigned char *val)
+{
+ unsigned int addr;
+
+ *val = 0xff;
+ addr = uni_north_access_data(bus, dev_fn, offset);
+ if (!addr)
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ *val = in_8((volatile unsigned char*)addr);
+ return PCIBIOS_SUCCESSFUL;
+}
+
+__pmac
+int uni_pcibios_read_config_word(unsigned char bus, unsigned char dev_fn,
+ unsigned char offset, unsigned short *val)
+{
+ unsigned int addr;
+
+ *val = 0xffff;
+ addr = uni_north_access_data(bus, dev_fn, offset);
+ if (!addr)
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ *val = in_le16((volatile unsigned short*)addr);
+ return PCIBIOS_SUCCESSFUL;
+}
+
+__pmac
+int uni_pcibios_read_config_dword(unsigned char bus, unsigned char dev_fn,
+ unsigned char offset, unsigned int *val)
+{
+ unsigned int addr;
+
+ *val = 0xffff;
+ addr = uni_north_access_data(bus, dev_fn, offset);
+ if (!addr)
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ *val = in_le32((volatile unsigned int*)addr);
+ return PCIBIOS_SUCCESSFUL;
+}
+
+__pmac
+int uni_pcibios_write_config_byte(unsigned char bus, unsigned char dev_fn,
+ unsigned char offset, unsigned char val)
+{
+ unsigned int addr;
+
+ addr = uni_north_access_data(bus, dev_fn, offset);
+ if (!addr)
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ out_8((volatile unsigned char *)addr, val);
+ (void)in_8((volatile unsigned char *)addr);
+ return PCIBIOS_SUCCESSFUL;
+}
+
+__pmac
+int uni_pcibios_write_config_word(unsigned char bus, unsigned char dev_fn,
+ unsigned char offset, unsigned short val)
+{
+ unsigned int addr;
+
+ addr = uni_north_access_data(bus, dev_fn, offset);
+ if (!addr)
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ out_le16((volatile unsigned short *)addr, val);
+ (void)in_le16((volatile unsigned short *)addr);
+ return PCIBIOS_SUCCESSFUL;
+}
+
+__pmac
+int uni_pcibios_write_config_dword(unsigned char bus, unsigned char dev_fn,
+ unsigned char offset, unsigned int val)
+{
+ unsigned int addr;
+
+ addr = uni_north_access_data(bus, dev_fn, offset);
+ if (!addr)
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ out_le32((volatile unsigned int *)addr, val);
+ (void)in_le32((volatile unsigned int *)addr);
+ return PCIBIOS_SUCCESSFUL;
+}
+
+
__pmac
int pmac_pcibios_read_config_byte(unsigned char bus, unsigned char dev_fn,
unsigned char offset, unsigned char *val)
bp->io_base);
}
+#define GRACKLE_PICR1_STG 0x00000040
+#define GRACKLE_PICR1_LOOPSNOOP 0x00000010
+
+/* N.B. this is called before bridges is initialized, so we can't
+ use grackle_pcibios_{read,write}_config_dword. */
+static inline void grackle_set_stg(struct bridge_data *bp, int enable)
+{
+ unsigned int val;
+
+ out_be32(bp->cfg_addr, GRACKLE_CFA(0, 0, 0xa8));
+ val = in_le32((volatile unsigned int *)bp->cfg_data);
+ val = enable? (val | GRACKLE_PICR1_STG) :
+ (val & ~GRACKLE_PICR1_STG);
+ out_be32(bp->cfg_addr, GRACKLE_CFA(0, 0, 0xa8));
+ out_le32((volatile unsigned int *)bp->cfg_data, val);
+}
+
+static inline void grackle_set_loop_snoop(struct bridge_data *bp, int enable)
+{
+ unsigned int val;
+
+ out_be32(bp->cfg_addr, GRACKLE_CFA(0, 0, 0xa8));
+ val = in_le32((volatile unsigned int *)bp->cfg_data);
+ val = enable? (val | GRACKLE_PICR1_LOOPSNOOP) :
+ (val & ~GRACKLE_PICR1_LOOPSNOOP);
+ out_be32(bp->cfg_addr, GRACKLE_CFA(0, 0, 0xa8));
+ out_le32((volatile unsigned int *)bp->cfg_data, val);
+}
+
+
__initfunc(unsigned long pmac_find_bridges(unsigned long mem_start, unsigned long mem_end))
{
int bus;
printk(KERN_INFO "PCI buses %d..%d", bus_range[0],
bus_range[1]);
printk(" controlled by %s at %x\n", dev->name, addr->address);
+ if (device_is_compatible(dev, "uni-north")) {
+ int i = uninorth_count++;
+ uninorth_bridges[i].cfg_addr = ioremap(addr->address + 0x800000, 0x1000);
+ uninorth_bridges[i].cfg_data = ioremap(addr->address + 0xc00000, 0x1000);
+ uninorth_bridges[i].node = dev;
+ /* XXX This is the bridge with the PCI expansion bus. This is also the
+ * address of the bus that will receive type 1 config accesses and io
+ * accesses. Appears to be correct for iMac DV and G4 Sawtooth too.
+ * That means that we cannot do io cycles on the AGP bus nor the internal
+ * ethernet/fw bus. Fortunately, they appear not to be needed on iMac DV
+ * and G4 neither.
+ */
+ if (addr->address == 0xf2000000)
+ uninorth_default = i;
+ else
+ continue;
+ }
bp = (struct bridge_data *) *mem_ptr;
*mem_ptr += sizeof(struct bridge_data);
- if (strcmp(dev->name, "pci") != 0) {
- bp->cfg_addr = (volatile unsigned int *)
- ioremap(addr->address + 0x800000, 0x1000);
- bp->cfg_data = (volatile unsigned char *)
- ioremap(addr->address + 0xc00000, 0x1000);
- bp->io_base = (void *) ioremap(addr->address, 0x10000);
- } else {
- /* XXX */
+ if (device_is_compatible(dev, "uni-north")) {
+ bp->cfg_addr = 0;
+ bp->cfg_data = 0;
+ /* is 0x10000 enough for io space ? */
+ bp->io_base = (void *)ioremap(addr->address, 0x10000);
+ } else if (strcmp(dev->name, "pci") == 0) {
+ /* XXX assume this is a mpc106 (grackle) */
bp->cfg_addr = (volatile unsigned int *)
ioremap(0xfec00000, 0x1000);
bp->cfg_data = (volatile unsigned char *)
ioremap(0xfee00000, 0x1000);
bp->io_base = (void *) ioremap(0xfe000000, 0x20000);
+ if (machine_is_compatible("AAPL,PowerBook1998"))
+ grackle_set_loop_snoop(bp, 1);
+#if 0 /* Disabled for now, HW problems ??? */
+ grackle_set_stg(bp, 1);
+#endif
+ } else {
+ /* a `bandit' or `chaos' bridge */
+ bp->cfg_addr = (volatile unsigned int *)
+ ioremap(addr->address + 0x800000, 0x1000);
+ bp->cfg_data = (volatile unsigned char *)
+ ioremap(addr->address + 0xc00000, 0x1000);
+ bp->io_base = (void *) ioremap(addr->address, 0x10000);
}
if (isa_io_base == 0)
isa_io_base = (unsigned long) bp->io_base;
if (pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin) ||
!pin)
continue; /* No interrupt generated -> no fixup */
- fix_intr(bp->node->child, dev);
+ /* We iterate all instances of uninorth for now */
+ if (uninorth_count && dev->bus->number == 0) {
+ int i;
+ for (i=0;i<uninorth_count;i++)
+ fix_intr(uninorth_bridges[i].node->child, dev);
+ } else
+ fix_intr(bp->node->child, dev);
}
}
void
pmac_setup_pci_ptrs(void))
{
- if (find_devices("pci") != 0) {
- /* looks like a G3 powermac */
- set_config_access_method(grackle);
+ struct device_node* np;
+
+ np = find_devices("pci");
+ if (np != 0) {
+ if (device_is_compatible(np, "uni-north")) {
+ /* looks like an Core99 powermac */
+ set_config_access_method(uni);
+ } else {
+ /* looks like a G3 powermac */
+ set_config_access_method(grackle);
+ }
} else {
set_config_access_method(pmac);
}
#include <linux/sched.h>
#include <linux/signal.h>
#include <linux/pci.h>
+#include <linux/openpic.h>
#include <asm/pci-bridge.h>
#include <asm/io.h>
#include <asm/smp.h>
static int max_irqs;
static int max_real_irqs;
+static int has_openpic = 0;
#define MAXCOUNT 10000000
pmac_set_irq_mask(irq_nr);
}
+static void pmac_openpic_mask_irq(unsigned int irq_nr)
+{
+ openpic_disable_irq(irq_nr);
+}
+
+static void pmac_openpic_unmask_irq(unsigned int irq_nr)
+{
+ openpic_enable_irq(irq_nr);
+}
+
+
+
struct hw_interrupt_type pmac_pic = {
" PMAC-PIC ",
NULL,
0
};
+struct hw_interrupt_type pmac_open_pic = {
+ " OpenPIC ",
+ NULL,
+ NULL,
+ NULL,
+ pmac_openpic_unmask_irq,
+ pmac_openpic_mask_irq,
+ NULL,/*pmac_openpic_mask_irq,*/
+ 0
+};
+
static void gatwick_action(int cpl, void *dev_id, struct pt_regs *regs)
{
int irq, bits;
}
#endif /* __SMP__ */
+ /* Yeah, I know, this could be a separate do_IRQ function */
+ if (has_openpic) {
+ irq = openpic_irq(0);
+ if (irq == OPENPIC_VEC_SPURIOUS) {
+ /* Spurious interrupts should never be ack'ed */
+ ppc_spurious_interrupts++;
+ } else {
+ /* Can this happen ? (comes from CHRP code) */
+ if (irq < 0) {
+ printk(KERN_DEBUG "Bogus interrupt %d from PC = %lx\n",
+ irq, regs->nip);
+ ppc_spurious_interrupts++;
+ } else {
+ if (!irq_desc[irq].level)
+ openpic_eoi(0);
+ ppc_irq_dispatch_handler( regs, irq );
+ if (irq_desc[irq].level)
+ openpic_eoi(0);
+ }
+ }
+ return;
+ }
+
for (irq = max_real_irqs - 1; irq > 0; irq -= 32) {
int i = irq >> 5;
bits = ld_le32(&pmac_irq_hw[i]->flag)
volatile struct pmac_irq_hw *addr;
int second_irq;
+ /* We first try to detect Apple's new Core99 chipset, since mac-io
+ * is quite different on those machines and contains an IBM MPIC2.
+ */
+ irqctrler = find_type_devices("open-pic");
+ if (irqctrler != NULL) {
+ printk("PowerMac using OpenPIC irq controller\n");
+ if (irqctrler->n_addrs > 0) {
+#ifdef CONFIG_XMON
+ struct device_node* pswitch;
+#endif /* CONFIG_XMON */
+ OpenPIC = (volatile struct OpenPIC *)
+ ioremap(irqctrler->addrs[0].address,
+ irqctrler->addrs[0].size);
+ for ( i = 0 ; i < NR_IRQS ; i++ ) {
+ irq_desc[i].ctl = &pmac_open_pic;
+ irq_desc[i].level = 0;
+ }
+ openpic_init(1);
+ has_openpic = 1;
+#ifdef CONFIG_XMON
+ pswitch = find_devices("programmer-switch");
+ if (pswitch && pswitch->n_intrs)
+ request_irq(pswitch->intrs[0].line, xmon_irq, 0,
+ "NMI - XMON", 0);
+#endif /* CONFIG_XMON */
+ return;
+ }
+ irqctrler = NULL;
+ }
+
/*
* G3 powermacs and 1999 G3 PowerBooks have 64 interrupts,
* 1998 G3 Series PowerBooks have 128,
extern char pckbd_unexpected_up(unsigned char keycode);
extern void pckbd_leds(unsigned char leds);
extern void pckbd_init_hw(void);
+extern void pmac_nvram_update(void);
unsigned char drive_info;
extern char saved_command_line[];
+extern int pmac_newworld;
+
#define DEFAULT_ROOT_DEVICE 0x0801 /* sda1 - slightly silly choice */
extern void zs_kgdb_hook(int tty_num);
static void ohare_init(void);
static void init_p2pbridge(void);
+static void init_uninorth(void);
__pmac
int
len += sprintf(buffer+len, "l2cr override\t: 0x%x\n", *l2cr);
}
}
+
+ /* Indicate newworld/oldworld */
+ len += sprintf(buffer+len, "pmac-generation\t: %s\n",
+ pmac_newworld ? "NewWorld" : "OldWorld");
return len;
}
if (fp != 0) {
switch (_get_PVR() >> 16) {
case 4: /* 604 */
+ case 8: /* G3 */
case 9: /* 604e */
case 10: /* mach V (604ev5) */
+ case 12: /* G4 */
case 20: /* 620 */
loops_per_sec = *fp;
break;
*memory_start_p = pmac_find_bridges(*memory_start_p, *memory_end_p);
init_p2pbridge();
-
+ init_uninorth();
+
/* Checks "l2cr-value" property in the registry */
- if ( (_get_PVR() >> 16) == 8) {
+ if ( (_get_PVR() >> 16) == 8 || (_get_PVR() >> 16) == 12 ) {
struct device_node *np = find_devices("cpus");
if (np == 0)
np = find_type_devices("cpu");
printk(KERN_INFO "L2CR overriden (0x%x), backside cache is %s\n",
ppc_override_l2cr_value, (ppc_override_l2cr_value & 0x80000000)
? "enabled" : "disabled");
-
feature_init();
#ifdef CONFIG_KGDB
}
}
+__initfunc(static void init_uninorth(void))
+{
+ /*
+ * Turns on the gmac clock so that it responds to PCI cycles
+ * later, the driver may want to turn it off again to save
+ * power when interface is down
+ */
+ struct device_node* uni_n = find_devices("uni-n");
+ struct device_node* gmac = find_devices("ethernet");
+ unsigned long* addr;
+
+ if (!uni_n || uni_n->n_addrs < 1)
+ return;
+ addr = ioremap(uni_n->addrs[0].address, 0x300);
+
+ while(gmac) {
+ if (device_is_compatible(gmac, "gmac"))
+ break;
+ gmac = gmac->next;
+ }
+ if (gmac) {
+ *(addr + 8) |= 2;
+ eieio();
+ }
+}
+
extern char *bootpath;
extern char *bootdevice;
void *boot_host;
#endif
#ifdef CONFIG_BLK_DEV_IDE_PMAC
-extern int pmac_ide_count;
-extern struct device_node *pmac_ide_node[];
-static int ide_majors[] = { 3, 22, 33, 34, 56, 57 };
+
+extern kdev_t pmac_find_ide_boot(char *bootdevice, int n);
__initfunc(kdev_t find_ide_boot(void))
{
char *p;
- int i, n;
+ int n;
if (bootdevice == NULL)
return 0;
return 0;
n = p - bootdevice;
- /*
- * Look through the list of IDE interfaces for this one.
- */
- for (i = 0; i < pmac_ide_count; ++i) {
- char *name = pmac_ide_node[i]->full_name;
- if (memcmp(name, bootdevice, n) == 0 && name[n] == 0) {
- /* XXX should cope with the 2nd drive as well... */
- return MKDEV(ide_majors[i], 0);
- }
- }
-
- return 0;
+ return pmac_find_ide_boot(bootdevice, n);
}
#endif /* CONFIG_BLK_DEV_IDE_PMAC */
if (boot_dev == 0 || dev == boot_dev) {
ROOT_DEV = MKDEV(MAJOR(dev), MINOR(dev) + part);
boot_dev = NODEV;
- printk(" (root)");
+ printk(" (root on %d)", part);
}
}
{
struct adb_request req;
+ pmac_nvram_update();
+
switch (adb_hardware) {
case ADB_VIACUDA:
cuda_request(&req, NULL, 2, CUDA_PACKET,
{
struct adb_request req;
+ pmac_nvram_update();
+
switch (adb_hardware) {
case ADB_VIACUDA:
cuda_request(&req, NULL, 2, CUDA_PACKET,
void
pmac_halt(void)
{
- pmac_power_off();
}
return 0;
}
+#if defined(CONFIG_BLK_DEV_IDE_PMAC)
+extern ide_ioreg_t pmac_ide_get_base(int index);
+#endif
+
ide_ioreg_t
pmac_ide_default_io_base(int index)
{
#if defined(CONFIG_BLK_DEV_IDE_PMAC)
- return pmac_ide_regbase[index];
+ return pmac_ide_get_base(index);
#else
return 0;
#endif
ppc_md.kbd_init_hw = mackbd_init_hw;
#ifdef CONFIG_MAGIC_SYSRQ
ppc_md.kbd_sysrq_xlate = mackbd_sysrq_xlate;
+ ppc_md.SYSRQ_KEY = 0x69;
#endif
#endif
/*
* Miscellaneous procedures for dealing with the PowerMac hardware.
+ * Contains support for the nvram.
+ *
+ * Copyright (C) 2000 Paul Mackerras
+ * Copyright (C) 2000 Benjamin Herrenschmidt
+ *
+ * ToDo: Handle type 0 and type 1 "NameRegistry" NVRAM properties. Those
+ * contain, among other things, the brightness, video mode, etc...
*/
#include <linux/kernel.h>
#include <linux/stddef.h>
#include <linux/reboot.h>
#include <linux/nvram.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
#include <asm/init.h>
#include <asm/ptrace.h>
#include <asm/io.h>
#include <asm/prom.h>
#include <asm/adb.h>
#include <asm/pmu.h>
+#include <asm/machdep.h>
+#include <asm/nvram.h>
+
+#undef DEBUG
/*
* Read and write the non-volatile RAM on PowerMacs and CHRP machines.
static int nvram_naddrs;
static volatile unsigned char *nvram_addr;
static volatile unsigned char *nvram_data;
-static int nvram_mult;
+static int nvram_mult, is_core_99;
+static char* nvram_image;
+static int core99_bank = 0;
+
+extern int pmac_newworld;
+
+#define NVRAM_SIZE 0x2000 /* 8kB of non-volatile RAM */
+
+#define CORE99_SIGNATURE 0x5a
+#define CORE99_ADLER_START 0x14
+
+/* Core99 nvram is a flash */
+#define CORE99_FLASH_STATUS_DONE 0x80
+#define CORE99_FLASH_STATUS_ERR 0x38
+#define CORE99_FLASH_CMD_ERASE_CONFIRM 0xd0
+#define CORE99_FLASH_CMD_ERASE_SETUP 0x20
+#define CORE99_FLASH_CMD_RESET 0xff
+#define CORE99_FLASH_CMD_WRITE_SETUP 0x40
+
+
+/* CHRP NVRAM header */
+struct chrp_header {
+ u8 signature;
+ u8 cksum;
+ u16 len;
+ char name[12];
+ u8 data[0];
+};
+
+struct core99_header {
+ struct chrp_header hdr;
+ u32 adler;
+ u32 generation;
+ u32 reserved[2];
+};
+
+static int nvram_partitions[3];
+
+static u8
+chrp_checksum(struct chrp_header* hdr)
+{
+ u8 *ptr;
+ u16 sum = hdr->signature;
+ for (ptr = (u8 *)&hdr->len; ptr < hdr->data; ptr++)
+ sum += *ptr;
+ while (sum > 0xFF)
+ sum = (sum & 0xFF) + (sum>>8);
+ return sum;
+}
+
+static u32
+core99_calc_adler(u8 *buffer)
+{
+ int cnt;
+ u32 low, high;
+
+ buffer += CORE99_ADLER_START;
+ low = 1;
+ high = 0;
+ for (cnt=0; cnt<(NVRAM_SIZE-CORE99_ADLER_START); cnt++) {
+ if ((cnt % 5000) == 0) {
+ high %= 65521UL;
+ high %= 65521UL;
+ }
+ low += buffer[cnt];
+ high += low;
+ }
+ low %= 65521UL;
+ high %= 65521UL;
+
+ return (high << 16) | low;
+}
+
+static u32
+core99_check(u8* datas)
+{
+ struct core99_header* hdr99 = (struct core99_header*)datas;
+
+ if (hdr99->hdr.signature != CORE99_SIGNATURE) {
+#ifdef DEBUG
+ printk("Invalid signature\n");
+#endif
+ return 0;
+ }
+ if (hdr99->hdr.cksum != chrp_checksum(&hdr99->hdr)) {
+#ifdef DEBUG
+ printk("Invalid checksum\n");
+#endif
+ return 0;
+ }
+ if (hdr99->adler != core99_calc_adler(datas)) {
+#ifdef DEBUG
+ printk("Invalid adler\n");
+#endif
+ return 0;
+ }
+ return hdr99->generation;
+}
+
+static int
+core99_erase_bank(int bank)
+{
+ int stat, i;
+
+ u8* base = (u8 *)nvram_data + core99_bank*NVRAM_SIZE;
+
+ out_8(base, CORE99_FLASH_CMD_ERASE_SETUP);
+ out_8(base, CORE99_FLASH_CMD_ERASE_CONFIRM);
+ do { stat = in_8(base); }
+ while(!(stat & CORE99_FLASH_STATUS_DONE));
+ out_8(base, CORE99_FLASH_CMD_RESET);
+ if (stat & CORE99_FLASH_STATUS_ERR) {
+ printk("nvram: flash error 0x%02x on erase !\n", stat);
+ return -ENXIO;
+ }
+ for (i=0; i<NVRAM_SIZE; i++)
+ if (base[i] != 0xff) {
+ printk("nvram: flash erase failed !\n");
+ return -ENXIO;
+ }
+ return 0;
+}
-#define NVRAM_SIZE 0x2000 /* 8kB of non-volatile RAM */
+static int
+core99_write_bank(int bank, u8* datas)
+{
+ int i, stat = 0;
+
+ u8* base = (u8 *)nvram_data + core99_bank*NVRAM_SIZE;
+
+ for (i=0; i<NVRAM_SIZE; i++) {
+ out_8(base+i, CORE99_FLASH_CMD_WRITE_SETUP);
+ out_8(base+i, datas[i]);
+ do { stat = in_8(base); }
+ while(!(stat & CORE99_FLASH_STATUS_DONE));
+ if (stat & CORE99_FLASH_STATUS_ERR)
+ break;
+ }
+ out_8(base, CORE99_FLASH_CMD_RESET);
+ if (stat & CORE99_FLASH_STATUS_ERR) {
+ printk("nvram: flash error 0x%02x on write !\n", stat);
+ return -ENXIO;
+ }
+ for (i=0; i<NVRAM_SIZE; i++)
+ if (base[i] != datas[i]) {
+ printk("nvram: flash write failed !\n");
+ return -ENXIO;
+ }
+ return 0;
+}
+static void
+lookup_partitions(void)
+{
+ u8 buffer[17];
+ int i, offset;
+ struct chrp_header* hdr;
+
+ if (pmac_newworld) {
+ nvram_partitions[pmac_nvram_OF] = -1;
+ nvram_partitions[pmac_nvram_XPRAM] = -1;
+ nvram_partitions[pmac_nvram_NR] = -1;
+ hdr = (struct chrp_header *)buffer;
+
+ offset = 0;
+ do {
+ for (i=0;i<16;i++)
+ buffer[i] = nvram_read_byte(offset+i);
+ if (!strcmp(hdr->name, "common"))
+ nvram_partitions[pmac_nvram_OF] = offset + 0x10;
+ if (!strcmp(hdr->name, "APL,MacOS75")) {
+ nvram_partitions[pmac_nvram_XPRAM] = offset + 0x10;
+ nvram_partitions[pmac_nvram_NR] = offset + 0x110;
+ }
+ offset += (hdr->len * 0x10);
+ } while(offset < NVRAM_SIZE);
+ } else {
+ nvram_partitions[pmac_nvram_OF] = 0x1800;
+ nvram_partitions[pmac_nvram_XPRAM] = 0x1300;
+ nvram_partitions[pmac_nvram_NR] = 0x1400;
+ }
+#ifdef DEBUG
+ printk("nvram: OF partition at 0x%x\n", nvram_partitions[pmac_nvram_OF]);
+ printk("nvram: XP partition at 0x%x\n", nvram_partitions[pmac_nvram_XPRAM]);
+ printk("nvram: NR partition at 0x%x\n", nvram_partitions[pmac_nvram_NR]);
+#endif
+}
__init
void pmac_nvram_init(void)
{
struct device_node *dp;
+ nvram_naddrs = 0;
+
dp = find_devices("nvram");
if (dp == NULL) {
printk(KERN_ERR "Can't find NVRAM device\n");
- nvram_naddrs = 0;
return;
}
nvram_naddrs = dp->n_addrs;
- if (_machine == _MACH_chrp && nvram_naddrs == 1) {
+ is_core_99 = device_is_compatible(dp, "nvram,flash");
+ printk("pmac nvram is core99: %d\n", is_core_99);
+ if (is_core_99) {
+ int i;
+ u32 gen_bank0, gen_bank1;
+
+ if (nvram_naddrs < 1) {
+ printk(KERN_ERR "nvram: no address\n");
+ return;
+ }
+ nvram_image = kmalloc(NVRAM_SIZE, GFP_KERNEL);
+ if (!nvram_image) {
+ printk(KERN_ERR "nvram: can't allocate image\n");
+ return;
+ }
+ nvram_data = ioremap(dp->addrs[0].address, NVRAM_SIZE*2);
+#ifdef DEBUG
+ printk("nvram: Checking bank 0...\n");
+#endif
+ gen_bank0 = core99_check((u8 *)nvram_data);
+ gen_bank1 = core99_check((u8 *)nvram_data + NVRAM_SIZE);
+ core99_bank = (gen_bank0 < gen_bank1) ? 1 : 0;
+#ifdef DEBUG
+ printk("nvram: gen0=%d, gen1=%d\n", gen_bank0, gen_bank1);
+ printk("nvram: Active bank is: %d\n", core99_bank);
+#endif
+ for (i=0; i<NVRAM_SIZE; i++)
+ nvram_image[i] = nvram_data[i + core99_bank*NVRAM_SIZE];
+ } else if (_machine == _MACH_chrp && nvram_naddrs == 1) {
nvram_data = ioremap(dp->addrs[0].address, dp->addrs[0].size);
nvram_mult = 1;
} else if (nvram_naddrs == 1) {
printk(KERN_ERR "Don't know how to access NVRAM with %d addresses\n",
nvram_naddrs);
}
+ lookup_partitions();
}
-unsigned char nvram_read_byte(int addr)
+void
+pmac_nvram_update(void)
+{
+ struct core99_header* hdr99;
+
+ if (!is_core_99 || !nvram_data || !nvram_image)
+ return;
+ if (!memcmp(nvram_image, (u8*)nvram_data + core99_bank*NVRAM_SIZE,
+ NVRAM_SIZE))
+ return;
+#ifdef DEBUG
+ printk("Updating nvram...\n");
+#endif
+ hdr99 = (struct core99_header*)nvram_image;
+ hdr99->generation++;
+ hdr99->hdr.signature = CORE99_SIGNATURE;
+ hdr99->hdr.cksum = chrp_checksum(&hdr99->hdr);
+ hdr99->adler = core99_calc_adler(nvram_image);
+ core99_bank = core99_bank ? 0 : 1;
+ if (core99_erase_bank(core99_bank)) {
+ printk("nvram: Error erasing bank %d\n", core99_bank);
+ return;
+ }
+ if (core99_write_bank(core99_bank, nvram_image))
+ printk("nvram: Error writing bank %d\n", core99_bank);
+}
+
+unsigned char
+nvram_read_byte(int addr)
{
struct adb_request req;
pmu_poll();
return req.reply[1];
case 1:
+ if (is_core_99)
+ return nvram_image[addr];
return nvram_data[(addr & (NVRAM_SIZE - 1)) * nvram_mult];
case 2:
*nvram_addr = addr >> 5;
return 0;
}
-void nvram_write_byte(unsigned char val, int addr)
+void
+nvram_write_byte(unsigned char val, int addr)
{
struct adb_request req;
pmu_poll();
break;
case 1:
+ if (is_core_99) {
+ nvram_image[addr] = val;
+ break;
+ }
nvram_data[(addr & (NVRAM_SIZE - 1)) * nvram_mult] = val;
break;
case 2:
}
eieio();
}
+
+int
+pmac_get_partition(int partition)
+{
+ return nvram_partitions[partition];
+}
+
+u8
+pmac_xpram_read(int xpaddr)
+{
+ int offset = nvram_partitions[pmac_nvram_XPRAM];
+
+ if (offset < 0)
+ return 0;
+
+ return nvram_read_byte(xpaddr + offset);
+}
+
+void
+pmac_xpram_write(int xpaddr, u8 data)
+{
+ int offset = nvram_partitions[pmac_nvram_XPRAM];
+
+ if (offset < 0)
+ return;
+
+ nvram_write_byte(xpaddr + offset, data);
+}
+
static inline void set_msr(int msr)
{
- asm volatile("mfmsr %0" : : "r" (msr));
+ asm volatile("mtmsr %0" : : "r" (msr));
}
/* Set up exception handlers for tracing and breakpoints
#define fr29 29
#define fr30 30
#define fr31 31
+
+#define vr0 0
+#define vr1 1
+#define vr2 2
+#define vr3 3
+#define vr4 4
+#define vr5 5
+#define vr6 6
+#define vr7 7
+#define vr8 8
+#define vr9 9
+#define vr10 10
+#define vr11 11
+#define vr12 12
+#define vr13 13
+#define vr14 14
+#define vr15 15
+#define vr16 16
+#define vr17 17
+#define vr18 18
+#define vr19 19
+#define vr20 20
+#define vr21 21
+#define vr22 22
+#define vr23 23
+#define vr24 24
+#define vr25 25
+#define vr26 26
+#define vr27 27
+#define vr28 28
+#define vr29 29
+#define vr30 30
+#define vr31 31
"0.5", "1.0", "(reserved2)", "(reserved3)"
};
- if ( (_get_PVR() >> 16) != 8) return -EFAULT;
+ if ( ((_get_PVR() >> 16) != 8) && ((_get_PVR() >> 16) != 12))
+ return -EFAULT;
if ( /*!table->maxlen ||*/ (filp->f_pos && !write)) {
*lenp = 0;
extern void do_lost_interrupts(unsigned long);
extern int do_signal(sigset_t *, struct pt_regs *);
-asmlinkage long long __ashrdi3(long long, int);
-asmlinkage long long __lshrdi3(long long, int);
-asmlinkage int abs(int);
+long long __ashrdi3(long long, int);
+long long __ashldi3(long long, int);
+long long __lshrdi3(long long, int);
+int abs(int);
EXPORT_SYMBOL(clear_page);
EXPORT_SYMBOL(do_signal);
EXPORT_SYMBOL(start_thread);
EXPORT_SYMBOL(kernel_thread);
+EXPORT_SYMBOL(init_mm);
EXPORT_SYMBOL(__cli);
EXPORT_SYMBOL(__sti);
EXPORT_SYMBOL(enable_kernel_fp);
EXPORT_SYMBOL(flush_icache_range);
EXPORT_SYMBOL(xchg_u32);
+
+#ifdef CONFIG_ALTIVEC
+EXPORT_SYMBOL(giveup_altivec);
+#endif
+
#ifdef __SMP__
EXPORT_SYMBOL(__global_cli);
EXPORT_SYMBOL(__global_sti);
EXPORT_SYMBOL(find_phandle);
EXPORT_SYMBOL(device_is_compatible);
EXPORT_SYMBOL(machine_is_compatible);
+EXPORT_SYMBOL(find_pci_device_OFnode);
+EXPORT_SYMBOL(find_all_nodes);
EXPORT_SYMBOL(get_property);
EXPORT_SYMBOL(pci_io_base);
EXPORT_SYMBOL(pci_device_loc);
EXPORT_SYMBOL(note_scsi_host);
#endif
EXPORT_SYMBOL(kd_mksound);
-#ifdef CONFIG_PMAC
+/*#ifdef CONFIG_PMAC */
EXPORT_SYMBOL(nvram_read_byte);
EXPORT_SYMBOL(nvram_write_byte);
-#endif /* CONFIG_PMAC */
+/*#endif*/ /* CONFIG_PMAC */
EXPORT_SYMBOL(abs);
EXPORT_SYMBOL_NOVERS(__ashrdi3);
+EXPORT_SYMBOL_NOVERS(__ashldi3);
EXPORT_SYMBOL_NOVERS(__lshrdi3);
EXPORT_SYMBOL_NOVERS(memcpy);
EXPORT_SYMBOL_NOVERS(memset);
*/
#include <linux/types.h>
+#include <linux/string.h>
#include <linux/pci.h>
#include <linux/kernel.h>
#include <linux/init.h>
unsigned char *Motherboard_routes;
void (*Motherboard_non0)(struct pci_dev *);
-void Mesquite_Map_Non0(struct pci_dev *);
+void Powerplus_Map_Non0(struct pci_dev *);
/* Used for Motorola to store system config register */
static unsigned long *ProcInfo;
13 /* Line 4 */
};
+/* Motorola PowerPlus architecture PCI IRQ tables */
+/* Interrupt line values for INTA-D on primary/secondary MPIC inputs */
+
+struct powerplus_irq_list
+{
+ unsigned char primary[4]; /* INT A-D */
+ unsigned char secondary[4]; /* INT A-D */
+};
+
+/*
+ * For standard PowerPlus boards, bus 0 PCI INTs A-D are routed to
+ * OpenPIC inputs 9-12. PCI INTs A-D from the on board P2P bridge
+ * are routed to OpenPIC inputs 5-8. These values are offset by
+ * 16 in the table to reflect the Linux kernel interrupt value.
+ */
+struct powerplus_irq_list Powerplus_pci_IRQ_list =
+{
+ {25, 26, 27, 28},
+ {21, 22, 23, 24}
+};
+
+/*
+ * For the MCP750 (system slot board), bus 0 PCI INTs A-D are routed
+ * to OpenPIC inputs 8-11. PCI INTs A-D from the on board P2P bridge
+ * are routed to OpenPIC inputs 12-15. These values are offset by 16
+ * in the table to reflect the Linux kernel interrupt value.
+ */
+struct powerplus_irq_list Mesquite_pci_IRQ_list =
+{
+ {24, 25, 26, 27},
+ {28, 29, 30, 31}
+};
+
+/*
+ * This table represents the standard PCI swizzle defined in the
+ * PCI bus specification.
+ */
+static unsigned char prep_pci_intpins[4][4] =
+{
+ { 1, 2, 3, 4}, /* Buses 0, 4, 8, ... */
+ { 2, 3, 4, 1}, /* Buses 1, 5, 9, ... */
+ { 3, 4, 1, 2}, /* Buses 2, 6, 10 ... */
+ { 4, 1, 2, 3}, /* Buses 3, 7, 11 ... */
+};
+
/* We have to turn on LEVEL mode for changed IRQ's */
/* All PCI IRQ's need to be level mode, so this should be something
* other than hard-coded as well... IRQ's are individually mappable
#define MOT_RAVEN_PRESENT 0x1
#define MOT_HAWK_PRESENT 0x2
-/* Keyboard present flag */
-int prep_kbd_present = 1; /* Keyboard present by default */
+int mot_entry = -1;
int MotMPIC = 0;
int mot_multi = 0;
mot_multi = 1;
}
- /* This is a hack. If this is a 2300 or 2400 mot board then there is
- * no keyboard controller and we have to indicate that.
+ /*
+ * If a Motorola MVME2300, 2400, or MCPN750 board is detected
+ * disable keyboard controller initialization to avoid system
+ * hangs.
*/
base_mod = inb(MOTOROLA_BASETYPE_REG);
if ((MotMPIC == MOT_HAWK_PRESENT) || (base_mod == 0xF9) ||
- (base_mod == 0xFA) || (base_mod == 0xE1))
- prep_kbd_present = 0;
+ (base_mod == 0xFA) || (base_mod == 0xE1)) {
+ ppc_md.kbd_leds = NULL;
+ ppc_md.kbd_init_hw = NULL;
+ }
return 1;
}
unsigned char *map;
unsigned char *routes;
void (*map_non0_bus)(struct pci_dev *); /* For boards with more than bus 0 devices. */
+ struct powerplus_irq_list *pci_irq_list; /* List of PCI MPIC inputs */
+ unsigned char secondary_bridge_devfn; /* devfn of secondary bus transparent bridge */
} mot_info[] = {
- {0x300, 0x00, 0x00, "MVME 2400", Genesis2_pci_IRQ_map, Raven_pci_IRQ_routes, NULL},
- {0x010, 0x00, 0x00, "Genesis", Genesis_pci_IRQ_map, Genesis_pci_IRQ_routes, NULL},
- {0x020, 0x00, 0x00, "Powerstack (Series E)", Comet_pci_IRQ_map, Comet_pci_IRQ_routes, NULL},
- {0x040, 0x00, 0x00, "Blackhawk (Powerstack)", Blackhawk_pci_IRQ_map, Blackhawk_pci_IRQ_routes, NULL},
- {0x050, 0x00, 0x00, "Omaha (PowerStack II Pro3000)", Omaha_pci_IRQ_map, Omaha_pci_IRQ_routes, NULL},
- {0x060, 0x00, 0x00, "Utah (Powerstack II Pro4000)", Utah_pci_IRQ_map, Utah_pci_IRQ_routes, NULL},
- {0x0A0, 0x00, 0x00, "Powerstack (Series EX)", Comet2_pci_IRQ_map, Comet2_pci_IRQ_routes, NULL},
- {0x1E0, 0xE0, 0x00, "Mesquite cPCI (MCP750)", Mesquite_pci_IRQ_map, Raven_pci_IRQ_routes, NULL},
- {0x1E0, 0xE1, 0x00, "Sitka cPCI (MCPN750)", Sitka_pci_IRQ_map, Raven_pci_IRQ_routes, NULL},
- {0x1E0, 0xE2, 0x00, "Mesquite cPCI (MCP750) w/ HAC", Mesquite_pci_IRQ_map, Raven_pci_IRQ_routes, Mesquite_Map_Non0},
- {0x1E0, 0xF6, 0x80, "MTX Plus", MTXplus_pci_IRQ_map, Raven_pci_IRQ_routes, NULL},
- {0x1E0, 0xF6, 0x81, "Dual MTX Plus", MTXplus_pci_IRQ_map, Raven_pci_IRQ_routes, NULL},
- {0x1E0, 0xF7, 0x80, "MTX wo/ Parallel Port", MTX_pci_IRQ_map, Raven_pci_IRQ_routes, NULL},
- {0x1E0, 0xF7, 0x81, "Dual MTX wo/ Parallel Port", MTX_pci_IRQ_map, Raven_pci_IRQ_routes, NULL},
- {0x1E0, 0xF8, 0x80, "MTX w/ Parallel Port", MTX_pci_IRQ_map, Raven_pci_IRQ_routes, NULL},
- {0x1E0, 0xF8, 0x81, "Dual MTX w/ Parallel Port", MTX_pci_IRQ_map, Raven_pci_IRQ_routes, NULL},
- {0x1E0, 0xF9, 0x00, "MVME 2300", Genesis2_pci_IRQ_map, Raven_pci_IRQ_routes, NULL},
- {0x1E0, 0xFA, 0x00, "MVME 2300SC/2600", Genesis2_pci_IRQ_map, Raven_pci_IRQ_routes, NULL},
- {0x1E0, 0xFB, 0x00, "MVME 2600 with MVME712M", Genesis2_pci_IRQ_map, Raven_pci_IRQ_routes, NULL},
- {0x1E0, 0xFC, 0x00, "MVME 2600/2700 with MVME761", Genesis2_pci_IRQ_map, Raven_pci_IRQ_routes, NULL},
- {0x1E0, 0xFD, 0x80, "MVME 3600 with MVME712M", Genesis2_pci_IRQ_map, Raven_pci_IRQ_routes, NULL},
- {0x1E0, 0xFD, 0x81, "MVME 4600 with MVME712M", Genesis2_pci_IRQ_map, Raven_pci_IRQ_routes, NULL},
- {0x1E0, 0xFE, 0x80, "MVME 3600 with MVME761", Genesis2_pci_IRQ_map, Raven_pci_IRQ_routes, NULL},
- {0x1E0, 0xFE, 0x81, "MVME 4600 with MVME761", Genesis2_pci_IRQ_map, Raven_pci_IRQ_routes, NULL},
- {0x1E0, 0xFF, 0x00, "MVME 1600-001 or 1600-011", Genesis2_pci_IRQ_map, Raven_pci_IRQ_routes, NULL},
- {0x000, 0x00, 0x00, "", NULL, NULL, NULL}
+ {0x300, 0x00, 0x00, "MVME 2400", Genesis2_pci_IRQ_map, Raven_pci_IRQ_routes, Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0x00},
+ {0x010, 0x00, 0x00, "Genesis", Genesis_pci_IRQ_map, Genesis_pci_IRQ_routes, Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0x00},
+ {0x020, 0x00, 0x00, "Powerstack (Series E)", Comet_pci_IRQ_map, Comet_pci_IRQ_routes, NULL, NULL, 0x00},
+ {0x040, 0x00, 0x00, "Blackhawk (Powerstack)", Blackhawk_pci_IRQ_map, Blackhawk_pci_IRQ_routes, NULL, NULL, 0x00},
+ {0x050, 0x00, 0x00, "Omaha (PowerStack II Pro3000)", Omaha_pci_IRQ_map, Omaha_pci_IRQ_routes, NULL, NULL, 0x00},
+ {0x060, 0x00, 0x00, "Utah (Powerstack II Pro4000)", Utah_pci_IRQ_map, Utah_pci_IRQ_routes, NULL, NULL, 0x00},
+ {0x0A0, 0x00, 0x00, "Powerstack (Series EX)", Comet2_pci_IRQ_map, Comet2_pci_IRQ_routes, NULL, NULL, 0x00},
+ {0x1E0, 0xE0, 0x00, "Mesquite cPCI (MCP750)", Mesquite_pci_IRQ_map, Raven_pci_IRQ_routes, Powerplus_Map_Non0, &Mesquite_pci_IRQ_list, 0x00},
+ {0x1E0, 0xE1, 0x00, "Sitka cPCI (MCPN750)", Sitka_pci_IRQ_map, Raven_pci_IRQ_routes, Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0x00},
+ {0x1E0, 0xE2, 0x00, "Mesquite cPCI (MCP750) w/ HAC", Mesquite_pci_IRQ_map, Raven_pci_IRQ_routes, Powerplus_Map_Non0, &Mesquite_pci_IRQ_list, 0xC0},
+ {0x1E0, 0xF6, 0x80, "MTX Plus", MTXplus_pci_IRQ_map, Raven_pci_IRQ_routes, Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0xA0},
+ {0x1E0, 0xF6, 0x81, "Dual MTX Plus", MTXplus_pci_IRQ_map, Raven_pci_IRQ_routes, Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0xA0},
+ {0x1E0, 0xF7, 0x80, "MTX wo/ Parallel Port", MTX_pci_IRQ_map, Raven_pci_IRQ_routes, Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0x00},
+ {0x1E0, 0xF7, 0x81, "Dual MTX wo/ Parallel Port", MTX_pci_IRQ_map, Raven_pci_IRQ_routes, Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0x00},
+ {0x1E0, 0xF8, 0x80, "MTX w/ Parallel Port", MTX_pci_IRQ_map, Raven_pci_IRQ_routes, Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0x00},
+ {0x1E0, 0xF8, 0x81, "Dual MTX w/ Parallel Port", MTX_pci_IRQ_map, Raven_pci_IRQ_routes, Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0x00},
+ {0x1E0, 0xF9, 0x00, "MVME 2300", Genesis2_pci_IRQ_map, Raven_pci_IRQ_routes, Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0x00},
+ {0x1E0, 0xFA, 0x00, "MVME 2300SC/2600", Genesis2_pci_IRQ_map, Raven_pci_IRQ_routes, Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0x00},
+ {0x1E0, 0xFB, 0x00, "MVME 2600 with MVME712M", Genesis2_pci_IRQ_map, Raven_pci_IRQ_routes, Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0x00},
+ {0x1E0, 0xFC, 0x00, "MVME 2600/2700 with MVME761", Genesis2_pci_IRQ_map, Raven_pci_IRQ_routes, Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0x00},
+ {0x1E0, 0xFD, 0x80, "MVME 3600 with MVME712M", Genesis2_pci_IRQ_map, Raven_pci_IRQ_routes, Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0x00},
+ {0x1E0, 0xFD, 0x81, "MVME 4600 with MVME712M", Genesis2_pci_IRQ_map, Raven_pci_IRQ_routes, Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0x00},
+ {0x1E0, 0xFE, 0x80, "MVME 3600 with MVME761", Genesis2_pci_IRQ_map, Raven_pci_IRQ_routes, Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0x00},
+ {0x1E0, 0xFE, 0x81, "MVME 4600 with MVME761", Genesis2_pci_IRQ_map, Raven_pci_IRQ_routes, Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0x00},
+ {0x1E0, 0xFF, 0x00, "MVME 1600-001 or 1600-011", Genesis2_pci_IRQ_map, Raven_pci_IRQ_routes, NULL, NULL, 0x00},
+ {0x000, 0x00, 0x00, "", NULL, NULL, NULL, 0x00}
};
__initfunc(unsigned long prep_route_pci_interrupts(void))
unsigned char cpu_type;
unsigned char base_mod;
int entry;
- int mot_entry = -1;
cpu_type = inb(MOTOROLA_CPUTYPE_REG) & 0xF0;
base_mod = inb(MOTOROLA_BASETYPE_REG);
return 0;
}
-static unsigned int pci_localpirqs[4] =
-{
- 24,
- 25,
- 26,
- 27
-};
-
-static unsigned int pci_remotepirqs[4] =
-{
- 28,
- 29,
- 30,
- 31
-};
-
-static unsigned int pci_remotedev = 0xc0;
-
+/*
+ * Remove a device from the kernel PCI device list based on its
+ * devfn identifier.
+ */
+__initfunc(
void
-Mesquite_Map_Non0(struct pci_dev *pdev)
+prep_exclude_pci_device(unsigned char devfn)
+)
{
- struct pci_bus *pbus; /* Parent Bus Structure Pointer */
- unsigned int devnum; /* Accumulated Device Number */
- unsigned int irq; /* IRQ Value */
+ struct pci_dev *dev, *pdev = NULL;
- /*
- ** Device Interrupt Line register initialization.
- ** The IRQ line number will be generated after
- ** taking into account all the PCI-2-PCI bridge
- ** devices between the device and the Host Bridge.
- */
- devnum = PCI_SLOT(pdev->devfn);
- pbus = pdev->bus;
-
- while ((pbus->parent)->primary != (pbus->parent)->secondary)
- {
- devnum += PCI_SLOT((pbus->self)->devfn);
+ /* Walk the pci device list */
+ for(dev=pci_devices; dev; dev=dev->next) {
+ if (dev->devfn == devfn)
+ {
+ /*
+ * If we find a matching device, adjust
+ * the list to remove the device.
+ */
+ if (pdev != NULL)
+ pdev->next = dev->next;
+ else
+ pci_devices = dev->next;
- pbus = pbus->parent;
+ break;
+ }
+ pdev = dev;
}
+}
- devnum &= 0x03;
-
- /*
- ** By default, get the PCI local domain IRQ value.
- */
- irq = pci_localpirqs[devnum];
+void
+Powerplus_Map_Non0(struct pci_dev *dev)
+{
+ struct pci_bus *pbus; /* Parent bus structure pointer */
+ struct pci_dev *tdev; /* Temporary device structure */
+ unsigned int devnum; /* Accumulated device number */
+ unsigned char intline; /* Linux interrupt value */
+ unsigned char intpin; /* PCI interrupt pin */
+
+ /* Check for valid PCI dev pointer */
+ if (dev == NULL) return;
+
+ /* Fill our temporary device, and get the device number */
+ *tdev = *dev;
+ devnum = PCI_SLOT(tdev->devfn);
+
+ /* Read the interrupt pin of the device and adjust for indexing */
+ pcibios_read_config_byte(tdev->bus->number, tdev->devfn,
+ PCI_INTERRUPT_PIN, &intpin);
+
+ /* If device doesn't request an interrupt, return */
+ if ( (intpin < 1) || (intpin > 4) )
+ return;
- /*
- ** Determine if the device is located in the
- ** remote domain or not. We must find the
- ** domain's bridge device located on bus 0.
- */
- pbus = pdev->bus;
+ intpin--;
- while (pbus->primary != 0)
- pbus = pbus->parent;
+ /* Walk up to bus 0, adjusting the interrupt pin for the standard
+ PCI bus swizzle. */
+ do {
+ intpin = (prep_pci_intpins[devnum % 4][intpin]) - 1;
+ pbus = tdev->bus; /* up one level */
+ tdev = pbus->self;
+ devnum = PCI_SLOT(tdev->devfn);
+ } while(tdev->bus->number);
- /*
- ** Check the device/function of domain's bridge
- ** device against the remote device/function.
- ** If the same, then the device is located in
- ** the remote domain. Thus, get the PCI remote
- ** domain IRQ value.
- */
- if ((pbus->self)->devfn == pci_remotedev)
- irq = pci_remotepirqs[devnum];
+ /* Use the primary interrupt inputs by default */
+ intline = mot_info[mot_entry].pci_irq_list->primary[intpin];
- /*
- ** Validate the IRQ number.
- */
- if (irq <= 255)
+ /* If the board has secondary interrupt inputs, walk the bus and
+ note the devfn of the bridge from bus 0. If it is the same as
+ the devfn of the bus bridge with secondary inputs, use those. */
+ if (mot_info[mot_entry].secondary_bridge_devfn)
{
- /*
- ** Set the device's Interrupt Line register
- ** to the IRQ number and save it in the
- ** device's structure.
- */
-
- pci_write_config_byte(pdev, PCI_INTERRUPT_LINE, (u8)irq);
-
- pdev->irq = irq;
-
+ pbus = dev->bus;
+
+ while (pbus->primary != 0)
+ pbus = pbus->parent;
+
+ if ((pbus->self)->devfn == mot_info[mot_entry].secondary_bridge_devfn)
+ intline = mot_info[mot_entry].pci_irq_list->secondary[intpin];
}
- return;
+
+ /* Write calculated interrupt value to header and device list */
+ pci_write_config_byte(dev, PCI_INTERRUPT_LINE, (u8)intline);
+ dev->irq = intline;
}
int motopenpic_to_irq(int n)
prep_route_pci_interrupts();
+ /*
+ * If MTX+, exclude the SL82C105 IDE controller so the driver
+ * doesn't hang.
+ */
+ if ( _prep_type == _PREP_Motorola )
+ if ( strstr(mot_info[mot_entry].name, "MTX Plus") )
+ /* On MTX+, SL82C105 is at IDSEL 0xb function 0x1 */
+ prep_exclude_pci_device(PCI_DEVFN(0xb, 0x1));
+
prep_pib_init();
printk("Setting PCI interrupts for a \"%s\"\n", Motherboard_map_name);
motopenpic_to_irq(Motherboard_map[PCI_SLOT(dev->devfn)]);
pcibios_write_config_byte(dev->bus->number, dev->devfn,
- PCI_INTERRUPT_PIN, dev->irq);
+ PCI_INTERRUPT_LINE, dev->irq);
} else {
if (Motherboard_non0 != NULL)
Motherboard_non0(dev);
int i;
if (OpenPIC != NULL) {
+ open_pic.irq_offset = 16;
for ( i = 16 ; i < 36 ; i++ )
irq_desc[i].ctl = &open_pic;
openpic_init(1);
ppc_md.kbd_init_hw = pckbd_init_hw;
#ifdef CONFIG_MAGIC_SYSRQ
ppc_md.kbd_sysrq_xlate = pckbd_sysrq_xlate;
+ ppc_md.SYSRQ_KEY = 0x54;
#endif
#endif
}
#include <asm/mmu_context.h>
int dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpregs);
+int dump_altivec(struct pt_regs *regs, elf_vrregset_t *vrregs);
extern unsigned long _get_SP(void);
struct task_struct *last_task_used_math = NULL;
+struct task_struct *last_task_used_altivec = NULL;
static struct vm_area_struct init_mmap = INIT_MMAP;
static struct fs_struct init_fs = INIT_FS;
static struct files_struct init_files = INIT_FILES;
return 1;
}
+#ifdef CONFIG_ALTIVEC
+int
+dump_altivec(struct pt_regs *regs, elf_vrregset_t *vrregs)
+{
+ if (regs->msr & MSR_VEC)
+ giveup_altivec(current);
+ memcpy(vrregs, ¤t->tss.vr[0], sizeof(*vrregs));
+ return 1;
+}
+
+void
+enable_kernel_altivec(void)
+{
+#ifdef __SMP__
+ if (current->tss.regs && (current->tss.regs->msr & MSR_VEC))
+ giveup_altivec(current);
+ else
+ giveup_altivec(NULL); /* just enable AltiVec for kernel - force */
+#else
+ giveup_altivec(last_task_used_altivec);
+#endif /* __SMP __ */
+ printk("MSR_VEC in enable_altivec_kernel\n");
+}
+#endif /* CONFIG_ALTIVEC */
+
void
enable_kernel_fp(void)
{
_enable_interrupts(s);
}
-void show_regs(struct pt_regs * regs)
+struct bits {
+ const char *name;
+ unsigned int bit;
+};
+
+void print_bits(unsigned int val, struct bits *bits)
+{
+ const char *sep = "";
+
+ printk("[");
+ for (; bits->bit != 0; ++bits) {
+ if (val & bits->bit) {
+ printk("%s", bits->name);
+ sep = ", ";
+ }
+ }
+ printk("]");
+}
+
+struct bits msr_bits[] = {
+ {"VEC", MSR_VEC},
+ {"EE", MSR_EE},
+ {"PR", MSR_PR},
+ {"FP", MSR_FP},
+ {"IR", MSR_IR},
+ {"DR", MSR_DR},
+ {"ME", MSR_ME},
+ {0, 0}
+};
+
+void show_regs(struct pt_regs *regs)
{
int i;
printk("NIP: %08lX XER: %08lX LR: %08lX REGS: %p TRAP: %04lx\n",
regs->nip, regs->xer, regs->link, regs,regs->trap);
- printk("MSR: %08lx EE: %01x PR: %01x FP: %01x ME: %01x IR/DR: %01x%01x\n",
- regs->msr, regs->msr&MSR_EE ? 1 : 0, regs->msr&MSR_PR ? 1 : 0,
- regs->msr & MSR_FP ? 1 : 0,regs->msr&MSR_ME ? 1 : 0,
- regs->msr&MSR_IR ? 1 : 0,
- regs->msr&MSR_DR ? 1 : 0);
+ printk("MSR: %08lx ", regs->msr);
+ print_bits(regs->msr, msr_bits);
+ printk("\n");
printk("TASK = %p[%d] '%s' mm->pgd %p ",
current, current->pid, current->comm, current->mm->pgd);
printk("Last syscall: %ld ", current->tss.last_syscall);
- printk("\nlast math %p", last_task_used_math);
-
+ if (last_task_used_math)
+ printk("\nlast math %p", last_task_used_math);
+ if (last_task_used_altivec)
+ printk("\nlast altivec %p", last_task_used_altivec);
+
#ifdef __SMP__
printk(" CPU: %d last CPU: %d", current->processor,current->last_processor);
#endif /* __SMP__ */
{
if (last_task_used_math == current)
last_task_used_math = NULL;
+ if (last_task_used_altivec == current)
+ last_task_used_altivec = NULL;
}
void flush_thread(void)
{
if (last_task_used_math == current)
last_task_used_math = NULL;
+ if (last_task_used_altivec == current)
+ last_task_used_altivec = NULL;
}
void
if (regs->msr & MSR_FP)
giveup_fpu(current);
+#ifdef CONFIG_ALTIVEC
+ /*
+ * copy altiVec info - assume lazy altiVec switch
+ * - kumar
+ */
+ if (regs->msr & MSR_VEC)
+ giveup_altivec(current);
+
+ memcpy(&p->tss.vr, ¤t->tss.vr, sizeof(p->tss.vr));
+ p->tss.vscr = current->tss.vscr;
+ childregs->msr &= ~MSR_VEC;
+#endif /* CONFIG_ALTIVEC */
+
memcpy(&p->tss.fpr, ¤t->tss.fpr, sizeof(p->tss.fpr));
p->tss.fpscr = current->tss.fpscr;
childregs->msr &= ~MSR_FP;
shove_aux_table(sp);
if (last_task_used_math == current)
last_task_used_math = 0;
+ if (last_task_used_altivec == current)
+ last_task_used_altivec = 0;
current->tss.fpscr = 0;
}
goto out;
if (regs->msr & MSR_FP)
giveup_fpu(current);
+#ifdef CONFIG_ALTIVEC
+ if (regs->msr & MSR_VEC)
+ giveup_altivec(current);
+#endif /* CONFIG_ALTIVEC */
error = do_execve(filename, (char **) a1, (char **) a2, regs);
putname(filename);
out:
#include <asm/bootx.h>
#include <asm/system.h>
#include <asm/gemini.h>
+#include <asm/linux_logo.h>
/*
* Properties whose value is longer than this get excluded from our
char *of_stdout_device = 0;
prom_entry prom = 0;
-ihandle prom_chosen = 0, prom_stdout = 0;
+ihandle prom_chosen = 0, prom_stdout = 0, prom_disp_node = 0;
int prom_version = 0;
extern char *klimit;
unsigned int rtas_size = 0;
unsigned int old_rtas = 0;
+/* Set for a newworld machine */
+int use_of_interrupt_tree = 0;
+int pmac_newworld = 0;
+
static struct device_node *allnodes = 0;
+#ifdef CONFIG_BOOTX_TEXT
+
static void clearscreen(void);
static void flushscreen(void);
-#ifdef CONFIG_BOOTX_TEXT
-
void drawchar(char c);
void drawstring(const char *c);
static void drawhex(unsigned long v);
static void scrollscreen(void);
static void draw_byte(unsigned char c, long locX, long locY);
-static void draw_byte_32(unsigned char *bits, unsigned long *base);
-static void draw_byte_16(unsigned char *bits, unsigned long *base);
-static void draw_byte_8(unsigned char *bits, unsigned long *base);
+static void draw_byte_32(unsigned char *bits, unsigned long *base, int rb);
+static void draw_byte_16(unsigned char *bits, unsigned long *base, int rb);
+static void draw_byte_8(unsigned char *bits, unsigned long *base, int rb);
-static long g_loc_X;
-static long g_loc_Y;
-static long g_max_loc_X;
-static long g_max_loc_Y;
+/* We want those in the data section */
+static long g_loc_X = 0;
+static long g_loc_Y = 0;
+static long g_max_loc_X = 0;
+static long g_max_loc_Y = 0;
#define cmapsz (16*256)
static unsigned char vga_font[cmapsz];
-#endif
+#endif /* CONFIG_BOOTX_TEXT */
static void *call_prom(const char *service, int nargs, int nret, ...);
unsigned long, struct device_node ***);
static unsigned long finish_node(struct device_node *, unsigned long,
interpret_func *);
+static unsigned long finish_node_interrupts(struct device_node *, unsigned long);
static unsigned long check_display(unsigned long);
static int prom_next_node(phandle *);
static void *early_get_property(unsigned long, unsigned long, char *);
+#ifdef CONFIG_BOOTX_TEXT
+static void setup_disp_fake_bi(ihandle dp);
+static void prom_welcome(boot_infos_t* bi, unsigned long phys);
+#endif
+
extern void enter_rtas(void *);
extern unsigned long reloc_offset(void);
extern char cmd_line[512]; /* XXX */
boot_infos_t *boot_infos = 0; /* init it so it's in data segment not bss */
+#ifdef CONFIG_BOOTX_TEXT
+boot_infos_t *disp_bi = 0;
+boot_infos_t fake_bi = {0,};
+#endif
/*
* prom_init() is called very early on, before the kernel text
if (RELOC(prom_stdout) == 0)
{
#ifdef CONFIG_BOOTX_TEXT
- if (RELOC(boot_infos) != 0)
+ if (RELOC(disp_bi) != 0)
drawstring(msg);
#endif
return;
phandle node;
char type[16], *path;
#endif
+ int chrp = 0;
unsigned long mem;
ihandle prom_rtas, prom_mmu, prom_op;
unsigned long offset = reloc_offset();
unsigned long space;
unsigned long ptr, x;
char *model;
-#ifdef CONFIG_BOOTX_TEXT
- unsigned long flags;
-#endif
RELOC(boot_infos) = PTRUNRELOC(bi);
if (!BOOT_INFO_IS_V2_COMPATIBLE(bi))
bi->logicalDisplayBase = 0;
-
- clearscreen();
-
#ifdef CONFIG_BOOTX_TEXT
RELOC(g_loc_X) = 0;
RELOC(g_loc_Y) = 0;
RELOC(g_max_loc_X) = (bi->dispDeviceRect[2] - bi->dispDeviceRect[0]) / 8;
RELOC(g_max_loc_Y) = (bi->dispDeviceRect[3] - bi->dispDeviceRect[1]) / 16;
+ RELOC(disp_bi) = PTRUNRELOC(bi);
+ clearscreen();
+
/* Test if boot-info is compatible. Done only in config CONFIG_BOOTX_TEXT since
there is nothing much we can do with an incompatible version, except display
a message and eventually hang the processor...
if (!BOOT_INFO_IS_COMPATIBLE(bi))
prom_print(RELOC(" !!! WARNING - Incompatible version of BootX !!!\n\n\n"));
- prom_print(RELOC("Welcome to Linux, kernel " UTS_RELEASE "\n"));
- prom_print(RELOC("\nstarted at : 0x"));
- drawhex(reloc_offset() + KERNELBASE);
- prom_print(RELOC("\nlinked at : 0x"));
- drawhex(KERNELBASE);
- prom_print(RELOC("\nframe buffer at : 0x"));
- drawhex((unsigned long)bi->dispDeviceBase);
- prom_print(RELOC(" (phys), 0x"));
- drawhex((unsigned long)bi->logicalDisplayBase);
- prom_print(RELOC(" (log)"));
- prom_print(RELOC("\nMSR : 0x"));
- __asm__ __volatile__ ("mfmsr %0" : "=r" ((flags)) : : "memory");
- drawhex(flags);
- prom_print(RELOC("\n\n"));
-#endif
- /* Out of the #if/#endif since it flushes the clearscreen too */
+ prom_welcome(bi, phys);
flushscreen();
-
+#endif /* CONFIG_BOOTX_TEXT */
+
/* New BootX enters kernel with MMU off, i/os are not allowed
here. This hack will have been done by the boostrap anyway.
*/
int sz;
sz = (int)call_prom(RELOC("getprop"), 4, 1, prom_op, RELOC("model"), model, 64);
if (sz > 0) {
- char *c;
- for (c = model; *c; c++)
- if (*c >= '0' && *c <= '9') {
- RELOC(prom_version) = *c - '0';
- break;
- }
+ if ( strncmp(model,RELOC("IBM"),3) ) {
+ char *c;
+ for (c = model; *c; c++)
+ if (*c >= '0' && *c <= '9') {
+ RELOC(prom_version) = *c - '0';
+ break;
+ }
+ } else
+ chrp = 1;
}
}
if (RELOC(prom_version) >= 3)
}
}
+#ifdef CONFIG_BOOTX_TEXT
+ if (!chrp && RELOC(prom_disp_node) != 0)
+ setup_disp_fake_bi(RELOC(prom_disp_node));
+#endif
+
#ifdef CONFIG_SMP
/*
* With CHRP SMP we need to use the OF to start the other
else
prom_print(RELOC("...failed\n"));
}
-#endif /* CONFIG_SMP */
+#endif
/* If OpenFirmware version >= 3, then use quiesce call */
if (RELOC(prom_version) >= 3) {
prom_print(RELOC("Calling quiesce ...\n"));
phys = offset + KERNELBASE;
}
+#ifdef CONFIG_BOOTX_TEXT
+ if (!chrp && RELOC(disp_bi)) {
+ RELOC(prom_stdout) = 0;
+ clearscreen();
+ prom_welcome(PTRRELOC(RELOC(disp_bi)), phys);
+ prom_print(RELOC("booting...\n"));
+ }
+#endif
+
return phys;
}
+#ifdef CONFIG_BOOTX_TEXT
+__init static void
+prom_welcome(boot_infos_t* bi, unsigned long phys)
+{
+ unsigned long offset = reloc_offset();
+ unsigned long flags;
+ unsigned long pvr;
+
+ prom_print(RELOC("Welcome to Linux, kernel " UTS_RELEASE "\n"));
+ prom_print(RELOC("\nstarted at : 0x"));
+ drawhex(phys);
+ prom_print(RELOC("\nlinked at : 0x"));
+ drawhex(KERNELBASE);
+ prom_print(RELOC("\nframe buffer at : 0x"));
+ drawhex((unsigned long)bi->dispDeviceBase);
+ prom_print(RELOC(" (phys), 0x"));
+ drawhex((unsigned long)bi->logicalDisplayBase);
+ prom_print(RELOC(" (log)"));
+ prom_print(RELOC("\nMSR : 0x"));
+ __asm__ __volatile__ ("mfmsr %0" : "=r" (flags));
+ drawhex(flags);
+ __asm__ __volatile__ ("mfspr %0, 287" : "=r" (pvr));
+ pvr >>= 16;
+ if (pvr > 1) {
+ prom_print(RELOC("\nHID0 : 0x"));
+ __asm__ __volatile__ ("mfspr %0, 1008" : "=r" (flags));
+ drawhex(flags);
+ }
+ if (pvr == 8 || pvr == 12) {
+ prom_print(RELOC("\nICTC : 0x"));
+ __asm__ __volatile__ ("mfspr %0, 1019" : "=r" (flags));
+ drawhex(flags);
+ }
+ prom_print(RELOC("\n\n"));
+}
+
+void showvalue(char *str, unsigned long val)
+{
+ drawstring(str);
+ drawhex(val);
+ drawstring("\n");
+}
+#endif
+
+static int prom_set_color(ihandle ih, int i, int r, int g, int b)
+{
+ struct prom_args prom_args;
+ unsigned long offset = reloc_offset();
+
+ prom_args.service = RELOC("call-method");
+ prom_args.nargs = 6;
+ prom_args.nret = 1;
+ prom_args.args[0] = RELOC("color!");
+ prom_args.args[1] = ih;
+ prom_args.args[2] = (void *) i;
+ prom_args.args[3] = (void *) b;
+ prom_args.args[4] = (void *) g;
+ prom_args.args[5] = (void *) r;
+ RELOC(prom)(&prom_args);
+ return (int) prom_args.args[6];
+}
+
/*
* If we have a display that we don't know how to drive,
* we will want to try to execute OF's open method for it
static unsigned long
check_display(unsigned long mem)
{
+#ifdef CONFIG_FB
phandle node;
ihandle ih;
int i;
unsigned long offset = reloc_offset();
char type[16], *path;
+ static unsigned char default_colors[] = {
+ 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xaa,
+ 0x00, 0xaa, 0x00,
+ 0x00, 0xaa, 0xaa,
+ 0xaa, 0x00, 0x00,
+ 0xaa, 0x00, 0xaa,
+ 0xaa, 0xaa, 0x00,
+ 0xaa, 0xaa, 0xaa,
+ 0x55, 0x55, 0x55,
+ 0x55, 0x55, 0xff,
+ 0x55, 0xff, 0x55,
+ 0x55, 0xff, 0xff,
+ 0xff, 0x55, 0x55,
+ 0xff, 0x55, 0xff,
+ 0xff, 0xff, 0x55,
+ 0xff, 0xff, 0xff
+ };
+
+ RELOC(prom_disp_node) = 0;
for (node = 0; prom_next_node(&node); ) {
type[0] = 0;
}
prom_print(RELOC("... ok\n"));
+ if (RELOC(prom_disp_node) == 0)
+ RELOC(prom_disp_node) = node;
+
+ /* Setup a useable color table when the appropriate
+ * method is available. Should update this to set-colors */
+ for (i = 0; i < 32; i++)
+ if (prom_set_color(ih, i, RELOC(default_colors)[i*3],
+ RELOC(default_colors)[i*3+1],
+ RELOC(default_colors)[i*3+2]) != 0)
+ break;
+
+ for (i = 0; i < LINUX_LOGO_COLORS; i++)
+ if (prom_set_color(ih, i + 32,
+ RELOC(linux_logo_red)[i],
+ RELOC(linux_logo_green)[i],
+ RELOC(linux_logo_blue)[i]) != 0)
+ break;
+
/*
* If this display is the device that OF is using for stdout,
* move it to the front of the list.
if (RELOC(prom_num_displays) >= FB_MAX)
break;
}
+#endif /* CONFIG_FB */
return ALIGN(mem);
}
+/* This function will enable the early boot text when doing OF booting. This
+ * way, xmon output should work too
+ */
+#ifdef CONFIG_BOOTX_TEXT
+__init
+static void
+setup_disp_fake_bi(ihandle dp)
+{
+ unsigned int len;
+ int width = 640, height = 480, depth = 8, pitch;
+ unsigned address;
+ boot_infos_t* bi;
+ unsigned long offset = reloc_offset();
+
+ prom_print(RELOC("Initing fake screen\n"));
+
+ len = 0;
+ call_prom(RELOC("getprop"), 4, 1, dp, RELOC("depth"), &len, sizeof(len));
+ if (len == 0)
+ prom_print(RELOC("Warning: assuming display depth = 8\n"));
+ else
+ depth = len;
+ width = len = 0;
+ call_prom(RELOC("getprop"), 4, 1, dp, RELOC("width"), &len, sizeof(len));
+ width = len;
+ if (width == 0) {
+ prom_print(RELOC("Failed to get width\n"));
+ return;
+ }
+ height = len = 0;
+ call_prom(RELOC("getprop"), 4, 1, dp, RELOC("height"), &len, sizeof(len));
+ height = len;
+ if (height == 0) {
+ prom_print(RELOC("Failed to get height\n"));
+ return;
+ }
+ pitch = len = 0;
+ call_prom(RELOC("getprop"), 4, 1, dp, RELOC("linebytes"), &len, sizeof(len));
+ pitch = len;
+ if (pitch == 0) {
+ prom_print(RELOC("Failed to get pitch\n"));
+ return;
+ }
+ address = len = 0;
+ call_prom(RELOC("getprop"), 4, 1, dp, RELOC("address"), &len, sizeof(len));
+ address = len;
+ if (address == 0) {
+ prom_print(RELOC("Failed to get address\n"));
+ return;
+ }
+#if 0
+ /* kludge for valkyrie */
+ if (strcmp(dp->name, "valkyrie") == 0)
+ address += 0x1000;
+ }
+#endif
+
+ RELOC(disp_bi) = &fake_bi;
+ bi = PTRRELOC((&fake_bi));
+ RELOC(g_loc_X) = 0;
+ RELOC(g_loc_Y) = 0;
+ RELOC(g_max_loc_X) = width / 8;
+ RELOC(g_max_loc_Y) = height / 16;
+ bi->logicalDisplayBase = (unsigned char *)address;
+ bi->dispDeviceBase = (unsigned char *)address;
+ bi->dispDeviceRowBytes = pitch;
+ bi->dispDeviceDepth = depth;
+ bi->dispDeviceRect[0] = bi->dispDeviceRect[1] = 0;
+ bi->dispDeviceRect[2] = width;
+ bi->dispDeviceRect[3] = height;
+}
+#endif
+
__init
static int
prom_next_node(phandle *nodep)
finish_device_tree(void)
{
unsigned long mem = (unsigned long) klimit;
+#if 0
+ char* model;
+
+ /* Here, we decide if we'll use the interrupt-tree (new Core99 code) or not.
+ * This code was only tested with Core99 machines so far, but should be easily
+ * adapted to older newworld machines (iMac, B&W G3, Lombard).
+ */
+ model = get_property(allnodes, "model", 0);
+ if ((boot_infos == 0) && model && (
+ strcmp(model, "PowerBook2,1") == 0 ||
+ strcmp(model, "PowerBook3,1") == 0 ||
+ strcmp(model, "PowerMac2,1") == 0 ||
+ strcmp(model, "PowerMac3,1") == 0))
+ use_of_interrupt_tree = 1;
+#endif
+ /* All newworld machines now use the interrupt tree */
+ struct device_node *np = allnodes;
+ while(np) {
+ if (get_property(np, "interrupt-parent", 0)) {
+ pmac_newworld = 1;
+ break;
+ }
+ np = np->allnext;
+ }
+ if (boot_infos == 0 && pmac_newworld)
+ use_of_interrupt_tree = 1;
mem = finish_node(allnodes, mem, NULL);
printk(KERN_INFO "device tree used %lu bytes\n",
if (ifunc != NULL) {
mem_start = ifunc(np, mem_start);
}
+ if (use_of_interrupt_tree) {
+ mem_start = finish_node_interrupts(np, mem_start);
+ }
/* the f50 sets the name to 'display' and 'compatible' to what we
* expect for the name -- Cort
return mem_start;
}
+/* This routine walks the interrupt tree for a given device node and gather
+ * all necessary informations according to the draft interrupt mapping
+ * for CHRP. The current version was only tested on Apple "Core99" machines
+ * and may not handle cascaded controllers correctly.
+ */
+__init
+static unsigned long
+finish_node_interrupts(struct device_node *np, unsigned long mem_start)
+{
+ /* Finish this node */
+ unsigned int *isizep, *asizep, *interrupts, *map, *map_mask, *reg;
+ phandle *parent;
+ struct device_node *node, *parent_node;
+ int l, isize, ipsize, asize, map_size, regpsize;
+
+ /* Currently, we don't look at all nodes with no "interrupts" property */
+ interrupts = (unsigned int *)get_property(np, "interrupts", &l);
+ if (interrupts == NULL)
+ return mem_start;
+ ipsize = l>>2;
+
+ reg = (unsigned int *)get_property(np, "reg", &l);
+ regpsize = l>>2;
+
+ /* We assume default interrupt cell size is 1 (bugus ?) */
+ isize = 1;
+ node = np;
+
+ do {
+ /* We adjust the cell size if the current parent contains an #interrupt-cells
+ * property */
+ isizep = (unsigned int *)get_property(node, "#interrupt-cells", &l);
+ if (isizep)
+ isize = *isizep;
+
+ /* We don't do interrupt cascade (ISA) for now, we stop on the first
+ * controller found
+ */
+ if (get_property(node, "interrupt-controller", &l)) {
+ int i,j;
+ np->intrs = (struct interrupt_info *) mem_start;
+ np->n_intrs = ipsize / isize;
+ mem_start += np->n_intrs * sizeof(struct interrupt_info);
+ for (i = 0; i < np->n_intrs; ++i) {
+ np->intrs[i].line = *interrupts++;
+ np->intrs[i].sense = 0;
+ if (isize > 1)
+ np->intrs[i].sense = *interrupts++;
+ for (j=2; j<isize; j++)
+ interrupts++;
+ }
+ return mem_start;
+ }
+ /* We lookup for an interrupt-map. This code can only handle one interrupt
+ * per device in the map. We also don't handle #address-cells in the parent
+ * I skip the pci node itself here, may not be necessary but I don't like it's
+ * reg property.
+ */
+ if (np != node)
+ map = (unsigned int *)get_property(node, "interrupt-map", &l);
+ else
+ map = NULL;
+ if (map && l) {
+ int i, found, temp_isize;
+ map_size = l>>2;
+ map_mask = (unsigned int *)get_property(node, "interrupt-map-mask", &l);
+ asizep = (unsigned int *)get_property(node, "#address-cells", &l);
+ if (asizep && l == sizeof(unsigned int))
+ asize = *asizep;
+ else
+ asize = 0;
+ found = 0;
+ while(map_size>0 && !found) {
+ found = 1;
+ for (i=0; i<asize; i++) {
+ unsigned int mask = map_mask ? map_mask[i] : 0xffffffff;
+ if (!reg || (i>=regpsize) || ((mask & *map) != (mask & reg[i])))
+ found = 0;
+ map++;
+ map_size--;
+ }
+ for (i=0; i<isize; i++) {
+ unsigned int mask = map_mask ? map_mask[i+asize] : 0xffffffff;
+ if ((mask & *map) != (mask & interrupts[i]))
+ found = 0;
+ map++;
+ map_size--;
+ }
+ parent = *((phandle *)(map));
+ map+=1; map_size-=1;
+ parent_node = find_phandle(parent);
+ temp_isize = isize;
+ if (parent_node) {
+ isizep = (unsigned int *)get_property(parent_node, "#interrupt-cells", &l);
+ if (isizep)
+ temp_isize = *isizep;
+ }
+ if (!found) {
+ map += temp_isize;
+ map_size-=temp_isize;
+ }
+ }
+ if (found) {
+ node = parent_node;
+ reg = NULL;
+ regpsize = 0;
+ interrupts = (unsigned int *)map;
+ ipsize = temp_isize*1;
+ continue;
+ }
+ }
+ /* We look for an explicit interrupt-parent.
+ */
+ parent = (phandle *)get_property(node, "interrupt-parent", &l);
+ if (parent && (l == sizeof(phandle)) &&
+ (parent_node = find_phandle(*parent))) {
+ node = parent_node;
+ continue;
+ }
+ /* Default, get real parent */
+ node = node->parent;
+ } while(node);
+
+ return mem_start;
+}
+
/*
* When BootX makes a copy of the device tree from the MacOS
* Name Registry, it is in the format we use but all of the pointers
mem_start += i * sizeof(struct address_range);
}
+ if (use_of_interrupt_tree)
+ return mem_start;
+
/*
* If the pci host bridge has an interrupt-map property,
* look for our node in it.
get_property(np->parent, "interrupt-map", &ml)) != 0
&& (ip = (int *) get_property(np, "interrupts", &l)) != 0) {
unsigned int devfn = pci_addrs[0].addr.a_hi & 0xff00;
+ unsigned int cell_size;
+ struct device_node* np2;
+ /* This is hackish, but is only used for BootX booting */
+ cell_size = sizeof(struct pci_intr_map);
+ np2 = np->parent;
+ while(np2) {
+ if (device_is_compatible(np2, "uni-north")) {
+ cell_size += 4;
+ break;
+ }
+ np2 = np2->parent;
+ }
np->n_intrs = 0;
np->intrs = (struct interrupt_info *) mem_start;
- for (i = 0; (ml -= sizeof(struct pci_intr_map)) >= 0; ++i) {
- if (imp[i].addr.a_hi == devfn) {
- np->intrs[np->n_intrs].line = imp[i].intr;
- np->intrs[np->n_intrs].sense = 0;
+ for (i = 0; (ml -= cell_size) >= 0; ++i) {
+ if (imp->addr.a_hi == devfn) {
+ np->intrs[np->n_intrs].line = imp->intr;
+ np->intrs[np->n_intrs].sense = 0; /* FIXME */
++np->n_intrs;
}
+ imp = (struct pci_intr_map *)(((unsigned int)imp)
+ + cell_size);
}
if (np->n_intrs == 0)
np->intrs = 0;
mem_start += i * sizeof(struct address_range);
}
+ if (use_of_interrupt_tree)
+ return mem_start;
+
ip = (int *) get_property(np, "AAPL,interrupts", &l);
if (ip == 0)
ip = (int *) get_property(np, "interrupts", &l);
struct reg_property *rp;
struct address_range *adr;
unsigned long base_address;
- int i, l, *ip;
+ int i, l, keylargo, *ip;
struct device_node *db;
base_address = 0;
for (db = np->parent; db != NULL; db = db->parent) {
if (!strcmp(db->type, "mac-io") && db->n_addrs != 0) {
base_address = db->addrs[0].address;
+ keylargo = device_is_compatible(db, "Keylargo");
break;
}
}
mem_start += i * sizeof(struct address_range);
}
+ if (use_of_interrupt_tree)
+ return mem_start;
+
ip = (int *) get_property(np, "interrupts", &l);
if (ip == 0)
ip = (int *) get_property(np, "AAPL,interrupts", &l);
if (_machine == _MACH_Pmac) {
/* for the iMac */
np->n_intrs = l / sizeof(int);
+ /* Hack for BootX on Core99 */
+ if (keylargo)
+ np->n_intrs = np->n_intrs/2;
for (i = 0; i < np->n_intrs; ++i) {
np->intrs[i].line = *ip++;
- np->intrs[i].sense = 0;
+ if (keylargo)
+ np->intrs[i].sense = *ip++;
+ else
+ np->intrs[i].sense = 0;
}
} else {
/* CHRP machines */
mem_start += i * sizeof(struct address_range);
}
+ if (use_of_interrupt_tree)
+ return mem_start;
+
ip = (int *) get_property(np, "interrupts", &l);
if (ip != 0) {
np->intrs = (struct interrupt_info *) mem_start;
mem_start += i * sizeof(struct address_range);
}
+ if (use_of_interrupt_tree)
+ return mem_start;
+
ip = (int *) get_property(np, "AAPL,interrupts", &l);
if (ip == 0)
ip = (int *) get_property(np, "interrupts", &l);
return head;
}
+/* Finds a device node given its PCI bus number, device number
+ * and function number
+ */
+__openfirmware
+struct device_node *
+find_pci_device_OFnode(unsigned char bus, unsigned char dev_fn)
+{
+ struct device_node* np;
+ unsigned int *reg;
+ int l;
+
+ for (np = allnodes; np != 0; np = np->allnext) {
+ char *pname = np->parent ?
+ (char *)get_property(np->parent, "name", &l) : 0;
+ if (pname && strcmp(pname, "mac-io") == 0)
+ continue;
+ reg = (unsigned int *) get_property(np, "reg", &l);
+ if (reg == 0 || l < sizeof(struct reg_property))
+ continue;
+ if (((reg[0] >> 8) & 0xff) == dev_fn && ((reg[0] >> 16) & 0xff) == bus)
+ break;
+ }
+ return np;
+}
+
+/*
+ * Returns all nodes linked together
+ */
+__openfirmware
+struct device_node *
+find_all_nodes(void)
+{
+ struct device_node *head, **prevp, *np;
+
+ prevp = &head;
+ for (np = allnodes; np != 0; np = np->allnext) {
+ *prevp = np;
+ prevp = &np->next;
+ }
+ *prevp = 0;
+ return head;
+}
+
/* Checks if the given "compat" string matches one of the strings in
* the device's "compatible" property
*/
prom_exit();
}
-#ifdef CONFIG_XMON
+/* Indicates whether the root node has a given value in its
+ * compatible property.
+ */
+__openfirmware
+int
+machine_is_compatible(const char *compat)
+{
+ struct device_node *root;
+
+ root = find_path_device("/");
+ if (root == 0)
+ return 0;
+ return device_is_compatible(root, compat);
+}
+
+
+#ifdef CONFIG_BOOTX_TEXT
+
+/* Here's a small text engine to use during early boot or for debugging purposes
+ *
+ * todo:
+ *
+ * - build some kind of vgacon with it to enable early printk
+ * - move to a separate file
+ * - add a few video driver hooks to keep in sync with display
+ * changes.
+ */
+
__init
void
map_bootx_text(void)
{
- if (boot_infos == 0)
+ if (disp_bi == 0)
return;
- boot_infos->logicalDisplayBase =
- ioremap((unsigned long) boot_infos->dispDeviceBase,
- boot_infos->dispDeviceRowBytes * boot_infos->dispDeviceRect[3]);
+ disp_bi->logicalDisplayBase =
+ ioremap((unsigned long) disp_bi->dispDeviceBase,
+ disp_bi->dispDeviceRowBytes * disp_bi->dispDeviceRect[3]);
}
-#endif /* CONFIG_XMON */
/* Calc the base address of a given point (x,y) */
__pmac
clearscreen(void)
{
unsigned long offset = reloc_offset();
- boot_infos_t* bi = PTRRELOC(RELOC(boot_infos));
+ boot_infos_t* bi = PTRRELOC(RELOC(disp_bi));
unsigned long *base = (unsigned long *)calc_base(bi, 0, 0);
unsigned long width = ((bi->dispDeviceRect[2] - bi->dispDeviceRect[0]) *
(bi->dispDeviceDepth >> 3)) >> 2;
flushscreen(void)
{
unsigned long offset = reloc_offset();
- boot_infos_t* bi = PTRRELOC(RELOC(boot_infos));
+ boot_infos_t* bi = PTRRELOC(RELOC(disp_bi));
unsigned long *base = (unsigned long *)calc_base(bi, 0, 0);
unsigned long width = ((bi->dispDeviceRect[2] - bi->dispDeviceRect[0]) *
(bi->dispDeviceDepth >> 3)) >> 2;
}
}
-/* Indicates whether the root node has a given value in its
- * compatible property.
- */
-__openfirmware
-int
-machine_is_compatible(const char *compat)
-{
- struct device_node *root;
-
- root = find_path_device("/");
- if (root == 0)
- return 0;
- return device_is_compatible(root, compat);
-}
-
-#ifdef CONFIG_BOOTX_TEXT
-
__pmac
static void
scrollscreen(void)
{
unsigned long offset = reloc_offset();
- boot_infos_t* bi = PTRRELOC(RELOC(boot_infos));
+ boot_infos_t* bi = PTRRELOC(RELOC(disp_bi));
unsigned long *src = (unsigned long *)calc_base(bi,0,16);
unsigned long *dst = (unsigned long *)calc_base(bi,0,0);
unsigned long width = ((bi->dispDeviceRect[2] - bi->dispDeviceRect[0]) *
draw_byte(unsigned char c, long locX, long locY)
{
unsigned long offset = reloc_offset();
- boot_infos_t* bi = PTRRELOC(RELOC(boot_infos));
+ boot_infos_t* bi = PTRRELOC(RELOC(disp_bi));
unsigned char *base = calc_base(bi, locX << 3, locY << 4);
unsigned char *font = &RELOC(vga_font)[((unsigned long)c) * 16];
+ int rb = bi->dispDeviceRowBytes;
switch(bi->dispDeviceDepth) {
case 32:
- draw_byte_32(font, (unsigned long *)base);
+ draw_byte_32(font, (unsigned long *)base, rb);
break;
case 16:
- draw_byte_16(font, (unsigned long *)base);
+ draw_byte_16(font, (unsigned long *)base, rb);
break;
case 8:
- draw_byte_8(font, (unsigned long *)base);
+ draw_byte_8(font, (unsigned long *)base, rb);
break;
default:
break;
__pmac
static void
-draw_byte_32(unsigned char *font, unsigned long *base)
+draw_byte_32(unsigned char *font, unsigned long *base, int rb)
{
- unsigned long offset = reloc_offset();
- boot_infos_t* bi = PTRRELOC(RELOC(boot_infos));
int l, bits;
int fg = 0xFFFFFFFFUL;
int bg = 0x00000000UL;
base[5] = (-((bits >> 2) & 1) & fg) ^ bg;
base[6] = (-((bits >> 1) & 1) & fg) ^ bg;
base[7] = (-(bits & 1) & fg) ^ bg;
- base = (unsigned long *) ((char *)base + bi->dispDeviceRowBytes);
+ base = (unsigned long *) ((char *)base + rb);
}
}
__pmac
static void
-draw_byte_16(unsigned char *font, unsigned long *base)
+draw_byte_16(unsigned char *font, unsigned long *base, int rb)
{
- unsigned long offset = reloc_offset();
- boot_infos_t* bi = PTRRELOC(RELOC(boot_infos));
int l, bits;
int fg = 0xFFFFFFFFUL;
int bg = 0x00000000UL;
+ unsigned long offset = reloc_offset();
unsigned long *eb = RELOC(expand_bits_16);
for (l = 0; l < 16; ++l)
base[1] = (eb[(bits >> 4) & 3] & fg) ^ bg;
base[2] = (eb[(bits >> 2) & 3] & fg) ^ bg;
base[3] = (eb[bits & 3] & fg) ^ bg;
- base = (unsigned long *) ((char *)base + bi->dispDeviceRowBytes);
+ base = (unsigned long *) ((char *)base + rb);
}
}
__pmac
static void
-draw_byte_8(unsigned char *font, unsigned long *base)
+draw_byte_8(unsigned char *font, unsigned long *base, int rb)
{
- unsigned long offset = reloc_offset();
- boot_infos_t* bi = PTRRELOC(RELOC(boot_infos));
int l, bits;
int fg = 0x0F0F0F0FUL;
int bg = 0x00000000UL;
+ unsigned long offset = reloc_offset();
unsigned long *eb = RELOC(expand_bits_8);
for (l = 0; l < 16; ++l)
bits = *font++;
base[0] = (eb[bits >> 4] & fg) ^ bg;
base[1] = (eb[bits & 0xf] & fg) ^ bg;
- base = (unsigned long *) ((char *)base + bi->dispDeviceRowBytes);
+ base = (unsigned long *) ((char *)base + rb);
}
}
unsigned long r6,
unsigned long r7);
+#ifdef CONFIG_BOOTX_TEXT
+extern void map_bootx_text(void);
+#endif
+#ifdef CONFIG_XMON
+extern void xmon_map_scc(void);
+#endif
+
extern boot_infos_t *boot_infos;
extern char cmd_line[512];
char saved_command_line[256];
case 10:
len += sprintf(len+buffer, "604ev5 (MachV)\n");
break;
+ case 12:
+ len += sprintf(len+buffer, "7400 (G4)\n");
+ break;
case 50:
len += sprintf(len+buffer, "821\n");
case 80:
char *p;
#ifdef CONFIG_BLK_DEV_INITRD
- if (r3 - KERNELBASE < 0x800000
- && r4 != 0 && r4 != 0xdeadbeef) {
+ /* Removed check < 0x800000, yaboot loads the kernel at +16Mb
+ * and the ramdisk _after_ the kernel */
+ if (r3 && r4 && r4 != 0xdeadbeef) {
+ if (r3 < KERNELBASE)
+ r3 += KERNELBASE;
initrd_start = r3;
initrd_end = r3 + r4;
ROOT_DEV = MKDEV(RAMDISK_MAJOR, 0);
+ initrd_below_start_ok = 1;
}
#endif
cmd_line[0] = 0;
/* Checks "l2cr=xxxx" command-line option */
void ppc_setup_l2cr(char *str, int *ints)
{
- if ( (_get_PVR() >> 16) == 8)
+ if ( ((_get_PVR() >> 16) == 8) || ((_get_PVR() >> 16) == 12) )
{
unsigned long val = simple_strtoul(str, NULL, 0);
printk(KERN_INFO "l2cr set to %lx\n", val);
extern unsigned long find_available_memory(void);
extern unsigned long *end_of_DRAM;
+#ifdef CONFIG_BOOTX_TEXT
+ map_bootx_text();
+#endif
+
#ifdef CONFIG_XMON
- extern void xmon_map_scc(void);
- char *p;
+ {
+ char *p;
- xmon_map_scc();
- p = strstr(cmd_line, "xmon");
- if (p != NULL && (p == cmd_line || p[-1] == ' '))
- xmon(0);
+ xmon_map_scc();
+ p = strstr(cmd_line, "xmon");
+ if (p != NULL && (p == cmd_line || p[-1] == ' '))
+ xmon(0);
+ }
#endif /* CONFIG_XMON */
/* reboot on panic */
sr = (struct sigregs *) sigctx.regs;
if (regs->msr & MSR_FP )
giveup_fpu(current);
+#ifdef CONFIG_ALTIVEC
+ if (regs->msr & MSR_VEC)
+ giveup_altivec(current);
+#endif /* CONFIG_ALTIVEC */
if (copy_from_user(saved_regs, &sr->gp_regs,
sizeof(sr->gp_regs)))
goto badframe;
goto badframe;
if (regs->msr & MSR_FP)
giveup_fpu(current);
+#ifdef CONFIG_ALTIVEC
+ if (regs->msr & MSR_VEC)
+ giveup_altivec(current);
+#endif /* CONFIG_ALTIVEC */
if (__copy_to_user(&frame->gp_regs, regs, GP_REGS_SIZE)
|| __copy_to_user(&frame->fp_regs, current->tss.fpr,
ELF_NFPREG * sizeof(double))
* deal of code from the sparc and intel versions.
*
* Support for PReP (Motorola MTX/MVME) SMP by Troy Benjegerdes
- * (troy@microux.com, hozer@drgw.net)
+ * (troy@blacklablinux.com, hozer@drgw.net)
*/
#include <linux/kernel.h>
asmlinkage int sys_uname(struct old_utsname * name)
{
- if (name && !copy_to_user(name, &system_utsname, sizeof (*name)))
- return 0;
- return -EFAULT;
+ int err;
+
+ if (!name)
+ return -EFAULT;
+ down(&uts_sem);
+ err = copy_to_user(name, &system_utsname, sizeof (*name));
+ up(&uts_sem);
+ return err ? -EFAULT : 0;
}
asmlinkage int sys_olduname(struct oldold_utsname * name)
if (!access_ok(VERIFY_WRITE,name,sizeof(struct oldold_utsname)))
return -EFAULT;
+ down(&uts_sem);
error = __copy_to_user(&name->sysname,&system_utsname.sysname,__OLD_UTS_LEN);
error -= __put_user(0,name->sysname+__OLD_UTS_LEN);
error -= __copy_to_user(&name->nodename,&system_utsname.nodename,__OLD_UTS_LEN);
error -= __copy_to_user(&name->machine,&system_utsname.machine,__OLD_UTS_LEN);
error = __put_user(0,name->machine+__OLD_UTS_LEN);
error = error ? -EFAULT : 0;
+ up(&uts_sem);
return error;
}
return;
}
#endif
- printk("Machine check in kernel mode.\n");
- printk("Caused by (from msr): ");
- printk("regs %p ",regs);
- switch( regs->msr & 0x0000F000)
- {
- case (1<<12) :
- printk("Machine check signal - probably due to mm fault\n"
- "with mmu off\n");
+ printk("Machine check in kernel mode. (regs at %p)\n", regs);
+ printk("Caused by (from srr1): ");
+ switch( regs->msr & 0x001F0000) {
+ case 0x100000:
+ printk("L2 data cache parity error\n");
break;
- case (1<<13) :
+ case 0x80000:
+ printk("Machine check signal\n");
+ printk("(probably due to access of bad physical address\n");
+ break;
+ case 0x40000:
printk("Transfer error ack signal\n");
break;
- case (1<<14) :
+ case 0x20000:
printk("Data parity signal\n");
break;
- case (1<<15) :
+ case 0x10000:
printk("Address parity signal\n");
break;
default:
- printk("Unknown values in msr\n");
+ printk("Unknown values in srr1\n");
}
show_regs(regs);
#if defined(CONFIG_XMON) || defined(CONFIG_KGDB)
#include <asm/processor.h>
#include <asm/errno.h>
+CACHELINE_BYTES = 32
+LG_CACHELINE_BYTES = 5
+CACHELINE_MASK = 0x1f
+CACHELINE_WORDS = 8
+
.globl strcpy
strcpy:
addi r5,r3,-1
andi. r0,r6,3
add r5,r0,r5
subf r6,r0,r6
- rlwinm r0,r5,32-2,2,31
+#if 0 /* Clever, but breaks fb stuff -- paulus */
+/*
+ * Use dcbz on the complete cache lines in the destination if
+ * we are setting to zero. This requires that the destination
+ * area is cacheable. -- paulus
+ */
+ cmpwi 0,r4,0
+ bne 2f
+ clrlwi r7,r6,32-LG_CACHELINE_BYTES
+ add r8,r7,r5
+ srwi r9,r8,LG_CACHELINE_BYTES
+ addic. r9,r9,-1 /* total number of complete cachelines */
+ ble 2f
+ xori r0,r7,CACHELINE_MASK & ~3
+ srwi. r0,r0,2
+ beq 3f
+ mtctr r0
+4: stwu r4,4(r6)
+ bdnz 4b
+3: mtctr r9
+ li r7,4
+10: dcbz r7,r6
+ addi r6,r6,CACHELINE_BYTES
+ bdnz 10b
+ clrlwi r5,r8,32-LG_CACHELINE_BYTES
+ addi r5,r5,4
+2:
+#endif
+ srwi r0,r5,2
mtctr r0
bdz 6f
1: stwu r4,4(r6)
memmove:
cmplw 0,r3,r4
bgt backwards_memcpy
- /* fall through */
+ b forwards_memcpy
.globl memcpy
memcpy:
- rlwinm. r7,r5,32-3,3,31 /* r0 = r5 >> 3 */
+#if 0 /* Clever, but will probably break fb stuff -- paulus */
+/*
+ * This version uses dcbz on the complete cache lines in the
+ * destination area to reduce memory traffic. This requires that
+ * the destination area is cacheable.
+ * We only use this version if the source and dest don't overlap.
+ * -- paulus.
+ */
+ add r7,r3,r5 /* test if the src & dst overlap */
+ add r8,r4,r5
+ cmplw 0,r4,r7
+ cmplw 1,r3,r8
+ crand 0,0,4 /* cr0.lt &= cr1.lt */
+ blt forwards_memcpy /* if regions overlap */
+
+ addi r4,r4,-4
+ addi r6,r3,-4
+ neg r0,r3
+ andi. r0,r0,CACHELINE_MASK /* # bytes to start of cache line */
+ beq 58f
+
+ cmplw 0,r5,r0 /* is this more than total to do? */
+ blt 63f /* if not much to do */
+ andi. r8,r0,3 /* get it word-aligned first */
+ subf r5,r0,r5
+ mtctr r8
+ beq+ 61f
+70: lbz r9,4(r4) /* do some bytes */
+ stb r9,4(r6)
+ addi r4,r4,1
+ addi r6,r6,1
+ bdnz 70b
+61: srwi. r0,r0,2
+ mtctr r0
+ beq 58f
+72: lwzu r9,4(r4) /* do some words */
+ stwu r9,4(r6)
+ bdnz 72b
+
+58: srwi. r0,r5,LG_CACHELINE_BYTES /* # complete cachelines */
+ clrlwi r5,r5,32-LG_CACHELINE_BYTES
+ li r11,4
+ mtctr r0
+ beq 63f
+53: dcbz r11,r6
+ lwz r7,4(r4)
+ lwz r8,8(r4)
+ lwz r9,12(r4)
+ lwzu r10,16(r4)
+ stw r7,4(r6)
+ stw r8,8(r6)
+ stw r9,12(r6)
+ stwu r10,16(r6)
+ lwz r7,4(r4)
+ lwz r8,8(r4)
+ lwz r9,12(r4)
+ lwzu r10,16(r4)
+ stw r7,4(r6)
+ stw r8,8(r6)
+ stw r9,12(r6)
+ stwu r10,16(r6)
+ bdnz 53b
+
+63: srwi. r0,r5,2
+ mtctr r0
+ beq 64f
+30: lwzu r0,4(r4)
+ stwu r0,4(r6)
+ bdnz 30b
+
+64: andi. r0,r5,3
+ mtctr r0
+ beq+ 65f
+40: lbz r0,4(r4)
+ stb r0,4(r6)
+ addi r4,r4,1
+ addi r6,r6,1
+ bdnz 40b
+65: blr
+#endif
+
+ .global forwards_memcpy
+forwards_memcpy:
+ srwi. r7,r5,3
addi r6,r3,-4
addi r4,r4,-4
beq 2f /* if less than 8 bytes to do */
.globl __copy_tofrom_user
__copy_tofrom_user:
- srwi. r7,r5,3
- addi r6,r3,-4
addi r4,r4,-4
- li r3,0 /* success return value */
- beq 2f /* if less than 8 bytes to do */
- andi. r0,r6,3 /* get dest word aligned */
- mtctr r7
- bne 5f
-1: lwz r7,4(r4)
-11: lwzu r8,8(r4)
-12: stw r7,4(r6)
-13: stwu r8,8(r6)
- bdnz 1b
- andi. r5,r5,7
-2: cmplwi 0,r5,4
- blt 3f
-14: lwzu r0,4(r4)
- addi r5,r5,-4
-15: stwu r0,4(r6)
-3: cmpwi 0,r5,0 /* do 1 byte at a time for the remainder */
- beqlr
- mtctr r5
- addi r4,r4,3
- addi r6,r6,3
-4: lbzu r0,1(r4)
-16: stbu r0,1(r6)
- bdnz 4b
- blr
-5: subfic r0,r0,4 /* copy bytes until we have the */
- mtctr r0 /* destination 4-byte aligned */
- subf r5,r0,r5
-6: lbz r7,4(r4)
+ addi r6,r3,-4
+ neg r0,r3
+ andi. r0,r0,CACHELINE_MASK /* # bytes to start of cache line */
+ beq 58f
+
+ cmplw 0,r5,r0 /* is this more than total to do? */
+ blt 63f /* if not much to do */
+ andi. r8,r0,3 /* get it word-aligned first */
+ mtctr r8
+ beq+ 61f
+70: lbz r9,4(r4) /* do some bytes */
+71: stb r9,4(r6)
addi r4,r4,1
-17: stb r7,4(r6)
addi r6,r6,1
- bdnz 6b
- srwi. r7,r5,3
- beq 2b
- mtctr r7
- b 1b
-/* we come here on a fault in the 8-byte-at-a-time loop */
-88: subi r4,r4,8 /* compensate for the lwzu */
-98: mfctr r0
- rlwimi r5,r0,3,0,28 /* use the byte-at-a-time loop to */
- b 3b /* copy up to the byte at fault */
-/* here on a write fault in the single-word copy */
-96: subi r4,r4,4
- b 3b
-/* here on a read fault in the initial single-byte copy */
-90: mfctr r3
- add r3,r3,r5
- b 70f
-/* here on a read fault in the final single-byte copy */
-99: mfctr r3
- subi r6,r6,3
-/* clear out the rest of the destination: r3 bytes starting at 4(r6) */
-70: li r0,0
- mr. r5,r3
- beq 76f
-71: andi. r4,r6,3
- beq 72f
-77: stb r0,4(r6)
+ bdnz 70b
+61: subf r5,r0,r5
+ srwi. r0,r0,2
+ mtctr r0
+ beq 58f
+72: lwzu r9,4(r4) /* do some words */
+73: stwu r9,4(r6)
+ bdnz 72b
+
+58: srwi. r0,r5,LG_CACHELINE_BYTES /* # complete cachelines */
+ clrlwi r5,r5,32-LG_CACHELINE_BYTES
+ li r11,4
+ mtctr r0
+ beq 63f
+53: dcbz r11,r6
+10: lwz r7,4(r4)
+11: lwz r8,8(r4)
+12: lwz r9,12(r4)
+13: lwzu r10,16(r4)
+14: stw r7,4(r6)
+15: stw r8,8(r6)
+16: stw r9,12(r6)
+17: stwu r10,16(r6)
+20: lwz r7,4(r4)
+21: lwz r8,8(r4)
+22: lwz r9,12(r4)
+23: lwzu r10,16(r4)
+24: stw r7,4(r6)
+25: stw r8,8(r6)
+26: stw r9,12(r6)
+27: stwu r10,16(r6)
+ bdnz 53b
+
+63: srwi. r0,r5,2
+ mtctr r0
+ beq 64f
+30: lwzu r0,4(r4)
+31: stwu r0,4(r6)
+ bdnz 30b
+
+64: andi. r0,r5,3
+ mtctr r0
+ beq+ 65f
+40: lbz r0,4(r4)
+41: stb r0,4(r6)
+ addi r4,r4,1
addi r6,r6,1
- addic. r5,r5,-1
- bne 71b
-72: srwi. r7,r5,2
- beq 73f
- mtctr r7
-74: stwu r0,4(r6)
- bdnz 74b
-73: andi. r5,r5,3
- beq 76f
- mtctr r5
- addi r6,r6,3
-75: stbu r0,1(r6)
- bdnz 75b
-76: blr
-/* here on a write fault in the initial single-byte copy */
-80: mfctr r3
- add r3,r3,r5
- blr
-/* here on a write fault in the final single-byte copy */
-81: mfctr r3
+ bdnz 40b
+65: li r3,0
blr
+/* read fault, initial single-byte copy */
+100: li r4,0
+ b 90f
+/* write fault, initial single-byte copy */
+101: li r4,1
+90: subf r5,r8,r5
+ li r3,0
+ b 99f
+/* read fault, initial word copy */
+102: li r4,0
+ b 91f
+/* write fault, initial word copy */
+103: li r4,1
+91: li r3,2
+ b 99f
+/* read fault in 2nd half of cacheline loop */
+106: addi r5,r5,-16
+/* read fault in 1st half of cacheline loop */
+104: li r4,0
+ b 92f
+/* write fault in 2nd half of cacheline loop */
+107: addi r5,r5,-16
+/* fault on dcbz (effectively a write fault) */
+/* or write fault in 1st half of cacheline loop */
+105: li r4,1
+92: li r3,LG_CACHELINE_BYTES
+ b 99f
+/* read fault in final word loop */
+108: li r4,0
+ b 93f
+/* write fault in final word loop */
+109: li r4,1
+93: andi. r5,r5,3
+ li r3,2
+ b 99f
+/* read fault in final byte loop */
+110: li r4,0
+ b 94f
+/* write fault in final byte loop */
+111: li r4,1
+94: li r5,0
+ li r3,0
+/*
+ * At this stage the number of bytes not copied is
+ * r5 + (ctr << r3), and r4 is 0 for read or 1 for write.
+ */
+99: mfctr r0
+ slw r3,r0,r3
+ add r3,r3,r5
+ cmpwi 0,r4,0
+ bne 120f
+/* for read fault, clear out the destination: r3 bytes starting at 4(r6) */
+ srwi. r0,r3,2
+ li r9,0
+ mtctr r0
+ beq 113f
+112: stwu r9,4(r6)
+ bdnz 112b
+113: andi. r0,r3,3
+ mtctr r0
+ beq 120f
+114: stb r9,4(r6)
+ addi r6,r6,1
+ bdnz 114b
+120: blr
+
.section __ex_table,"a"
.align 2
- .long 1b,98b
- .long 11b,98b
- .long 12b,88b
- .long 13b,88b
- .long 14b,3b
- .long 15b,96b
- .long 4b,99b
- .long 16b,81b
- .long 6b,90b
- .long 17b,80b
- .long 77b,76b
- .long 74b,76b
- .long 75b,76b
+ .long 70b,100b
+ .long 71b,101b
+ .long 72b,102b
+ .long 73b,103b
+ .long 53b,105b
+ .long 10b,104b
+ .long 11b,104b
+ .long 12b,104b
+ .long 13b,104b
+ .long 14b,105b
+ .long 15b,105b
+ .long 16b,105b
+ .long 17b,105b
+ .long 20b,106b
+ .long 21b,106b
+ .long 22b,106b
+ .long 23b,106b
+ .long 24b,107b
+ .long 25b,107b
+ .long 26b,107b
+ .long 27b,107b
+ .long 30b,108b
+ .long 31b,109b
+ .long 40b,110b
+ .long 41b,111b
+ .long 112b,120b
+ .long 114b,120b
.text
.globl __clear_user
andi. r0,r6,3
add r4,r0,r4
subf r6,r0,r6
- /*rlwinm r0,r4,32-2,2,31*/
srwi r0,r4,2
mtctr r0
bdz 6f
(error_code&0x80000000)?"I/O ":"",
(regs->trap == 0x400)?"instr":"data"
);*/
-
+
+ if (regs->trap == 0x400)
+ error_code &= 0x48200000;
+
#if defined(CONFIG_XMON) || defined(CONFIG_KGDB)
if (debugger_fault_handler && regs->trap == 0x300) {
debugger_fault_handler(regs);
void iounmap(void *addr)
{
- /* XXX todo */
+ /* For support of dynamic hot swap on the cPCI bus this routine
+ is now necessary. This has been well tested on a Motorola
+ MPC750 (Mesquite) processor board. Johnnie Peters
+ */
+ if (addr > high_memory && addr < ioremap_bot)
+ return vfree((void *) (PAGE_MASK & (unsigned long) addr));
}
unsigned long iopa(unsigned long addr)
CONFIG_NET_ETHERNET=y
CONFIG_MACE=y
CONFIG_BMAC=y
+CONFIG_GMAC=y
# CONFIG_NET_VENDOR_3COM is not set
# CONFIG_LANCE is not set
# CONFIG_NET_VENDOR_SMC is not set
CONFIG_FB_PLATINUM=y
CONFIG_FB_VALKYRIE=y
CONFIG_FB_ATY=y
+CONFIG_FB_ATY128=y
CONFIG_FB_IMSTT=y
CONFIG_FB_CT65550=y
# CONFIG_FB_S3TRIO is not set
#include <asm/prom.h>
#include <asm/bootx.h>
#include <asm/pmu.h>
+#include <asm/feature.h>
static volatile unsigned char *sccc, *sccd;
unsigned long TXRDY, RXRDY;
extern void xmon_printf(const char *fmt, ...);
-extern void map_bootx_text(void);
extern void drawchar(char);
extern void drawstring(const char *str);
+static int xmon_expect(const char *str, unsigned int timeout);
static int console = 0;
static int use_screen = 0;
+static int via_modem = 0;
+static int xmon_use_sccb = 0;
+static struct device_node *macio_node;
+
+#define TB_SPEED 25000000
+
+static inline unsigned int readtb(void)
+{
+ unsigned int ret;
+
+ asm volatile("mftb %0" : "=r" (ret) :);
+ return ret;
+}
void buf_access(void)
{
if ( _machine == _MACH_Pmac )
{
struct device_node *np;
- extern boot_infos_t *boot_infos;
unsigned long addr;
-
#ifdef CONFIG_BOOTX_TEXT
- if (boot_infos != 0 && find_via_pmu()) {
+ extern boot_infos_t *disp_bi;
+
+ /* needs to be hacked if xmon_printk is to be used
+ from within find_via_pmu() */
+ if (!via_modem && disp_bi && find_via_pmu()) {
printk(KERN_INFO "xmon uses screen and keyboard\n");
use_screen = 1;
- map_bootx_text();
- return;
}
#endif
+
#ifdef CHRP_ESCC
addr = 0xc1013020;
#else
np = find_devices("mac-io");
if (np && np->n_addrs) {
- addr = np->addrs[0].address + 0x13000;
- /* use the B channel on the iMac, A channel on others */
- if (addr >= 0xf0000000)
- addr += 0x20; /* use A channel */
+ macio_node = np;
+ addr = np->addrs[0].address + 0x13020;
}
- base = (volatile unsigned char *) ioremap(addr & PAGE_MASK, PAGE_SIZE);
+ base = (volatile unsigned char *)
+ ioremap(addr & PAGE_MASK, PAGE_SIZE);
sccc = base + (addr & ~PAGE_MASK);
-#ifdef CHRP_ESCC
- sccd = sccc + (0xc1013030 - 0xc1013020);
-#else
- sccd = sccc + (0xf3013030 - 0xf3013020);
-#endif
+ sccd = sccc + 0x10;
}
else
{
xmon_write(void *handle, void *ptr, int nb)
{
char *p = ptr;
- int i, ct;
+ int i, c, ct;
#ifdef CONFIG_BOOTX_TEXT
if (use_screen) {
#endif
if (!scc_initialized)
xmon_init_scc();
+ ct = 0;
for (i = 0; i < nb; ++i) {
while ((*sccc & TXRDY) == 0)
if (adb_hardware == ADB_VIAPMU)
pmu_poll();
+ c = p[i];
+ if (c == '\n' && !ct) {
+ c = '\r';
+ ct = 1;
+ --i;
+ } else {
+ if (console)
+ printk("%c", c);
+ ct = 0;
+ }
buf_access();
- if ( console && (*p != '\r'))
- printk("%c", *p);
- ct = 0;
- if ( *p == '\n')
- ct = 1;
- *sccd = *p++;
- if ( ct )
- xmon_write(handle, "\r", 1);
+ *sccd = c;
}
return i;
}
if (adb_hardware == ADB_VIAPMU)
pmu_poll();
buf_access();
-#if 0
- if ( 0/*console*/ )
- *p++ = ppc_md.kbd_getkeycode();
- else
-#endif
- *p++ = *sccd;
+ *p++ = *sccd;
}
return i;
}
+int
+xmon_read_poll(void)
+{
+ if ((*sccc & RXRDY) == 0) {
+ if (adb_hardware == ADB_VIAPMU)
+ pmu_poll();
+ return -1;
+ }
+ buf_access();
+ return *sccd;
+}
+
static unsigned char scc_inittab[] = {
13, 0, /* set baud rate divisor */
12, 1,
14, 1, /* baud rate gen enable, src=rtxc */
11, 0x50, /* clocks = br gen */
- 5, 0x6a, /* tx 8 bits, assert RTS */
- 4, 0x44, /* x16 clock, 1 stop */
+ 5, 0xea, /* tx 8 bits, assert DTR & RTS */
+ 4, 0x46, /* x16 clock, 1 stop */
3, 0xc1, /* rx enable, 8 bits */
};
{
int i, x;
+ if (macio_node != 0) {
+ unsigned int t0;
+
+ feature_set(macio_node, FEATURE_Serial_enable);
+ if (via_modem) {
+ feature_set(macio_node, FEATURE_Modem_power);
+ t0 = readtb();
+ while (readtb() - t0 < 3*TB_SPEED)
+ eieio();
+ }
+ }
+ if (xmon_use_sccb) {
+ sccc -= 0x20;
+ sccd -= 0x20;
+ }
for (i = 20000; i != 0; --i) {
x = *sccc; eieio();
}
}
}
scc_initialized = 1;
+ if (via_modem) {
+ for (;;) {
+ xmon_write(0, "ATE1V1\r", 7);
+ if (xmon_expect("OK", 5)) {
+ xmon_write(0, "ATA\r", 4);
+ if (xmon_expect("CONNECT", 40))
+ break;
+ }
+ xmon_write(0, "+++", 3);
+ xmon_expect("OK", 3);
+ }
+ }
}
#if 0
static char *lineptr;
static int lineleft;
+int xmon_expect(const char *str, unsigned int timeout)
+{
+ int c;
+ unsigned int t0;
+
+ timeout *= TB_SPEED;
+ t0 = readtb();
+ do {
+ lineptr = line;
+ for (;;) {
+ c = xmon_read_poll();
+ if (c == -1) {
+ if (readtb() - t0 > timeout) {
+ printk("timeout\n");
+ return 0;
+ }
+ continue;
+ }
+ if (c == '\n')
+ break;
+ printk("%c", c);
+ if (c != '\r' && lineptr < &line[sizeof(line) - 1])
+ *lineptr++ = c;
+ }
+ *lineptr = 0;
+ } while (strstr(line, str) == NULL);
+ return 1;
+}
+
int
xmon_getchar(void)
{
unsigned long pci_dvma_v2p_hash[PCI_DVMA_HASHSZ];
unsigned long pci_dvma_p2v_hash[PCI_DVMA_HASHSZ];
+/* If this is non-NULL it points to Sabre's DMA write-sync register
+ * which is used by drivers of devices behind bridges other than APB
+ * to synchronize DMA write streams with interrupt delivery.
+ */
+volatile u64 *pci_dma_wsync = NULL;
+
#ifndef CONFIG_PCI
int pcibios_present(void)
prom_halt();
}
+ pci_dma_wsync = &sabre->psycho_regs->pci_dma_wsync;
+
printk("PCI: Found SABRE, main regs at %p CTRL[%016lx]\n",
sabre->psycho_regs, sabre->psycho_regs->control);
#ifdef PROM_DEBUG
#endif
#ifdef CONFIG_PCI
#include <asm/ebus.h>
+#include <asm/pbm.h>
#endif
#include <asm/a.out.h>
#include <asm/svr4.h>
EXPORT_SYMBOL(insb);
EXPORT_SYMBOL(insw);
EXPORT_SYMBOL(insl);
+EXPORT_SYMBOL(pci_dma_wsync);
#endif
/* Solaris/SunOS binary compatibility */
struct request_sense sense;
int ret;
- toc = info->toc;
- if (!CDROM_STATE_FLAGS(drive)->toc_valid || toc == NULL)
+ if (!CDROM_STATE_FLAGS(drive)->toc_valid || info->toc == NULL)
if ((ret = cdrom_read_toc(drive, &sense)))
return ret;
+ toc = info->toc;
ms_info->addr.lba = toc->last_session_lba;
ms_info->xa_flag = toc->xa_flag;
case KDGETKEYCODE:
case KDSETKEYCODE:
+ if(!suser())
+ perm=0;
return do_kbkeycode_ioctl(cmd, (struct kbkeycode *)arg, perm);
case KDGKBENT:
if (adb_controller == NULL)
printk(KERN_WARNING "Warning: no ADB interface detected\n");
- else
- {
+ else {
adb_hardware = adb_controller->kind;
+
#ifdef CONFIG_PMAC_PBOOK
pmu_register_sleep_notifier(&adb_sleep_notifier);
#endif /* CONFIG_PMAC_PBOOK */
switch (when) {
case PBOOK_SLEEP_REQUEST:
adb_got_sleep = 1;
+ if (adb_controller->autopoll)
+ adb_controller->autopoll(0);
ret = notifier_call_chain(&adb_client_list, ADB_MSG_POWERDOWN, NULL);
if (ret & NOTIFY_STOP_MASK)
return PBOOK_SLEEP_REFUSE;
break;
case PBOOK_WAKE:
adb_reset_bus();
+ adb_got_sleep = 0;
break;
}
return PBOOK_SLEEP_OK;
int
adb_reset_bus(void)
{
- int ret, devs;
+ int ret, nret, devs;
unsigned long flags;
if (adb_controller == NULL)
return -ENXIO;
- ret = notifier_call_chain(&adb_client_list, ADB_MSG_PRE_RESET, NULL);
- if (ret & NOTIFY_STOP_MASK)
+ if (adb_controller->autopoll)
+ adb_controller->autopoll(0);
+
+ nret = notifier_call_chain(&adb_client_list, ADB_MSG_PRE_RESET, NULL);
+ if (nret & NOTIFY_STOP_MASK) {
+ if (adb_controller->autopoll)
+ adb_controller->autopoll(devs);
return -EBUSY;
+ }
save_flags(flags);
cli();
else
ret = 0;
- if (!ret)
- {
+ if (!ret) {
devs = adb_scan_bus();
if (adb_controller->autopoll)
adb_controller->autopoll(devs);
}
- ret = notifier_call_chain(&adb_client_list, ADB_MSG_POST_RESET, NULL);
- if (ret & NOTIFY_STOP_MASK)
+ nret = notifier_call_chain(&adb_client_list, ADB_MSG_POST_RESET, NULL);
+ if (nret & NOTIFY_STOP_MASK)
return -EBUSY;
- return 1;
+ return ret;
}
void
int i, id;
static int dump_adb_input = 0;
+ /* We skip keystrokes and mouse moves when the sleep process
+ * has been started. We stop autopoll, but this is another security
+ */
+ if (adb_got_sleep)
+ return;
+
id = buf[0] >> 4;
if (dump_adb_input) {
printk(KERN_INFO "adb packet: ");
if (adb_handler[address].handler_id == new_id)
return 1;
- adb_request(&req, NULL, ADBREQ_SYNC | ADBREQ_REPLY, 1,
- ADB_READREG(address,3));
- if (req.reply_len < 2)
- return 0;
adb_request(&req, NULL, ADBREQ_SYNC, 3,
- ADB_WRITEREG(address, 3), req.reply[1] & 0xF0, new_id);
+ ADB_WRITEREG(address, 3), address | 0x20, new_id);
adb_request(&req, NULL, ADBREQ_SYNC | ADBREQ_REPLY, 1,
ADB_READREG(address, 3));
if (req.reply_len < 2)
{
struct adbdev_state *state;
- if (MINOR(inode->i_rdev) > 0 || (adb_controller == NULL)/*adb_hardware == ADB_NONE*/)
+ if (MINOR(inode->i_rdev) > 0 || (adb_controller == NULL))
return -ENXIO;
state = kmalloc(sizeof(struct adbdev_state), GFP_KERNEL);
if (state == 0)
/* Special case for ADB_BUSRESET request, all others are sent to
the controller */
if ((req->data[0] == ADB_PACKET)&&(count > 1)
- &&(req->data[1] == ADB_BUSRESET))
+ &&(req->data[1] == ADB_BUSRESET)) {
ret = adb_reset_bus();
- else
- {
+ atomic_dec(&state->n_pending);
+ goto out;
+ } else {
req->reply_expected = ((req->data[1] & 0xc) == 0xc);
if (adb_controller && adb_controller->send_request)
* - Hunter digital (NoHandsMouse)
* - Kensignton TurboMouse 5 (needs testing)
* - Mouse Systems A3 mice and trackballs <aidan@kublai.com>
+ * - MacAlly 2-buttons mouse (needs testing) <pochini@denise.shiny.it>
*
* To do:
*
#define ADBMOUSE_MICROSPEED 6 /* Microspeed mouse (&trackball ?), MacPoint */
#define ADBMOUSE_TRACKBALLPRO 7 /* Trackball Pro (special buttons) */
#define ADBMOUSE_MS_A3 8 /* Mouse systems A3 trackball (handler 3) */
+#define ADBMOUSE_MACALLY2 9 /* MacAlly 2-button mouse */
static int adb_mouse_kinds[16];
data[3] = byyy bxxx Third button and fourth button. Y is additional
high bits of y-axis motion. XY is additional
high bits of x-axis motion.
+
+ MacAlly 2-button mouse protocol.
+
+ For MacAlly 2-button mouse protocol the data array will contain the
+ following values:
+
+ BITS COMMENTS
+ data[0] = dddd 1100 ADB command: Talk, register 0, for device dddd.
+ data[1] = bxxx xxxx Left button and x-axis motion.
+ data[2] = byyy yyyy Right button and y-axis motion.
+ data[3] = ???? ???? unknown
+ data[4] = ???? ???? unknown
+
*/
struct kbd_struct *kbd;
data[2] = (data[2] & 0x7f) | ((data[3] & 0x02) << 6);
data[3] = ((data[3] & 0x04) << 5);
break;
+ case ADBMOUSE_MACALLY2:
+ data[3] = (data[2] & 0x80) ? 0x80 : 0x00;
+ data[2] |= 0x80; /* Right button is mapped as button 3 */
+ nb=4;
+ break;
}
if (adb_mouse_interrupt_hook)
/* Ignore data from register other than 0 */
if ((adb_hardware != ADB_VIAPMU) || (data[0] & 0x3) || (nb < 2))
return;
-
+
switch (data[1]&0xf )
{
/* mute */
static void real_mackbd_leds(unsigned char leds, int device)
{
-
if (led_request.complete) {
adb_request(&led_request, leds_done, 0, 3,
ADB_WRITEREG(device, KEYB_LEDREG), 0xff,
led_request.complete = 1;
mackeyb_probe();
-
+
notifier_chain_register(&adb_client_list, &mackeyb_adb_notifier);
}
static int
adb_message_handler(struct notifier_block *this, unsigned long code, void *x)
{
+ unsigned long flags;
+
switch (code) {
case ADB_MSG_PRE_RESET:
case ADB_MSG_POWERDOWN:
- /* Add unregister_keyboard when merging with Paul Mackerras */
+ /* Stop the repeat timer. Autopoll is already off at this point */
+ save_flags(flags);
+ cli();
+ del_timer(&repeat_timer);
+ restore_flags(flags);
+
+ /* Stop pending led requests */
while(!led_request.complete)
adb_poll();
break;
-
+
case ADB_MSG_POST_RESET:
mackeyb_probe();
break;
|| (adb_mouse_kinds[id] == ADBMOUSE_MICROSPEED)) {
init_microspeed(id);
} else if (adb_mouse_kinds[id] == ADBMOUSE_MS_A3) {
- init_ms_a3(id);
+ init_ms_a3(id);
} else if (adb_mouse_kinds[id] == ADBMOUSE_EXTENDED) {
/*
* Register 1 is usually used for device
(req.reply[1] == 0x4b) && (req.reply[2] == 0x4d) &&
(req.reply[3] == 0x4c) && (req.reply[4] == 0x31))
init_turbomouse(id);
+ else if ((req.reply_len == 9) &&
+ (req.reply[1] == 0x4b) && (req.reply[2] == 0x4f) &&
+ (req.reply[3] == 0x49) && (req.reply[4] == 0x54)){
+ if (adb_try_handler_change(id, 0x42)) {
+ printk("\nADB MacAlly 2-button mouse at %d, handler set to 0x42", id);
+ adb_mouse_kinds[id] = ADBMOUSE_MACALLY2;
+ }
+ }
}
printk("\n");
}
static void
init_trackpad(int id)
{
- struct adb_request req;
+ struct adb_request req;
unsigned char r1_buffer[8];
printk(" (trackpad)");
init_trackball(int id)
{
struct adb_request req;
-
+
printk(" (trackman/mouseman)");
-
+
adb_mouse_kinds[id] = ADBMOUSE_TRACKBALL;
adb_request(&req, NULL, ADBREQ_SYNC, 3,
printk(" (TurboMouse 5)");
adb_mouse_kinds[id] = ADBMOUSE_TURBOMOUSE5;
-
+
adb_request(&req, NULL, ADBREQ_SYNC, 1, ADB_FLUSH(id));
adb_request(&req, NULL, ADBREQ_SYNC, 1, ADB_FLUSH(3));
out_8(&adb->intr_enb.r, DFB | TAG);
adb_controller = &macio_controller;
-// adb_hardware = ADB_MACIO;
-
-// adb_send_request = macio_adb_send_request;
-// adb_autopoll = macio_adb_autopoll;
-// adb_reset_bus = macio_reset_bus;
}
static int macio_adb_autopoll(int devs)
#define _INLINE_ inline
+#ifdef SERIAL_DEBUG_OPEN
+#define OPNDBG(fmt, arg...) printk(KERN_INFO fmt , ## arg)
+#else
+#define OPNDBG(fmt, arg...) do { } while (0)
+#endif
+#ifdef SERIAL_DEBUG_POWER
+#define PWRDBG(fmt, arg...) printk(KERN_INFO fmt , ## arg)
+#else
+#define PWRDBG(fmt, arg...) do { } while (0)
+#endif
+#ifdef SERIAL_DEBUG_BAUDS
+#define BAUDBG(fmt, arg...) printk(KERN_INFO fmt , ## arg)
+#else
+#define BAUDBG(fmt, arg...) do { } while (0)
+#endif
+
static void probe_sccs(void);
static void change_speed(struct mac_serial *info, struct termios *old);
static void rs_wait_until_sent(struct tty_struct *tty, int timeout);
* to it. - paulus)
*/
for (i = 200; i > 0; --i)
- if (ld_le32(&dma->control) & RUN)
+ if (ld_le32(&dma->status) & RUN)
udelay(1);
}
continue;
if (tty->flip.count >= TTY_FLIPBUF_SIZE)
tty_flip_buffer_push(tty);
-
+
if (tty->flip.count >= TTY_FLIPBUF_SIZE) {
static int flip_buf_ovf;
if (++flip_buf_ovf <= 1)
if (info->tx_stopped) {
#ifdef SERIAL_DEBUG_FLOW
printk("CTS up\n");
-#endif
+#endif
info->tx_stopped = 0;
if (!info->tx_active)
transmit_chars(info);
} else {
#ifdef SERIAL_DEBUG_FLOW
printk("CTS down\n");
-#endif
+#endif
info->tx_stopped = 1;
}
}
== virt_to_bus(info->rx_cmds[info->rx_cbuf] + 1))
where -= in_le16(&info->rx->res_count);
where--;
-
+
stat = read_zsreg(info->zs_channel, R1);
flag = stat_to_flag(stat);
#ifdef SERIAL_DEBUG_INTR
printk("rs_interrupt: irq %d, zs_intreg 0x%x\n",
irq, (int)zs_intreg);
-#endif
+#endif
if ((zs_intreg & CHAN_IRQMASK) == 0)
break;
if (serial_paranoia_check(info, tty->device, "rs_stop"))
return;
-
+
#if 0
save_flags(flags); cli();
if (info->curregs[5] & TxENAB) {
{
struct mac_serial *info = (struct mac_serial *)tty->driver_data;
unsigned long flags;
-
+
#ifdef SERIAL_DEBUG_STOP
printk("rs_start %ld....\n",
tty->ldisc.chars_in_buffer(tty));
if (serial_paranoia_check(info, tty->device, "rs_start"))
return;
-
+
save_flags(flags); cli();
#if 0
if (info->xmit_cnt && info->xmit_buf && !(info->curregs[5] & TxENAB)) {
{
struct mac_serial *info = (struct mac_serial *) private_;
struct tty_struct *tty;
-
+
tty = info->tty;
if (!tty)
return;
{
int delay;
-#ifdef SERIAL_DEBUG_OPEN
- printk("startup() (ttyS%d, irq %d)\n", info->line, info->irq);
-#endif
+ OPNDBG("startup() (ttyS%d, irq %d)\n", info->line, info->irq);
if (info->flags & ZILOG_INITIALIZED) {
-#ifdef SERIAL_DEBUG_OPEN
- printk(" -> already inited\n");
-#endif
+ OPNDBG(" -> already inited\n");
return 0;
}
return -ENOMEM;
}
-#ifdef SERIAL_DEBUG_OPEN
- printk("starting up ttyS%d (irq %d)...\n", info->line, info->irq);
-#endif
+ OPNDBG("starting up ttyS%d (irq %d)...\n", info->line, info->irq);
delay = set_scc_power(info, 1);
-
+
setup_scc(info);
-#ifdef SERIAL_DEBUG_OPEN
- printk("enabling IRQ on ttyS%d (irq %d)...\n", info->line, info->irq);
-#endif
+ OPNDBG("enabling IRQ on ttyS%d (irq %d)...\n", info->line, info->irq);
info->flags |= ZILOG_INITIALIZED;
enable_irq(info->irq);
if (info->dma_initted) {
-// enable_irq(info->tx_dma_irq);
enable_irq(info->rx_dma_irq);
}
volatile struct dbdma_cmd *cd;
unsigned char *p;
-//printk(KERN_DEBUG "SCC: dma_init\n");
-
info->rx_nbuf = 8;
/* various mem set up */
static int setup_scc(struct mac_serial * info)
{
unsigned long flags;
-
-#ifdef SERIAL_DEBUG_OPEN
- printk("setting up ttys%d SCC...\n", info->line);
-#endif
- save_flags(flags); cli(); /* Disable interrupts */
+ OPNDBG("setting up ttys%d SCC...\n", info->line);
+
+ save_flags(flags); cli(); /* Disable interrupts */
/*
* Reset the chip.
/*
* Turn on RTS and DTR.
*/
- zs_rtsdtr(info, 1);
+ if (!info->is_irda)
+ zs_rtsdtr(info, 1);
/*
* Finally, enable sequencing and interrupts
*/
static void shutdown(struct mac_serial * info)
{
-#ifdef SERIAL_DEBUG_OPEN
- printk("Shutting down serial port %d (irq %d)....\n", info->line,
+ OPNDBG("Shutting down serial port %d (irq %d)....\n", info->line,
info->irq);
-#endif
-
+
if (!(info->flags & ZILOG_INITIALIZED)) {
-#ifdef SERIAL_DEBUG_OPEN
- printk("(already shutdown)\n");
-#endif
-
+ OPNDBG("(already shutdown)\n");
return;
}
/* The timings looks strange but that's the ones MacOS seems
to use for the internal modem. I think we can use a lot faster
ones, at least whe not using the modem, this should be tested.
- */
+ */
if (state) {
-#ifdef SERIAL_DEBUG_POWER
- printk(KERN_INFO "ttyS%02d: powering up hardware\n", info->line);
-#endif
+ PWRDBG("ttyS%02d: powering up hardware\n", info->line);
if (feature_test(info->dev_node, FEATURE_Serial_enable) == 0) {
- feature_clear(info->dev_node, FEATURE_Serial_reset);
- mdelay(5);
feature_set(info->dev_node, FEATURE_Serial_enable);
+ mdelay(10);
+ feature_set(info->dev_node, FEATURE_Serial_reset);
+ mdelay(15);
+ feature_clear(info->dev_node, FEATURE_Serial_reset);
+ mdelay(10);
}
if (info->zs_chan_a == info->zs_channel)
feature_set(info->dev_node, FEATURE_Serial_IO_A);
else
feature_set(info->dev_node, FEATURE_Serial_IO_B);
- delay = 1;
-
+ delay = 10;
if (info->is_cobalt_modem){
- feature_set(info->dev_node, FEATURE_Modem_Reset);
+ mdelay(300);
+ feature_set(info->dev_node, FEATURE_Modem_power);
mdelay(5);
- feature_clear(info->dev_node, FEATURE_Modem_Reset);
+ feature_clear(info->dev_node, FEATURE_Modem_power);
+ mdelay(10);
+ feature_set(info->dev_node, FEATURE_Modem_power);
delay = 2500; /* wait for 2.5s before using */
}
#ifdef CONFIG_PMAC_PBOOK
- if (info->is_pwbk_ir)
+ if (info->is_irda)
pmu_enable_irled(1);
#endif /* CONFIG_PMAC_PBOOK */
} else {
-#ifdef SERIAL_DEBUG_POWER
- printk(KERN_INFO "ttyS%02d: shutting down hardware\n", info->line);
-#endif
-#ifdef CONFIG_KGDB
- if (info->kgdb_channel) {
-#ifdef SERIAL_DEBUG_POWER
- printk(KERN_INFO " (canceled by KGDB)\n");
-#endif
- return 0;
- }
-#endif
-#ifdef CONFIG_XMON
- if (!info->is_cobalt_modem) {
-#ifdef SERIAL_DEBUG_POWER
- printk(KERN_INFO " (canceled by XMON)\n");
-#endif
- return 0;
- }
-#endif
+ PWRDBG("ttyS%02d: shutting down hardware\n", info->line);
if (info->is_cobalt_modem) {
-#ifdef SERIAL_DEBUG_POWER
- printk(KERN_INFO "ttyS%02d: shutting down modem\n", info->line);
-#endif
- feature_set(info->dev_node, FEATURE_Modem_Reset);
- mdelay(15);
- feature_clear(info->dev_node, FEATURE_Modem_Reset);
- mdelay(25);
+ PWRDBG("ttyS%02d: shutting down modem\n", info->line);
+ feature_clear(info->dev_node, FEATURE_Modem_power);
+ mdelay(10);
}
#ifdef CONFIG_PMAC_PBOOK
- if (info->is_pwbk_ir)
+ if (info->is_irda)
pmu_enable_irled(0);
#endif /* CONFIG_PMAC_PBOOK */
-
- if (info->zs_chan_a == info->zs_channel) {
-#ifdef SERIAL_DEBUG_POWER
- printk(KERN_INFO "ttyS%02d: shutting down SCC channel A\n", info->line);
-#endif
+
+ if (info->zs_chan_a == info->zs_channel && !info->is_irda) {
+ PWRDBG("ttyS%02d: shutting down SCC channel A\n", info->line);
feature_clear(info->dev_node, FEATURE_Serial_IO_A);
- } else {
-#ifdef SERIAL_DEBUG_POWER
- printk(KERN_INFO "ttyS%02d: shutting down SCC channel B\n", info->line);
-#endif
+ } else if (!info->is_irda) {
+ PWRDBG("ttyS%02d: shutting down SCC channel B\n", info->line);
feature_clear(info->dev_node, FEATURE_Serial_IO_B);
}
/* XXX for now, shut down SCC core only on powerbooks */
if (is_powerbook
&& !(feature_test(info->dev_node, FEATURE_Serial_IO_A) ||
feature_test(info->dev_node, FEATURE_Serial_IO_B))) {
-#ifdef SERIAL_DEBUG_POWER
- printk(KERN_INFO "ttyS%02d: shutting down SCC core\n", info->line);
-#endif
+ PWRDBG("ttyS%02d: shutting down SCC core\n", info->line);
feature_set(info->dev_node, FEATURE_Serial_reset);
- mdelay(10);
+ mdelay(15);
+ feature_clear(info->dev_node, FEATURE_Serial_reset);
+ mdelay(25);
feature_clear(info->dev_node, FEATURE_Serial_enable);
mdelay(5);
}
return delay;
}
+static void irda_rts_pulses(struct mac_serial *info, int w)
+{
+ unsigned long flags;
+
+ udelay(w);
+ save_flags(flags); cli();
+ write_zsreg(info->zs_channel, 5, Tx8 | TxENAB);
+ udelay(2);
+ write_zsreg(info->zs_channel, 5, Tx8 | TxENAB | RTS);
+ udelay(8);
+ write_zsreg(info->zs_channel, 5, Tx8 | TxENAB);
+ udelay(4);
+ write_zsreg(info->zs_channel, 5, Tx8 | TxENAB | RTS);
+ restore_flags(flags);
+}
+
+/*
+ * Set the irda codec on the imac to the specified baud rate.
+ */
+static void irda_setup(struct mac_serial *info)
+{
+ int code, speed, t;
+ unsigned long flags;
+
+ speed = info->tty->termios->c_cflag & CBAUD;
+ if (speed < B2400 || speed > B115200)
+ return;
+ code = 0x4d + B115200 - speed;
+
+ /* disable serial interrupts and receive DMA */
+ write_zsreg(info->zs_channel, 1, info->curregs[1] & ~0x9f);
+
+ /* wait for transmitter to drain */
+ t = 10000;
+ while ((read_zsreg(info->zs_channel, 0) & Tx_BUF_EMP) == 0
+ || (read_zsreg(info->zs_channel, 1) & ALL_SNT) == 0) {
+ if (--t <= 0) {
+ printk(KERN_ERR "transmitter didn't drain\n");
+ return;
+ }
+ udelay(10);
+ }
+ udelay(100);
+
+ /* set to 8 bits, no parity, 19200 baud, RTS on, DTR off */
+ write_zsreg(info->zs_channel, 4, X16CLK | SB1);
+ write_zsreg(info->zs_channel, 11, TCBR | RCBR);
+ t = BPS_TO_BRG(19200, ZS_CLOCK/16);
+ write_zsreg(info->zs_channel, 12, t);
+ write_zsreg(info->zs_channel, 13, t >> 8);
+ write_zsreg(info->zs_channel, 14, BRENABL);
+ write_zsreg(info->zs_channel, 3, Rx8 | RxENABLE);
+ write_zsreg(info->zs_channel, 5, Tx8 | TxENAB | RTS);
+
+ /* set TxD low for ~104us and pulse RTS */
+ udelay(1000);
+ save_flags(flags); cli();
+ write_zsdata(info->zs_channel, 0xfe);
+ irda_rts_pulses(info, 150);
+ restore_flags(flags);
+ irda_rts_pulses(info, 180);
+ irda_rts_pulses(info, 50);
+ udelay(100);
+
+ /* assert DTR, wait 30ms, talk to the chip */
+ write_zsreg(info->zs_channel, 5, Tx8 | TxENAB | RTS | DTR);
+ udelay(30000);
+ while (read_zsreg(info->zs_channel, 0) & Rx_CH_AV)
+ read_zsdata(info->zs_channel);
+
+ write_zsdata(info->zs_channel, 1);
+ t = 1000;
+ while ((read_zsreg(info->zs_channel, 0) & Rx_CH_AV) == 0) {
+ if (--t <= 0) {
+ printk(KERN_ERR "irda_setup timed out on 1st byte\n");
+ goto out;
+ }
+ udelay(10);
+ }
+ t = read_zsdata(info->zs_channel);
+ if (t != 4)
+ printk(KERN_ERR "irda_setup 1st byte = %x\n", t);
+
+ write_zsdata(info->zs_channel, code);
+ t = 1000;
+ while ((read_zsreg(info->zs_channel, 0) & Rx_CH_AV) == 0) {
+ if (--t <= 0) {
+ printk(KERN_ERR "irda_setup timed out on 2nd byte\n");
+ goto out;
+ }
+ udelay(10);
+ }
+ t = read_zsdata(info->zs_channel);
+ if (t != code)
+ printk(KERN_ERR "irda_setup 2nd byte = %x (%x)\n", t, code);
+
+ /* Drop DTR again and do some more RTS pulses */
+ out:
+ udelay(100);
+ write_zsreg(info->zs_channel, 5, Tx8 | TxENAB | RTS);
+ irda_rts_pulses(info, 80);
+
+ /* We should be right to go now. We assume that load_zsregs
+ will get called soon to load up the correct baud rate etc. */
+ info->curregs[5] = (info->curregs[5] | RTS) & ~DTR;
+ info->pendregs[5] = info->curregs[5];
+}
/*
* This routine is called to set the UART divisor registers to match
*/
static void change_speed(struct mac_serial *info, struct termios *old_termios)
{
- unsigned short port;
unsigned cflag;
int bits;
int brg, baud;
if (!info->tty || !info->tty->termios)
return;
- if (!(port = info->port))
- return;
cflag = info->tty->termios->c_cflag;
baud = tty_get_baud_rate(info->tty);
info->zs_baud = baud;
info->clk_divisor = 16;
-#ifdef SERIAL_DEBUG_BAUDS
- printk("set speed to %d bds, ", baud);
-#endif
+ BAUDBG("set speed to %d bds, ", baud);
switch (baud) {
case ZS_CLOCK/16: /* 230400 */
case CS5:
info->curregs[3] |= Rx5;
info->curregs[5] |= Tx5;
-#ifdef SERIAL_DEBUG_BAUDS
- printk("5 bits, ");
-#endif
+ BAUDBG("5 bits, ");
bits = 7;
break;
case CS6:
info->curregs[3] |= Rx6;
info->curregs[5] |= Tx6;
-#ifdef SERIAL_DEBUG_BAUDS
- printk("6 bits, ");
-#endif
+ BAUDBG("6 bits, ");
bits = 8;
break;
case CS7:
info->curregs[3] |= Rx7;
info->curregs[5] |= Tx7;
-#ifdef SERIAL_DEBUG_BAUDS
- printk("7 bits, ");
-#endif
+ BAUDBG("7 bits, ");
bits = 9;
break;
case CS8:
default: /* defaults to 8 bits */
info->curregs[3] |= Rx8;
info->curregs[5] |= Tx8;
-#ifdef SERIAL_DEBUG_BAUDS
- printk("8 bits, ");
-#endif
+ BAUDBG("8 bits, ");
bits = 10;
break;
}
if (cflag & CSTOPB) {
info->curregs[4] |= SB2;
bits++;
-#ifdef SERIAL_DEBUG_BAUDS
- printk("2 stop, ");
-#endif
+ BAUDBG("2 stop, ");
} else {
info->curregs[4] |= SB1;
-#ifdef SERIAL_DEBUG_BAUDS
- printk("1 stop, ");
-#endif
+ BAUDBG("1 stop, ");
}
if (cflag & PARENB) {
bits++;
info->curregs[4] |= PAR_ENA;
-#ifdef SERIAL_DEBUG_BAUDS
- printk("parity, ");
-#endif
+ BAUDBG("parity, ");
}
if (!(cflag & PARODD)) {
info->curregs[4] |= PAR_EVEN;
info->timeout = ((info->xmit_fifo_size*HZ*bits) / baud);
info->timeout += HZ/50+1; /* Add .02 seconds of slop */
-#ifdef SERIAL_DEBUG_BAUDS
- printk("timeout=%d/%ds, base:%d\n", (int)info->timeout, (int)HZ, (int)info->baud_base);
-#endif
+ BAUDBG("timeout=%d/%ds, base:%d\n", (int)info->timeout, (int)HZ,
+ (int)info->baud_base);
+
+ /* set the irda codec to the right rate */
+ if (info->is_irda)
+ irda_setup(info);
/* Load up the new values */
load_zsregs(info->zs_channel, info->curregs);
} else {
while (1) {
save_flags(flags);
- cli();
+ cli();
c = MIN(count,
MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
SERIAL_XMIT_SIZE - info->xmit_head));
{
struct mac_serial *info = (struct mac_serial *)tty->driver_data;
int ret;
-
+
if (serial_paranoia_check(info, tty->device, "rs_write_room"))
return 0;
ret = SERIAL_XMIT_SIZE - info->xmit_cnt - 1;
static int rs_chars_in_buffer(struct tty_struct *tty)
{
struct mac_serial *info = (struct mac_serial *)tty->driver_data;
-
+
if (serial_paranoia_check(info, tty->device, "rs_chars_in_buffer"))
return 0;
return info->xmit_cnt;
{
struct mac_serial *info = (struct mac_serial *)tty->driver_data;
unsigned long flags;
-
+
if (serial_paranoia_check(info, tty->device, "rs_flush_buffer"))
return;
save_flags(flags); cli();
struct mac_serial *info = (struct mac_serial *)tty->driver_data;
unsigned long flags;
#ifdef SERIAL_DEBUG_THROTTLE
-
+
printk("throttle %ld....\n",tty->ldisc.chars_in_buffer(tty));
#endif
if (serial_paranoia_check(info, tty->device, "rs_throttle"))
return;
-
+
if (I_IXOFF(tty)) {
save_flags(flags); cli();
info->x_char = STOP_CHAR(tty);
struct mac_serial *info = (struct mac_serial *)tty->driver_data;
unsigned long flags;
#ifdef SERIAL_DEBUG_THROTTLE
-
+
printk("unthrottle %s: %d....\n",tty->ldisc.chars_in_buffer(tty));
#endif
if (serial_paranoia_check(info, tty->device, "rs_unthrottle"))
return;
-
+
if (I_IXOFF(tty)) {
save_flags(flags); cli();
if (info->x_char)
if (serial_paranoia_check(info, tty->device, "rs_break"))
return;
- if (!info->port)
- return;
save_flags(flags); cli();
if (break_state == -1)
if (tty->flags & (1 << TTY_IO_ERROR))
return -EIO;
}
-
+
switch (cmd) {
case TIOCMGET:
return get_modem_info(info, (unsigned int *) arg);
info, sizeof(struct mac_serial)))
return -EFAULT;
return 0;
-
+
default:
return -ENOIOCTLCMD;
}
if (!info || serial_paranoia_check(info, tty->device, "rs_close"))
return;
-
+
save_flags(flags); cli();
-
+
if (tty_hung_up_p(filp)) {
MOD_DEC_USE_COUNT;
restore_flags(flags);
return;
}
-
-#ifdef SERIAL_DEBUG_OPEN
- printk("rs_close ttys%d, count = %d\n", info->line, info->count);
-#endif
+
+ OPNDBG("rs_close ttys%d, count = %d\n", info->line, info->count);
if ((tty->count == 1) && (info->count != 1)) {
/*
* Uh, oh. tty->count is 1, which means that the tty
* Now we wait for the transmit buffer to clear; and we notify
* the line discipline to only process XON/XOFF characters.
*/
-#ifdef SERIAL_DEBUG_OPEN
- printk("waiting end of Tx... (timeout:%d)\n", info->closing_wait);
-#endif
+ OPNDBG("waiting end of Tx... (timeout:%d)\n", info->closing_wait);
tty->closing = 1;
if (info->closing_wait != ZILOG_CLOSING_WAIT_NONE) {
restore_flags(flags);
* Before we drop DTR, make sure the SCC transmitter
* has completely drained.
*/
-#ifdef SERIAL_DEBUG_OPEN
- printk("waiting end of Rx...\n");
-#endif
+ OPNDBG("waiting end of Rx...\n");
restore_flags(flags);
rs_wait_until_sent(tty, info->timeout);
save_flags(flags); cli();
info->flags |= ZILOG_CALLOUT_ACTIVE;
return 0;
}
-
+
/*
* If non-blocking mode is set, or the port is not enabled,
* then make the check up front and then exit.
if (tty->termios->c_cflag & CLOCAL)
do_clocal = 1;
}
-
+
/*
* Block waiting for the carrier detect and the line to become
* free (i.e., not in use by the callout). While we are in
*/
retval = 0;
add_wait_queue(&info->open_wait, &wait);
-#ifdef SERIAL_DEBUG_OPEN
- printk("block_til_ready before block: ttys%d, count = %d\n",
+ OPNDBG("block_til_ready before block: ttys%d, count = %d\n",
info->line, info->count);
-#endif
cli();
if (!tty_hung_up_p(filp))
info->count--;
while (1) {
cli();
if (!(info->flags & ZILOG_CALLOUT_ACTIVE) &&
- (tty->termios->c_cflag & CBAUD))
+ (tty->termios->c_cflag & CBAUD) &&
+ !info->is_irda)
zs_rtsdtr(info, 1);
sti();
current->state = TASK_INTERRUPTIBLE;
if (info->flags & ZILOG_HUP_NOTIFY)
retval = -EAGAIN;
else
- retval = -ERESTARTSYS;
+ retval = -ERESTARTSYS;
#else
retval = -EAGAIN;
#endif
retval = -ERESTARTSYS;
break;
}
-#ifdef SERIAL_DEBUG_OPEN
- printk("block_til_ready blocking: ttys%d, count = %d\n",
+ OPNDBG("block_til_ready blocking: ttys%d, count = %d\n",
info->line, info->count);
-#endif
schedule();
}
current->state = TASK_RUNNING;
if (!tty_hung_up_p(filp))
info->count++;
info->blocked_open--;
-#ifdef SERIAL_DEBUG_OPEN
- printk("block_til_ready after blocking: ttys%d, count = %d\n",
+ OPNDBG("block_til_ready after blocking: ttys%d, count = %d\n",
info->line, info->count);
-#endif
if (retval)
return retval;
info->flags |= ZILOG_NORMAL_ACTIVE;
return 0;
-}
+}
/*
* This routine is called whenever a serial port is opened. It
#endif
if (serial_paranoia_check(info, tty->device, "rs_open"))
return -ENODEV;
-#ifdef SERIAL_DEBUG_OPEN
- printk("rs_open %s%d, count = %d\n", tty->driver.name, info->line,
+ OPNDBG("rs_open %s%d, count = %d\n", tty->driver.name, info->line,
info->count);
-#endif
info->count++;
tty->driver_data = info;
retval = block_til_ready(tty, filp, info);
if (retval) {
-#ifdef SERIAL_DEBUG_OPEN
- printk("rs_open returning after block_til_ready with %d\n",
+ OPNDBG("rs_open returning after block_til_ready with %d\n",
retval);
-#endif
return retval;
}
info->session = current->session;
info->pgrp = current->pgrp;
-#ifdef SERIAL_DEBUG_OPEN
- printk("rs_open ttys%d successful...\n", info->line);
-#endif
+ OPNDBG("rs_open ttys%d successful...\n", info->line);
return 0;
}
struct device_node *ch = zss->dev_node;
char *conn;
int len;
+ struct slot_names_prop {
+ int count;
+ char name[1];
+ } *slots;
zss->irq = ch->intrs[0].line;
zss->has_dma = 0;
/* XXX tested only with wallstreet PowerBook,
should do no harm anyway */
conn = get_property(ch, "AAPL,connector", &len);
- zss->is_pwbk_ir = conn && (strcmp(conn, "infrared") == 0);
+ zss->is_irda = conn && (strcmp(conn, "infrared") == 0);
+ /* 1999 Powerbook G3 has slot-names property instead */
+ slots = (struct slot_names_prop *)get_property(ch, "slot-names", &len);
+ if (slots && slots->count > 0 && strcmp(slots->name, "IrDA") == 0)
+ zss->is_irda = 1;
if (zss->has_dma) {
zss->dma_priv = NULL;
zs_soft[channel].clk_divisor = 16;
/* -- we are not sure the SCC is powered ON at this point
zs_soft[channel].zs_baud = get_zsbaud(&zs_soft[channel]);
-*/
+*/
zs_soft[channel].zs_baud = 38400;
/* If console serial line, then enable interrupts. */
printk(", port = %s", connector);
if (info->is_cobalt_modem)
printk(" (cobalt modem)");
- if (info->is_pwbk_ir)
- printk(" (powerbook IR)");
+ if (info->is_irda)
+ printk(" (IrDA)");
printk("\n");
+#ifndef CONFIG_XMON
#ifdef CONFIG_KGDB
- if (info->kgdb_channel)
- continue;
-#endif
-#ifdef CONFIG_XMON
- if (!info->is_cobalt_modem)
- continue;
-#endif
- /* By default, disable the port */
- set_scc_power(info, 0);
+ if (!info->kgdb_channel)
+#endif /* CONFIG_KGDB */
+ /* By default, disable the port */
+ set_scc_power(info, 0);
+#endif /* CONFIG_XMON */
}
tmp_buf = 0;
while ((read_zsreg(info->zs_channel, 0) & Tx_BUF_EMP)
== 0)
eieio();
-
+
write_zsdata(info->zs_channel, 13);
}
}
probe_sccs();
set_scc_power(&zs_soft[tty_num], 1);
-
+
zs_kgdbchan = zs_soft[tty_num].zs_channel;
zs_soft[tty_num].change_needed = 0;
zs_soft[tty_num].clk_divisor = 16;
serial_notify_sleep(struct pmu_sleep_notifier *self, int when)
{
int i;
-
+
switch (when) {
case PBOOK_SLEEP_REQUEST:
case PBOOK_SLEEP_REJECT:
break;
-
+
case PBOOK_SLEEP_NOW:
for (i=0; i<zs_channels_found; i++) {
struct mac_serial *info = &zs_soft[i];
char kgdb_channel; /* Kgdb is running on this channel */
char is_cons; /* Is this our console. */
char is_cobalt_modem; /* is a gatwick-based cobalt modem */
- char is_pwbk_ir; /* is connected to an IR led on powerbooks */
+ char is_irda; /* is connected to an IrDA codec */
unsigned char tx_active; /* character is being xmitted */
unsigned char tx_stopped; /* output is suspended */
*
* Copyright (C) 1998 Paul Mackerras.
*
+ * Various evolutions by Benjamin Herrenschmidt & Henry Worth
+ *
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
#endif
#undef MB_USE_INTERRUPTS
+#undef MB_DEBUG
+#define MB_IGNORE_SIGNALS
+
+#ifdef MB_DEBUG
+#define MBDBG(fmt, arg...) printk(KERN_INFO fmt , ## arg)
+#else
+#define MBDBG(fmt, arg...) do { } while (0)
+#endif
struct media_bay_hw {
unsigned char b0;
struct media_bay_info {
volatile struct media_bay_hw* addr;
+ volatile u8* extint_gpio;
int content_id;
- int previous_id;
- int ready;
+ int state;
int last_value;
int value_count;
- int reset_timer;
+ int timer;
struct device_node* dev_node;
+ int pismo; /* New PowerBook3,1 */
+ int gpio_cache;
#ifdef CONFIG_BLK_DEV_IDE
unsigned long cd_base;
int cd_index;
int cd_irq;
- int cd_timer;
+ int cd_retry;
#endif
};
static volatile struct media_bay_info media_bays[MAX_BAYS];
int media_bay_count = 0;
-#define MB_CONTENTS(i) ((in_8(&media_bays[i].addr->contents) >> 4) & 7)
+inline int mb_content(volatile struct media_bay_info *bay)
+{
+ if (bay->pismo) {
+ unsigned char new_gpio = in_8(bay->extint_gpio + 0xe) & 2;
+ if (new_gpio) {
+ bay->gpio_cache = new_gpio;
+ return MB_NO;
+ } else if (bay->gpio_cache != new_gpio) {
+ /* make sure content bits are set */
+ feature_set(bay->dev_node, FEATURE_Mediabay_content);
+ udelay(5);
+ bay->gpio_cache = new_gpio;
+ }
+ return (in_le32((unsigned*)bay->addr) >> 4) & 0xf;
+ } else {
+ int cont = (in_8(&bay->addr->contents) >> 4) & 7;
+ return (cont == 7) ? MB_NO : cont;
+ }
+}
#ifdef CONFIG_BLK_DEV_IDE
/* check the busy bit in the media-bay ide interface
(assumes the media-bay contains an ide device) */
+//#define MB_IDE_READY(i) ((inb(media_bays[i].cd_base + 0x70) & 0xc0) == 0x40)
#define MB_IDE_READY(i) ((inb(media_bays[i].cd_base + 0x70) & 0x80) == 0)
#endif
+/* Note: All delays are not in milliseconds and converted to HZ relative
+ * values by the macro below
+ */
+#define MS_TO_HZ(ms) ((ms * HZ) / 1000)
+
/*
* Consider the media-bay ID value stable if it is the same for
- * this many consecutive samples (at intervals of 1/HZ seconds).
+ * this number of milliseconds
+ */
+#define MB_STABLE_DELAY 40
+
+/* Wait after powering up the media bay this delay in ms
+ * timeout bumped for some powerbooks
*/
-#define MB_STABLE_COUNT 4
+#define MB_POWER_DELAY 200
/*
* Hold the media-bay reset signal true for this many ticks
* after a device is inserted before releasing it.
*/
-#define MB_RESET_COUNT 40
+#define MB_RESET_DELAY 40
+
+/*
+ * Wait this long after the reset signal is released and before doing
+ * further operations. After this delay, the IDE reset signal is released
+ * too for an IDE device
+ */
+#define MB_SETUP_DELAY 100
/*
* Wait this many ticks after an IDE device (e.g. CD-ROM) is inserted
- * (or until the device is ready) before registering the IDE interface.
+ * (or until the device is ready) before waiting for busy bit to disappear
+ */
+#define MB_IDE_WAIT 1000
+
+/*
+ * Timeout waiting for busy bit of an IDE device to go down
+ */
+#define MB_IDE_TIMEOUT 5000
+
+/*
+ * Max retries of the full power up/down sequence for an IDE device
*/
-#define MB_IDE_WAIT 1500
+#define MAX_CD_RETRIES 3
/*
- * Wait at least this many ticks after resetting an IDE device before
- * believing its ready bit.
+ * States of a media bay
*/
-#define MB_IDE_MINWAIT 250
+enum {
+ mb_empty = 0, /* Idle */
+ mb_powering_up, /* power bit set, waiting MB_POWER_DELAY */
+ mb_enabling_bay, /* enable bits set, waiting MB_RESET_DELAY */
+ mb_resetting, /* reset bit unset, waiting MB_SETUP_DELAY */
+ mb_ide_resetting, /* IDE reset bit unser, waiting MB_IDE_WAIT */
+ mb_ide_waiting, /* Waiting for BUSY bit to go away until MB_IDE_TIMEOUT */
+ mb_up, /* Media bay full */
+ mb_powering_down /* Powering down (avoid too fast down/up) */
+};
static void poll_media_bay(int which);
static void set_media_bay(int which, int id);
+static void set_mb_power(int which, int onoff);
+static void media_bay_step(int i);
static int media_bay_task(void *);
+#ifdef MB_USE_INTERRUPTS
+static void media_bay_intr(int irq, void *devid, struct pt_regs *regs);
+#endif
+
/*
* It seems that the bit for the media-bay interrupt in the IRQ_LEVEL
* register is always set when there is something in the media bay.
{
struct device_node *np;
int n,i;
-
- for (i=0; i<MAX_BAYS; i++)
- {
+
+ for (i=0; i<MAX_BAYS; i++) {
memset((char *)&media_bays[i], 0, sizeof(struct media_bay_info));
media_bays[i].content_id = -1;
#ifdef CONFIG_BLK_DEV_IDE
media_bays[i].cd_index = -1;
#endif
}
-
+
np = find_devices("media-bay");
n = 0;
- while(np && (n<MAX_BAYS))
- {
+ while(np && (n<MAX_BAYS)) {
if (np->n_addrs == 0)
continue;
media_bays[n].addr = (volatile struct media_bay_hw *)
ioremap(np->addrs[0].address, sizeof(struct media_bay_hw));
+ media_bays[n].pismo = device_is_compatible(np, "keylargo-media-bay");
+ if (media_bays[n].pismo) {
+ if (!np->parent || strcmp(np->parent->name, "mac-io")) {
+ printk(KERN_ERR "Pismo media-bay has no mac-io parent !\n");
+ continue;
+ }
+ media_bays[n].extint_gpio = ioremap(np->parent->addrs[0].address
+ + 0x58, 0x10);
+ }
+
#ifdef MB_USE_INTERRUPTS
- if (np->n_intrs == 0)
- {
+ if (np->n_intrs == 0) {
printk(KERN_ERR "media bay %d has no irq\n",n);
continue;
}
-
- if (request_irq(np_intrs[0].line, media_bay_intr, 0, "Media bay", NULL))
- {
- printk(KERN_ERR "Couldn't get IRQ %d for media bay %d\n", irq, n);
+
+ if (request_irq(np->intrs[0].line, media_bay_intr, 0, "Media bay", (void *)n)) {
+ printk(KERN_ERR "Couldn't get IRQ %d for media bay %d\n",
+ np->intrs[0].line, n);
continue;
}
-#endif
+#endif
media_bay_count++;
-
- set_media_bay(n, MB_CONTENTS(n));
- if (media_bays[n].content_id != MB_NO) {
- feature_clear(media_bays[n].dev_node, FEATURE_Mediabay_reset);
- udelay(500);
- }
- media_bays[n].ready = 1;
- media_bays[n].previous_id = media_bays[n].content_id;
- media_bays[n].reset_timer = 0;
+
media_bays[n].dev_node = np;
-#ifdef CONFIG_BLK_DEV_IDE
- media_bays[n].cd_timer = 0;
-#endif
+
+ /* Force an immediate detect */
+ set_mb_power(n,0);
+ mdelay(MB_POWER_DELAY);
+ if(!media_bays[n].pismo)
+ out_8(&media_bays[n].addr->contents, 0x70);
+ mdelay(MB_STABLE_DELAY);
+ media_bays[n].content_id = MB_NO;
+ media_bays[n].last_value = mb_content(&media_bays[n]);
+ media_bays[n].value_count = MS_TO_HZ(MB_STABLE_DELAY);
+ media_bays[n].state = mb_empty;
+ do {
+ mdelay(1000/HZ);
+ media_bay_step(n);
+ } while((media_bays[n].state != mb_empty) &&
+ (media_bays[n].state != mb_up));
+
n++;
np=np->next;
}
-
+
if (media_bay_count)
{
printk(KERN_INFO "Registered %d media-bay(s)\n", media_bay_count);
pmu_register_sleep_notifier(&mb_sleep_notifier);
#endif /* CONFIG_PMAC_PBOOK */
- kernel_thread(media_bay_task, NULL, 0);
+ kernel_thread(media_bay_task, NULL,
+ CLONE_FS | CLONE_FILES | CLONE_SIGHAND);
}
}
-#if 0
+#ifdef MB_USE_INTERRUPTS
static void
media_bay_intr(int irq, void *devid, struct pt_regs *regs)
{
- int id = MB_CONTENTS();
-
- if (id == MB_NO)
- set_media_bay(id);
}
#endif
+static void
+set_mb_power(int which, int onoff)
+{
+ volatile struct media_bay_info* mb = &media_bays[which];
+
+ if (onoff) {
+ feature_set(mb->dev_node, FEATURE_Mediabay_power);
+ udelay(10);
+ feature_set(mb->dev_node, FEATURE_Mediabay_reset);
+ udelay(10);
+ mb->state = mb_powering_up;
+ MBDBG("mediabay%d: powering up\n", which);
+ } else {
+ feature_clear(mb->dev_node, FEATURE_Mediabay_floppy_enable);
+ if (mb->pismo)
+ feature_clear(mb->dev_node, FEATURE_IDE0_enable);
+ else
+ feature_clear(mb->dev_node, FEATURE_IDE1_enable);
+ feature_clear(mb->dev_node, FEATURE_Mediabay_IDE_switch);
+ feature_clear(mb->dev_node, FEATURE_Mediabay_PCI_enable);
+ feature_clear(mb->dev_node, FEATURE_SWIM3_enable);
+ feature_clear(mb->dev_node, FEATURE_Mediabay_power);
+ mb->state = mb_powering_down;
+ MBDBG("mediabay%d: powering down\n", which);
+ }
+ mb->timer = MS_TO_HZ(MB_POWER_DELAY);
+}
+
+static void
+set_media_bay(int which, int id)
+{
+ volatile struct media_bay_info* bay;
+
+ bay = &media_bays[which];
+
+ switch (id) {
+ case MB_CD:
+ if (bay->pismo) {
+ feature_set(bay->dev_node, FEATURE_Mediabay_IDE_switch);
+ udelay(10);
+ feature_set(bay->dev_node, FEATURE_IDE0_enable);
+ udelay(10);
+ feature_set(bay->dev_node, FEATURE_IDE0_reset);
+ } else {
+ feature_set(bay->dev_node, FEATURE_IDE1_enable);
+ udelay(10);
+ feature_set(bay->dev_node, FEATURE_IDE1_reset);
+ }
+ printk(KERN_INFO "media bay %d contains a CD-ROM drive\n", which);
+ break;
+ case MB_FD:
+ case MB_FD1:
+ feature_set(bay->dev_node, FEATURE_Mediabay_floppy_enable);
+ feature_set(bay->dev_node, FEATURE_SWIM3_enable);
+ printk(KERN_INFO "media bay %d contains a floppy disk drive\n", which);
+ break;
+ case MB_NO:
+ break;
+ default:
+ printk(KERN_INFO "media bay %d contains an unknown device (%d)\n",
+ which, id);
+ break;
+ }
+}
+
int
check_media_bay(struct device_node *which_bay, int what)
{
for (i=0; i<media_bay_count; i++)
if (which_bay == media_bays[i].dev_node)
{
- if ((what == media_bays[i].content_id) && media_bays[i].ready)
+ if ((what == media_bays[i].content_id) && media_bays[i].state == mb_up)
return 0;
media_bays[i].cd_index = -1;
return -EINVAL;
for (i=0; i<media_bay_count; i++)
if (base == media_bays[i].cd_base)
{
- if ((what == media_bays[i].content_id) && media_bays[i].ready)
+ if ((what == media_bays[i].content_id) && media_bays[i].state == mb_up)
return 0;
media_bays[i].cd_index = -1;
return -EINVAL;
}
#endif
-
+
return -ENODEV;
}
for (i=0; i<media_bay_count; i++)
if (which_bay == media_bays[i].dev_node)
{
+ int timeout = 5000;
+
media_bays[i].cd_base = base;
media_bays[i].cd_irq = irq;
- media_bays[i].cd_index = index;
- printk(KERN_DEBUG "Registered ide %d for media bay %d\n", index, i);
- return 0;
+
+ if ((MB_CD != media_bays[i].content_id) || media_bays[i].state != mb_up)
+ return 0;
+
+ printk(KERN_DEBUG "Registered ide %d for media bay %d\n", index, i);
+ do {
+ if (MB_IDE_READY(i)) {
+ media_bays[i].cd_index = index;
+ return 0;
+ }
+ mdelay(1);
+ } while(--timeout);
+ printk(KERN_DEBUG "Timeount waiting IDE in bay %d\n", i);
+ return -ENODEV;
}
#endif
-
+
return -ENODEV;
}
+static void
+media_bay_step(int i)
+{
+ volatile struct media_bay_info* bay = &media_bays[i];
+
+ /* We don't poll when powering down */
+ if (bay->state != mb_powering_down)
+ poll_media_bay(i);
+
+ /* If timer expired or polling IDE busy, run state machine */
+ if ((bay->state != mb_ide_waiting) && (bay->timer != 0) && ((--bay->timer) != 0))
+ return;
+
+ switch(bay->state) {
+ case mb_powering_up:
+ set_media_bay(i, bay->last_value);
+ bay->timer = MS_TO_HZ(MB_RESET_DELAY);
+ bay->state = mb_enabling_bay;
+ MBDBG("mediabay%d: enabling (kind:%d)\n", i, bay->content_id);
+ break;
+ case mb_enabling_bay:
+ feature_clear(bay->dev_node, FEATURE_Mediabay_reset);
+ bay->timer = MS_TO_HZ(MB_SETUP_DELAY);
+ bay->state = mb_resetting;
+ MBDBG("mediabay%d: waiting reset (kind:%d)\n", i, bay->content_id);
+ break;
+
+ case mb_resetting:
+ if (bay->content_id != MB_CD) {
+ MBDBG("mediabay%d: bay is up (kind:%d)\n", i, bay->content_id);
+ bay->state = mb_up;
+ break;
+ }
+#ifdef CONFIG_BLK_DEV_IDE
+ MBDBG("mediabay%d: waiting IDE reset (kind:%d)\n", i, bay->content_id);
+ if (bay->pismo)
+ feature_clear(bay->dev_node, FEATURE_IDE0_reset);
+ else
+ feature_clear(bay->dev_node, FEATURE_IDE1_reset);
+ bay->timer = MS_TO_HZ(MB_IDE_WAIT);
+ bay->state = mb_ide_resetting;
+#else
+ printk(KERN_DEBUG "media-bay %d is ide (not compiled in kernel)\n", i);
+ set_mb_power(i, 0);
+#endif // #ifdef CONFIG_BLK_DEV_IDE
+ break;
+
+#ifdef CONFIG_BLK_DEV_IDE
+ case mb_ide_resetting:
+ bay->timer = MS_TO_HZ(MB_IDE_TIMEOUT);
+ bay->state = mb_ide_waiting;
+ MBDBG("mediabay%d: waiting IDE ready (kind:%d)\n", i, bay->content_id);
+ break;
+
+ case mb_ide_waiting:
+ if (bay->cd_base == 0) {
+ bay->timer = 0;
+ bay->state = mb_up;
+ MBDBG("mediabay%d: up before IDE init\n", i);
+ break;
+ } else if (MB_IDE_READY(i)) {
+ bay->timer = 0;
+ bay->state = mb_up;
+ if (bay->cd_index < 0)
+ bay->cd_index = ide_register(bay->cd_base, 0, bay->cd_irq);
+ if (bay->cd_index == -1) {
+ /* We eventually do a retry */
+ bay->cd_retry++;
+ printk("IDE register error\n");
+ set_mb_power(i, 0);
+ } else {
+ printk(KERN_DEBUG "media-bay %d is ide %d\n", i, bay->cd_index);
+ MBDBG("mediabay %d IDE ready\n", i);
+ }
+ break;
+ }
+ if (bay->timer == 0) {
+ printk("\nIDE Timeout in bay %d !\n", i);
+ MBDBG("mediabay%d: nIDE Timeout !\n", i);
+ set_mb_power(i, 0);
+ }
+ break;
+#endif // #ifdef CONFIG_BLK_DEV_IDE
+
+ case mb_powering_down:
+ bay->state = mb_empty;
+#ifdef CONFIG_BLK_DEV_IDE
+ if (bay->cd_index >= 0) {
+ printk(KERN_DEBUG "Unregistering mb %d ide, index:%d\n", i,
+ bay->cd_index);
+ ide_unregister(bay->cd_index);
+ bay->cd_index = -1;
+ }
+ if (bay->cd_retry) {
+ if (bay->cd_retry > MAX_CD_RETRIES) {
+ /* Should add an error sound (sort of beep in dmasound) */
+ printk("\nmedia-bay %d, IDE device badly inserted or unrecognised\n", i);
+ } else {
+ /* Force a new power down/up sequence */
+ bay->content_id = MB_NO;
+ }
+ }
+#endif
+ MBDBG("mediabay%d: end of power down\n", i);
+ break;
+ }
+}
+
/*
* This procedure runs as a kernel thread to poll the media bay
* once each tick and register and unregister the IDE interface
int
media_bay_task(void *x)
{
- volatile struct media_bay_info* bay;
int i = 0;
-
+
strcpy(current->comm, "media-bay");
- for (;;)
- {
- bay = &media_bays[i];
- poll_media_bay(i);
- if (bay->content_id != bay->previous_id) {
- bay->reset_timer = (bay->content_id != MB_NO) ?
- MB_RESET_COUNT: 0;
- bay->ready = 0;
-#ifdef CONFIG_BLK_DEV_IDE
- bay->cd_timer = 0;
- if (bay->content_id != MB_CD && bay->cd_index >= 0) {
- printk(KERN_DEBUG "Unregistering mb %d ide, index:%d\n", i, bay->cd_index);
- ide_unregister(bay->cd_index);
- bay->cd_index = -1;
- }
+#ifdef MB_IGNORE_SIGNALS
+ sigfillset(¤t->blocked);
#endif
- } else if (bay->reset_timer) {
- if (--bay->reset_timer == 0) {
- feature_clear(bay->dev_node, FEATURE_Mediabay_reset);
- bay->ready = 1;
-#ifdef CONFIG_BLK_DEV_IDE
- bay->cd_timer = 0;
- if (bay->content_id == MB_CD && bay->cd_base != 0)
- bay->cd_timer = MB_IDE_WAIT;
-#endif
- }
-#ifdef CONFIG_BLK_DEV_IDE
- } else if (bay->cd_timer
- && (--bay->cd_timer == 0
- || (bay->cd_timer < MB_IDE_WAIT - MB_IDE_MINWAIT
- && MB_IDE_READY(i)))
- && bay->cd_index < 0) {
- bay->cd_timer = 0;
- printk(KERN_DEBUG "Registering IDE, base:0x%08lx, irq:%d\n", bay->cd_base, bay->cd_irq);
- printk("\n");
- bay->cd_index = ide_register(bay->cd_base, 0, bay->cd_irq);
- if (bay->cd_index == -1)
- printk("\nCD-ROM badly inserted. Remove it and try again !\n");
- else
- printk(KERN_DEBUG "media-bay %d is ide %d\n", i, bay->cd_index);
-#endif
- }
- bay->previous_id = bay->content_id;
- if (++i >= media_bay_count) {
- i = 0;
- current->state = TASK_INTERRUPTIBLE;
- schedule_timeout(1);
- if (signal_pending(current))
- return 0;
- }
+ for (;;) {
+ media_bay_step(i);
+
+ if (++i >= media_bay_count) {
+ i = 0;
+ current->state = TASK_INTERRUPTIBLE;
+ schedule_timeout(1);
+ if (signal_pending(current))
+ return 0;
+ }
}
}
void
poll_media_bay(int which)
{
- int id = MB_CONTENTS(which);
+ volatile struct media_bay_info* bay = &media_bays[which];
+ int id = mb_content(bay);
- if (id == media_bays[which].last_value) {
- if (id != media_bays[which].content_id
- && ++media_bays[which].value_count >= MB_STABLE_COUNT) {
+ if (id == bay->last_value) {
+ if (id != bay->content_id
+ && ++bay->value_count >= MS_TO_HZ(MB_STABLE_DELAY)) {
/* If the device type changes without going thru "MB_NO", we force
a pass by "MB_NO" to make sure things are properly reset */
- if ((id != MB_NO) && (media_bays[which].content_id != MB_NO)) {
- set_media_bay(which, MB_NO);
- udelay(500);
+ if ((id != MB_NO) && (bay->content_id != MB_NO)) {
+ id = MB_NO;
+ MBDBG("mediabay%d: forcing MB_NO\n", which);
+ }
+ MBDBG("mediabay%d: switching to %d\n", which, id);
+ set_mb_power(which, id != MB_NO);
+ bay->content_id = id;
+ if (id == MB_NO) {
+#ifdef CONFIG_BLK_DEV_IDE
+ bay->cd_retry = 0;
+#endif
+ printk(KERN_INFO "media bay %d is empty\n", which);
}
- set_media_bay(which, id);
}
} else {
- media_bays[which].last_value = id;
- media_bays[which].value_count = 0;
+ bay->last_value = id;
+ bay->value_count = 0;
}
}
-static void
-set_media_bay(int which, int id)
-{
- volatile struct media_bay_info* bay;
-
- bay = &media_bays[which];
-
- bay->content_id = id;
- bay->last_value = id;
-
- switch (id) {
- case MB_CD:
- feature_set(bay->dev_node, FEATURE_Mediabay_enable);
- feature_set(bay->dev_node, FEATURE_Mediabay_IDE_enable);
- udelay(500);
- feature_set(bay->dev_node, FEATURE_CD_power);
- printk(KERN_INFO "media bay %d contains a CD-ROM drive\n", which);
- break;
- case MB_FD:
- feature_set(bay->dev_node, FEATURE_Mediabay_enable);
- feature_set(bay->dev_node, FEATURE_Mediabay_floppy_enable);
- feature_set(bay->dev_node, FEATURE_SWIM3_enable);
- printk(KERN_INFO "media bay %d contains a floppy disk drive\n", which);
- break;
- case MB_NO:
- feature_clear(bay->dev_node, FEATURE_CD_power);
- feature_clear(bay->dev_node, FEATURE_Mediabay_enable);
- feature_clear(bay->dev_node, FEATURE_Mediabay_floppy_enable);
- feature_clear(bay->dev_node, FEATURE_Mediabay_IDE_enable);
- feature_clear(bay->dev_node, FEATURE_SWIM3_enable);
- feature_set(bay->dev_node, FEATURE_Mediabay_reset);
- printk(KERN_INFO "media bay %d is empty\n", which);
- break;
- default:
- feature_set(bay->dev_node, FEATURE_Mediabay_enable);
- printk(KERN_INFO "media bay %d contains an unknown device (%d)\n",
- which, id);
- break;
- }
-
- udelay(500);
-}
#ifdef CONFIG_PMAC_PBOOK
/*
{
volatile struct media_bay_info* bay;
int i;
-
+
switch (when) {
case PBOOK_SLEEP_REQUEST:
case PBOOK_SLEEP_REJECT:
break;
-
+
case PBOOK_SLEEP_NOW:
for (i=0; i<media_bay_count; i++) {
bay = &media_bays[i];
- feature_clear(bay->dev_node, FEATURE_Mediabay_enable);
- feature_clear(bay->dev_node, FEATURE_Mediabay_IDE_enable);
- feature_clear(bay->dev_node, FEATURE_SWIM3_enable);
- feature_clear(bay->dev_node, FEATURE_Mediabay_floppy_enable);
- feature_set(bay->dev_node, FEATURE_Mediabay_reset);
- feature_clear(bay->dev_node, FEATURE_CD_power);
- out_8(&media_bays[i].addr->contents, 0x70);
+ set_mb_power(i, 0);
+ mdelay(10);
+ feature_clear(bay->dev_node, FEATURE_IOBUS_enable);
}
break;
case PBOOK_WAKE:
for (i=0; i<media_bay_count; i++) {
bay = &media_bays[i];
- feature_set(bay->dev_node, FEATURE_Mediabay_enable);
- /* I suppose this is enough delay to stabilize MB_CONTENT ... */
- mdelay(10);
/* We re-enable the bay using it's previous content
- only if it did not change */
- if (MB_CONTENTS(i) != bay->content_id)
- continue;
- set_media_bay(i, bay->content_id);
- if (bay->content_id == MB_NO)
+ only if it did not change. Note those bozo timings,
+ they seem to help the 3400 get it right.
+ */
+ feature_set(bay->dev_node, FEATURE_IOBUS_enable);
+ mdelay(MB_STABLE_DELAY);
+ if (!bay->pismo)
+ out_8(&bay->addr->contents, 0x70);
+ mdelay(MB_STABLE_DELAY);
+ if (mb_content(bay) != bay->content_id)
continue;
- mdelay(400);
- /* Clear the bay reset */
- feature_clear(bay->dev_node, FEATURE_Mediabay_reset);
- /* This small delay makes sure the device has time
- to assert the BUSY bit (used by IDE sleep) */
- udelay(100);
- /* We reset the state machine timers in case we were
- in the middle of a wait loop */
- if (bay->reset_timer)
- bay->reset_timer = MB_RESET_COUNT;
-#ifdef CONFIG_BLK_DEV_IDE
- if (bay->cd_timer)
- bay->cd_timer = MB_IDE_WAIT;
-#endif
+ set_mb_power(i, 1);
+ bay->last_value = bay->content_id;
+ bay->value_count = MS_TO_HZ(MB_STABLE_DELAY);
+ bay->timer = MS_TO_HZ(MB_POWER_DELAY);
+ bay->cd_retry = 0;
+ do {
+ mdelay(1000/HZ);
+ media_bay_step(i);
+ } while((media_bays[i].state != mb_empty) &&
+ (media_bays[i].state != mb_up));
}
break;
}
#include <asm/pgtable.h>
#include <asm/system.h>
#include <asm/init.h>
+#include <asm/machdep.h>
static volatile unsigned char *via;
cuda_present(void)
{
return (adb_controller && (adb_controller->kind == ADB_VIACUDA) && via);
-}
\ No newline at end of file
+}
* and the RTC (real time clock) chip.
*
* Copyright (C) 1998 Paul Mackerras and Fabio Riccardi.
+ *
+ * todo: - Check this driver for smp safety (new Core99 motherboards).
+ * - Cleanup synchro between VIA interrupt and GPIO-based PMU
+ * interrupt.
+ *
+ *
*/
#include <stdarg.h>
#include <linux/config.h>
/* Misc minor number allocated for /dev/pmu */
#define PMU_MINOR 154
-static volatile unsigned char *via;
+static volatile unsigned char *via = 0;
/* VIA registers - spaced 0x200 bytes apart */
#define RS 0x200 /* skip between registers */
static unsigned char *reply_ptr;
static int data_index;
static int data_len;
-static int adb_int_pending;
+static volatile int adb_int_pending;
static int pmu_adb_flags;
static int adb_dev_map = 0;
static struct adb_request bright_req_1, bright_req_2, bright_req_3;
static struct device_node *vias;
static int pmu_kind = PMU_UNKNOWN;
static int pmu_fully_inited = 0;
+static int pmu_has_adb, pmu_has_backlight;
+static unsigned char *gpio_reg = NULL;
+static int gpio_irq;
int asleep;
-struct notifier_block *sleep_notifier_list;
static int init_pmu(void);
static int pmu_queue_request(struct adb_request *req);
static void pmu_handle_data(unsigned char *data, int len,
struct pt_regs *regs);
static void set_volume(int level);
+static void gpio1_interrupt(int irq, void *arg, struct pt_regs *regs);
#ifdef CONFIG_PMAC_PBOOK
static void pmu_pass_intr(unsigned char *data, int len);
#endif
"PowerBook 2400/3400/3500(G3)",
"PowerBook G3 Series",
"1999 PowerBook G3",
+ "Core99"
};
int __openfirmware
return 0;
if (vias->next != 0)
printk(KERN_WARNING "Warning: only using 1st via-pmu\n");
-
- feature_set(vias, FEATURE_VIA_enable);
-
#if 0
{ int i;
printk("\n"); }
#endif
- if (vias->n_addrs != 1 || vias->n_intrs != 1) {
+ if (vias->n_addrs < 1 || vias->n_intrs < 1) {
printk(KERN_ERR "via-pmu: %d addresses, %d interrupts!\n",
vias->n_addrs, vias->n_intrs);
if (vias->n_addrs < 1 || vias->n_intrs < 1)
return 0;
}
+ pmu_has_adb = 1;
+ pmu_has_backlight = 1;
+
if (vias->parent->name && ((strcmp(vias->parent->name, "ohare") == 0)
|| device_is_compatible(vias->parent, "ohare")))
pmu_kind = PMU_OHARE_BASED;
pmu_kind = PMU_PADDINGTON_BASED;
else if (device_is_compatible(vias->parent, "heathrow"))
pmu_kind = PMU_HEATHROW_BASED;
- else
+ else if (device_is_compatible(vias->parent, "Keylargo")) {
+ pmu_kind = PMU_KEYLARGO_BASED;
+ pmu_has_adb = (find_type_devices("adb") != NULL);
+ pmu_has_backlight = (find_type_devices("backlight") != NULL);
+ } else
pmu_kind = PMU_UNKNOWN;
via = (volatile unsigned char *) ioremap(vias->addrs->address, 0x2000);
out_8(&via[IER], IER_CLR | 0x7f); /* disable all intrs */
+ out_8(&via[IFR], 0x7f); /* clear IFR */
pmu_state = idle;
- if (!init_pmu())
+ if (!init_pmu()) {
via = NULL;
+ return 0;
+ }
adb_controller = &pmu_controller;
- if (via)
- printk(KERN_INFO "PMU driver initialized for %s\n",
- pbook_type[pmu_kind]);
+ printk(KERN_INFO "PMU driver initialized for %s\n",
+ pbook_type[pmu_kind]);
return via != 0;
}
return;
}
+ if (pmu_kind == PMU_KEYLARGO_BASED) {
+ struct device_node *gpio, *gpiop;
+
+ gpiop = find_devices("gpio");
+ if (gpiop && gpiop->n_addrs) {
+ gpio_reg = ioremap(gpiop->addrs->address, 0x10);
+ gpio = find_devices("extint-gpio1");
+ if (gpio && gpio->parent == gpiop && gpio->n_intrs) {
+ gpio_irq = gpio->intrs[0].line;
+ if (request_irq(gpio_irq, gpio1_interrupt, 0,
+ "GPIO1/ADB", (void *)0))
+ printk(KERN_ERR "pmu: can't get irq %d (GPIO1)\n",
+ gpio->intrs[0].line);
+ }
+ }
+ }
+
/* Enable interrupts */
out_8(&via[IER], IER_SET | SR_INT | CB1_INT);
pmu_fully_inited = 1;
-
+
/* Enable backlight */
pmu_enable_backlight(1);
}
{
int i, ret;
- if ((vias == NULL) || (!pmu_fully_inited))
- {
+ if ((vias == NULL) || (!pmu_fully_inited)) {
req->complete = 1;
return -ENXIO;
- }
+ }
ret = -EINVAL;
-
+
switch (req->data[0]) {
case PMU_PACKET:
for (i = 0; i < req->nbytes - 1; ++i)
}
break;
case ADB_PACKET:
+ if (!pmu_has_adb)
+ return -ENXIO;
for (i = req->nbytes - 1; i > 1; --i)
req->data[i+2] = req->data[i];
req->data[3] = req->nbytes - 2;
req->complete = 1;
return ret;
}
-
+
if (sync) {
while (!req->complete)
pmu_poll();
{
struct adb_request req;
- if ((vias == NULL) || (!pmu_fully_inited))
+ if ((vias == NULL) || (!pmu_fully_inited) || !pmu_has_adb)
return -ENXIO;
if (devs) {
pmu_adb_reset_bus(void)
{
struct adb_request req;
- long timeout;
int save_autopoll = adb_dev_map;
- if ((vias == NULL) || (!pmu_fully_inited))
+ if ((vias == NULL) || (!pmu_fully_inited) || !pmu_has_adb)
return -ENXIO;
/* anyone got a better idea?? */
req.done = NULL;
req.data[0] = PMU_ADB_CMD;
req.data[1] = 0;
- req.data[2] = 3; /* ADB_BUSRESET ??? */
+ req.data[2] = ADB_BUSRESET; /* 3 ??? */
req.data[3] = 0;
req.data[4] = 0;
req.reply_len = 0;
req.reply_expected = 1;
- if (pmu_queue_request(&req) != 0)
- {
+ if (pmu_queue_request(&req) != 0) {
printk(KERN_ERR "pmu_adb_reset_bus: pmu_queue_request failed\n");
return -EIO;
}
while (!req.complete)
pmu_poll();
- timeout = 100000;
- while (!req.complete) {
- if (--timeout < 0) {
- printk(KERN_ERR "pmu_adb_reset_bus (reset): no response from PMU\n");
- return -EIO;
- }
- udelay(10);
- pmu_poll();
- }
if (save_autopoll != 0)
pmu_adb_autopoll(save_autopoll);
-
+
return 0;
}
return 0;
}
+/* New PMU seems to be very sensitive to those timings, so we make sure
+ * PCI is flushed immediately */
static void __openfirmware
send_byte(int x)
{
out_8(&v[ACR], in_8(&v[ACR]) | SR_OUT | SR_EXT);
out_8(&v[SR], x);
out_8(&v[B], in_8(&v[B]) & ~TREQ); /* assert TREQ */
+ (void)in_8(&v[B]);
}
static void __openfirmware
out_8(&v[ACR], (in_8(&v[ACR]) & ~SR_OUT) | SR_EXT);
in_8(&v[SR]); /* resets SR */
- out_8(&v[B], in_8(&v[B]) & ~0x10);
+ out_8(&v[B], in_8(&v[B]) & ~TREQ);
+ (void)in_8(&v[B]);
}
-static int disable_poll;
+static volatile int disable_poll;
static void __openfirmware
pmu_start()
if (disable_poll)
return;
ie = _disable_interrupts();
- if (via[IFR] & (SR_INT | CB1_INT))
+ if ((via[IFR] & (SR_INT | CB1_INT)) ||
+ (gpio_reg && (in_8(gpio_reg + 0x9) & 0x02) == 0))
via_pmu_interrupt(0, 0, 0);
_enable_interrupts(ie);
}
{
int intr;
int nloop = 0;
+ unsigned long flags;
+ /* Currently, we use brute-force cli() for syncing with GPIO
+ * interrupt. I'll make this smarter later, along with some
+ * spinlocks for SMP */
+ save_flags(flags);cli();
++disable_poll;
while ((intr = in_8(&via[IFR])) != 0) {
if (++nloop > 1000) {
out_8(&via[IFR], intr);
}
}
+ if (gpio_reg && (in_8(gpio_reg + 0x9) & 0x02) == 0)
+ adb_int_pending = 1;
+
if (pmu_state == idle) {
if (adb_int_pending) {
pmu_state = intack;
}
}
--disable_poll;
+ restore_flags(flags);
}
+static void __openfirmware
+gpio1_interrupt(int irq, void *arg, struct pt_regs *regs)
+{
+ via_pmu_interrupt(0, 0, 0);
+ }
+
static void __openfirmware
pmu_sr_intr(struct pt_regs *regs)
{
out_8(&via[IFR], SR_INT);
return;
}
- if (via[B] & TACK)
+ /* This one seems to appear with PMU99. According to OF methods,
+ * the protocol didn't change...
+ */
+ if (via[B] & TACK) {
+ while ((in_8(&via[B]) & TACK) != 0)
+ ;
+#if 0
printk(KERN_ERR "PMU: sr_intr but ack still high! (%x)\n",
via[B]);
+#endif
+ }
/* reset TREQ and wait for TACK to go high */
out_8(&via[B], in_8(&via[B]) | TREQ);
{
struct adb_request req;
- if (vias == NULL)
+ if ((vias == NULL) || !pmu_has_backlight)
return;
-
+
/* first call: get current backlight value */
if (on && backlight_level < 0) {
switch (pmu_kind) {
printk(KERN_DEBUG "pmu: nvram returned bright: %d\n", backlight_level);
break;
case PMU_PADDINGTON_BASED:
+ case PMU_KEYLARGO_BASED:
/* the G3 PB 1999 has a backlight node
and chrp-structured nvram */
/* XXX should read macos's "blkt" property in nvram
{
int bright;
- if (vias == NULL)
+ if ((vias == NULL) || !pmu_has_backlight)
return ;
backlight_level = level;
struct adb_request req;
_disable_interrupts();
-
+
pmu_request(&req, NULL, 2, PMU_SET_INTR_MASK, PMU_INT_ADB |
PMU_INT_TICK );
while(!req.complete)
pmu_poll();
-
+
pmu_request(&req, NULL, 1, PMU_RESET);
while(!req.complete || (pmu_state != idle))
pmu_poll();
struct adb_request req;
_disable_interrupts();
-
+
pmu_request(&req, NULL, 2, PMU_SET_INTR_MASK, PMU_INT_ADB |
PMU_INT_TICK );
while(!req.complete)
int
pmu_present(void)
{
- return (adb_controller && (adb_controller->kind == ADB_VIAPMU) && vias);
+ return via != 0;
}
#ifdef CONFIG_PMAC_PBOOK
/* Sleep is broadcast last-to-first */
static int
-broadcast_sleep(int when, int can_cancel)
+broadcast_sleep(int when, int fallback)
{
int ret = PBOOK_SLEEP_OK;
struct list_head *list;
list = list->prev) {
current = list_entry(list, struct pmu_sleep_notifier, list);
ret = current->notifier_call(current, when);
- if (can_cancel && (ret != PBOOK_SLEEP_OK))
+ if (ret != PBOOK_SLEEP_OK) {
+ printk(KERN_DEBUG "sleep %d rejected by %p (%p)\n",
+ when, current, current->notifier_call);
+ for (; list != &sleep_notifiers; list = list->next) {
+ current = list_entry(list, struct pmu_sleep_notifier, list);
+ current->notifier_call(current, fallback);
+ }
return ret;
+ }
}
return ret;
}
ioremap(macio->addrs[0].address, 0x40);
/* Notify device drivers */
- ret = broadcast_sleep(PBOOK_SLEEP_REQUEST, 1);
+ ret = broadcast_sleep(PBOOK_SLEEP_REQUEST, PBOOK_SLEEP_REJECT);
if (ret != PBOOK_SLEEP_OK) {
- broadcast_sleep(PBOOK_SLEEP_REJECT, 0);
printk("pmu: sleep rejected\n");
return -EBUSY;
}
* vmalloc's are done before actual sleep of block drivers */
fsync_dev(0);
- broadcast_sleep(PBOOK_SLEEP_NOW, 0);
+ /* Sleep can fail now. May not be very robust but useful for debugging */
+ ret = broadcast_sleep(PBOOK_SLEEP_NOW, PBOOK_WAKE);
+ if (ret != PBOOK_SLEEP_OK) {
+ printk("pmu: sleep failed\n");
+ return -EBUSY;
+ }
/* Give the disks a little time to actually finish writing */
for (wait = jiffies + (HZ/4); time_before(jiffies, wait); )
/* Restore L2 cache */
if (save_l2cr)
_set_L2CR(save_l2cr | 0x200000); /* set invalidate bit */
-
+
/* reenable interrupts */
sleep_restore_intrs();
struct adb_request sleep_req;
/* Notify device drivers */
- ret = broadcast_sleep(PBOOK_SLEEP_REQUEST, 1);
+ ret = broadcast_sleep(PBOOK_SLEEP_REQUEST, PBOOK_SLEEP_REJECT);
if (ret != PBOOK_SLEEP_OK) {
- broadcast_sleep(PBOOK_SLEEP_REJECT, 0);
printk("pmu: sleep rejected\n");
return -EBUSY;
}
* vmalloc's are done before actual sleep of block drivers */
fsync_dev(0);
- broadcast_sleep(PBOOK_SLEEP_NOW, 0);
+ /* Sleep can fail now. May not be very robust but useful for debugging */
+ ret = broadcast_sleep(PBOOK_SLEEP_NOW, PBOOK_WAKE);
+ if (ret != PBOOK_SLEEP_OK) {
+ printk("pmu: sleep failed\n");
+ return -EBUSY;
+ }
/* Give the disks a little time to actually finish writing */
for (wait = jiffies + (HZ/4); time_before(jiffies, wait); )
error = powerbook_sleep_G3();
break;
default:
- error = ENOSYS;
+ error = -ENOSYS;
}
return error;
case PMU_IOC_GET_BACKLIGHT:
+ if (!pmu_has_backlight)
+ return -ENOSYS;
return put_user(backlight_level, (__u32 *)arg);
case PMU_IOC_SET_BACKLIGHT:
+ if (!pmu_has_backlight)
+ return -ENOSYS;
error = get_user(value, (__u32 *)arg);
if (!error)
pmu_set_brightness(value);
return error;
case PMU_IOC_GET_MODEL:
return put_user(pmu_kind, (__u32 *)arg);
+ case PMU_IOC_HAS_ADB:
+ return put_user(pmu_has_adb, (__u32 *)arg);
}
return -EINVAL;
}
static inline void polled_send_byte(volatile unsigned char *via, int x)
{
- xmon_printf("s%.2x", x);
via[ACR] |= SR_OUT | SR_EXT; eieio();
via[SR] = x; eieio();
polled_handshake(via);
x = via[SR]; eieio();
polled_handshake(via);
x = via[SR]; eieio();
- xmon_printf("r%.2x", x);
return x;
}
if [ "$CONFIG_PPC" = "y" ]; then
tristate 'MACE (Power Mac ethernet) support' CONFIG_MACE
tristate 'BMAC (G3 ethernet) support' CONFIG_BMAC
+ tristate 'GMAC (G4/iBook ethernet) support' CONFIG_GMAC
tristate 'Symbios 53c885 (Synergy ethernet) support' CONFIG_NCR885E
fi
if [ "$CONFIG_ZORRO" = "y" ]; then
endif
endif
+ifeq ($(CONFIG_GMAC),y)
+L_OBJS += gmac.o
+else
+ ifeq ($(CONFIG_GMAC),m)
+ M_OBJS += gmac.o
+ endif
+endif
+
ifeq ($(CONFIG_NCR885E),y)
L_OBJS += ncr885e.o
else
extern int tlan_probe(struct device *);
extern int mace_probe(struct device *);
extern int bmac_probe(struct device *);
+extern int gmac_probe(struct device *);
extern int ncr885e_probe(struct device *);
extern int cs89x0_probe(struct device *dev);
extern int ethertap_probe(struct device *dev);
#ifdef CONFIG_BMAC
{bmac_probe, 0},
#endif
+#ifdef CONFIG_GMAC
+ {gmac_probe, 0},
+#endif
#ifdef CONFIG_NCR885E
{ncr885e_probe, 0},
#endif
#define ALIGN64 ((u_long)64 - 1) /* 16 longword align */
#define ALIGN128 ((u_long)128 - 1) /* 32 longword align */
+#ifndef __powerpc__
#define ALIGN ALIGN32 /* Keep the DC21040 happy... */
#define CACHE_ALIGN CAL_16LONG
#define DESC_SKIP_LEN DSL_0 /* Must agree with DESC_ALIGN */
/*#define DESC_ALIGN u32 dummy[4]; / * Must agree with DESC_SKIP_LEN */
#define DESC_ALIGN
+#else /* __powerpc__ */
+#define ALIGN ALIGN32 /* Keep the DC21040 happy... */
+#define CACHE_ALIGN CAL_8LONG
+#define DESC_SKIP_LEN DSL_4 /* Must agree with DESC_ALIGN */
+#define DESC_ALIGN u32 dummy[4]; /* Must agree with DESC_SKIP_LEN */
+#endif /* __powerpc__ */
+
#ifndef DEC_ONLY /* See README.de4x5 for using this */
static int dec_only = 0;
#else
struct de4x5_private {
char adapter_name[80]; /* Adapter name */
u_long interrupt; /* Aligned ISR flag */
+#ifdef __powerpc__
+ u_long dummy[3]; /* Keep rx_ring 32-byte aligned */
+#endif
struct de4x5_desc rx_ring[NUM_RX_DESC]; /* RX descriptor ring */
struct de4x5_desc tx_ring[NUM_TX_DESC]; /* TX descriptor ring */
struct sk_buff *tx_skb[NUM_TX_DESC]; /* TX skb for freeing when sent */
--- /dev/null
+/*
+ * Network device driver for the GMAC ethernet controller on
+ * Apple G4 Powermacs.
+ *
+ * Copyright (C) 2000 Paul Mackerras.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/delay.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <asm/prom.h>
+#include <asm/io.h>
+#include <asm/pgtable.h>
+#include "gmac.h"
+
+#define DEBUG_PHY
+
+#define NTX 32 /* must be power of 2 */
+#define NRX 32 /* must be power of 2 */
+#define RX_BUFLEN (ETH_FRAME_LEN + 8)
+
+struct gmac_dma_desc {
+ unsigned int cmd;
+ unsigned int status;
+ unsigned int address; /* phys addr, low 32 bits */
+ unsigned int hi_addr;
+};
+
+/* Bits in cmd */
+#define RX_OWN 0x80000000 /* 1 = owned by chip */
+#define TX_SOP 0x80000000
+#define TX_EOP 0x40000000
+
+struct gmac {
+ volatile unsigned int *regs; /* hardware registers, virtual addr */
+ volatile unsigned int *sysregs;
+ unsigned long desc_page; /* page for DMA descriptors */
+ volatile struct gmac_dma_desc *rxring;
+ struct sk_buff *rx_buff[NRX];
+ int next_rx;
+ volatile struct gmac_dma_desc *txring;
+ struct sk_buff *tx_buff[NTX];
+ int next_tx;
+ int tx_gone;
+ unsigned char tx_full;
+ int phy_addr;
+ int full_duplex;
+ struct net_device_stats stats;
+};
+
+#define GM_OUT(r, v) out_le32(gm->regs + (r)/4, (v))
+#define GM_IN(r) in_le32(gm->regs + (r)/4)
+#define GM_BIS(r, v) GM_OUT((r), GM_IN(r) | (v))
+#define GM_BIC(r, v) GM_OUT((r), GM_IN(r) & ~(v))
+
+#define PHY_B5400 0x6040
+#define PHY_B5201 0x6212
+
+static unsigned char dummy_buf[RX_BUFLEN+2];
+static struct device *gmacs = NULL;
+
+/* Prototypes */
+static int mii_read(struct gmac *gm, int phy, int r);
+static int mii_write(struct gmac *gm, int phy, int r, int v);
+static void powerup_transceiver(struct gmac *gm);
+static int gmac_reset(struct device *dev);
+static void gmac_mac_init(struct gmac *gm, unsigned char *mac_addr);
+static void gmac_init_rings(struct gmac *gm);
+static void gmac_start_dma(struct gmac *gm);
+static int gmac_open(struct device *dev);
+static int gmac_close(struct device *dev);
+static int gmac_xmit_start(struct sk_buff *skb, struct device *dev);
+static int gmac_tx_cleanup(struct gmac *gm);
+static void gmac_receive(struct device *dev);
+static void gmac_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+static struct net_device_stats *gmac_stats(struct device *dev);
+int gmac_probe(struct device *dev);
+
+/* Stuff for talking to the physical-layer chip */
+static int
+mii_read(struct gmac *gm, int phy, int r)
+{
+ int timeout;
+
+ GM_OUT(MIFFRAME, 0x60020000 | (phy << 23) | (r << 18));
+ for (timeout = 1000; timeout > 0; --timeout) {
+ udelay(20);
+ if (GM_IN(MIFFRAME) & 0x10000)
+ return GM_IN(MIFFRAME) & 0xffff;
+ }
+ return -1;
+}
+
+static int
+mii_write(struct gmac *gm, int phy, int r, int v)
+{
+ int timeout;
+
+ GM_OUT(MIFFRAME, 0x50020000 | (phy << 23) | (r << 18) | (v & 0xffff));
+ for (timeout = 1000; timeout > 0; --timeout) {
+ udelay(20);
+ if (GM_IN(MIFFRAME) & 0x10000)
+ return 0;
+ }
+ return -1;
+}
+
+static void
+mii_poll_start(struct gmac *gm)
+{
+ unsigned int tmp;
+
+ /* Start the MIF polling on the external transceiver. */
+ tmp = GM_IN(MIFCONFIG);
+ tmp &= ~(GMAC_MIF_CFGPR_MASK | GMAC_MIF_CFGPD_MASK);
+ tmp |= ((gm->phy_addr & 0x1f) << GMAC_MIF_CFGPD_SHIFT);
+ tmp |= (0x19 << GMAC_MIF_CFGPR_SHIFT);
+ tmp |= GMAC_MIF_CFGPE;
+ GM_OUT(MIFCONFIG, tmp);
+
+ /* Let the bits set. */
+ udelay(GMAC_MIF_POLL_DELAY);
+
+ GM_OUT(MIFINTMASK, 0xffc0);
+}
+
+static void
+mii_poll_stop(struct gmac *gm)
+{
+ GM_OUT(MIFINTMASK, 0xffff);
+ GM_BIC(MIFCONFIG, GMAC_MIF_CFGPE);
+ udelay(GMAC_MIF_POLL_DELAY);
+}
+
+static void
+mii_interrupt(struct gmac *gm)
+{
+ unsigned long flags;
+ int phy_status;
+
+ save_flags(flags);
+ cli();
+
+ mii_poll_stop(gm);
+
+ /* May the status change before polling is re-enabled ? */
+ mii_poll_start(gm);
+
+ /* We read the Auxilliary Status Summary register */
+ phy_status = mii_read(gm, gm->phy_addr, 0x19);
+#ifdef DEBUG_PHY
+ printk("mii_interrupt, phy_status: %x\n", phy_status);
+#endif
+ /* Auto-neg. complete ? */
+ if (phy_status & 0x8000) {
+ int full_duplex = 0;
+ switch((phy_status >> 8) & 0x7) {
+ case 2:
+ case 5:
+ full_duplex = 1;
+ break;
+ }
+ if (full_duplex != gm->full_duplex) {
+ GM_BIC(TXMAC_CONFIG, 1);
+ udelay(200);
+ if (full_duplex) {
+ printk("full duplex active\n");
+ GM_OUT(TXMAC_CONFIG, 6);
+ GM_OUT(XIF_CONFIG, 1);
+ } else {
+ printk("half duplex active\n");
+ GM_OUT(TXMAC_CONFIG, 0);
+ GM_OUT(XIF_CONFIG, 5);
+ }
+ GM_BIS(TXMAC_CONFIG, 1);
+ gm->full_duplex = full_duplex;
+ }
+ }
+
+ restore_flags(flags);
+}
+
+static void
+powerup_transceiver(struct gmac *gm)
+{
+ int phytype = mii_read(gm, 0, 3);
+#ifdef DEBUG_PHY
+ int i;
+#endif
+ switch (phytype) {
+ case PHY_B5400:
+ mii_write(gm, 0, 0, mii_read(gm, 0, 0) & ~0x800);
+ mii_write(gm, 31, 30, mii_read(gm, 31, 30) & ~8);
+ break;
+ case PHY_B5201:
+ mii_write(gm, 0, 30, mii_read(gm, 0, 30) & ~8);
+ break;
+ default:
+ printk(KERN_ERR "GMAC: unknown PHY type %x\n", phytype);
+ }
+ /* Check this */
+ gm->phy_addr = 0;
+ gm->full_duplex = 0;
+
+#ifdef DEBUG_PHY
+ printk("PHY regs:\n");
+ for (i=0; i<0x20; i++) {
+ printk("%04x ", mii_read(gm, 0, i));
+ if ((i % 4) == 3)
+ printk("\n");
+ }
+#endif
+}
+
+static int
+gmac_reset(struct device *dev)
+{
+ struct gmac *gm = (struct gmac *) dev->priv;
+ int timeout;
+
+ /* turn on GB clock */
+ out_le32(gm->sysregs + 0x20/4, in_le32(gm->sysregs + 0x20/4) | 2);
+ udelay(10);
+ GM_OUT(SW_RESET, 3);
+ for (timeout = 100; timeout > 0; --timeout) {
+ mdelay(10);
+ if ((GM_IN(SW_RESET) & 3) == 0)
+ return 0;
+ }
+ printk(KERN_ERR "GMAC: reset failed!\n");
+ return -1;
+}
+
+static void
+gmac_mac_init(struct gmac *gm, unsigned char *mac_addr)
+{
+ int i;
+
+ GM_OUT(RANSEED, 937);
+ GM_OUT(DATAPATHMODE, 4);
+ mii_write(gm, 0, 0, 0x1000);
+ GM_OUT(TXDMA_CONFIG, 0xffc00);
+ GM_OUT(RXDMA_CONFIG, 0);
+ GM_OUT(MACPAUSE, 0x1bf0);
+ GM_OUT(IPG0, 0);
+ GM_OUT(IPG1, 8);
+ GM_OUT(IPG2, 4);
+ GM_OUT(MINFRAMESIZE, 64);
+ GM_OUT(MAXFRAMESIZE, 2000);
+ GM_OUT(PASIZE, 7);
+ GM_OUT(JAMSIZE, 4);
+ GM_OUT(ATTEMPT_LIMIT, 16);
+ GM_OUT(SLOTTIME, 64);
+ GM_OUT(MACCNTL_TYPE, 0x8808);
+ GM_OUT(MAC_ADDR_0, (mac_addr[4] << 8) + mac_addr[5]);
+ GM_OUT(MAC_ADDR_1, (mac_addr[2] << 8) + mac_addr[3]);
+ GM_OUT(MAC_ADDR_2, (mac_addr[0] << 8) + mac_addr[1]);
+ GM_OUT(MAC_ADDR_3, 0);
+ GM_OUT(MAC_ADDR_4, 0);
+ GM_OUT(MAC_ADDR_5, 0);
+ GM_OUT(MAC_ADDR_6, 0x0180);
+ GM_OUT(MAC_ADDR_7, 0xc200);
+ GM_OUT(MAC_ADDR_8, 0x0001);
+ GM_OUT(MAC_ADDR_FILTER_0, 0);
+ GM_OUT(MAC_ADDR_FILTER_1, 0);
+ GM_OUT(MAC_ADDR_FILTER_2, 0);
+ GM_OUT(MAC_ADDR_FILTER_MASK21, 0);
+ GM_OUT(MAC_ADDR_FILTER_MASK0, 0);
+ for (i = 0; i < 27; ++i)
+ GM_OUT(MAC_HASHTABLE + i, 0);
+ GM_OUT(MACCNTL_CONFIG, 0);
+ /* default to half duplex */
+ GM_OUT(TXMAC_CONFIG, 0);
+ GM_OUT(XIF_CONFIG, 5);
+}
+
+static void
+gmac_init_rings(struct gmac *gm)
+{
+ int i;
+ struct sk_buff *skb;
+ unsigned char *data;
+ struct gmac_dma_desc *ring;
+
+ /* init rx ring */
+ ring = (struct gmac_dma_desc *) gm->rxring;
+ memset(ring, 0, NRX * sizeof(struct gmac_dma_desc));
+ for (i = 0; i < NRX; ++i, ++ring) {
+ data = dummy_buf;
+ gm->rx_buff[i] = skb = dev_alloc_skb(RX_BUFLEN + 2);
+ if (skb != 0) {
+ /*skb_reserve(skb, 2);*/
+ data = skb->data;
+ }
+ st_le32(&ring->address, virt_to_bus(data));
+ st_le32(&ring->cmd, RX_OWN);
+ }
+
+ /* init tx ring */
+ ring = (struct gmac_dma_desc *) gm->txring;
+ memset(ring, 0, NRX * sizeof(struct gmac_dma_desc));
+
+ /* set pointers in chip */
+ mb();
+ GM_OUT(RXDMA_BASE_HIGH, 0);
+ GM_OUT(RXDMA_BASE_LOW, virt_to_bus(gm->rxring));
+ GM_OUT(TXDMA_BASE_HIGH, 0);
+ GM_OUT(TXDMA_BASE_LOW, virt_to_bus(gm->txring));
+}
+
+static void
+gmac_start_dma(struct gmac *gm)
+{
+ GM_BIS(RXDMA_CONFIG, 1);
+ GM_BIS(RXMAC_CONFIG, 1);
+ GM_OUT(RXDMA_KICK, NRX);
+ GM_BIS(TXDMA_CONFIG, 1);
+ GM_BIS(TXMAC_CONFIG, 1);
+}
+
+static int gmac_open(struct device *dev)
+{
+ struct gmac *gm = (struct gmac *) dev->priv;
+
+ if (gmac_reset(dev))
+ return -EIO;
+
+ MOD_INC_USE_COUNT;
+
+ powerup_transceiver(gm);
+ gmac_mac_init(gm, dev->dev_addr);
+ gmac_init_rings(gm);
+ gmac_start_dma(gm);
+ mii_interrupt(gm);
+
+ GM_OUT(INTR_DISABLE, 0xfffdffe8);
+
+ return 0;
+}
+
+static int gmac_close(struct device *dev)
+{
+ struct gmac *gm = (struct gmac *) dev->priv;
+ int i;
+
+ mii_poll_stop(gm);
+
+ GM_BIC(RXDMA_CONFIG, 1);
+ GM_BIC(RXMAC_CONFIG, 1);
+ GM_BIC(TXDMA_CONFIG, 1);
+ GM_BIC(TXMAC_CONFIG, 1);
+ GM_OUT(INTR_DISABLE, ~0U);
+ for (i = 0; i < NRX; ++i) {
+ if (gm->rx_buff[i] != 0) {
+ dev_kfree_skb(gm->rx_buff[i]);
+ gm->rx_buff[i] = 0;
+ }
+ }
+ for (i = 0; i < NTX; ++i) {
+ if (gm->tx_buff[i] != 0) {
+ dev_kfree_skb(gm->tx_buff[i]);
+ gm->tx_buff[i] = 0;
+ }
+ }
+
+ MOD_DEC_USE_COUNT;
+ return 0;
+}
+
+static int gmac_xmit_start(struct sk_buff *skb, struct device *dev)
+{
+ struct gmac *gm = (struct gmac *) dev->priv;
+ volatile struct gmac_dma_desc *dp;
+ unsigned long flags;
+ int i;
+
+ save_flags(flags); cli();
+ i = gm->next_tx;
+ if (gm->tx_buff[i] != 0) {
+ /* buffer is full, can't send this packet at the moment */
+ dev->tbusy = 1;
+ gm->tx_full = 1;
+ restore_flags(flags);
+ return 1;
+ }
+ gm->next_tx = (i + 1) & (NTX - 1);
+ gm->tx_buff[i] = skb;
+ restore_flags(flags);
+
+ dp = &gm->txring[i];
+ dp->status = 0;
+ dp->hi_addr = 0;
+ st_le32(&dp->address, virt_to_bus(skb->data));
+ mb();
+ st_le32(&dp->cmd, TX_SOP | TX_EOP | skb->len);
+ mb();
+
+ GM_OUT(TXDMA_KICK, gm->next_tx);
+
+ return 0;
+}
+
+static int gmac_tx_cleanup(struct gmac *gm)
+{
+ int i = gm->tx_gone;
+ volatile struct gmac_dma_desc *dp;
+ struct sk_buff *skb;
+ int ret = 0;
+ int gone = GM_IN(TXDMA_COMPLETE);
+
+ while (i != gone) {
+ skb = gm->tx_buff[i];
+ if (skb == NULL)
+ break;
+ dp = &gm->txring[i];
+ gm->stats.tx_bytes += skb->len;
+ ++gm->stats.tx_packets;
+ gm->tx_buff[i] = NULL;
+ dev_kfree_skb(skb);
+ if (++i >= NTX)
+ i = 0;
+ }
+ if (i != gm->tx_gone) {
+ ret = gm->tx_full;
+ gm->tx_gone = i;
+ gm->tx_full = 0;
+ }
+ return ret;
+}
+
+static void gmac_receive(struct device *dev)
+{
+ struct gmac *gm = (struct gmac *) dev->priv;
+ int i = gm->next_rx;
+ volatile struct gmac_dma_desc *dp;
+ struct sk_buff *skb;
+ int len;
+ unsigned char *data;
+
+ for (;;) {
+ dp = &gm->rxring[i];
+ if (ld_le32(&dp->cmd) & RX_OWN)
+ break;
+ len = (ld_le32(&dp->cmd) >> 16) & 0x7fff;
+ skb = gm->rx_buff[i];
+ if (skb == 0) {
+ ++gm->stats.rx_dropped;
+ } else if (ld_le32(&dp->status) & 0x40000000) {
+ ++gm->stats.rx_errors;
+ dev_kfree_skb(skb);
+ } else {
+ skb_put(skb, len);
+ skb->dev = dev;
+ skb->protocol = eth_type_trans(skb, dev);
+ netif_rx(skb);
+ gm->stats.rx_bytes += skb->len;
+ ++gm->stats.rx_packets;
+ }
+ data = dummy_buf;
+ gm->rx_buff[i] = skb = dev_alloc_skb(RX_BUFLEN + 2);
+ if (skb != 0) {
+ /*skb_reserve(skb, 2);*/
+ data = skb->data;
+ }
+ st_le32(&dp->address, virt_to_bus(data));
+ dp->hi_addr = 0;
+ mb();
+ st_le32(&dp->cmd, RX_OWN);
+ if (++i >= NRX)
+ i = 0;
+ }
+ gm->next_rx = i;
+}
+
+static void gmac_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+ struct device *dev = (struct device *) dev_id;
+ struct gmac *gm = (struct gmac *) dev->priv;
+ unsigned int status;
+
+ status = GM_IN(INTR_STATUS);
+ GM_OUT(INTR_ACK, status);
+
+ if (status & GMAC_IRQ_MIF) {
+ mii_interrupt(gm);
+ }
+ gmac_receive(dev);
+ if (gmac_tx_cleanup(gm)){
+ dev->tbusy = 0;
+ mark_bh(NET_BH);
+ }
+}
+
+static struct net_device_stats *gmac_stats(struct device *dev)
+{
+ struct gmac *gm = (struct gmac *) dev->priv;
+
+ return &gm->stats;
+}
+
+int gmac_probe(struct device *dev)
+{
+ static int gmacs_found;
+ static struct device_node *next_gmac;
+ struct device_node *gmac;
+ struct gmac *gm;
+ unsigned long descpage;
+ unsigned char *addr;
+ int i;
+
+ /*
+ * We could (and maybe should) do this using PCI scanning
+ * for vendor/device ID 0x106b/0x21.
+ */
+ if (!gmacs_found) {
+ next_gmac = find_compatible_devices("network", "gmac");
+ gmacs_found = 1;
+ }
+ if ((gmac = next_gmac) == 0)
+ return -ENODEV;
+ next_gmac = gmac->next;
+
+ if (gmac->n_addrs < 1 || gmac->n_intrs < 1) {
+ printk(KERN_ERR "can't use GMAC %s: %d addrs and %d intrs\n",
+ gmac->full_name, gmac->n_addrs, gmac->n_intrs);
+ return -ENODEV;
+ }
+
+ dev = init_etherdev(0, sizeof(struct gmac));
+ memset(dev->priv, 0, sizeof(struct gmac));
+
+ gm = (struct gmac *) dev->priv;
+ dev->base_addr = gmac->addrs[0].address;
+ gm->regs = (volatile unsigned int *)
+ ioremap(gmac->addrs[0].address, 0x10000);
+ gm->sysregs = (volatile unsigned int *) ioremap(0xf8000000, 0x1000);
+ dev->irq = gmac->intrs[0].line;
+
+ addr = get_property(gmac, "local-mac-address", NULL);
+ if (addr == NULL) {
+ printk(KERN_ERR "Can't get mac-address for GMAC %s\n",
+ gmac->full_name);
+ return -EAGAIN;
+ }
+
+ printk(KERN_INFO "%s: GMAC at", dev->name);
+ for (i = 0; i < 6; ++i) {
+ dev->dev_addr[i] = addr[i];
+ printk("%c%.2x", (i? ':': ' '), addr[i]);
+ }
+ printk("\n");
+
+ descpage = get_free_page(GFP_KERNEL);
+ if (descpage == 0) {
+ printk(KERN_ERR "GMAC: can't get a page for descriptors\n");
+ return -EAGAIN;
+ }
+
+ gm->desc_page = descpage;
+ gm->rxring = (volatile struct gmac_dma_desc *) descpage;
+ gm->txring = (volatile struct gmac_dma_desc *) (descpage + 0x800);
+
+ gm->phy_addr = 0;
+
+ dev->open = gmac_open;
+ dev->stop = gmac_close;
+ dev->hard_start_xmit = gmac_xmit_start;
+ dev->get_stats = gmac_stats;
+
+ ether_setup(dev);
+
+ if (request_irq(dev->irq, gmac_interrupt, 0, "GMAC", dev)) {
+ printk(KERN_ERR "GMAC: can't get irq %d\n", dev->irq);
+ return -EAGAIN;
+ }
+
+ gmacs = dev;
+
+ return 0;
+}
+
+#ifdef MODULE
+
+MODULE_AUTHOR("Paul Mackerras");
+MODULE_DESCRIPTION("PowerMac GMAC driver.");
+
+int init_module(void)
+{
+ if (gmacs != NULL)
+ return -EBUSY;
+ return gmac_probe(NULL);
+}
+
+void cleanup_module(void)
+{
+ struct gmac *gm;
+
+ /* XXX should handle more than one */
+ if (gmacs == NULL)
+ return;
+
+ gm = (struct gmac *) gmacs->priv;
+ free_irq(gmacs->irq, gmac_interrupt);
+ free_page(gm->desc_page);
+ unregister_netdev(gmacs);
+ kfree(gmacs);
+ gmacs = NULL;
+}
+
+#endif
--- /dev/null
+/*
+ * Definitions for the GMAC ethernet chip, used in the
+ * Apple G4 powermac.
+ */
+
+/* Register offsets */
+#define INTR_STATUS 0x000c
+#define INTR_DISABLE 0x0010
+#define INTR_ACK 0x0014
+#define SW_RESET 0x1010
+#define TXDMA_KICK 0x2000
+#define TXDMA_CONFIG 0x2004
+#define TXDMA_BASE_LOW 0x2008
+#define TXDMA_BASE_HIGH 0x200c
+#define TXDMA_STATE_MACH 0x2028
+#define TXDMA_COMPLETE 0x2100
+#define RXDMA_CONFIG 0x4000
+#define RXDMA_BASE_LOW 0x4004
+#define RXDMA_BASE_HIGH 0x4008
+#define RXDMA_KICK 0x4100
+#define MACPAUSE 0x6008
+#define TXMAC_STATUS 0x6010
+#define TXMAC_CONFIG 0x6030
+#define RXMAC_CONFIG 0x6034
+#define MACCNTL_CONFIG 0x6038
+#define XIF_CONFIG 0x603c
+#define IPG0 0x6040
+#define IPG1 0x6044
+#define IPG2 0x6048
+#define SLOTTIME 0x604c
+#define MINFRAMESIZE 0x6050
+#define MAXFRAMESIZE 0x6054
+#define PASIZE 0x6058
+#define JAMSIZE 0x605c
+#define ATTEMPT_LIMIT 0x6060
+#define MACCNTL_TYPE 0x6064
+#define MAC_ADDR_0 0x6080
+#define MAC_ADDR_1 0x6084
+#define MAC_ADDR_2 0x6088
+#define MAC_ADDR_3 0x608c
+#define MAC_ADDR_4 0x6090
+#define MAC_ADDR_5 0x6094
+#define MAC_ADDR_6 0x6098
+#define MAC_ADDR_7 0x609c
+#define MAC_ADDR_8 0x60a0
+#define MAC_ADDR_FILTER_0 0x60a4
+#define MAC_ADDR_FILTER_1 0x60a8
+#define MAC_ADDR_FILTER_2 0x60ac
+#define MAC_ADDR_FILTER_MASK21 0x60b0
+#define MAC_ADDR_FILTER_MASK0 0x60b4
+#define MAC_HASHTABLE 0x60c0
+#define RANSEED 0x6130
+#define MIFFRAME 0x620c
+#define MIFCONFIG 0x6210
+#define MIFINTMASK 0x6214
+#define MIFSTATUS 0x6218
+#define DATAPATHMODE 0x9050
+
+/* -- 0x000C R-C Global Interrupt status.
+ * d: 0x00000000 bits 0-6 cleared on read (C)
+ */
+#define GMAC_IRQ_TX_INT_ME 0x00000001 /* C Frame with INT_ME bit set in fifo */
+#define GMAC_IRQ_TX_ALL 0x00000002 /* C TX descriptor ring empty */
+#define GMAC_IRQ_TX_DONE 0x00000004 /* C moved from host to TX fifo */
+#define GMAC_IRQ_RX_DONE 0x00000010 /* C moved from RX fifo to host */
+#define GMAC_IRQ_RX_NO_BUF 0x00000020 /* C No RX buffer available */
+#define GMAC_IRQ_RX_TAG_ERR 0x00000040 /* C RX tag error */
+
+#define GMAC_IRQ_PCS 0x00002000 /* PCS interrupt ? */
+#define GMAC_IRQ_MAC_TX 0x00004000 /* MAC tx register set */
+#define GMAC_IRQ_MAC_RX 0x00008000 /* MAC rx register set */
+#define GMAC_IRQ_MAC_CTRL 0x00010000 /* MAC control register set */
+#define GMAC_IRQ_MIF 0x00020000 /* MIF status register set */
+#define GMAC_IRQ_BUS_ERROR 0x00040000 /* Bus error status register set */
+
+#define GMAC_IRQ_TX_COMP 0xfff80000 /* TX completion mask */
+
+/* -- 0x6210 RW MIF config reg
+ */
+
+#define GMAC_MIF_CFGPS 0x00000001 /* PHY Select */
+#define GMAC_MIF_CFGPE 0x00000002 /* Poll Enable */
+#define GMAC_MIF_CFGBB 0x00000004 /* Bit Bang Enable */
+#define GMAC_MIF_CFGPR_MASK 0x000000f8 /* Poll Register address */
+#define GMAC_MIF_CFGPR_SHIFT 3
+#define GMAC_MIF_CFGM0 0x00000100 /* MDIO_0 Data / MDIO_0 attached */
+#define GMAC_MIF_CFGM1 0x00000200 /* MDIO_1 Data / MDIO_1 attached */
+#define GMAC_MIF_CFGPD_MASK 0x00007c00 /* Poll Device PHY address */
+#define GMAC_MIF_CFGPD_SHIFT 10
+
+#define GMAC_MIF_POLL_DELAY 200
+
+#define GMAC_INTERNAL_PHYAD 1 /* PHY address for int. transceiver */
+#define GMAC_EXTERNAL_PHYAD 0 /* PHY address for ext. transceiver */
+
+
+/* -- 0x6214 RW MIF interrupt mask reg
+ * same as basic/status Register
+ */
+
+/* -- 0x6214 RW MIF basic/status reg
+ * The Basic portion of this register indicates the last
+ * value of the register read indicated in the POLL REG field
+ * of the Configuration Register.
+ * The Status portion indicates bit(s) that have changed.
+ * The MIF Mask register is corresponding to this register in
+ * terms of the bit(s) that need to be masked for generating
+ * interrupt on the MIF Interrupt Bit of the Global Status Rgister.
+ */
+
+#define GMAC_MIF_STATUS 0x0000ffff /* 0-15 : Status */
+#define GMAC_MIF_BASIC 0xffff0000 /* 16-31 : Basic register */
+
dev->interrupt = 1;
+ if ((happy_status & (GREG_STAT_TXALL | GREG_STAT_RXTOHOST)) &&
+ (hp->happy_flags & HFLAG_QUATTRO) != 0 &&
+ pci_dma_wsync != NULL)
+ (void) *(pci_dma_wsync);
+
if(happy_status & GREG_STAT_ERRORS) {
HMD(("ERRORS "));
if(happy_meal_is_not_so_happy(hp, gregs, /* un- */ happy_status)) {
#include <asm/adb.h>
#include <asm/cuda.h>
#include <asm/pmu.h>
+#include <asm/feature.h>
#include "awacs_defs.h"
#include <linux/nvram.h>
#include <linux/vt_kern.h>
static int awacs_rate_index;
static int awacs_subframe;
static int awacs_spkr_vol;
+static struct device_node* awacs_node;
static int awacs_revision;
#define AWACS_BURGUNDY 100 /* fake revision # for burgundy */
out_le32(&awacs_txdma->control, RUN<<16);
/* disable interrupts from awacs interface */
out_le32(&awacs->control, in_le32(&awacs->control) & 0xfff);
+#ifdef CONFIG_PMAC_PBOOK
+ if (is_pbook_G3) {
+ feature_clear(awacs_node, FEATURE_Sound_power);
+ feature_clear(awacs_node, FEATURE_Sound_CLK_enable);
+ }
+#endif
free_irq(awacs_irq, (void *) awacs);
free_irq(awacs_tx_irq, (void *) awacs);
kfree(awacs_tx_cmd_space);
PMacSilence();
disable_irq(awacs_irq);
disable_irq(awacs_tx_irq);
+ feature_clear(awacs_node, FEATURE_Sound_CLK_enable);
+ feature_clear(awacs_node, FEATURE_Sound_power);
break;
case PBOOK_WAKE:
+ /* There is still a problem on wake. Sound seems to work fine
+ if I launch mpg123 and resumes fine if mpg123 was playing,
+ but the console beep is dead until I do something with the
+ mixer. Probably yet another timing issue */
+ if (!feature_test(awacs_node, FEATURE_Sound_CLK_enable)
+ || !feature_test(awacs_node, FEATURE_Sound_power)) {
+ /* these aren't present on the 3400 AFAIK -- paulus */
+ feature_set(awacs_node, FEATURE_Sound_CLK_enable);
+ feature_set(awacs_node, FEATURE_Sound_power);
+ mdelay(1000);
+ }
out_le32(&awacs->control, MASK_IEPC
| (awacs_rate_index << 8) | 0x11
| (awacs_revision < AWACS_BURGUNDY? MASK_IEE: 0));
mdelay(2);
awacs_write(awacs_reg[1] | MASK_ADDR1);
}
+ /* enable CD sound input */
+ if (macio_base && is_pbook_G3) {
+ out_8(macio_base + 0x37, 3);
+ } else if (is_pbook_3400) {
+ feature_set(awacs_node, FEATURE_IOBUS_enable);
+ udelay(10);
+ in_8((unsigned char *)0xf301a190);
+ }
+ /* Resume pending sounds. Paul, Is this wrong ? */
+ PMacPlay();
}
return PBOOK_SLEEP_OK;
}
u_long fmt;
int data;
int size, nbufs;
+ audio_buf_info info;
switch (cmd) {
case SNDCTL_DSP_RESET:
sq_setup(numBufs, size, sound_buffers);
sq.max_active = nbufs;
return 0;
+ case SNDCTL_DSP_GETOSPACE:
+ info.fragments = sq.max_active - sq.count;
+ info.fragstotal = sq.max_active;
+ info.fragsize = sq.block_size;
+ info.bytes = info.fragments * info.fragsize;
+ if (copy_to_user((void *)arg, &info, sizeof(info)))
+ return -EFAULT;
+ return 0;
default:
return mixer_ioctl(inode, file, cmd, arg);
#endif /* CONFIG_AMIGA */
#ifdef CONFIG_PPC
case DMASND_AWACS:
- sprintf(mach, "PowerMac (AWACS rev %d) ", awacs_revision);
+ /* BenH: This one used to sprintf in mach which doesn't point to
+ * a large enough buffer */
+ len += sprintf(buffer+len, "PowerMac (AWACS rev %d) ", awacs_revision);
break;
#endif /* CONFIG_PPC */
}
printk(KERN_ERR "DMA sound driver: Not enough buffer memory, driver disabled!\n");
return;
}
+ awacs_node = np;
+#ifdef CONFIG_PMAC_PBOOK
+ if (machine_is_compatible("PowerBook1,1")
+ || machine_is_compatible("AAPL,PowerBook1998")) {
+ feature_set(np, FEATURE_Sound_CLK_enable);
+ feature_set(np, FEATURE_Sound_power);
+ /* Shorter delay will not work */
+ mdelay(1000);
+ }
+#endif
awacs_tx_cmds = (volatile struct dbdma_cmd *)
DBDMA_ALIGN(awacs_tx_cmd_space);
awacs_reg[0] = MASK_MUX_CD;
awacs_revision =
(in_le32(&awacs->codec_stat) >> 12) & 0xf;
if (awacs_revision == 3) {
+ mdelay(100);
awacs_write(0x6000);
+ mdelay(2);
+ awacs_write(awacs_reg[1] + MASK_ADDR1);
awacs_enable_amp(100 * 0x101);
}
}
/* Powerbooks have odd ways of enabling inputs such as
an expansion-bay CD or sound from an internal modem
or a PC-card modem. */
- if (machine_is_compatible("AAPL,3400/2400")) {
+ if (machine_is_compatible("AAPL,3400/2400")
+ || machine_is_compatible("AAPL,3500")) {
is_pbook_3400 = 1;
/*
* Enable CD and PC-card sound inputs.
* This is done by reading from address
* f301a000, + 0x10 to enable the expansion-bay
* CD sound input, + 0x80 to enable the PC-card
- * sound input. The 0x100 seems to enable the
- * MESH and/or its SCSI bus drivers.
+ * sound input. The 0x100 enables the SCSI bus
+ * terminator power.
*/
in_8((unsigned char *)0xf301a190);
- } else if (machine_is_compatible("PowerBook1,1")) {
- np = find_devices("mac-io");
- if (np && np->n_addrs > 0) {
- is_pbook_G3 = 1;
- macio_base = (unsigned char *)
- ioremap(np->addrs[0].address, 0x40);
- /* enable CD sound input */
- out_8(macio_base + 0x37, 3);
+ } else if (machine_is_compatible("PowerBook1,1")
+ || machine_is_compatible("AAPL,PowerBook1998")) {
+ struct device_node* mio;
+ macio_base = 0;
+ is_pbook_G3 = 1;
+ for (mio = np->parent; mio; mio = mio->parent) {
+ if (strcmp(mio->name, "mac-io") == 0
+ && mio->n_addrs > 0) {
+ macio_base = (unsigned char *) ioremap
+ (mio->addrs[0].address, 0x40);
+ break;
+ }
}
- }
+ /* enable CD sound input */
+ if (macio_base)
+ out_8(macio_base + 0x37, 3);
+ }
}
#endif /* CONFIG_PPC */
if (EXT2_HAS_INCOMPAT_FEATURE(dir->i_sb,
EXT2_FEATURE_INCOMPAT_FILETYPE))
de->file_type = EXT2_FT_REG_FILE;
+ } else if (S_ISSOCK(inode->i_mode)) {
+ if (EXT2_HAS_INCOMPAT_FEATURE(dir->i_sb,
+ EXT2_FEATURE_INCOMPAT_FILETYPE))
+ de->file_type = EXT2_FT_SOCK;
} else if (S_ISCHR(inode->i_mode)) {
inode->i_op = &chrdev_inode_operations;
if (EXT2_HAS_INCOMPAT_FEATURE(dir->i_sb,
de->file_type = EXT2_FT_DIR;
else if (S_ISLNK(inode->i_mode))
de->file_type = EXT2_FT_SYMLINK;
+ else if (S_ISSOCK(inode->i_mode))
+ de->file_type = EXT2_FT_SOCK;
else if (S_ISCHR(inode->i_mode))
de->file_type = EXT2_FT_CHRDEV;
else if (S_ISBLK(inode->i_mode))
if (copy_from_user(iov, vector, count*sizeof(*vector)))
goto out;
+ /* BSD readv/writev returns EINVAL if one of the iov_len
+ values < 0 or tot_len overflowed a 32-bit integer. -ink */
tot_len = 0;
- for (i = 0 ; i < count ; i++)
- tot_len += iov[i].iov_len;
-
- if((long) tot_len <0)
- return -EINVAL;
+ ret = -EINVAL;
+ for (i = 0 ; i < count ; i++) {
+ size_t tmp = tot_len;
+ int len = iov[i].iov_len;
+ if (len < 0)
+ goto out;
+ (u32)tot_len += len;
+ if (tot_len < tmp || tot_len < (u32)len)
+ goto out;
+ }
inode = file->f_dentry->d_inode;
/* VERIFY_WRITE actually means a read, as we write to user space */
#endif
#endif
-
\ No newline at end of file
* ELF register definitions..
*/
#include <asm/ptrace.h>
+#include <asm/types.h>
#define ELF_NGREG 48 /* includes nip, msr, lr, etc. */
#define ELF_NFPREG 33 /* includes fpscr */
+#define ELF_NVRREG 33 /* includes vscr */
/*
* This is used to ensure we don't load something for the wrong architecture.
typedef double elf_fpreg_t;
typedef elf_fpreg_t elf_fpregset_t[ELF_NFPREG];
+/* Altivec registers */
+typedef vector128 elf_vrreg_t;
+typedef elf_vrreg_t elf_vrregset_t[ELF_NVRREG];
+
#define ELF_CORE_COPY_REGS(gregs, regs) \
memcpy(gregs, regs, \
sizeof(struct pt_regs) < sizeof(elf_gregset_t)? \
* for more details.
*
* Copyright (C) 1998 Paul Mackerras.
+ *
*/
#ifndef __ASM_PPC_FEATURE_H
#define __ASM_PPC_FEATURE_H
/*
- * The FCR bits for particular features vary somewhat between
+ * The FCR selector for particular features vary somewhat between
* different machines. So we abstract a list of features here
* and let the feature_* routines map them to the actual bits.
*/
FEATURE_Serial_IO_B,
FEATURE_SWIM3_enable,
FEATURE_MESH_enable,
- FEATURE_IDE_enable,
- FEATURE_VIA_enable,
- FEATURE_CD_power,
+ FEATURE_IDE0_enable, /* Internal IDE */
+ FEATURE_IDE0_reset, /* Internal IDE */
+ FEATURE_IOBUS_enable, /* Internal IDE */
FEATURE_Mediabay_reset,
- FEATURE_Mediabay_enable,
+ FEATURE_Mediabay_power,
FEATURE_Mediabay_PCI_enable,
- FEATURE_Mediabay_IDE_enable,
+ FEATURE_IDE1_enable, /* MediaBay IDE */
+ FEATURE_IDE1_reset, /* MediaBay IDE */
FEATURE_Mediabay_floppy_enable,
FEATURE_BMac_reset,
FEATURE_BMac_IO_enable,
- FEATURE_Modem_Reset,
- FEATURE_IDE_DiskPower,
- FEATURE_IDE_Reset,
+ FEATURE_Modem_power,
+ FEATURE_Slow_SCC_PCLK,
+ FEATURE_Sound_power,
+ FEATURE_Sound_CLK_enable,
+ FEATURE_IDE2_enable,
+ FEATURE_IDE2_reset,
+ FEATURE_Mediabay_IDE_switch, /* MB IDE bus switch */
+ FEATURE_Mediabay_content, /* MB content indicator enable */
FEATURE_last,
};
--- /dev/null
+/*
+ * heathrow.h: definitions for using the "Heathrow" I/O controller chip.
+ *
+ * Grabbed from Open Firmware definitions on a PowerBook G3 Series
+ *
+ * Copyright (C) 1997 Paul Mackerras.
+ */
+
+/* offset from ohare base for feature control register */
+#define HEATHROW_FEATURE_REG 0x38
+
+/*
+ * Bits in feature control register.
+ * Bits postfixed with a _N are in inverse logic
+ */
+#define HRW_RESET_SCC 0x00000001 /* Named in_use_led in OF ??? */
+#define HRW_BAY_POWER_N 0x00000002
+#define HRW_BAY_PCI_ENABLE 0x00000004
+#define HRW_BAY_IDE_ENABLE 0x00000008
+#define HRW_BAY_FLOPPY_ENABLE 0x00000010
+#define HRW_IDE0_ENABLE 0x00000020
+#define HRW_IDE0_RESET_N 0x00000040
+#define HRW_BAY_RESET_N 0x00000080
+#define HRW_IOBUS_ENABLE 0x00000100 /* Internal IDE ? */
+#define HRW_SCC_ENABLE 0x00000200
+#define HRW_MESH_ENABLE 0x00000400
+#define HRW_SWIM_ENABLE 0x00000800
+#define HRW_SOUND_POWER_N 0x00001000
+#define HRW_SOUND_CLK_ENABLE 0x00002000
+#define HRW_SCCA_IO 0x00004000
+#define HRW_SCCB_IO 0x00008000
+#define HRW_PORT_OR_DESK_VIA_N 0x00010000 /* This one is 0 on PowerBook */
+#define HRW_PWM_MON_ID_N 0x00020000 /* ??? (0) */
+#define HRW_HOOK_MB_CNT_N 0x00040000 /* ??? (0) */
+#define HRW_SWIM_CLONE_FLOPPY 0x00080000 /* ??? (0) */
+#define HRW_AUD_RUN22 0x00100000 /* ??? (1) */
+#define HRW_SCSI_LINK_MODE 0x00200000 /* Read ??? (1) */
+#define HRW_ARB_BYPASS 0x00400000 /* ??? (0 on main, 1 on gatwick) */
+#define HRW_IDE1_RESET_N 0x00800000 /* Media bay */
+#define HRW_SLOW_SCC_PCLK 0x01000000 /* ??? (0) */
+#define HRW_MODEM_POWER_N 0x02000000 /* Used by internal modem on wallstreet */
+#define HRW_MFDC_CELL_ENABLE 0x04000000 /* ??? (0) */
+#define HRW_USE_MFDC 0x08000000 /* ??? (0) */
+#define HRW_BMAC_IO_ENABLE 0x60000000 /* two bits, not documented in OF */
+#define HRW_BMAC_RESET 0x80000000 /* not documented in OF */
+
+#define PADD_MODEM_POWER_N 0x00000001 /* modem power on paddington */
void ide_outsw(ide_ioreg_t port, void *buf, int ns);
void ppc_generic_ide_fix_driveid(struct hd_driveid *id);
-#undef insw
-#define insw(port, buf, ns) do { \
- ppc_ide_md.insw((port), (buf), (ns)); \
-} while (0)
-
-#undef outsw
-#define outsw(port, buf, ns) do { \
- ppc_ide_md.outsw((port), (buf), (ns)); \
-} while (0)
-
#undef SUPPORT_SLOW_DATA_PORTS
#define SUPPORT_SLOW_DATA_PORTS 0
#undef SUPPORT_VLB_SYNC
#define insb(port, buf, ns) _insb((unsigned char *)((port)+_IO_BASE), (buf), (ns))
#define outsb(port, buf, ns) _outsb((unsigned char *)((port)+_IO_BASE), (buf), (ns))
-#define insw(port, buf, ns) _insw((unsigned short *)((port)+_IO_BASE), (buf), (ns))
-#define outsw(port, buf, ns) _outsw((unsigned short *)((port)+_IO_BASE), (buf), (ns))
-#define insl(port, buf, nl) _insl((unsigned long *)((port)+_IO_BASE), (buf), (nl))
-#define outsl(port, buf, nl) _outsl((unsigned long *)((port)+_IO_BASE), (buf), (nl))
+#define insw(port, buf, ns) _insw_ns((unsigned short *)((port)+_IO_BASE), (buf), (ns))
+#define outsw(port, buf, ns) _outsw_ns((unsigned short *)((port)+_IO_BASE), (buf), (ns))
+#define insl(port, buf, nl) _insl_ns((unsigned long *)((port)+_IO_BASE), (buf), (nl))
+#define outsl(port, buf, nl) _outsl_ns((unsigned long *)((port)+_IO_BASE), (buf), (nl))
#define inb(port) in_8((unsigned char *)((port)+_IO_BASE))
#define outb(val, port) out_8((unsigned char *)((port)+_IO_BASE), (val))
}
#define kbd_sysrq_xlate (ppc_md.kbd_sysrq_xlate)
-
-#define SYSRQ_KEY 0x54
+#define SYSRQ_KEY (ppc_md.SYSRQ_KEY)
/* resource allocation */
#define kbd_request_region()
void (*kbd_init_hw)(void);
#ifdef CONFIG_MAGIC_SYSRQ
unsigned char *kbd_sysrq_xlate;
+ unsigned long SYSRQ_KEY;
#endif
/* PCI interfaces */
#ifndef _PPC_MEDIABAY_H
#define _PPC_MEDIABAY_H
+#ifdef __KERNEL__
+
+/* We keep those constants local to the kernel to avoid
+ * compatibility problems with different HW. A /proc inteface
+ * could be defined to tell userland about the content of the bay
+ */
#define MB_FD 0 /* media bay contains floppy drive */
+#define MB_FD1 1 /* media bay contains floppy drive */
#define MB_CD 3 /* media bay contains ATA drive such as CD */
-#define MB_NO 7 /* media bay contains nothing */
-
-#ifdef __KERNEL__
+#define MB_NO 0xF /* media bay contains nothing */
void media_bay_init(void);
int check_media_bay(struct device_node *which_bay, int what);
#define MOTO_RTC_SECONDS 0x1FF9
#define MOTO_RTC_MINUTES 0x1FFA
-#define MOTO_RTC_HOURS 0x1FFB
+#define MOTO_RTC_HOURS 0x1FFB
#define MOTO_RTC_DAY_OF_WEEK 0x1FFC
-#define MOTO_RTC_DAY_OF_MONTH 0x1FFD
-#define MOTO_RTC_MONTH 0x1FFE
-#define MOTO_RTC_YEAR 0x1FFF
-#define MOTO_RTC_CONTROLA 0x1FF8
-#define MOTO_RTC_CONTROLB 0x1FF9
+#define MOTO_RTC_DAY_OF_MONTH 0x1FFD
+#define MOTO_RTC_MONTH 0x1FFE
+#define MOTO_RTC_YEAR 0x1FFF
+#define MOTO_RTC_CONTROLA 0x1FF8
+#define MOTO_RTC_CONTROLB 0x1FF9
#ifndef BCD_TO_BIN
#define BCD_TO_BIN(val) ((val)=((val)&15) + ((val)>>4)*10)
#define BIN_TO_BCD(val) ((val)=(((val)/10)<<4) + (val)%10)
#endif
+/* PowerMac specific nvram stuffs */
+
+enum {
+ pmac_nvram_OF, /* Open Firmware partition */
+ pmac_nvram_XPRAM, /* MacOS XPRAM partition */
+ pmac_nvram_NR /* MacOS Name Registry partition */
+};
+
+/* Return partition offset in nvram */
+extern int pmac_get_partition(int partition);
+
+/* Direct access to XPRAM */
+extern u8 pmac_xpram_read(int xpaddr);
+extern void pmac_xpram_write(int xpaddr, u8 data);
+
+/* Some offsets in XPRAM */
+#define PMAC_XPRAM_MACHINE_LOC 0xe4
+#define PMAC_XPRAM_SOUND_VOLUME 0x08
+
+/* Machine location structure in XPRAM */
+struct pmac_machine_location {
+ u32 latitude; /* 2+30 bit Fractional number */
+ u32 longitude; /* 2+30 bit Fractional number */
+ u32 delta; /* mix of GMT delta and DLS */
+};
+
#endif
* ohare.h: definitions for using the "O'Hare" I/O controller chip.
*
* Copyright (C) 1997 Paul Mackerras.
+ *
+ * BenH: Changed to match those of heathrow (but not all of them). Please
+ * check if I didn't break anything (especially the media bay).
*/
/* offset from ohare base for feature control register */
* and may differ for other machines.
*/
#define OH_SCC_RESET 1
-#define OH_BAY_RESET 2 /* a guess */
+#define OH_BAY_POWER_N 2 /* a guess */
#define OH_BAY_PCI_ENABLE 4 /* a guess */
#define OH_BAY_IDE_ENABLE 8
#define OH_BAY_FLOPPY_ENABLE 0x10
-#define OH_IDE_ENABLE 0x20
-#define OH_IDE_POWER 0x40 /* a guess */
-#define OH_BAY_ENABLE 0x80
-#define OH_IDE_RESET 0x100 /* 0-based, a guess */
+#define OH_IDE0_ENABLE 0x20
+#define OH_IDE0_RESET_N 0x40 /* a guess */
+#define OH_BAY_RESET_N 0x80
+#define OH_IOBUS_ENABLE 0x100 /* IOBUS seems to be IDE */
#define OH_SCC_ENABLE 0x200
#define OH_MESH_ENABLE 0x400
#define OH_FLOPPY_ENABLE 0x800
#define OH_SCCA_IO 0x4000
#define OH_SCCB_IO 0x8000
-#define OH_VIA_ENABLE 0x10000
-#define OH_IDECD_POWER 0x800000
+#define OH_VIA_ENABLE 0x10000 /* Is apparently wrong, to be verified */
+#define OH_IDE1_RESET_N 0x800000
/*
* Bits to set in the feature control register on PowerBooks.
#define PAGE_ALIGN(addr) (((addr)+PAGE_SIZE-1)&PAGE_MASK)
extern void clear_page(unsigned long page);
-#define copy_page(to,from) memcpy((void *)(to), (void *)(from), PAGE_SIZE)
+extern void copy_page(unsigned long to, unsigned long from);
/* map phys->virtual and virtual->phys for RAM pages */
#ifdef CONFIG_APUS
PMU_OHARE_BASED, /* 2400, 3400, 3500 (old G3 powerbook) */
PMU_HEATHROW_BASED, /* PowerBook G3 series */
PMU_PADDINGTON_BASED, /* 1999 PowerBook G3 */
+ PMU_KEYLARGO_BASED, /* Core99 motherboard (PMU99) */
};
/*
#define PMU_IOC_SET_BACKLIGHT _IOW('B', 2, sizeof(__u32))
/* out param: u32* backlight value: 0 to 31 */
#define PMU_IOC_GET_MODEL _IOR('B', 3, sizeof(__u32*))
+/* out param: u32* has_adb: 0 or 1 */
+#define PMU_IOC_HAS_ADB _IOR('B', 4, sizeof(__u32*))
#ifdef __KERNEL__
#include <asm/residual.h>
/* Bit encodings for Machine State Register (MSR) */
+#define MSR_VEC (1<<25) /* Enable Altivec */
#define MSR_POW (1<<18) /* Enable Power Management */
#define MSR_TGPR (1<<17) /* TLB Update registers in use */
#define MSR_ILE (1<<16) /* Interrupt Little-Endian enable */
#define HID0_DCI (1<<10) /* Data Cache Invalidate */
#define HID0_SPD (1<<9) /* Speculative disable */
#define HID0_SIED (1<<7) /* Serial Instruction Execution [Disable] */
+#define HID0_SGE (1<<7) /* Store Gathering Enable */
+#define HID0_BTIC (1<<5) /* Branch Target Instruction Cache Enable */
+#define HID0_ABE (1<<3) /* Address Broadcast Enable */
#define HID0_BHTE (1<<2) /* Branch History Table Enable */
#define HID0_BTCD (1<<1) /* Branch target cache disable */
#define EAR 282 /* External Address Register */
#define L2CR 1017 /* PPC 750 L2 control register */
+#define ICTC 1019
#define THRM1 1020
#define THRM2 1021
#define THRM3 1022
#define SR15 15
#ifndef __ASSEMBLY__
+#include <asm/types.h>
+
+#ifdef __KERNEL__
+
extern int _machine;
/* Temporary hacks until we can clean things up better - Corey */
double fpr[32]; /* Complete floating point set */
unsigned long fpscr_pad; /* fpr ... fpscr must be contiguous */
unsigned long fpscr; /* Floating point status */
+#ifdef CONFIG_ALTIVEC
+ vector128 vr[32]; /* Complete AltiVec set */
+ vector128 vscr; /* AltiVec status */
+ unsigned long vrsave;
+#endif /* CONFIG_ALTIVEC */
};
#define INIT_SP (sizeof(init_stack) + (unsigned long) &init_stack)
+#ifdef CONFIG_ALTIVEC
+#define INIT_TSS_AVEC {{{0}}}, {{0}}, 0,
+#else
+#define INIT_TSS_AVEC
+#endif /* CONFIG_ALTIVEC */
+
#define INIT_TSS { \
INIT_SP, /* ksp */ \
(unsigned long *) swapper_pg_dir, /* pg_tables */ \
(struct pt_regs *)INIT_SP - 1, /* regs */ \
KERNEL_DS, /*fs*/ \
0, /* last_syscall */ \
- {0}, 0, 0 \
+ {0}, 0, 0, \
+ INIT_TSS_AVEC \
}
/*
#endif /* ndef ASSEMBLY*/
-
+#endif /* __KERNEL__ */
+
#endif /* __ASM_PPC_PROCESSOR_H */
extern struct device_node *find_path_device(const char *path);
extern struct device_node *find_compatible_devices(const char *type,
const char *compat);
+extern struct device_node *find_pci_device_OFnode(unsigned char bus,
+ unsigned char dev_fn);
extern struct device_node *find_phandle(phandle);
+extern struct device_node *find_all_nodes(void);
extern int device_is_compatible(struct device_node *device, const char *);
extern int machine_is_compatible(const char *compat);
extern unsigned char *get_property(struct device_node *node, const char *name,
extern void pmac_find_display(void);
extern void giveup_fpu(struct task_struct *);
extern void enable_kernel_fp(void);
+extern void giveup_altivec(struct task_struct *);
extern void cvt_fd(float *from, double *to, unsigned long *fpscr);
extern void cvt_df(double *from, float *to, unsigned long *fpscr);
extern int call_rtas(const char *, int, int, unsigned long *, ...);
#define ICRNL 0000400
#define IXON 0001000
#define IXOFF 0002000
-#if defined(__KERNEL__) || defined(__USE_BSD)
- /* POSIX.1 doesn't want these... */
-# define IXANY 0004000
-# define IUCLC 0010000
-# define IMAXBEL 0020000
-#endif
+#define IXANY 0004000
+#define IUCLC 0010000
+#define IMAXBEL 0020000
/* c_oflag bits */
#define OPOST 0000001
typedef signed long long s64;
typedef unsigned long long u64;
+typedef struct {
+ u32 u[4];
+} __attribute((aligned(16))) vector128;
+
#define BITS_PER_LONG 32
#endif /* __KERNEL__ */
struct linux_pbm_info;
+extern volatile u64 *pci_dma_wsync;
+
/* This is what we use to determine what the PROM has assigned so
* far, so that we can perform assignments for addresses which
* were not taken care of by OBP. See psycho.c for details.
/*
* Wait for more memory for a socket
+ *
+ * If we got here an allocation has failed on us. We cannot
+ * spin here or we may block the very code freeing memory
+ * for us.
*/
static void wait_for_tcp_memory(struct sock * sk)
{
release_sock(sk);
if (!tcp_memory_free(sk)) {
struct wait_queue wait = { current, NULL };
-
sk->socket->flags &= ~SO_NOSPACE;
add_wait_queue(sk->sleep, &wait);
for (;;) {
current->state = TASK_RUNNING;
remove_wait_queue(sk->sleep, &wait);
}
+ else
+ {
+ /* Yield time to the memory freeing paths */
+ current->state = TASK_INTERRUPTIBLE;
+ schedule_timeout(1);
+ }
lock_sock(sk);
}