patch-2.2.8 linux/arch/ppc/kernel/prep_setup.c

Next file: linux/arch/ppc/kernel/prep_time.c
Previous file: linux/arch/ppc/kernel/prep_pci.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.2.7/linux/arch/ppc/kernel/prep_setup.c linux/arch/ppc/kernel/prep_setup.c
@@ -30,6 +30,9 @@
 #include <linux/blk.h>
 #include <linux/ioport.h>
 #include <linux/console.h>
+#include <linux/timex.h>
+#include <linux/pci.h>
+#include <linux/openpic.h>
 
 #include <asm/mmu.h>
 #include <asm/processor.h>
@@ -38,12 +41,57 @@
 #include <asm/pgtable.h>
 #include <asm/ide.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 "time.h"
+#include "local_irq.h"
+#include "i8259.h"
+#include "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 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[128];
+
+extern void prep_setup_pci_ptrs(void);
+extern void chrp_do_IRQ(struct pt_regs *regs, int cpu, int isfake);
+extern char saved_command_line[256];
+
+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 */
@@ -60,6 +108,9 @@
 extern int rd_prompt;		/* 1 = prompt for ramdisk, 0 = don't prompt */
 extern int rd_image_start;	/* starting block # of image */
 #endif
+#ifdef CONFIG_VGA_CONSOLE
+unsigned long vgacon_remap_base;
+#endif
 
 __prep
 int
@@ -177,6 +228,13 @@
 	outb(reg, SIO_CONFIG_RD);
 	outb(reg, SIO_CONFIG_RD);	/* Have to write twice to change! */
 
+	/*
+	 * We need to set up the NvRAM access routines early as prep_init
+	 * has yet to be called
+	 */
+	ppc_md.nvram_read_val = prep_nvram_read_val;
+	ppc_md.nvram_write_val = prep_nvram_write_val;
+
 	/* we should determine this according to what we find! -- Cort */
 	switch ( _prep_type )
 	{
@@ -210,9 +268,38 @@
 		ucBoardRev=inb(0x854);
 		ucBoardRevMaj=ucBoardRev>>5;
 		ucBoardRevMin=ucBoardRev&0x1f;
+
+		/*
+		 * Most Radstone boards have memory mapped NvRAM
+		 */
+		if((ucSystemType==RS_SYS_TYPE_PPC1) && (ucBoardRevMaj<5))
+		{
+			ppc_md.nvram_read_val = prep_nvram_read_val;
+			ppc_md.nvram_write_val = prep_nvram_write_val;
+		}
+		else
+		{
+			ppc_md.nvram_read_val = rs_nvram_read_val;
+			ppc_md.nvram_write_val = rs_nvram_write_val;
+		}
 		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);
+              }
+      }
+
 	printk("Boot arguments: %s\n", cmd_line);
 	
 #ifdef CONFIG_SOUND_CS4232
@@ -262,12 +349,349 @@
 	request_region(0x80,0x10,"dma page reg");
 	request_region(0xc0,0x20,"dma2");
 
+	raven_init();
+
 #ifdef CONFIG_VGA_CONSOLE
+	/* remap the VGA memory */
+	vgacon_remap_base = 0xf0000000;
+	/*vgacon_remap_base = ioremap(0xc0000000, 0xba000);*/
         conswitchp = &vga_con;
 #endif
 }
 
