📄 prep_setup.c
字号:
/* vgacon.c needs to know where we mapped IO memory in io_block_mapping() */ vgacon_remap_base = 0xf0000000; 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;}/* 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 __initmk48t59_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 unsigned int __prepprep_irq_cannonicalize(u_int irq){ if (irq == 2) { return 9; } else { return irq; }}static void __initprep_init_IRQ(void){ int i; unsigned int pci_viddid, pci_did; if (OpenPIC_Addr != NULL) { openpic_init(NUM_8259_INTERRUPTS); /* We have a cascade on OpenPIC IRQ 0, Linux IRQ 16 */ openpic_hookup_cascade(NUM_8259_INTERRUPTS, "82c59 cascade", i8259_irq); } for (i = 0; i < NUM_8259_INTERRUPTS; i++) irq_desc[i].handler = &i8259_pic; /* If we have a Raven PCI bridge or a Hawk PCI bridge / Memory * controller, we poll (as they have a different int-ack address). */ early_read_config_dword(0, 0, 0, PCI_VENDOR_ID, &pci_viddid); pci_did = (pci_viddid & 0xffff0000) >> 16; if (((pci_viddid & 0xffff) == PCI_VENDOR_ID_MOTOROLA) && ((pci_did == PCI_DEVICE_ID_MOTOROLA_RAVEN) || (pci_did == PCI_DEVICE_ID_MOTOROLA_HAWK))) i8259_init(0); else /* PCI interrupt ack address given in section 6.1.8 of the * PReP specification. */ i8259_init(0xbffffff0);}#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)/* * IDE stuff. */static int __prepprep_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 __prepprep_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; }}#endif#ifdef CONFIG_SMP/* PReP (MTX) support */static int __initsmp_prep_probe(void){ extern int mot_multi; if (mot_multi) { openpic_request_IPIs(); smp_hw_index[1] = 1; return 2; } return 1;}static void __initsmp_prep_kick_cpu(int nr){ *(unsigned long *)KERNELBASE = nr; asm volatile("dcbf 0,%0"::"r"(KERNELBASE):"memory"); printk("CPU1 released, waiting\n");}static void __initsmp_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 *//* * What ever boots us must pass in the ammount of memory. */static unsigned long __initprep_find_end_of_memory(void){ return boot_mem_size;}/* * Setup the bat mappings we're going to load that cover * the io areas. RAM was mapped by mapin_ram(). * -- Cort */static void __initprep_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 __initprep_init2(void){#ifdef CONFIG_NVRAM request_region(PREP_NVRAM_AS0, 0x8, "nvram");#endif request_region(0x00,0x20,"dma1"); request_region(0x40,0x20,"timer"); request_region(0x80,0x10,"dma page reg"); request_region(0xc0,0x20,"dma2");}void __initprep_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 = NULL; /* set in prep_setup_arch() */ 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 = NULL; /* set in prep_setup_arch() */ 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;#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 */}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -