Path: blob/master/arch/arm/mach-footbridge/netwinder-hw.c
10817 views
/*1* linux/arch/arm/mach-footbridge/netwinder-hw.c2*3* Netwinder machine fixup4*5* Copyright (C) 1998, 1999 Russell King, Phil Blundell6*/7#include <linux/module.h>8#include <linux/ioport.h>9#include <linux/kernel.h>10#include <linux/delay.h>11#include <linux/init.h>12#include <linux/io.h>13#include <linux/spinlock.h>1415#include <asm/hardware/dec21285.h>16#include <asm/leds.h>17#include <asm/mach-types.h>18#include <asm/setup.h>1920#include <asm/mach/arch.h>2122#include "common.h"2324#define IRDA_IO_BASE 0x18025#define GP1_IO_BASE 0x33826#define GP2_IO_BASE 0x33a272829#ifdef CONFIG_LEDS30#define DEFAULT_LEDS 031#else32#define DEFAULT_LEDS GPIO_GREEN_LED33#endif3435/*36* Winbond WB83977F accessibility stuff37*/38static inline void wb977_open(void)39{40outb(0x87, 0x370);41outb(0x87, 0x370);42}4344static inline void wb977_close(void)45{46outb(0xaa, 0x370);47}4849static inline void wb977_wb(int reg, int val)50{51outb(reg, 0x370);52outb(val, 0x371);53}5455static inline void wb977_ww(int reg, int val)56{57outb(reg, 0x370);58outb(val >> 8, 0x371);59outb(reg + 1, 0x370);60outb(val & 255, 0x371);61}6263#define wb977_device_select(dev) wb977_wb(0x07, dev)64#define wb977_device_disable() wb977_wb(0x30, 0x00)65#define wb977_device_enable() wb977_wb(0x30, 0x01)6667/*68* This is a lock for accessing ports GP1_IO_BASE and GP2_IO_BASE69*/70DEFINE_SPINLOCK(nw_gpio_lock);71EXPORT_SYMBOL(nw_gpio_lock);7273static unsigned int current_gpio_op;74static unsigned int current_gpio_io;75static unsigned int current_cpld;7677void nw_gpio_modify_op(unsigned int mask, unsigned int set)78{79unsigned int new_gpio, changed;8081new_gpio = (current_gpio_op & ~mask) | set;82changed = new_gpio ^ current_gpio_op;83current_gpio_op = new_gpio;8485if (changed & 0xff)86outb(new_gpio, GP1_IO_BASE);87if (changed & 0xff00)88outb(new_gpio >> 8, GP2_IO_BASE);89}90EXPORT_SYMBOL(nw_gpio_modify_op);9192static inline void __gpio_modify_io(int mask, int in)93{94unsigned int new_gpio, changed;95int port;9697new_gpio = (current_gpio_io & ~mask) | in;98changed = new_gpio ^ current_gpio_io;99current_gpio_io = new_gpio;100101changed >>= 1;102new_gpio >>= 1;103104wb977_device_select(7);105106for (port = 0xe1; changed && port < 0xe8; changed >>= 1) {107wb977_wb(port, new_gpio & 1);108109port += 1;110new_gpio >>= 1;111}112113wb977_device_select(8);114115for (port = 0xe8; changed && port < 0xec; changed >>= 1) {116wb977_wb(port, new_gpio & 1);117118port += 1;119new_gpio >>= 1;120}121}122123void nw_gpio_modify_io(unsigned int mask, unsigned int in)124{125/* Open up the SuperIO chip */126wb977_open();127128__gpio_modify_io(mask, in);129130/* Close up the EFER gate */131wb977_close();132}133EXPORT_SYMBOL(nw_gpio_modify_io);134135unsigned int nw_gpio_read(void)136{137return inb(GP1_IO_BASE) | inb(GP2_IO_BASE) << 8;138}139EXPORT_SYMBOL(nw_gpio_read);140141/*142* Initialise the Winbond W83977F global registers143*/144static inline void wb977_init_global(void)145{146/*147* Enable R/W config registers148*/149wb977_wb(0x26, 0x40);150151/*152* Power down FDC (not used)153*/154wb977_wb(0x22, 0xfe);155156/*157* GP12, GP11, CIRRX, IRRXH, GP10158*/159wb977_wb(0x2a, 0xc1);160161/*162* GP23, GP22, GP21, GP20, GP13163*/164wb977_wb(0x2b, 0x6b);165166/*167* GP17, GP16, GP15, GP14168*/169wb977_wb(0x2c, 0x55);170}171172/*173* Initialise the Winbond W83977F printer port174*/175static inline void wb977_init_printer(void)176{177wb977_device_select(1);178179/*180* mode 1 == EPP181*/182wb977_wb(0xf0, 0x01);183}184185/*186* Initialise the Winbond W83977F keyboard controller187*/188static inline void wb977_init_keyboard(void)189{190wb977_device_select(5);191192/*193* Keyboard controller address194*/195wb977_ww(0x60, 0x0060);196wb977_ww(0x62, 0x0064);197198/*199* Keyboard IRQ 1, active high, edge trigger200*/201wb977_wb(0x70, 1);202wb977_wb(0x71, 0x02);203204/*205* Mouse IRQ 5, active high, edge trigger206*/207wb977_wb(0x72, 5);208wb977_wb(0x73, 0x02);209210/*211* KBC 8MHz212*/213wb977_wb(0xf0, 0x40);214215/*216* Enable device217*/218wb977_device_enable();219}220221/*222* Initialise the Winbond W83977F Infra-Red device223*/224static inline void wb977_init_irda(void)225{226wb977_device_select(6);227228/*229* IR base address230*/231wb977_ww(0x60, IRDA_IO_BASE);232233/*234* IRDA IRQ 6, active high, edge trigger235*/236wb977_wb(0x70, 6);237wb977_wb(0x71, 0x02);238239/*240* RX DMA - ISA DMA 0241*/242wb977_wb(0x74, 0x00);243244/*245* TX DMA - Disable Tx DMA246*/247wb977_wb(0x75, 0x04);248249/*250* Append CRC, Enable bank selection251*/252wb977_wb(0xf0, 0x03);253254/*255* Enable device256*/257wb977_device_enable();258}259260/*261* Initialise Winbond W83977F general purpose IO262*/263static inline void wb977_init_gpio(void)264{265unsigned long flags;266267/*268* Set up initial I/O definitions269*/270current_gpio_io = -1;271__gpio_modify_io(-1, GPIO_DONE | GPIO_WDTIMER);272273wb977_device_select(7);274275/*276* Group1 base address277*/278wb977_ww(0x60, GP1_IO_BASE);279wb977_ww(0x62, 0);280wb977_ww(0x64, 0);281282/*283* GP10 (Orage button) IRQ 10, active high, edge trigger284*/285wb977_wb(0x70, 10);286wb977_wb(0x71, 0x02);287288/*289* GP10: Debounce filter enabled, IRQ, input290*/291wb977_wb(0xe0, 0x19);292293/*294* Enable Group1295*/296wb977_device_enable();297298wb977_device_select(8);299300/*301* Group2 base address302*/303wb977_ww(0x60, GP2_IO_BASE);304305/*306* Clear watchdog timer regs307* - timer disable308*/309wb977_wb(0xf2, 0x00);310311/*312* - disable LED, no mouse nor keyboard IRQ313*/314wb977_wb(0xf3, 0x00);315316/*317* - timer counting, disable power LED, disable timeouot318*/319wb977_wb(0xf4, 0x00);320321/*322* Enable group2323*/324wb977_device_enable();325326/*327* Set Group1/Group2 outputs328*/329spin_lock_irqsave(&nw_gpio_lock, flags);330nw_gpio_modify_op(-1, GPIO_RED_LED | GPIO_FAN);331spin_unlock_irqrestore(&nw_gpio_lock, flags);332}333334/*335* Initialise the Winbond W83977F chip.336*/337static void __init wb977_init(void)338{339request_region(0x370, 2, "W83977AF configuration");340341/*342* Open up the SuperIO chip343*/344wb977_open();345346/*347* Initialise the global registers348*/349wb977_init_global();350351/*352* Initialise the various devices in353* the multi-IO chip.354*/355wb977_init_printer();356wb977_init_keyboard();357wb977_init_irda();358wb977_init_gpio();359360/*361* Close up the EFER gate362*/363wb977_close();364}365366void nw_cpld_modify(unsigned int mask, unsigned int set)367{368int msk;369370current_cpld = (current_cpld & ~mask) | set;371372nw_gpio_modify_io(GPIO_DATA | GPIO_IOCLK | GPIO_IOLOAD, 0);373nw_gpio_modify_op(GPIO_IOLOAD, 0);374375for (msk = 8; msk; msk >>= 1) {376int bit = current_cpld & msk;377378nw_gpio_modify_op(GPIO_DATA | GPIO_IOCLK, bit ? GPIO_DATA : 0);379nw_gpio_modify_op(GPIO_IOCLK, GPIO_IOCLK);380}381382nw_gpio_modify_op(GPIO_IOCLK|GPIO_DATA, 0);383nw_gpio_modify_op(GPIO_IOLOAD|GPIO_DSCLK, GPIO_IOLOAD|GPIO_DSCLK);384nw_gpio_modify_op(GPIO_IOLOAD, 0);385}386EXPORT_SYMBOL(nw_cpld_modify);387388static void __init cpld_init(void)389{390unsigned long flags;391392spin_lock_irqsave(&nw_gpio_lock, flags);393nw_cpld_modify(-1, CPLD_UNMUTE | CPLD_7111_DISABLE);394spin_unlock_irqrestore(&nw_gpio_lock, flags);395}396397static unsigned char rwa_unlock[] __initdata =398{ 0x00, 0x00, 0x6a, 0xb5, 0xda, 0xed, 0xf6, 0xfb, 0x7d, 0xbe, 0xdf, 0x6f, 0x37, 0x1b,3990x0d, 0x86, 0xc3, 0x61, 0xb0, 0x58, 0x2c, 0x16, 0x8b, 0x45, 0xa2, 0xd1, 0xe8, 0x74,4000x3a, 0x9d, 0xce, 0xe7, 0x73, 0x39 };401402#ifndef DEBUG403#define dprintk(x...)404#else405#define dprintk(x...) printk(x)406#endif407408#define WRITE_RWA(r,v) do { outb((r), 0x279); udelay(10); outb((v), 0xa79); } while (0)409410static inline void rwa010_unlock(void)411{412int i;413414WRITE_RWA(2, 2);415mdelay(10);416417for (i = 0; i < sizeof(rwa_unlock); i++) {418outb(rwa_unlock[i], 0x279);419udelay(10);420}421}422423static inline void rwa010_read_ident(void)424{425unsigned char si[9];426int i, j;427428WRITE_RWA(3, 0);429WRITE_RWA(0, 128);430431outb(1, 0x279);432433mdelay(1);434435dprintk("Identifier: ");436for (i = 0; i < 9; i++) {437si[i] = 0;438for (j = 0; j < 8; j++) {439int bit;440udelay(250);441inb(0x203);442udelay(250);443bit = inb(0x203);444dprintk("%02X ", bit);445bit = (bit == 0xaa) ? 1 : 0;446si[i] |= bit << j;447}448dprintk("(%02X) ", si[i]);449}450dprintk("\n");451}452453static inline void rwa010_global_init(void)454{455WRITE_RWA(6, 2); // Assign a card no = 2456457dprintk("Card no = %d\n", inb(0x203));458459/* disable the modem section of the chip */460WRITE_RWA(7, 3);461WRITE_RWA(0x30, 0);462463/* disable the cdrom section of the chip */464WRITE_RWA(7, 4);465WRITE_RWA(0x30, 0);466467/* disable the MPU-401 section of the chip */468WRITE_RWA(7, 2);469WRITE_RWA(0x30, 0);470}471472static inline void rwa010_game_port_init(void)473{474int i;475476WRITE_RWA(7, 5);477478dprintk("Slider base: ");479WRITE_RWA(0x61, 1);480i = inb(0x203);481482WRITE_RWA(0x60, 2);483dprintk("%02X%02X (201)\n", inb(0x203), i);484485WRITE_RWA(0x30, 1);486}487488static inline void rwa010_waveartist_init(int base, int irq, int dma)489{490int i;491492WRITE_RWA(7, 0);493494dprintk("WaveArtist base: ");495WRITE_RWA(0x61, base & 255);496i = inb(0x203);497498WRITE_RWA(0x60, base >> 8);499dprintk("%02X%02X (%X),", inb(0x203), i, base);500501WRITE_RWA(0x70, irq);502dprintk(" irq: %d (%d),", inb(0x203), irq);503504WRITE_RWA(0x74, dma);505dprintk(" dma: %d (%d)\n", inb(0x203), dma);506507WRITE_RWA(0x30, 1);508}509510static inline void rwa010_soundblaster_init(int sb_base, int al_base, int irq, int dma)511{512int i;513514WRITE_RWA(7, 1);515516dprintk("SoundBlaster base: ");517WRITE_RWA(0x61, sb_base & 255);518i = inb(0x203);519520WRITE_RWA(0x60, sb_base >> 8);521dprintk("%02X%02X (%X),", inb(0x203), i, sb_base);522523dprintk(" irq: ");524WRITE_RWA(0x70, irq);525dprintk("%d (%d),", inb(0x203), irq);526527dprintk(" 8-bit DMA: ");528WRITE_RWA(0x74, dma);529dprintk("%d (%d)\n", inb(0x203), dma);530531dprintk("AdLib base: ");532WRITE_RWA(0x63, al_base & 255);533i = inb(0x203);534535WRITE_RWA(0x62, al_base >> 8);536dprintk("%02X%02X (%X)\n", inb(0x203), i, al_base);537538WRITE_RWA(0x30, 1);539}540541static void rwa010_soundblaster_reset(void)542{543int i;544545outb(1, 0x226);546udelay(3);547outb(0, 0x226);548549for (i = 0; i < 5; i++) {550if (inb(0x22e) & 0x80)551break;552mdelay(1);553}554if (i == 5)555printk("SoundBlaster: DSP reset failed\n");556557dprintk("SoundBlaster DSP reset: %02X (AA)\n", inb(0x22a));558559for (i = 0; i < 5; i++) {560if ((inb(0x22c) & 0x80) == 0)561break;562mdelay(1);563}564565if (i == 5)566printk("SoundBlaster: DSP not ready\n");567else {568outb(0xe1, 0x22c);569570dprintk("SoundBlaster DSP id: ");571i = inb(0x22a);572udelay(1);573i |= inb(0x22a) << 8;574dprintk("%04X\n", i);575576for (i = 0; i < 5; i++) {577if ((inb(0x22c) & 0x80) == 0)578break;579mdelay(1);580}581582if (i == 5)583printk("SoundBlaster: could not turn speaker off\n");584585outb(0xd3, 0x22c);586}587588/* turn on OPL3 */589outb(5, 0x38a);590outb(1, 0x38b);591}592593static void __init rwa010_init(void)594{595rwa010_unlock();596rwa010_read_ident();597rwa010_global_init();598rwa010_game_port_init();599rwa010_waveartist_init(0x250, 3, 7);600rwa010_soundblaster_init(0x220, 0x388, 3, 1);601rwa010_soundblaster_reset();602}603604/*605* Initialise any other hardware after we've got the PCI bus606* initialised. We may need the PCI bus to talk to this other607* hardware.608*/609static int __init nw_hw_init(void)610{611if (machine_is_netwinder()) {612unsigned long flags;613614wb977_init();615cpld_init();616rwa010_init();617618spin_lock_irqsave(&nw_gpio_lock, flags);619nw_gpio_modify_op(GPIO_RED_LED|GPIO_GREEN_LED, DEFAULT_LEDS);620spin_unlock_irqrestore(&nw_gpio_lock, flags);621}622return 0;623}624625__initcall(nw_hw_init);626627/*628* Older NeTTroms either do not provide a parameters629* page, or they don't supply correct information in630* the parameter page.631*/632static void __init633fixup_netwinder(struct machine_desc *desc, struct tag *tags,634char **cmdline, struct meminfo *mi)635{636#ifdef CONFIG_ISAPNP637extern int isapnp_disable;638639/*640* We must not use the kernels ISAPnP code641* on the NetWinder - it will reset the settings642* for the WaveArtist chip and render it inoperable.643*/644isapnp_disable = 1;645#endif646}647648MACHINE_START(NETWINDER, "Rebel-NetWinder")649/* Maintainer: Russell King/Rebel.com */650.boot_params = 0x00000100,651.video_start = 0x000a0000,652.video_end = 0x000bffff,653.reserve_lp0 = 1,654.reserve_lp2 = 1,655.fixup = fixup_netwinder,656.map_io = footbridge_map_io,657.init_irq = footbridge_init_irq,658.timer = &isa_timer,659MACHINE_END660661662