1 /* $Id: setup.c,v 1.8 2000/02/02 04:42:38 prumpf Exp $
3 * Initial setup-routines for HP 9000 based hardware.
5 * Copyright (C) 1991, 1992, 1995 Linus Torvalds
6 * Modifications for PA-RISC (C) 1999 Helge Deller <helge.deller@ruhr-uni-bochum.de>
7 * Modifications copyright 1999 SuSE GmbH (Philipp Rumpf)
8 * Modifications copyright 2000 Martin K. Petersen <mkp@mkp.net>
9 * Modifications copyright 2000 Philipp Rumpf <prumpf@tux.org>
11 * Initial PA-RISC Version: 04-23-1999 by Helge Deller
13 * This program is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU General Public License as published by
15 * the Free Software Foundation; either version 2, or (at your option)
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
23 * You should have received a copy of the GNU General Public License
24 * along with this program; if not, write to the Free Software
25 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
29 #include <linux/errno.h>
30 #include <linux/kernel.h>
31 #include <linux/malloc.h>
33 #include <linux/ptrace.h>
34 #include <linux/sched.h>
35 #include <linux/stddef.h>
36 #include <linux/unistd.h>
37 #include <linux/user.h>
38 #include <linux/tty.h>
39 #include <linux/config.h>
41 #include <linux/kdev_t.h>
42 #include <linux/major.h>
43 #include <linux/string.h>
44 #include <linux/blk.h>
45 #include <linux/init.h>
46 #include <linux/interrupt.h>
47 #include <linux/console.h>
48 #include <linux/bootmem.h>
49 #include <linux/delay.h>
50 #include <linux/pci.h>
51 #include <linux/threads.h>
53 #include <asm/cache.h>
54 #include <asm/hardware.h> /* for register_driver() stuff */
55 #include <asm/processor.h>
60 #include <asm/system.h>
61 #include <asm/machdep.h> /* for pa7300lc_init() proto */
63 #include <asm/irq.h> /* for struct irq_region */
64 #include <asm/pdc.h> /* for mem_pdc_call() proto */
65 #include <asm/pdcpat.h> /* for PA_VIEW PDC_PAT_CPU_GET_NUMBER etc */
67 #include <linux/proc_fs.h>
68 #include <asm/cache.h> /* for get_cache_info() proto */
70 #define COMMAND_LINE_SIZE 1024
71 char saved_command_line
[COMMAND_LINE_SIZE
];
76 ** We *really* should be using a combination of request_resource()
77 ** and request_region()! But request_region() requires kmalloc since
78 ** returns a new struct resource. And kmalloc just isn't available
79 ** until after mem_init() is called from start_kernel().
81 ** FIXME: assume contiguous memory initially.
82 ** Additional chunks of memory might be added to sysram_resource.sibling.
84 static struct resource sysrom_resource
= {
85 name
: "System ROM", start
: 0x0f0000000UL
, end
: 0x0f00fffffUL
,
86 flags
: IORESOURCE_BUSY
| IORESOURCE_MEM
,
87 parent
: &iomem_resource
, sibling
: NULL
, child
: NULL
};
89 static struct resource pdcdata_resource
;
91 static struct resource sysram_resource
= {
92 name
: "System RAM", start
: 0UL, end
: ~0UL /* bogus */,
93 flags
: IORESOURCE_MEM
,
94 parent
: &iomem_resource
, sibling
: &sysrom_resource
, child
: &pdcdata_resource
};
96 extern char _text
; /* start of kernel code, defined by linker */
97 extern int data_start
;
98 extern char _edata
; /* end of data, begin BSS, defined by linker */
99 extern char _end
; /* end of BSS, defined by linker */
101 static struct resource data_resource
= {
102 name
: "kernel Data", start
: virt_to_phys(&data_start
), end
: virt_to_phys(&_end
)-1,
103 flags
: IORESOURCE_BUSY
| IORESOURCE_MEM
,
104 parent
: &sysram_resource
, sibling
: NULL
, child
: NULL
};
106 static struct resource code_resource
= {
107 name
: "Kernel Code", start
: virt_to_phys(&_text
), end
: virt_to_phys(&data_start
)-1,
108 flags
: IORESOURCE_BUSY
| IORESOURCE_MEM
,
109 parent
: &sysram_resource
, sibling
: &data_resource
, child
: NULL
};
111 static struct resource pdcdata_resource
= {
112 name
: "PDC data (Page Zero)", start
: 0, end
: 0x9ff,
113 flags
: IORESOURCE_BUSY
| IORESOURCE_MEM
,
114 parent
: &sysram_resource
, sibling
: &code_resource
, child
: NULL
};
119 struct system_cpuinfo_parisc boot_cpu_data
;
120 struct cpuinfo_parisc cpu_data
[NR_CPUS
];
122 extern void do_inventory(void);
123 extern void cache_init(void);
124 extern struct hp_device
* register_module(void *hpa
);
126 static int cpu_driver_callback(struct hp_device
*, struct pa_iodc_driver
*);
128 static struct pa_iodc_driver cpu_drivers_for
[] = {
129 {HPHW_NPROC
, 0x0, 0x0, 0x0, 0, 0,
131 "CPU", "PARISC", (void *) cpu_driver_callback
},
134 (char *) NULL
, (char *) NULL
, (void *) NULL
}
137 static long fallback_cpu_hpa
[] = { 0xfffa0000L
, 0xfffbe000L
, 0x0 };
141 ** PARISC CPU driver - claim "device" and initialize CPU data structures.
143 ** Consolidate per CPU initialization into (mostly) one module.
144 ** Monarch CPU will initialize boot_cpu_data which shouldn't
145 ** change once the system has booted.
147 ** The callback *should* do per-instance initialization of
148 ** everything including the monarch. Some of the code that's
149 ** in setup.c:start_parisc() should migrate here and start_parisc()
150 ** should "register_driver(cpu_driver_for)" before calling
153 ** The goal of consolidating CPU initialization into one place is
154 ** to make sure all CPU's get initialized the same way.
155 ** It would be nice if the even the manarch through the exact same code path.
156 ** (up to rendevous at least).
159 #define ASSERT(expr) \
161 printk( "\n" __FILE__ ":%d: Assertion " #expr " failed!\n",__LINE__); \
166 cpu_driver_callback(struct hp_device
*d
, struct pa_iodc_driver
*dri
)
169 extern int pdc_pat
; /* arch/parisc/kernel/inventory.c */
170 static unsigned long pdc_result
[32] __attribute__ ((aligned (8))) = {0,0,0,0};
172 struct cpuinfo_parisc
*p
;
175 if (boot_cpu_data
.cpu_count
> 0) {
176 printk(KERN_INFO
"CONFIG_SMP disabled - not claiming addional CPUs\n");
181 p
= &cpu_data
[boot_cpu_data
.cpu_count
];
182 boot_cpu_data
.cpu_count
++;
184 /* TODO: Enable FP regs - done early in start_parisc() now */
186 /* initialize counters */
187 memset(p
, 0, sizeof(struct cpuinfo_parisc
));
189 p
->hpa
= (unsigned long) d
->hpa
; /* save CPU hpa */
194 pdc_pat_cell_mod_maddr_block_t pa_pdc_cell
;
196 status
= pdc_pat_cell_module(& pdc_result
, d
->pcell_loc
,
197 d
->mod_index
, PA_VIEW
, & pa_pdc_cell
);
199 ASSERT(PDC_RET_OK
== status
);
201 /* verify it's the same as what do_pat_inventory() found */
202 ASSERT(d
->mod_info
== pa_pdc_cell
.mod_info
);
203 ASSERT(d
->pmod_loc
== pa_pdc_cell
.mod_location
);
204 ASSERT(d
->mod_path
== pa_pdc_cell
.mod_path
);
206 p
->txn_addr
= pa_pdc_cell
.mod
[0]; /* id_eid for IO sapic */
208 /* get the cpu number */
209 status
= mem_pdc_call( PDC_PAT_CPU
, PDC_PAT_CPU_GET_NUMBER
,
210 __pa(& pdc_result
), d
->hpa
);
212 ASSERT(PDC_RET_OK
== status
);
214 p
->cpuid
= pdc_result
[0];
219 p
->txn_addr
= (unsigned long) d
->hpa
; /* for normal parisc */
221 /* logical CPU ID and update global counter */
222 p
->cpuid
= boot_cpu_data
.cpu_count
- 1;
226 ** itimer and ipi IRQ handlers are statically initialized in
227 ** arch/parisc/kernel/irq.c
229 p
->region
= irq_region
[IRQ_FROM_REGION(CPU_IRQ_REGION
)];
235 void __xchg_called_with_bad_pointer(void)
237 printk(KERN_EMERG
"xchg() called with bad pointer !\n");
241 /* Some versions of IODC don't list the CPU, and since we don't walk
242 * the bus yet, we have to probe for processors at well known hpa
246 void __init
register_fallback_cpu (void)
248 struct hp_device
*d
= NULL
;
252 #error "Revisit CPU fallback addresses for SMP (Assuming bus walk hasn't been implemented)"
254 printk ("No CPUs reported by firmware - probing...\n");
256 while (fallback_cpu_hpa
[i
]) {
258 d
= register_module ((void *) fallback_cpu_hpa
[i
]);
261 printk ("Found CPU at %lx\n", fallback_cpu_hpa
[i
]);
262 cpu_driver_callback (d
, 0);
269 panic ("No CPUs found. System halted.\n");
275 * Get CPU information and store it in the boot_cpu_data structure. */
276 void __init
collect_boot_cpu_data(void)
278 memset(&boot_cpu_data
,0,sizeof(boot_cpu_data
));
280 boot_cpu_data
.cpu_hz
= 100 * PAGE0
->mem_10msec
; /* Hz of this PARISC */
282 /* get CPU-Model Information... */
283 #define p ((unsigned long *)&boot_cpu_data.pdc.model)
284 if(pdc_model_info(&boot_cpu_data
.pdc
.model
)==0)
285 printk("model %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n",
286 p
[0], p
[1], p
[2], p
[3], p
[4], p
[5], p
[6], p
[7], p
[8]);
289 if(pdc_model_versions(&boot_cpu_data
.pdc
.versions
, 0)==0)
290 printk("vers %08lx\n", boot_cpu_data
.pdc
.versions
.cpuid
);
292 if(pdc_model_cpuid(&boot_cpu_data
.pdc
.cpuid
)==0)
293 printk("cpuid %08lx\n", boot_cpu_data
.pdc
.cpuid
.cpuid
);
295 printk("CPUID vers %ld rev %ld\n",
296 (boot_cpu_data
.pdc
.cpuid
.cpuid
>> 5) & 127,
297 boot_cpu_data
.pdc
.cpuid
.cpuid
& 31);
299 if (pdc_model_sysmodel(boot_cpu_data
.pdc
.sys_model_name
)==0)
300 printk("model %s\n",boot_cpu_data
.pdc
.sys_model_name
);
302 boot_cpu_data
.model_name
= parisc_getHWdescription(HPHW_NPROC
,
303 boot_cpu_data
.pdc
.model
.hversion
>>4,
304 boot_cpu_data
.pdc
.model
.sversion
>>8);
306 boot_cpu_data
.hversion
= boot_cpu_data
.pdc
.model
.hversion
;
307 boot_cpu_data
.sversion
= boot_cpu_data
.pdc
.model
.sversion
;
309 boot_cpu_data
.cpu_type
=
310 parisc_get_cpu_type(boot_cpu_data
.pdc
.model
.hversion
);
312 boot_cpu_data
.cpu_name
= cpu_name_version
[boot_cpu_data
.cpu_type
][0];
313 boot_cpu_data
.family_name
= cpu_name_version
[boot_cpu_data
.cpu_type
][1];
318 #define COMMAND_GLOBAL 0xfffffffffffe0030UL
320 #define COMMAND_GLOBAL 0xfffe0030
323 #define CMD_RESET 5 /* reset any module */
326 ** The Wright Brothers and Gecko systems have a H/W problem
327 ** (Lasi...'nuf said) may cause a broadcast reset to lockup
328 ** the system. An HVERSION dependent PDC call was developed
329 ** to perform a "safe", platform specific broadcast reset instead
330 ** of kludging up all the code.
332 ** Older machines which do not implement PDC_BROADCAST_RESET will
333 ** return (with an error) and the regular broadcast reset can be
334 ** issued. Obviously, if the PDC does implement PDC_BROADCAST_RESET
335 ** the PDC call will not return (the system will be reset).
338 reset_parisc(struct notifier_block
*self
, unsigned long command
, void *ptr
)
340 printk("%s: %s(cmd=%lu)\n", __FILE__
, __FUNCTION__
, command
);
344 #ifdef FASTBOOT_SELFTEST_SUPPORT
346 ** If user has modified the Firmware Selftest Bitmap,
347 ** run the tests specified in the bitmap after the
348 ** system is rebooted w/PDC_DO_RESET.
350 ** ftc_bitmap = 0x1AUL "Skip destructive memory tests"
352 ** Using "directed resets" at each processor with the MEM_TOC
353 ** vector cleared will also avoid running destructive
354 ** memory self tests. (Not implemented yet)
357 mem_pdc_call( PDC_BROADCAST_RESET
,
358 PDC_DO_FIRM_TEST_RESET
, PDC_FIRM_TEST_MAGIC
,
363 /* "Normal" system reset */
364 (void) mem_pdc_call(PDC_BROADCAST_RESET
, PDC_DO_RESET
,
367 /* Nope...box should reset with just CMD_RESET now */
368 gsc_writel(CMD_RESET
, COMMAND_GLOBAL
);
370 /* Wait for RESET to lay us to rest. */
378 static struct notifier_block parisc_block
= { reset_parisc
, NULL
, 0 };
381 /* start_parisc() will be called from head.S to setup our new memory_start
382 and actually start our kernel !
384 - Kernel-Image (code+data+BSS)
385 - Stack (stack-size see below!, stack-setup-code is in head.S)
386 - memory_start at end of stack..
389 unsigned long mem_start
, mem_max
;
390 unsigned long start_pfn
, max_pfn
;
391 extern asmlinkage
void __init
start_kernel(void);
393 #define PFN_UP(x) (((x) + PAGE_SIZE-1) >> PAGE_SHIFT)
394 #define PFN_DOWN(x) ((x) >> PAGE_SHIFT)
395 #define PFN_PHYS(x) ((x) << PAGE_SHIFT)
397 void __init
start_parisc(unsigned arg0
, unsigned arg1
,
398 unsigned arg2
, unsigned arg3
)
400 register unsigned long ccr
;
401 unsigned long memory_start
;
406 char *p
= &_edata
, *q
= &_end
;
417 printk("The 64-bit Kernel has started...\n");
419 printk("The 32-bit Kernel has started...\n");
423 ** Enable FP coprocessor
425 ** REVISIT: ccr should be set by PDC_COPROC results to support PA1.0.
426 ** Hardcoding works for PA1.1 processors.
428 ** REVISIT: this could be done in the "code 22" trap handler.
429 ** (frowands idea - that way we know which processes need FP
430 ** registers saved on the interrupt stack.)
432 ** NEWS FLASH: wide kernels need FP coprocessor enabled to handle
433 ** formatted printing of %lx for example (double divides I think)
437 printk("Enabled FP coprocessor\n");
440 printk( "If this is the LAST MESSAGE YOU SEE, you're probably using\n"
441 "32-bit millicode by mistake.\n");
444 memory_start
= (unsigned long) &_end
;
445 memory_start
= (memory_start
+ PAGE_SIZE
) & PAGE_MASK
;
446 printk("Free memory starts at: 0x%lx\n", memory_start
);
448 /* Collect stuff passed in from the boot loader */
449 printk(KERN_WARNING
"%s(0x%x,0x%x,0x%x,0x%x)\n",
450 __FUNCTION__
, arg0
, arg1
, arg2
, arg3
);
452 /* arg0 is free-mem start, arg1 is ptr to command line */
454 /* called from hpux boot loader */
455 saved_command_line
[0] = '\0';
457 strcpy(saved_command_line
, (char *)__va(arg1
));
458 printk("PALO command line: '%s'\nPALO initrd %x-%x\n",
459 saved_command_line
, arg2
, arg3
);
461 #ifdef CONFIG_BLK_DEV_INITRD
462 if (arg2
!= 0) /* did palo pass us a ramdisk? */
464 initrd_start
= (unsigned long)__va(arg2
);
465 initrd_end
= (unsigned long)__va(arg3
);
470 mem_start
= __pa(memory_start
);
471 #define MAX_MEM (512*1024*1024)
472 mem_max
= (PAGE0
->imm_max_mem
> MAX_MEM
? MAX_MEM
: PAGE0
->imm_max_mem
);
474 collect_boot_cpu_data();
476 /* initialize the LCD/LED after boot_cpu_data is available ! */
477 led_init(); /* LCD/LED initialization */
479 do_inventory(); /* probe for hardware */
480 register_driver(cpu_drivers_for
); /* claim all the CPUs */
482 if (boot_cpu_data
.cpu_count
== 0)
483 register_fallback_cpu();
485 printk("CPU(s): %d x %s at %d.%06d MHz\n",
486 boot_cpu_data
.cpu_count
,
487 boot_cpu_data
.cpu_name
,
488 boot_cpu_data
.cpu_hz
/ 1000000,
489 boot_cpu_data
.cpu_hz
% 1000000 );
491 switch (boot_cpu_data
.cpu_type
) {
495 hppa_dma_ops
= &pcx_dma_ops
;
499 case pcxl
: /* falls through */
500 hppa_dma_ops
= &pcxl_dma_ops
;
507 /* KLUGE! this really belongs in kernel/resource.c! */
508 iomem_resource
.end
= ~0UL;
510 sysram_resource
.end
= mem_max
- 1;
511 notifier_chain_register(&mach_notifier
, &parisc_block
);
512 start_kernel(); /* now back to arch-generic code... */
515 void __init
setup_arch(char **cmdline_p
)
517 unsigned long bootmap_size
;
518 unsigned long start_pfn
;
519 unsigned long mem_free
;
521 *cmdline_p
= saved_command_line
;
523 /* initialize bootmem */
525 start_pfn
= PFN_UP(mem_start
);
526 max_pfn
= PFN_DOWN(mem_max
);
528 bootmap_size
= init_bootmem(start_pfn
, max_pfn
);
530 mem_start
+= bootmap_size
;
531 mem_free
= mem_max
- mem_start
;
533 /* free_bootmem handles rounding nicely */
534 printk("free_bootmem(0x%lx, 0x%lx)\n", (unsigned long)mem_start
,
535 (unsigned long)mem_free
);
536 free_bootmem(mem_start
, mem_free
);
538 #ifdef CONFIG_BLK_DEV_INITRD
539 printk("initrd: %08x-%08x\n", (int) initrd_start
, (int) initrd_end
);
541 if (initrd_end
!= 0) {
542 initrd_below_start_ok
= 1;
543 reserve_bootmem(__pa(initrd_start
), initrd_end
- initrd_start
);
551 if((unsigned long)&init_task_union
&(INIT_TASK_SIZE
- 1)) {
552 printk("init_task_union not aligned. Please recompile the kernel after changing the first line in arch/parisc/kernel/init_task.c from \n\"#define PAD 0\" to\n\"#define PAD 1\" or vice versa\n");
557 #ifdef CONFIG_SERIAL_CONSOLE
560 #if defined(CONFIG_STI_CONSOLE)
561 conswitchp
= &dummy_con
; /* we use take_over_console() later ! */
562 #elif defined(CONFIG_IODC_CONSOLE)
563 conswitchp
= &prom_con
; /* it's currently really "prom_con" */
564 #elif defined(CONFIG_DUMMY_CONSOLE)
565 conswitchp
= &dummy_con
;
571 #ifdef CONFIG_PROC_FS
573 * Get CPU information for use by procfs.
576 int get_cpuinfo(char *buffer
)
581 for(n
=0; n
<boot_cpu_data
.cpu_count
; n
++) {
583 if (!(cpu_online_map
& (1<<n
)))
586 p
+= sprintf(p
, "processor\t: %d\n"
587 "cpu family\t: PA-RISC %s\n",
588 n
, boot_cpu_data
.family_name
);
590 p
+= sprintf(p
, "cpu\t\t: %s\n", boot_cpu_data
.cpu_name
);
593 p
+= sprintf(p
, "cpu MHz\t\t: %d.%06d\n",
594 boot_cpu_data
.cpu_hz
/ 1000000,
595 boot_cpu_data
.cpu_hz
% 1000000 );
597 p
+= sprintf(p
, "model\t\t: %s\n"
598 "model name\t: %s\n",
599 boot_cpu_data
.pdc
.sys_model_name
,
600 boot_cpu_data
.model_name
);
602 p
+= sprintf(p
, "hversion\t: 0x%08x\n"
603 "sversion\t: 0x%08x\n",
604 boot_cpu_data
.hversion
,
605 boot_cpu_data
.sversion
);
607 p
+= get_cache_info(p
);
608 /* print cachesize info ? */
609 p
+= sprintf(p
, "bogomips\t: %lu.%02lu\n",
610 (loops_per_sec
+2500)/500000,
611 ((loops_per_sec
+2500)/5000) % 100);