From: Philipp R. <pr...@pa...> - 2001-01-30 20:19:12
|
Obvious-ish updates to the EC3104/Epson 1355 code (as tested on my Aero 8000). This contains some more debugging/dead code which will be removed once everything's a bit more stable. Philipp Rumpf diff -urNx CVS linuxsh/kernel/arch/sh/kernel/setup_ec3104.c linux-aero/arch/sh/kernel/setup_ec3104.c --- linuxsh/kernel/arch/sh/kernel/setup_ec3104.c Mon Dec 25 16:07:13 2000 +++ linux-aero/arch/sh/kernel/setup_ec3104.c Sat Jan 27 04:40:19 2001 @@ -42,10 +42,32 @@ * 8 serial (2) b0ec8000 b0ec0020 00000100 * 9 serial (3) b0ec9000 b0ec0024 00000200 * 10 serial (4) b0eca000 b0ec0028 00000400 + * 12 GPIO (1) b0ecc000 b0ec0030 + * 13 GPIO (2) b0ecc000 b0ec0030 * 16 pcmcia (1) b0ed0000 b0ec0040 00010000 * 17 pcmcia (2) b0ed1000 b0ec0044 00020000 */ +/* I used the register names from another interrupt controller I worked with, + * since it seems to be identical to the ec3104 except that all bits are + * inverted: + * + * IRR: Interrupt Request Register (pending and enabled interrupts) + * IMR: Interrupt Mask Register (which interrupts are enabled) + * IPR: Interrupt Pending Register (pending interrupts, even disabled ones) + * + * 0 bits mean pending or enabled, 1 bits mean not pending or disabled. all + * IRQs seem to be level-triggered. + */ + +#define EC3104_IRR (EC3104_BASE + 0x1000) +#define EC3104_IMR (EC3104_BASE + 0x1004) +#define EC3104_IPR (EC3104_BASE + 0x1008) + +#define ctrl_readl(addr) (*(volatile u32 *)(addr)) +#define ctrl_writel(data,addr) (*(volatile u32 *)(addr) = (data)) +#define ctrl_readb(addr) (*(volatile u8 *)(addr)) + static char *ec3104_name(unsigned index) { switch(index) { @@ -83,26 +105,25 @@ } } -/* I used the register names from another interrupt controller I worked with, - * since it seems to be identical to the ec3104 except that all bits are - * inverted: - * - * IRR: Interrupt Request Register (pending and enabled interrupts) - * IMR: Interrupt Mask Register (which interrupts are enabled) - * IPR: Interrupt Pending Register (pending interrupts, even disabled ones) - * - * 0 bits mean pending or enabled, 1 bits mean not pending or disabled. all - * IRQs seem to be level-triggered. - */ - -#define EC3104_IRR (EC3104_BASE + 0x1000) -#define EC3104_IMR (EC3104_BASE + 0x1004) -#define EC3104_IPR (EC3104_BASE + 0x1008) - -#define ctrl_readl(addr) (*(volatile u32 *)(addr)) -#define ctrl_writel(data,addr) (*(volatile u32 *)(addr) = (data)) -#define ctrl_readb(addr) (*(volatile u8 *)(addr)) +int get_pending_interrupts(char *buf) +{ + u32 ipr; + u32 bit; + char *p = buf; + + p += sprintf(p, "pending: ("); + + ipr = ctrl_inl(EC3104_IPR); + + for (bit = 1; bit < 32; bit++) + if (!(ipr & (1<<bit))) + p += sprintf(p, "%s ", ec3104_name(bit)); + + p += sprintf(p, ")\n"); + return p - buf; +} + static inline u32 ec3104_irq2mask(unsigned int irq) { return (1 << (irq - EC3104_IRQBASE)); diff -urNx CVS linuxsh/kernel/drivers/char/ec3104_keyb.c linux-aero/drivers/char/ec3104_keyb.c --- linuxsh/kernel/drivers/char/ec3104_keyb.c Mon Dec 25 16:07:13 2000 +++ linux-aero/drivers/char/ec3104_keyb.c Sat Jan 27 04:35:59 2001 @@ -60,10 +60,12 @@ #define MSR_CTS 0x10 #define MCR_RTS 0x02 #define LSR_DR 0x01 +#define LSR_BOTH_EMPTY 0x60 -static struct ec3104_keyb_struct { - u8 packet[3]; +static struct e5_struct { + u8 packet[8]; int pos; + int length; u8 cached_mcr; u8 last_msr; @@ -192,6 +194,9 @@ case 106: /* Fn */ /* this is wrong. */ return 84; + + default: + return 0; } } @@ -222,30 +227,153 @@ { } -static void ec3104_keyb_receive(struct ec3104_keyb_struct *k) +static u8 e5_checksum(u8 *packet, int count) +{ + int i; + u8 sum = 0; + + for (i=0; i<count; i++) + sum ^= packet[i]; + + if (sum & 0x80) + sum ^= 0xc0; + + return sum; +} + +static void e5_wait_for_cts(struct e5_struct *k) +{ + u8 msr; + + do { + msr = ctrl_inb(EC3104_SER4_MSR); + } while (!(msr & MSR_CTS)); +} + + +static void e5_send_byte(u8 byte, struct e5_struct *k) +{ + u8 status; + + do { + status = ctrl_inb(EC3104_SER4_LSR); + } while ((status & LSR_BOTH_EMPTY) != LSR_BOTH_EMPTY); + + printk("<%02x>", byte); + + ctrl_outb(byte, EC3104_SER4_DATA); + + do { + status = ctrl_inb(EC3104_SER4_LSR); + } while ((status & LSR_BOTH_EMPTY) != LSR_BOTH_EMPTY); + +} + +static int e5_send_packet(u8 *packet, int count, struct e5_struct *k) +{ + int i; + + disable_irq(EC3104_IRQ_SER4); + + if (k->cached_mcr & MCR_RTS) { + printk("e5_send_packet: too slow\n"); + enable_irq(EC3104_IRQ_SER4); + return -EAGAIN; + } + + k->cached_mcr |= MCR_RTS; + ctrl_outb(k->cached_mcr, EC3104_SER4_MCR); + + e5_wait_for_cts(k); + + printk("p: "); + + for(i=0; i<count; i++) + e5_send_byte(packet[i], k); + + e5_send_byte(e5_checksum(packet, count), k); + + printk("\n"); + + udelay(1500); + + k->cached_mcr &= ~MCR_RTS; + ctrl_outb(k->cached_mcr, EC3104_SER4_MCR); + + set_current_state(TASK_UNINTERRUPTIBLE); + + + + enable_irq(EC3104_IRQ_SER4); + + + + return 0; +} + +/* + * E5 packets we know about: + * E5->host 0x80 0x05 <checksum> - resend packet + * host->E5 0x83 0x43 <contrast> - set LCD contrast + * host->E5 0x85 0x41 0x02 <brightness> 0x02 - set LCD backlight + * E5->host 0x87 <ps2 packet> 0x00 <checksum> - external PS2 + * E5->host 0x88 <scancode> <checksum> - key press + */ + +static void e5_receive(struct e5_struct *k) { k->packet[k->pos++] = ctrl_inb(EC3104_SER4_DATA); - /* All E5 packets I've seen look like this: - * 0x88 <scancode> <mystery byte>. mystery byte seems to depend on the - * key that was pressed only so we ignore it (scancode has all the - * information we need). - */ - - if (k->pos == 3) { - if (k->packet[0] != 0x88) - printk(KERN_WARNING "got bogus EC3104/E5 packet (%02x)\n", + if (k->pos == 1) { + switch(k->packet[0]) { + case 0x80: + k->length = 3; + break; + + case 0x87: /* PS2 ext */ + k->length = 6; + break; + + case 0x88: /* keyboard */ + k->length = 3; + break; + + default: + k->length = 1; + printk(KERN_WARNING "unknown E5 packet %02x\n", k->packet[0]); + } + } - handle_keyboard_event(k->packet[1]); - - k->pos = 0; + if (k->pos == k->length) { + int i; + + if (e5_checksum(k->packet, k->length) != 0) + printk(KERN_WARNING "E5: wrong checksum\n"); + +#if 0 + printk("E5 packet ["); + for(i=0; i<k->length; i++) { + printk("%02x ", k->packet[i]); + } + + printk("(%02x)]\n", e5_checksum(k->packet, k->length-1)); +#endif + + switch(k->packet[0]) { + case 0x80: + case 0x88: + handle_keyboard_event(k->packet[1]); + break; + } + + k->pos = k->length = 0; } } static void ec3104_keyb_interrupt(int irq, void *data, struct pt_regs *regs) { - struct ec3104_keyb_struct *k = &ec3104_keyb; + struct e5_struct *k = &ec3104_keyb; u8 msr, lsr; kbd_pt_regs = regs; @@ -274,12 +402,12 @@ lsr = ctrl_inb(EC3104_SER4_LSR); if (lsr & LSR_DR) - ec3104_keyb_receive(k); + e5_receive(k); } static void ec3104_keyb_clear_state(void) { - struct ec3104_keyb_struct *k = &ec3104_keyb; + struct e5_struct *k = &ec3104_keyb; u8 msr, lsr; /* we want CTS to be low */ @@ -293,7 +421,7 @@ lsr = ctrl_inb(EC3104_SER4_LSR); if (lsr & LSR_DR) { - ec3104_keyb_receive(k); + e5_receive(k); continue; } diff -urNx CVS linuxsh/kernel/drivers/video/Config.in linux-aero/drivers/video/Config.in --- linuxsh/kernel/drivers/video/Config.in Tue Jan 30 07:15:17 2001 +++ linux-aero/drivers/video/Config.in Sat Jan 27 04:47:54 2001 @@ -98,7 +98,11 @@ bool ' CGsix (GX,TurboGX) support' CONFIG_FB_CGSIX fi fi - bool 'Epson 1355 framebuffer support' CONFIG_FB_E1355 + bool ' Epson 1355 framebuffer support' CONFIG_FB_E1355 + if [ "$CONFIG_FB_E1355" = "y" ]; then + hex ' Register Base Address' CONFIG_E1355_REG_BASE a8000000 + hex ' Framebuffer Base Address' CONFIG_E1355_FB_BASE a8200000 + fi if [ "$CONFIG_SH_DREAMCAST" = "y" ]; then tristate ' Dreamcast Frame Buffer support' CONFIG_FB_DC fi diff -urNx CVS linuxsh/kernel/drivers/video/epson1355fb.c linux-aero/drivers/video/epson1355fb.c --- linuxsh/kernel/drivers/video/epson1355fb.c Mon Dec 25 19:02:08 2000 +++ linux-aero/drivers/video/epson1355fb.c Fri Jan 26 09:41:04 2001 @@ -15,6 +15,7 @@ * 16 bpp support * crt support * hw cursor support + * SwivelView */ #include <asm/io.h> @@ -38,14 +39,14 @@ #define E1355_PANEL 0x02 #define E1355_DISPLAY 0x0D +#define E1355_MISC 0x1B #define E1355_GPIO 0x20 #define E1355_LUT_INDEX 0x24 #define E1355_LUT_DATA 0x26 #ifdef CONFIG_SUPERH -/* tell me if your machine has a different base address .. */ -#define E1355_REG_BASE 0xB0000000 -#define E1355_FB_BASE 0xB0200000 +#define E1355_REG_BASE CONFIG_E1355_REG_BASE +#define E1355_FB_BASE CONFIG_E1355_FB_BASE static inline u8 e1355_read_reg(int index) { @@ -87,16 +88,30 @@ /* ------------------- chipset specific functions -------------------------- */ +static void disable_hw_cursor(void) +{ + u8 curs; + + curs = e1355_read_reg(0x27); + curs &= ~0xc0; + e1355_write_reg(curs, 0x27); +} + static void e1355_detect(void) { u8 rev; + e1355_write_reg(0x00, E1355_MISC); + rev = e1355_read_reg(0x00); if ((rev & 0xfc) != 0x0c) { printk(KERN_WARNING "Epson 1355 not detected\n"); } + /* XXX */ + disable_hw_cursor(); + e1355_encode_var(&default_var, NULL, NULL); } @@ -373,7 +388,7 @@ * The AERO_HACKS parts disable/enable the backlight on the Compaq Aero 8000. * I'm not sure they aren't dangerous to the hardware, so be warned. */ -#define AERO_HACKS +#undef AERO_HACKS static int e1355_blank(int blank_mode, struct fb_info_gen *info) { @@ -478,19 +493,8 @@ return 0; } -static void disable_hw_cursor(void) -{ - u8 curs; - - curs = e1355_read_reg(0x27); - curs &= ~0xc0; - e1355_write_reg(curs, 0x27); -} - int __init e1355fb_init(void) { - disable_hw_cursor(); - fb_info.gen.fbhw = &e1355_switch; fb_info.gen.fbhw->detect(); strcpy(fb_info.gen.info.modename, "SED1355"); |