0001
0002
0003
0004
0005
0006
0007
0008
0009 #include <linux/module.h>
0010 #include <linux/ioport.h>
0011 #include <linux/kernel.h>
0012 #include <linux/delay.h>
0013 #include <linux/init.h>
0014 #include <linux/io.h>
0015 #include <linux/spinlock.h>
0016 #include <linux/slab.h>
0017 #include <linux/leds.h>
0018
0019 #include <asm/hardware/dec21285.h>
0020 #include <asm/mach-types.h>
0021 #include <asm/setup.h>
0022 #include <asm/system_misc.h>
0023
0024 #include <asm/mach/arch.h>
0025
0026 #include "common.h"
0027
0028 #define IRDA_IO_BASE 0x180
0029 #define GP1_IO_BASE 0x338
0030 #define GP2_IO_BASE 0x33a
0031
0032
0033
0034
0035 static inline void wb977_open(void)
0036 {
0037 outb(0x87, 0x370);
0038 outb(0x87, 0x370);
0039 }
0040
0041 static inline void wb977_close(void)
0042 {
0043 outb(0xaa, 0x370);
0044 }
0045
0046 static inline void wb977_wb(int reg, int val)
0047 {
0048 outb(reg, 0x370);
0049 outb(val, 0x371);
0050 }
0051
0052 static inline void wb977_ww(int reg, int val)
0053 {
0054 outb(reg, 0x370);
0055 outb(val >> 8, 0x371);
0056 outb(reg + 1, 0x370);
0057 outb(val & 255, 0x371);
0058 }
0059
0060 #define wb977_device_select(dev) wb977_wb(0x07, dev)
0061 #define wb977_device_disable() wb977_wb(0x30, 0x00)
0062 #define wb977_device_enable() wb977_wb(0x30, 0x01)
0063
0064
0065
0066
0067 DEFINE_RAW_SPINLOCK(nw_gpio_lock);
0068 EXPORT_SYMBOL(nw_gpio_lock);
0069
0070 static unsigned int current_gpio_op;
0071 static unsigned int current_gpio_io;
0072 static unsigned int current_cpld;
0073
0074 void nw_gpio_modify_op(unsigned int mask, unsigned int set)
0075 {
0076 unsigned int new_gpio, changed;
0077
0078 new_gpio = (current_gpio_op & ~mask) | set;
0079 changed = new_gpio ^ current_gpio_op;
0080 current_gpio_op = new_gpio;
0081
0082 if (changed & 0xff)
0083 outb(new_gpio, GP1_IO_BASE);
0084 if (changed & 0xff00)
0085 outb(new_gpio >> 8, GP2_IO_BASE);
0086 }
0087 EXPORT_SYMBOL(nw_gpio_modify_op);
0088
0089 static inline void __gpio_modify_io(int mask, int in)
0090 {
0091 unsigned int new_gpio, changed;
0092 int port;
0093
0094 new_gpio = (current_gpio_io & ~mask) | in;
0095 changed = new_gpio ^ current_gpio_io;
0096 current_gpio_io = new_gpio;
0097
0098 changed >>= 1;
0099 new_gpio >>= 1;
0100
0101 wb977_device_select(7);
0102
0103 for (port = 0xe1; changed && port < 0xe8; changed >>= 1) {
0104 wb977_wb(port, new_gpio & 1);
0105
0106 port += 1;
0107 new_gpio >>= 1;
0108 }
0109
0110 wb977_device_select(8);
0111
0112 for (port = 0xe8; changed && port < 0xec; changed >>= 1) {
0113 wb977_wb(port, new_gpio & 1);
0114
0115 port += 1;
0116 new_gpio >>= 1;
0117 }
0118 }
0119
0120 void nw_gpio_modify_io(unsigned int mask, unsigned int in)
0121 {
0122
0123 wb977_open();
0124
0125 __gpio_modify_io(mask, in);
0126
0127
0128 wb977_close();
0129 }
0130 EXPORT_SYMBOL(nw_gpio_modify_io);
0131
0132 unsigned int nw_gpio_read(void)
0133 {
0134 return inb(GP1_IO_BASE) | inb(GP2_IO_BASE) << 8;
0135 }
0136 EXPORT_SYMBOL(nw_gpio_read);
0137
0138
0139
0140
0141 static inline void wb977_init_global(void)
0142 {
0143
0144
0145
0146 wb977_wb(0x26, 0x40);
0147
0148
0149
0150
0151 wb977_wb(0x22, 0xfe);
0152
0153
0154
0155
0156 wb977_wb(0x2a, 0xc1);
0157
0158
0159
0160
0161 wb977_wb(0x2b, 0x6b);
0162
0163
0164
0165
0166 wb977_wb(0x2c, 0x55);
0167 }
0168
0169
0170
0171
0172 static inline void wb977_init_printer(void)
0173 {
0174 wb977_device_select(1);
0175
0176
0177
0178
0179 wb977_wb(0xf0, 0x01);
0180 }
0181
0182
0183
0184
0185 static inline void wb977_init_keyboard(void)
0186 {
0187 wb977_device_select(5);
0188
0189
0190
0191
0192 wb977_ww(0x60, 0x0060);
0193 wb977_ww(0x62, 0x0064);
0194
0195
0196
0197
0198 wb977_wb(0x70, 1);
0199 wb977_wb(0x71, 0x02);
0200
0201
0202
0203
0204 wb977_wb(0x72, 5);
0205 wb977_wb(0x73, 0x02);
0206
0207
0208
0209
0210 wb977_wb(0xf0, 0x40);
0211
0212
0213
0214
0215 wb977_device_enable();
0216 }
0217
0218
0219
0220
0221 static inline void wb977_init_irda(void)
0222 {
0223 wb977_device_select(6);
0224
0225
0226
0227
0228 wb977_ww(0x60, IRDA_IO_BASE);
0229
0230
0231
0232
0233 wb977_wb(0x70, 6);
0234 wb977_wb(0x71, 0x02);
0235
0236
0237
0238
0239 wb977_wb(0x74, 0x00);
0240
0241
0242
0243
0244 wb977_wb(0x75, 0x04);
0245
0246
0247
0248
0249 wb977_wb(0xf0, 0x03);
0250
0251
0252
0253
0254 wb977_device_enable();
0255 }
0256
0257
0258
0259
0260 static inline void wb977_init_gpio(void)
0261 {
0262 unsigned long flags;
0263
0264
0265
0266
0267 current_gpio_io = -1;
0268 __gpio_modify_io(-1, GPIO_DONE | GPIO_WDTIMER);
0269
0270 wb977_device_select(7);
0271
0272
0273
0274
0275 wb977_ww(0x60, GP1_IO_BASE);
0276 wb977_ww(0x62, 0);
0277 wb977_ww(0x64, 0);
0278
0279
0280
0281
0282 wb977_wb(0x70, 10);
0283 wb977_wb(0x71, 0x02);
0284
0285
0286
0287
0288 wb977_wb(0xe0, 0x19);
0289
0290
0291
0292
0293 wb977_device_enable();
0294
0295 wb977_device_select(8);
0296
0297
0298
0299
0300 wb977_ww(0x60, GP2_IO_BASE);
0301
0302
0303
0304
0305
0306 wb977_wb(0xf2, 0x00);
0307
0308
0309
0310
0311 wb977_wb(0xf3, 0x00);
0312
0313
0314
0315
0316 wb977_wb(0xf4, 0x00);
0317
0318
0319
0320
0321 wb977_device_enable();
0322
0323
0324
0325
0326 raw_spin_lock_irqsave(&nw_gpio_lock, flags);
0327 nw_gpio_modify_op(-1, GPIO_RED_LED | GPIO_FAN);
0328 raw_spin_unlock_irqrestore(&nw_gpio_lock, flags);
0329 }
0330
0331
0332
0333
0334 static void __init wb977_init(void)
0335 {
0336 request_region(0x370, 2, "W83977AF configuration");
0337
0338
0339
0340
0341 wb977_open();
0342
0343
0344
0345
0346 wb977_init_global();
0347
0348
0349
0350
0351
0352 wb977_init_printer();
0353 wb977_init_keyboard();
0354 wb977_init_irda();
0355 wb977_init_gpio();
0356
0357
0358
0359
0360 wb977_close();
0361 }
0362
0363 void nw_cpld_modify(unsigned int mask, unsigned int set)
0364 {
0365 int msk;
0366
0367 current_cpld = (current_cpld & ~mask) | set;
0368
0369 nw_gpio_modify_io(GPIO_DATA | GPIO_IOCLK | GPIO_IOLOAD, 0);
0370 nw_gpio_modify_op(GPIO_IOLOAD, 0);
0371
0372 for (msk = 8; msk; msk >>= 1) {
0373 int bit = current_cpld & msk;
0374
0375 nw_gpio_modify_op(GPIO_DATA | GPIO_IOCLK, bit ? GPIO_DATA : 0);
0376 nw_gpio_modify_op(GPIO_IOCLK, GPIO_IOCLK);
0377 }
0378
0379 nw_gpio_modify_op(GPIO_IOCLK|GPIO_DATA, 0);
0380 nw_gpio_modify_op(GPIO_IOLOAD|GPIO_DSCLK, GPIO_IOLOAD|GPIO_DSCLK);
0381 nw_gpio_modify_op(GPIO_IOLOAD, 0);
0382 }
0383 EXPORT_SYMBOL(nw_cpld_modify);
0384
0385 static void __init cpld_init(void)
0386 {
0387 unsigned long flags;
0388
0389 raw_spin_lock_irqsave(&nw_gpio_lock, flags);
0390 nw_cpld_modify(-1, CPLD_UNMUTE | CPLD_7111_DISABLE);
0391 raw_spin_unlock_irqrestore(&nw_gpio_lock, flags);
0392 }
0393
0394 static unsigned char rwa_unlock[] __initdata =
0395 { 0x00, 0x00, 0x6a, 0xb5, 0xda, 0xed, 0xf6, 0xfb, 0x7d, 0xbe, 0xdf, 0x6f, 0x37, 0x1b,
0396 0x0d, 0x86, 0xc3, 0x61, 0xb0, 0x58, 0x2c, 0x16, 0x8b, 0x45, 0xa2, 0xd1, 0xe8, 0x74,
0397 0x3a, 0x9d, 0xce, 0xe7, 0x73, 0x39 };
0398
0399 #ifndef DEBUG
0400 #define dprintk(x...)
0401 #else
0402 #define dprintk(x...) printk(x)
0403 #endif
0404
0405 #define WRITE_RWA(r,v) do { outb((r), 0x279); udelay(10); outb((v), 0xa79); } while (0)
0406
0407 static inline void rwa010_unlock(void)
0408 {
0409 int i;
0410
0411 WRITE_RWA(2, 2);
0412 mdelay(10);
0413
0414 for (i = 0; i < sizeof(rwa_unlock); i++) {
0415 outb(rwa_unlock[i], 0x279);
0416 udelay(10);
0417 }
0418 }
0419
0420 static inline void rwa010_read_ident(void)
0421 {
0422 unsigned char si[9];
0423 int i, j;
0424
0425 WRITE_RWA(3, 0);
0426 WRITE_RWA(0, 128);
0427
0428 outb(1, 0x279);
0429
0430 mdelay(1);
0431
0432 dprintk("Identifier: ");
0433 for (i = 0; i < 9; i++) {
0434 si[i] = 0;
0435 for (j = 0; j < 8; j++) {
0436 int bit;
0437 udelay(250);
0438 inb(0x203);
0439 udelay(250);
0440 bit = inb(0x203);
0441 dprintk("%02X ", bit);
0442 bit = (bit == 0xaa) ? 1 : 0;
0443 si[i] |= bit << j;
0444 }
0445 dprintk("(%02X) ", si[i]);
0446 }
0447 dprintk("\n");
0448 }
0449
0450 static inline void rwa010_global_init(void)
0451 {
0452 WRITE_RWA(6, 2);
0453
0454 dprintk("Card no = %d\n", inb(0x203));
0455
0456
0457 WRITE_RWA(7, 3);
0458 WRITE_RWA(0x30, 0);
0459
0460
0461 WRITE_RWA(7, 4);
0462 WRITE_RWA(0x30, 0);
0463
0464
0465 WRITE_RWA(7, 2);
0466 WRITE_RWA(0x30, 0);
0467 }
0468
0469 static inline void rwa010_game_port_init(void)
0470 {
0471 int i;
0472
0473 WRITE_RWA(7, 5);
0474
0475 dprintk("Slider base: ");
0476 WRITE_RWA(0x61, 1);
0477 i = inb(0x203);
0478
0479 WRITE_RWA(0x60, 2);
0480 dprintk("%02X%02X (201)\n", inb(0x203), i);
0481
0482 WRITE_RWA(0x30, 1);
0483 }
0484
0485 static inline void rwa010_waveartist_init(int base, int irq, int dma)
0486 {
0487 int i;
0488
0489 WRITE_RWA(7, 0);
0490
0491 dprintk("WaveArtist base: ");
0492 WRITE_RWA(0x61, base & 255);
0493 i = inb(0x203);
0494
0495 WRITE_RWA(0x60, base >> 8);
0496 dprintk("%02X%02X (%X),", inb(0x203), i, base);
0497
0498 WRITE_RWA(0x70, irq);
0499 dprintk(" irq: %d (%d),", inb(0x203), irq);
0500
0501 WRITE_RWA(0x74, dma);
0502 dprintk(" dma: %d (%d)\n", inb(0x203), dma);
0503
0504 WRITE_RWA(0x30, 1);
0505 }
0506
0507 static inline void rwa010_soundblaster_init(int sb_base, int al_base, int irq, int dma)
0508 {
0509 int i;
0510
0511 WRITE_RWA(7, 1);
0512
0513 dprintk("SoundBlaster base: ");
0514 WRITE_RWA(0x61, sb_base & 255);
0515 i = inb(0x203);
0516
0517 WRITE_RWA(0x60, sb_base >> 8);
0518 dprintk("%02X%02X (%X),", inb(0x203), i, sb_base);
0519
0520 dprintk(" irq: ");
0521 WRITE_RWA(0x70, irq);
0522 dprintk("%d (%d),", inb(0x203), irq);
0523
0524 dprintk(" 8-bit DMA: ");
0525 WRITE_RWA(0x74, dma);
0526 dprintk("%d (%d)\n", inb(0x203), dma);
0527
0528 dprintk("AdLib base: ");
0529 WRITE_RWA(0x63, al_base & 255);
0530 i = inb(0x203);
0531
0532 WRITE_RWA(0x62, al_base >> 8);
0533 dprintk("%02X%02X (%X)\n", inb(0x203), i, al_base);
0534
0535 WRITE_RWA(0x30, 1);
0536 }
0537
0538 static void rwa010_soundblaster_reset(void)
0539 {
0540 int i;
0541
0542 outb(1, 0x226);
0543 udelay(3);
0544 outb(0, 0x226);
0545
0546 for (i = 0; i < 5; i++) {
0547 if (inb(0x22e) & 0x80)
0548 break;
0549 mdelay(1);
0550 }
0551 if (i == 5)
0552 printk("SoundBlaster: DSP reset failed\n");
0553
0554 dprintk("SoundBlaster DSP reset: %02X (AA)\n", inb(0x22a));
0555
0556 for (i = 0; i < 5; i++) {
0557 if ((inb(0x22c) & 0x80) == 0)
0558 break;
0559 mdelay(1);
0560 }
0561
0562 if (i == 5)
0563 printk("SoundBlaster: DSP not ready\n");
0564 else {
0565 outb(0xe1, 0x22c);
0566
0567 dprintk("SoundBlaster DSP id: ");
0568 i = inb(0x22a);
0569 udelay(1);
0570 i |= inb(0x22a) << 8;
0571 dprintk("%04X\n", i);
0572
0573 for (i = 0; i < 5; i++) {
0574 if ((inb(0x22c) & 0x80) == 0)
0575 break;
0576 mdelay(1);
0577 }
0578
0579 if (i == 5)
0580 printk("SoundBlaster: could not turn speaker off\n");
0581
0582 outb(0xd3, 0x22c);
0583 }
0584
0585
0586 outb(5, 0x38a);
0587 outb(1, 0x38b);
0588 }
0589
0590 static void __init rwa010_init(void)
0591 {
0592 rwa010_unlock();
0593 rwa010_read_ident();
0594 rwa010_global_init();
0595 rwa010_game_port_init();
0596 rwa010_waveartist_init(0x250, 3, 7);
0597 rwa010_soundblaster_init(0x220, 0x388, 3, 1);
0598 rwa010_soundblaster_reset();
0599 }
0600
0601
0602
0603
0604
0605
0606 static int __init nw_hw_init(void)
0607 {
0608 if (machine_is_netwinder()) {
0609 wb977_init();
0610 cpld_init();
0611 rwa010_init();
0612 }
0613 return 0;
0614 }
0615
0616 __initcall(nw_hw_init);
0617
0618
0619
0620
0621
0622
0623 static void __init
0624 fixup_netwinder(struct tag *tags, char **cmdline)
0625 {
0626 #ifdef CONFIG_ISAPNP
0627 extern int isapnp_disable;
0628
0629
0630
0631
0632
0633
0634 isapnp_disable = 1;
0635 #endif
0636 }
0637
0638 static void netwinder_restart(enum reboot_mode mode, const char *cmd)
0639 {
0640 if (mode == REBOOT_SOFT) {
0641
0642 soft_restart(0x41000000);
0643 } else {
0644 local_irq_disable();
0645 local_fiq_disable();
0646
0647
0648 outb(0x87, 0x370);
0649 outb(0x87, 0x370);
0650
0651
0652 outb(0x07, 0x370);
0653 outb(0x07, 0x371);
0654
0655
0656 outb(0xe6, 0x370);
0657 outb(0x00, 0x371);
0658
0659
0660 outb(0xc4, 0x338);
0661 }
0662 }
0663
0664
0665 #if defined(CONFIG_NEW_LEDS) && defined(CONFIG_LEDS_CLASS)
0666 struct netwinder_led {
0667 struct led_classdev cdev;
0668 u8 mask;
0669 };
0670
0671
0672
0673
0674
0675 static const struct {
0676 const char *name;
0677 const char *trigger;
0678 } netwinder_leds[] = {
0679 { "netwinder:green", "heartbeat", },
0680 { "netwinder:red", "cpu0", },
0681 };
0682
0683
0684
0685
0686
0687
0688 static void netwinder_led_set(struct led_classdev *cdev,
0689 enum led_brightness b)
0690 {
0691 struct netwinder_led *led = container_of(cdev,
0692 struct netwinder_led, cdev);
0693 unsigned long flags;
0694 u32 reg;
0695
0696 raw_spin_lock_irqsave(&nw_gpio_lock, flags);
0697 reg = nw_gpio_read();
0698 if (b != LED_OFF)
0699 reg &= ~led->mask;
0700 else
0701 reg |= led->mask;
0702 nw_gpio_modify_op(led->mask, reg);
0703 raw_spin_unlock_irqrestore(&nw_gpio_lock, flags);
0704 }
0705
0706 static enum led_brightness netwinder_led_get(struct led_classdev *cdev)
0707 {
0708 struct netwinder_led *led = container_of(cdev,
0709 struct netwinder_led, cdev);
0710 unsigned long flags;
0711 u32 reg;
0712
0713 raw_spin_lock_irqsave(&nw_gpio_lock, flags);
0714 reg = nw_gpio_read();
0715 raw_spin_unlock_irqrestore(&nw_gpio_lock, flags);
0716
0717 return (reg & led->mask) ? LED_OFF : LED_FULL;
0718 }
0719
0720 static int __init netwinder_leds_init(void)
0721 {
0722 int i;
0723
0724 if (!machine_is_netwinder())
0725 return -ENODEV;
0726
0727 for (i = 0; i < ARRAY_SIZE(netwinder_leds); i++) {
0728 struct netwinder_led *led;
0729
0730 led = kzalloc(sizeof(*led), GFP_KERNEL);
0731 if (!led)
0732 break;
0733
0734 led->cdev.name = netwinder_leds[i].name;
0735 led->cdev.brightness_set = netwinder_led_set;
0736 led->cdev.brightness_get = netwinder_led_get;
0737 led->cdev.default_trigger = netwinder_leds[i].trigger;
0738
0739 if (i == 0)
0740 led->mask = GPIO_GREEN_LED;
0741 else
0742 led->mask = GPIO_RED_LED;
0743
0744 if (led_classdev_register(NULL, &led->cdev) < 0) {
0745 kfree(led);
0746 break;
0747 }
0748 }
0749
0750 return 0;
0751 }
0752
0753
0754
0755
0756
0757 fs_initcall(netwinder_leds_init);
0758 #endif
0759
0760 MACHINE_START(NETWINDER, "Rebel-NetWinder")
0761
0762 .atag_offset = 0x100,
0763 .video_start = 0x000a0000,
0764 .video_end = 0x000bffff,
0765 .reserve_lp0 = 1,
0766 .reserve_lp2 = 1,
0767 .fixup = fixup_netwinder,
0768 .map_io = footbridge_map_io,
0769 .init_irq = footbridge_init_irq,
0770 .init_time = isa_timer_init,
0771 .restart = netwinder_restart,
0772 MACHINE_END