diff options
Diffstat (limited to 'arch/x86/mach-visws/setup.c')
-rw-r--r-- | arch/x86/mach-visws/setup.c | 249 |
1 files changed, 105 insertions, 144 deletions
diff --git a/arch/x86/mach-visws/setup.c b/arch/x86/mach-visws/setup.c index d67868ec9b7f..2f5e277686b8 100644 --- a/arch/x86/mach-visws/setup.c +++ b/arch/x86/mach-visws/setup.c | |||
@@ -1,183 +1,144 @@ | |||
1 | /* | 1 | /* |
2 | * Unmaintained SGI Visual Workstation support. | 2 | * Machine specific setup for generic |
3 | * Split out from setup.c by davej@suse.de | ||
4 | */ | 3 | */ |
5 | 4 | ||
6 | #include <linux/smp.h> | 5 | #include <linux/smp.h> |
7 | #include <linux/init.h> | 6 | #include <linux/init.h> |
8 | #include <linux/interrupt.h> | 7 | #include <linux/interrupt.h> |
9 | #include <linux/module.h> | 8 | #include <asm/acpi.h> |
10 | |||
11 | #include <asm/fixmap.h> | ||
12 | #include <asm/arch_hooks.h> | 9 | #include <asm/arch_hooks.h> |
13 | #include <asm/io.h> | ||
14 | #include <asm/e820.h> | 10 | #include <asm/e820.h> |
15 | #include <asm/setup.h> | 11 | #include <asm/setup.h> |
16 | #include "cobalt.h" | ||
17 | #include "piix4.h" | ||
18 | |||
19 | int no_broadcast; | ||
20 | |||
21 | char visws_board_type = -1; | ||
22 | char visws_board_rev = -1; | ||
23 | |||
24 | void __init visws_get_board_type_and_rev(void) | ||
25 | { | ||
26 | int raw; | ||
27 | |||
28 | visws_board_type = (char)(inb_p(PIIX_GPI_BD_REG) & PIIX_GPI_BD_REG) | ||
29 | >> PIIX_GPI_BD_SHIFT; | ||
30 | /* | ||
31 | * Get Board rev. | ||
32 | * First, we have to initialize the 307 part to allow us access | ||
33 | * to the GPIO registers. Let's map them at 0x0fc0 which is right | ||
34 | * after the PIIX4 PM section. | ||
35 | */ | ||
36 | outb_p(SIO_DEV_SEL, SIO_INDEX); | ||
37 | outb_p(SIO_GP_DEV, SIO_DATA); /* Talk to GPIO regs. */ | ||
38 | |||
39 | outb_p(SIO_DEV_MSB, SIO_INDEX); | ||
40 | outb_p(SIO_GP_MSB, SIO_DATA); /* MSB of GPIO base address */ | ||
41 | |||
42 | outb_p(SIO_DEV_LSB, SIO_INDEX); | ||
43 | outb_p(SIO_GP_LSB, SIO_DATA); /* LSB of GPIO base address */ | ||
44 | |||
45 | outb_p(SIO_DEV_ENB, SIO_INDEX); | ||
46 | outb_p(1, SIO_DATA); /* Enable GPIO registers. */ | ||
47 | |||
48 | /* | ||
49 | * Now, we have to map the power management section to write | ||
50 | * a bit which enables access to the GPIO registers. | ||
51 | * What lunatic came up with this shit? | ||
52 | */ | ||
53 | outb_p(SIO_DEV_SEL, SIO_INDEX); | ||
54 | outb_p(SIO_PM_DEV, SIO_DATA); /* Talk to GPIO regs. */ | ||
55 | 12 | ||
56 | outb_p(SIO_DEV_MSB, SIO_INDEX); | 13 | #ifdef CONFIG_HOTPLUG_CPU |
57 | outb_p(SIO_PM_MSB, SIO_DATA); /* MSB of PM base address */ | 14 | #define DEFAULT_SEND_IPI (1) |
58 | 15 | #else | |
59 | outb_p(SIO_DEV_LSB, SIO_INDEX); | 16 | #define DEFAULT_SEND_IPI (0) |
60 | outb_p(SIO_PM_LSB, SIO_DATA); /* LSB of PM base address */ | 17 | #endif |
61 | |||
62 | outb_p(SIO_DEV_ENB, SIO_INDEX); | ||
63 | outb_p(1, SIO_DATA); /* Enable PM registers. */ | ||
64 | |||
65 | /* | ||
66 | * Now, write the PM register which enables the GPIO registers. | ||
67 | */ | ||
68 | outb_p(SIO_PM_FER2, SIO_PM_INDEX); | ||
69 | outb_p(SIO_PM_GP_EN, SIO_PM_DATA); | ||
70 | |||
71 | /* | ||
72 | * Now, initialize the GPIO registers. | ||
73 | * We want them all to be inputs which is the | ||
74 | * power on default, so let's leave them alone. | ||
75 | * So, let's just read the board rev! | ||
76 | */ | ||
77 | raw = inb_p(SIO_GP_DATA1); | ||
78 | raw &= 0x7f; /* 7 bits of valid board revision ID. */ | ||
79 | |||
80 | if (visws_board_type == VISWS_320) { | ||
81 | if (raw < 0x6) { | ||
82 | visws_board_rev = 4; | ||
83 | } else if (raw < 0xc) { | ||
84 | visws_board_rev = 5; | ||
85 | } else { | ||
86 | visws_board_rev = 6; | ||
87 | } | ||
88 | } else if (visws_board_type == VISWS_540) { | ||
89 | visws_board_rev = 2; | ||
90 | } else { | ||
91 | visws_board_rev = raw; | ||
92 | } | ||
93 | |||
94 | printk(KERN_INFO "Silicon Graphics Visual Workstation %s (rev %d) detected\n", | ||
95 | (visws_board_type == VISWS_320 ? "320" : | ||
96 | (visws_board_type == VISWS_540 ? "540" : | ||
97 | "unknown")), visws_board_rev); | ||
98 | } | ||
99 | 18 | ||
19 | int no_broadcast=DEFAULT_SEND_IPI; | ||
20 | |||
21 | /** | ||
22 | * pre_intr_init_hook - initialisation prior to setting up interrupt vectors | ||
23 | * | ||
24 | * Description: | ||
25 | * Perform any necessary interrupt initialisation prior to setting up | ||
26 | * the "ordinary" interrupt call gates. For legacy reasons, the ISA | ||
27 | * interrupts should be initialised here if the machine emulates a PC | ||
28 | * in any way. | ||
29 | **/ | ||
100 | void __init pre_intr_init_hook(void) | 30 | void __init pre_intr_init_hook(void) |
101 | { | 31 | { |
102 | init_VISWS_APIC_irqs(); | 32 | init_ISA_irqs(); |
103 | } | 33 | } |
104 | 34 | ||
35 | /* | ||
36 | * IRQ2 is cascade interrupt to second interrupt controller | ||
37 | */ | ||
38 | static struct irqaction irq2 = { | ||
39 | .handler = no_action, | ||
40 | .mask = CPU_MASK_NONE, | ||
41 | .name = "cascade", | ||
42 | }; | ||
43 | |||
44 | /** | ||
45 | * intr_init_hook - post gate setup interrupt initialisation | ||
46 | * | ||
47 | * Description: | ||
48 | * Fill in any interrupts that may have been left out by the general | ||
49 | * init_IRQ() routine. interrupts having to do with the machine rather | ||
50 | * than the devices on the I/O bus (like APIC interrupts in intel MP | ||
51 | * systems) are started here. | ||
52 | **/ | ||
105 | void __init intr_init_hook(void) | 53 | void __init intr_init_hook(void) |
106 | { | 54 | { |
107 | #ifdef CONFIG_X86_LOCAL_APIC | 55 | #ifdef CONFIG_X86_LOCAL_APIC |
108 | apic_intr_init(); | 56 | apic_intr_init(); |
109 | #endif | 57 | #endif |
58 | |||
59 | if (!acpi_ioapic) | ||
60 | setup_irq(2, &irq2); | ||
61 | } | ||
62 | |||
63 | /** | ||
64 | * pre_setup_arch_hook - hook called prior to any setup_arch() execution | ||
65 | * | ||
66 | * Description: | ||
67 | * generally used to activate any machine specific identification | ||
68 | * routines that may be needed before setup_arch() runs. On VISWS | ||
69 | * this is used to get the board revision and type. | ||
70 | **/ | ||
71 | void __init pre_setup_arch_hook(void) | ||
72 | { | ||
110 | } | 73 | } |
111 | 74 | ||
112 | void __init pre_setup_arch_hook() | 75 | /** |
76 | * trap_init_hook - initialise system specific traps | ||
77 | * | ||
78 | * Description: | ||
79 | * Called as the final act of trap_init(). Used in VISWS to initialise | ||
80 | * the various board specific APIC traps. | ||
81 | **/ | ||
82 | void __init trap_init_hook(void) | ||
113 | { | 83 | { |
114 | visws_get_board_type_and_rev(); | ||
115 | } | 84 | } |
116 | 85 | ||
117 | static struct irqaction irq0 = { | 86 | static struct irqaction irq0 = { |
118 | .handler = timer_interrupt, | 87 | .handler = timer_interrupt, |
119 | .flags = IRQF_DISABLED | IRQF_IRQPOLL, | 88 | .flags = IRQF_DISABLED | IRQF_NOBALANCING | IRQF_IRQPOLL, |
120 | .name = "timer", | 89 | .mask = CPU_MASK_NONE, |
90 | .name = "timer" | ||
121 | }; | 91 | }; |
122 | 92 | ||
93 | /** | ||
94 | * time_init_hook - do any specific initialisations for the system timer. | ||
95 | * | ||
96 | * Description: | ||
97 | * Must plug the system timer interrupt source at HZ into the IRQ listed | ||
98 | * in irq_vectors.h:TIMER_IRQ | ||
99 | **/ | ||
123 | void __init time_init_hook(void) | 100 | void __init time_init_hook(void) |
124 | { | 101 | { |
125 | printk(KERN_INFO "Starting Cobalt Timer system clock\n"); | 102 | irq0.mask = cpumask_of_cpu(0); |
126 | |||
127 | /* Set the countdown value */ | ||
128 | co_cpu_write(CO_CPU_TIMEVAL, CO_TIME_HZ/HZ); | ||
129 | |||
130 | /* Start the timer */ | ||
131 | co_cpu_write(CO_CPU_CTRL, co_cpu_read(CO_CPU_CTRL) | CO_CTRL_TIMERUN); | ||
132 | |||
133 | /* Enable (unmask) the timer interrupt */ | ||
134 | co_cpu_write(CO_CPU_CTRL, co_cpu_read(CO_CPU_CTRL) & ~CO_CTRL_TIMEMASK); | ||
135 | |||
136 | /* Wire cpu IDT entry to s/w handler (and Cobalt APIC to IDT) */ | ||
137 | setup_irq(0, &irq0); | 103 | setup_irq(0, &irq0); |
138 | } | 104 | } |
139 | 105 | ||
140 | /* Hook for machine specific memory setup. */ | 106 | #ifdef CONFIG_MCA |
141 | 107 | /** | |
142 | #define MB (1024 * 1024) | 108 | * mca_nmi_hook - hook into MCA specific NMI chain |
143 | 109 | * | |
144 | unsigned long sgivwfb_mem_phys; | 110 | * Description: |
145 | unsigned long sgivwfb_mem_size; | 111 | * The MCA (Microchannel Architecture) has an NMI chain for NMI sources |
146 | EXPORT_SYMBOL(sgivwfb_mem_phys); | 112 | * along the MCA bus. Use this to hook into that chain if you will need |
147 | EXPORT_SYMBOL(sgivwfb_mem_size); | 113 | * it. |
148 | 114 | **/ | |
149 | long long mem_size __initdata = 0; | 115 | void mca_nmi_hook(void) |
150 | |||
151 | char * __init machine_specific_memory_setup(void) | ||
152 | { | 116 | { |
153 | long long gfx_mem_size = 8 * MB; | 117 | /* If I recall correctly, there's a whole bunch of other things that |
118 | * we can do to check for NMI problems, but that's all I know about | ||
119 | * at the moment. | ||
120 | */ | ||
154 | 121 | ||
155 | mem_size = boot_params.alt_mem_k; | 122 | printk("NMI generated from unknown source!\n"); |
123 | } | ||
124 | #endif | ||
156 | 125 | ||
157 | if (!mem_size) { | 126 | static __init int no_ipi_broadcast(char *str) |
158 | printk(KERN_WARNING "Bootloader didn't set memory size, upgrade it !\n"); | 127 | { |
159 | mem_size = 128 * MB; | 128 | get_option(&str, &no_broadcast); |
160 | } | 129 | printk ("Using %s mode\n", no_broadcast ? "No IPI Broadcast" : |
130 | "IPI Broadcast"); | ||
131 | return 1; | ||
132 | } | ||
161 | 133 | ||
162 | /* | 134 | __setup("no_ipi_broadcast=", no_ipi_broadcast); |
163 | * this hardcodes the graphics memory to 8 MB | ||
164 | * it really should be sized dynamically (or at least | ||
165 | * set as a boot param) | ||
166 | */ | ||
167 | if (!sgivwfb_mem_size) { | ||
168 | printk(KERN_WARNING "Defaulting to 8 MB framebuffer size\n"); | ||
169 | sgivwfb_mem_size = 8 * MB; | ||
170 | } | ||
171 | 135 | ||
172 | /* | 136 | static int __init print_ipi_mode(void) |
173 | * Trim to nearest MB | 137 | { |
174 | */ | 138 | printk ("Using IPI %s mode\n", no_broadcast ? "No-Shortcut" : |
175 | sgivwfb_mem_size &= ~((1 << 20) - 1); | 139 | "Shortcut"); |
176 | sgivwfb_mem_phys = mem_size - gfx_mem_size; | 140 | return 0; |
141 | } | ||
177 | 142 | ||
178 | e820_add_region(0, LOWMEMSIZE(), E820_RAM); | 143 | late_initcall(print_ipi_mode); |
179 | e820_add_region(HIGH_MEMORY, mem_size - sgivwfb_mem_size - HIGH_MEMORY, E820_RAM); | ||
180 | e820_add_region(sgivwfb_mem_phys, sgivwfb_mem_size, E820_RESERVED); | ||
181 | 144 | ||
182 | return "PROM"; | ||
183 | } | ||