diff options
author | Ralf Baechle <ralf@linux-mips.org> | 1998-05-07 02:55:41 +0000 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 1998-05-07 02:55:41 +0000 |
commit | dcec8a13bf565e47942a1751a9cec21bec5648fe (patch) | |
tree | 548b69625b18cc2e88c3e68d0923be546c9ebb03 /drivers/macintosh | |
parent | 2e0f55e79c49509b7ff70ff1a10e1e9e90a3dfd4 (diff) |
o Merge with Linux 2.1.99.
o Fix ancient bug in the ELF loader making ldd crash.
o Fix ancient bug in the keyboard code for SGI, SNI and Jazz.
Diffstat (limited to 'drivers/macintosh')
-rw-r--r-- | drivers/macintosh/Makefile | 13 | ||||
-rw-r--r-- | drivers/macintosh/adb.c | 325 | ||||
-rw-r--r-- | drivers/macintosh/ati-gx.h | 81 | ||||
-rw-r--r-- | drivers/macintosh/aty.c | 29 | ||||
-rw-r--r-- | drivers/macintosh/chips.c | 43 | ||||
-rw-r--r-- | drivers/macintosh/control.c | 22 | ||||
-rw-r--r-- | drivers/macintosh/imstt.c | 759 | ||||
-rw-r--r-- | drivers/macintosh/imstt.h | 7 | ||||
-rw-r--r-- | drivers/macintosh/mac_keyb.c | 294 | ||||
-rw-r--r-- | drivers/macintosh/macio-adb.c | 12 | ||||
-rw-r--r-- | drivers/macintosh/macserial.c | 453 | ||||
-rw-r--r-- | drivers/macintosh/mediabay.c | 236 | ||||
-rw-r--r-- | drivers/macintosh/platinum.c | 20 | ||||
-rw-r--r-- | drivers/macintosh/pmac-cons.c | 42 | ||||
-rw-r--r-- | drivers/macintosh/valkyrie.c | 24 | ||||
-rw-r--r-- | drivers/macintosh/via-cuda.c | 28 | ||||
-rw-r--r-- | drivers/macintosh/via-pmu.c | 669 |
17 files changed, 2453 insertions, 604 deletions
diff --git a/drivers/macintosh/Makefile b/drivers/macintosh/Makefile index 2d280d4c8..116a1d98e 100644 --- a/drivers/macintosh/Makefile +++ b/drivers/macintosh/Makefile @@ -14,7 +14,10 @@ MOD_SUB_DIRS := $(SUB_DIRS) L_TARGET := macintosh.a M_OBJS := -L_OBJS := via-cuda.o adb.o nvram.o macio-adb.o + +ifndef CONFIG_MBX +L_OBJS := via-cuda.o adb.o nvram.o macio-adb.o via-pmu.o mediabay.o +endif ifeq ($(CONFIG_SERIAL)$(CONFIG_PMAC),yy) LX_OBJS += macserial.o @@ -25,7 +28,7 @@ else endif ifdef CONFIG_MAC_KEYBOARD -L_OBJS += mac_keyb.o mackeymap.o +L_OBJS += mac_keyb.o endif ifdef CONFIG_VT @@ -54,5 +57,7 @@ endif include $(TOPDIR)/Rules.make -mackeymap.c: mackeymap.map - loadkeys --mktable mackeymap.map > mackeymap.c +# Integrated in mac_keyb.c +# mackeymap.map is retained for historical reasons +#mackeymap.c: mackeymap.map +# loadkeys --mktable mackeymap.map > mackeymap.c diff --git a/drivers/macintosh/adb.c b/drivers/macintosh/adb.c index 945c7d456..c20efde6b 100644 --- a/drivers/macintosh/adb.c +++ b/drivers/macintosh/adb.c @@ -10,18 +10,23 @@ #include <linux/malloc.h> #include <linux/fs.h> #include <linux/mm.h> +#include <linux/sched.h> #include <asm/prom.h> #include <asm/adb.h> #include <asm/cuda.h> +#include <asm/pmu.h> #include <asm/uaccess.h> #include <asm/hydra.h> enum adb_hw adb_hardware; int (*adb_send_request)(struct adb_request *req, int sync); int (*adb_autopoll)(int on); +static void adb_scan_bus(void); static struct adb_handler { void (*handler)(unsigned char *, int, struct pt_regs *, int); + int original_address; + int handler_id; } adb_handler[16]; static int adb_nodev(void) @@ -29,17 +34,123 @@ static int adb_nodev(void) return -1; } +#if 0 +static void printADBreply(struct adb_request *req) +{ + int i; + + printk("adb reply (%d)", req->reply_len); + for(i = 0; i < req->reply_len; i++) + printk(" %x", req->reply[i]); + printk("\n"); + +} +#endif + +static void adb_scan_bus(void) +{ + int i, highFree=0, noMovement; + struct adb_request req; + + /* reset ADB bus */ + /*adb_request(&req, NULL, ADBREQ_SYNC, 1, 0);*/ + + /* assumes adb_handler[] is all zeroes at this point */ + for (i = 1; i < 16; i++) { + /* see if there is anything at address i */ + adb_request(&req, NULL, ADBREQ_SYNC | ADBREQ_REPLY, 1, + (i << 4) | 0xf); + if (req.reply_len > 1) + /* one or more devices at this address */ + adb_handler[i].original_address = i; + else if (i > highFree) + highFree = i; + } + + /* Note we reset noMovement to 0 each time we move a device */ + for (noMovement = 1; noMovement < 2 && highFree > 0; noMovement++) { + for (i = 1; i < 16; i++) { + if (adb_handler[i].original_address == 0) + continue; + /* + * Send a "talk register 3" command to address i + * to provoke a collision if there is more than + * one device at this address. + */ + adb_request(&req, NULL, ADBREQ_SYNC | ADBREQ_REPLY, 1, + (i << 4) | 0xf); + /* + * Move the device(s) which didn't detect a + * collision to address `highFree'. Hopefully + * this only moves one device. + */ + adb_request(&req, NULL, ADBREQ_SYNC, 3, + (i<< 4) | 0xb, (highFree | 0x60), 0xfe); + /* + * Test whether there are any device(s) left + * at address i. + */ + adb_request(&req, NULL, ADBREQ_SYNC | ADBREQ_REPLY, 1, + (i << 4) | 0xf); + if (req.reply_len > 1) { + /* + * There are still one or more devices + * left at address i. Register the one(s) + * we moved to `highFree', and find a new + * value for highFree. + */ + adb_handler[highFree].original_address = + adb_handler[i].original_address; + while (highFree > 0 && + adb_handler[highFree].original_address) + highFree--; + if (highFree <= 0) + break; + + noMovement = 0; + } + else { + /* + * No devices left at address i; move the + * one(s) we moved to `highFree' back to i. + */ + adb_request(&req, NULL, ADBREQ_SYNC, 3, + (highFree << 4) | 0xb, + (i | 0x60), 0xfe); + } + } + } + + /* Now fill in the handler_id field of the adb_handler entries. */ + printk(KERN_DEBUG "adb devices:"); + for (i = 1; i < 16; i++) { + if (adb_handler[i].original_address == 0) + continue; + adb_request(&req, NULL, ADBREQ_SYNC | ADBREQ_REPLY, 1, + (i << 4) | 0xf); + adb_handler[i].handler_id = req.reply[2]; + printk(" [%d]: %d %x", i, adb_handler[i].original_address, + adb_handler[i].handler_id); + } + printk("\n"); +} + void adb_init(void) { adb_hardware = ADB_NONE; adb_send_request = (void *) adb_nodev; adb_autopoll = (void *) adb_nodev; + if ( (_machine != _MACH_chrp) && (_machine != _MACH_Pmac) ) + return; via_cuda_init(); + via_pmu_init(); macio_adb_init(); if (adb_hardware == ADB_NONE) printk(KERN_WARNING "Warning: no ADB interface detected\n"); - else + else { + adb_scan_bus(); adb_autopoll(1); + } } int @@ -67,12 +178,25 @@ adb_request(struct adb_request *req, void (*done)(struct adb_request *), /* Ultimately this should return the number of devices with the given default id. */ int -adb_register(int default_id, +adb_register(int default_id, int handler_id, struct adb_ids *ids, void (*handler)(unsigned char *, int, struct pt_regs *, int)) { - if (adb_handler[default_id].handler != 0) - panic("Two handlers for ADB device %d\n", default_id); - adb_handler[default_id].handler = handler; + int i; + + ids->nids = 0; + for (i = 1; i < 16; i++) { + if ((adb_handler[i].original_address == default_id) || + (adb_handler[i].handler_id == handler_id)) { + if (adb_handler[i].handler != 0) { + printk(KERN_ERR + "Two handlers for ADB device %d\n", + default_id); + return 0; + } + adb_handler[i].handler = handler; + ids->id[ids->nids++] = i; + } + } return 1; } @@ -103,44 +227,40 @@ adb_input(unsigned char *buf, int nb, struct pt_regs *regs, int autopoll) extern void adbdev_init(void); struct adbdev_state { - struct adb_request req; + spinlock_t lock; + atomic_t n_pending; + struct adb_request *completed; + struct wait_queue *wait_queue; + int inuse; }; -static struct wait_queue *adb_wait; - -static int adb_wait_reply(struct adbdev_state *state, struct file *file) -{ - int ret = 0; - struct wait_queue wait = { current, NULL }; - - add_wait_queue(&adb_wait, &wait); - current->state = TASK_INTERRUPTIBLE; - - while (!state->req.complete) { - if (file->f_flags & O_NONBLOCK) { - ret = -EAGAIN; - break; - } - if (signal_pending(current)) { - ret = -ERESTARTSYS; - break; - } - schedule(); - } - - current->state = TASK_RUNNING; - remove_wait_queue(&adb_wait, &wait); - - return ret; -} - static void adb_write_done(struct adb_request *req) { + struct adbdev_state *state = (struct adbdev_state *) req->arg; + unsigned long flags; + if (!req->complete) { req->reply_len = 0; req->complete = 1; } - wake_up_interruptible(&adb_wait); + spin_lock_irqsave(&state->lock, flags); + atomic_dec(&state->n_pending); + if (!state->inuse) { + kfree(req); + if (atomic_read(&state->n_pending) == 0) { + spin_unlock_irqrestore(&state->lock, flags); + kfree(state); + return; + } + } else { + struct adb_request **ap = &state->completed; + while (*ap != NULL) + ap = &(*ap)->next; + req->next = NULL; + *ap = req; + wake_up_interruptible(&state->wait_queue); + } + spin_unlock_irqrestore(&state->lock, flags); } static int adb_open(struct inode *inode, struct file *file) @@ -153,20 +273,31 @@ static int adb_open(struct inode *inode, struct file *file) if (state == 0) return -ENOMEM; file->private_data = state; - state->req.reply_expected = 0; + spin_lock_init(&state->lock); + atomic_set(&state->n_pending, 0); + state->completed = NULL; + state->wait_queue = NULL; + state->inuse = 1; + return 0; } static int adb_release(struct inode *inode, struct file *file) { struct adbdev_state *state = file->private_data; + unsigned long flags; if (state) { file->private_data = NULL; - if (state->req.reply_expected && !state->req.complete) - if (adb_wait_reply(state, file)) - return 0; - kfree(state); + spin_lock_irqsave(&state->lock, flags); + if (atomic_read(&state->n_pending) == 0 + && state->completed == NULL) { + spin_unlock_irqrestore(&state->lock, flags); + kfree(state); + } else { + state->inuse = 0; + spin_unlock_irqrestore(&state->lock, flags); + } } return 0; } @@ -181,27 +312,57 @@ static ssize_t adb_read(struct file *file, char *buf, { int ret; struct adbdev_state *state = file->private_data; + struct adb_request *req; + struct wait_queue wait = { current, NULL }; + unsigned long flags; if (count < 2) return -EINVAL; - if (count > sizeof(state->req.reply)) - count = sizeof(state->req.reply); + if (count > sizeof(req->reply)) + count = sizeof(req->reply); ret = verify_area(VERIFY_WRITE, buf, count); if (ret) return ret; - if (!state->req.reply_expected) - return 0; + req = NULL; + add_wait_queue(&state->wait_queue, &wait); + current->state = TASK_INTERRUPTIBLE; + + for (;;) { + spin_lock_irqsave(&state->lock, flags); + req = state->completed; + if (req != NULL) + state->completed = req->next; + else if (atomic_read(&state->n_pending) == 0) + ret = -EIO; + spin_unlock_irqrestore(&state->lock, flags); + if (req != NULL || ret != 0) + break; + + if (file->f_flags & O_NONBLOCK) { + ret = -EAGAIN; + break; + } + if (signal_pending(current)) { + ret = -ERESTARTSYS; + break; + } + schedule(); + } + + current->state = TASK_RUNNING; + remove_wait_queue(&state->wait_queue, &wait); - ret = adb_wait_reply(state, file); if (ret) return ret; - state->req.reply_expected = 0; - ret = state->req.reply_len; - if (copy_to_user(buf, state->req.reply, ret)) - return -EFAULT; + ret = req->reply_len; + if (ret > count) + ret = count; + if (ret > 0 && copy_to_user(buf, req->reply, ret)) + ret = -EFAULT; + kfree(req); return ret; } @@ -210,46 +371,64 @@ static ssize_t adb_write(struct file *file, const char *buf, { int ret, i; struct adbdev_state *state = file->private_data; + struct adb_request *req; - if (count < 2 || count > sizeof(state->req.data)) + if (count < 2 || count > sizeof(req->data)) return -EINVAL; ret = verify_area(VERIFY_READ, buf, count); if (ret) return ret; - if (state->req.reply_expected && !state->req.complete) { - /* A previous request is still being processed. - Wait for it to finish. */ - ret = adb_wait_reply(state, file); - if (ret) - return ret; - } + req = (struct adb_request *) kmalloc(sizeof(struct adb_request), + GFP_KERNEL); + if (req == NULL) + return -ENOMEM; - state->req.nbytes = count; - state->req.done = adb_write_done; - state->req.complete = 0; - if (copy_from_user(state->req.data, buf, count)) - return -EFAULT; + req->nbytes = count; + req->done = adb_write_done; + req->arg = (void *) state; + req->complete = 0; + ret = -EFAULT; + if (copy_from_user(req->data, buf, count)) + goto out; + + atomic_inc(&state->n_pending); switch (adb_hardware) { case ADB_NONE: - return -ENXIO; + ret = -ENXIO; + break; case ADB_VIACUDA: - state->req.reply_expected = 1; - cuda_send_request(&state->req); + req->reply_expected = 1; + ret = cuda_send_request(req); break; + case ADB_VIAPMU: + if (req->data[0] != ADB_PACKET) { + ret = pmu_send_request(req); + break; + } + /* else fall through */ default: - if (state->req.data[0] != ADB_PACKET) - return -EINVAL; - for (i = 1; i < state->req.nbytes; ++i) - state->req.data[i] = state->req.data[i+1]; - state->req.reply_expected = - ((state->req.data[0] & 0xc) == 0xc); - adb_send_request(&state->req, 0); + ret = -EINVAL; + if (req->data[0] != ADB_PACKET) + break; + for (i = 0; i < req->nbytes-1; ++i) + req->data[i] = req->data[i+1]; + req->nbytes--; + req->reply_expected = ((req->data[0] & 0xc) == 0xc); + ret = adb_send_request(req, 0); break; } + if (ret != 0) { + atomic_dec(&state->n_pending); + goto out; + } return count; + +out: + kfree(req); + return ret; } static struct file_operations adb_fops = { @@ -266,6 +445,8 @@ static struct file_operations adb_fops = { void adbdev_init() { + if ( (_machine != _MACH_chrp) && (_machine != _MACH_Pmac) ) + return; if (register_chrdev(ADB_MAJOR, "adb", &adb_fops)) printk(KERN_ERR "adb: unable to get major %d\n", ADB_MAJOR); } diff --git a/drivers/macintosh/ati-gx.h b/drivers/macintosh/ati-gx.h index b986cc38e..df48c1865 100644 --- a/drivers/macintosh/ati-gx.h +++ b/drivers/macintosh/ati-gx.h @@ -1,64 +1,37 @@ -#if 0 /* not filled inaty_gt_reg_init yet */ -/* Register values for 1280x1024, 75Hz mode (20) */ +/* Register values for 1280x1024, 75Hz (WAS 60) mode (20) */ static struct aty_regvals aty_gx_reg_init_20 = { - { 0x10, 0x28, 0x3c }, - { }, - { } /* pixel clock = 134.61MHz for V=74.81Hz */ -}; + { 0x200, 0x200, 0x200 }, -/* Register values for 1280x960, 75Hz mode (19) */ -static struct aty_regvals aty_gx_reg_init_19 = { - { 0x10, 0x28, 0x3c }, - { }, - { } /* pixel clock = 126.01MHz for V=75.01 Hz */ -}; + { 0x1200a5, 0x1200a3, 0x1200a3 }, + { 0x30c0200, 0x30e0300, 0x30e0300 }, + { 0x2, 0x3, 0x3 }, + + 0x9f00d2, 0x3ff0429, 0x30400, 0x28100040, + { 0xd4, 0x9 } +}; /* Register values for 1152x870, 75Hz mode (18) */ static struct aty_regvals aty_gx_reg_init_18 = { - { 0x10, 0x28, 0x50 }, - { }, - { } /* pixel clock = 100.33MHz for V=75.31Hz */ -}; + { 0x200, 0x200, 0x200 }, -/* Register values for 1024x768, 75Hz mode (17) */ -static struct aty_regvals aty_gx_reg_init_17 = { - { 0x10, 0x28, 0x50 }, - { }, - { } /* pixel clock = 79.55MHz for V=74.50Hz */ -}; + { 0x300097, 0x300095, 0x300094 }, + { 0x3090200, 0x30e0300, 0x30e0600 }, + { 0x2, 0x3, 0x6 }, -/* Register values for 1024x768, 72Hz mode (15) */ -static struct aty_regvals aty_gx_reg_init_15 = { - { 0x10, 0x28, 0x50 }, - { }, - { } /* pixel clock = 78.12MHz for V=72.12Hz */ + 0x8f00b5, 0x3650392, 0x230368, 0x24100040, + { 0x53, 0x3 } }; -#endif - - -/* Register values for 1280x1024, 60Hz mode (20) */ -static struct aty_regvals aty_gx_reg_init_20 = { - { 0, 0, 0 }, - - { 0x310086, 0x310084, 0x310084 }, - { 0x3070200, 0x30e0300, 0x30e0300 }, - { 0x2002312, 0x3002312, 0x3002312 }, - - 0x7f00a5, 0x2ff0325, 0x260302, 0x20100000, - { 0x88, 0x7 } -}; - /* Register values for 1024x768, 75Hz mode (17) */ static struct aty_regvals aty_gx_reg_init_17 = { - { 0, 0, 0 }, + { 0x200, 0x200, 0x200 }, - { 0xc0085, 0xc0083, 0xc0083 }, - { 0x3070200, 0x30e0300, 0x30e0300 }, - { 0x2002312, 0x3002312, 0x3002312 }, + { 0x2c0087, 0x2c0085, 0x2c0084 }, + { 0x3070200, 0x30e0300, 0x30e0600 }, + { 0x2, 0x3, 0x6 }, - 0x7f00a3, 0x2ff031f, 0x30300, 0x20100000, - { 0x41, 0x3 } + 0x7f00a5, 0x2ff0323, 0x230302, 0x20100000, + { 0x42, 0x3 } }; /* Register values for 1024x768, 72Hz mode (15) */ @@ -87,14 +60,14 @@ static struct aty_regvals aty_gx_reg_init_14 = { /* Register values for 832x624, 75Hz mode (13) */ static struct aty_regvals aty_gx_reg_init_13 = { - { 0x200, 0x200, 0x200 }, + { 0x200, 0x200, 0x200 }, - { 0x28006f, 0x28006d, 0x28006c }, - { 0x3050200, 0x30b0300, 0x30e0600 }, - { 0x2002312, 0x3002312, 0x6002312 }, + { 0x28006f, 0x28006d, 0x28006c }, + { 0x3050200, 0x30b0300, 0x30e0600 }, + { 0x2, 0x3, 0x6 }, - 0x67008f, 0x26f029a, 0x230270, 0x1a100040, - { 0x4f, 0x05 } + 0x67008f, 0x26f029a, 0x230270, 0x1a100040, + { 0x4f, 0x5 } }; #if 0 /* not filled in yet */ diff --git a/drivers/macintosh/aty.c b/drivers/macintosh/aty.c index ec70b4a50..7bd48052b 100644 --- a/drivers/macintosh/aty.c +++ b/drivers/macintosh/aty.c @@ -18,12 +18,12 @@ #include <linux/string.h> #include <linux/vc_ioctl.h> #include <linux/pci.h> -#include <linux/bios32.h> #include <linux/nvram.h> #include <linux/selection.h> #include <linux/vt_kern.h> #include <asm/prom.h> #include <asm/io.h> +#include <asm/pgtable.h> #include <asm/pci-bridge.h> #include "pmac-cons.h" #include "aty.h" @@ -61,10 +61,12 @@ static int aty_vram_reqd(int vmode, int cmode); static aty_regvals *get_aty_struct(void); static unsigned char *frame_buffer; +static unsigned long frame_buffer_phys; static int total_vram; /* total amount of video memory, bytes */ static int chip_type; /* what chip type was detected */ static unsigned long ati_regbase; +static unsigned long ati_regbase_phys; static struct aty_cmap_regs *aty_cmap_regs; #if 0 @@ -126,7 +128,8 @@ static struct aty_regvals *aty_gx_reg_init[20] = { &aty_gx_reg_init_15, NULL, &aty_gx_reg_init_17, - NULL, NULL, + &aty_gx_reg_init_18, + NULL, &aty_gx_reg_init_20 }; @@ -323,7 +326,8 @@ map_aty_display(struct device_node *dp) printk("Warning: expecting 1 or 3 addresses for ATY (got %d)", dp->n_addrs); - ati_regbase = (int) ioremap((0x7ffc00 + dp->addrs[0].address), 0x1000); + ati_regbase_phys = 0x7ffc00 + dp->addrs[0].address; + ati_regbase = (int) ioremap(ati_regbase_phys, 0x1000); aty_cmap_regs = (struct aty_cmap_regs *) (ati_regbase + 0xC0); /* enable memory-space accesses using config-space command register */ @@ -384,12 +388,12 @@ map_aty_display(struct device_node *dp) total_vram = 0x80000; } -#if 1 +#if 0 printk("aty_display_init: node = %p, addrs = ", dp->node); printk(" %x(%x)", dp->addrs[0].address, dp->addrs[0].size); printk(", intrs ="); for (i = 0; i < dp->n_intrs; ++i) - printk(" %x", dp->intrs[i]); + printk(" %x", dp->intrs[i].line); printk("\nregbase: %x pci loc: %x:%x total_vram: %x cregs: %x\n", (int) ati_regbase, bus, devfn, total_vram, (int) aty_cmap_regs); #endif @@ -398,10 +402,11 @@ map_aty_display(struct device_node *dp) /* use the big-endian aperture (??) */ addr += 0x800000; - frame_buffer = ioremap(addr, 0x800000); + frame_buffer_phys = addr; + frame_buffer = __ioremap(addr, 0x800000, _PAGE_WRITETHRU); sense = read_aty_sense(); - printk("monitor sense = %x\n", sense); + printk(KERN_INFO "monitor sense = %x\n", sense); if (video_mode == VMODE_NVRAM) { video_mode = nvram_read_byte(NV_VMODE); init = get_aty_struct(); @@ -720,11 +725,11 @@ aty_init() break; } display_info.fb_address = (chip_type != MACH64_GT_ID) ? - (unsigned long) frame_buffer + init->offset[color_mode] : - (unsigned long) frame_buffer; - display_info.cmap_adr_address = (unsigned long) &aty_cmap_regs->windex; - display_info.cmap_data_address = (unsigned long) &aty_cmap_regs->lut; - display_info.disp_reg_address = ati_regbase; + frame_buffer_phys + init->offset[color_mode] : + frame_buffer_phys; + display_info.cmap_adr_address = ati_regbase_phys + 0xc0; + display_info.cmap_data_address = ati_regbase_phys + 0xc1; + display_info.disp_reg_address = ati_regbase_phys; } int diff --git a/drivers/macintosh/chips.c b/drivers/macintosh/chips.c index d959608cb..d60abe84f 100644 --- a/drivers/macintosh/chips.c +++ b/drivers/macintosh/chips.c @@ -14,10 +14,13 @@ #include <linux/string.h> #include <linux/vc_ioctl.h> #include <linux/pci.h> -#include <linux/bios32.h> #include <linux/selection.h> #include <asm/prom.h> #include <asm/io.h> +#include <asm/pgtable.h> +#include <asm/adb.h> +#include <asm/cuda.h> +#include <asm/pmu.h> #include <asm/pci-bridge.h> #include "pmac-cons.h" #include "chips.h" @@ -26,6 +29,8 @@ static unsigned char *frame_buffer; static unsigned char *blitter_regs; static unsigned char *io_space; +static unsigned long chips_base_phys; +static unsigned long chips_io_phys; void map_chips_display(struct device_node *dp) @@ -35,17 +40,21 @@ map_chips_display(struct device_node *dp) unsigned long addr; addr = dp->addrs[0].address; - frame_buffer = ioremap(addr + 0x800000, 0x100000); + chips_base_phys = addr; + frame_buffer = __ioremap(addr + 0x800000, 0x100000, _PAGE_WRITETHRU); blitter_regs = ioremap(addr + 0xC00000, 4096); - printk("Mapped chips65550 frame buffer at %p, blitter at %p\n", frame_buffer, blitter_regs); + printk("Mapped chips65550 frame buffer at %p, blitter at %p\n", + frame_buffer, blitter_regs); if (pci_device_loc(dp, &bus, &devfn) == 0) { pcibios_read_config_word(bus, devfn, PCI_COMMAND, &cmd); cmd |= 3; // enable memory and IO space pcibios_write_config_word(bus, devfn, PCI_COMMAND, cmd); - io_space = ioremap((unsigned long) pci_io_base(bus), 4096); - printk("Mapped chips65550 IO space at %p\n", io_space); + io_space = (unsigned char *) pci_io_base(bus); + /* XXX really want the physical address here */ + chips_io_phys = (unsigned long) pci_io_base(bus); + printk("Chips65550 IO space at %p\n", io_space); } video_mode = VMODE_800_600_60; @@ -65,11 +74,15 @@ chips_init() unsigned *p; int i, hres; - if (video_mode != VMODE_800_600_60) - panic("chips65550: display mode %d not supported", video_mode); + if (video_mode != VMODE_800_600_60) { + printk(KERN_ERR "chips65550: display mode %d not supported", video_mode); + video_mode = VMODE_800_600_60; + } - if (color_mode != CMODE_8 && color_mode != CMODE_16) - panic("chips65550: color mode %d not supported", color_mode); + if (color_mode != CMODE_8 && color_mode != CMODE_16) { + printk(KERN_ERR "chips65550: color mode %d not supported", color_mode); + color_mode = CMODE_8; + } n_scanlines = 600; hres = 800; @@ -106,15 +119,18 @@ chips_init() display_info.pitch = line_pitch; display_info.mode = video_mode; strncpy(display_info.name, "chips65550", sizeof(display_info.name)); - display_info.fb_address = (unsigned long) frame_buffer; - display_info.cmap_adr_address = 0; - display_info.cmap_data_address = 0; - display_info.disp_reg_address = 0; + display_info.fb_address = chips_base_phys + 0x800000; + display_info.cmap_adr_address = chips_io_phys + 0x3c8; + display_info.cmap_data_address = chips_io_phys + 0x3c9; + display_info.disp_reg_address = chips_base_phys + 0xC00000; /* Clear screen */ p = (unsigned *) frame_buffer; for (i = n_scanlines * line_pitch / sizeof(unsigned); i != 0; --i) *p++ = 0; + + /* Turn on backlight */ + pmu_enable_backlight(1); } int @@ -164,4 +180,5 @@ chips_set_palette(unsigned char red[], unsigned char green[], void chips_set_blanking(int blank_mode) { + pmu_enable_backlight(blank_mode == VESA_NO_BLANKING); } diff --git a/drivers/macintosh/control.c b/drivers/macintosh/control.c index 4f6e6c84b..9db048a4a 100644 --- a/drivers/macintosh/control.c +++ b/drivers/macintosh/control.c @@ -18,6 +18,7 @@ #include <asm/io.h> #include <asm/adb.h> #include <asm/cuda.h> +#include <asm/pgtable.h> #include <linux/selection.h> #include "pmac-cons.h" #include "control.h" @@ -88,6 +89,10 @@ static struct cmap_regs *cmap_regs; static struct control_regs *disp_regs; static int control_use_bank2; +static unsigned long frame_buffer_phys; +static unsigned long disp_regs_phys; +static unsigned long cmap_regs_phys; + /* * Register initialization tables for the control display. * @@ -317,7 +322,7 @@ map_control_display(struct device_node *dp) printk(" %x(%x)", dp->addrs[i].address, dp->addrs[i].size); printk(", intrs ="); for (i = 0; i < dp->n_intrs; ++i) - printk(" %x", dp->intrs[i]); + printk(" %x", dp->intrs[i].line); printk("\n"); #endif @@ -329,12 +334,15 @@ map_control_display(struct device_node *dp) /* use the big-endian aperture (??) */ addr += 0x800000; /* map at most 8MB for the frame buffer */ - frame_buffer = ioremap(addr, 0x800000); + frame_buffer_phys = addr; + frame_buffer = __ioremap(addr, 0x800000, _PAGE_WRITETHRU); } else { + disp_regs_phys = addr; disp_regs = ioremap(addr, size); } } - cmap_regs = ioremap(0xf301b000, 0x1000); /* XXX not in prom? */ + cmap_regs_phys = 0xf301b000; /* XXX not in prom? */ + cmap_regs = ioremap(cmap_regs_phys, 0x1000); /* Work out which banks of VRAM we have installed. */ frame_buffer[0] = 0x5a; @@ -454,10 +462,10 @@ control_init() display_info.pitch = line_pitch; display_info.mode = video_mode; strncpy(display_info.name, "control", sizeof(display_info.name)); - display_info.fb_address = (unsigned long) frame_buffer + init->offset[color_mode]; - display_info.cmap_adr_address = (unsigned long) &cmap_regs->addr; - display_info.cmap_data_address = (unsigned long) &cmap_regs->lut; - display_info.disp_reg_address = (unsigned long) &disp_regs; + display_info.fb_address = frame_buffer_phys + init->offset[color_mode]; + display_info.cmap_adr_address = cmap_regs_phys; + display_info.cmap_data_address = cmap_regs_phys + 0x30; + display_info.disp_reg_address = disp_regs_phys; } int diff --git a/drivers/macintosh/imstt.c b/drivers/macintosh/imstt.c index 2f74a153c..0cf18edc7 100644 --- a/drivers/macintosh/imstt.c +++ b/drivers/macintosh/imstt.c @@ -2,28 +2,39 @@ * imstt.c: Console support for PowerMac "imstt" display adaptor. * * Copyright (C) 1997 Sigurdur Asgeirsson + * Modified by Danilo Beuche 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 <linux/module.h> + #include <linux/kernel.h> #include <linux/sched.h> #include <linux/delay.h> #include <linux/string.h> #include <linux/vc_ioctl.h> #include <linux/pci.h> -#include <linux/bios32.h> #include <linux/nvram.h> #include <asm/prom.h> #include <asm/io.h> +#include <asm/pgtable.h> #include <asm/pci-bridge.h> #include <linux/selection.h> #include <linux/vt_kern.h> #include "pmac-cons.h" #include "imstt.h" + +enum { + IBMRAMDAC = 0x00, + TVPRAMDAC = 0x01 +}; + + +// IMS TWIN TURBO enum { S1SA = 0, /* 0x00 */ @@ -79,6 +90,8 @@ enum #endif }; + +// IBM RAMDAC enum { PADDRW = 0x00, @@ -97,12 +110,256 @@ enum PC0 = 0x23 }; +// TI TVP 3030 RAMDAC Direct Registers +enum +{ + TVPADDRW = 0x00, // 0 Palette/Cursor RAM Write Adress/Index + TVPPDATA = 0x04, // 1 Palette Data RAM Data + TVPPMASK = 0x08, // 2 Pixel Read-Mask + TVPPADRR = 0x0c, // 3 Palette/Cursor RAM Read Adress + TVPCADRW = 0x10, // 4 Cursor/Overscan Color Write Address + TVPCDATA = 0x14, // 5 Cursor/Overscan Color Data + // 6 reserved + TVPCADRR = 0x1c, // 7 Cursor/Overscan Color Read Address + // 8 reserved + TVPDCCTL = 0x24, // 9 Direct Cursor Control + TVPIDATA = 0x28, // 10 Index Data + TVPCRDAT = 0x2c, // 11 Cursor RAM Data + TVPCXPOL = 0x30, // 12 Cursor-Position X LSB + TVPCXPOH = 0x34, // 13 Cursor-Position X MSB + TVPCYPOL = 0x38, // 14 Cursor-Position Y LSB + TVPCYPOH = 0x3c, // 15 Cursor-Position Y MSB +}; + +// TI TVP 3030 RAMDAC Indirect Registers +enum +{ + TVPIRREV = 0x01, // Silicon Revision [RO] + TVPIRICC = 0x06, // Indirect Cursor Control (0x00) + TVPIRBRC = 0x07, // Byte Router Control (0xe4) + TVPIRLAC = 0x0f, // Latch Control (0x06) + TVPIRTCC = 0x18, // True Color Control (0x80) + TVPIRMXC = 0x19, // Multiplex Control (0x98) + TVPIRCLS = 0x1a, // Clock Selection (0x07) + TVPIRPPG = 0x1c, // Palette Page (0x00) + TVPIRGEC = 0x1d, // General Control (0x00) + TVPIRMIC = 0x1e, // Miscellaneous Control (0x00) + TVPIRPLA = 0x2c, // PLL Address + TVPIRPPD = 0x2d, // Pixel Clock PLL Data + TVPIRMPD = 0x2e, // Memory Clock PLL Data + TVPIRLPD = 0x2f, // Loop Clock PLL Data + TVPIRCKL = 0x30, // Color-Key Overlay Low + TVPIRCKH = 0x31, // Color-Key Overlay High + TVPIRCRL = 0x32, // Color-Key Red Low + TVPIRCRH = 0x33, // Color-Key Red High + TVPIRCGL = 0x34, // Color-Key Green Low + TVPIRCGH = 0x35, // Color-Key Green High + TVPIRCBL = 0x36, // Color-Key Blue Low + TVPIRCBH = 0x37, // Color-Key Blue High + TVPIRCKC = 0x38, // Color-Key Control (0x00) + TVPIRMLC = 0x39, // MCLK/Loop Clock Control (0x18) + TVPIRSEN = 0x3a, // Sense Test (0x00) + TVPIRTMD = 0x3b, // Test Mode Data + TVPIRRML = 0x3c, // CRC Remainder LSB [RO] + TVPIRRMM = 0x3d, // CRC Remainder MSB [RO] + TVPIRRMS = 0x3e, // CRC Bit Select [WO] + TVPIRDID = 0x3f, // Device ID [RO] (0x30) + TVPIRRES = 0xff, // Software Reset [WO] + +}; + struct initvalues { unsigned char addr, value; }; -static struct initvalues initregs[] = + + +// Values which only depend on resolution not on color mode +struct tt_single_rmodevals +{ + unsigned short hes; + unsigned short heb; + unsigned short hsb; + unsigned short ht; + unsigned short ves; + unsigned short veb; + unsigned short vsb; + unsigned short vt; +}; + +struct tvp_single_rmodevals +{ + unsigned char pclk_n; + unsigned char pclk_m; + unsigned char pclk_p; +}; + +struct ibm_single_rmodevals +{ + unsigned char pclk_m; + unsigned char pclk_n; + unsigned char pclk_p; + unsigned char pclk_c; +}; + +// Values which only depend on color mode not on resolution +struct tvp_single_cmodevals +{ + unsigned char tcc; // True Color control + unsigned char mxc; // Multiplexer control + unsigned char lckl_n; // N value of LCKL PLL +}; + +struct ibm_single_cmodevals +{ + unsigned char pformat; // pixel format +}; + +// Values of the tvp which change depending on colormode x resolution +struct tvp_single_crmodevals +{ + unsigned char mlc; // Memory Loop Config 0x39 + unsigned char lckl_p; // P value of LCKL PLL +}; + +struct ibm_single_crmodevals +{ + // oh nothing changes +}; + +// complete configuration for a resolution in all depths +// 0 = 8 Bit, 15/16 bit = 1 , 32 Bit = 2 +struct ims_crmodevals +{ + int pitch; + struct tt_single_rmodevals tt[2]; // for each ramdac seperate tt config + + struct tvp_single_rmodevals tvp_clock; // for each ramdac seperate clock config + struct tvp_single_crmodevals tvp[3]; // for each colormode + + struct ibm_single_rmodevals ibm_clock; // for each ramdac seperate clock config +// struct ibm_single_crmodevals ibm[3]; // for each color mode +}; + +struct ims_modevals +{ + int dac; // which dac do we have + int total_vram; // how much vram is on board + int sense; // what monitor + unsigned char* fb; // frame buffer address + unsigned char* fb_phys; // frame buffer address + unsigned char* cmap; // dac address + unsigned char* cmap_phys; // dac address + unsigned int* dc; // tt address + unsigned int* dc_phys; // tt address + + struct initvalues* init[2]; // initial register settings for each ramdac + + struct ims_crmodevals* mode[20]; // for each possible mode + + struct tvp_single_cmodevals tvp[3]; // for each color mode + + struct ibm_single_cmodevals ibm[3]; // for each color mode +}; + + +struct ims_crmodevals imsmode_6 = +{ + 640, + { + { 0x08, 0x12, 0x62, 0x6C, 0x0003, 0x002A, 0x020A, 0x020C }, + { 0x04, 0x0009, 0x0031, 0x0036, 0x0003, 0x002a, 0x020a, 0x020d }, + }, + { 0xef, 0x2e, 0xb2 }, + { + { 0x39, 0xf3 }, + { 0x39, 0xf3 }, + { 0x38, 0xf3 } + }, + // IBM CLOCK + { 0x78, 0x13, 0x02, 0x02 }, +}; + +struct ims_crmodevals imsmode_13 = +{ + 832, + { + { 0x05, 0x20, 0x88, 0x90, 0x0003, 0x0028, 0x0298, 0x029B }, + { 0x04, 0x0011, 0x0045, 0x0048, 0x0003, 0x002a, 0x029a, 0x029b}, + }, + { 0xfe, 0x3e, 0xf1 }, + { + { 0x39, 0xf3 }, + { 0x38, 0xf3 }, + { 0x38, 0xf2 } + }, + { 0x3E, 0x0A, 0x01, 0x02 } +}; +struct ims_crmodevals imsmode_17 = +{ + 1024, + { + { 0x0A, 0x1C, 0x9C, 0xA6, 0x0003, 0x0020, 0x0320, 0x0323 } , + { 0x06, 0x0210, 0x0250, 0x0053, 0x1003, 0x0021, 0x0321, 0x0324 }, + }, + { 0xfc, 0x3a, 0xf1 }, + { + { 0x39, 0xf3 }, + { 0x38, 0xf3 }, + { 0x38, 0xf2 } + }, + { 0x07, 0x00, 0x01, 0x02 } +}; +struct ims_crmodevals imsmode_18 = +{ + 1152, + { + { 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0x09, 0x0011, 0x059, 0x5b, 0x0003, 0x0031, 0x0397, 0x039a }, + }, + { 0xfd, 0x3a, 0xf1 }, + { + { 0x39, 0xf3 }, + { 0x38, 0xf3 }, + { 0x38, 0xf2 } + }, + { 0, 0, 0, 0 } +}; +struct ims_crmodevals imsmode_19 = +{ + 1280, + { + { 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0x09, 0x0016, 0x0066, 0x0069, 0x0003, 0x0027, 0x03e7, 0x03e8 }, + }, + { 0xf7, 0x36, 0xf0 }, + { + { 0x38, 0xf3 }, + { 0x38, 0xf2 }, + { 0x38, 0xf1 } + }, + { 0, 0, 0, 0 } +}; +struct ims_crmodevals imsmode_20 = +{ + 1280, + { + { 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0x09, 0x0018, 0x0068, 0x006a, 0x0003, 0x0029, 0x0429, 0x042a }, + }, + { 0xf0, 0x2d, 0xf0 }, + { + { 0x38, 0xf3 }, + { 0x38, 0xf2 }, + { 0x38, 0xf1 } + }, + { 0, 0, 0, 0 } +}; + +// IBM RAMDAC initial register values + +static struct initvalues ibm_initregs[] = { { 0x02, 0x21 }, /* (0x01) Miscellaneous Clock Control */ { 0x03, 0x00 }, /* (0x00) Sync Control */ @@ -129,64 +386,114 @@ static struct initvalues initregs[] = { 0x71, 0x45 }, /* (0x00) Miscellaneous Control 2 */ { 0x72, 0x00 }, /* (0x00) Miscellaneous Control 3 */ { 0x78, 0x00 }, /* (0x00) Key Control/DB Operation */ + { 0x00, 0x00 } }; -static void set_imstt_clock(unsigned char *params); -static int read_imstt_sense(void); -static int imstt_vram_reqd(int vmode, int cmode); -static int total_vram = 2 * 1024 * 1024; /* total amount of video memory, bytes */ -static unsigned char *frame_buffer; -static unsigned char *cmap_regs; -static unsigned *dc_regs; +static struct initvalues tvp_initregs[] = +{ +{ 0x6, 0x00}, +{ 0x7, 0xe4}, +{ 0xf, 0x06}, +{ 0x18, 0x80}, +{ 0x19, 0x4d}, +{ 0x1a, 0x05}, +{ 0x1c, 0x00}, +{ 0x1d, 0x00}, +{ 0x1e, 0x08}, +{ 0x30, 0xff}, +{ 0x31, 0xff}, +{ 0x32, 0xff}, +{ 0x33, 0xff}, +{ 0x34, 0xff}, +{ 0x35, 0xff}, +{ 0x36, 0xff}, +{ 0x37, 0xff}, +{ 0x38, 0x00}, +{ TVPIRPLA, 0x00 }, +{ TVPIRPPD, 0xc0 }, +{ TVPIRPPD, 0xd5 }, +{ TVPIRPPD, 0xea }, +{ TVPIRPLA, 0x00 }, +{ TVPIRMPD, 0xb9 }, +{ TVPIRMPD, 0x3a }, +{ TVPIRMPD, 0xb1 }, +{ TVPIRPLA, 0x00 }, +{ TVPIRLPD, 0xc1 }, +{ TVPIRLPD, 0x3d }, +{ TVPIRLPD, 0xf3 }, +{ 0x00, 0x00 } +}; -/* - * Register initialization tables for the imstt display. - * - * Dot clock rate is 20MHz * (m + 1) / ((n + 1) * (p ? 2 * p : 1) - * where m = clk[0], n = clk[1], p = clk[2] - * clk[3] is c, charge pump bias which depends on the VCO frequency - */ -struct imstt_regvals { - unsigned short cfg[8]; - unsigned char clk[4]; - unsigned long pitch[3]; -} imsttmode; - -/* Register values for 1024x768, 75Hz mode (17) */ -static struct imstt_regvals imstt_reg_init_17 = { - { 0x0A, 0x1C, 0x9C, 0xA6, 0x0003, 0x0020, 0x0320, 0x0323 }, - { 0x07, 0x00, 0x01, 0x02 }, - { 0x0400, 0x0800, 0x1000 } -}; +static struct ims_modevals ims_info = +{ + -1, // DAC + -1, // VRAM + -1, // Monitor; + 0, // Framebuffer + 0, // Framebuffer_phys + 0, // colormap + 0, // colormap_phys + 0, // dc + 0, // dc_phys + { ibm_initregs, tvp_initregs}, + { + NULL, + NULL, + NULL, + NULL, + &imsmode_6, + &imsmode_6, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + &imsmode_13, + NULL, + NULL, + NULL, + &imsmode_17, + &imsmode_18, + &imsmode_19, + &imsmode_20 + }, + { + { 0x80, 0x4d, 0xc1 }, + { 0x44, 0x55, 0xe1 }, + { 0x46, 0x5d, 0xf1 } + }, + { + { 0x03 }, + { 0x04 }, + { 0x06 } + } +}; + + -/* Register values for 832x624, 75Hz mode (13) */ -static struct imstt_regvals imstt_reg_init_13 = { - { 0x05, 0x20, 0x88, 0x90, 0x0003, 0x0028, 0x0298, 0x029B }, - { 0x3E, 0x0A, 0x01, 0x02 }, - { 832, 832 * 2, 832 * 4 } -}; -/* Register values for 640x480, 67Hz mode (6) */ -static struct imstt_regvals imstt_reg_init_6 = { - { 0x08, 0x12, 0x62, 0x6C, 0x0003, 0x002A, 0x020A, 0x020C }, - { 0x78, 0x13, 0x02, 0x02 }, - { 640, 640 * 2, 640 * 4 } -}; +// static void set_imstt_clock(unsigned char *params); +static void map_imstt_display(struct device_node *, int); +static int read_imstt_sense(void); +static int imstt_vram_reqd(int vmode, int cmode); -static struct imstt_regvals *imstt_reg_init[20] = { - NULL, NULL, NULL, NULL, - &imstt_reg_init_6, // fake'm out - &imstt_reg_init_6, - NULL, NULL, NULL, - NULL, NULL, NULL, - &imstt_reg_init_13, - NULL, NULL, NULL, - &imstt_reg_init_17, - NULL, NULL, NULL -}; +#if 0 +static int get_tvp_ireg(int iaddr) +{ + ims_info.cmap[0] = iaddr & 0xff; eieio(); + return ims_info.cmap[40]; +} +#endif + +static void set_tvp_ireg(int iaddr,unsigned char value) +{ + ims_info.cmap[0] = iaddr & 0xff; eieio(); + ims_info.cmap[40] = value; eieio(); +} /* * Get the monitor sense value. * Note that this can be called before calibrate_delay, @@ -199,28 +506,28 @@ read_imstt_sense() int sense; unsigned gio, gioe; - gio = ld_le32(dc_regs + GIO) & ~0x0038; + gio = ld_le32(ims_info.dc + GIO) & ~0x0038; gioe = ld_le32(dc_ - out_le32(dc_regs + GIOE, reg); /* drive all lines high */ + out_le32(ims_info.dc + GIOE, reg); /* drive all lines high */ __delay(200); - out_le32(dc_regs + GIOE, 077); /* turn off drivers */ + out_le32(ims_info.dc + GIOE, 077); /* turn off drivers */ __delay(2000); - sense = (in_le32(dc_regs + GIOE) & 0x1c0) << 2; + sense = (in_le32(ims_info.dc + GIOE) & 0x1c0) << 2; /* drive each sense line low in turn and collect the other 2 */ - out_le32(dc_regs + GIOE, 033); /* drive A low */ + out_le32(ims_info.dc + GIOE, 033); /* drive A low */ __delay(2000); - sense |= (in_le32(dc_regs + GIOE) & 0xc0) >> 2; - out_le32(dc_regs + GIOE, 055); /* drive B low */ + sense |= (in_le32(ims_info.dc + GIOE) & 0xc0) >> 2; + out_le32(ims_info.dc + GIOE, 055); /* drive B low */ __delay(2000); - sense |= ((in_le32(dc_regs + GIOE) & 0x100) >> 5) - | ((in_le32(dc_regs + GIOE) & 0x40) >> 4); - out_le32(dc_regs + GIOE, 066); /* drive C low */ + sense |= ((in_le32(ims_info.dc + GIOE) & 0x100) >> 5) + | ((in_le32(ims_info.dc + GIOE) & 0x40) >> 4); + out_le32(ims_info.dc + GIOE, 066); /* drive C low */ __delay(2000); - sense |= (in_le32(dc_regs + GIOE) & 0x180) >> 7; + sense |= (in_le32(ims_info.dc + GIOE) & 0x180) >> 7; - out_le32(dc_regs + GIOE, 077); /* turn off drivers */ + out_le32(ims_info.dc + GIOE, 077); /* turn off drivers */ return sense; #else return 0; @@ -229,12 +536,24 @@ read_imstt_sense() static inline int imstt_vram_reqd(int vmode, int cmode) { - return vmode_attrs[vmode-1].vres - * imstt_reg_init[vmode-1]->pitch[cmode]; + return vmode_attrs[vmode-1].vres * + (ims_info.mode[vmode-1])->pitch * ( 1 << cmode); +} + +void +map_imstt_display_tvp(struct device_node *dp) +{ + map_imstt_display(dp,1); } void -map_imstt_display(struct device_node *dp) +map_imstt_display_ibm(struct device_node *dp) +{ + map_imstt_display(dp,0); +} + +static void +map_imstt_display(struct device_node *dp, int which) { int i, sense; unsigned long addr, size, tmp; @@ -244,7 +563,7 @@ map_imstt_display(struct device_node *dp) if (dp->next != 0) printk("Warning: only using first imstt display device\n"); -#if 1 +#if 0 printk("pmac_display_init: node = %p, addrs =", dp->node); for (i = 0; i < dp->n_addrs; ++i) printk(" %x(%x)", dp->addrs[i].address, dp->addrs[i].size); @@ -259,12 +578,14 @@ map_imstt_display(struct device_node *dp) addr = dp->addrs[i].address; size = dp->addrs[i].size; if (size >= 0x02000000) { - frame_buffer = ioremap(addr, size); - dc_regs = (unsigned*)(frame_buffer + 0x00800000); - cmap_regs = (unsigned char*)(frame_buffer + 0x00840000); - - printk("mapped frame_buffer=%x(%x)", (unsigned)frame_buffer, (unsigned)size); - printk(" dc_regs=%x, cmap_regs=%x\n", (unsigned)dc_regs, (unsigned)cmap_regs); + ims_info.fb = __ioremap(addr, size, _PAGE_NO_CACHE); + ims_info.fb_phys = (unsigned char*)addr; + ims_info.dc = (unsigned*)(ims_info.fb + 0x00800000); + ims_info.dc_phys = (unsigned*)(ims_info.fb_phys + 0x00800000); + ims_info.cmap = (unsigned char*)(ims_info.fb + 0x00840000); + ims_info.cmap_phys = (unsigned char*)(ims_info.fb_phys + 0x00840000); + printk("mapped ims_info.fb=%x(%x)", (unsigned)ims_info.fb, (unsigned)size); + printk(" ims_info.dc=%x, ims_info.cmap=%x\n", (unsigned)ims_info.dc, (unsigned)ims_info.cmap); } } @@ -282,12 +603,28 @@ map_imstt_display(struct device_node *dp) else printk("unable to find pci device\n"); - tmp = in_le32(dc_regs + SSTATUS); + tmp = in_le32(ims_info.dc + SSTATUS); printk("chip version %ld, ", (tmp & 0x0F00) >> 8); - tmp = in_le32(dc_regs + PRC); - total_vram = (tmp & 0x0004) ? 0x000400000L : 0x000200000L; - printk("VRAM size %ldM\n", total_vram / 0x000100000L); + tmp = in_le32(ims_info.dc + PRC); + + if (0 == which ) + ims_info.total_vram = (tmp & 0x0004) ? 0x000400000L : 0x000200000L; + else + ims_info.total_vram = 0x000800000L; + + printk("VRAM size %ldM\n", ims_info.total_vram / 0x000100000L); + + if (ims_info.total_vram == 0x000800000L) + { + ims_info.dac = TVPRAMDAC; + printk("Selecting TVP 3030 RAMDAC\n"); + } + else + { + ims_info.dac = IBMRAMDAC; + printk("Selecting IBM RAMDAC\n"); + } sense = read_imstt_sense(); printk("Monitor sense value = 0x%x, ", sense); @@ -311,147 +648,232 @@ map_imstt_display(struct device_node *dp) if (color_mode < CMODE_8 || color_mode > CMODE_32) color_mode = CMODE_8; while (color_mode > CMODE_8 - && imstt_vram_reqd(video_mode, color_mode) > total_vram) + && imstt_vram_reqd(video_mode, color_mode) > ims_info.total_vram) --color_mode; #endif - + // Hack Hack Hack !!! video_mode = VMODE_640_480_67; color_mode = CMODE_8; } +/* + * We dont need it ( all is done in ims_init ) +static void +set_imstt_clock_tvp(char* tvprv) +{ + int j; + for (j=0;j<3;j++) + { + set_tvp_ireg(TVPIRPLA,(j << 4) | (j << 2) | j); // Select same value for all plls + set_tvp_ireg(TVPIRPPD,tvprv[j]); + set_tvp_ireg(TVPIRMPD,tvprv[3+j]); + set_tvp_ireg(TVPIRLPD,tvprv[6+j]); + } +} + static void -set_imstt_clock(unsigned char *params) +set_imstt_clock_ibm(unsigned char *params) { - cmap_regs[PIDXHI] = 0; eieio(); - cmap_regs[PIDXLO] = PM0; eieio(); - cmap_regs[PIDXDATA] = params[0]; eieio(); + ims_info.cmap[PIDXHI] = 0; eieio(); + ims_info.cmap[PIDXLO] = PM0; eieio(); + ims_info.cmap[PIDXDATA] = params[0]; eieio(); - cmap_regs[PIDXLO] = PN0; eieio(); - cmap_regs[PIDXDATA] = params[1]; eieio(); + ims_info.cmap[PIDXLO] = PN0; eieio(); + ims_info.cmap[PIDXDATA] = params[1]; eieio(); - cmap_regs[PIDXLO] = PP0; eieio(); - cmap_regs[PIDXDATA] = params[2]; eieio(); + ims_info.cmap[PIDXLO] = PP0; eieio(); + ims_info.cmap[PIDXDATA] = params[2]; eieio(); - cmap_regs[PIDXLO] = PC0; eieio(); - cmap_regs[PIDXDATA] = params[3]; eieio(); + ims_info.cmap[PIDXLO] = PC0; eieio(); + ims_info.cmap[PIDXDATA] = params[3]; eieio(); } +*/ void imstt_init() { int i, yoff, hres; - unsigned long ctl, pitch, tmp; - unsigned char pformat; - unsigned *p; - struct imstt_regvals *init; + unsigned long ctl, pitch, tmp, scrCmode; + struct ims_crmodevals *init; - if (video_mode <= 0 || video_mode > VMODE_MAX - || (init = imstt_reg_init[video_mode-1]) == 0) - panic("imstt: display mode %d not supported", video_mode); + if (video_mode <= 0 || video_mode > VMODE_MAX ) panic("imstt: display mode %d not supported(not in valid range)", video_mode); + if ((init = ims_info.mode[video_mode-1]) == 0) panic("imstt: display mode %d not supported(no mode definition)", video_mode); + if (init->tt[ims_info.dac].vt == 0) panic("imstt: display mode %d not supported (no timing definition)", video_mode); + n_scanlines = vmode_attrs[video_mode-1].vres; hres = vmode_attrs[video_mode-1].hres; pixel_size = 1 << color_mode; - line_pitch = init->pitch[color_mode]; + line_pitch = init->pitch * pixel_size; row_pitch = line_pitch * 16; /* initialize the card */ - tmp = in_le32(dc_regs + STGCTL); - out_le32(dc_regs + STGCTL, tmp & ~0x1); + tmp = in_le32(ims_info.dc + STGCTL); + out_le32(ims_info.dc + STGCTL, tmp & ~0x1); #if 0 - out_le32(dc_regs + SCR, 0); + out_le32(ims_info.dc + SCR, 0); #endif - cmap_regs[PPMASK] = 0xFF; - /* set default values for DAC registers */ - cmap_regs[PIDXHI] = 0; eieio(); - for(i = 0; i < sizeof(initregs) / sizeof(*initregs); i++) { - cmap_regs[PIDXLO] = initregs[i].addr; eieio(); - cmap_regs[PIDXDATA] = initregs[i].value; eieio(); + switch(ims_info.dac) + { + case IBMRAMDAC: + ims_info.cmap[PPMASK] = 0xFF; eieio(); + ims_info.cmap[PIDXHI] = 0x00; eieio(); + for (i = 0; ims_info.init[IBMRAMDAC][i].addr != 0 && ims_info.init[IBMRAMDAC][i].value != 0 ;i++) + { + ims_info.cmap[PIDXLO] = ims_info.init[IBMRAMDAC][i].addr; eieio(); + ims_info.cmap[PIDXDATA] = ims_info.init[IBMRAMDAC][i].value; eieio(); + } + + ims_info.cmap[PIDXHI] = 0; eieio(); + ims_info.cmap[PIDXLO] = PM0; eieio(); + ims_info.cmap[PIDXDATA] = init->ibm_clock.pclk_m; eieio(); + + ims_info.cmap[PIDXLO] = PN0; eieio(); + ims_info.cmap[PIDXDATA] = init->ibm_clock.pclk_n; eieio(); + + ims_info.cmap[PIDXLO] = PP0; eieio(); + ims_info.cmap[PIDXDATA] = init->ibm_clock.pclk_p; eieio(); + + ims_info.cmap[PIDXLO] = PC0; eieio(); + ims_info.cmap[PIDXDATA] = init->ibm_clock.pclk_c; eieio(); + + ims_info.cmap[PIDXLO] = PPIXREP; eieio(); + ims_info.cmap[PIDXDATA] = ims_info.ibm[color_mode].pformat; eieio(); + + break; + case TVPRAMDAC: + for (i = 0; ims_info.init[TVPRAMDAC][i].addr != 0 && ims_info.init[TVPRAMDAC][i].value != 0 ;i++) + { + set_tvp_ireg(ims_info.init[TVPRAMDAC][i].addr,ims_info.init[TVPRAMDAC][i].value); + } + set_tvp_ireg(TVPIRPLA,0x00); + set_tvp_ireg(TVPIRPPD,init->tvp_clock.pclk_n); + set_tvp_ireg(TVPIRPPD,init->tvp_clock.pclk_m); + set_tvp_ireg(TVPIRPPD,init->tvp_clock.pclk_p); + + set_tvp_ireg(TVPIRTCC,ims_info.tvp[color_mode].tcc); + set_tvp_ireg(TVPIRMXC,ims_info.tvp[color_mode].mxc); + + set_tvp_ireg(TVPIRPLA,0x00); + set_tvp_ireg(TVPIRLPD,ims_info.tvp[color_mode].lckl_n); + + set_tvp_ireg(TVPIRPLA,0x15); + set_tvp_ireg(TVPIRMLC,(init->tvp[color_mode]).mlc); + + set_tvp_ireg(TVPIRPLA,0x2a); + set_tvp_ireg(TVPIRLPD,init->tvp[color_mode].lckl_p); + break; } - set_imstt_clock(init->clk); + switch(color_mode) { case CMODE_32: - ctl = 0x17b5; - pitch = init->pitch[2] / 4; - pformat = 0x06; + ctl = 0x1785; + pitch = init->pitch; + scrCmode = 0x300; break; case CMODE_16: - ctl = 0x17b3; - pitch = init->pitch[1] / 4; - pformat = 0x04; + ctl = 0x1783; + pitch = init->pitch / 2; + scrCmode = 0x100; break; case CMODE_8: default: - ctl = 0x17b1; - pitch = init->pitch[0] / 4; - pformat = 0x03; + ctl = 0x1781; + pitch = init->pitch / 4; + scrCmode = 0x000; break; } - out_le32(&dc_regs[HES], init->cfg[0]); - out_le32(&dc_regs[HEB], init->cfg[1]); - out_le32(&dc_regs[HSB], init->cfg[2]); - out_le32(&dc_regs[HT], init->cfg[3]); - out_le32(&dc_regs[VES], init->cfg[4]); - out_le32(&dc_regs[VEB], init->cfg[5]); - out_le32(&dc_regs[VSB], init->cfg[6]); - out_le32(&dc_regs[VT], init->cfg[7]); - out_le32(&dc_regs[HCIV], 1); - out_le32(&dc_regs[VCIV], 1); - out_le32(&dc_regs[TCDR], 4); - out_le32(&dc_regs[VIL], 0); + out_le32(&ims_info.dc[HES], init->tt[ims_info.dac].hes); + out_le32(&ims_info.dc[HEB], init->tt[ims_info.dac].heb); + out_le32(&ims_info.dc[HSB], init->tt[ims_info.dac].hsb); + out_le32(&ims_info.dc[HT], init->tt[ims_info.dac].ht); + out_le32(&ims_info.dc[VES], init->tt[ims_info.dac].ves); + out_le32(&ims_info.dc[VEB], init->tt[ims_info.dac].veb); + out_le32(&ims_info.dc[VSB], init->tt[ims_info.dac].vsb); + out_le32(&ims_info.dc[VT], init->tt[ims_info.dac].vt); + out_le32(&ims_info.dc[HCIV], 1); + out_le32(&ims_info.dc[VCIV], 1); + out_le32(&ims_info.dc[TCDR], 4); + out_le32(&ims_info.dc[VIL], 0); - out_le32(&dc_regs[SSR], 0); - out_le32(&dc_regs[HRIR], 0x0200); - out_le32(&dc_regs[CMR], 0x01FF); - out_le32(&dc_regs[SRGCTL], 0x0003); - if(total_vram == 0x000200000) - out_le32(&dc_regs[SCR], 0x0059D); - else { - pitch /= 2; - out_le32(&dc_regs[SCR], 0x00D0DC); + out_le32(&ims_info.dc[SSR], 0); + out_le32(&ims_info.dc[HRIR], 0x0200); + out_le32(&ims_info.dc[CMR], 0x01FF); + out_le32(&ims_info.dc[SRGCTL], 0x0003); + switch(ims_info.total_vram) + { + case 0x000200000: + out_le32(&ims_info.dc[SCR], 0x0059D| scrCmode); + break; + case 0x000400000: + pitch /= 2; + out_le32(&ims_info.dc[SCR], 0x00D0DC | scrCmode); + break; + case 0x000800000: + pitch /= 2; + out_le32(&ims_info.dc[SCR], 0x0150DD | scrCmode); + break; } - out_le32(&dc_regs[SPR], pitch); - - cmap_regs[PIDXLO] = PPIXREP; eieio(); - cmap_regs[PIDXDATA] = pformat; eieio(); + out_le32(&ims_info.dc[SPR], pitch); + if (ims_info.dac == IBMRAMDAC) + { + + } + pmac_init_palette(); /* Initialize colormap */ - out_le32(&dc_regs[STGCTL], ctl); + out_le32(&ims_info.dc[STGCTL], ctl); yoff = (n_scanlines % 16) / 2; - fb_start = frame_buffer + yoff * line_pitch; + fb_start = ims_info.fb + yoff * line_pitch; /* Clear screen */ - p = (unsigned *)frame_buffer; - for (i = n_scanlines * line_pitch / sizeof(unsigned); i != 0; --i) - *p++ = 0; + { + unsigned long *p; + p = (unsigned long*)ims_info.fb; + for (i = n_scanlines * line_pitch / sizeof(unsigned); i != 0; --i) + *p++ = 0; + } display_info.height = n_scanlines; display_info.width = hres; display_info.depth = pixel_size * 8; display_info.pitch = line_pitch; display_info.mode = video_mode; - strncpy(display_info.name, "IMS,tt128mb", sizeof(display_info.name)); - display_info.fb_address = (unsigned long) frame_buffer; - display_info.cmap_adr_address = (unsigned long) &cmap_regs[PADDRW]; - display_info.cmap_data_address = (unsigned long) &cmap_regs[PDATA]; + + if (ims_info.dac == IBMRAMDAC ) + strncpy(display_info.name, "IMS,tt128mb2/4", sizeof(display_info.name)); + else + strncpy(display_info.name, "IMS,tt128mb8/8A", sizeof(display_info.name)); + + display_info.fb_address = (unsigned long) ims_info.fb_phys; + display_info.cmap_adr_address = (unsigned long) &ims_info.cmap_phys[PADDRW]; + display_info.cmap_data_address = (unsigned long) &ims_info.cmap_phys[PDATA]; display_info.disp_reg_address = (unsigned long) NULL; } int imstt_setmode(struct vc_mode *mode, int doit) { - int cmode; + int cmode; + struct ims_crmodevals *init; + + if (video_mode <= 0 || video_mode > VMODE_MAX ) + return -EINVAL; + if ((init = ims_info.mode[video_mode-1]) == 0) + return -EINVAL; + if (init->tt[ims_info.dac].vt == 0) + return -EINVAL; if (mode->mode <= 0 || mode->mode > VMODE_MAX - || imstt_reg_init[mode->mode-1] == 0) + || (ims_info.mode[mode->mode-1] == 0)) return -EINVAL; switch (mode->depth) { case 24: @@ -468,7 +890,7 @@ imstt_setmode(struct vc_mode *mode, int doit) default: return -EINVAL; } - if (imstt_vram_reqd(mode->mode, cmode) > total_vram) + if (imstt_vram_reqd(mode->mode, cmode) > ims_info.total_vram) return -EINVAL; if (doit) { video_mode = mode->mode; @@ -478,17 +900,32 @@ imstt_setmode(struct vc_mode *mode, int doit) return 0; } +// set palette for TI TVP3030 ramdac (used on 8MB version) +void +imstt_set_palette_tvp(unsigned char red[], unsigned char green[], + unsigned char blue[], int index, int ncolors) +{ + int i; + for (i = 0; i < ncolors; ++i) { + ims_info.cmap[TVPADDRW] = index + i; eieio(); + ims_info.cmap[TVPPDATA] = red[i]; eieio(); + ims_info.cmap[TVPPDATA] = green[i]; eieio(); + ims_info.cmap[TVPPDATA] = blue[i]; eieio(); + } +} + +// set palette for IBM ramdac (used on 2MB/4MB version) void -imstt_set_palette(unsigned char red[], unsigned char green[], +imstt_set_palette_ibm(unsigned char red[], unsigned char green[], unsigned char blue[], int index, int ncolors) { int i; for (i = 0; i < ncolors; ++i) { - cmap_regs[PADDRW] = index + i; eieio(); - cmap_regs[PDATA] = red[i]; eieio(); - cmap_regs[PDATA] = green[i]; eieio(); - cmap_regs[PDATA] = blue[i]; eieio(); + ims_info.cmap[PADDRW] = index + i; eieio(); + ims_info.cmap[PDATA] = red[i]; eieio(); + ims_info.cmap[PDATA] = green[i]; eieio(); + ims_info.cmap[PDATA] = blue[i]; eieio(); } } @@ -497,10 +934,12 @@ imstt_set_blanking(int blank_mode) { long ctrl; - ctrl = ld_le32(dc_regs + STGCTL) | 0x0030; + ctrl = ld_le32(ims_info.dc + STGCTL) | 0x0030; if (blank_mode & VESA_VSYNC_SUSPEND) ctrl &= ~0x0020; if (blank_mode & VESA_HSYNC_SUSPEND) ctrl &= ~0x0010; - out_le32(dc_regs + STGCTL, ctrl); + out_le32(ims_info.dc + STGCTL, ctrl); } + + diff --git a/drivers/macintosh/imstt.h b/drivers/macintosh/imstt.h index 853e8f00d..a7f635982 100644 --- a/drivers/macintosh/imstt.h +++ b/drivers/macintosh/imstt.h @@ -9,10 +9,13 @@ * 2 of the License, or (at your option) any later version. */ -extern void map_imstt_display(struct device_node *); +extern void map_imstt_display_ibm(struct device_node *); +extern void map_imstt_display_tvp(struct device_node *); extern void imstt_init(void); extern int imstt_setmode(struct vc_mode *mode, int doit); -extern void imstt_set_palette(unsigned char red[], unsigned char green[], +extern void imstt_set_palette_ibm(unsigned char red[], unsigned char green[], + unsigned char blue[], int index, int ncolors); +extern void imstt_set_palette_tvp(unsigned char red[], unsigned char green[], unsigned char blue[], int index, int ncolors); extern void imstt_set_blanking(int blank_mode); diff --git a/drivers/macintosh/mac_keyb.c b/drivers/macintosh/mac_keyb.c index 49dbd622b..190e5222a 100644 --- a/drivers/macintosh/mac_keyb.c +++ b/drivers/macintosh/mac_keyb.c @@ -15,8 +15,8 @@ #include <linux/mm.h> #include <linux/signal.h> #include <linux/ioport.h> +#include <linux/init.h> -#include <asm/keyboard.h> #include <asm/bitops.h> #include <asm/adb.h> #include <asm/cuda.h> @@ -28,6 +28,140 @@ #define KEYB_LEDREG 2 /* register # for leds on ADB keyboard */ #define MOUSE_DATAREG 0 /* reg# for movement/button codes from mouse */ +static u_short macplain_map[NR_KEYS] = __initdata { + 0xfb61, 0xfb73, 0xfb64, 0xfb66, 0xfb68, 0xfb67, 0xfb7a, 0xfb78, + 0xfb63, 0xfb76, 0xf200, 0xfb62, 0xfb71, 0xfb77, 0xfb65, 0xfb72, + 0xfb79, 0xfb74, 0xf031, 0xf032, 0xf033, 0xf034, 0xf036, 0xf035, + 0xf03d, 0xf039, 0xf037, 0xf02d, 0xf038, 0xf030, 0xf05d, 0xfb6f, + 0xfb75, 0xf05b, 0xfb69, 0xfb70, 0xf201, 0xfb6c, 0xfb6a, 0xf027, + 0xfb6b, 0xf03b, 0xf05c, 0xf02c, 0xf02f, 0xfb6e, 0xfb6d, 0xf02e, + 0xf009, 0xf020, 0xf060, 0xf07f, 0xf200, 0xf01b, 0xf702, 0xf703, + 0xf700, 0xf207, 0xf701, 0xf601, 0xf602, 0xf600, 0xf603, 0xf200, + 0xf200, 0xf310, 0xf200, 0xf30c, 0xf200, 0xf30a, 0xf200, 0xf208, + 0xf200, 0xf200, 0xf200, 0xf30d, 0xf30e, 0xf200, 0xf30b, 0xf200, + 0xf200, 0xf200, 0xf300, 0xf301, 0xf302, 0xf303, 0xf304, 0xf305, + 0xf306, 0xf307, 0xf200, 0xf308, 0xf309, 0xf200, 0xf200, 0xf200, + 0xf104, 0xf105, 0xf106, 0xf102, 0xf107, 0xf108, 0xf200, 0xf10a, + 0xf200, 0xf10c, 0xf200, 0xf209, 0xf200, 0xf109, 0xf200, 0xf10b, + 0xf200, 0xf11d, 0xf115, 0xf114, 0xf118, 0xf116, 0xf103, 0xf117, + 0xf101, 0xf119, 0xf100, 0xf700, 0xf701, 0xf702, 0xf200, 0xf200, +}; + +static u_short macshift_map[NR_KEYS] __initdata = { + 0xfb41, 0xfb53, 0xfb44, 0xfb46, 0xfb48, 0xfb47, 0xfb5a, 0xfb58, + 0xfb43, 0xfb56, 0xf200, 0xfb42, 0xfb51, 0xfb57, 0xfb45, 0xfb52, + 0xfb59, 0xfb54, 0xf021, 0xf040, 0xf023, 0xf024, 0xf05e, 0xf025, + 0xf02b, 0xf028, 0xf026, 0xf05f, 0xf02a, 0xf029, 0xf07d, 0xfb4f, + 0xfb55, 0xf07b, 0xfb49, 0xfb50, 0xf201, 0xfb4c, 0xfb4a, 0xf022, + 0xfb4b, 0xf03a, 0xf07c, 0xf03c, 0xf03f, 0xfb4e, 0xfb4d, 0xf03e, + 0xf009, 0xf020, 0xf07e, 0xf07f, 0xf200, 0xf01b, 0xf702, 0xf703, + 0xf700, 0xf207, 0xf701, 0xf601, 0xf602, 0xf600, 0xf603, 0xf200, + 0xf200, 0xf310, 0xf200, 0xf30c, 0xf200, 0xf30a, 0xf200, 0xf208, + 0xf200, 0xf200, 0xf200, 0xf30d, 0xf30e, 0xf200, 0xf30b, 0xf200, + 0xf200, 0xf200, 0xf300, 0xf301, 0xf302, 0xf303, 0xf304, 0xf305, + 0xf306, 0xf307, 0xf200, 0xf308, 0xf309, 0xf200, 0xf200, 0xf200, + 0xf10e, 0xf10f, 0xf110, 0xf10c, 0xf111, 0xf112, 0xf200, 0xf10a, + 0xf200, 0xf10c, 0xf200, 0xf203, 0xf200, 0xf113, 0xf200, 0xf10b, + 0xf200, 0xf11d, 0xf115, 0xf114, 0xf20b, 0xf116, 0xf10d, 0xf117, + 0xf10b, 0xf20a, 0xf10a, 0xf700, 0xf701, 0xf702, 0xf200, 0xf200, +}; + +static u_short macaltgr_map[NR_KEYS] __initdata = { + 0xf914, 0xfb73, 0xf917, 0xf919, 0xfb68, 0xfb67, 0xfb7a, 0xfb78, + 0xf916, 0xfb76, 0xf200, 0xf915, 0xfb71, 0xfb77, 0xf918, 0xfb72, + 0xfb79, 0xfb74, 0xf200, 0xf040, 0xf200, 0xf024, 0xf200, 0xf200, + 0xf200, 0xf05d, 0xf07b, 0xf05c, 0xf05b, 0xf07d, 0xf07e, 0xfb6f, + 0xfb75, 0xf200, 0xfb69, 0xfb70, 0xf201, 0xfb6c, 0xfb6a, 0xf200, + 0xfb6b, 0xf200, 0xf200, 0xf200, 0xf200, 0xfb6e, 0xfb6d, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf702, 0xf703, + 0xf700, 0xf207, 0xf701, 0xf601, 0xf602, 0xf600, 0xf603, 0xf200, + 0xf200, 0xf310, 0xf200, 0xf30c, 0xf200, 0xf30a, 0xf200, 0xf208, + 0xf200, 0xf200, 0xf200, 0xf30d, 0xf30e, 0xf200, 0xf30b, 0xf200, + 0xf200, 0xf200, 0xf90a, 0xf90b, 0xf90c, 0xf90d, 0xf90e, 0xf90f, + 0xf910, 0xf911, 0xf200, 0xf912, 0xf913, 0xf200, 0xf200, 0xf200, + 0xf510, 0xf511, 0xf512, 0xf50e, 0xf513, 0xf514, 0xf200, 0xf516, + 0xf200, 0xf10c, 0xf200, 0xf202, 0xf200, 0xf515, 0xf200, 0xf517, + 0xf200, 0xf11d, 0xf115, 0xf114, 0xf118, 0xf116, 0xf50f, 0xf117, + 0xf50d, 0xf119, 0xf50c, 0xf700, 0xf701, 0xf702, 0xf200, 0xf200, +}; + +static u_short macctrl_map[NR_KEYS] __initdata = { + 0xf001, 0xf013, 0xf004, 0xf006, 0xf008, 0xf007, 0xf01a, 0xf018, + 0xf003, 0xf016, 0xf200, 0xf002, 0xf011, 0xf017, 0xf005, 0xf012, + 0xf019, 0xf014, 0xf200, 0xf000, 0xf01b, 0xf01c, 0xf01e, 0xf01d, + 0xf200, 0xf200, 0xf01f, 0xf01f, 0xf07f, 0xf200, 0xf01d, 0xf00f, + 0xf015, 0xf01b, 0xf009, 0xf010, 0xf201, 0xf00c, 0xf00a, 0xf007, + 0xf00b, 0xf200, 0xf01c, 0xf200, 0xf07f, 0xf00e, 0xf00d, 0xf20e, + 0xf200, 0xf000, 0xf000, 0xf008, 0xf200, 0xf200, 0xf702, 0xf703, + 0xf700, 0xf207, 0xf701, 0xf601, 0xf602, 0xf600, 0xf603, 0xf200, + 0xf200, 0xf310, 0xf200, 0xf30c, 0xf200, 0xf30a, 0xf200, 0xf208, + 0xf200, 0xf200, 0xf200, 0xf30d, 0xf30e, 0xf200, 0xf30b, 0xf200, + 0xf200, 0xf200, 0xf300, 0xf301, 0xf302, 0xf303, 0xf304, 0xf305, + 0xf306, 0xf307, 0xf200, 0xf308, 0xf309, 0xf200, 0xf200, 0xf200, + 0xf104, 0xf105, 0xf106, 0xf102, 0xf107, 0xf108, 0xf200, 0xf10a, + 0xf200, 0xf10c, 0xf200, 0xf204, 0xf200, 0xf109, 0xf200, 0xf10b, + 0xf200, 0xf11d, 0xf115, 0xf114, 0xf118, 0xf116, 0xf103, 0xf117, + 0xf101, 0xf119, 0xf100, 0xf700, 0xf701, 0xf702, 0xf200, 0xf200, +}; + +static u_short macshift_ctrl_map[NR_KEYS] __initdata = { + 0xf001, 0xf013, 0xf004, 0xf006, 0xf008, 0xf007, 0xf01a, 0xf018, + 0xf003, 0xf016, 0xf200, 0xf002, 0xf011, 0xf017, 0xf005, 0xf012, + 0xf019, 0xf014, 0xf200, 0xf000, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf01f, 0xf200, 0xf200, 0xf200, 0xf00f, + 0xf015, 0xf200, 0xf009, 0xf010, 0xf201, 0xf00c, 0xf00a, 0xf200, + 0xf00b, 0xf200, 0xf200, 0xf200, 0xf200, 0xf00e, 0xf00d, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf702, 0xf703, + 0xf700, 0xf207, 0xf701, 0xf601, 0xf602, 0xf600, 0xf603, 0xf200, + 0xf200, 0xf310, 0xf200, 0xf30c, 0xf200, 0xf30a, 0xf200, 0xf208, + 0xf200, 0xf200, 0xf200, 0xf30d, 0xf30e, 0xf200, 0xf30b, 0xf200, + 0xf200, 0xf200, 0xf300, 0xf301, 0xf302, 0xf303, 0xf304, 0xf305, + 0xf306, 0xf307, 0xf200, 0xf308, 0xf309, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf10c, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf11d, 0xf115, 0xf114, 0xf118, 0xf116, 0xf200, 0xf117, + 0xf200, 0xf119, 0xf200, 0xf700, 0xf701, 0xf702, 0xf200, 0xf20c, +}; + +static u_short macalt_map[NR_KEYS] __initdata = { + 0xf861, 0xf873, 0xf864, 0xf866, 0xf868, 0xf867, 0xf87a, 0xf878, + 0xf863, 0xf876, 0xf200, 0xf862, 0xf871, 0xf877, 0xf865, 0xf872, + 0xf879, 0xf874, 0xf831, 0xf832, 0xf833, 0xf834, 0xf836, 0xf835, + 0xf83d, 0xf839, 0xf837, 0xf82d, 0xf838, 0xf830, 0xf85d, 0xf86f, + 0xf875, 0xf85b, 0xf869, 0xf870, 0xf80d, 0xf86c, 0xf86a, 0xf827, + 0xf86b, 0xf83b, 0xf85c, 0xf82c, 0xf82f, 0xf86e, 0xf86d, 0xf82e, + 0xf809, 0xf820, 0xf860, 0xf87f, 0xf200, 0xf81b, 0xf702, 0xf703, + 0xf700, 0xf207, 0xf701, 0xf210, 0xf211, 0xf600, 0xf603, 0xf200, + 0xf200, 0xf310, 0xf200, 0xf30c, 0xf200, 0xf30a, 0xf200, 0xf208, + 0xf200, 0xf200, 0xf200, 0xf30d, 0xf30e, 0xf200, 0xf30b, 0xf200, + 0xf200, 0xf200, 0xf900, 0xf901, 0xf902, 0xf903, 0xf904, 0xf905, + 0xf906, 0xf907, 0xf200, 0xf908, 0xf909, 0xf200, 0xf200, 0xf200, + 0xf504, 0xf505, 0xf506, 0xf502, 0xf507, 0xf508, 0xf200, 0xf50a, + 0xf200, 0xf10c, 0xf200, 0xf209, 0xf200, 0xf509, 0xf200, 0xf50b, + 0xf200, 0xf11d, 0xf115, 0xf114, 0xf118, 0xf116, 0xf503, 0xf117, + 0xf501, 0xf119, 0xf500, 0xf700, 0xf701, 0xf702, 0xf200, 0xf200, +}; + +static u_short macctrl_alt_map[NR_KEYS] __initdata = { + 0xf801, 0xf813, 0xf804, 0xf806, 0xf808, 0xf807, 0xf81a, 0xf818, + 0xf803, 0xf816, 0xf200, 0xf802, 0xf811, 0xf817, 0xf805, 0xf812, + 0xf819, 0xf814, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf80f, + 0xf815, 0xf200, 0xf809, 0xf810, 0xf201, 0xf80c, 0xf80a, 0xf200, + 0xf80b, 0xf200, 0xf200, 0xf200, 0xf200, 0xf80e, 0xf80d, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf702, 0xf703, + 0xf700, 0xf207, 0xf701, 0xf601, 0xf602, 0xf600, 0xf603, 0xf200, + 0xf200, 0xf310, 0xf200, 0xf30c, 0xf200, 0xf30a, 0xf200, 0xf208, + 0xf200, 0xf200, 0xf200, 0xf30d, 0xf30e, 0xf200, 0xf30b, 0xf200, + 0xf200, 0xf200, 0xf300, 0xf301, 0xf302, 0xf303, 0xf304, 0xf305, + 0xf306, 0xf307, 0xf200, 0xf308, 0xf309, 0xf200, 0xf200, 0xf200, + 0xf504, 0xf505, 0xf506, 0xf502, 0xf507, 0xf508, 0xf200, 0xf50a, + 0xf200, 0xf10c, 0xf200, 0xf200, 0xf200, 0xf509, 0xf200, 0xf50b, + 0xf200, 0xf11d, 0xf115, 0xf114, 0xf118, 0xf116, 0xf503, 0xf117, + 0xf501, 0xf119, 0xf500, 0xf700, 0xf701, 0xf702, 0xf200, 0xf200, +}; + + static void kbd_repeat(unsigned long); static struct timer_list repeat_timer = { NULL, NULL, 0, 0, kbd_repeat }; static int last_keycode; @@ -38,8 +172,7 @@ static void leds_done(struct adb_request *); /* XXX: Hook for mouse driver */ void (*adb_mouse_interrupt_hook) (char *, int); -int adb_emulate_button2; -int adb_emulate_button3; +static int adb_emulate_buttons = 0; extern int console_loglevel; extern struct kbd_struct kbd_table[]; @@ -47,6 +180,9 @@ extern struct kbd_struct kbd_table[]; extern void handle_scancode(unsigned char); extern void put_queue(int); +static struct adb_ids keyboard_ids; +static struct adb_ids mouse_ids; + /* this map indicates which keys shouldn't autorepeat. */ static unsigned char dont_repeat[128] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -118,6 +254,10 @@ input_keycode(int keycode, int repeat) up_flag = (keycode & 0x80); keycode &= 0x7f; + /* on the powerbook 3400, the power key gives code 0x7e */ + if (keycode == 0x7e) + keycode = 0x7f; + if (!repeat) del_timer(&repeat_timer); @@ -130,7 +270,8 @@ input_keycode(int keycode, int repeat) * Might also want to know how many buttons need to be emulated. * -> hide this as function in arch/m68k/mac ? */ - if (adb_mouse_interrupt_hook || console_loglevel == 10) { + if ( (adb_emulate_buttons) && + (adb_mouse_interrupt_hook || console_loglevel == 10) ) { unsigned char button, button2, button3, fake_event; static unsigned char button2state=0, button3state=0; /* up */ /* faked ADB packet */ @@ -140,19 +281,19 @@ input_keycode(int keycode, int repeat) fake_event = 0; switch (keycode) { /* which 'button' ? */ case 0x7c: /* R-option */ - button2 = (!up_flag); /* new state */ - if (button2 != button2state) /* change ? */ - button = 2; - button2state = button2; /* save state */ - fake_event = 2; - break; - case 0x7d: /* R-control */ button3 = (!up_flag); /* new state */ if (button3 != button3state) /* change ? */ button = 3; button3state = button3; /* save state */ fake_event = 3; break; + case 0x7d: /* R-control */ + button2 = (!up_flag); /* new state */ + if (button2 != button2state) /* change ? */ + button = 2; + button2state = button2; /* save state */ + fake_event = 2; + break; } if (fake_event && console_loglevel >= 8) printk("fake event: button2 %d button3 %d button %d\n", @@ -365,57 +506,134 @@ static unsigned char mac_ledmap[8] = { }; static struct adb_request led_request; -static int leds_pending; +static int leds_pending[16]; +static int pending_devs[16]; +static int pending_led_start=0; +static int pending_led_end=0; + +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, + ~mac_ledmap[leds]); + } else { + if (!(leds_pending[device] & 0x100)) { + pending_devs[pending_led_end] = device; + pending_led_end++; + pending_led_end = (pending_led_end < 16) ? pending_led_end : 0; + } + leds_pending[device] = leds | 0x100; + } +} void mackbd_leds(unsigned char leds) { - if (led_request.complete) { - adb_request(&led_request, leds_done, 0, 3, - ADB_WRITEREG(ADB_KEYBOARD, KEYB_LEDREG), - 0xff, ~mac_ledmap[leds]); - } else - leds_pending = leds | 0x100; + int i; + + for(i = 0; i < keyboard_ids.nids; i++) + real_mackbd_leds(leds,keyboard_ids.id[i]); } static void leds_done(struct adb_request *req) { - int leds; + int leds,device; + + if (pending_led_start != pending_led_end) { + device = pending_devs[pending_led_start]; + leds = leds_pending[device] & 0xff; + leds_pending[device] = 0; + pending_led_start++; + pending_led_start = (pending_led_start < 16) ? pending_led_start : 0; + real_mackbd_leds(leds,device); + } - if (leds_pending) { - leds = leds_pending & 0xff; - leds_pending = 0; - mackbd_leds(leds); - } } -void mackbd_init_hw(void) +__initfunc(void mackbd_init_hw(void)) { struct adb_request req; + int i; + + if ( (_machine != _MACH_chrp) && (_machine != _MACH_Pmac) ) + return; + + /* setup key map */ + memcpy(plain_map, macplain_map, sizeof(plain_map)); + memcpy(shift_map, macshift_map, sizeof(shift_map)); + memcpy(altgr_map, macaltgr_map, sizeof(altgr_map)); + memcpy(ctrl_map, macctrl_map, sizeof(ctrl_map)); + memcpy(shift_ctrl_map, macshift_ctrl_map, sizeof(shift_ctrl_map)); + memcpy(alt_map, macalt_map, sizeof(alt_map)); + memcpy(ctrl_alt_map, macctrl_alt_map, sizeof(ctrl_alt_map)); /* initialize mouse interrupt hook */ adb_mouse_interrupt_hook = NULL; - /* assume broken mouse :-) - should be adjusted based on - * result of the mouse setup !! (or passed as kernel option) */ - adb_emulate_button2 = 1; - adb_emulate_button3 = 1; - adb_register(ADB_KEYBOARD, keyboard_input); - adb_register(ADB_MOUSE, mouse_input); + adb_register(ADB_KEYBOARD, 5, &keyboard_ids, keyboard_input); + adb_register(ADB_MOUSE, 1, &mouse_ids, mouse_input); - /* turn off all leds */ - adb_request(&req, NULL, ADBREQ_SYNC, 3, - ADB_WRITEREG(ADB_KEYBOARD, KEYB_LEDREG), 0xff, 0xff); + for(i = 0; i < keyboard_ids.nids; i++) { + /* turn off all leds */ + adb_request(&req, NULL, ADBREQ_SYNC, 3, + ADB_WRITEREG(keyboard_ids.id[i], KEYB_LEDREG), 0xff, 0xff); + } /* get the keyboard to send separate codes for left and right shift, control, option keys. */ - adb_request(&req, NULL, ADBREQ_SYNC, 3, - ADB_WRITEREG(ADB_KEYBOARD, 3), 0, 3); + for(i = 0;i < keyboard_ids.nids; i++) { + /* get the keyboard to send separate codes for + left and right shift, control, option keys. */ + adb_request(&req, NULL, ADBREQ_SYNC, 3, + ADB_WRITEREG(keyboard_ids.id[i], 3), 0, 3); + } led_request.complete = 1; /* Try to switch the mouse (id 3) to handler 4, for three-button mode. (0x20 is Service Request Enable, 0x03 is Device ID). */ - adb_request(&req, NULL, ADBREQ_SYNC, 3, - ADB_WRITEREG(ADB_MOUSE, 3), 0x23, 4 ); + for(i = 0; i < mouse_ids.nids; i++) { + adb_request(&req, NULL, ADBREQ_SYNC | ADBREQ_REPLY, 1, + ADB_READREG(mouse_ids.id[i], 1)); + + if ((req.reply_len) && + (req.reply[1] == 0x9a) && (req.reply[2] == 0x21)) { + + printk("aha, trackball found at %d\n", mouse_ids.id[i]); + + adb_request(&req, NULL, ADBREQ_SYNC, 3, + ADB_WRITEREG(mouse_ids.id[i], 3), 0x63, 4 ); + + adb_request(&req, NULL, ADBREQ_SYNC, 3, + ADB_WRITEREG(mouse_ids.id[i],1), 00,0x81); + + adb_request(&req, NULL, ADBREQ_SYNC, 3, + ADB_WRITEREG(mouse_ids.id[i],1), 01,0x81); + + adb_request(&req, NULL, ADBREQ_SYNC, 3, + ADB_WRITEREG(mouse_ids.id[i],1), 02,0x81); + + adb_request(&req, NULL, ADBREQ_SYNC, 3, + ADB_WRITEREG(mouse_ids.id[i],1), 03,0x38); + + adb_request(&req, NULL, ADBREQ_SYNC, 3, + ADB_WRITEREG(mouse_ids.id[i],1), 00,0x81); + + adb_request(&req, NULL, ADBREQ_SYNC, 3, + ADB_WRITEREG(mouse_ids.id[i],1), 01,0x81); + + adb_request(&req, NULL, ADBREQ_SYNC, 3, + ADB_WRITEREG(mouse_ids.id[i],1), 02,0x81); + + adb_request(&req, NULL, ADBREQ_SYNC, 3, + ADB_WRITEREG(mouse_ids.id[i],1), 03,0x38); + } + } } +void adb_setup_mouse( char *s, int *ints ) +{ + if (ints[0] >= 1) + adb_emulate_buttons = ints[1]; +} diff --git a/drivers/macintosh/macio-adb.c b/drivers/macintosh/macio-adb.c index 65048b0da..a826daea6 100644 --- a/drivers/macintosh/macio-adb.c +++ b/drivers/macintosh/macio-adb.c @@ -10,6 +10,7 @@ #include <asm/prom.h> #include <asm/adb.h> #include <asm/io.h> +#include <asm/pgtable.h> #include <asm/hydra.h> #include <asm/irq.h> #include <asm/system.h> @@ -71,7 +72,7 @@ void macio_adb_init(void) if (adbs == 0) return; -#if 1 +#if 0 { int i; printk("macio_adb_init: node = %p, addrs =", adbs->node); @@ -79,16 +80,17 @@ void macio_adb_init(void) printk(" %x(%x)", adbs->addrs[i].address, adbs->addrs[i].size); printk(", intrs ="); for (i = 0; i < adbs->n_intrs; ++i) - printk(" %x", adbs->intrs[i]); + printk(" %x", adbs->intrs[i].line); printk("\n"); } #endif - adb = (volatile struct adb_regs *) adbs->addrs->address; + adb = (volatile struct adb_regs *) + ioremap(adbs->addrs->address, sizeof(struct adb_regs)); - if (request_irq(openpic_to_irq(adbs->intrs[0]), macio_adb_interrupt, + if (request_irq(adbs->intrs[0].line, macio_adb_interrupt, 0, "ADB", (void *)0)) { printk(KERN_ERR "ADB: can't get irq %d\n", - openpic_to_irq(adbs->intrs[0])); + adbs->intrs[0].line); return; } diff --git a/drivers/macintosh/macserial.c b/drivers/macintosh/macserial.c index 3a99b07b2..4232f5953 100644 --- a/drivers/macintosh/macserial.c +++ b/drivers/macintosh/macserial.c @@ -7,6 +7,7 @@ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) */ +#include <linux/config.h> #include <linux/errno.h> #include <linux/signal.h> #include <linux/sched.h> @@ -20,13 +21,21 @@ #include <linux/mm.h> #include <linux/kernel.h> #include <linux/delay.h> +#include <linux/init.h> +#ifdef CONFIG_SERIAL_CONSOLE +#include <linux/console.h> +#endif #include <asm/io.h> +#include <asm/pgtable.h> #include <asm/irq.h> #include <asm/prom.h> #include <asm/system.h> #include <asm/segment.h> #include <asm/bitops.h> +#ifdef CONFIG_KGDB +#include <asm/kgdb.h> +#endif #include "macserial.h" @@ -43,7 +52,6 @@ in the order we want. */ #define RECOVERY_DELAY eieio() -struct mac_zschannel *zs_kgdbchan; struct mac_zschannel zs_channels[NUM_CHANNELS]; struct mac_serial zs_soft[NUM_CHANNELS]; @@ -51,31 +59,24 @@ int zs_channels_found; struct mac_serial *zs_chain; /* list of all channels */ struct tty_struct zs_ttys[NUM_CHANNELS]; -/** struct tty_struct *zs_constty; **/ -/* Console hooks... */ -static int zs_cons_chan = 0; -struct mac_serial *zs_consinfo = 0; -struct mac_zschannel *zs_conschan; +#ifdef CONFIG_SERIAL_CONSOLE +static struct console sercons; +#endif -/* - * Initialization values for when a channel is used for - * kernel gdb support. - */ -static unsigned char kgdb_regs[16] = { - 0, 0, 0, /* write 0, 1, 2 */ - (Rx8 | RxENABLE), /* write 3 */ - (X16CLK | SB1), /* write 4 */ - (Tx8 | TxENAB | RTS), /* write 5 */ - 0, 0, 0, /* write 6, 7, 8 */ - (NV), /* write 9 */ - (NRZ), /* write 10 */ - (TCBR | RCBR), /* write 11 */ - 1, 0, /* 38400 baud divisor, write 12 + 13 */ - (BRENABL), /* write 14 */ - (DCDIE) /* write 15 */ +#ifdef CONFIG_KGDB +struct mac_zschannel *zs_kgdbchan; +static unsigned char scc_inittab[] = { + 9, 0x80, /* reset A side (CHRA) */ + 13, 0, /* set baud rate divisor */ + 12, 1, + 14, 1, /* baud rate gen enable, src=rtxc (BRENABL) */ + 11, 0x50, /* clocks = br gen (RCBR | TCBR) */ + 5, 0x6a, /* tx 8 bits, assert RTS (Tx8 | TxENAB | RTS) */ + 4, 0x44, /* x16 clock, 1 stop (SB1 | X16CLK)*/ + 3, 0xc1, /* rx enable, 8 bits (RxENABLE | Rx8)*/ }; - +#endif #define ZS_CLOCK 3686400 /* Z8530 RTxC input clock rate */ DECLARE_TASK_QUEUE(tq_serial); @@ -90,8 +91,8 @@ static int serial_refcount; /* number of characters left in xmit buffer before we ask for more */ #define WAKEUP_CHARS 256 -/* Debugging... DEBUG_INTR is bad to use when one of the zs - * lines is your console ;( +/* + * Debugging. */ #undef SERIAL_DEBUG_INTR #undef SERIAL_DEBUG_OPEN @@ -233,23 +234,6 @@ static inline void zs_rtsdtr(struct mac_serial *ss, int set) return; } -static inline void kgdb_chaninit(struct mac_serial *ss, int intson, int bps) -{ - int brg; - - if (intson) { - kgdb_regs[R1] = INT_ALL_Rx; - kgdb_regs[R9] |= MIE; - } else { - kgdb_regs[R1] = 0; - kgdb_regs[R9] &= ~MIE; - } - brg = BPS_TO_BRG(bps, ZS_CLOCK/16); - kgdb_regs[R12] = brg; - kgdb_regs[R13] = brg >> 8; - load_zsregs(ss->zs_channel, kgdb_regs); -} - /* Utility routines for the Zilog */ static inline int get_zsbaud(struct mac_serial *ss) { @@ -300,8 +284,6 @@ static _INLINE_ void rs_sched_event(struct mac_serial *info, mark_bh(SERIAL_BH); } -extern void breakpoint(void); /* For the KGDB frame character */ - static _INLINE_ void receive_chars(struct mac_serial *info, struct pt_regs *regs) { @@ -313,17 +295,13 @@ static _INLINE_ void receive_chars(struct mac_serial *info, stat = read_zsreg(info->zs_channel, R1); ch = read_zsdata(info->zs_channel); -#if 0 /* KGDB not yet supported */ - /* Look for kgdb 'stop' character, consult the gdb documentation - * for remote target debugging and arch/sparc/kernel/sparc-stub.c - * to see how all this works. - */ - if ((info->kgdb_channel) && (ch =='\003')) { - breakpoint(); - continue; +#ifdef CONFIG_KGDB + if (info->kgdb_channel) { + if (ch == 0x03 || ch == '$') + breakpoint(); + return; } #endif - if (!tty) continue; tty_flip_buffer_push(tty); @@ -767,93 +745,6 @@ static void change_speed(struct mac_serial *info) restore_flags(flags); } -/* This is for console output over ttya/ttyb */ -static void rs_put_char(char ch) -{ - struct mac_zschannel *chan = zs_conschan; - int loops = 0; - unsigned long flags; - - if(!chan) - return; - - save_flags(flags); cli(); - while ((read_zsreg(chan, 0) & Tx_BUF_EMP) == 0) - if (++loops >= 1000000) - break; - write_zsdata(chan, ch); - restore_flags(flags); -} - -/* These are for receiving and sending characters under the kgdb - * source level kernel debugger. - */ -void putDebugChar(char kgdb_char) -{ - struct mac_zschannel *chan = zs_kgdbchan; - - while ((read_zsreg(chan, 0) & Tx_BUF_EMP) == 0) - udelay(5); - write_zsdata(chan, kgdb_char); -} - -char getDebugChar(void) -{ - struct mac_zschannel *chan = zs_kgdbchan; - - while ((read_zsreg(chan, 0) & Rx_CH_AV) == 0) - udelay(5); - return read_zsdata(chan); -} - -/* - * Fair output driver allows a process to speak. - */ -static void rs_fair_output(void) -{ - int left; /* Output no more than that */ - unsigned long flags; - struct mac_serial *info = zs_consinfo; - char c; - - if (info == 0) return; - if (info->xmit_buf == 0) return; - - save_flags(flags); cli(); - left = info->xmit_cnt; - while (left != 0) { - c = info->xmit_buf[info->xmit_tail]; - info->xmit_tail = (info->xmit_tail+1) & (SERIAL_XMIT_SIZE-1); - info->xmit_cnt--; - restore_flags(flags); - - rs_put_char(c); - - save_flags(flags); cli(); - left = MIN(info->xmit_cnt, left-1); - } - - restore_flags(flags); - return; -} - -/* - * zs_console_print is registered for printk. - */ -static void zs_console_print(const char *p) -{ - char c; - - while ((c = *(p++)) != 0) { - if (c == '\n') - rs_put_char('\r'); - rs_put_char(c); - } - - /* Comment this if you want to have a strict interrupt-driven output */ - rs_fair_output(); -} - static void rs_flush_chars(struct tty_struct *tty) { struct mac_serial *info = (struct mac_serial *)tty->driver_data; @@ -1204,6 +1095,10 @@ static int rs_ioctl(struct tty_struct *tty, struct file * file, int error; struct mac_serial * info = (struct mac_serial *)tty->driver_data; +#ifdef CONFIG_KGDB + if (info->kgdb_channel) + return -ENODEV; +#endif if (serial_paranoia_check(info, tty->device, "rs_ioctl")) return -ENODEV; @@ -1340,7 +1235,6 @@ static void rs_close(struct tty_struct *tty, struct file * filp) * At this point we stop accepting input. To do this, we * disable the receiver and receive interrupts. */ - /** if (!info->iscons) ... **/ info->curregs[3] &= ~RxENABLE; info->pendregs[3] = info->curregs[3]; write_zsreg(info->zs_channel, 3, info->curregs[3]); @@ -1580,9 +1474,10 @@ int rs_open(struct tty_struct *tty, struct file * filp) return -ENODEV; info = zs_soft + line; - /* Is the kgdb running over this line? */ +#ifdef CONFIG_KGDB if (info->kgdb_channel) return -ENODEV; +#endif if (serial_paranoia_check(info, tty->device, "rs_open")) return -ENODEV; #ifdef SERIAL_DEBUG_OPEN @@ -1632,6 +1527,13 @@ int rs_open(struct tty_struct *tty, struct file * filp) *tty->termios = info->callout_termios; change_speed(info); } +#ifdef CONFIG_SERIAL_CONSOLE + if (sercons.cflag && sercons.index == line) { + tty->termios->c_cflag = sercons.cflag; + sercons.cflag = 0; + change_speed(info); + } +#endif info->session = current->session; info->pgrp = current->pgrp; @@ -1672,15 +1574,15 @@ probe_sccs() continue; } zs_channels[n].control = (volatile unsigned char *) - ch->addrs[0].address; + ioremap(ch->addrs[0].address, 0x1000); zs_channels[n].data = zs_channels[n].control + ch->addrs[0].size / 2; zs_soft[n].zs_channel = &zs_channels[n]; - zs_soft[n].irq = ch->intrs[0]; - if (request_irq(ch->intrs[0], rs_interrupt, 0, + zs_soft[n].irq = ch->intrs[0].line; + if (request_irq(ch->intrs[0].line, rs_interrupt, 0, "SCC", &zs_soft[n])) - panic("macserial: can't get irq %d", - ch->intrs[0]); + printk(KERN_ERR "macserial: can't get irq %d\n", + ch->intrs[0].line); /* XXX this assumes the prom puts chan A before B */ if (n & 1) zs_soft[n].zs_chan_a = &zs_channels[n-1]; @@ -1769,6 +1671,11 @@ int rs_init(void) save_flags(flags); cli(); for (channel = 0; channel < zs_channels_found; ++channel) { +#ifdef CONFIG_KGDB + if (zs_soft[channel].kgdb_channel) { + continue; + } +#endif zs_soft[channel].clk_divisor = 16; zs_soft[channel].zs_baud = get_zsbaud(&zs_soft[channel]); @@ -1779,17 +1686,15 @@ int rs_init(void) write_zsreg(zs_soft[channel].zs_channel, R9, (NV | MIE)); } - /* If this is the kgdb line, enable interrupts because we - * now want to receive the 'control-c' character from the - * client attached to us asynchronously. - */ - if (zs_soft[channel].kgdb_channel) - kgdb_chaninit(&zs_soft[channel], 1, - zs_soft[channel].zs_baud); } for (info = zs_chain, i = 0; info; info = info->zs_next, i++) { +#ifdef CONFIG_KGDB + if (info->kgdb_channel) { + continue; + } +#endif info->magic = SERIAL_MAGIC; info->port = (int) info->zs_channel->control; info->line = i; @@ -1832,84 +1737,212 @@ void unregister_serial(int line) return; } -extern void register_console(void (*proc)(const char *)); +/* + * ------------------------------------------------------------ + * Serial console driver + * ------------------------------------------------------------ + */ +#ifdef CONFIG_SERIAL_CONSOLE + /* - * Initialization values for when a channel is used for - * a serial console. + * Print a string to the serial port trying not to disturb + * any possible real use of the port... */ -static unsigned char cons_init_regs[16] = { - 0, 0, 0, /* write 0, 1, 2 */ - (Rx8 | RxENABLE), /* write 3 */ - (X16CLK | SB1), /* write 4 */ - (Tx8 | TxENAB | RTS), /* write 5 */ - 0, 0, 0, /* write 6, 7, 8 */ - 0, /* write 9 */ - (NRZ), /* write 10 */ - (TCBR | RCBR), /* write 11 */ - 1, 0, /* 38400 baud divisor, write 12 + 13 */ - (BRENABL), /* write 14 */ - 0 /* write 15 */ -}; +static void serial_console_write(struct console *co, const char *s, + unsigned count) +{ +} /* - * Hooks for running a serial console. con_init() calls this if the - * console is being run over one of the serial ports. - * 'channel' is decoded as 1=modem, 2=printer. + * Receive character from the serial port */ -void -rs_cons_hook(int chip, int out, int channel) +static int serial_console_wait_key(struct console *co) { - int brg; + return 0; +} - if (!out) - return; - if (zs_consinfo != 0) { - printk("rs_cons_hook called twice?\n"); - return; +static kdev_t serial_console_device(struct console *c) +{ + return MKDEV(TTY_MAJOR, 64 + c->index); +} + +/* + * Setup initial baud/bits/parity. We do two things here: + * - construct a cflag setting for the first rs_open() + * - initialize the serial port + * Return non-zero if we didn't find a serial port. + */ +__initfunc(static int serial_console_setup(struct console *co, char *options)) +{ + struct serial_state *ser; + unsigned cval; + int baud = 9600; + int bits = 8; + int parity = 'n'; + int cflag = CREAD | HUPCL | CLOCAL; + int quot = 0; + char *s; + + if (options) { + baud = simple_strtoul(options, NULL, 10); + s = options; + while(*s >= '0' && *s <= '9') + s++; + if (*s) + parity = *s++; + if (*s) + bits = *s - '0'; } - if (zs_chain == 0) - probe_sccs(); - --channel; - if (channel < 0 || channel >= zs_channels_found) { - printk("rs_cons_hook: channel = %d?\n", channel); - return; + + /* + * Now construct a cflag setting. + */ + switch(baud) { + case 1200: + cflag |= B1200; + break; + case 2400: + cflag |= B2400; + break; + case 4800: + cflag |= B4800; + break; + case 19200: + cflag |= B19200; + break; + case 38400: + cflag |= B38400; + break; + case 57600: + cflag |= B57600; + break; + case 115200: + cflag |= B115200; + break; + case 9600: + default: + cflag |= B9600; + break; + } + switch(bits) { + case 7: + cflag |= CS7; + break; + default: + case 8: + cflag |= CS8; + break; + } + switch(parity) { + case 'o': case 'O': + cflag |= PARODD; + break; + case 'e': case 'E': + cflag |= PARENB; + break; } + co->cflag = cflag; - zs_cons_chan = channel; - zs_consinfo = &zs_soft[channel]; - zs_conschan = zs_consinfo->zs_channel; - zs_consinfo->clk_divisor = 16; - zs_consinfo->zs_baud = 38400; - zs_consinfo->is_cons = 1; - - memcpy(zs_consinfo->curregs, cons_init_regs, sizeof(cons_init_regs)); - brg = BPS_TO_BRG(zs_consinfo->zs_baud, ZS_CLOCK/16); - zs_consinfo->curregs[R12] = brg; - zs_consinfo->curregs[R13] = brg >> 8; - load_zsregs(zs_conschan, zs_consinfo->curregs); - - register_console(zs_console_print); - printk("zs%d: console I/O\n", channel); + return 0; } +static struct console sercons = { + "ttyS", + serial_console_write, + NULL, + serial_console_device, + serial_console_wait_key, + NULL, + serial_console_setup, + CON_PRINTBUFFER, + -1, + 0, + NULL +}; + +/* + * Register console. + */ +__initfunc (long serial_console_init(long kmem_start, long kmem_end)) +{ + register_console(&sercons); + return kmem_start; +} +#endif /* ifdef CONFIG_SERIAL_CONSOLE */ +#ifdef CONFIG_KGDB +/* These are for receiving and sending characters under the kgdb + * source level kernel debugger. + */ +void putDebugChar(char kgdb_char) +{ + struct mac_zschannel *chan = zs_kgdbchan; + while ((read_zsreg(chan, 0) & Tx_BUF_EMP) == 0) + udelay(5); + write_zsdata(chan, kgdb_char); +} +char getDebugChar(void) +{ + struct mac_zschannel *chan = zs_kgdbchan; + while((read_zsreg(chan, 0) & Rx_CH_AV) == 0) + eieio(); /*barrier();*/ + return read_zsdata(chan); +} +void kgdb_interruptible(int yes) +{ + struct mac_zschannel *chan = zs_kgdbchan; + int one, nine; + nine = read_zsreg(chan, 9); + if (yes == 1) { + one = EXT_INT_ENAB|INT_ALL_Rx; + nine |= MIE; + printk("turning serial ints on\n"); + } else { + one = RxINT_DISAB; + nine &= ~MIE; + printk("turning serial ints off\n"); + } + write_zsreg(chan, 1, one); + write_zsreg(chan, 9, nine); +} +/* This sets up the serial port we're using, and turns on + * interrupts for that channel, so kgdb is usable once we're done. + */ +static inline void kgdb_chaninit(struct mac_zschannel *ms, int intson, int bps) +{ + int brg; + int i, x; + volatile char *sccc = ms->control; + brg = BPS_TO_BRG(bps, ZS_CLOCK/16); + printk("setting bps on kgdb line to %d [brg=%x]\n", bps, brg); + for (i = 20000; i != 0; --i) { + x = *sccc; eieio(); + } + for (i = 0; i < sizeof(scc_inittab); ++i) { + write_zsreg(ms, scc_inittab[i], scc_inittab[i+1]); + i++; + } +} /* This is called at boot time to prime the kgdb serial debugging - * serial line. The 'tty_num' argument is 0 for /dev/ttyS0 and 1 - * for /dev/ttyS1 which is determined in setup_arch() from the + * serial line. The 'tty_num' argument is 0 for /dev/ttya and 1 + * for /dev/ttyb which is determined in setup_arch() from the * boot command line flags. */ -void -rs_kgdb_hook(int tty_num) +__initfunc(void zs_kgdb_hook(int tty_num)) { + /* Find out how many Z8530 SCCs we have */ if (zs_chain == 0) probe_sccs(); + zs_soft[tty_num].zs_channel = &zs_channels[tty_num]; zs_kgdbchan = zs_soft[tty_num].zs_channel; + zs_soft[tty_num].change_needed = 0; zs_soft[tty_num].clk_divisor = 16; - zs_soft[tty_num].zs_baud = get_zsbaud(&zs_soft[tty_num]); + zs_soft[tty_num].zs_baud = 38400; zs_soft[tty_num].kgdb_channel = 1; /* This runs kgdb */ zs_soft[tty_num ^ 1].kgdb_channel = 0; /* This does not */ /* Turn on transmitter/receiver at 8-bits/char */ - kgdb_chaninit(&zs_soft[tty_num], 0, 9600); - ZS_CLEARERR(zs_kgdbchan); - ZS_CLEARFIFO(zs_kgdbchan); + kgdb_chaninit(zs_soft[tty_num].zs_channel, 1, 38400); + printk("KGDB: on channel %d initialized\n", tty_num); + set_debug_traps(); /* init stub */ } +#endif /* ifdef CONFIG_KGDB */ diff --git a/drivers/macintosh/mediabay.c b/drivers/macintosh/mediabay.c new file mode 100644 index 000000000..6e39367e0 --- /dev/null +++ b/drivers/macintosh/mediabay.c @@ -0,0 +1,236 @@ +/* + * Driver for the media bay on the PowerBook 3400 and 2400. + * + * Copyright (C) 1998 Paul Mackerras. + * + * 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 <linux/config.h> +#include <linux/types.h> +#include <linux/errno.h> +#include <linux/kernel.h> +#include <linux/delay.h> +#include <linux/sched.h> +#include <linux/timer.h> +#include <linux/hdreg.h> +#include <asm/prom.h> +#include <asm/pgtable.h> +#include <asm/io.h> +#include <asm/ohare.h> +#include <asm/mediabay.h> + +struct media_bay_hw { + unsigned char b0; + unsigned char contents; + unsigned char b2; + unsigned char b3; + unsigned feature; +}; + +static volatile struct media_bay_hw *mb_addr; + +#define MB_CONTENTS() ((in_8(&mb_addr->contents) >> 4) & 7) +#define SET_FEATURES(set, clr) \ + out_le32(&mb_addr->feature, \ + (in_le32(&mb_addr->feature) & ~(clr)) | (set)); + +static int media_bay_id = -1; +static int mb_ready; +static int mb_last_value; +static int mb_value_count; + +int media_bay_present; + +#ifdef CONFIG_BLK_DEV_IDE +unsigned long mb_cd_base; +int mb_cd_index = -1; +int mb_cd_irq; + +/* check the busy bit in the media-bay ide interface + (assumes the media-bay contains an ide device) */ +#define MB_IDE_READY() ((in_8((volatile unsigned char *) \ + (mb_cd_base + 0x70)) & 0x80) == 0) +#endif + +/* + * Consider the media-bay ID value stable if it is the same for + * this many consecutive samples (at intervals of 1/HZ seconds). + */ +#define MB_STABLE_COUNT 4 + +/* + * Hold the media-bay reset signal true for this many ticks + * after a device is inserted before releasing it. + */ +#define MB_RESET_COUNT 10 + +/* + * 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. + */ +#define MB_IDE_WAIT 500 + +static void poll_media_bay(void); +static void set_media_bay(int id); + +/* + * 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. + * This causes problems for the interrupt code if we attach an interrupt + * handler to the media-bay interrupt, because it tends to go into + * an infinite loop calling the media bay interrupt handler. + * Therefore we do it all by polling the media bay once each tick. + */ + +void +media_bay_init(void) +{ + struct device_node *np; + + np = find_devices("media-bay"); + if (np == NULL || np->n_addrs == 0) + return; + mb_addr = (volatile struct media_bay_hw *) + ioremap(np->addrs[0].address, sizeof(struct media_bay_hw)); + +#if 0 + if (np->n_intrs == 0) { + printk(KERN_WARNING "No interrupt for media bay?\n"); + } else { + if (request_irq(np->intrs[0].line, media_bay_intr, 0, + "Media bay", NULL)) + printk(KERN_WARNING "Couldn't get IRQ %d for " + "media bay\n", np->intrs[0].line); + } +#endif + + media_bay_present = 1; + set_media_bay(MB_CONTENTS()); + if (media_bay_id != MB_NO) { + SET_FEATURES(0, OH_BAY_RESET); + mb_ready = 1; + } +} + +#if 0 +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 + +int +check_media_bay(int what) +{ + return what == media_bay_id && mb_ready; +} + +/* + * This procedure runs as a kernel thread to poll the media bay + * once each tick and register and unregister the IDE interface + * with the IDE driver. It needs to be a thread because + * ide_register can't be called from interrupt context. + */ +int +media_bay_task(void *x) +{ + int prev = media_bay_id; + int reset_timer = 0; +#ifdef CONFIG_BLK_DEV_IDE + int cd_timer = 0; +#endif + + strcpy(current->comm, "media-bay"); + for (;;) { + poll_media_bay(); + if (media_bay_id != prev) { + reset_timer = (media_bay_id != MB_NO)? + MB_RESET_COUNT: 0; + mb_ready = 0; +#ifdef CONFIG_BLK_DEV_IDE + cd_timer = 0; + if (media_bay_id != MB_CD && mb_cd_index >= 0) { + printk(KERN_DEBUG "Unregistering mb ide\n"); + ide_unregister(mb_cd_index); + mb_cd_index = -1; + } +#endif + } else if (reset_timer) { + if (--reset_timer == 0) { + SET_FEATURES(0, OH_BAY_RESET); + mb_ready = 1; +#ifdef CONFIG_BLK_DEV_IDE + if (media_bay_id == MB_CD && mb_cd_base != 0) + cd_timer = MB_IDE_WAIT; +#endif + } +#ifdef CONFIG_BLK_DEV_IDE + } else if (cd_timer && (--cd_timer == 0 || MB_IDE_READY()) + && mb_cd_index < 0) { + mb_cd_index = ide_register(mb_cd_base, 0, mb_cd_irq); + printk(KERN_DEBUG "media-bay is ide %d\n", mb_cd_index); +#endif + } + + prev = media_bay_id; + current->state = TASK_INTERRUPTIBLE; + current->timeout = jiffies + 1; + schedule(); + if (signal_pending(current)) + return 0; + } +} + +void +poll_media_bay(void) +{ + int id = MB_CONTENTS(); + + if (id == mb_last_value) { + if (id != media_bay_id + && ++mb_value_count >= MB_STABLE_COUNT) + set_media_bay(id); + } else { + mb_last_value = id; + mb_value_count = 0; + } +} + +static void +set_media_bay(int id) +{ + u32 clr, set; + + media_bay_id = id; + mb_last_value = id; + clr = OH_FLOPPY_ENABLE | OH_IDECD_POWER; + set = 0; + switch (id) { + case MB_CD: + set = OH_BAY_ENABLE | OH_IDECD_POWER | OH_BAY_IDE_ENABLE; + printk(KERN_INFO "media bay contains a CD-ROM drive\n"); + break; + case MB_FD: + set = OH_BAY_ENABLE | OH_BAY_FLOPPY_ENABLE | OH_FLOPPY_ENABLE; + printk(KERN_INFO "media bay contains a floppy disk drive\n"); + break; + case MB_NO: + printk(KERN_INFO "media bay is empty\n"); + break; + default: + set = OH_BAY_ENABLE; + printk(KERN_INFO "media bay contains an unknown device (%d)\n", + id); + break; + } + + SET_FEATURES(set, clr); + printk(KERN_DEBUG "feature reg now %x\n", in_le32(&mb_addr->feature)); +} diff --git a/drivers/macintosh/platinum.c b/drivers/macintosh/platinum.c index 34f314df7..d35961d79 100644 --- a/drivers/macintosh/platinum.c +++ b/drivers/macintosh/platinum.c @@ -16,6 +16,7 @@ #include <linux/nvram.h> #include <asm/prom.h> #include <asm/io.h> +#include <asm/pgtable.h> #include <linux/selection.h> #include "pmac-cons.h" #include "platinum.h" @@ -58,6 +59,10 @@ static unsigned char *base_frame_buffer; static struct cmap_regs *cmap_regs; static volatile struct platinum_regs *plat_regs; +static unsigned long frame_buffer_phys; +static unsigned long cmap_regs_phys; +static unsigned long plat_regs_phys; + /* * Register initialization tables for the platinum display. * @@ -403,14 +408,17 @@ map_platinum(struct device_node *dp) size = dp->addrs[i].size; if (size >= 0x400000) { /* frame buffer - map only 4MB */ - frame_buffer = ioremap(addr, 0x400000); + frame_buffer_phys = addr; + frame_buffer = __ioremap(addr, 0x400000, _PAGE_WRITETHRU); base_frame_buffer = frame_buffer; } else { /* registers */ + plat_regs_phys = addr; plat_regs = ioremap(addr, size); } } - cmap_regs = ioremap(0xf301b000, 0x1000); /* XXX not in prom? */ + cmap_regs_phys = 0xf301b000; /* XXX not in prom? */ + cmap_regs = ioremap(cmap_regs_phys, 0x1000); /* Grok total video ram */ plat_regs->reg[16].r = (unsigned)frame_buffer; @@ -560,10 +568,10 @@ platinum_init() display_info.pitch = line_pitch; display_info.mode = video_mode; strncpy(display_info.name, "platinum", sizeof(display_info.name)); - display_info.fb_address = (unsigned long) frame_buffer + 0x10; - display_info.cmap_adr_address = (unsigned long) &cmap_regs->addr; - display_info.cmap_data_address = (unsigned long) &cmap_regs->lut; - display_info.disp_reg_address = (unsigned long) &plat_regs; + display_info.fb_address = frame_buffer_phys + init->fb_offset + 0x10; + display_info.cmap_adr_address = cmap_regs_phys; + display_info.cmap_data_address = cmap_regs_phys + 0x30; + display_info.disp_reg_address = plat_regs_phys; } int diff --git a/drivers/macintosh/pmac-cons.c b/drivers/macintosh/pmac-cons.c index 8c199e94f..731d19fe2 100644 --- a/drivers/macintosh/pmac-cons.c +++ b/drivers/macintosh/pmac-cons.c @@ -26,6 +26,7 @@ #include <linux/selection.h> #include <linux/console_struct.h> #include <linux/vt_kern.h> +#include "../char/console_macros.h" #include "pmac-cons.h" #include "control.h" #include "platinum.h" @@ -95,6 +96,7 @@ struct mon_map { {0x72d, VMODE_832_624_75}, /* 16" RGB (Goldfish) */ {0x730, VMODE_768_576_50I}, /* PAL (Alternate) */ {0x73a, VMODE_1152_870_75}, /* 3rd party 19" */ + {0x73f, VMODE_640_480_67}, /* no sense lines connected at all */ {-1, VMODE_640_480_60}, /* catch-all, must be last */ }; @@ -183,12 +185,22 @@ struct display_interface { aty_setmode, aty_set_palette, aty_set_blanking }, { "ATY,XCLAIMVR", map_aty_display, aty_init, aty_setmode, aty_set_palette, aty_set_blanking }, - { "ATY,RAGEII_M", map_aty_display, aty_init, // untested!! +#if 0 /* problematic */ + { "ATY,RAGEII_M", map_aty_display, aty_init, + aty_setmode, aty_set_palette, aty_set_blanking }, +#endif + { "ATY,XCLAIMVRPro", map_aty_display, aty_init, + aty_setmode, aty_set_palette, aty_set_blanking }, + { "ATY,mach64_3DU", map_aty_display, aty_init, aty_setmode, aty_set_palette, aty_set_blanking }, #endif #ifdef CONFIG_IMSTT_VIDEO - { "IMS,tt128mb", map_imstt_display, imstt_init, - imstt_setmode, imstt_set_palette, imstt_set_blanking }, + { "IMS,tt128mb", map_imstt_display_ibm, imstt_init, + imstt_setmode, imstt_set_palette_ibm, imstt_set_blanking }, + { "IMS,tt128mb8", map_imstt_display_tvp, imstt_init, + imstt_setmode, imstt_set_palette_tvp, imstt_set_blanking }, + { "IMS,tt128mb8A", map_imstt_display_tvp, imstt_init, + imstt_setmode, imstt_set_palette_tvp, imstt_set_blanking }, #endif { NULL } }; @@ -593,6 +605,16 @@ console_setmode(struct vc_mode *mode, int doit) } int +console_setcmap(int n_entries, unsigned char *red, + unsigned char *green, unsigned char *blue) +{ + if (current_display == NULL || current_display->set_palette == NULL) + return -EOPNOTSUPP; + (*current_display->set_palette)(red, green, blue, 0, n_entries); + return 0; +} + +int console_powermode(int mode) { if (mode == VC_POWERMODE_INQUIRY) @@ -600,7 +622,7 @@ console_powermode(int mode) if (mode < VESA_NO_BLANKING || mode > VESA_POWERDOWN) return -EINVAL; if (current_display == NULL || current_display->set_blanking == NULL) - return -ENXIO; + return mode == VESA_NO_BLANKING? 0: -ENXIO; (*current_display->set_blanking)(mode); vesa_blanked = mode; return 0; @@ -890,6 +912,7 @@ static int unknown_modes[] = { static unsigned char *frame_buffer; static unsigned char *unknown_cmap_adr; static volatile unsigned char *unknown_cmap_data; +static unsigned long frame_buffer_phys; static int map_unknown(struct device_node *dp) { @@ -938,7 +961,8 @@ static int map_unknown(struct device_node *dp) address = dp->addrs[i].address; } printk(KERN_INFO "%s: using address %x\n", dp->full_name, address); - frame_buffer = ioremap(address, len); + frame_buffer_phys = address; + frame_buffer = __ioremap(frame_buffer_phys, len, _PAGE_WRITETHRU); video_mode = 0; color_mode = CMODE_8; @@ -961,15 +985,15 @@ static int map_unknown(struct device_node *dp) display_info.pitch = line_pitch; display_info.mode = video_mode; strncpy(display_info.name, dp->name, sizeof(display_info.name)); - display_info.fb_address = (unsigned long) frame_buffer; + display_info.fb_address = frame_buffer_phys; display_info.cmap_adr_address = 0; display_info.cmap_data_address = 0; unknown_cmap_adr = 0; /* XXX kludge for ati */ if (strncmp(dp->name, "ATY,", 4) == 0) { - display_info.disp_reg_address = address + 0x7ffc00; - display_info.cmap_adr_address = address + 0x7ffcc0; - display_info.cmap_data_address = address + 0x7ffcc1; + display_info.disp_reg_address = frame_buffer_phys + 0x7ffc00; + display_info.cmap_adr_address = frame_buffer_phys + 0x7ffcc0; + display_info.cmap_data_address = frame_buffer_phys + 0x7ffcc1; unknown_cmap_adr = ioremap(address + 0x7ff000, 0x1000) + 0xcc0; unknown_cmap_data = unknown_cmap_adr + 1; } diff --git a/drivers/macintosh/valkyrie.c b/drivers/macintosh/valkyrie.c index 63c8fe074..02b81ea72 100644 --- a/drivers/macintosh/valkyrie.c +++ b/drivers/macintosh/valkyrie.c @@ -18,6 +18,7 @@ #include <asm/io.h> #include <asm/adb.h> #include <asm/cuda.h> +#include <asm/pgtable.h> #include <linux/selection.h> #include "pmac-cons.h" #include "valkyrie.h" @@ -62,6 +63,10 @@ static unsigned char *frame_buffer; static struct cmap_regs *cmap_regs; static struct valkyrie_regs *disp_regs; +static unsigned long frame_buffer_phys; +static unsigned long disp_regs_phys; +static unsigned long cmap_regs_phys; + /* * Register initialization tables for the valkyrie display. * @@ -161,7 +166,7 @@ read_valkyrie_sense() __delay(20000); sense |= (in_8(&disp_regs->msense) & 0x60) >> 5; - out_8(&disp_regs->msense, 7); + out_8(&disp_regs->msense, 0); return sense; } @@ -178,9 +183,12 @@ map_valkyrie_display(struct device_node *dp) /* Map in frame buffer and registers */ addr = dp->addrs[0].address; - frame_buffer = ioremap(addr, 0x100000); - disp_regs = ioremap(addr + 0x30a000, 4096); - cmap_regs = ioremap(addr + 0x304000, 4096); + frame_buffer_phys = addr; + frame_buffer = __ioremap(addr, 0x100000, _PAGE_WRITETHRU); + disp_regs_phys = addr + 0x30a000; + disp_regs = ioremap(disp_regs_phys, 4096); + cmap_regs_phys = addr + 0x304000; + cmap_regs = ioremap(cmap_regs_phys, 4096); /* Read the monitor sense value and choose the video mode */ sense = read_valkyrie_sense(); @@ -266,10 +274,10 @@ valkyrie_init() display_info.pitch = line_pitch; display_info.mode = video_mode; strncpy(display_info.name, "valkyrie", sizeof(display_info.name)); - display_info.fb_address = (unsigned long) frame_buffer + 0x1000; - display_info.cmap_adr_address = (unsigned long) &cmap_regs->addr; - display_info.cmap_data_address = (unsigned long) &cmap_regs->lut; - display_info.disp_reg_address = (unsigned long) &disp_regs; + display_info.fb_address = frame_buffer_phys + 0x1000; + display_info.cmap_adr_address = cmap_regs_phys; + display_info.cmap_data_address = cmap_regs_phys + 8; + display_info.disp_reg_address = disp_regs_phys; } int diff --git a/drivers/macintosh/via-cuda.c b/drivers/macintosh/via-cuda.c index 6185e16c5..55fd8ea92 100644 --- a/drivers/macintosh/via-cuda.c +++ b/drivers/macintosh/via-cuda.c @@ -18,6 +18,7 @@ #include <asm/adb.h> #include <asm/cuda.h> #include <asm/io.h> +#include <asm/pgtable.h> #include <asm/system.h> static volatile unsigned char *via; @@ -98,7 +99,7 @@ via_cuda_init() printk(" %x(%x)", vias->addrs[i].address, vias->addrs[i].size); printk(", intrs ="); for (i = 0; i < vias->n_intrs; ++i) - printk(" %x", vias->intrs[i]); + printk(" %x", vias->intrs[i].line); printk("\n"); } #endif @@ -108,7 +109,7 @@ via_cuda_init() if (vias->n_addrs < 1 || vias->n_intrs < 1) return; } - via = (volatile unsigned char *) vias->addrs->address; + via = (volatile unsigned char *) ioremap(vias->addrs->address, 0x2000); if (!init_via()) { printk(KERN_ERR "init_via failed\n"); @@ -117,8 +118,8 @@ via_cuda_init() cuda_state = idle; - if (request_irq(vias->intrs[0], via_interrupt, 0, "VIA", (void *)0)) { - printk(KERN_ERR "VIA: can't get irq %d\n", vias->intrs[0]); + if (request_irq(vias->intrs[0].line, via_interrupt, 0, "VIA", (void *)0)) { + printk(KERN_ERR "VIA: can't get irq %d\n", vias->intrs[0].line); return; } @@ -238,6 +239,14 @@ cuda_send_request(struct adb_request *req) { unsigned long flags; + if (via == NULL) { + req->complete = 1; + return -ENXIO; + } + if (req->nbytes < 2 || req->data[0] > CUDA_PACKET) { + req->complete = 1; + return -EINVAL; + } req->next = 0; req->sent = 0; req->complete = 0; @@ -388,6 +397,17 @@ via_interrupt(int irq, void *arg, struct pt_regs *regs) if (reading_reply) { req = current_req; req->reply_len = reply_ptr - req->reply; + if (req->data[0] == ADB_PACKET) { + /* Have to adjust the reply from ADB commands */ + if (req->reply_len <= 2 || (req->reply[1] & 2) != 0) { + /* the 0x2 bit indicates no response */ + req->reply_len = 0; + } else { + /* leave just the command and result bytes in the reply */ + req->reply_len -= 2; + memmove(req->reply, req->reply + 2, req->reply_len); + } + } req->complete = 1; current_req = req->next; if (req->done) diff --git a/drivers/macintosh/via-pmu.c b/drivers/macintosh/via-pmu.c new file mode 100644 index 000000000..922aed06b --- /dev/null +++ b/drivers/macintosh/via-pmu.c @@ -0,0 +1,669 @@ +/* + * Device driver for the via-pmu on Apple Powermacs. + * + * The VIA (versatile interface adapter) interfaces to the PMU, + * a 6805 microprocessor core whose primary function is to control + * battery charging and system power on the PowerBook 3400 and 2400. + * The PMU also controls the ADB (Apple Desktop Bus) which connects + * to the keyboard and mouse, as well as the non-volatile RAM + * and the RTC (real time clock) chip. + * + * Copyright (C) 1998 Paul Mackerras and Fabio Riccardi. + */ +#include <stdarg.h> +#include <linux/types.h> +#include <linux/errno.h> +#include <linux/kernel.h> +#include <linux/delay.h> +#include <linux/sched.h> +#include <asm/prom.h> +#include <asm/adb.h> +#include <asm/pmu.h> +#include <asm/cuda.h> +#include <asm/io.h> +#include <asm/pgtable.h> +#include <asm/system.h> + +static volatile unsigned char *via; + +/* VIA registers - spaced 0x200 bytes apart */ +#define RS 0x200 /* skip between registers */ +#define B 0 /* B-side data */ +#define A RS /* A-side data */ +#define DIRB (2*RS) /* B-side direction (1=output) */ +#define DIRA (3*RS) /* A-side direction (1=output) */ +#define T1CL (4*RS) /* Timer 1 ctr/latch (low 8 bits) */ +#define T1CH (5*RS) /* Timer 1 counter (high 8 bits) */ +#define T1LL (6*RS) /* Timer 1 latch (low 8 bits) */ +#define T1LH (7*RS) /* Timer 1 latch (high 8 bits) */ +#define T2CL (8*RS) /* Timer 2 ctr/latch (low 8 bits) */ +#define T2CH (9*RS) /* Timer 2 counter (high 8 bits) */ +#define SR (10*RS) /* Shift register */ +#define ACR (11*RS) /* Auxiliary control register */ +#define PCR (12*RS) /* Peripheral control register */ +#define IFR (13*RS) /* Interrupt flag register */ +#define IER (14*RS) /* Interrupt enable register */ +#define ANH (15*RS) /* A-side data, no handshake */ + +/* Bits in B data register: both active low */ +#define TACK 0x08 /* Transfer acknowledge (input) */ +#define TREQ 0x10 /* Transfer request (output) */ + +/* Bits in ACR */ +#define SR_CTRL 0x1c /* Shift register control bits */ +#define SR_EXT 0x0c /* Shift on external clock */ +#define SR_OUT 0x10 /* Shift out if 1 */ + +/* Bits in IFR and IER */ +#define IER_SET 0x80 /* set bits in IER */ +#define IER_CLR 0 /* clear bits in IER */ +#define SR_INT 0x04 /* Shift register full/empty */ +#define CB1_INT 0x10 /* transition on CB1 input */ + +static enum pmu_state { + idle, + sending, + intack, + reading, + reading_intr, +} pmu_state; + +static struct adb_request *current_req; +static struct adb_request *last_req; +static struct adb_request *req_awaiting_reply; +static unsigned char interrupt_data[32]; +static unsigned char *reply_ptr; +static int data_index; +static int data_len; +static 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; + +static int init_pmu(void); +static int pmu_queue_request(struct adb_request *req); +static void pmu_start(void); +static void via_pmu_interrupt(int irq, void *arg, struct pt_regs *regs); +static int pmu_adb_send_request(struct adb_request *req, int sync); +static int pmu_adb_autopoll(int on); +static void send_byte(int x); +static void recv_byte(void); +static void pmu_sr_intr(struct pt_regs *regs); +static void pmu_done(struct adb_request *req); +static void pmu_handle_data(unsigned char *data, int len, + struct pt_regs *regs); +static void set_brightness(int level); +static void set_volume(int level); + +/* + * This table indicates for each PMU opcode: + * - the number of data bytes to be sent with the command, or -1 + * if a length byte should be sent, + * - the number of response bytes which the PMU will return, or + * -1 if it will send a length byte. + */ +static s8 pmu_data_len[256][2] = { +/* 0 1 2 3 4 5 6 7 */ +/*00*/ {-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0}, +/*08*/ {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, +/*10*/ { 1, 0},{ 1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0}, +/*18*/ { 0, 1},{ 0, 1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{ 0, 0}, +/*20*/ {-1, 0},{ 0, 0},{ 2, 0},{ 1, 0},{ 1, 0},{-1, 0},{-1, 0},{-1, 0}, +/*28*/ { 0,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, +/*30*/ { 4, 0},{20, 0},{ 2, 0},{ 3, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0}, +/*38*/ { 0, 4},{ 0,20},{ 1, 1},{ 2, 1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, +/*40*/ { 1, 0},{ 1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0}, +/*48*/ { 0, 1},{ 0, 1},{-1,-1},{-1,-1},{ 1, 0},{-1,-1},{-1,-1},{-1,-1}, +/*50*/ { 1, 0},{ 0, 0},{ 2, 0},{ 2, 0},{-1, 0},{ 1, 0},{ 3, 0},{ 1, 0}, +/*58*/ { 0, 1},{ 1, 0},{ 0, 2},{ 0, 2},{ 0,-1},{-1,-1},{-1,-1},{-1,-1}, +/*60*/ { 2, 0},{-1, 0},{ 2, 0},{ 0, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0}, +/*68*/ { 0, 3},{ 0, 3},{ 0, 2},{ 0, 8},{ 0,-1},{ 0,-1},{-1,-1},{-1,-1}, +/*70*/ { 1, 0},{ 1, 0},{ 1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0}, +/*78*/ { 0,-1},{ 0,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{ 4, 1},{ 4, 1}, +/*80*/ { 4, 0},{-1, 0},{ 0, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0}, +/*88*/ { 0, 5},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, +/*90*/ { 1, 0},{ 2, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0}, +/*98*/ { 0, 1},{ 0, 1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, +/*a0*/ { 2, 0},{ 2, 0},{ 2, 0},{ 4, 0},{-1, 0},{ 0, 0},{-1, 0},{-1, 0}, +/*a8*/ { 1, 1},{ 1, 0},{ 3, 0},{ 2, 0},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, +/*b0*/ {-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0}, +/*b8*/ {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, +/*c0*/ {-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0}, +/*c8*/ {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, +/*d0*/ { 0, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0}, +/*d8*/ { 1, 1},{ 1, 1},{-1,-1},{-1,-1},{ 0, 1},{ 0,-1},{-1,-1},{-1,-1}, +/*e0*/ {-1, 0},{ 4, 0},{ 0, 1},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0}, +/*e8*/ { 3,-1},{-1,-1},{ 0, 1},{-1,-1},{ 0,-1},{-1,-1},{-1,-1},{ 0, 0}, +/*f0*/ {-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0}, +/*f8*/ {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, +}; + +void +via_pmu_init() +{ + struct device_node *vias; + + vias = find_devices("via-pmu"); + if (vias == 0) + return; + if (vias->next != 0) + printk(KERN_WARNING "Warning: only using 1st via-pmu\n"); + +#if 0 + { int i; + + printk("via_pmu_init: node = %p, addrs =", vias->node); + for (i = 0; i < vias->n_addrs; ++i) + printk(" %x(%x)", vias->addrs[i].address, vias->addrs[i].size); + printk(", intrs ="); + for (i = 0; i < vias->n_intrs; ++i) + printk(" %x", vias->intrs[i].line); + printk("\n"); } +#endif + + 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; + } + via = (volatile unsigned char *) ioremap(vias->addrs->address, 0x2000); + + out_8(&via[IER], IER_CLR | 0x7f); /* disable all intrs */ + + pmu_state = idle; + + if (!init_pmu()) + return; + + if (request_irq(vias->intrs[0].line, via_pmu_interrupt, 0, "VIA-PMU", + (void *)0)) { + printk(KERN_ERR "VIA-PMU: can't get irq %d\n", + vias->intrs[0].line); + return; + } + + /* Enable interrupts */ + out_8(&via[IER], IER_SET | SR_INT | CB1_INT); + + /* Set function pointers */ + adb_hardware = ADB_VIAPMU; + adb_send_request = pmu_adb_send_request; + adb_autopoll = pmu_adb_autopoll; + + bright_req_1.complete = 1; + bright_req_2.complete = 1; +} + +static int +init_pmu() +{ + int timeout; + struct adb_request req; + + out_8(&via[B], via[B] | TREQ); /* negate TREQ */ + out_8(&via[DIRB], (via[DIRB] | TREQ) & ~TACK); /* TACK in, TREQ out */ + + pmu_request(&req, NULL, 2, PMU_SET_INTR_MASK, 0xff); + timeout = 100000; + while (!req.complete) { + if (--timeout < 0) { + printk(KERN_ERR "init_pmu: no response from PMU\n"); + return 0; + } + udelay(10); + pmu_poll(); + } + + /* ack all pending interrupts */ + timeout = 100000; + interrupt_data[0] = 1; + while (interrupt_data[0] || pmu_state != idle) { + if (--timeout < 0) { + printk(KERN_ERR "init_pmu: timed out acking intrs\n"); + return 0; + } + if (pmu_state == idle) + adb_int_pending = 1; + via_pmu_interrupt(0, 0, 0); + udelay(10); + } + + return 1; +} + +/* Send an ADB command */ +static int +pmu_adb_send_request(struct adb_request *req, int sync) +{ + int i; + + for (i = req->nbytes - 1; i > 0; --i) + req->data[i+3] = req->data[i]; + req->data[3] = req->nbytes - 1; + req->data[2] = pmu_adb_flags; + req->data[1] = req->data[0]; + req->data[0] = PMU_ADB_CMD; + req->nbytes += 3; + req->reply_expected = 1; + req->reply_len = 0; + i = pmu_queue_request(req); + if (i) + return i; + if (sync) { + while (!req->complete) + pmu_poll(); + } + return 0; +} + +/* Enable/disable autopolling */ +static int +pmu_adb_autopoll(int on) +{ + struct adb_request req; + + if (on) { + pmu_request(&req, NULL, 5, PMU_ADB_CMD, 0, 0x86, + adb_dev_map >> 8, adb_dev_map); + pmu_adb_flags = 2; + } else { + pmu_request(&req, NULL, 1, PMU_ADB_POLL_OFF); + pmu_adb_flags = 0; + } + while (!req.complete) + pmu_poll(); + return 0; +} + +/* Construct and send a pmu request */ +int +pmu_request(struct adb_request *req, void (*done)(struct adb_request *), + int nbytes, ...) +{ + va_list list; + int i; + + if (nbytes < 0 || nbytes > 32) { + printk(KERN_ERR "pmu_request: bad nbytes (%d)\n", nbytes); + req->complete = 1; + return -EINVAL; + } + req->nbytes = nbytes; + req->done = done; + va_start(list, nbytes); + for (i = 0; i < nbytes; ++i) + req->data[i] = va_arg(list, int); + va_end(list); + if (pmu_data_len[req->data[0]][1] != 0) { + req->reply[0] = ADB_RET_OK; + req->reply_len = 1; + } else + req->reply_len = 0; + req->reply_expected = 0; + return pmu_queue_request(req); +} + +/* + * This procedure handles requests written to /dev/adb where the + * first byte is CUDA_PACKET or PMU_PACKET. For CUDA_PACKET, we + * emulate a few CUDA requests. + */ +int +pmu_send_request(struct adb_request *req) +{ + int i; + + switch (req->data[0]) { + case PMU_PACKET: + for (i = 0; i < req->nbytes - 1; ++i) + req->data[i] = req->data[i+1]; + --req->nbytes; + if (pmu_data_len[req->data[0]][1] != 0) { + req->reply[0] = ADB_RET_OK; + req->reply_len = 1; + } else + req->reply_len = 0; + return pmu_queue_request(req); + case CUDA_PACKET: + switch (req->data[1]) { + case CUDA_GET_TIME: + if (req->nbytes != 2) + break; + req->data[0] = PMU_READ_RTC; + req->nbytes = 1; + req->reply_len = 3; + req->reply[0] = CUDA_PACKET; + req->reply[1] = 0; + req->reply[2] = CUDA_GET_TIME; + return pmu_queue_request(req); + case CUDA_SET_TIME: + if (req->nbytes != 6) + break; + req->data[0] = PMU_SET_RTC; + req->nbytes = 5; + for (i = 1; i <= 4; ++i) + req->data[i] = req->data[i+1]; + req->reply_len = 0; + return pmu_queue_request(req); + } + break; + } + return -EINVAL; +} + +int +pmu_queue_request(struct adb_request *req) +{ + unsigned long flags; + int nsend; + + if (via == NULL) { + req->complete = 1; + return -ENXIO; + } + if (req->nbytes <= 0) { + req->complete = 1; + return 0; + } + nsend = pmu_data_len[req->data[0]][0]; + if (nsend >= 0 && req->nbytes != nsend + 1) { + req->complete = 1; + return -EINVAL; + } + + req->next = 0; + req->sent = 0; + req->complete = 0; + save_flags(flags); cli(); + + if (current_req != 0) { + last_req->next = req; + last_req = req; + } else { + current_req = req; + last_req = req; + if (pmu_state == idle) + pmu_start(); + } + + restore_flags(flags); + return 0; +} + +static void +send_byte(int x) +{ + out_8(&via[ACR], 0x1c); + out_8(&via[SR], x); + out_8(&via[B], via[B] & ~0x10); /* assert TREQ */ +} + +static void +recv_byte() +{ + out_8(&via[ACR], 0x0c); + in_8(&via[SR]); /* resets SR */ + out_8(&via[B], via[B] & ~0x10); +} + +static void +pmu_start() +{ + unsigned long flags; + struct adb_request *req; + + /* assert pmu_state == idle */ + /* get the packet to send */ + save_flags(flags); cli(); + req = current_req; + if (req == 0 || pmu_state != idle + || (req->reply_expected && req_awaiting_reply)) + goto out; + + pmu_state = sending; + data_index = 1; + data_len = pmu_data_len[req->data[0]][0]; + + /* set the shift register to shift out and send a byte */ + send_byte(req->data[0]); + +out: + restore_flags(flags); +} + +void +pmu_poll() +{ + int ie; + + ie = _disable_interrupts(); + if (via[IFR] & (SR_INT | CB1_INT)) + via_pmu_interrupt(0, 0, 0); + _enable_interrupts(ie); +} + +static void +via_pmu_interrupt(int irq, void *arg, struct pt_regs *regs) +{ + int intr; + int nloop = 0; + + while ((intr = (in_8(&via[IFR]) & (SR_INT | CB1_INT))) != 0) { + if (++nloop > 1000) { + printk(KERN_DEBUG "PMU: stuck in intr loop, " + "intr=%x pmu_state=%d\n", intr, pmu_state); + break; + } + if (intr & SR_INT) + pmu_sr_intr(regs); + else if (intr & CB1_INT) { + adb_int_pending = 1; + out_8(&via[IFR], CB1_INT); + } + } + if (pmu_state == idle) { + if (adb_int_pending) { + pmu_state = intack; + send_byte(PMU_INT_ACK); + adb_int_pending = 0; + } else if (current_req) { + pmu_start(); + } + } +} + +static void +pmu_sr_intr(struct pt_regs *regs) +{ + struct adb_request *req; + int bite, timeout; + + if (via[B] & TACK) + printk(KERN_DEBUG "PMU: sr_intr but ack still high! (%x)\n", + via[B]); + + /* if reading grab the byte, and reset the interrupt */ + if ((via[ACR] & SR_OUT) == 0) + bite = in_8(&via[SR]); + out_8(&via[IFR], SR_INT); + + /* reset TREQ and wait for TACK to go high */ + out_8(&via[B], via[B] | TREQ); + timeout = 3200; + while ((in_8(&via[B]) & TACK) == 0) { + if (--timeout < 0) { + printk(KERN_ERR "PMU not responding (!ack)\n"); + return; + } + udelay(10); + } + + switch (pmu_state) { + case sending: + req = current_req; + if (data_len < 0) { + data_len = req->nbytes - 1; + send_byte(data_len); + break; + } + if (data_index <= data_len) { + send_byte(req->data[data_index++]); + break; + } + req->sent = 1; + data_len = pmu_data_len[req->data[0]][1]; + if (data_len == 0) { + pmu_state = idle; + current_req = req->next; + if (req->reply_expected) + req_awaiting_reply = req; + else + pmu_done(req); + } else { + pmu_state = reading; + data_index = 0; + reply_ptr = req->reply + req->reply_len; + recv_byte(); + } + break; + + case intack: + data_index = 0; + data_len = -1; + pmu_state = reading_intr; + reply_ptr = interrupt_data; + recv_byte(); + break; + + case reading: + case reading_intr: + if (data_len == -1) { + data_len = bite; + if (bite > 32) + printk(KERN_ERR "PMU: bad reply len %d\n", + bite); + } else { + reply_ptr[data_index++] = bite; + } + if (data_index < data_len) { + recv_byte(); + break; + } + + if (pmu_state == reading_intr) { + pmu_handle_data(interrupt_data, data_index, regs); + } else { + req = current_req; + current_req = req->next; + req->reply_len += data_index; + pmu_done(req); + } + pmu_state = idle; + + break; + + default: + printk(KERN_ERR "via_pmu_interrupt: unknown state %d?\n", + pmu_state); + } +} + +static void +pmu_done(struct adb_request *req) +{ + req->complete = 1; + if (req->done) + (*req->done)(req); +} + +/* Interrupt data could be the result data from an ADB cmd */ +static void +pmu_handle_data(unsigned char *data, int len, struct pt_regs *regs) +{ + static int show_pmu_ints = 1; + + if (len < 1) { + adb_int_pending = 0; + return; + } + if (data[0] & PMU_INT_ADB) { + if ((data[0] & PMU_INT_ADB_AUTO) == 0) { + struct adb_request *req = req_awaiting_reply; + if (req == 0) { + printk(KERN_ERR "PMU: extra ADB reply\n"); + return; + } + req_awaiting_reply = 0; + if (len <= 2) + req->reply_len = 0; + else { + memcpy(req->reply, data + 1, len - 1); + req->reply_len = len - 1; + } + pmu_done(req); + } else { + adb_input(data+1, len-1, regs, 1); + } + } else { + if (data[0] == 0x08 && len == 3) { + /* sound/brightness buttons pressed */ + set_brightness(data[1]); + set_volume(data[2]); + } else if (show_pmu_ints + && !(data[0] == PMU_INT_TICK && len == 1)) { + int i; + printk(KERN_DEBUG "pmu intr"); + for (i = 0; i < len; ++i) + printk(" %.2x", data[i]); + printk("\n"); + } + } +} + +int backlight_bright = -1; +int backlight_enabled = 0; + +#define LEVEL_TO_BRIGHT(lev) ((lev) < 8? 0x7f: 0x4a - ((lev) >> 2)) + +void +pmu_enable_backlight(int on) +{ + struct adb_request req; + + if (on) { + if (backlight_bright < 0) { + pmu_request(&req, NULL, 2, 0xd9, 0); + while (!req.complete) + pmu_poll(); + backlight_bright = LEVEL_TO_BRIGHT(req.reply[1]); + } + pmu_request(&req, NULL, 2, PMU_BACKLIGHT_BRIGHT, + backlight_bright); + while (!req.complete) + pmu_poll(); + } + pmu_request(&req, NULL, 2, PMU_BACKLIGHT_CTRL, on? 0x81: 1); + while (!req.complete) + pmu_poll(); + backlight_enabled = on; +} + +static void +set_brightness(int level) +{ + backlight_bright = LEVEL_TO_BRIGHT(level); + if (bright_req_1.complete) + pmu_request(&bright_req_1, NULL, 2, PMU_BACKLIGHT_BRIGHT, + backlight_bright); + if (bright_req_2.complete) { + backlight_enabled = backlight_bright < 0x7f; + pmu_request(&bright_req_2, NULL, 2, PMU_BACKLIGHT_CTRL, + backlight_enabled? 0x81: 1); + } +} + +static void +set_volume(int level) +{ +} |