📄 prep_setup.c
字号:
/* * BK Id: SCCS/s.prep_setup.c 1.47 12/19/01 09:45:54 trini *//* * 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 "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>#endifunsigned 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_BLK_DEV_RAMextern int rd_doload; /* 1 = load ramdisk, 0 = don't load */extern int rd_prompt; /* 1 = prompt for ramdisk, 0 = don't prompt */extern int rd_image_start; /* starting block # of image */#endif#ifdef CONFIG_SOUND_MODULEEXPORT_SYMBOL(ppc_cs4232_dma);EXPORT_SYMBOL(ppc_cs4232_dma2);#endifstatic int __prepprep_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 __prepprep_show_percpuinfo(struct seq_file *m, int i){ int len = 0; /* 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>>20 : res->VitalProductData.ProcessorHz); else#endif /* CONFIG_PREP_RESIDUAL */ seq_printf(m, "???\n"); return 0;}static void __initprep_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 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 ) { 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 __initprep_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 __initprep_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 __initprep_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 __initmk48t59_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;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -