patch-2.4.20 linux-2.4.20/arch/ppc/platforms/prep_setup.c
Next file: linux-2.4.20/arch/ppc/platforms/prep_time.c
Previous file: linux-2.4.20/arch/ppc/platforms/prep_pci.c
Back to the patch index
Back to the overall index
- Lines: 891
- Date:
Thu Nov 28 15:53:11 2002
- Orig file:
linux-2.4.19/arch/ppc/platforms/prep_setup.c
- Orig date:
Wed Dec 31 16:00:00 1969
diff -urN linux-2.4.19/arch/ppc/platforms/prep_setup.c linux-2.4.20/arch/ppc/platforms/prep_setup.c
@@ -0,0 +1,890 @@
+/*
+ * BK Id: %F% %I% %G% %U% %#%
+ */
+/*
+ * linux/arch/ppc/kernel/setup.c
+ *
+ * Copyright (C) 1995 Linus Torvalds
+ * Adapted from 'alpha' version by Gary Thomas
+ * Modified by Cort Dougan (cort@cs.nmt.edu)
+ *
+ * Support for PReP (Motorola MTX/MVME)
+ * by Troy Benjegerdes (hozer@drgw.net)
+ */
+
+/*
+ * bootup setup stuff..
+ */
+
+#include <linux/config.h>
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/stddef.h>
+#include <linux/unistd.h>
+#include <linux/ptrace.h>
+#include <linux/slab.h>
+#include <linux/user.h>
+#include <linux/a.out.h>
+#include <linux/tty.h>
+#include <linux/major.h>
+#include <linux/interrupt.h>
+#include <linux/reboot.h>
+#include <linux/init.h>
+#include <linux/blk.h>
+#include <linux/ioport.h>
+#include <linux/console.h>
+#include <linux/timex.h>
+#include <linux/pci.h>
+#include <linux/ide.h>
+#include <linux/seq_file.h>
+
+#include <asm/sections.h>
+#include <asm/mmu.h>
+#include <asm/processor.h>
+#include <asm/residual.h>
+#include <asm/io.h>
+#include <asm/pgtable.h>
+#include <asm/cache.h>
+#include <asm/dma.h>
+#include <asm/machdep.h>
+#include <asm/mk48t59.h>
+#include <asm/prep_nvram.h>
+#include <asm/raven.h>
+#include <asm/keyboard.h>
+#include <asm/vga.h>
+#include <asm/time.h>
+#include <asm/i8259.h>
+#include <asm/open_pic.h>
+
+#if defined(CONFIG_SOUND) || defined(CONFIG_SOUND_MODULE)
+#include <../drivers/sound/sound_config.h>
+#include <../drivers/sound/dev_table.h>
+#endif
+
+unsigned char ucSystemType;
+unsigned char ucBoardRev;
+unsigned char ucBoardRevMaj, ucBoardRevMin;
+
+extern unsigned long mc146818_get_rtc_time(void);
+extern int mc146818_set_rtc_time(unsigned long nowtime);
+extern unsigned long mk48t59_get_rtc_time(void);
+extern int mk48t59_set_rtc_time(unsigned long nowtime);
+
+extern unsigned char prep_nvram_read_val(int addr);
+extern void prep_nvram_write_val(int addr,
+ unsigned char val);
+extern unsigned char rs_nvram_read_val(int addr);
+extern void rs_nvram_write_val(int addr,
+ unsigned char val);
+extern void ibm_prep_init(void);
+
+extern int pckbd_setkeycode(unsigned int scancode, unsigned int keycode);
+extern int pckbd_getkeycode(unsigned int scancode);
+extern int pckbd_translate(unsigned char scancode, unsigned char *keycode,
+ char raw_mode);
+extern char pckbd_unexpected_up(unsigned char keycode);
+extern void pckbd_leds(unsigned char leds);
+extern void pckbd_init_hw(void);
+extern unsigned char pckbd_sysrq_xlate[];
+
+extern void prep_find_bridges(void);
+extern char saved_command_line[];
+
+int _prep_type;
+
+#define cached_21 (((char *)(ppc_cached_irq_mask))[3])
+#define cached_A1 (((char *)(ppc_cached_irq_mask))[2])
+
+/* for the mac fs */
+kdev_t boot_dev;
+/* used in nasty hack for sound - see prep_setup_arch() -- Cort */
+long ppc_cs4232_dma, ppc_cs4232_dma2;
+
+extern PTE *Hash, *Hash_end;
+extern unsigned long Hash_size, Hash_mask;
+extern int probingmem;
+extern unsigned long loops_per_jiffy;
+
+#ifdef CONFIG_SOUND_MODULE
+EXPORT_SYMBOL(ppc_cs4232_dma);
+EXPORT_SYMBOL(ppc_cs4232_dma2);
+#endif
+
+static int __prep
+prep_show_cpuinfo(struct seq_file *m)
+{
+ extern char *Motherboard_map_name;
+ int cachew;
+#ifdef CONFIG_PREP_RESIDUAL
+ int i;
+#endif
+
+ seq_printf(m, "machine\t\t: PReP %s\n", Motherboard_map_name);
+
+ switch ( _prep_type ) {
+ case _PREP_IBM:
+ cachew = inw(0x80c);
+ if (cachew & (1<<6))
+ seq_printf(m, "Upgrade CPU\n");
+ seq_printf(m, "L2\t\t: ");
+ if (cachew & (1<<7)) {
+ seq_printf(m, "not present\n");
+ goto no_l2;
+ }
+ seq_printf(m, "%sKb,", (cachew & (1 << 10))? "512" : "256");
+ seq_printf(m, "%ssync\n", (cachew & (1 << 15))? "" : "a");
+ break;
+ case _PREP_Motorola:
+ cachew = *((unsigned char *)CACHECRBA);
+ seq_printf(m, "L2\t\t: ");
+ switch (cachew & L2CACHE_MASK) {
+ case L2CACHE_512KB:
+ seq_printf(m, "512Kb");
+ break;
+ case L2CACHE_256KB:
+ seq_printf(m, "256Kb");
+ break;
+ case L2CACHE_1MB:
+ seq_printf(m, "1MB");
+ break;
+ case L2CACHE_NONE:
+ seq_printf(m, "none\n");
+ goto no_l2;
+ break;
+ default:
+ seq_printf(m, "%x\n", cachew);
+ }
+
+ seq_printf(m, ", parity %s",
+ (cachew & L2CACHE_PARITY)? "enabled" : "disabled");
+
+ seq_printf(m, " SRAM:");
+
+ switch ( ((cachew & 0xf0) >> 4) & ~(0x3) ) {
+ case 1: seq_printf(m, "synchronous,parity,flow-through\n");
+ break;
+ case 2: seq_printf(m, "asynchronous,no parity\n");
+ break;
+ case 3: seq_printf(m, "asynchronous,parity\n");
+ break;
+ default:seq_printf(m, "synchronous,pipelined,no parity\n");
+ break;
+ }
+ break;
+ default:
+ break;
+ }
+
+no_l2:
+#ifdef CONFIG_PREP_RESIDUAL
+ if (res->ResidualLength != 0) {
+ /* print info about SIMMs */
+ seq_printf(m, "simms\t\t: ");
+ for (i = 0; (res->ActualNumMemories) && (i < MAX_MEMS); i++) {
+ if (res->Memories[i].SIMMSize != 0)
+ seq_printf(m, "%d:%ldM ", i,
+ (res->Memories[i].SIMMSize > 1024) ?
+ res->Memories[i].SIMMSize>>20 :
+ res->Memories[i].SIMMSize);
+ }
+ seq_printf(m, "\n");
+ }
+#endif
+
+ return 0;
+}
+
+static int __prep
+prep_show_percpuinfo(struct seq_file *m, int i)
+{
+ /* PREP's without residual data will give incorrect values here */
+ seq_printf(m, "clock\t\t: ");
+#ifdef CONFIG_PREP_RESIDUAL
+ if (res->ResidualLength)
+ seq_printf(m, "%ldMHz\n",
+ (res->VitalProductData.ProcessorHz > 1024) ?
+ res->VitalProductData.ProcessorHz / 1000000 :
+ res->VitalProductData.ProcessorHz);
+ else
+#endif /* CONFIG_PREP_RESIDUAL */
+ seq_printf(m, "???\n");
+
+ return 0;
+}
+
+static void __init
+prep_setup_arch(void)
+{
+ unsigned char reg;
+#if 0 /* unused?? */
+ unsigned char ucMothMemType;
+ unsigned char ucEquipPres1;
+#endif
+
+ /* init to some ~sane value until calibrate_delay() runs */
+ loops_per_jiffy = 50000000;
+
+ /* Lookup PCI host bridges */
+ prep_find_bridges();
+
+ /* Set up floppy in PS/2 mode */
+ outb(0x09, SIO_CONFIG_RA);
+ reg = inb(SIO_CONFIG_RD);
+ reg = (reg & 0x3F) | 0x40;
+ outb(reg, SIO_CONFIG_RD);
+ outb(reg, SIO_CONFIG_RD); /* Have to write twice to change! */
+
+ /* we should determine this according to what we find! -- Cort */
+ switch ( _prep_type )
+ {
+ case _PREP_IBM:
+ /* Enable L2. Assume we don't need to flush -- Cort*/
+ *(unsigned char *)(0x8000081c) |= 3;
+ ROOT_DEV = to_kdev_t(0x0301); /* hda1 */
+ break;
+ case _PREP_Motorola:
+ /* Enable L2. Assume we don't need to flush -- Cort*/
+ *(unsigned char *)(0x8000081c) |= 3;
+#ifdef CONFIG_BLK_DEV_INITRD
+ if (initrd_start)
+ ROOT_DEV = MKDEV(RAMDISK_MAJOR, 0); /* /dev/ram */
+ else
+#endif
+#ifdef CONFIG_ROOT_NFS
+ ROOT_DEV = to_kdev_t(0x00ff); /* /dev/nfs */
+#else
+ ROOT_DEV = to_kdev_t(0x0802); /* /dev/sda2 */
+#endif
+ break;
+ }
+
+ /* Read in NVRAM data */
+ init_prep_nvram();
+
+ /* if no bootargs, look in NVRAM */
+ if ( cmd_line[0] == '\0' ) {
+ char *bootargs;
+ bootargs = prep_nvram_get_var("bootargs");
+ if (bootargs != NULL) {
+ strcpy(cmd_line, bootargs);
+ /* again.. */
+ strcpy(saved_command_line, cmd_line);
+ }
+ }
+
+#ifdef CONFIG_SOUND_CS4232
+ /*
+ * setup proper values for the cs4232 driver so we don't have
+ * to recompile for the motorola or ibm workstations sound systems.
+ * This is a really nasty hack, but unless we change the driver
+ * it's the only way to support both addrs from one binary.
+ * -- Cort
+ */
+ if ( _machine == _MACH_prep )
+ {
+ extern struct card_info snd_installed_cards[];
+ struct card_info *snd_ptr;
+
+ for ( snd_ptr = snd_installed_cards;
+ snd_ptr < &snd_installed_cards[num_sound_cards];
+ snd_ptr++ )
+ {
+ if ( snd_ptr->card_type == SNDCARD_CS4232 )
+ {
+ if ( _prep_type == _PREP_Motorola )
+ {
+ snd_ptr->config.io_base = 0x830;
+ snd_ptr->config.irq = 10;
+ snd_ptr->config.dma = ppc_cs4232_dma = 6;
+ snd_ptr->config.dma2 = ppc_cs4232_dma2 = 7;
+ }
+ if ( _prep_type == _PREP_IBM )
+ {
+ snd_ptr->config.io_base = 0x530;
+ snd_ptr->config.irq = 5;
+ snd_ptr->config.dma = ppc_cs4232_dma = 1;
+ /* this is wrong - but leave it for now */
+ snd_ptr->config.dma2 = ppc_cs4232_dma2 = 7;
+ }
+ }
+ }
+ }
+#endif /* CONFIG_SOUND_CS4232 */
+
+ /*print_residual_device_info();*/
+
+ switch (_prep_type) {
+ case _PREP_Motorola:
+ raven_init();
+ break;
+ case _PREP_IBM:
+ ibm_prep_init();
+ break;
+ }
+
+#ifdef CONFIG_VGA_CONSOLE
+ /* remap the VGA memory */
+ vgacon_remap_base = 0xf0000000;
+ /*vgacon_remap_base = ioremap(0xc0000000, 0xba000);*/
+ conswitchp = &vga_con;
+#elif defined(CONFIG_DUMMY_CONSOLE)
+ conswitchp = &dummy_con;
+#endif
+}
+
+/*
+ * Determine the decrementer frequency from the residual data
+ * This allows for a faster boot as we do not need to calibrate the
+ * decrementer against another clock. This is important for embedded systems.
+ */
+static int __init
+prep_res_calibrate_decr(void)
+{
+#ifdef CONFIG_PREP_RESIDUAL
+ unsigned long freq, divisor = 4;
+
+ if ( res->VitalProductData.ProcessorBusHz ) {
+ freq = res->VitalProductData.ProcessorBusHz;
+ printk("time_init: decrementer frequency = %lu.%.6lu MHz\n",
+ (freq/divisor)/1000000,
+ (freq/divisor)%1000000);
+ tb_to_us = mulhwu_scale_factor(freq/divisor, 1000000);
+ tb_ticks_per_jiffy = freq / HZ / divisor;
+ return 0;
+ } else
+#endif
+ return 1;
+}
+
+/*
+ * Uses the on-board timer to calibrate the on-chip decrementer register
+ * for prep systems. On the pmac the OF tells us what the frequency is
+ * but on prep we have to figure it out.
+ * -- Cort
+ */
+/* Done with 3 interrupts: the first one primes the cache and the
+ * 2 following ones measure the interval. The precision of the method
+ * is still doubtful due to the short interval sampled.
+ */
+static volatile int calibrate_steps __initdata = 3;
+static unsigned tbstamp __initdata = 0;
+
+static void __init
+prep_calibrate_decr_handler(int irq, void *dev, struct pt_regs *regs)
+{
+ unsigned long t, freq;
+ int step=--calibrate_steps;
+
+ t = get_tbl();
+ if (step > 0) {
+ tbstamp = t;
+ } else {
+ freq = (t - tbstamp)*HZ;
+ printk("time_init: decrementer frequency = %lu.%.6lu MHz\n",
+ freq/1000000, freq%1000000);
+ tb_ticks_per_jiffy = freq / HZ;
+ tb_to_us = mulhwu_scale_factor(freq, 1000000);
+ }
+}
+
+static void __init
+prep_calibrate_decr(void)
+{
+ int res;
+
+ /* Try and get this from the residual data. */
+ res = prep_res_calibrate_decr();
+
+ /* If we didn't get it from the residual data, try this. */
+ if ( res ) {
+ unsigned long flags;
+
+ save_flags(flags);
+
+#define TIMER0_COUNT 0x40
+#define TIMER_CONTROL 0x43
+ /* set timer to periodic mode */
+ outb_p(0x34,TIMER_CONTROL);/* binary, mode 2, LSB/MSB, ch 0 */
+ /* set the clock to ~100 Hz */
+ outb_p(LATCH & 0xff , TIMER0_COUNT); /* LSB */
+ outb(LATCH >> 8 , TIMER0_COUNT); /* MSB */
+
+ if (request_irq(0, prep_calibrate_decr_handler, 0, "timer", NULL) != 0)
+ panic("Could not allocate timer IRQ!");
+ __sti();
+ /* wait for calibrate */
+ while ( calibrate_steps )
+ ;
+ restore_flags(flags);
+ free_irq( 0, NULL);
+ }
+}
+
+static long __init
+mk48t59_init(void) {
+ unsigned char tmp;
+
+ tmp = ppc_md.nvram_read_val(MK48T59_RTC_CONTROLB);
+ if (tmp & MK48T59_RTC_CB_STOP) {
+ printk("Warning: RTC was stopped, date will be wrong.\n");
+ ppc_md.nvram_write_val(MK48T59_RTC_CONTROLB,
+ tmp & ~MK48T59_RTC_CB_STOP);
+ /* Low frequency crystal oscillators may take a very long
+ * time to startup and stabilize. For now just ignore the
+ * the issue, but attempting to calibrate the decrementer
+ * from the RTC just after this wakeup is likely to be very
+ * inaccurate. Firmware should not allow to load
+ * the OS with the clock stopped anyway...
+ */
+ }
+ /* Ensure that the clock registers are updated */
+ tmp = ppc_md.nvram_read_val(MK48T59_RTC_CONTROLA);
+ tmp &= ~(MK48T59_RTC_CA_READ | MK48T59_RTC_CA_WRITE);
+ ppc_md.nvram_write_val(MK48T59_RTC_CONTROLA, tmp);
+ return 0;
+}
+
+/* We use the NVRAM RTC to time a second to calibrate the decrementer,
+ * the RTC registers have just been set up in the right state by the
+ * preceding routine.
+ */
+static void __init
+mk48t59_calibrate_decr(void)
+{
+ unsigned long freq;
+ unsigned long t1;
+ unsigned char save_control;
+ long i;
+ unsigned char sec;
+
+
+ /* Make sure the time is not stopped. */
+ save_control = ppc_md.nvram_read_val(MK48T59_RTC_CONTROLB);
+
+ ppc_md.nvram_write_val(MK48T59_RTC_CONTROLA,
+ (save_control & (~MK48T59_RTC_CB_STOP)));
+
+ /* Now make sure the read bit is off so the value will change. */
+ save_control = ppc_md.nvram_read_val(MK48T59_RTC_CONTROLA);
+ save_control &= ~MK48T59_RTC_CA_READ;
+ ppc_md.nvram_write_val(MK48T59_RTC_CONTROLA, save_control);
+
+
+ /* Read the seconds value to see when it changes. */
+ sec = ppc_md.nvram_read_val(MK48T59_RTC_SECONDS);
+ /* Actually this is bad for precision, we should have a loop in
+ * which we only read the seconds counter. nvram_read_val writes
+ * the address bytes on every call and this takes a lot of time.
+ * Perhaps an nvram_wait_change method returning a time
+ * stamp with a loop count as parameter would be the solution.
+ */
+ for (i = 0 ; i < 1000000 ; i++) { /* may take up to 1 second... */
+ t1 = get_tbl();
+ if (ppc_md.nvram_read_val(MK48T59_RTC_SECONDS) != sec) {
+ break;
+ }
+ }
+
+ sec = ppc_md.nvram_read_val(MK48T59_RTC_SECONDS);
+ for (i = 0 ; i < 1000000 ; i++) { /* Should take up 1 second... */
+ freq = get_tbl()-t1;
+ if (ppc_md.nvram_read_val(MK48T59_RTC_SECONDS) != sec)
+ break;
+ }
+
+ printk("time_init: decrementer frequency = %lu.%.6lu MHz\n",
+ freq/1000000, freq%1000000);
+ tb_ticks_per_jiffy = freq / HZ;
+ tb_to_us = mulhwu_scale_factor(freq, 1000000);
+}
+
+static void __prep
+prep_restart(char *cmd)
+{
+#define PREP_SP92 0x92 /* Special Port 92 */
+ __cli(); /* no interrupts */
+
+ /* set exception prefix high - to the prom */
+ _nmask_and_or_msr(0, MSR_IP);
+
+ /* make sure bit 0 (reset) is a 0 */
+ outb( inb(PREP_SP92) & ~1L , PREP_SP92);
+ /* signal a reset to system control port A - soft reset */
+ outb( inb(PREP_SP92) | 1 , PREP_SP92);
+
+ while ( 1 ) ;
+ /* not reached */
+#undef PREP_SP92
+}
+
+static void __prep
+prep_halt(void)
+{
+ __cli(); /* no interrupts */
+
+ /* set exception prefix high - to the prom */
+ _nmask_and_or_msr(0, MSR_IP);
+
+ while ( 1 ) ;
+ /* not reached */
+}
+
+/*
+ * On IBM PReP's, power management is handled by a Signetics 87c750 behind the
+ * Utah component on the ISA bus. To access the 750 you must write a series of
+ * nibbles to port 0x82a (decoded by the Utah). This is described somewhat in
+ * the IBM Carolina Technical Specification.
+ * -Hollis
+ */
+static void __prep
+utah_sig87c750_setbit(unsigned int bytenum, unsigned int bitnum, int value)
+{
+ /*
+ * byte1: 0 0 0 1 0 d a5 a4
+ * byte2: 0 0 0 1 a3 a2 a1 a0
+ *
+ * d = the bit's value, enabled or disabled
+ * (a5 a4 a3) = the byte number, minus 20
+ * (a2 a1 a0) = the bit number
+ *
+ * example: set the 5th bit of byte 21 (21.5)
+ * a5 a4 a3 = 001 (byte 1)
+ * a2 a1 a0 = 101 (bit 5)
+ *
+ * byte1 = 0001 0100 (0x14)
+ * byte2 = 0001 1101 (0x1d)
+ */
+ unsigned char byte1=0x10, byte2=0x10;
+ const unsigned int pm_reg_1=0x82a; /* ISA address */
+
+ /* the 750's '20.0' is accessed as '0.0' through Utah (which adds 20) */
+ bytenum -= 20;
+
+ byte1 |= (!!value) << 2; /* set d */
+ byte1 |= (bytenum >> 1) & 0x3; /* set a5, a4 */
+
+ byte2 |= (bytenum & 0x1) << 3; /* set a3 */
+ byte2 |= bitnum & 0x7; /* set a2, a1, a0 */
+
+ outb(byte1, pm_reg_1); /* first nibble */
+ mb();
+ udelay(100); /* important: let controller recover */
+
+ outb(byte2, pm_reg_1); /* second nibble */
+ mb();
+ udelay(100); /* important: let controller recover */
+}
+
+static void __prep
+prep_power_off(void)
+{
+ if ( _prep_type == _PREP_IBM) {
+ /* tested on:
+ * Carolina's: 7248-43P, 6070 (PowerSeries 850)
+ * should work on:
+ * Carolina: 6050 (PowerSeries 830)
+ * 7043-140 (Tiger 1)
+ */
+ unsigned long flags;
+ __cli();
+ /* set exception prefix high - to the prom */
+ save_flags( flags );
+ restore_flags( flags|MSR_IP );
+
+ utah_sig87c750_setbit(21, 5, 1); /* set bit 21.5, "PMEXEC_OFF" */
+
+ while ( 1 ) ;
+ /* not reached */
+ } else {
+ prep_halt();
+ }
+}
+
+static unsigned int __prep
+prep_irq_cannonicalize(u_int irq)
+{
+ if (irq == 2)
+ {
+ return 9;
+ }
+ else
+ {
+ return irq;
+ }
+}
+
+static void __init
+prep_init_IRQ(void)
+{
+ int i;
+
+ if (OpenPIC_Addr != NULL)
+ openpic_init(1, NUM_8259_INTERRUPTS, 0, -1);
+ for ( i = 0 ; i < NUM_8259_INTERRUPTS ; i++ )
+ irq_desc[i].handler = &i8259_pic;
+ i8259_init(0xbffffff0); /* PCI interrupt ack address for MPC105 and 106 */
+}
+
+#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
+/*
+ * IDE stuff.
+ */
+static int __prep
+prep_ide_default_irq(ide_ioreg_t base)
+{
+ switch (base) {
+ case 0x1f0: return 13;
+ case 0x170: return 13;
+ case 0x1e8: return 11;
+ case 0x168: return 10;
+ case 0xfff0: return 14; /* MCP(N)750 ide0 */
+ case 0xffe0: return 15; /* MCP(N)750 ide1 */
+ default: return 0;
+ }
+}
+
+static ide_ioreg_t __prep
+prep_ide_default_io_base(int index)
+{
+ switch (index) {
+ case 0: return 0x1f0;
+ case 1: return 0x170;
+ case 2: return 0x1e8;
+ case 3: return 0x168;
+ default:
+ return 0;
+ }
+}
+
+static int __prep
+prep_ide_check_region(ide_ioreg_t from, unsigned int extent)
+{
+ return check_region(from, extent);
+}
+
+static void __prep
+prep_ide_request_region(ide_ioreg_t from,
+ unsigned int extent,
+ const char *name)
+{
+ request_region(from, extent, name);
+}
+
+static void __prep
+prep_ide_release_region(ide_ioreg_t from,
+ unsigned int extent)
+{
+ release_region(from, extent);
+}
+
+static void __init
+prep_ide_init_hwif_ports (hw_regs_t *hw, ide_ioreg_t data_port, ide_ioreg_t ctrl_port, int *irq)
+{
+ ide_ioreg_t reg = data_port;
+ int i;
+
+ for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++) {
+ hw->io_ports[i] = reg;
+ reg += 1;
+ }
+ if (ctrl_port) {
+ hw->io_ports[IDE_CONTROL_OFFSET] = ctrl_port;
+ } else {
+ hw->io_ports[IDE_CONTROL_OFFSET] = hw->io_ports[IDE_DATA_OFFSET] + 0x206;
+ }
+ if (irq != NULL)
+ *irq = 0;
+}
+#endif
+
+#ifdef CONFIG_SMP
+/* PReP (MTX) support */
+static int __init
+smp_prep_probe(void)
+{
+ extern int mot_multi;
+
+ if (mot_multi) {
+ openpic_request_IPIs();
+ smp_hw_index[1] = 1;
+ return 2;
+ }
+
+ return 1;
+}
+
+static void __init
+smp_prep_kick_cpu(int nr)
+{
+ *(unsigned long *)KERNELBASE = nr;
+ asm volatile("dcbf 0,%0"::"r"(KERNELBASE):"memory");
+ printk("CPU1 reset, waiting\n");
+}
+
+static void __init
+smp_prep_setup_cpu(int cpu_nr)
+{
+ if (OpenPIC_Addr)
+ do_openpic_setup_cpu();
+}
+
+static struct smp_ops_t prep_smp_ops __prepdata = {
+ smp_openpic_message_pass,
+ smp_prep_probe,
+ smp_prep_kick_cpu,
+ smp_prep_setup_cpu,
+};
+#endif /* CONFIG_SMP */
+
+/*
+ * This finds the amount of physical ram and does necessary
+ * setup for prep. This is pretty architecture specific so
+ * this will likely stay separate from the pmac.
+ * -- Cort
+ */
+static unsigned long __init
+prep_find_end_of_memory(void)
+{
+ unsigned long total = 0;
+ extern unsigned int boot_mem_size;
+
+#ifdef CONFIG_PREP_RESIDUAL
+ total = res->TotalMemory;
+#endif
+
+ if (total == 0 && boot_mem_size != 0)
+ total = boot_mem_size;
+ else if (total == 0) {
+ /*
+ * I need a way to probe the amount of memory if the residual
+ * data doesn't contain it. -- Cort
+ */
+ total = 0x02000000;
+ printk(KERN_INFO "Ramsize from residual data was 0"
+ " -- defaulting to %ldM\n", total>>20);
+ }
+
+ return (total);
+}
+
+/*
+ * Setup the bat mappings we're going to load that cover
+ * the io areas. RAM was mapped by mapin_ram().
+ * -- Cort
+ */
+static void __init
+prep_map_io(void)
+{
+ io_block_mapping(0x80000000, PREP_ISA_IO_BASE, 0x10000000, _PAGE_IO);
+ io_block_mapping(0xf0000000, PREP_ISA_MEM_BASE, 0x08000000, _PAGE_IO);
+}
+
+static void __init
+prep_init2(void)
+{
+#ifdef CONFIG_NVRAM
+ request_region(PREP_NVRAM_AS0, 0x8, "nvram");
+#endif
+ request_region(0x20,0x20,"pic1");
+ request_region(0xa0,0x20,"pic2");
+ request_region(0x00,0x20,"dma1");
+ request_region(0x40,0x20,"timer");
+ request_region(0x80,0x10,"dma page reg");
+ request_region(0xc0,0x20,"dma2");
+}
+
+void __init
+prep_init(unsigned long r3, unsigned long r4, unsigned long r5,
+ unsigned long r6, unsigned long r7)
+{
+#ifdef CONFIG_PREP_RESIDUAL
+ /* make a copy of residual data */
+ if ( r3 ) {
+ memcpy((void *)res,(void *)(r3+KERNELBASE),
+ sizeof(RESIDUAL));
+ }
+#endif
+
+ isa_io_base = PREP_ISA_IO_BASE;
+ isa_mem_base = PREP_ISA_MEM_BASE;
+ pci_dram_offset = PREP_PCI_DRAM_OFFSET;
+ ISA_DMA_THRESHOLD = 0x00ffffff;
+ DMA_MODE_READ = 0x44;
+ DMA_MODE_WRITE = 0x48;
+
+ /* figure out what kind of prep workstation we are */
+#ifdef CONFIG_PREP_RESIDUAL
+ if ( res->ResidualLength != 0 )
+ {
+ if ( !strncmp(res->VitalProductData.PrintableModel,"IBM",3) )
+ _prep_type = _PREP_IBM;
+ else
+ _prep_type = _PREP_Motorola;
+ }
+ else /* assume motorola if no residual (netboot?) */
+#endif
+ {
+ _prep_type = _PREP_Motorola;
+ }
+
+ ppc_md.setup_arch = prep_setup_arch;
+ ppc_md.show_percpuinfo = prep_show_percpuinfo;
+ ppc_md.show_cpuinfo = prep_show_cpuinfo;
+ ppc_md.irq_cannonicalize = prep_irq_cannonicalize;
+ ppc_md.init_IRQ = prep_init_IRQ;
+ /* this gets changed later on if we have an OpenPIC -- Cort */
+ ppc_md.get_irq = i8259_irq;
+ ppc_md.init = prep_init2;
+
+ ppc_md.restart = prep_restart;
+ ppc_md.power_off = prep_power_off;
+ ppc_md.halt = prep_halt;
+
+ ppc_md.nvram_read_val = prep_nvram_read_val;
+ ppc_md.nvram_write_val = prep_nvram_write_val;
+
+ ppc_md.time_init = NULL;
+ if (_prep_type == _PREP_IBM) {
+ ppc_md.set_rtc_time = mc146818_set_rtc_time;
+ ppc_md.get_rtc_time = mc146818_get_rtc_time;
+ ppc_md.calibrate_decr = prep_calibrate_decr;
+ } else {
+ ppc_md.set_rtc_time = mk48t59_set_rtc_time;
+ ppc_md.get_rtc_time = mk48t59_get_rtc_time;
+ ppc_md.calibrate_decr = mk48t59_calibrate_decr;
+ ppc_md.time_init = mk48t59_init;
+ }
+
+ ppc_md.find_end_of_memory = prep_find_end_of_memory;
+ ppc_md.setup_io_mappings = prep_map_io;
+
+#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
+ ppc_ide_md.default_irq = prep_ide_default_irq;
+ ppc_ide_md.default_io_base = prep_ide_default_io_base;
+ ppc_ide_md.ide_check_region = prep_ide_check_region;
+ ppc_ide_md.ide_request_region = prep_ide_request_region;
+ ppc_ide_md.ide_release_region = prep_ide_release_region;
+ ppc_ide_md.ide_init_hwif = prep_ide_init_hwif_ports;
+#endif
+
+#ifdef CONFIG_VT
+ ppc_md.kbd_setkeycode = pckbd_setkeycode;
+ ppc_md.kbd_getkeycode = pckbd_getkeycode;
+ ppc_md.kbd_translate = pckbd_translate;
+ ppc_md.kbd_unexpected_up = pckbd_unexpected_up;
+ ppc_md.kbd_leds = pckbd_leds;
+ ppc_md.kbd_init_hw = pckbd_init_hw;
+#ifdef CONFIG_MAGIC_SYSRQ
+ ppc_md.ppc_kbd_sysrq_xlate = pckbd_sysrq_xlate;
+ SYSRQ_KEY = 0x54;
+#endif
+#endif
+
+#ifdef CONFIG_SMP
+ ppc_md.smp_ops = &prep_smp_ops;
+#endif /* CONFIG_SMP */
+}
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)