-__initfunc(void prep_ide_init_hwif_ports (ide_ioreg_t *p, ide_ioreg_t base, int *irq))
+/*
+ * 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.
+ */
+__initfunc(void prep_res_calibrate_decr(void))
+{
+	int freq, divisor;
+
+	freq = res->VitalProductData.ProcessorBusHz;
+	divisor = 4;
+	printk("time_init: decrementer frequency = %d/%d\n", freq, divisor);
+	decrementer_count = freq / HZ / divisor;
+	count_period_num = divisor;
+	count_period_den = freq / 1000000;
+}
+
+/*
+ * 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
+ */
+int calibrate_done = 0;
+volatile int *done_ptr = &calibrate_done;
+
+__initfunc(void
+prep_calibrate_decr_handler(int            irq,
+			    void           *dev,
+			    struct pt_regs *regs))
+{
+	unsigned long freq, divisor;
+	static unsigned long t1 = 0, t2 = 0;
+	
+	if ( !t1 )
+		t1 = get_dec();
+	else if (!t2)
+	{
+		t2 = get_dec();
+		t2 = t1-t2;  /* decr's in 1/HZ */
+		t2 = t2*HZ;  /* # decrs in 1s - thus in Hz */
+		freq = t2 * 60;	/* try to make freq/1e6 an integer */
+		divisor = 60;
+		printk("time_init: decrementer frequency = %lu/%lu (%luMHz)\n",
+		       freq, divisor,t2>>20);
+		decrementer_count = freq / HZ / divisor;
+		count_period_num = divisor;
+		count_period_den = freq / 1000000;
+		*done_ptr = 1;
+	}
+}
+
+__initfunc(void prep_calibrate_decr(void))
+{
+	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();
+	while ( ! *done_ptr ) /* nothing */; /* wait for calibrate */
+        restore_flags(flags);
+	free_irq( 0, NULL);
+}
+
+
+/* We use the NVRAM RTC to time a second to calibrate the decrementer. */
+__initfunc(void mk48t59_calibrate_decr(void))
+{
+	unsigned long freq, divisor;
+	unsigned long t1, t2;
+        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);
+	for (i = 0 ; i < 1000000 ; i++)	{ /* may take up to 1 second... */
+	   if (ppc_md.nvram_read_val(MK48T59_RTC_SECONDS) != sec) {
+	      break;
+	   }
+	}
+	t1 = get_dec();
+
+	sec = ppc_md.nvram_read_val(MK48T59_RTC_SECONDS);
+	for (i = 0 ; i < 1000000 ; i++)	{ /* Should take up 1 second... */
+	   if (ppc_md.nvram_read_val(MK48T59_RTC_SECONDS) != sec) {
+	      break;
+	   }
+	}
+
+	t2 = t1 - get_dec();
+
+	freq = t2 * 60;	/* try to make freq/1e6 an integer */
+	divisor = 60;
+	printk("time_init: decrementer frequency = %lu/%lu (%luMHz)\n",
+	       freq, divisor,t2>>20);
+	decrementer_count = freq / HZ / divisor;
+	count_period_num = divisor;
+	count_period_den = freq / 1000000;
+}
+
+void
+prep_restart(char *cmd)
+{
+        unsigned long i = 10000;
+
+
+        _disable_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(0x92) & ~1L , 0x92 );
+        /* signal a reset to system control port A - soft reset */
+        outb( inb(0x92) | 1 , 0x92 );
+
+        while ( i != 0 ) i++;
+        panic("restart failed\n");
+}
+
+/*
+ * This function will restart a board regardless of port 92 functionality
+ */
+void
+prep_direct_restart(char *cmd)
+{
+	u32 jumpaddr=0xfff00100;
+	u32 defaultmsr=MSR_IP;
+
+	/*
+	 * This will ALWAYS work regardless of port 92
+	 * functionality
+	 */
+	_disable_interrupts();
+
+	__asm__ __volatile__("\n\
+	mtspr   26, %1  /* SRR0 */
+	mtspr   27, %0  /* SRR1 */
+	rfi"
+	:
+	: "r" (defaultmsr), "r" (jumpaddr));
+	/*
+	 * Not reached
+	 */
+}
+
+void
+prep_halt(void)
+{
+        unsigned long flags;
+	_disable_interrupts();
+	/* set exception prefix high - to the prom */
+	save_flags( flags );
+	restore_flags( flags|MSR_IP );
+	
+	/* make sure bit 0 (reset) is a 0 */
+	outb( inb(0x92) & ~1L , 0x92 );
+	/* signal a reset to system control port A - soft reset */
+	outb( inb(0x92) | 1 , 0x92 );
+                
+	while ( 1 ) ;
+	/*
+	 * Not reached
+	 */
+}
+
+void
+prep_power_off(void)
+{
+	prep_halt();
+}
+
+int prep_setup_residual(char *buffer)
+{
+        int len = 0;
+
+
+	/* PREP's without residual data will give incorrect values here */
+	len += sprintf(len+buffer, "clock\t\t: ");
+	if ( res->ResidualLength )
+		len += sprintf(len+buffer, "%ldMHz\n",
+		       (res->VitalProductData.ProcessorHz > 1024) ?
+		       res->VitalProductData.ProcessorHz>>20 :
+		       res->VitalProductData.ProcessorHz);
+	else
+		len += sprintf(len+buffer, "???\n");
+
+	return len;
+}
+
+u_int
+prep_irq_cannonicalize(u_int irq)
+{
+	if (irq == 2)
+	{
+		return 9;
+	}
+	else
+	{
+		return irq;
+	}
+}
+
+void                           
+prep_do_IRQ(struct pt_regs *regs, int cpu, int isfake)
+{
+        int irq;
+
+	if ( (irq = i8259_irq(0)) < 0 )
+	{
+		printk(KERN_DEBUG "Bogus interrupt from PC = %lx\n",
+		       regs->nip);
+		ppc_spurious_interrupts++;
+		return;
+	}
+        ppc_irq_dispatch_handler( regs, irq );
+}		
+
+__initfunc(void
+prep_init_IRQ(void))
+{
+	int i;
+
+	if (OpenPIC != NULL) {
+		for ( i = 16 ; i < 36 ; i++ )
+			irq_desc[i].ctl = &open_pic;
+		openpic_init(1);
+	}
+	
+        for ( i = 0 ; i < 16  ; i++ )
+                irq_desc[i].ctl = &i8259_pic;
+        i8259_init();
+#ifdef __SMP__
+	request_irq(openpic_to_irq(OPENPIC_VEC_SPURIOUS), openpic_ipi_action,
+		    0, "IPI0", 0);
+#endif /* __SMP__ */
+}
+
+#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
+/*
+ * IDE stuff.
+ */
+void
+prep_ide_insw(ide_ioreg_t port, void *buf, int ns)
+{
+	_insw((unsigned short *)((port)+_IO_BASE), buf, ns);
+}
+
+void
+prep_ide_outsw(ide_ioreg_t port, void *buf, int ns)
+{
+	_outsw((unsigned short *)((port)+_IO_BASE), buf, ns);
+}
+
+int
+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;
+		default:
+                        return 0;
+	}
+}
+
+ide_ioreg_t
+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;
+	}
+}
+
+int
+prep_ide_check_region(ide_ioreg_t from, unsigned int extent)
+{
+        return check_region(from, extent);
+}
+
+void
+prep_ide_request_region(ide_ioreg_t from,
+			unsigned int extent,
+			const char *name)
+{
+        request_region(from, extent, name);
+}
+
+void
+prep_ide_release_region(ide_ioreg_t from,
+			unsigned int extent)
+{
+        release_region(from, extent);
+}
+
+void
+prep_ide_fix_driveid(struct hd_driveid *id)
+{
+}
+
+__initfunc(void
+prep_ide_init_hwif_ports (ide_ioreg_t *p, ide_ioreg_t base, int *irq))
 {
 	ide_ioreg_t port = base;
 	int i = 8;
@@ -277,6 +701,143 @@
 	*p++ = base + 0x206;
 	if (irq != NULL)
 		*irq = 0;
+}
+#endif
+
+__initfunc(void
+prep_init(unsigned long r3, unsigned long r4, unsigned long r5,
+	  unsigned long r6, unsigned long r7))
+{
+	/* make a copy of residual data */
+	if ( r3 )
+	{
+		memcpy((void *)res,(void *)(r3+KERNELBASE),
+		       sizeof(RESIDUAL));
+	}
+
+	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 */
+	if ( res->ResidualLength != 0 )
+	{
+		if ( !strncmp(res->VitalProductData.PrintableModel,"IBM",3) )
+			_prep_type = _PREP_IBM;
+                else if (!strncmp(res->VitalProductData.PrintableModel,
+                                  "Radstone",8))
+                {
+                        extern char *Motherboard_map_name;
+
+                        _prep_type = _PREP_Radstone;
+                        Motherboard_map_name=
+                                res->VitalProductData.PrintableModel;
+                }
+		else
+			_prep_type = _PREP_Motorola;
+	}
+	else /* assume motorola if no residual (netboot?) */
+	{
+		_prep_type = _PREP_Motorola;
+	}
+
+	prep_setup_pci_ptrs();
+
+#ifdef CONFIG_BLK_DEV_INITRD
+	/* take care of initrd if we have one */
+	if ( r4 )
+	{
+		initrd_start = r4 + KERNELBASE;
+		initrd_end = r5 + KERNELBASE;
+	}
+#endif /* CONFIG_BLK_DEV_INITRD */
+
+	/* take care of cmd line */
+	if ( r6  && (((char *) r6) != '\0'))
+	{
+		*(char *)(r7+KERNELBASE) = 0;
+		strcpy(cmd_line, (char *)(r6+KERNELBASE));
+	}
+
+	ppc_md.setup_arch     = prep_setup_arch;
+	ppc_md.setup_residual = prep_setup_residual;
+	ppc_md.get_cpuinfo    = prep_get_cpuinfo;
+	ppc_md.irq_cannonicalize = prep_irq_cannonicalize;
+	ppc_md.init_IRQ       = prep_init_IRQ;
+	if ( !OpenPIC )
+		ppc_md.do_IRQ         = prep_do_IRQ;
+	else
+		ppc_md.do_IRQ         = chrp_do_IRQ;
+	ppc_md.init           = NULL;
+
+	ppc_md.restart        = prep_restart;
+	ppc_md.power_off      = prep_power_off;
+	ppc_md.halt           = prep_halt;
+
+	ppc_md.time_init      = NULL;
+	if (_prep_type == _PREP_Radstone) {
+		/*
+		 * We require a direct restart as port 92 does not work on
+		 * all Radstone boards
+		 */
+		ppc_md.restart        = prep_direct_restart;
+		/*
+		 * The RTC device used varies according to board type
+		 */
+		if(((ucSystemType==RS_SYS_TYPE_PPC1) && (ucBoardRevMaj>=5)) ||
+		   (ucSystemType==RS_SYS_TYPE_PPC1a))
+		{
+			ppc_md.set_rtc_time   = mk48t59_set_rtc_time;
+			ppc_md.get_rtc_time   = mk48t59_get_rtc_time;
+		}
+		else
+		{
+			ppc_md.set_rtc_time   = mc146818_set_rtc_time;
+			ppc_md.get_rtc_time   = mc146818_get_rtc_time;
+		}
+		/*
+		 * Determine the decrementer rate from the residual data
+		 */
+		ppc_md.calibrate_decr = prep_res_calibrate_decr;
+	}
+	else 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;
+	}
+
+#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
+        ppc_ide_md.insw = prep_ide_insw;
+        ppc_ide_md.outsw = prep_ide_outsw;
+        ppc_ide_md.default_irq = prep_ide_default_irq;
+        ppc_ide_md.default_io_base = prep_ide_default_io_base;
+        ppc_ide_md.check_region = prep_ide_check_region;
+        ppc_ide_md.request_region = prep_ide_request_region;
+        ppc_ide_md.release_region = prep_ide_release_region;
+        ppc_ide_md.fix_driveid = prep_ide_fix_driveid;
+        ppc_ide_md.ide_init_hwif = prep_ide_init_hwif_ports;
+#endif		
+        ppc_ide_md.io_base = _IO_BASE;
+
+#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.kbd_sysrq_xlate	 = pckbd_sysrq_xlate;
+#endif
+#endif
 }
 
 #ifdef CONFIG_SOUND_MODULE

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)