diff options
-rw-r--r-- | arch/powerpc/platforms/Makefile | 4 | ||||
-rw-r--r-- | arch/ppc64/kernel/Makefile | 10 | ||||
-rw-r--r-- | arch/ppc64/kernel/pmac.h | 31 | ||||
-rw-r--r-- | arch/ppc64/kernel/pmac_feature.c | 767 | ||||
-rw-r--r-- | arch/ppc64/kernel/pmac_low_i2c.c | 523 | ||||
-rw-r--r-- | arch/ppc64/kernel/pmac_nvram.c | 493 | ||||
-rw-r--r-- | arch/ppc64/kernel/pmac_pci.c | 793 | ||||
-rw-r--r-- | arch/ppc64/kernel/pmac_setup.c | 476 | ||||
-rw-r--r-- | arch/ppc64/kernel/pmac_smp.c | 316 | ||||
-rw-r--r-- | arch/ppc64/kernel/pmac_time.c | 174 |
10 files changed, 6 insertions, 3581 deletions
diff --git a/arch/powerpc/platforms/Makefile b/arch/powerpc/platforms/Makefile index 9b54e805b8aa..509622da5408 100644 --- a/arch/powerpc/platforms/Makefile +++ b/arch/powerpc/platforms/Makefile | |||
@@ -1,5 +1,9 @@ | |||
1 | ifeq ($(CONFIG_PPC_MERGE),y) | 1 | ifeq ($(CONFIG_PPC_MERGE),y) |
2 | obj-$(CONFIG_PPC_PMAC) += powermac/ | 2 | obj-$(CONFIG_PPC_PMAC) += powermac/ |
3 | else | ||
4 | ifeq ($(CONFIG_PPC64),y) | ||
5 | obj-$(CONFIG_PPC_PMAC) += powermac/ | ||
6 | endif | ||
3 | endif | 7 | endif |
4 | obj-$(CONFIG_4xx) += 4xx/ | 8 | obj-$(CONFIG_4xx) += 4xx/ |
5 | obj-$(CONFIG_85xx) += 85xx/ | 9 | obj-$(CONFIG_85xx) += 85xx/ |
diff --git a/arch/ppc64/kernel/Makefile b/arch/ppc64/kernel/Makefile index 6c02a79955c7..424dd250cd87 100644 --- a/arch/ppc64/kernel/Makefile +++ b/arch/ppc64/kernel/Makefile | |||
@@ -56,11 +56,7 @@ obj-$(CONFIG_HVCS) += hvcserver.o | |||
56 | obj-$(CONFIG_IBMVIO) += vio.o | 56 | obj-$(CONFIG_IBMVIO) += vio.o |
57 | obj-$(CONFIG_XICS) += xics.o | 57 | obj-$(CONFIG_XICS) += xics.o |
58 | 58 | ||
59 | ifneq ($(CONFIG_PPC_MERGE),y) | 59 | obj-$(CONFIG_PPC_PMAC) += udbg_scc.o |
60 | obj-$(CONFIG_PPC_PMAC) += pmac_setup.o pmac_feature.o pmac_pci.o \ | ||
61 | pmac_time.o pmac_nvram.o pmac_low_i2c.o \ | ||
62 | udbg_scc.o | ||
63 | endif | ||
64 | 60 | ||
65 | obj-$(CONFIG_PPC_MAPLE) += maple_setup.o maple_pci.o maple_time.o \ | 61 | obj-$(CONFIG_PPC_MAPLE) += maple_setup.o maple_pci.o maple_time.o \ |
66 | udbg_16550.o | 62 | udbg_16550.o |
@@ -68,9 +64,7 @@ obj-$(CONFIG_PPC_MAPLE) += maple_setup.o maple_pci.o maple_time.o \ | |||
68 | obj-$(CONFIG_U3_DART) += u3_iommu.o | 64 | obj-$(CONFIG_U3_DART) += u3_iommu.o |
69 | 65 | ||
70 | ifdef CONFIG_SMP | 66 | ifdef CONFIG_SMP |
71 | ifneq ($(CONFIG_PPC_MERGE),y) | 67 | obj-$(CONFIG_PPC_PMAC) += smp-tbsync.o |
72 | obj-$(CONFIG_PPC_PMAC) += pmac_smp.o smp-tbsync.o | ||
73 | endif | ||
74 | obj-$(CONFIG_PPC_MAPLE) += smp-tbsync.o | 68 | obj-$(CONFIG_PPC_MAPLE) += smp-tbsync.o |
75 | endif | 69 | endif |
76 | 70 | ||
diff --git a/arch/ppc64/kernel/pmac.h b/arch/ppc64/kernel/pmac.h deleted file mode 100644 index fa59f2a5c722..000000000000 --- a/arch/ppc64/kernel/pmac.h +++ /dev/null | |||
@@ -1,31 +0,0 @@ | |||
1 | #ifndef __PMAC_H__ | ||
2 | #define __PMAC_H__ | ||
3 | |||
4 | #include <linux/pci.h> | ||
5 | #include <linux/ide.h> | ||
6 | |||
7 | /* | ||
8 | * Declaration for the various functions exported by the | ||
9 | * pmac_* files. Mostly for use by pmac_setup | ||
10 | */ | ||
11 | |||
12 | extern unsigned long pmac_get_boot_time(void); | ||
13 | extern void pmac_get_rtc_time(struct rtc_time *tm); | ||
14 | extern int pmac_set_rtc_time(struct rtc_time *tm); | ||
15 | extern void pmac_read_rtc_time(void); | ||
16 | extern void pmac_calibrate_decr(void); | ||
17 | |||
18 | extern void pmac_pcibios_fixup(void); | ||
19 | extern void pmac_pci_init(void); | ||
20 | extern void pmac_setup_pci_dma(void); | ||
21 | extern void pmac_check_ht_link(void); | ||
22 | |||
23 | extern void pmac_setup_smp(void); | ||
24 | |||
25 | extern unsigned long pmac_ide_get_base(int index); | ||
26 | extern void pmac_ide_init_hwif_ports(hw_regs_t *hw, | ||
27 | unsigned long data_port, unsigned long ctrl_port, int *irq); | ||
28 | |||
29 | extern void pmac_nvram_init(void); | ||
30 | |||
31 | #endif /* __PMAC_H__ */ | ||
diff --git a/arch/ppc64/kernel/pmac_feature.c b/arch/ppc64/kernel/pmac_feature.c deleted file mode 100644 index 26075f11db77..000000000000 --- a/arch/ppc64/kernel/pmac_feature.c +++ /dev/null | |||
@@ -1,767 +0,0 @@ | |||
1 | /* | ||
2 | * arch/ppc/platforms/pmac_feature.c | ||
3 | * | ||
4 | * Copyright (C) 1996-2001 Paul Mackerras (paulus@cs.anu.edu.au) | ||
5 | * Ben. Herrenschmidt (benh@kernel.crashing.org) | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or | ||
8 | * modify it under the terms of the GNU General Public License | ||
9 | * as published by the Free Software Foundation; either version | ||
10 | * 2 of the License, or (at your option) any later version. | ||
11 | * | ||
12 | * TODO: | ||
13 | * | ||
14 | * - Replace mdelay with some schedule loop if possible | ||
15 | * - Shorten some obfuscated delays on some routines (like modem | ||
16 | * power) | ||
17 | * - Refcount some clocks (see darwin) | ||
18 | * - Split split split... | ||
19 | * | ||
20 | */ | ||
21 | #include <linux/config.h> | ||
22 | #include <linux/types.h> | ||
23 | #include <linux/init.h> | ||
24 | #include <linux/delay.h> | ||
25 | #include <linux/kernel.h> | ||
26 | #include <linux/sched.h> | ||
27 | #include <linux/spinlock.h> | ||
28 | #include <linux/adb.h> | ||
29 | #include <linux/pmu.h> | ||
30 | #include <linux/ioport.h> | ||
31 | #include <linux/pci.h> | ||
32 | #include <asm/sections.h> | ||
33 | #include <asm/errno.h> | ||
34 | #include <asm/keylargo.h> | ||
35 | #include <asm/uninorth.h> | ||
36 | #include <asm/io.h> | ||
37 | #include <asm/prom.h> | ||
38 | #include <asm/machdep.h> | ||
39 | #include <asm/pmac_feature.h> | ||
40 | #include <asm/dbdma.h> | ||
41 | #include <asm/pci-bridge.h> | ||
42 | #include <asm/pmac_low_i2c.h> | ||
43 | |||
44 | #undef DEBUG_FEATURE | ||
45 | |||
46 | #ifdef DEBUG_FEATURE | ||
47 | #define DBG(fmt...) printk(KERN_DEBUG fmt) | ||
48 | #else | ||
49 | #define DBG(fmt...) | ||
50 | #endif | ||
51 | |||
52 | /* | ||
53 | * We use a single global lock to protect accesses. Each driver has | ||
54 | * to take care of its own locking | ||
55 | */ | ||
56 | static DEFINE_SPINLOCK(feature_lock); | ||
57 | |||
58 | #define LOCK(flags) spin_lock_irqsave(&feature_lock, flags); | ||
59 | #define UNLOCK(flags) spin_unlock_irqrestore(&feature_lock, flags); | ||
60 | |||
61 | |||
62 | /* | ||
63 | * Instance of some macio stuffs | ||
64 | */ | ||
65 | struct macio_chip macio_chips[MAX_MACIO_CHIPS] ; | ||
66 | |||
67 | struct macio_chip* macio_find(struct device_node* child, int type) | ||
68 | { | ||
69 | while(child) { | ||
70 | int i; | ||
71 | |||
72 | for (i=0; i < MAX_MACIO_CHIPS && macio_chips[i].of_node; i++) | ||
73 | if (child == macio_chips[i].of_node && | ||
74 | (!type || macio_chips[i].type == type)) | ||
75 | return &macio_chips[i]; | ||
76 | child = child->parent; | ||
77 | } | ||
78 | return NULL; | ||
79 | } | ||
80 | EXPORT_SYMBOL_GPL(macio_find); | ||
81 | |||
82 | static const char* macio_names[] = | ||
83 | { | ||
84 | "Unknown", | ||
85 | "Grand Central", | ||
86 | "OHare", | ||
87 | "OHareII", | ||
88 | "Heathrow", | ||
89 | "Gatwick", | ||
90 | "Paddington", | ||
91 | "Keylargo", | ||
92 | "Pangea", | ||
93 | "Intrepid", | ||
94 | "K2" | ||
95 | }; | ||
96 | |||
97 | |||
98 | |||
99 | /* | ||
100 | * Uninorth reg. access. Note that Uni-N regs are big endian | ||
101 | */ | ||
102 | |||
103 | #define UN_REG(r) (uninorth_base + ((r) >> 2)) | ||
104 | #define UN_IN(r) (in_be32(UN_REG(r))) | ||
105 | #define UN_OUT(r,v) (out_be32(UN_REG(r), (v))) | ||
106 | #define UN_BIS(r,v) (UN_OUT((r), UN_IN(r) | (v))) | ||
107 | #define UN_BIC(r,v) (UN_OUT((r), UN_IN(r) & ~(v))) | ||
108 | |||
109 | static struct device_node* uninorth_node; | ||
110 | static u32* uninorth_base; | ||
111 | static u32 uninorth_rev; | ||
112 | static void *u3_ht; | ||
113 | |||
114 | extern struct device_node *k2_skiplist[2]; | ||
115 | |||
116 | /* | ||
117 | * For each motherboard family, we have a table of functions pointers | ||
118 | * that handle the various features. | ||
119 | */ | ||
120 | |||
121 | typedef long (*feature_call)(struct device_node* node, long param, long value); | ||
122 | |||
123 | struct feature_table_entry { | ||
124 | unsigned int selector; | ||
125 | feature_call function; | ||
126 | }; | ||
127 | |||
128 | struct pmac_mb_def | ||
129 | { | ||
130 | const char* model_string; | ||
131 | const char* model_name; | ||
132 | int model_id; | ||
133 | struct feature_table_entry* features; | ||
134 | unsigned long board_flags; | ||
135 | }; | ||
136 | static struct pmac_mb_def pmac_mb; | ||
137 | |||
138 | /* | ||
139 | * Here are the chip specific feature functions | ||
140 | */ | ||
141 | |||
142 | |||
143 | static long g5_read_gpio(struct device_node* node, long param, long value) | ||
144 | { | ||
145 | struct macio_chip* macio = &macio_chips[0]; | ||
146 | |||
147 | return MACIO_IN8(param); | ||
148 | } | ||
149 | |||
150 | |||
151 | static long g5_write_gpio(struct device_node* node, long param, long value) | ||
152 | { | ||
153 | struct macio_chip* macio = &macio_chips[0]; | ||
154 | |||
155 | MACIO_OUT8(param, (u8)(value & 0xff)); | ||
156 | return 0; | ||
157 | } | ||
158 | |||
159 | static long g5_gmac_enable(struct device_node* node, long param, long value) | ||
160 | { | ||
161 | struct macio_chip* macio = &macio_chips[0]; | ||
162 | unsigned long flags; | ||
163 | |||
164 | if (node == NULL) | ||
165 | return -ENODEV; | ||
166 | |||
167 | LOCK(flags); | ||
168 | if (value) { | ||
169 | MACIO_BIS(KEYLARGO_FCR1, K2_FCR1_GMAC_CLK_ENABLE); | ||
170 | mb(); | ||
171 | k2_skiplist[0] = NULL; | ||
172 | } else { | ||
173 | k2_skiplist[0] = node; | ||
174 | mb(); | ||
175 | MACIO_BIC(KEYLARGO_FCR1, K2_FCR1_GMAC_CLK_ENABLE); | ||
176 | } | ||
177 | |||
178 | UNLOCK(flags); | ||
179 | mdelay(1); | ||
180 | |||
181 | return 0; | ||
182 | } | ||
183 | |||
184 | static long g5_fw_enable(struct device_node* node, long param, long value) | ||
185 | { | ||
186 | struct macio_chip* macio = &macio_chips[0]; | ||
187 | unsigned long flags; | ||
188 | |||
189 | if (node == NULL) | ||
190 | return -ENODEV; | ||
191 | |||
192 | LOCK(flags); | ||
193 | if (value) { | ||
194 | MACIO_BIS(KEYLARGO_FCR1, K2_FCR1_FW_CLK_ENABLE); | ||
195 | mb(); | ||
196 | k2_skiplist[1] = NULL; | ||
197 | } else { | ||
198 | k2_skiplist[1] = node; | ||
199 | mb(); | ||
200 | MACIO_BIC(KEYLARGO_FCR1, K2_FCR1_FW_CLK_ENABLE); | ||
201 | } | ||
202 | |||
203 | UNLOCK(flags); | ||
204 | mdelay(1); | ||
205 | |||
206 | return 0; | ||
207 | } | ||
208 | |||
209 | static long g5_mpic_enable(struct device_node* node, long param, long value) | ||
210 | { | ||
211 | unsigned long flags; | ||
212 | |||
213 | if (node->parent == NULL || strcmp(node->parent->name, "u3")) | ||
214 | return 0; | ||
215 | |||
216 | LOCK(flags); | ||
217 | UN_BIS(U3_TOGGLE_REG, U3_MPIC_RESET | U3_MPIC_OUTPUT_ENABLE); | ||
218 | UNLOCK(flags); | ||
219 | |||
220 | return 0; | ||
221 | } | ||
222 | |||
223 | static long g5_eth_phy_reset(struct device_node* node, long param, long value) | ||
224 | { | ||
225 | struct macio_chip* macio = &macio_chips[0]; | ||
226 | struct device_node *phy; | ||
227 | int need_reset; | ||
228 | |||
229 | /* | ||
230 | * We must not reset the combo PHYs, only the BCM5221 found in | ||
231 | * the iMac G5. | ||
232 | */ | ||
233 | phy = of_get_next_child(node, NULL); | ||
234 | if (!phy) | ||
235 | return -ENODEV; | ||
236 | need_reset = device_is_compatible(phy, "B5221"); | ||
237 | of_node_put(phy); | ||
238 | if (!need_reset) | ||
239 | return 0; | ||
240 | |||
241 | /* PHY reset is GPIO 29, not in device-tree unfortunately */ | ||
242 | MACIO_OUT8(K2_GPIO_EXTINT_0 + 29, | ||
243 | KEYLARGO_GPIO_OUTPUT_ENABLE | KEYLARGO_GPIO_OUTOUT_DATA); | ||
244 | /* Thankfully, this is now always called at a time when we can | ||
245 | * schedule by sungem. | ||
246 | */ | ||
247 | msleep(10); | ||
248 | MACIO_OUT8(K2_GPIO_EXTINT_0 + 29, 0); | ||
249 | |||
250 | return 0; | ||
251 | } | ||
252 | |||
253 | static long g5_i2s_enable(struct device_node *node, long param, long value) | ||
254 | { | ||
255 | /* Very crude implementation for now */ | ||
256 | struct macio_chip* macio = &macio_chips[0]; | ||
257 | unsigned long flags; | ||
258 | |||
259 | if (value == 0) | ||
260 | return 0; /* don't disable yet */ | ||
261 | |||
262 | LOCK(flags); | ||
263 | MACIO_BIS(KEYLARGO_FCR3, KL3_CLK45_ENABLE | KL3_CLK49_ENABLE | | ||
264 | KL3_I2S0_CLK18_ENABLE); | ||
265 | udelay(10); | ||
266 | MACIO_BIS(KEYLARGO_FCR1, K2_FCR1_I2S0_CELL_ENABLE | | ||
267 | K2_FCR1_I2S0_CLK_ENABLE_BIT | K2_FCR1_I2S0_ENABLE); | ||
268 | udelay(10); | ||
269 | MACIO_BIC(KEYLARGO_FCR1, K2_FCR1_I2S0_RESET); | ||
270 | UNLOCK(flags); | ||
271 | udelay(10); | ||
272 | |||
273 | return 0; | ||
274 | } | ||
275 | |||
276 | |||
277 | #ifdef CONFIG_SMP | ||
278 | static long g5_reset_cpu(struct device_node* node, long param, long value) | ||
279 | { | ||
280 | unsigned int reset_io = 0; | ||
281 | unsigned long flags; | ||
282 | struct macio_chip* macio; | ||
283 | struct device_node* np; | ||
284 | |||
285 | macio = &macio_chips[0]; | ||
286 | if (macio->type != macio_keylargo2) | ||
287 | return -ENODEV; | ||
288 | |||
289 | np = find_path_device("/cpus"); | ||
290 | if (np == NULL) | ||
291 | return -ENODEV; | ||
292 | for (np = np->child; np != NULL; np = np->sibling) { | ||
293 | u32* num = (u32 *)get_property(np, "reg", NULL); | ||
294 | u32* rst = (u32 *)get_property(np, "soft-reset", NULL); | ||
295 | if (num == NULL || rst == NULL) | ||
296 | continue; | ||
297 | if (param == *num) { | ||
298 | reset_io = *rst; | ||
299 | break; | ||
300 | } | ||
301 | } | ||
302 | if (np == NULL || reset_io == 0) | ||
303 | return -ENODEV; | ||
304 | |||
305 | LOCK(flags); | ||
306 | MACIO_OUT8(reset_io, KEYLARGO_GPIO_OUTPUT_ENABLE); | ||
307 | (void)MACIO_IN8(reset_io); | ||
308 | udelay(1); | ||
309 | MACIO_OUT8(reset_io, 0); | ||
310 | (void)MACIO_IN8(reset_io); | ||
311 | UNLOCK(flags); | ||
312 | |||
313 | return 0; | ||
314 | } | ||
315 | #endif /* CONFIG_SMP */ | ||
316 | |||
317 | /* | ||
318 | * This can be called from pmac_smp so isn't static | ||
319 | * | ||
320 | * This takes the second CPU off the bus on dual CPU machines | ||
321 | * running UP | ||
322 | */ | ||
323 | void g5_phy_disable_cpu1(void) | ||
324 | { | ||
325 | UN_OUT(U3_API_PHY_CONFIG_1, 0); | ||
326 | } | ||
327 | |||
328 | static long generic_get_mb_info(struct device_node* node, long param, long value) | ||
329 | { | ||
330 | switch(param) { | ||
331 | case PMAC_MB_INFO_MODEL: | ||
332 | return pmac_mb.model_id; | ||
333 | case PMAC_MB_INFO_FLAGS: | ||
334 | return pmac_mb.board_flags; | ||
335 | case PMAC_MB_INFO_NAME: | ||
336 | /* hack hack hack... but should work */ | ||
337 | *((const char **)value) = pmac_mb.model_name; | ||
338 | return 0; | ||
339 | } | ||
340 | return -EINVAL; | ||
341 | } | ||
342 | |||
343 | |||
344 | /* | ||
345 | * Table definitions | ||
346 | */ | ||
347 | |||
348 | /* Used on any machine | ||
349 | */ | ||
350 | static struct feature_table_entry any_features[] = { | ||
351 | { PMAC_FTR_GET_MB_INFO, generic_get_mb_info }, | ||
352 | { 0, NULL } | ||
353 | }; | ||
354 | |||
355 | /* G5 features | ||
356 | */ | ||
357 | static struct feature_table_entry g5_features[] = { | ||
358 | { PMAC_FTR_GMAC_ENABLE, g5_gmac_enable }, | ||
359 | { PMAC_FTR_1394_ENABLE, g5_fw_enable }, | ||
360 | { PMAC_FTR_ENABLE_MPIC, g5_mpic_enable }, | ||
361 | { PMAC_FTR_READ_GPIO, g5_read_gpio }, | ||
362 | { PMAC_FTR_WRITE_GPIO, g5_write_gpio }, | ||
363 | { PMAC_FTR_GMAC_PHY_RESET, g5_eth_phy_reset }, | ||
364 | { PMAC_FTR_SOUND_CHIP_ENABLE, g5_i2s_enable }, | ||
365 | #ifdef CONFIG_SMP | ||
366 | { PMAC_FTR_RESET_CPU, g5_reset_cpu }, | ||
367 | #endif /* CONFIG_SMP */ | ||
368 | { 0, NULL } | ||
369 | }; | ||
370 | |||
371 | static struct pmac_mb_def pmac_mb_defs[] = { | ||
372 | { "PowerMac7,2", "PowerMac G5", | ||
373 | PMAC_TYPE_POWERMAC_G5, g5_features, | ||
374 | 0, | ||
375 | }, | ||
376 | { "PowerMac7,3", "PowerMac G5", | ||
377 | PMAC_TYPE_POWERMAC_G5, g5_features, | ||
378 | 0, | ||
379 | }, | ||
380 | { "PowerMac8,1", "iMac G5", | ||
381 | PMAC_TYPE_IMAC_G5, g5_features, | ||
382 | 0, | ||
383 | }, | ||
384 | { "PowerMac9,1", "PowerMac G5", | ||
385 | PMAC_TYPE_POWERMAC_G5_U3L, g5_features, | ||
386 | 0, | ||
387 | }, | ||
388 | { "RackMac3,1", "XServe G5", | ||
389 | PMAC_TYPE_XSERVE_G5, g5_features, | ||
390 | 0, | ||
391 | }, | ||
392 | }; | ||
393 | |||
394 | /* | ||
395 | * The toplevel feature_call callback | ||
396 | */ | ||
397 | long pmac_do_feature_call(unsigned int selector, ...) | ||
398 | { | ||
399 | struct device_node* node; | ||
400 | long param, value; | ||
401 | int i; | ||
402 | feature_call func = NULL; | ||
403 | va_list args; | ||
404 | |||
405 | if (pmac_mb.features) | ||
406 | for (i=0; pmac_mb.features[i].function; i++) | ||
407 | if (pmac_mb.features[i].selector == selector) { | ||
408 | func = pmac_mb.features[i].function; | ||
409 | break; | ||
410 | } | ||
411 | if (!func) | ||
412 | for (i=0; any_features[i].function; i++) | ||
413 | if (any_features[i].selector == selector) { | ||
414 | func = any_features[i].function; | ||
415 | break; | ||
416 | } | ||
417 | if (!func) | ||
418 | return -ENODEV; | ||
419 | |||
420 | va_start(args, selector); | ||
421 | node = (struct device_node*)va_arg(args, void*); | ||
422 | param = va_arg(args, long); | ||
423 | value = va_arg(args, long); | ||
424 | va_end(args); | ||
425 | |||
426 | return func(node, param, value); | ||
427 | } | ||
428 | |||
429 | static int __init probe_motherboard(void) | ||
430 | { | ||
431 | int i; | ||
432 | struct macio_chip* macio = &macio_chips[0]; | ||
433 | const char* model = NULL; | ||
434 | struct device_node *dt; | ||
435 | |||
436 | /* Lookup known motherboard type in device-tree. First try an | ||
437 | * exact match on the "model" property, then try a "compatible" | ||
438 | * match is none is found. | ||
439 | */ | ||
440 | dt = find_devices("device-tree"); | ||
441 | if (dt != NULL) | ||
442 | model = (const char *) get_property(dt, "model", NULL); | ||
443 | for(i=0; model && i<(sizeof(pmac_mb_defs)/sizeof(struct pmac_mb_def)); i++) { | ||
444 | if (strcmp(model, pmac_mb_defs[i].model_string) == 0) { | ||
445 | pmac_mb = pmac_mb_defs[i]; | ||
446 | goto found; | ||
447 | } | ||
448 | } | ||
449 | for(i=0; i<(sizeof(pmac_mb_defs)/sizeof(struct pmac_mb_def)); i++) { | ||
450 | if (machine_is_compatible(pmac_mb_defs[i].model_string)) { | ||
451 | pmac_mb = pmac_mb_defs[i]; | ||
452 | goto found; | ||
453 | } | ||
454 | } | ||
455 | |||
456 | /* Fallback to selection depending on mac-io chip type */ | ||
457 | switch(macio->type) { | ||
458 | case macio_keylargo2: | ||
459 | pmac_mb.model_id = PMAC_TYPE_UNKNOWN_K2; | ||
460 | pmac_mb.model_name = "Unknown K2-based"; | ||
461 | pmac_mb.features = g5_features; | ||
462 | |||
463 | default: | ||
464 | return -ENODEV; | ||
465 | } | ||
466 | found: | ||
467 | /* Check for "mobile" machine */ | ||
468 | if (model && (strncmp(model, "PowerBook", 9) == 0 | ||
469 | || strncmp(model, "iBook", 5) == 0)) | ||
470 | pmac_mb.board_flags |= PMAC_MB_MOBILE; | ||
471 | |||
472 | |||
473 | printk(KERN_INFO "PowerMac motherboard: %s\n", pmac_mb.model_name); | ||
474 | return 0; | ||
475 | } | ||
476 | |||
477 | /* Initialize the Core99 UniNorth host bridge and memory controller | ||
478 | */ | ||
479 | static void __init probe_uninorth(void) | ||
480 | { | ||
481 | uninorth_node = of_find_node_by_name(NULL, "u3"); | ||
482 | if (uninorth_node && uninorth_node->n_addrs > 0) { | ||
483 | /* Small hack until I figure out if parsing in prom.c is correct. I should | ||
484 | * get rid of those pre-parsed junk anyway | ||
485 | */ | ||
486 | unsigned long address = uninorth_node->addrs[0].address; | ||
487 | uninorth_base = ioremap(address, 0x40000); | ||
488 | uninorth_rev = in_be32(UN_REG(UNI_N_VERSION)); | ||
489 | u3_ht = ioremap(address + U3_HT_CONFIG_BASE, 0x1000); | ||
490 | } else | ||
491 | uninorth_node = NULL; | ||
492 | |||
493 | if (!uninorth_node) | ||
494 | return; | ||
495 | |||
496 | printk(KERN_INFO "Found U3 memory controller & host bridge, revision: %d\n", | ||
497 | uninorth_rev); | ||
498 | printk(KERN_INFO "Mapped at 0x%08lx\n", (unsigned long)uninorth_base); | ||
499 | |||
500 | } | ||
501 | |||
502 | static void __init probe_one_macio(const char* name, const char* compat, int type) | ||
503 | { | ||
504 | struct device_node* node; | ||
505 | int i; | ||
506 | volatile u32* base; | ||
507 | u32* revp; | ||
508 | |||
509 | node = find_devices(name); | ||
510 | if (!node || !node->n_addrs) | ||
511 | return; | ||
512 | if (compat) | ||
513 | do { | ||
514 | if (device_is_compatible(node, compat)) | ||
515 | break; | ||
516 | node = node->next; | ||
517 | } while (node); | ||
518 | if (!node) | ||
519 | return; | ||
520 | for(i=0; i<MAX_MACIO_CHIPS; i++) { | ||
521 | if (!macio_chips[i].of_node) | ||
522 | break; | ||
523 | if (macio_chips[i].of_node == node) | ||
524 | return; | ||
525 | } | ||
526 | if (i >= MAX_MACIO_CHIPS) { | ||
527 | printk(KERN_ERR "pmac_feature: Please increase MAX_MACIO_CHIPS !\n"); | ||
528 | printk(KERN_ERR "pmac_feature: %s skipped\n", node->full_name); | ||
529 | return; | ||
530 | } | ||
531 | base = (volatile u32*)ioremap(node->addrs[0].address, node->addrs[0].size); | ||
532 | if (!base) { | ||
533 | printk(KERN_ERR "pmac_feature: Can't map mac-io chip !\n"); | ||
534 | return; | ||
535 | } | ||
536 | if (type == macio_keylargo) { | ||
537 | u32* did = (u32 *)get_property(node, "device-id", NULL); | ||
538 | if (*did == 0x00000025) | ||
539 | type = macio_pangea; | ||
540 | if (*did == 0x0000003e) | ||
541 | type = macio_intrepid; | ||
542 | } | ||
543 | macio_chips[i].of_node = node; | ||
544 | macio_chips[i].type = type; | ||
545 | macio_chips[i].base = base; | ||
546 | macio_chips[i].flags = MACIO_FLAG_SCCB_ON | MACIO_FLAG_SCCB_ON; | ||
547 | macio_chips[i].name = macio_names[type]; | ||
548 | revp = (u32 *)get_property(node, "revision-id", NULL); | ||
549 | if (revp) | ||
550 | macio_chips[i].rev = *revp; | ||
551 | printk(KERN_INFO "Found a %s mac-io controller, rev: %d, mapped at 0x%p\n", | ||
552 | macio_names[type], macio_chips[i].rev, macio_chips[i].base); | ||
553 | } | ||
554 | |||
555 | static int __init | ||
556 | probe_macios(void) | ||
557 | { | ||
558 | probe_one_macio("mac-io", "K2-Keylargo", macio_keylargo2); | ||
559 | |||
560 | macio_chips[0].lbus.index = 0; | ||
561 | macio_chips[1].lbus.index = 1; | ||
562 | |||
563 | return (macio_chips[0].of_node == NULL) ? -ENODEV : 0; | ||
564 | } | ||
565 | |||
566 | static void __init | ||
567 | set_initial_features(void) | ||
568 | { | ||
569 | struct device_node *np; | ||
570 | |||
571 | if (macio_chips[0].type == macio_keylargo2) { | ||
572 | #ifndef CONFIG_SMP | ||
573 | /* On SMP machines running UP, we have the second CPU eating | ||
574 | * bus cycles. We need to take it off the bus. This is done | ||
575 | * from pmac_smp for SMP kernels running on one CPU | ||
576 | */ | ||
577 | np = of_find_node_by_type(NULL, "cpu"); | ||
578 | if (np != NULL) | ||
579 | np = of_find_node_by_type(np, "cpu"); | ||
580 | if (np != NULL) { | ||
581 | g5_phy_disable_cpu1(); | ||
582 | of_node_put(np); | ||
583 | } | ||
584 | #endif /* CONFIG_SMP */ | ||
585 | /* Enable GMAC for now for PCI probing. It will be disabled | ||
586 | * later on after PCI probe | ||
587 | */ | ||
588 | np = of_find_node_by_name(NULL, "ethernet"); | ||
589 | while(np) { | ||
590 | if (device_is_compatible(np, "K2-GMAC")) | ||
591 | g5_gmac_enable(np, 0, 1); | ||
592 | np = of_find_node_by_name(np, "ethernet"); | ||
593 | } | ||
594 | |||
595 | /* Enable FW before PCI probe. Will be disabled later on | ||
596 | * Note: We should have a batter way to check that we are | ||
597 | * dealing with uninorth internal cell and not a PCI cell | ||
598 | * on the external PCI. The code below works though. | ||
599 | */ | ||
600 | np = of_find_node_by_name(NULL, "firewire"); | ||
601 | while(np) { | ||
602 | if (device_is_compatible(np, "pci106b,5811")) { | ||
603 | macio_chips[0].flags |= MACIO_FLAG_FW_SUPPORTED; | ||
604 | g5_fw_enable(np, 0, 1); | ||
605 | } | ||
606 | np = of_find_node_by_name(np, "firewire"); | ||
607 | } | ||
608 | } | ||
609 | } | ||
610 | |||
611 | void __init | ||
612 | pmac_feature_init(void) | ||
613 | { | ||
614 | /* Detect the UniNorth memory controller */ | ||
615 | probe_uninorth(); | ||
616 | |||
617 | /* Probe mac-io controllers */ | ||
618 | if (probe_macios()) { | ||
619 | printk(KERN_WARNING "No mac-io chip found\n"); | ||
620 | return; | ||
621 | } | ||
622 | |||
623 | /* Setup low-level i2c stuffs */ | ||
624 | pmac_init_low_i2c(); | ||
625 | |||
626 | /* Probe machine type */ | ||
627 | if (probe_motherboard()) | ||
628 | printk(KERN_WARNING "Unknown PowerMac !\n"); | ||
629 | |||
630 | /* Set some initial features (turn off some chips that will | ||
631 | * be later turned on) | ||
632 | */ | ||
633 | set_initial_features(); | ||
634 | } | ||
635 | |||
636 | int __init pmac_feature_late_init(void) | ||
637 | { | ||
638 | #if 0 | ||
639 | struct device_node* np; | ||
640 | |||
641 | /* Request some resources late */ | ||
642 | if (uninorth_node) | ||
643 | request_OF_resource(uninorth_node, 0, NULL); | ||
644 | np = find_devices("hammerhead"); | ||
645 | if (np) | ||
646 | request_OF_resource(np, 0, NULL); | ||
647 | np = find_devices("interrupt-controller"); | ||
648 | if (np) | ||
649 | request_OF_resource(np, 0, NULL); | ||
650 | #endif | ||
651 | return 0; | ||
652 | } | ||
653 | |||
654 | device_initcall(pmac_feature_late_init); | ||
655 | |||
656 | #if 0 | ||
657 | static void dump_HT_speeds(char *name, u32 cfg, u32 frq) | ||
658 | { | ||
659 | int freqs[16] = { 200,300,400,500,600,800,1000,0,0,0,0,0,0,0,0,0 }; | ||
660 | int bits[8] = { 8,16,0,32,2,4,0,0 }; | ||
661 | int freq = (frq >> 8) & 0xf; | ||
662 | |||
663 | if (freqs[freq] == 0) | ||
664 | printk("%s: Unknown HT link frequency %x\n", name, freq); | ||
665 | else | ||
666 | printk("%s: %d MHz on main link, (%d in / %d out) bits width\n", | ||
667 | name, freqs[freq], | ||
668 | bits[(cfg >> 28) & 0x7], bits[(cfg >> 24) & 0x7]); | ||
669 | } | ||
670 | #endif | ||
671 | |||
672 | void __init pmac_check_ht_link(void) | ||
673 | { | ||
674 | #if 0 /* Disabled for now */ | ||
675 | u32 ufreq, freq, ucfg, cfg; | ||
676 | struct device_node *pcix_node; | ||
677 | struct pci_dn *pdn; | ||
678 | u8 px_bus, px_devfn; | ||
679 | struct pci_controller *px_hose; | ||
680 | |||
681 | (void)in_be32(u3_ht + U3_HT_LINK_COMMAND); | ||
682 | ucfg = cfg = in_be32(u3_ht + U3_HT_LINK_CONFIG); | ||
683 | ufreq = freq = in_be32(u3_ht + U3_HT_LINK_FREQ); | ||
684 | dump_HT_speeds("U3 HyperTransport", cfg, freq); | ||
685 | |||
686 | pcix_node = of_find_compatible_node(NULL, "pci", "pci-x"); | ||
687 | if (pcix_node == NULL) { | ||
688 | printk("No PCI-X bridge found\n"); | ||
689 | return; | ||
690 | } | ||
691 | pdn = pcix_node->data; | ||
692 | px_hose = pdn->phb; | ||
693 | px_bus = pdn->busno; | ||
694 | px_devfn = pdn->devfn; | ||
695 | |||
696 | early_read_config_dword(px_hose, px_bus, px_devfn, 0xc4, &cfg); | ||
697 | early_read_config_dword(px_hose, px_bus, px_devfn, 0xcc, &freq); | ||
698 | dump_HT_speeds("PCI-X HT Uplink", cfg, freq); | ||
699 | early_read_config_dword(px_hose, px_bus, px_devfn, 0xc8, &cfg); | ||
700 | early_read_config_dword(px_hose, px_bus, px_devfn, 0xd0, &freq); | ||
701 | dump_HT_speeds("PCI-X HT Downlink", cfg, freq); | ||
702 | #endif | ||
703 | } | ||
704 | |||
705 | /* | ||
706 | * Early video resume hook | ||
707 | */ | ||
708 | |||
709 | static void (*pmac_early_vresume_proc)(void *data); | ||
710 | static void *pmac_early_vresume_data; | ||
711 | |||
712 | void pmac_set_early_video_resume(void (*proc)(void *data), void *data) | ||
713 | { | ||
714 | if (_machine != _MACH_Pmac) | ||
715 | return; | ||
716 | preempt_disable(); | ||
717 | pmac_early_vresume_proc = proc; | ||
718 | pmac_early_vresume_data = data; | ||
719 | preempt_enable(); | ||
720 | } | ||
721 | EXPORT_SYMBOL(pmac_set_early_video_resume); | ||
722 | |||
723 | |||
724 | /* | ||
725 | * AGP related suspend/resume code | ||
726 | */ | ||
727 | |||
728 | static struct pci_dev *pmac_agp_bridge; | ||
729 | static int (*pmac_agp_suspend)(struct pci_dev *bridge); | ||
730 | static int (*pmac_agp_resume)(struct pci_dev *bridge); | ||
731 | |||
732 | void pmac_register_agp_pm(struct pci_dev *bridge, | ||
733 | int (*suspend)(struct pci_dev *bridge), | ||
734 | int (*resume)(struct pci_dev *bridge)) | ||
735 | { | ||
736 | if (suspend || resume) { | ||
737 | pmac_agp_bridge = bridge; | ||
738 | pmac_agp_suspend = suspend; | ||
739 | pmac_agp_resume = resume; | ||
740 | return; | ||
741 | } | ||
742 | if (bridge != pmac_agp_bridge) | ||
743 | return; | ||
744 | pmac_agp_suspend = pmac_agp_resume = NULL; | ||
745 | return; | ||
746 | } | ||
747 | EXPORT_SYMBOL(pmac_register_agp_pm); | ||
748 | |||
749 | void pmac_suspend_agp_for_card(struct pci_dev *dev) | ||
750 | { | ||
751 | if (pmac_agp_bridge == NULL || pmac_agp_suspend == NULL) | ||
752 | return; | ||
753 | if (pmac_agp_bridge->bus != dev->bus) | ||
754 | return; | ||
755 | pmac_agp_suspend(pmac_agp_bridge); | ||
756 | } | ||
757 | EXPORT_SYMBOL(pmac_suspend_agp_for_card); | ||
758 | |||
759 | void pmac_resume_agp_for_card(struct pci_dev *dev) | ||
760 | { | ||
761 | if (pmac_agp_bridge == NULL || pmac_agp_resume == NULL) | ||
762 | return; | ||
763 | if (pmac_agp_bridge->bus != dev->bus) | ||
764 | return; | ||
765 | pmac_agp_resume(pmac_agp_bridge); | ||
766 | } | ||
767 | EXPORT_SYMBOL(pmac_resume_agp_for_card); | ||
diff --git a/arch/ppc64/kernel/pmac_low_i2c.c b/arch/ppc64/kernel/pmac_low_i2c.c deleted file mode 100644 index f3f39e8e337a..000000000000 --- a/arch/ppc64/kernel/pmac_low_i2c.c +++ /dev/null | |||
@@ -1,523 +0,0 @@ | |||
1 | /* | ||
2 | * arch/ppc/platforms/pmac_low_i2c.c | ||
3 | * | ||
4 | * Copyright (C) 2003 Ben. Herrenschmidt (benh@kernel.crashing.org) | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of the GNU General Public License | ||
8 | * as published by the Free Software Foundation; either version | ||
9 | * 2 of the License, or (at your option) any later version. | ||
10 | * | ||
11 | * This file contains some low-level i2c access routines that | ||
12 | * need to be used by various bits of the PowerMac platform code | ||
13 | * at times where the real asynchronous & interrupt driven driver | ||
14 | * cannot be used. The API borrows some semantics from the darwin | ||
15 | * driver in order to ease the implementation of the platform | ||
16 | * properties parser | ||
17 | */ | ||
18 | |||
19 | #undef DEBUG | ||
20 | |||
21 | #include <linux/config.h> | ||
22 | #include <linux/types.h> | ||
23 | #include <linux/sched.h> | ||
24 | #include <linux/init.h> | ||
25 | #include <linux/module.h> | ||
26 | #include <linux/adb.h> | ||
27 | #include <linux/pmu.h> | ||
28 | #include <asm/keylargo.h> | ||
29 | #include <asm/uninorth.h> | ||
30 | #include <asm/io.h> | ||
31 | #include <asm/prom.h> | ||
32 | #include <asm/machdep.h> | ||
33 | #include <asm/pmac_low_i2c.h> | ||
34 | |||
35 | #define MAX_LOW_I2C_HOST 4 | ||
36 | |||
37 | #ifdef DEBUG | ||
38 | #define DBG(x...) do {\ | ||
39 | printk(KERN_DEBUG "KW:" x); \ | ||
40 | } while(0) | ||
41 | #else | ||
42 | #define DBG(x...) | ||
43 | #endif | ||
44 | |||
45 | struct low_i2c_host; | ||
46 | |||
47 | typedef int (*low_i2c_func_t)(struct low_i2c_host *host, u8 addr, u8 sub, u8 *data, int len); | ||
48 | |||
49 | struct low_i2c_host | ||
50 | { | ||
51 | struct device_node *np; /* OF device node */ | ||
52 | struct semaphore mutex; /* Access mutex for use by i2c-keywest */ | ||
53 | low_i2c_func_t func; /* Access function */ | ||
54 | unsigned int is_open : 1; /* Poor man's access control */ | ||
55 | int mode; /* Current mode */ | ||
56 | int channel; /* Current channel */ | ||
57 | int num_channels; /* Number of channels */ | ||
58 | void __iomem *base; /* For keywest-i2c, base address */ | ||
59 | int bsteps; /* And register stepping */ | ||
60 | int speed; /* And speed */ | ||
61 | }; | ||
62 | |||
63 | static struct low_i2c_host low_i2c_hosts[MAX_LOW_I2C_HOST]; | ||
64 | |||
65 | /* No locking is necessary on allocation, we are running way before | ||
66 | * anything can race with us | ||
67 | */ | ||
68 | static struct low_i2c_host *find_low_i2c_host(struct device_node *np) | ||
69 | { | ||
70 | int i; | ||
71 | |||
72 | for (i = 0; i < MAX_LOW_I2C_HOST; i++) | ||
73 | if (low_i2c_hosts[i].np == np) | ||
74 | return &low_i2c_hosts[i]; | ||
75 | return NULL; | ||
76 | } | ||
77 | |||
78 | /* | ||
79 | * | ||
80 | * i2c-keywest implementation (UniNorth, U2, U3, Keylargo's) | ||
81 | * | ||
82 | */ | ||
83 | |||
84 | /* | ||
85 | * Keywest i2c definitions borrowed from drivers/i2c/i2c-keywest.h, | ||
86 | * should be moved somewhere in include/asm-ppc/ | ||
87 | */ | ||
88 | /* Register indices */ | ||
89 | typedef enum { | ||
90 | reg_mode = 0, | ||
91 | reg_control, | ||
92 | reg_status, | ||
93 | reg_isr, | ||
94 | reg_ier, | ||
95 | reg_addr, | ||
96 | reg_subaddr, | ||
97 | reg_data | ||
98 | } reg_t; | ||
99 | |||
100 | |||
101 | /* Mode register */ | ||
102 | #define KW_I2C_MODE_100KHZ 0x00 | ||
103 | #define KW_I2C_MODE_50KHZ 0x01 | ||
104 | #define KW_I2C_MODE_25KHZ 0x02 | ||
105 | #define KW_I2C_MODE_DUMB 0x00 | ||
106 | #define KW_I2C_MODE_STANDARD 0x04 | ||
107 | #define KW_I2C_MODE_STANDARDSUB 0x08 | ||
108 | #define KW_I2C_MODE_COMBINED 0x0C | ||
109 | #define KW_I2C_MODE_MODE_MASK 0x0C | ||
110 | #define KW_I2C_MODE_CHAN_MASK 0xF0 | ||
111 | |||
112 | /* Control register */ | ||
113 | #define KW_I2C_CTL_AAK 0x01 | ||
114 | #define KW_I2C_CTL_XADDR 0x02 | ||
115 | #define KW_I2C_CTL_STOP 0x04 | ||
116 | #define KW_I2C_CTL_START 0x08 | ||
117 | |||
118 | /* Status register */ | ||
119 | #define KW_I2C_STAT_BUSY 0x01 | ||
120 | #define KW_I2C_STAT_LAST_AAK 0x02 | ||
121 | #define KW_I2C_STAT_LAST_RW 0x04 | ||
122 | #define KW_I2C_STAT_SDA 0x08 | ||
123 | #define KW_I2C_STAT_SCL 0x10 | ||
124 | |||
125 | /* IER & ISR registers */ | ||
126 | #define KW_I2C_IRQ_DATA 0x01 | ||
127 | #define KW_I2C_IRQ_ADDR 0x02 | ||
128 | #define KW_I2C_IRQ_STOP 0x04 | ||
129 | #define KW_I2C_IRQ_START 0x08 | ||
130 | #define KW_I2C_IRQ_MASK 0x0F | ||
131 | |||
132 | /* State machine states */ | ||
133 | enum { | ||
134 | state_idle, | ||
135 | state_addr, | ||
136 | state_read, | ||
137 | state_write, | ||
138 | state_stop, | ||
139 | state_dead | ||
140 | }; | ||
141 | |||
142 | #define WRONG_STATE(name) do {\ | ||
143 | printk(KERN_DEBUG "KW: wrong state. Got %s, state: %s (isr: %02x)\n", \ | ||
144 | name, __kw_state_names[state], isr); \ | ||
145 | } while(0) | ||
146 | |||
147 | static const char *__kw_state_names[] = { | ||
148 | "state_idle", | ||
149 | "state_addr", | ||
150 | "state_read", | ||
151 | "state_write", | ||
152 | "state_stop", | ||
153 | "state_dead" | ||
154 | }; | ||
155 | |||
156 | static inline u8 __kw_read_reg(struct low_i2c_host *host, reg_t reg) | ||
157 | { | ||
158 | return readb(host->base + (((unsigned int)reg) << host->bsteps)); | ||
159 | } | ||
160 | |||
161 | static inline void __kw_write_reg(struct low_i2c_host *host, reg_t reg, u8 val) | ||
162 | { | ||
163 | writeb(val, host->base + (((unsigned)reg) << host->bsteps)); | ||
164 | (void)__kw_read_reg(host, reg_subaddr); | ||
165 | } | ||
166 | |||
167 | #define kw_write_reg(reg, val) __kw_write_reg(host, reg, val) | ||
168 | #define kw_read_reg(reg) __kw_read_reg(host, reg) | ||
169 | |||
170 | |||
171 | /* Don't schedule, the g5 fan controller is too | ||
172 | * timing sensitive | ||
173 | */ | ||
174 | static u8 kw_wait_interrupt(struct low_i2c_host* host) | ||
175 | { | ||
176 | int i, j; | ||
177 | u8 isr; | ||
178 | |||
179 | for (i = 0; i < 100000; i++) { | ||
180 | isr = kw_read_reg(reg_isr) & KW_I2C_IRQ_MASK; | ||
181 | if (isr != 0) | ||
182 | return isr; | ||
183 | |||
184 | /* This code is used with the timebase frozen, we cannot rely | ||
185 | * on udelay ! For now, just use a bogus loop | ||
186 | */ | ||
187 | for (j = 1; j < 10000; j++) | ||
188 | mb(); | ||
189 | } | ||
190 | return isr; | ||
191 | } | ||
192 | |||
193 | static int kw_handle_interrupt(struct low_i2c_host *host, int state, int rw, int *rc, u8 **data, int *len, u8 isr) | ||
194 | { | ||
195 | u8 ack; | ||
196 | |||
197 | DBG("kw_handle_interrupt(%s, isr: %x)\n", __kw_state_names[state], isr); | ||
198 | |||
199 | if (isr == 0) { | ||
200 | if (state != state_stop) { | ||
201 | DBG("KW: Timeout !\n"); | ||
202 | *rc = -EIO; | ||
203 | goto stop; | ||
204 | } | ||
205 | if (state == state_stop) { | ||
206 | ack = kw_read_reg(reg_status); | ||
207 | if (!(ack & KW_I2C_STAT_BUSY)) { | ||
208 | state = state_idle; | ||
209 | kw_write_reg(reg_ier, 0x00); | ||
210 | } | ||
211 | } | ||
212 | return state; | ||
213 | } | ||
214 | |||
215 | if (isr & KW_I2C_IRQ_ADDR) { | ||
216 | ack = kw_read_reg(reg_status); | ||
217 | if (state != state_addr) { | ||
218 | kw_write_reg(reg_isr, KW_I2C_IRQ_ADDR); | ||
219 | WRONG_STATE("KW_I2C_IRQ_ADDR"); | ||
220 | *rc = -EIO; | ||
221 | goto stop; | ||
222 | } | ||
223 | if ((ack & KW_I2C_STAT_LAST_AAK) == 0) { | ||
224 | *rc = -ENODEV; | ||
225 | DBG("KW: NAK on address\n"); | ||
226 | return state_stop; | ||
227 | } else { | ||
228 | if (rw) { | ||
229 | state = state_read; | ||
230 | if (*len > 1) | ||
231 | kw_write_reg(reg_control, KW_I2C_CTL_AAK); | ||
232 | } else { | ||
233 | state = state_write; | ||
234 | kw_write_reg(reg_data, **data); | ||
235 | (*data)++; (*len)--; | ||
236 | } | ||
237 | } | ||
238 | kw_write_reg(reg_isr, KW_I2C_IRQ_ADDR); | ||
239 | } | ||
240 | |||
241 | if (isr & KW_I2C_IRQ_DATA) { | ||
242 | if (state == state_read) { | ||
243 | **data = kw_read_reg(reg_data); | ||
244 | (*data)++; (*len)--; | ||
245 | kw_write_reg(reg_isr, KW_I2C_IRQ_DATA); | ||
246 | if ((*len) == 0) | ||
247 | state = state_stop; | ||
248 | else if ((*len) == 1) | ||
249 | kw_write_reg(reg_control, 0); | ||
250 | } else if (state == state_write) { | ||
251 | ack = kw_read_reg(reg_status); | ||
252 | if ((ack & KW_I2C_STAT_LAST_AAK) == 0) { | ||
253 | DBG("KW: nack on data write\n"); | ||
254 | *rc = -EIO; | ||
255 | goto stop; | ||
256 | } else if (*len) { | ||
257 | kw_write_reg(reg_data, **data); | ||
258 | (*data)++; (*len)--; | ||
259 | } else { | ||
260 | kw_write_reg(reg_control, KW_I2C_CTL_STOP); | ||
261 | state = state_stop; | ||
262 | *rc = 0; | ||
263 | } | ||
264 | kw_write_reg(reg_isr, KW_I2C_IRQ_DATA); | ||
265 | } else { | ||
266 | kw_write_reg(reg_isr, KW_I2C_IRQ_DATA); | ||
267 | WRONG_STATE("KW_I2C_IRQ_DATA"); | ||
268 | if (state != state_stop) { | ||
269 | *rc = -EIO; | ||
270 | goto stop; | ||
271 | } | ||
272 | } | ||
273 | } | ||
274 | |||
275 | if (isr & KW_I2C_IRQ_STOP) { | ||
276 | kw_write_reg(reg_isr, KW_I2C_IRQ_STOP); | ||
277 | if (state != state_stop) { | ||
278 | WRONG_STATE("KW_I2C_IRQ_STOP"); | ||
279 | *rc = -EIO; | ||
280 | } | ||
281 | return state_idle; | ||
282 | } | ||
283 | |||
284 | if (isr & KW_I2C_IRQ_START) | ||
285 | kw_write_reg(reg_isr, KW_I2C_IRQ_START); | ||
286 | |||
287 | return state; | ||
288 | |||
289 | stop: | ||
290 | kw_write_reg(reg_control, KW_I2C_CTL_STOP); | ||
291 | return state_stop; | ||
292 | } | ||
293 | |||
294 | static int keywest_low_i2c_func(struct low_i2c_host *host, u8 addr, u8 subaddr, u8 *data, int len) | ||
295 | { | ||
296 | u8 mode_reg = host->speed; | ||
297 | int state = state_addr; | ||
298 | int rc = 0; | ||
299 | |||
300 | /* Setup mode & subaddress if any */ | ||
301 | switch(host->mode) { | ||
302 | case pmac_low_i2c_mode_dumb: | ||
303 | printk(KERN_ERR "low_i2c: Dumb mode not supported !\n"); | ||
304 | return -EINVAL; | ||
305 | case pmac_low_i2c_mode_std: | ||
306 | mode_reg |= KW_I2C_MODE_STANDARD; | ||
307 | break; | ||
308 | case pmac_low_i2c_mode_stdsub: | ||
309 | mode_reg |= KW_I2C_MODE_STANDARDSUB; | ||
310 | break; | ||
311 | case pmac_low_i2c_mode_combined: | ||
312 | mode_reg |= KW_I2C_MODE_COMBINED; | ||
313 | break; | ||
314 | } | ||
315 | |||
316 | /* Setup channel & clear pending irqs */ | ||
317 | kw_write_reg(reg_isr, kw_read_reg(reg_isr)); | ||
318 | kw_write_reg(reg_mode, mode_reg | (host->channel << 4)); | ||
319 | kw_write_reg(reg_status, 0); | ||
320 | |||
321 | /* Set up address and r/w bit */ | ||
322 | kw_write_reg(reg_addr, addr); | ||
323 | |||
324 | /* Set up the sub address */ | ||
325 | if ((mode_reg & KW_I2C_MODE_MODE_MASK) == KW_I2C_MODE_STANDARDSUB | ||
326 | || (mode_reg & KW_I2C_MODE_MODE_MASK) == KW_I2C_MODE_COMBINED) | ||
327 | kw_write_reg(reg_subaddr, subaddr); | ||
328 | |||
329 | /* Start sending address & disable interrupt*/ | ||
330 | kw_write_reg(reg_ier, 0 /*KW_I2C_IRQ_MASK*/); | ||
331 | kw_write_reg(reg_control, KW_I2C_CTL_XADDR); | ||
332 | |||
333 | /* State machine, to turn into an interrupt handler */ | ||
334 | while(state != state_idle) { | ||
335 | u8 isr = kw_wait_interrupt(host); | ||
336 | state = kw_handle_interrupt(host, state, addr & 1, &rc, &data, &len, isr); | ||
337 | } | ||
338 | |||
339 | return rc; | ||
340 | } | ||
341 | |||
342 | static void keywest_low_i2c_add(struct device_node *np) | ||
343 | { | ||
344 | struct low_i2c_host *host = find_low_i2c_host(NULL); | ||
345 | u32 *psteps, *prate, steps, aoffset = 0; | ||
346 | struct device_node *parent; | ||
347 | |||
348 | if (host == NULL) { | ||
349 | printk(KERN_ERR "low_i2c: Can't allocate host for %s\n", | ||
350 | np->full_name); | ||
351 | return; | ||
352 | } | ||
353 | memset(host, 0, sizeof(*host)); | ||
354 | |||
355 | init_MUTEX(&host->mutex); | ||
356 | host->np = of_node_get(np); | ||
357 | psteps = (u32 *)get_property(np, "AAPL,address-step", NULL); | ||
358 | steps = psteps ? (*psteps) : 0x10; | ||
359 | for (host->bsteps = 0; (steps & 0x01) == 0; host->bsteps++) | ||
360 | steps >>= 1; | ||
361 | parent = of_get_parent(np); | ||
362 | host->num_channels = 1; | ||
363 | if (parent && parent->name[0] == 'u') { | ||
364 | host->num_channels = 2; | ||
365 | aoffset = 3; | ||
366 | } | ||
367 | /* Select interface rate */ | ||
368 | host->speed = KW_I2C_MODE_100KHZ; | ||
369 | prate = (u32 *)get_property(np, "AAPL,i2c-rate", NULL); | ||
370 | if (prate) switch(*prate) { | ||
371 | case 100: | ||
372 | host->speed = KW_I2C_MODE_100KHZ; | ||
373 | break; | ||
374 | case 50: | ||
375 | host->speed = KW_I2C_MODE_50KHZ; | ||
376 | break; | ||
377 | case 25: | ||
378 | host->speed = KW_I2C_MODE_25KHZ; | ||
379 | break; | ||
380 | } | ||
381 | |||
382 | host->mode = pmac_low_i2c_mode_std; | ||
383 | host->base = ioremap(np->addrs[0].address + aoffset, | ||
384 | np->addrs[0].size); | ||
385 | host->func = keywest_low_i2c_func; | ||
386 | } | ||
387 | |||
388 | /* | ||
389 | * | ||
390 | * PMU implementation | ||
391 | * | ||
392 | */ | ||
393 | |||
394 | |||
395 | #ifdef CONFIG_ADB_PMU | ||
396 | |||
397 | static int pmu_low_i2c_func(struct low_i2c_host *host, u8 addr, u8 sub, u8 *data, int len) | ||
398 | { | ||
399 | // TODO | ||
400 | return -ENODEV; | ||
401 | } | ||
402 | |||
403 | static void pmu_low_i2c_add(struct device_node *np) | ||
404 | { | ||
405 | struct low_i2c_host *host = find_low_i2c_host(NULL); | ||
406 | |||
407 | if (host == NULL) { | ||
408 | printk(KERN_ERR "low_i2c: Can't allocate host for %s\n", | ||
409 | np->full_name); | ||
410 | return; | ||
411 | } | ||
412 | memset(host, 0, sizeof(*host)); | ||
413 | |||
414 | init_MUTEX(&host->mutex); | ||
415 | host->np = of_node_get(np); | ||
416 | host->num_channels = 3; | ||
417 | host->mode = pmac_low_i2c_mode_std; | ||
418 | host->func = pmu_low_i2c_func; | ||
419 | } | ||
420 | |||
421 | #endif /* CONFIG_ADB_PMU */ | ||
422 | |||
423 | void __init pmac_init_low_i2c(void) | ||
424 | { | ||
425 | struct device_node *np; | ||
426 | |||
427 | /* Probe keywest-i2c busses */ | ||
428 | np = of_find_compatible_node(NULL, "i2c", "keywest-i2c"); | ||
429 | while(np) { | ||
430 | keywest_low_i2c_add(np); | ||
431 | np = of_find_compatible_node(np, "i2c", "keywest-i2c"); | ||
432 | } | ||
433 | |||
434 | #ifdef CONFIG_ADB_PMU | ||
435 | /* Probe PMU busses */ | ||
436 | np = of_find_node_by_name(NULL, "via-pmu"); | ||
437 | if (np) | ||
438 | pmu_low_i2c_add(np); | ||
439 | #endif /* CONFIG_ADB_PMU */ | ||
440 | |||
441 | /* TODO: Add CUDA support as well */ | ||
442 | } | ||
443 | |||
444 | int pmac_low_i2c_lock(struct device_node *np) | ||
445 | { | ||
446 | struct low_i2c_host *host = find_low_i2c_host(np); | ||
447 | |||
448 | if (!host) | ||
449 | return -ENODEV; | ||
450 | down(&host->mutex); | ||
451 | return 0; | ||
452 | } | ||
453 | EXPORT_SYMBOL(pmac_low_i2c_lock); | ||
454 | |||
455 | int pmac_low_i2c_unlock(struct device_node *np) | ||
456 | { | ||
457 | struct low_i2c_host *host = find_low_i2c_host(np); | ||
458 | |||
459 | if (!host) | ||
460 | return -ENODEV; | ||
461 | up(&host->mutex); | ||
462 | return 0; | ||
463 | } | ||
464 | EXPORT_SYMBOL(pmac_low_i2c_unlock); | ||
465 | |||
466 | |||
467 | int pmac_low_i2c_open(struct device_node *np, int channel) | ||
468 | { | ||
469 | struct low_i2c_host *host = find_low_i2c_host(np); | ||
470 | |||
471 | if (!host) | ||
472 | return -ENODEV; | ||
473 | |||
474 | if (channel >= host->num_channels) | ||
475 | return -EINVAL; | ||
476 | |||
477 | down(&host->mutex); | ||
478 | host->is_open = 1; | ||
479 | host->channel = channel; | ||
480 | |||
481 | return 0; | ||
482 | } | ||
483 | EXPORT_SYMBOL(pmac_low_i2c_open); | ||
484 | |||
485 | int pmac_low_i2c_close(struct device_node *np) | ||
486 | { | ||
487 | struct low_i2c_host *host = find_low_i2c_host(np); | ||
488 | |||
489 | if (!host) | ||
490 | return -ENODEV; | ||
491 | |||
492 | host->is_open = 0; | ||
493 | up(&host->mutex); | ||
494 | |||
495 | return 0; | ||
496 | } | ||
497 | EXPORT_SYMBOL(pmac_low_i2c_close); | ||
498 | |||
499 | int pmac_low_i2c_setmode(struct device_node *np, int mode) | ||
500 | { | ||
501 | struct low_i2c_host *host = find_low_i2c_host(np); | ||
502 | |||
503 | if (!host) | ||
504 | return -ENODEV; | ||
505 | WARN_ON(!host->is_open); | ||
506 | host->mode = mode; | ||
507 | |||
508 | return 0; | ||
509 | } | ||
510 | EXPORT_SYMBOL(pmac_low_i2c_setmode); | ||
511 | |||
512 | int pmac_low_i2c_xfer(struct device_node *np, u8 addrdir, u8 subaddr, u8 *data, int len) | ||
513 | { | ||
514 | struct low_i2c_host *host = find_low_i2c_host(np); | ||
515 | |||
516 | if (!host) | ||
517 | return -ENODEV; | ||
518 | WARN_ON(!host->is_open); | ||
519 | |||
520 | return host->func(host, addrdir, subaddr, data, len); | ||
521 | } | ||
522 | EXPORT_SYMBOL(pmac_low_i2c_xfer); | ||
523 | |||
diff --git a/arch/ppc64/kernel/pmac_nvram.c b/arch/ppc64/kernel/pmac_nvram.c deleted file mode 100644 index 5fe9785ad7d8..000000000000 --- a/arch/ppc64/kernel/pmac_nvram.c +++ /dev/null | |||
@@ -1,493 +0,0 @@ | |||
1 | /* | ||
2 | * arch/ppc/platforms/pmac_nvram.c | ||
3 | * | ||
4 | * Copyright (C) 2002 Benjamin Herrenschmidt (benh@kernel.crashing.org) | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of the GNU General Public License | ||
8 | * as published by the Free Software Foundation; either version | ||
9 | * 2 of the License, or (at your option) any later version. | ||
10 | * | ||
11 | * Todo: - add support for the OF persistent properties | ||
12 | */ | ||
13 | #include <linux/config.h> | ||
14 | #include <linux/module.h> | ||
15 | #include <linux/kernel.h> | ||
16 | #include <linux/stddef.h> | ||
17 | #include <linux/string.h> | ||
18 | #include <linux/init.h> | ||
19 | #include <linux/slab.h> | ||
20 | #include <linux/delay.h> | ||
21 | #include <linux/errno.h> | ||
22 | #include <linux/bootmem.h> | ||
23 | #include <linux/completion.h> | ||
24 | #include <linux/spinlock.h> | ||
25 | #include <asm/sections.h> | ||
26 | #include <asm/io.h> | ||
27 | #include <asm/system.h> | ||
28 | #include <asm/prom.h> | ||
29 | #include <asm/machdep.h> | ||
30 | #include <asm/nvram.h> | ||
31 | |||
32 | #define DEBUG | ||
33 | |||
34 | #ifdef DEBUG | ||
35 | #define DBG(x...) printk(x) | ||
36 | #else | ||
37 | #define DBG(x...) | ||
38 | #endif | ||
39 | |||
40 | #define NVRAM_SIZE 0x2000 /* 8kB of non-volatile RAM */ | ||
41 | |||
42 | #define CORE99_SIGNATURE 0x5a | ||
43 | #define CORE99_ADLER_START 0x14 | ||
44 | |||
45 | /* On Core99, nvram is either a sharp, a micron or an AMD flash */ | ||
46 | #define SM_FLASH_STATUS_DONE 0x80 | ||
47 | #define SM_FLASH_STATUS_ERR 0x38 | ||
48 | |||
49 | #define SM_FLASH_CMD_ERASE_CONFIRM 0xd0 | ||
50 | #define SM_FLASH_CMD_ERASE_SETUP 0x20 | ||
51 | #define SM_FLASH_CMD_RESET 0xff | ||
52 | #define SM_FLASH_CMD_WRITE_SETUP 0x40 | ||
53 | #define SM_FLASH_CMD_CLEAR_STATUS 0x50 | ||
54 | #define SM_FLASH_CMD_READ_STATUS 0x70 | ||
55 | |||
56 | /* CHRP NVRAM header */ | ||
57 | struct chrp_header { | ||
58 | u8 signature; | ||
59 | u8 cksum; | ||
60 | u16 len; | ||
61 | char name[12]; | ||
62 | u8 data[0]; | ||
63 | }; | ||
64 | |||
65 | struct core99_header { | ||
66 | struct chrp_header hdr; | ||
67 | u32 adler; | ||
68 | u32 generation; | ||
69 | u32 reserved[2]; | ||
70 | }; | ||
71 | |||
72 | /* | ||
73 | * Read and write the non-volatile RAM on PowerMacs and CHRP machines. | ||
74 | */ | ||
75 | static volatile unsigned char *nvram_data; | ||
76 | static int core99_bank = 0; | ||
77 | // XXX Turn that into a sem | ||
78 | static DEFINE_SPINLOCK(nv_lock); | ||
79 | |||
80 | extern int system_running; | ||
81 | |||
82 | static int (*core99_write_bank)(int bank, u8* datas); | ||
83 | static int (*core99_erase_bank)(int bank); | ||
84 | |||
85 | static char *nvram_image; | ||
86 | |||
87 | |||
88 | static ssize_t core99_nvram_read(char *buf, size_t count, loff_t *index) | ||
89 | { | ||
90 | int i; | ||
91 | |||
92 | if (nvram_image == NULL) | ||
93 | return -ENODEV; | ||
94 | if (*index > NVRAM_SIZE) | ||
95 | return 0; | ||
96 | |||
97 | i = *index; | ||
98 | if (i + count > NVRAM_SIZE) | ||
99 | count = NVRAM_SIZE - i; | ||
100 | |||
101 | memcpy(buf, &nvram_image[i], count); | ||
102 | *index = i + count; | ||
103 | return count; | ||
104 | } | ||
105 | |||
106 | static ssize_t core99_nvram_write(char *buf, size_t count, loff_t *index) | ||
107 | { | ||
108 | int i; | ||
109 | |||
110 | if (nvram_image == NULL) | ||
111 | return -ENODEV; | ||
112 | if (*index > NVRAM_SIZE) | ||
113 | return 0; | ||
114 | |||
115 | i = *index; | ||
116 | if (i + count > NVRAM_SIZE) | ||
117 | count = NVRAM_SIZE - i; | ||
118 | |||
119 | memcpy(&nvram_image[i], buf, count); | ||
120 | *index = i + count; | ||
121 | return count; | ||
122 | } | ||
123 | |||
124 | static ssize_t core99_nvram_size(void) | ||
125 | { | ||
126 | if (nvram_image == NULL) | ||
127 | return -ENODEV; | ||
128 | return NVRAM_SIZE; | ||
129 | } | ||
130 | |||
131 | static u8 chrp_checksum(struct chrp_header* hdr) | ||
132 | { | ||
133 | u8 *ptr; | ||
134 | u16 sum = hdr->signature; | ||
135 | for (ptr = (u8 *)&hdr->len; ptr < hdr->data; ptr++) | ||
136 | sum += *ptr; | ||
137 | while (sum > 0xFF) | ||
138 | sum = (sum & 0xFF) + (sum>>8); | ||
139 | return sum; | ||
140 | } | ||
141 | |||
142 | static u32 core99_calc_adler(u8 *buffer) | ||
143 | { | ||
144 | int cnt; | ||
145 | u32 low, high; | ||
146 | |||
147 | buffer += CORE99_ADLER_START; | ||
148 | low = 1; | ||
149 | high = 0; | ||
150 | for (cnt=0; cnt<(NVRAM_SIZE-CORE99_ADLER_START); cnt++) { | ||
151 | if ((cnt % 5000) == 0) { | ||
152 | high %= 65521UL; | ||
153 | high %= 65521UL; | ||
154 | } | ||
155 | low += buffer[cnt]; | ||
156 | high += low; | ||
157 | } | ||
158 | low %= 65521UL; | ||
159 | high %= 65521UL; | ||
160 | |||
161 | return (high << 16) | low; | ||
162 | } | ||
163 | |||
164 | static u32 core99_check(u8* datas) | ||
165 | { | ||
166 | struct core99_header* hdr99 = (struct core99_header*)datas; | ||
167 | |||
168 | if (hdr99->hdr.signature != CORE99_SIGNATURE) { | ||
169 | DBG("Invalid signature\n"); | ||
170 | return 0; | ||
171 | } | ||
172 | if (hdr99->hdr.cksum != chrp_checksum(&hdr99->hdr)) { | ||
173 | DBG("Invalid checksum\n"); | ||
174 | return 0; | ||
175 | } | ||
176 | if (hdr99->adler != core99_calc_adler(datas)) { | ||
177 | DBG("Invalid adler\n"); | ||
178 | return 0; | ||
179 | } | ||
180 | return hdr99->generation; | ||
181 | } | ||
182 | |||
183 | static int sm_erase_bank(int bank) | ||
184 | { | ||
185 | int stat, i; | ||
186 | unsigned long timeout; | ||
187 | |||
188 | u8* base = (u8 *)nvram_data + core99_bank*NVRAM_SIZE; | ||
189 | |||
190 | DBG("nvram: Sharp/Micron Erasing bank %d...\n", bank); | ||
191 | |||
192 | out_8(base, SM_FLASH_CMD_ERASE_SETUP); | ||
193 | out_8(base, SM_FLASH_CMD_ERASE_CONFIRM); | ||
194 | timeout = 0; | ||
195 | do { | ||
196 | if (++timeout > 1000000) { | ||
197 | printk(KERN_ERR "nvram: Sharp/Miron flash erase timeout !\n"); | ||
198 | break; | ||
199 | } | ||
200 | out_8(base, SM_FLASH_CMD_READ_STATUS); | ||
201 | stat = in_8(base); | ||
202 | } while (!(stat & SM_FLASH_STATUS_DONE)); | ||
203 | |||
204 | out_8(base, SM_FLASH_CMD_CLEAR_STATUS); | ||
205 | out_8(base, SM_FLASH_CMD_RESET); | ||
206 | |||
207 | for (i=0; i<NVRAM_SIZE; i++) | ||
208 | if (base[i] != 0xff) { | ||
209 | printk(KERN_ERR "nvram: Sharp/Micron flash erase failed !\n"); | ||
210 | return -ENXIO; | ||
211 | } | ||
212 | return 0; | ||
213 | } | ||
214 | |||
215 | static int sm_write_bank(int bank, u8* datas) | ||
216 | { | ||
217 | int i, stat = 0; | ||
218 | unsigned long timeout; | ||
219 | |||
220 | u8* base = (u8 *)nvram_data + core99_bank*NVRAM_SIZE; | ||
221 | |||
222 | DBG("nvram: Sharp/Micron Writing bank %d...\n", bank); | ||
223 | |||
224 | for (i=0; i<NVRAM_SIZE; i++) { | ||
225 | out_8(base+i, SM_FLASH_CMD_WRITE_SETUP); | ||
226 | udelay(1); | ||
227 | out_8(base+i, datas[i]); | ||
228 | timeout = 0; | ||
229 | do { | ||
230 | if (++timeout > 1000000) { | ||
231 | printk(KERN_ERR "nvram: Sharp/Micron flash write timeout !\n"); | ||
232 | break; | ||
233 | } | ||
234 | out_8(base, SM_FLASH_CMD_READ_STATUS); | ||
235 | stat = in_8(base); | ||
236 | } while (!(stat & SM_FLASH_STATUS_DONE)); | ||
237 | if (!(stat & SM_FLASH_STATUS_DONE)) | ||
238 | break; | ||
239 | } | ||
240 | out_8(base, SM_FLASH_CMD_CLEAR_STATUS); | ||
241 | out_8(base, SM_FLASH_CMD_RESET); | ||
242 | for (i=0; i<NVRAM_SIZE; i++) | ||
243 | if (base[i] != datas[i]) { | ||
244 | printk(KERN_ERR "nvram: Sharp/Micron flash write failed !\n"); | ||
245 | return -ENXIO; | ||
246 | } | ||
247 | return 0; | ||
248 | } | ||
249 | |||
250 | static int amd_erase_bank(int bank) | ||
251 | { | ||
252 | int i, stat = 0; | ||
253 | unsigned long timeout; | ||
254 | |||
255 | u8* base = (u8 *)nvram_data + core99_bank*NVRAM_SIZE; | ||
256 | |||
257 | DBG("nvram: AMD Erasing bank %d...\n", bank); | ||
258 | |||
259 | /* Unlock 1 */ | ||
260 | out_8(base+0x555, 0xaa); | ||
261 | udelay(1); | ||
262 | /* Unlock 2 */ | ||
263 | out_8(base+0x2aa, 0x55); | ||
264 | udelay(1); | ||
265 | |||
266 | /* Sector-Erase */ | ||
267 | out_8(base+0x555, 0x80); | ||
268 | udelay(1); | ||
269 | out_8(base+0x555, 0xaa); | ||
270 | udelay(1); | ||
271 | out_8(base+0x2aa, 0x55); | ||
272 | udelay(1); | ||
273 | out_8(base, 0x30); | ||
274 | udelay(1); | ||
275 | |||
276 | timeout = 0; | ||
277 | do { | ||
278 | if (++timeout > 1000000) { | ||
279 | printk(KERN_ERR "nvram: AMD flash erase timeout !\n"); | ||
280 | break; | ||
281 | } | ||
282 | stat = in_8(base) ^ in_8(base); | ||
283 | } while (stat != 0); | ||
284 | |||
285 | /* Reset */ | ||
286 | out_8(base, 0xf0); | ||
287 | udelay(1); | ||
288 | |||
289 | for (i=0; i<NVRAM_SIZE; i++) | ||
290 | if (base[i] != 0xff) { | ||
291 | printk(KERN_ERR "nvram: AMD flash erase failed !\n"); | ||
292 | return -ENXIO; | ||
293 | } | ||
294 | return 0; | ||
295 | } | ||
296 | |||
297 | static int amd_write_bank(int bank, u8* datas) | ||
298 | { | ||
299 | int i, stat = 0; | ||
300 | unsigned long timeout; | ||
301 | |||
302 | u8* base = (u8 *)nvram_data + core99_bank*NVRAM_SIZE; | ||
303 | |||
304 | DBG("nvram: AMD Writing bank %d...\n", bank); | ||
305 | |||
306 | for (i=0; i<NVRAM_SIZE; i++) { | ||
307 | /* Unlock 1 */ | ||
308 | out_8(base+0x555, 0xaa); | ||
309 | udelay(1); | ||
310 | /* Unlock 2 */ | ||
311 | out_8(base+0x2aa, 0x55); | ||
312 | udelay(1); | ||
313 | |||
314 | /* Write single word */ | ||
315 | out_8(base+0x555, 0xa0); | ||
316 | udelay(1); | ||
317 | out_8(base+i, datas[i]); | ||
318 | |||
319 | timeout = 0; | ||
320 | do { | ||
321 | if (++timeout > 1000000) { | ||
322 | printk(KERN_ERR "nvram: AMD flash write timeout !\n"); | ||
323 | break; | ||
324 | } | ||
325 | stat = in_8(base) ^ in_8(base); | ||
326 | } while (stat != 0); | ||
327 | if (stat != 0) | ||
328 | break; | ||
329 | } | ||
330 | |||
331 | /* Reset */ | ||
332 | out_8(base, 0xf0); | ||
333 | udelay(1); | ||
334 | |||
335 | for (i=0; i<NVRAM_SIZE; i++) | ||
336 | if (base[i] != datas[i]) { | ||
337 | printk(KERN_ERR "nvram: AMD flash write failed !\n"); | ||
338 | return -ENXIO; | ||
339 | } | ||
340 | return 0; | ||
341 | } | ||
342 | |||
343 | |||
344 | static void core99_nvram_sync(void) | ||
345 | { | ||
346 | struct core99_header* hdr99; | ||
347 | unsigned long flags; | ||
348 | |||
349 | spin_lock_irqsave(&nv_lock, flags); | ||
350 | if (!memcmp(nvram_image, (u8*)nvram_data + core99_bank*NVRAM_SIZE, | ||
351 | NVRAM_SIZE)) | ||
352 | goto bail; | ||
353 | |||
354 | DBG("Updating nvram...\n"); | ||
355 | |||
356 | hdr99 = (struct core99_header*)nvram_image; | ||
357 | hdr99->generation++; | ||
358 | hdr99->hdr.signature = CORE99_SIGNATURE; | ||
359 | hdr99->hdr.cksum = chrp_checksum(&hdr99->hdr); | ||
360 | hdr99->adler = core99_calc_adler(nvram_image); | ||
361 | core99_bank = core99_bank ? 0 : 1; | ||
362 | if (core99_erase_bank) | ||
363 | if (core99_erase_bank(core99_bank)) { | ||
364 | printk("nvram: Error erasing bank %d\n", core99_bank); | ||
365 | goto bail; | ||
366 | } | ||
367 | if (core99_write_bank) | ||
368 | if (core99_write_bank(core99_bank, nvram_image)) | ||
369 | printk("nvram: Error writing bank %d\n", core99_bank); | ||
370 | bail: | ||
371 | spin_unlock_irqrestore(&nv_lock, flags); | ||
372 | } | ||
373 | |||
374 | int __init pmac_nvram_init(void) | ||
375 | { | ||
376 | struct device_node *dp; | ||
377 | u32 gen_bank0, gen_bank1; | ||
378 | int i; | ||
379 | |||
380 | dp = find_devices("nvram"); | ||
381 | if (dp == NULL) { | ||
382 | printk(KERN_ERR "Can't find NVRAM device\n"); | ||
383 | return -ENODEV; | ||
384 | } | ||
385 | if (!device_is_compatible(dp, "nvram,flash")) { | ||
386 | printk(KERN_ERR "Incompatible type of NVRAM\n"); | ||
387 | return -ENXIO; | ||
388 | } | ||
389 | |||
390 | nvram_image = alloc_bootmem(NVRAM_SIZE); | ||
391 | if (nvram_image == NULL) { | ||
392 | printk(KERN_ERR "nvram: can't allocate ram image\n"); | ||
393 | return -ENOMEM; | ||
394 | } | ||
395 | nvram_data = ioremap(dp->addrs[0].address, NVRAM_SIZE*2); | ||
396 | |||
397 | DBG("nvram: Checking bank 0...\n"); | ||
398 | |||
399 | gen_bank0 = core99_check((u8 *)nvram_data); | ||
400 | gen_bank1 = core99_check((u8 *)nvram_data + NVRAM_SIZE); | ||
401 | core99_bank = (gen_bank0 < gen_bank1) ? 1 : 0; | ||
402 | |||
403 | DBG("nvram: gen0=%d, gen1=%d\n", gen_bank0, gen_bank1); | ||
404 | DBG("nvram: Active bank is: %d\n", core99_bank); | ||
405 | |||
406 | for (i=0; i<NVRAM_SIZE; i++) | ||
407 | nvram_image[i] = nvram_data[i + core99_bank*NVRAM_SIZE]; | ||
408 | |||
409 | ppc_md.nvram_read = core99_nvram_read; | ||
410 | ppc_md.nvram_write = core99_nvram_write; | ||
411 | ppc_md.nvram_size = core99_nvram_size; | ||
412 | ppc_md.nvram_sync = core99_nvram_sync; | ||
413 | |||
414 | /* | ||
415 | * Maybe we could be smarter here though making an exclusive list | ||
416 | * of known flash chips is a bit nasty as older OF didn't provide us | ||
417 | * with a useful "compatible" entry. A solution would be to really | ||
418 | * identify the chip using flash id commands and base ourselves on | ||
419 | * a list of known chips IDs | ||
420 | */ | ||
421 | if (device_is_compatible(dp, "amd-0137")) { | ||
422 | core99_erase_bank = amd_erase_bank; | ||
423 | core99_write_bank = amd_write_bank; | ||
424 | } else { | ||
425 | core99_erase_bank = sm_erase_bank; | ||
426 | core99_write_bank = sm_write_bank; | ||
427 | } | ||
428 | |||
429 | return 0; | ||
430 | } | ||
431 | |||
432 | int pmac_get_partition(int partition) | ||
433 | { | ||
434 | struct nvram_partition *part; | ||
435 | const char *name; | ||
436 | int sig; | ||
437 | |||
438 | switch(partition) { | ||
439 | case pmac_nvram_OF: | ||
440 | name = "common"; | ||
441 | sig = NVRAM_SIG_SYS; | ||
442 | break; | ||
443 | case pmac_nvram_XPRAM: | ||
444 | name = "APL,MacOS75"; | ||
445 | sig = NVRAM_SIG_OS; | ||
446 | break; | ||
447 | case pmac_nvram_NR: | ||
448 | default: | ||
449 | /* Oldworld stuff */ | ||
450 | return -ENODEV; | ||
451 | } | ||
452 | |||
453 | part = nvram_find_partition(sig, name); | ||
454 | if (part == NULL) | ||
455 | return 0; | ||
456 | |||
457 | return part->index; | ||
458 | } | ||
459 | |||
460 | u8 pmac_xpram_read(int xpaddr) | ||
461 | { | ||
462 | int offset = pmac_get_partition(pmac_nvram_XPRAM); | ||
463 | loff_t index; | ||
464 | u8 buf; | ||
465 | ssize_t count; | ||
466 | |||
467 | if (offset < 0 || xpaddr < 0 || xpaddr > 0x100) | ||
468 | return 0xff; | ||
469 | index = offset + xpaddr; | ||
470 | |||
471 | count = ppc_md.nvram_read(&buf, 1, &index); | ||
472 | if (count != 1) | ||
473 | return 0xff; | ||
474 | return buf; | ||
475 | } | ||
476 | |||
477 | void pmac_xpram_write(int xpaddr, u8 data) | ||
478 | { | ||
479 | int offset = pmac_get_partition(pmac_nvram_XPRAM); | ||
480 | loff_t index; | ||
481 | u8 buf; | ||
482 | |||
483 | if (offset < 0 || xpaddr < 0 || xpaddr > 0x100) | ||
484 | return; | ||
485 | index = offset + xpaddr; | ||
486 | buf = data; | ||
487 | |||
488 | ppc_md.nvram_write(&buf, 1, &index); | ||
489 | } | ||
490 | |||
491 | EXPORT_SYMBOL(pmac_get_partition); | ||
492 | EXPORT_SYMBOL(pmac_xpram_read); | ||
493 | EXPORT_SYMBOL(pmac_xpram_write); | ||
diff --git a/arch/ppc64/kernel/pmac_pci.c b/arch/ppc64/kernel/pmac_pci.c deleted file mode 100644 index 7a81c8275940..000000000000 --- a/arch/ppc64/kernel/pmac_pci.c +++ /dev/null | |||
@@ -1,793 +0,0 @@ | |||
1 | /* | ||
2 | * Support for PCI bridges found on Power Macintoshes. | ||
3 | * At present the "bandit" and "chaos" bridges are supported. | ||
4 | * Fortunately you access configuration space in the same | ||
5 | * way with either bridge. | ||
6 | * | ||
7 | * Copyright (C) 2003 Benjamin Herrenschmuidt (benh@kernel.crashing.org) | ||
8 | * Copyright (C) 1997 Paul Mackerras (paulus@samba.org) | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or | ||
11 | * modify it under the terms of the GNU General Public License | ||
12 | * as published by the Free Software Foundation; either version | ||
13 | * 2 of the License, or (at your option) any later version. | ||
14 | */ | ||
15 | |||
16 | #include <linux/kernel.h> | ||
17 | #include <linux/pci.h> | ||
18 | #include <linux/delay.h> | ||
19 | #include <linux/string.h> | ||
20 | #include <linux/init.h> | ||
21 | #include <linux/bootmem.h> | ||
22 | |||
23 | #include <asm/sections.h> | ||
24 | #include <asm/io.h> | ||
25 | #include <asm/prom.h> | ||
26 | #include <asm/pci-bridge.h> | ||
27 | #include <asm/machdep.h> | ||
28 | #include <asm/pmac_feature.h> | ||
29 | #include <asm/iommu.h> | ||
30 | #include <asm/ppc-pci.h> | ||
31 | |||
32 | #include "pmac.h" | ||
33 | |||
34 | #define DEBUG | ||
35 | |||
36 | #ifdef DEBUG | ||
37 | #define DBG(x...) printk(x) | ||
38 | #else | ||
39 | #define DBG(x...) | ||
40 | #endif | ||
41 | |||
42 | /* XXX Could be per-controller, but I don't think we risk anything by | ||
43 | * assuming we won't have both UniNorth and Bandit */ | ||
44 | static int has_uninorth; | ||
45 | static struct pci_controller *u3_agp; | ||
46 | struct device_node *k2_skiplist[2]; | ||
47 | |||
48 | static int __init fixup_one_level_bus_range(struct device_node *node, int higher) | ||
49 | { | ||
50 | for (; node != 0;node = node->sibling) { | ||
51 | int * bus_range; | ||
52 | unsigned int *class_code; | ||
53 | int len; | ||
54 | |||
55 | /* For PCI<->PCI bridges or CardBus bridges, we go down */ | ||
56 | class_code = (unsigned int *) get_property(node, "class-code", NULL); | ||
57 | if (!class_code || ((*class_code >> 8) != PCI_CLASS_BRIDGE_PCI && | ||
58 | (*class_code >> 8) != PCI_CLASS_BRIDGE_CARDBUS)) | ||
59 | continue; | ||
60 | bus_range = (int *) get_property(node, "bus-range", &len); | ||
61 | if (bus_range != NULL && len > 2 * sizeof(int)) { | ||
62 | if (bus_range[1] > higher) | ||
63 | higher = bus_range[1]; | ||
64 | } | ||
65 | higher = fixup_one_level_bus_range(node->child, higher); | ||
66 | } | ||
67 | return higher; | ||
68 | } | ||
69 | |||
70 | /* This routine fixes the "bus-range" property of all bridges in the | ||
71 | * system since they tend to have their "last" member wrong on macs | ||
72 | * | ||
73 | * Note that the bus numbers manipulated here are OF bus numbers, they | ||
74 | * are not Linux bus numbers. | ||
75 | */ | ||
76 | static void __init fixup_bus_range(struct device_node *bridge) | ||
77 | { | ||
78 | int * bus_range; | ||
79 | int len; | ||
80 | |||
81 | /* Lookup the "bus-range" property for the hose */ | ||
82 | bus_range = (int *) get_property(bridge, "bus-range", &len); | ||
83 | if (bus_range == NULL || len < 2 * sizeof(int)) { | ||
84 | printk(KERN_WARNING "Can't get bus-range for %s\n", | ||
85 | bridge->full_name); | ||
86 | return; | ||
87 | } | ||
88 | bus_range[1] = fixup_one_level_bus_range(bridge->child, bus_range[1]); | ||
89 | } | ||
90 | |||
91 | /* | ||
92 | * Apple MacRISC (U3, UniNorth, Bandit, Chaos) PCI controllers. | ||
93 | * | ||
94 | * The "Bandit" version is present in all early PCI PowerMacs, | ||
95 | * and up to the first ones using Grackle. Some machines may | ||
96 | * have 2 bandit controllers (2 PCI busses). | ||
97 | * | ||
98 | * "Chaos" is used in some "Bandit"-type machines as a bridge | ||
99 | * for the separate display bus. It is accessed the same | ||
100 | * way as bandit, but cannot be probed for devices. It therefore | ||
101 | * has its own config access functions. | ||
102 | * | ||
103 | * The "UniNorth" version is present in all Core99 machines | ||
104 | * (iBook, G4, new IMacs, and all the recent Apple machines). | ||
105 | * It contains 3 controllers in one ASIC. | ||
106 | * | ||
107 | * The U3 is the bridge used on G5 machines. It contains on | ||
108 | * AGP bus which is dealt with the old UniNorth access routines | ||
109 | * and an HyperTransport bus which uses its own set of access | ||
110 | * functions. | ||
111 | */ | ||
112 | |||
113 | #define MACRISC_CFA0(devfn, off) \ | ||
114 | ((1 << (unsigned long)PCI_SLOT(dev_fn)) \ | ||
115 | | (((unsigned long)PCI_FUNC(dev_fn)) << 8) \ | ||
116 | | (((unsigned long)(off)) & 0xFCUL)) | ||
117 | |||
118 | #define MACRISC_CFA1(bus, devfn, off) \ | ||
119 | ((((unsigned long)(bus)) << 16) \ | ||
120 | |(((unsigned long)(devfn)) << 8) \ | ||
121 | |(((unsigned long)(off)) & 0xFCUL) \ | ||
122 | |1UL) | ||
123 | |||
124 | static unsigned long macrisc_cfg_access(struct pci_controller* hose, | ||
125 | u8 bus, u8 dev_fn, u8 offset) | ||
126 | { | ||
127 | unsigned int caddr; | ||
128 | |||
129 | if (bus == hose->first_busno) { | ||
130 | if (dev_fn < (11 << 3)) | ||
131 | return 0; | ||
132 | caddr = MACRISC_CFA0(dev_fn, offset); | ||
133 | } else | ||
134 | caddr = MACRISC_CFA1(bus, dev_fn, offset); | ||
135 | |||
136 | /* Uninorth will return garbage if we don't read back the value ! */ | ||
137 | do { | ||
138 | out_le32(hose->cfg_addr, caddr); | ||
139 | } while (in_le32(hose->cfg_addr) != caddr); | ||
140 | |||
141 | offset &= has_uninorth ? 0x07 : 0x03; | ||
142 | return ((unsigned long)hose->cfg_data) + offset; | ||
143 | } | ||
144 | |||
145 | static int macrisc_read_config(struct pci_bus *bus, unsigned int devfn, | ||
146 | int offset, int len, u32 *val) | ||
147 | { | ||
148 | struct pci_controller *hose; | ||
149 | unsigned long addr; | ||
150 | |||
151 | hose = pci_bus_to_host(bus); | ||
152 | if (hose == NULL) | ||
153 | return PCIBIOS_DEVICE_NOT_FOUND; | ||
154 | |||
155 | addr = macrisc_cfg_access(hose, bus->number, devfn, offset); | ||
156 | if (!addr) | ||
157 | return PCIBIOS_DEVICE_NOT_FOUND; | ||
158 | /* | ||
159 | * Note: the caller has already checked that offset is | ||
160 | * suitably aligned and that len is 1, 2 or 4. | ||
161 | */ | ||
162 | switch (len) { | ||
163 | case 1: | ||
164 | *val = in_8((u8 *)addr); | ||
165 | break; | ||
166 | case 2: | ||
167 | *val = in_le16((u16 *)addr); | ||
168 | break; | ||
169 | default: | ||
170 | *val = in_le32((u32 *)addr); | ||
171 | break; | ||
172 | } | ||
173 | return PCIBIOS_SUCCESSFUL; | ||
174 | } | ||
175 | |||
176 | static int macrisc_write_config(struct pci_bus *bus, unsigned int devfn, | ||
177 | int offset, int len, u32 val) | ||
178 | { | ||
179 | struct pci_controller *hose; | ||
180 | unsigned long addr; | ||
181 | |||
182 | hose = pci_bus_to_host(bus); | ||
183 | if (hose == NULL) | ||
184 | return PCIBIOS_DEVICE_NOT_FOUND; | ||
185 | |||
186 | addr = macrisc_cfg_access(hose, bus->number, devfn, offset); | ||
187 | if (!addr) | ||
188 | return PCIBIOS_DEVICE_NOT_FOUND; | ||
189 | /* | ||
190 | * Note: the caller has already checked that offset is | ||
191 | * suitably aligned and that len is 1, 2 or 4. | ||
192 | */ | ||
193 | switch (len) { | ||
194 | case 1: | ||
195 | out_8((u8 *)addr, val); | ||
196 | (void) in_8((u8 *)addr); | ||
197 | break; | ||
198 | case 2: | ||
199 | out_le16((u16 *)addr, val); | ||
200 | (void) in_le16((u16 *)addr); | ||
201 | break; | ||
202 | default: | ||
203 | out_le32((u32 *)addr, val); | ||
204 | (void) in_le32((u32 *)addr); | ||
205 | break; | ||
206 | } | ||
207 | return PCIBIOS_SUCCESSFUL; | ||
208 | } | ||
209 | |||
210 | static struct pci_ops macrisc_pci_ops = | ||
211 | { | ||
212 | macrisc_read_config, | ||
213 | macrisc_write_config | ||
214 | }; | ||
215 | |||
216 | /* | ||
217 | * These versions of U3 HyperTransport config space access ops do not | ||
218 | * implement self-view of the HT host yet | ||
219 | */ | ||
220 | |||
221 | /* | ||
222 | * This function deals with some "special cases" devices. | ||
223 | * | ||
224 | * 0 -> No special case | ||
225 | * 1 -> Skip the device but act as if the access was successfull | ||
226 | * (return 0xff's on reads, eventually, cache config space | ||
227 | * accesses in a later version) | ||
228 | * -1 -> Hide the device (unsuccessful acess) | ||
229 | */ | ||
230 | static int u3_ht_skip_device(struct pci_controller *hose, | ||
231 | struct pci_bus *bus, unsigned int devfn) | ||
232 | { | ||
233 | struct device_node *busdn, *dn; | ||
234 | int i; | ||
235 | |||
236 | /* We only allow config cycles to devices that are in OF device-tree | ||
237 | * as we are apparently having some weird things going on with some | ||
238 | * revs of K2 on recent G5s | ||
239 | */ | ||
240 | if (bus->self) | ||
241 | busdn = pci_device_to_OF_node(bus->self); | ||
242 | else | ||
243 | busdn = hose->arch_data; | ||
244 | for (dn = busdn->child; dn; dn = dn->sibling) | ||
245 | if (dn->data && PCI_DN(dn)->devfn == devfn) | ||
246 | break; | ||
247 | if (dn == NULL) | ||
248 | return -1; | ||
249 | |||
250 | /* | ||
251 | * When a device in K2 is powered down, we die on config | ||
252 | * cycle accesses. Fix that here. | ||
253 | */ | ||
254 | for (i=0; i<2; i++) | ||
255 | if (k2_skiplist[i] == dn) | ||
256 | return 1; | ||
257 | |||
258 | return 0; | ||
259 | } | ||
260 | |||
261 | #define U3_HT_CFA0(devfn, off) \ | ||
262 | ((((unsigned long)devfn) << 8) | offset) | ||
263 | #define U3_HT_CFA1(bus, devfn, off) \ | ||
264 | (U3_HT_CFA0(devfn, off) \ | ||
265 | + (((unsigned long)bus) << 16) \ | ||
266 | + 0x01000000UL) | ||
267 | |||
268 | static unsigned long u3_ht_cfg_access(struct pci_controller* hose, | ||
269 | u8 bus, u8 devfn, u8 offset) | ||
270 | { | ||
271 | if (bus == hose->first_busno) { | ||
272 | /* For now, we don't self probe U3 HT bridge */ | ||
273 | if (PCI_SLOT(devfn) == 0) | ||
274 | return 0; | ||
275 | return ((unsigned long)hose->cfg_data) + U3_HT_CFA0(devfn, offset); | ||
276 | } else | ||
277 | return ((unsigned long)hose->cfg_data) + U3_HT_CFA1(bus, devfn, offset); | ||
278 | } | ||
279 | |||
280 | static int u3_ht_read_config(struct pci_bus *bus, unsigned int devfn, | ||
281 | int offset, int len, u32 *val) | ||
282 | { | ||
283 | struct pci_controller *hose; | ||
284 | unsigned long addr; | ||
285 | |||
286 | |||
287 | hose = pci_bus_to_host(bus); | ||
288 | if (hose == NULL) | ||
289 | return PCIBIOS_DEVICE_NOT_FOUND; | ||
290 | |||
291 | addr = u3_ht_cfg_access(hose, bus->number, devfn, offset); | ||
292 | if (!addr) | ||
293 | return PCIBIOS_DEVICE_NOT_FOUND; | ||
294 | |||
295 | switch (u3_ht_skip_device(hose, bus, devfn)) { | ||
296 | case 0: | ||
297 | break; | ||
298 | case 1: | ||
299 | switch (len) { | ||
300 | case 1: | ||
301 | *val = 0xff; break; | ||
302 | case 2: | ||
303 | *val = 0xffff; break; | ||
304 | default: | ||
305 | *val = 0xfffffffful; break; | ||
306 | } | ||
307 | return PCIBIOS_SUCCESSFUL; | ||
308 | default: | ||
309 | return PCIBIOS_DEVICE_NOT_FOUND; | ||
310 | } | ||
311 | |||
312 | /* | ||
313 | * Note: the caller has already checked that offset is | ||
314 | * suitably aligned and that len is 1, 2 or 4. | ||
315 | */ | ||
316 | switch (len) { | ||
317 | case 1: | ||
318 | *val = in_8((u8 *)addr); | ||
319 | break; | ||
320 | case 2: | ||
321 | *val = in_le16((u16 *)addr); | ||
322 | break; | ||
323 | default: | ||
324 | *val = in_le32((u32 *)addr); | ||
325 | break; | ||
326 | } | ||
327 | return PCIBIOS_SUCCESSFUL; | ||
328 | } | ||
329 | |||
330 | static int u3_ht_write_config(struct pci_bus *bus, unsigned int devfn, | ||
331 | int offset, int len, u32 val) | ||
332 | { | ||
333 | struct pci_controller *hose; | ||
334 | unsigned long addr; | ||
335 | |||
336 | hose = pci_bus_to_host(bus); | ||
337 | if (hose == NULL) | ||
338 | return PCIBIOS_DEVICE_NOT_FOUND; | ||
339 | |||
340 | addr = u3_ht_cfg_access(hose, bus->number, devfn, offset); | ||
341 | if (!addr) | ||
342 | return PCIBIOS_DEVICE_NOT_FOUND; | ||
343 | |||
344 | switch (u3_ht_skip_device(hose, bus, devfn)) { | ||
345 | case 0: | ||
346 | break; | ||
347 | case 1: | ||
348 | return PCIBIOS_SUCCESSFUL; | ||
349 | default: | ||
350 | return PCIBIOS_DEVICE_NOT_FOUND; | ||
351 | } | ||
352 | |||
353 | /* | ||
354 | * Note: the caller has already checked that offset is | ||
355 | * suitably aligned and that len is 1, 2 or 4. | ||
356 | */ | ||
357 | switch (len) { | ||
358 | case 1: | ||
359 | out_8((u8 *)addr, val); | ||
360 | (void) in_8((u8 *)addr); | ||
361 | break; | ||
362 | case 2: | ||
363 | out_le16((u16 *)addr, val); | ||
364 | (void) in_le16((u16 *)addr); | ||
365 | break; | ||
366 | default: | ||
367 | out_le32((u32 *)addr, val); | ||
368 | (void) in_le32((u32 *)addr); | ||
369 | break; | ||
370 | } | ||
371 | return PCIBIOS_SUCCESSFUL; | ||
372 | } | ||
373 | |||
374 | static struct pci_ops u3_ht_pci_ops = | ||
375 | { | ||
376 | u3_ht_read_config, | ||
377 | u3_ht_write_config | ||
378 | }; | ||
379 | |||
380 | static void __init setup_u3_agp(struct pci_controller* hose) | ||
381 | { | ||
382 | /* On G5, we move AGP up to high bus number so we don't need | ||
383 | * to reassign bus numbers for HT. If we ever have P2P bridges | ||
384 | * on AGP, we'll have to move pci_assign_all_buses to the | ||
385 | * pci_controller structure so we enable it for AGP and not for | ||
386 | * HT childs. | ||
387 | * We hard code the address because of the different size of | ||
388 | * the reg address cell, we shall fix that by killing struct | ||
389 | * reg_property and using some accessor functions instead | ||
390 | */ | ||
391 | hose->first_busno = 0xf0; | ||
392 | hose->last_busno = 0xff; | ||
393 | has_uninorth = 1; | ||
394 | hose->ops = ¯isc_pci_ops; | ||
395 | hose->cfg_addr = ioremap(0xf0000000 + 0x800000, 0x1000); | ||
396 | hose->cfg_data = ioremap(0xf0000000 + 0xc00000, 0x1000); | ||
397 | |||
398 | u3_agp = hose; | ||
399 | } | ||
400 | |||
401 | static void __init setup_u3_ht(struct pci_controller* hose) | ||
402 | { | ||
403 | struct device_node *np = (struct device_node *)hose->arch_data; | ||
404 | int i, cur; | ||
405 | |||
406 | hose->ops = &u3_ht_pci_ops; | ||
407 | |||
408 | /* We hard code the address because of the different size of | ||
409 | * the reg address cell, we shall fix that by killing struct | ||
410 | * reg_property and using some accessor functions instead | ||
411 | */ | ||
412 | hose->cfg_data = (volatile unsigned char *)ioremap(0xf2000000, 0x02000000); | ||
413 | |||
414 | /* | ||
415 | * /ht node doesn't expose a "ranges" property, so we "remove" regions that | ||
416 | * have been allocated to AGP. So far, this version of the code doesn't assign | ||
417 | * any of the 0xfxxxxxxx "fine" memory regions to /ht. | ||
418 | * We need to fix that sooner or later by either parsing all child "ranges" | ||
419 | * properties or figuring out the U3 address space decoding logic and | ||
420 | * then read it's configuration register (if any). | ||
421 | */ | ||
422 | hose->io_base_phys = 0xf4000000; | ||
423 | hose->io_base_virt = ioremap(hose->io_base_phys, 0x00400000); | ||
424 | isa_io_base = pci_io_base = (unsigned long) hose->io_base_virt; | ||
425 | hose->io_resource.name = np->full_name; | ||
426 | hose->io_resource.start = 0; | ||
427 | hose->io_resource.end = 0x003fffff; | ||
428 | hose->io_resource.flags = IORESOURCE_IO; | ||
429 | hose->pci_mem_offset = 0; | ||
430 | hose->first_busno = 0; | ||
431 | hose->last_busno = 0xef; | ||
432 | hose->mem_resources[0].name = np->full_name; | ||
433 | hose->mem_resources[0].start = 0x80000000; | ||
434 | hose->mem_resources[0].end = 0xefffffff; | ||
435 | hose->mem_resources[0].flags = IORESOURCE_MEM; | ||
436 | |||
437 | if (u3_agp == NULL) { | ||
438 | DBG("U3 has no AGP, using full resource range\n"); | ||
439 | return; | ||
440 | } | ||
441 | |||
442 | /* We "remove" the AGP resources from the resources allocated to HT, that | ||
443 | * is we create "holes". However, that code does assumptions that so far | ||
444 | * happen to be true (cross fingers...), typically that resources in the | ||
445 | * AGP node are properly ordered | ||
446 | */ | ||
447 | cur = 0; | ||
448 | for (i=0; i<3; i++) { | ||
449 | struct resource *res = &u3_agp->mem_resources[i]; | ||
450 | if (res->flags != IORESOURCE_MEM) | ||
451 | continue; | ||
452 | /* We don't care about "fine" resources */ | ||
453 | if (res->start >= 0xf0000000) | ||
454 | continue; | ||
455 | /* Check if it's just a matter of "shrinking" us in one direction */ | ||
456 | if (hose->mem_resources[cur].start == res->start) { | ||
457 | DBG("U3/HT: shrink start of %d, %08lx -> %08lx\n", | ||
458 | cur, hose->mem_resources[cur].start, res->end + 1); | ||
459 | hose->mem_resources[cur].start = res->end + 1; | ||
460 | continue; | ||
461 | } | ||
462 | if (hose->mem_resources[cur].end == res->end) { | ||
463 | DBG("U3/HT: shrink end of %d, %08lx -> %08lx\n", | ||
464 | cur, hose->mem_resources[cur].end, res->start - 1); | ||
465 | hose->mem_resources[cur].end = res->start - 1; | ||
466 | continue; | ||
467 | } | ||
468 | /* No, it's not the case, we need a hole */ | ||
469 | if (cur == 2) { | ||
470 | /* not enough resources for a hole, we drop part of the range */ | ||
471 | printk(KERN_WARNING "Running out of resources for /ht host !\n"); | ||
472 | hose->mem_resources[cur].end = res->start - 1; | ||
473 | continue; | ||
474 | } | ||
475 | cur++; | ||
476 | DBG("U3/HT: hole, %d end at %08lx, %d start at %08lx\n", | ||
477 | cur-1, res->start - 1, cur, res->end + 1); | ||
478 | hose->mem_resources[cur].name = np->full_name; | ||
479 | hose->mem_resources[cur].flags = IORESOURCE_MEM; | ||
480 | hose->mem_resources[cur].start = res->end + 1; | ||
481 | hose->mem_resources[cur].end = hose->mem_resources[cur-1].end; | ||
482 | hose->mem_resources[cur-1].end = res->start - 1; | ||
483 | } | ||
484 | } | ||
485 | |||
486 | static void __init pmac_process_bridge_OF_ranges(struct pci_controller *hose, | ||
487 | struct device_node *dev, int primary) | ||
488 | { | ||
489 | static unsigned int static_lc_ranges[2024]; | ||
490 | unsigned int *dt_ranges, *lc_ranges, *ranges, *prev; | ||
491 | unsigned int size; | ||
492 | int rlen = 0, orig_rlen; | ||
493 | int memno = 0; | ||
494 | struct resource *res; | ||
495 | int np, na = prom_n_addr_cells(dev); | ||
496 | |||
497 | np = na + 5; | ||
498 | |||
499 | /* First we try to merge ranges to fix a problem with some pmacs | ||
500 | * that can have more than 3 ranges, fortunately using contiguous | ||
501 | * addresses -- BenH | ||
502 | */ | ||
503 | dt_ranges = (unsigned int *) get_property(dev, "ranges", &rlen); | ||
504 | if (!dt_ranges) | ||
505 | return; | ||
506 | /* lc_ranges = alloc_bootmem(rlen);*/ | ||
507 | lc_ranges = static_lc_ranges; | ||
508 | if (!lc_ranges) | ||
509 | return; /* what can we do here ? */ | ||
510 | memcpy(lc_ranges, dt_ranges, rlen); | ||
511 | orig_rlen = rlen; | ||
512 | |||
513 | /* Let's work on a copy of the "ranges" property instead of damaging | ||
514 | * the device-tree image in memory | ||
515 | */ | ||
516 | ranges = lc_ranges; | ||
517 | prev = NULL; | ||
518 | while ((rlen -= np * sizeof(unsigned int)) >= 0) { | ||
519 | if (prev) { | ||
520 | if (prev[0] == ranges[0] && prev[1] == ranges[1] && | ||
521 | (prev[2] + prev[na+4]) == ranges[2] && | ||
522 | (prev[na+2] + prev[na+4]) == ranges[na+2]) { | ||
523 | prev[na+4] += ranges[na+4]; | ||
524 | ranges[0] = 0; | ||
525 | ranges += np; | ||
526 | continue; | ||
527 | } | ||
528 | } | ||
529 | prev = ranges; | ||
530 | ranges += np; | ||
531 | } | ||
532 | |||
533 | /* | ||
534 | * The ranges property is laid out as an array of elements, | ||
535 | * each of which comprises: | ||
536 | * cells 0 - 2: a PCI address | ||
537 | * cells 3 or 3+4: a CPU physical address | ||
538 | * (size depending on dev->n_addr_cells) | ||
539 | * cells 4+5 or 5+6: the size of the range | ||
540 | */ | ||
541 | ranges = lc_ranges; | ||
542 | rlen = orig_rlen; | ||
543 | while (ranges && (rlen -= np * sizeof(unsigned int)) >= 0) { | ||
544 | res = NULL; | ||
545 | size = ranges[na+4]; | ||
546 | switch (ranges[0] >> 24) { | ||
547 | case 1: /* I/O space */ | ||
548 | if (ranges[2] != 0) | ||
549 | break; | ||
550 | hose->io_base_phys = ranges[na+2]; | ||
551 | /* limit I/O space to 16MB */ | ||
552 | if (size > 0x01000000) | ||
553 | size = 0x01000000; | ||
554 | hose->io_base_virt = ioremap(ranges[na+2], size); | ||
555 | if (primary) | ||
556 | isa_io_base = (unsigned long) hose->io_base_virt; | ||
557 | res = &hose->io_resource; | ||
558 | res->flags = IORESOURCE_IO; | ||
559 | res->start = ranges[2]; | ||
560 | break; | ||
561 | case 2: /* memory space */ | ||
562 | memno = 0; | ||
563 | if (ranges[1] == 0 && ranges[2] == 0 | ||
564 | && ranges[na+4] <= (16 << 20)) { | ||
565 | /* 1st 16MB, i.e. ISA memory area */ | ||
566 | #if 0 | ||
567 | if (primary) | ||
568 | isa_mem_base = ranges[na+2]; | ||
569 | #endif | ||
570 | memno = 1; | ||
571 | } | ||
572 | while (memno < 3 && hose->mem_resources[memno].flags) | ||
573 | ++memno; | ||
574 | if (memno == 0) | ||
575 | hose->pci_mem_offset = ranges[na+2] - ranges[2]; | ||
576 | if (memno < 3) { | ||
577 | res = &hose->mem_resources[memno]; | ||
578 | res->flags = IORESOURCE_MEM; | ||
579 | res->start = ranges[na+2]; | ||
580 | } | ||
581 | break; | ||
582 | } | ||
583 | if (res != NULL) { | ||
584 | res->name = dev->full_name; | ||
585 | res->end = res->start + size - 1; | ||
586 | res->parent = NULL; | ||
587 | res->sibling = NULL; | ||
588 | res->child = NULL; | ||
589 | } | ||
590 | ranges += np; | ||
591 | } | ||
592 | } | ||
593 | |||
594 | /* | ||
595 | * We assume that if we have a G3 powermac, we have one bridge called | ||
596 | * "pci" (a MPC106) and no bandit or chaos bridges, and contrariwise, | ||
597 | * if we have one or more bandit or chaos bridges, we don't have a MPC106. | ||
598 | */ | ||
599 | static int __init add_bridge(struct device_node *dev) | ||
600 | { | ||
601 | int len; | ||
602 | struct pci_controller *hose; | ||
603 | char* disp_name; | ||
604 | int *bus_range; | ||
605 | int primary = 1; | ||
606 | struct property *of_prop; | ||
607 | |||
608 | DBG("Adding PCI host bridge %s\n", dev->full_name); | ||
609 | |||
610 | bus_range = (int *) get_property(dev, "bus-range", &len); | ||
611 | if (bus_range == NULL || len < 2 * sizeof(int)) { | ||
612 | printk(KERN_WARNING "Can't get bus-range for %s, assume bus 0\n", | ||
613 | dev->full_name); | ||
614 | } | ||
615 | |||
616 | hose = alloc_bootmem(sizeof(struct pci_controller)); | ||
617 | if (hose == NULL) | ||
618 | return -ENOMEM; | ||
619 | pci_setup_pci_controller(hose); | ||
620 | |||
621 | hose->arch_data = dev; | ||
622 | hose->first_busno = bus_range ? bus_range[0] : 0; | ||
623 | hose->last_busno = bus_range ? bus_range[1] : 0xff; | ||
624 | |||
625 | of_prop = alloc_bootmem(sizeof(struct property) + | ||
626 | sizeof(hose->global_number)); | ||
627 | if (of_prop) { | ||
628 | memset(of_prop, 0, sizeof(struct property)); | ||
629 | of_prop->name = "linux,pci-domain"; | ||
630 | of_prop->length = sizeof(hose->global_number); | ||
631 | of_prop->value = (unsigned char *)&of_prop[1]; | ||
632 | memcpy(of_prop->value, &hose->global_number, sizeof(hose->global_number)); | ||
633 | prom_add_property(dev, of_prop); | ||
634 | } | ||
635 | |||
636 | disp_name = NULL; | ||
637 | if (device_is_compatible(dev, "u3-agp")) { | ||
638 | setup_u3_agp(hose); | ||
639 | disp_name = "U3-AGP"; | ||
640 | primary = 0; | ||
641 | } else if (device_is_compatible(dev, "u3-ht")) { | ||
642 | setup_u3_ht(hose); | ||
643 | disp_name = "U3-HT"; | ||
644 | primary = 1; | ||
645 | } | ||
646 | printk(KERN_INFO "Found %s PCI host bridge. Firmware bus number: %d->%d\n", | ||
647 | disp_name, hose->first_busno, hose->last_busno); | ||
648 | |||
649 | /* Interpret the "ranges" property */ | ||
650 | /* This also maps the I/O region and sets isa_io/mem_base */ | ||
651 | pmac_process_bridge_OF_ranges(hose, dev, primary); | ||
652 | |||
653 | /* Fixup "bus-range" OF property */ | ||
654 | fixup_bus_range(dev); | ||
655 | |||
656 | return 0; | ||
657 | } | ||
658 | |||
659 | /* | ||
660 | * We use our own read_irq_line here because PCI_INTERRUPT_PIN is | ||
661 | * crap on some of Apple ASICs. We unconditionally use the Open Firmware | ||
662 | * interrupt number as this is always right. | ||
663 | */ | ||
664 | static int pmac_pci_read_irq_line(struct pci_dev *pci_dev) | ||
665 | { | ||
666 | struct device_node *node; | ||
667 | |||
668 | node = pci_device_to_OF_node(pci_dev); | ||
669 | if (node == NULL) | ||
670 | return -1; | ||
671 | if (node->n_intrs == 0) | ||
672 | return -1; | ||
673 | pci_dev->irq = node->intrs[0].line; | ||
674 | pci_write_config_byte(pci_dev, PCI_INTERRUPT_LINE, pci_dev->irq); | ||
675 | |||
676 | return 0; | ||
677 | } | ||
678 | |||
679 | void __init pmac_pcibios_fixup(void) | ||
680 | { | ||
681 | struct pci_dev *dev = NULL; | ||
682 | |||
683 | for_each_pci_dev(dev) | ||
684 | pmac_pci_read_irq_line(dev); | ||
685 | } | ||
686 | |||
687 | static void __init pmac_fixup_phb_resources(void) | ||
688 | { | ||
689 | struct pci_controller *hose, *tmp; | ||
690 | |||
691 | list_for_each_entry_safe(hose, tmp, &hose_list, list_node) { | ||
692 | unsigned long offset = (unsigned long)hose->io_base_virt - pci_io_base; | ||
693 | hose->io_resource.start += offset; | ||
694 | hose->io_resource.end += offset; | ||
695 | printk(KERN_INFO "PCI Host %d, io start: %lx; io end: %lx\n", | ||
696 | hose->global_number, | ||
697 | hose->io_resource.start, hose->io_resource.end); | ||
698 | } | ||
699 | } | ||
700 | |||
701 | void __init pmac_pci_init(void) | ||
702 | { | ||
703 | struct device_node *np, *root; | ||
704 | struct device_node *ht = NULL; | ||
705 | |||
706 | /* Probe root PCI hosts, that is on U3 the AGP host and the | ||
707 | * HyperTransport host. That one is actually "kept" around | ||
708 | * and actually added last as it's resource management relies | ||
709 | * on the AGP resources to have been setup first | ||
710 | */ | ||
711 | root = of_find_node_by_path("/"); | ||
712 | if (root == NULL) { | ||
713 | printk(KERN_CRIT "pmac_find_bridges: can't find root of device tree\n"); | ||
714 | return; | ||
715 | } | ||
716 | for (np = NULL; (np = of_get_next_child(root, np)) != NULL;) { | ||
717 | if (np->name == NULL) | ||
718 | continue; | ||
719 | if (strcmp(np->name, "pci") == 0) { | ||
720 | if (add_bridge(np) == 0) | ||
721 | of_node_get(np); | ||
722 | } | ||
723 | if (strcmp(np->name, "ht") == 0) { | ||
724 | of_node_get(np); | ||
725 | ht = np; | ||
726 | } | ||
727 | } | ||
728 | of_node_put(root); | ||
729 | |||
730 | /* Now setup the HyperTransport host if we found any | ||
731 | */ | ||
732 | if (ht && add_bridge(ht) != 0) | ||
733 | of_node_put(ht); | ||
734 | |||
735 | /* Fixup the IO resources on our host bridges as the common code | ||
736 | * does it only for childs of the host bridges | ||
737 | */ | ||
738 | pmac_fixup_phb_resources(); | ||
739 | |||
740 | /* Setup the linkage between OF nodes and PHBs */ | ||
741 | pci_devs_phb_init(); | ||
742 | |||
743 | /* Fixup the PCI<->OF mapping for U3 AGP due to bus renumbering. We | ||
744 | * assume there is no P2P bridge on the AGP bus, which should be a | ||
745 | * safe assumptions hopefully. | ||
746 | */ | ||
747 | if (u3_agp) { | ||
748 | struct device_node *np = u3_agp->arch_data; | ||
749 | PCI_DN(np)->busno = 0xf0; | ||
750 | for (np = np->child; np; np = np->sibling) | ||
751 | PCI_DN(np)->busno = 0xf0; | ||
752 | } | ||
753 | |||
754 | pmac_check_ht_link(); | ||
755 | |||
756 | /* Tell pci.c to not use the common resource allocation mecanism */ | ||
757 | pci_probe_only = 1; | ||
758 | |||
759 | /* Allow all IO */ | ||
760 | io_page_mask = -1; | ||
761 | } | ||
762 | |||
763 | /* | ||
764 | * Disable second function on K2-SATA, it's broken | ||
765 | * and disable IO BARs on first one | ||
766 | */ | ||
767 | static void fixup_k2_sata(struct pci_dev* dev) | ||
768 | { | ||
769 | int i; | ||
770 | u16 cmd; | ||
771 | |||
772 | if (PCI_FUNC(dev->devfn) > 0) { | ||
773 | pci_read_config_word(dev, PCI_COMMAND, &cmd); | ||
774 | cmd &= ~(PCI_COMMAND_IO | PCI_COMMAND_MEMORY); | ||
775 | pci_write_config_word(dev, PCI_COMMAND, cmd); | ||
776 | for (i = 0; i < 6; i++) { | ||
777 | dev->resource[i].start = dev->resource[i].end = 0; | ||
778 | dev->resource[i].flags = 0; | ||
779 | pci_write_config_dword(dev, PCI_BASE_ADDRESS_0 + 4 * i, 0); | ||
780 | } | ||
781 | } else { | ||
782 | pci_read_config_word(dev, PCI_COMMAND, &cmd); | ||
783 | cmd &= ~PCI_COMMAND_IO; | ||
784 | pci_write_config_word(dev, PCI_COMMAND, cmd); | ||
785 | for (i = 0; i < 5; i++) { | ||
786 | dev->resource[i].start = dev->resource[i].end = 0; | ||
787 | dev->resource[i].flags = 0; | ||
788 | pci_write_config_dword(dev, PCI_BASE_ADDRESS_0 + 4 * i, 0); | ||
789 | } | ||
790 | } | ||
791 | } | ||
792 | DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SERVERWORKS, 0x0240, fixup_k2_sata); | ||
793 | |||
diff --git a/arch/ppc64/kernel/pmac_setup.c b/arch/ppc64/kernel/pmac_setup.c deleted file mode 100644 index c3ea73df937d..000000000000 --- a/arch/ppc64/kernel/pmac_setup.c +++ /dev/null | |||
@@ -1,476 +0,0 @@ | |||
1 | /* | ||
2 | * arch/ppc/platforms/setup.c | ||
3 | * | ||
4 | * PowerPC version | ||
5 | * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) | ||
6 | * | ||
7 | * Adapted for Power Macintosh by Paul Mackerras | ||
8 | * Copyright (C) 1996 Paul Mackerras (paulus@cs.anu.edu.au) | ||
9 | * | ||
10 | * Derived from "arch/alpha/kernel/setup.c" | ||
11 | * Copyright (C) 1995 Linus Torvalds | ||
12 | * | ||
13 | * Maintained by Benjamin Herrenschmidt (benh@kernel.crashing.org) | ||
14 | * | ||
15 | * This program is free software; you can redistribute it and/or | ||
16 | * modify it under the terms of the GNU General Public License | ||
17 | * as published by the Free Software Foundation; either version | ||
18 | * 2 of the License, or (at your option) any later version. | ||
19 | * | ||
20 | */ | ||
21 | |||
22 | /* | ||
23 | * bootup setup stuff.. | ||
24 | */ | ||
25 | |||
26 | #undef DEBUG | ||
27 | |||
28 | #include <linux/config.h> | ||
29 | #include <linux/init.h> | ||
30 | #include <linux/errno.h> | ||
31 | #include <linux/sched.h> | ||
32 | #include <linux/kernel.h> | ||
33 | #include <linux/mm.h> | ||
34 | #include <linux/stddef.h> | ||
35 | #include <linux/unistd.h> | ||
36 | #include <linux/ptrace.h> | ||
37 | #include <linux/slab.h> | ||
38 | #include <linux/user.h> | ||
39 | #include <linux/a.out.h> | ||
40 | #include <linux/tty.h> | ||
41 | #include <linux/string.h> | ||
42 | #include <linux/delay.h> | ||
43 | #include <linux/ioport.h> | ||
44 | #include <linux/major.h> | ||
45 | #include <linux/initrd.h> | ||
46 | #include <linux/vt_kern.h> | ||
47 | #include <linux/console.h> | ||
48 | #include <linux/ide.h> | ||
49 | #include <linux/pci.h> | ||
50 | #include <linux/adb.h> | ||
51 | #include <linux/cuda.h> | ||
52 | #include <linux/pmu.h> | ||
53 | #include <linux/irq.h> | ||
54 | #include <linux/seq_file.h> | ||
55 | #include <linux/root_dev.h> | ||
56 | #include <linux/bitops.h> | ||
57 | |||
58 | #include <asm/processor.h> | ||
59 | #include <asm/sections.h> | ||
60 | #include <asm/prom.h> | ||
61 | #include <asm/system.h> | ||
62 | #include <asm/io.h> | ||
63 | #include <asm/pci-bridge.h> | ||
64 | #include <asm/iommu.h> | ||
65 | #include <asm/machdep.h> | ||
66 | #include <asm/dma.h> | ||
67 | #include <asm/btext.h> | ||
68 | #include <asm/cputable.h> | ||
69 | #include <asm/pmac_feature.h> | ||
70 | #include <asm/time.h> | ||
71 | #include <asm/of_device.h> | ||
72 | #include <asm/lmb.h> | ||
73 | #include <asm/smu.h> | ||
74 | #include <asm/pmc.h> | ||
75 | #include <asm/mpic.h> | ||
76 | #include <asm/udbg.h> | ||
77 | |||
78 | #include "pmac.h" | ||
79 | |||
80 | #ifdef DEBUG | ||
81 | #define DBG(fmt...) udbg_printf(fmt) | ||
82 | #else | ||
83 | #define DBG(fmt...) | ||
84 | #endif | ||
85 | |||
86 | static int current_root_goodness = -1; | ||
87 | #define DEFAULT_ROOT_DEVICE Root_SDA1 /* sda1 - slightly silly choice */ | ||
88 | |||
89 | extern int powersave_nap; | ||
90 | int sccdbg; | ||
91 | |||
92 | sys_ctrler_t sys_ctrler; | ||
93 | EXPORT_SYMBOL(sys_ctrler); | ||
94 | |||
95 | #ifdef CONFIG_PMAC_SMU | ||
96 | unsigned long smu_cmdbuf_abs; | ||
97 | EXPORT_SYMBOL(smu_cmdbuf_abs); | ||
98 | #endif | ||
99 | |||
100 | extern void udbg_init_scc(struct device_node *np); | ||
101 | |||
102 | static void pmac_show_cpuinfo(struct seq_file *m) | ||
103 | { | ||
104 | struct device_node *np; | ||
105 | char *pp; | ||
106 | int plen; | ||
107 | char* mbname; | ||
108 | int mbmodel = pmac_call_feature(PMAC_FTR_GET_MB_INFO, NULL, | ||
109 | PMAC_MB_INFO_MODEL, 0); | ||
110 | unsigned int mbflags = pmac_call_feature(PMAC_FTR_GET_MB_INFO, NULL, | ||
111 | PMAC_MB_INFO_FLAGS, 0); | ||
112 | |||
113 | if (pmac_call_feature(PMAC_FTR_GET_MB_INFO, NULL, PMAC_MB_INFO_NAME, | ||
114 | (long)&mbname) != 0) | ||
115 | mbname = "Unknown"; | ||
116 | |||
117 | /* find motherboard type */ | ||
118 | seq_printf(m, "machine\t\t: "); | ||
119 | np = find_devices("device-tree"); | ||
120 | if (np != NULL) { | ||
121 | pp = (char *) get_property(np, "model", NULL); | ||
122 | if (pp != NULL) | ||
123 | seq_printf(m, "%s\n", pp); | ||
124 | else | ||
125 | seq_printf(m, "PowerMac\n"); | ||
126 | pp = (char *) get_property(np, "compatible", &plen); | ||
127 | if (pp != NULL) { | ||
128 | seq_printf(m, "motherboard\t:"); | ||
129 | while (plen > 0) { | ||
130 | int l = strlen(pp) + 1; | ||
131 | seq_printf(m, " %s", pp); | ||
132 | plen -= l; | ||
133 | pp += l; | ||
134 | } | ||
135 | seq_printf(m, "\n"); | ||
136 | } | ||
137 | } else | ||
138 | seq_printf(m, "PowerMac\n"); | ||
139 | |||
140 | /* print parsed model */ | ||
141 | seq_printf(m, "detected as\t: %d (%s)\n", mbmodel, mbname); | ||
142 | seq_printf(m, "pmac flags\t: %08x\n", mbflags); | ||
143 | |||
144 | /* Indicate newworld */ | ||
145 | seq_printf(m, "pmac-generation\t: NewWorld\n"); | ||
146 | } | ||
147 | |||
148 | |||
149 | static void __init pmac_setup_arch(void) | ||
150 | { | ||
151 | /* init to some ~sane value until calibrate_delay() runs */ | ||
152 | loops_per_jiffy = 50000000; | ||
153 | |||
154 | /* Probe motherboard chipset */ | ||
155 | pmac_feature_init(); | ||
156 | #if 0 | ||
157 | /* Lock-enable the SCC channel used for debug */ | ||
158 | if (sccdbg) { | ||
159 | np = of_find_node_by_name(NULL, "escc"); | ||
160 | if (np) | ||
161 | pmac_call_feature(PMAC_FTR_SCC_ENABLE, np, | ||
162 | PMAC_SCC_ASYNC | PMAC_SCC_FLAG_XMON, 1); | ||
163 | } | ||
164 | #endif | ||
165 | /* We can NAP */ | ||
166 | powersave_nap = 1; | ||
167 | |||
168 | #ifdef CONFIG_ADB_PMU | ||
169 | /* Initialize the PMU if any */ | ||
170 | find_via_pmu(); | ||
171 | #endif | ||
172 | #ifdef CONFIG_PMAC_SMU | ||
173 | /* Initialize the SMU if any */ | ||
174 | smu_init(); | ||
175 | #endif | ||
176 | |||
177 | /* Init NVRAM access */ | ||
178 | pmac_nvram_init(); | ||
179 | |||
180 | /* Setup SMP callback */ | ||
181 | #ifdef CONFIG_SMP | ||
182 | pmac_setup_smp(); | ||
183 | #endif | ||
184 | |||
185 | /* Lookup PCI hosts */ | ||
186 | pmac_pci_init(); | ||
187 | |||
188 | #ifdef CONFIG_DUMMY_CONSOLE | ||
189 | conswitchp = &dummy_con; | ||
190 | #endif | ||
191 | |||
192 | printk(KERN_INFO "Using native/NAP idle loop\n"); | ||
193 | } | ||
194 | |||
195 | #ifdef CONFIG_SCSI | ||
196 | void note_scsi_host(struct device_node *node, void *host) | ||
197 | { | ||
198 | /* Obsolete */ | ||
199 | } | ||
200 | #endif | ||
201 | |||
202 | |||
203 | static int initializing = 1; | ||
204 | |||
205 | static int pmac_late_init(void) | ||
206 | { | ||
207 | initializing = 0; | ||
208 | return 0; | ||
209 | } | ||
210 | |||
211 | late_initcall(pmac_late_init); | ||
212 | |||
213 | /* can't be __init - can be called whenever a disk is first accessed */ | ||
214 | void note_bootable_part(dev_t dev, int part, int goodness) | ||
215 | { | ||
216 | extern dev_t boot_dev; | ||
217 | char *p; | ||
218 | |||
219 | if (!initializing) | ||
220 | return; | ||
221 | if ((goodness <= current_root_goodness) && | ||
222 | ROOT_DEV != DEFAULT_ROOT_DEVICE) | ||
223 | return; | ||
224 | p = strstr(saved_command_line, "root="); | ||
225 | if (p != NULL && (p == saved_command_line || p[-1] == ' ')) | ||
226 | return; | ||
227 | |||
228 | if (!boot_dev || dev == boot_dev) { | ||
229 | ROOT_DEV = dev + part; | ||
230 | boot_dev = 0; | ||
231 | current_root_goodness = goodness; | ||
232 | } | ||
233 | } | ||
234 | |||
235 | static void pmac_restart(char *cmd) | ||
236 | { | ||
237 | switch(sys_ctrler) { | ||
238 | #ifdef CONFIG_ADB_PMU | ||
239 | case SYS_CTRLER_PMU: | ||
240 | pmu_restart(); | ||
241 | break; | ||
242 | #endif | ||
243 | |||
244 | #ifdef CONFIG_PMAC_SMU | ||
245 | case SYS_CTRLER_SMU: | ||
246 | smu_restart(); | ||
247 | break; | ||
248 | #endif | ||
249 | default: | ||
250 | ; | ||
251 | } | ||
252 | } | ||
253 | |||
254 | static void pmac_power_off(void) | ||
255 | { | ||
256 | switch(sys_ctrler) { | ||
257 | #ifdef CONFIG_ADB_PMU | ||
258 | case SYS_CTRLER_PMU: | ||
259 | pmu_shutdown(); | ||
260 | break; | ||
261 | #endif | ||
262 | #ifdef CONFIG_PMAC_SMU | ||
263 | case SYS_CTRLER_SMU: | ||
264 | smu_shutdown(); | ||
265 | break; | ||
266 | #endif | ||
267 | default: | ||
268 | ; | ||
269 | } | ||
270 | } | ||
271 | |||
272 | static void pmac_halt(void) | ||
273 | { | ||
274 | pmac_power_off(); | ||
275 | } | ||
276 | |||
277 | /* | ||
278 | * Early initialization. | ||
279 | */ | ||
280 | static void __init pmac_init_early(void) | ||
281 | { | ||
282 | DBG(" -> pmac_init_early\n"); | ||
283 | |||
284 | /* Initialize hash table, from now on, we can take hash faults | ||
285 | * and call ioremap | ||
286 | */ | ||
287 | hpte_init_native(); | ||
288 | |||
289 | /* Init SCC */ | ||
290 | if (strstr(cmd_line, "sccdbg")) { | ||
291 | sccdbg = 1; | ||
292 | udbg_init_scc(NULL); | ||
293 | } | ||
294 | |||
295 | /* Setup interrupt mapping options */ | ||
296 | ppc64_interrupt_controller = IC_OPEN_PIC; | ||
297 | |||
298 | iommu_init_early_u3(); | ||
299 | |||
300 | DBG(" <- pmac_init_early\n"); | ||
301 | } | ||
302 | |||
303 | static int pmac_u3_cascade(struct pt_regs *regs, void *data) | ||
304 | { | ||
305 | return mpic_get_one_irq((struct mpic *)data, regs); | ||
306 | } | ||
307 | |||
308 | static __init void pmac_init_IRQ(void) | ||
309 | { | ||
310 | struct device_node *irqctrler = NULL; | ||
311 | struct device_node *irqctrler2 = NULL; | ||
312 | struct device_node *np = NULL; | ||
313 | struct mpic *mpic1, *mpic2; | ||
314 | |||
315 | /* We first try to detect Apple's new Core99 chipset, since mac-io | ||
316 | * is quite different on those machines and contains an IBM MPIC2. | ||
317 | */ | ||
318 | while ((np = of_find_node_by_type(np, "open-pic")) != NULL) { | ||
319 | struct device_node *parent = of_get_parent(np); | ||
320 | if (parent && !strcmp(parent->name, "u3")) | ||
321 | irqctrler2 = of_node_get(np); | ||
322 | else | ||
323 | irqctrler = of_node_get(np); | ||
324 | of_node_put(parent); | ||
325 | } | ||
326 | if (irqctrler != NULL && irqctrler->n_addrs > 0) { | ||
327 | unsigned char senses[128]; | ||
328 | |||
329 | printk(KERN_INFO "PowerMac using OpenPIC irq controller at 0x%08x\n", | ||
330 | (unsigned int)irqctrler->addrs[0].address); | ||
331 | |||
332 | prom_get_irq_senses(senses, 0, 128); | ||
333 | mpic1 = mpic_alloc(irqctrler->addrs[0].address, | ||
334 | MPIC_PRIMARY | MPIC_WANTS_RESET, | ||
335 | 0, 0, 128, 256, senses, 128, " K2-MPIC "); | ||
336 | BUG_ON(mpic1 == NULL); | ||
337 | mpic_init(mpic1); | ||
338 | |||
339 | if (irqctrler2 != NULL && irqctrler2->n_intrs > 0 && | ||
340 | irqctrler2->n_addrs > 0) { | ||
341 | printk(KERN_INFO "Slave OpenPIC at 0x%08x hooked on IRQ %d\n", | ||
342 | (u32)irqctrler2->addrs[0].address, | ||
343 | irqctrler2->intrs[0].line); | ||
344 | |||
345 | pmac_call_feature(PMAC_FTR_ENABLE_MPIC, irqctrler2, 0, 0); | ||
346 | prom_get_irq_senses(senses, 128, 128 + 128); | ||
347 | |||
348 | /* We don't need to set MPIC_BROKEN_U3 here since we don't have | ||
349 | * hypertransport interrupts routed to it | ||
350 | */ | ||
351 | mpic2 = mpic_alloc(irqctrler2->addrs[0].address, | ||
352 | MPIC_BIG_ENDIAN | MPIC_WANTS_RESET, | ||
353 | 0, 128, 128, 0, senses, 128, " U3-MPIC "); | ||
354 | BUG_ON(mpic2 == NULL); | ||
355 | mpic_init(mpic2); | ||
356 | mpic_setup_cascade(irqctrler2->intrs[0].line, | ||
357 | pmac_u3_cascade, mpic2); | ||
358 | } | ||
359 | } | ||
360 | of_node_put(irqctrler); | ||
361 | of_node_put(irqctrler2); | ||
362 | } | ||
363 | |||
364 | static void __init pmac_progress(char *s, unsigned short hex) | ||
365 | { | ||
366 | if (sccdbg) { | ||
367 | udbg_puts(s); | ||
368 | udbg_puts("\n"); | ||
369 | } | ||
370 | #ifdef CONFIG_BOOTX_TEXT | ||
371 | else if (boot_text_mapped) { | ||
372 | btext_drawstring(s); | ||
373 | btext_drawstring("\n"); | ||
374 | } | ||
375 | #endif /* CONFIG_BOOTX_TEXT */ | ||
376 | } | ||
377 | |||
378 | /* | ||
379 | * pmac has no legacy IO, anything calling this function has to | ||
380 | * fail or bad things will happen | ||
381 | */ | ||
382 | static int pmac_check_legacy_ioport(unsigned int baseport) | ||
383 | { | ||
384 | return -ENODEV; | ||
385 | } | ||
386 | |||
387 | static int __init pmac_declare_of_platform_devices(void) | ||
388 | { | ||
389 | struct device_node *np, *npp; | ||
390 | |||
391 | npp = of_find_node_by_name(NULL, "u3"); | ||
392 | if (npp) { | ||
393 | for (np = NULL; (np = of_get_next_child(npp, np)) != NULL;) { | ||
394 | if (strncmp(np->name, "i2c", 3) == 0) { | ||
395 | of_platform_device_create(np, "u3-i2c", NULL); | ||
396 | of_node_put(np); | ||
397 | break; | ||
398 | } | ||
399 | } | ||
400 | of_node_put(npp); | ||
401 | } | ||
402 | npp = of_find_node_by_type(NULL, "smu"); | ||
403 | if (npp) { | ||
404 | of_platform_device_create(npp, "smu", NULL); | ||
405 | of_node_put(npp); | ||
406 | } | ||
407 | |||
408 | return 0; | ||
409 | } | ||
410 | |||
411 | device_initcall(pmac_declare_of_platform_devices); | ||
412 | |||
413 | /* | ||
414 | * Called very early, MMU is off, device-tree isn't unflattened | ||
415 | */ | ||
416 | static int __init pmac_probe(int platform) | ||
417 | { | ||
418 | if (platform != PLATFORM_POWERMAC) | ||
419 | return 0; | ||
420 | /* | ||
421 | * On U3, the DART (iommu) must be allocated now since it | ||
422 | * has an impact on htab_initialize (due to the large page it | ||
423 | * occupies having to be broken up so the DART itself is not | ||
424 | * part of the cacheable linar mapping | ||
425 | */ | ||
426 | alloc_u3_dart_table(); | ||
427 | |||
428 | #ifdef CONFIG_PMAC_SMU | ||
429 | /* | ||
430 | * SMU based G5s need some memory below 2Gb, at least the current | ||
431 | * driver needs that. We have to allocate it now. We allocate 4k | ||
432 | * (1 small page) for now. | ||
433 | */ | ||
434 | smu_cmdbuf_abs = lmb_alloc_base(4096, 4096, 0x80000000UL); | ||
435 | #endif /* CONFIG_PMAC_SMU */ | ||
436 | |||
437 | return 1; | ||
438 | } | ||
439 | |||
440 | static int pmac_probe_mode(struct pci_bus *bus) | ||
441 | { | ||
442 | struct device_node *node = bus->sysdata; | ||
443 | |||
444 | /* We need to use normal PCI probing for the AGP bus, | ||
445 | since the device for the AGP bridge isn't in the tree. */ | ||
446 | if (bus->self == NULL && device_is_compatible(node, "u3-agp")) | ||
447 | return PCI_PROBE_NORMAL; | ||
448 | |||
449 | return PCI_PROBE_DEVTREE; | ||
450 | } | ||
451 | |||
452 | struct machdep_calls __initdata pmac_md = { | ||
453 | #ifdef CONFIG_HOTPLUG_CPU | ||
454 | .cpu_die = generic_mach_cpu_die, | ||
455 | #endif | ||
456 | .probe = pmac_probe, | ||
457 | .setup_arch = pmac_setup_arch, | ||
458 | .init_early = pmac_init_early, | ||
459 | .show_cpuinfo = pmac_show_cpuinfo, | ||
460 | .init_IRQ = pmac_init_IRQ, | ||
461 | .get_irq = mpic_get_irq, | ||
462 | .pcibios_fixup = pmac_pcibios_fixup, | ||
463 | .pci_probe_mode = pmac_probe_mode, | ||
464 | .restart = pmac_restart, | ||
465 | .power_off = pmac_power_off, | ||
466 | .halt = pmac_halt, | ||
467 | .get_boot_time = pmac_get_boot_time, | ||
468 | .set_rtc_time = pmac_set_rtc_time, | ||
469 | .get_rtc_time = pmac_get_rtc_time, | ||
470 | .calibrate_decr = pmac_calibrate_decr, | ||
471 | .feature_call = pmac_do_feature_call, | ||
472 | .progress = pmac_progress, | ||
473 | .check_legacy_ioport = pmac_check_legacy_ioport, | ||
474 | .idle_loop = native_idle, | ||
475 | .enable_pmcs = power4_enable_pmcs, | ||
476 | }; | ||
diff --git a/arch/ppc64/kernel/pmac_smp.c b/arch/ppc64/kernel/pmac_smp.c deleted file mode 100644 index 83c2f8dc1ec6..000000000000 --- a/arch/ppc64/kernel/pmac_smp.c +++ /dev/null | |||
@@ -1,316 +0,0 @@ | |||
1 | /* | ||
2 | * SMP support for power macintosh. | ||
3 | * | ||
4 | * We support both the old "powersurge" SMP architecture | ||
5 | * and the current Core99 (G4 PowerMac) machines. | ||
6 | * | ||
7 | * Note that we don't support the very first rev. of | ||
8 | * Apple/DayStar 2 CPUs board, the one with the funky | ||
9 | * watchdog. Hopefully, none of these should be there except | ||
10 | * maybe internally to Apple. I should probably still add some | ||
11 | * code to detect this card though and disable SMP. --BenH. | ||
12 | * | ||
13 | * Support Macintosh G4 SMP by Troy Benjegerdes (hozer@drgw.net) | ||
14 | * and Ben Herrenschmidt <benh@kernel.crashing.org>. | ||
15 | * | ||
16 | * Support for DayStar quad CPU cards | ||
17 | * Copyright (C) XLR8, Inc. 1994-2000 | ||
18 | * | ||
19 | * This program is free software; you can redistribute it and/or | ||
20 | * modify it under the terms of the GNU General Public License | ||
21 | * as published by the Free Software Foundation; either version | ||
22 | * 2 of the License, or (at your option) any later version. | ||
23 | */ | ||
24 | |||
25 | #undef DEBUG | ||
26 | |||
27 | #include <linux/config.h> | ||
28 | #include <linux/kernel.h> | ||
29 | #include <linux/sched.h> | ||
30 | #include <linux/smp.h> | ||
31 | #include <linux/smp_lock.h> | ||
32 | #include <linux/interrupt.h> | ||
33 | #include <linux/kernel_stat.h> | ||
34 | #include <linux/init.h> | ||
35 | #include <linux/spinlock.h> | ||
36 | #include <linux/errno.h> | ||
37 | #include <linux/irq.h> | ||
38 | |||
39 | #include <asm/ptrace.h> | ||
40 | #include <asm/atomic.h> | ||
41 | #include <asm/irq.h> | ||
42 | #include <asm/page.h> | ||
43 | #include <asm/pgtable.h> | ||
44 | #include <asm/sections.h> | ||
45 | #include <asm/io.h> | ||
46 | #include <asm/prom.h> | ||
47 | #include <asm/smp.h> | ||
48 | #include <asm/machdep.h> | ||
49 | #include <asm/pmac_feature.h> | ||
50 | #include <asm/time.h> | ||
51 | #include <asm/cacheflush.h> | ||
52 | #include <asm/keylargo.h> | ||
53 | #include <asm/pmac_low_i2c.h> | ||
54 | #include <asm/mpic.h> | ||
55 | |||
56 | #ifdef DEBUG | ||
57 | #define DBG(fmt...) udbg_printf(fmt) | ||
58 | #else | ||
59 | #define DBG(fmt...) | ||
60 | #endif | ||
61 | |||
62 | extern void __secondary_start_pmac_0(void); | ||
63 | |||
64 | extern struct smp_ops_t *smp_ops; | ||
65 | |||
66 | static void (*pmac_tb_freeze)(int freeze); | ||
67 | static struct device_node *pmac_tb_clock_chip_host; | ||
68 | static u8 pmac_tb_pulsar_addr; | ||
69 | static DEFINE_SPINLOCK(timebase_lock); | ||
70 | static unsigned long timebase; | ||
71 | |||
72 | static void smp_core99_cypress_tb_freeze(int freeze) | ||
73 | { | ||
74 | u8 data; | ||
75 | int rc; | ||
76 | |||
77 | /* Strangely, the device-tree says address is 0xd2, but darwin | ||
78 | * accesses 0xd0 ... | ||
79 | */ | ||
80 | pmac_low_i2c_setmode(pmac_tb_clock_chip_host, pmac_low_i2c_mode_combined); | ||
81 | rc = pmac_low_i2c_xfer(pmac_tb_clock_chip_host, | ||
82 | 0xd0 | pmac_low_i2c_read, | ||
83 | 0x81, &data, 1); | ||
84 | if (rc != 0) | ||
85 | goto bail; | ||
86 | |||
87 | data = (data & 0xf3) | (freeze ? 0x00 : 0x0c); | ||
88 | |||
89 | pmac_low_i2c_setmode(pmac_tb_clock_chip_host, pmac_low_i2c_mode_stdsub); | ||
90 | rc = pmac_low_i2c_xfer(pmac_tb_clock_chip_host, | ||
91 | 0xd0 | pmac_low_i2c_write, | ||
92 | 0x81, &data, 1); | ||
93 | |||
94 | bail: | ||
95 | if (rc != 0) { | ||
96 | printk("Cypress Timebase %s rc: %d\n", | ||
97 | freeze ? "freeze" : "unfreeze", rc); | ||
98 | panic("Timebase freeze failed !\n"); | ||
99 | } | ||
100 | } | ||
101 | |||
102 | static void smp_core99_pulsar_tb_freeze(int freeze) | ||
103 | { | ||
104 | u8 data; | ||
105 | int rc; | ||
106 | |||
107 | pmac_low_i2c_setmode(pmac_tb_clock_chip_host, pmac_low_i2c_mode_combined); | ||
108 | rc = pmac_low_i2c_xfer(pmac_tb_clock_chip_host, | ||
109 | pmac_tb_pulsar_addr | pmac_low_i2c_read, | ||
110 | 0x2e, &data, 1); | ||
111 | if (rc != 0) | ||
112 | goto bail; | ||
113 | |||
114 | data = (data & 0x88) | (freeze ? 0x11 : 0x22); | ||
115 | |||
116 | pmac_low_i2c_setmode(pmac_tb_clock_chip_host, pmac_low_i2c_mode_stdsub); | ||
117 | rc = pmac_low_i2c_xfer(pmac_tb_clock_chip_host, | ||
118 | pmac_tb_pulsar_addr | pmac_low_i2c_write, | ||
119 | 0x2e, &data, 1); | ||
120 | bail: | ||
121 | if (rc != 0) { | ||
122 | printk(KERN_ERR "Pulsar Timebase %s rc: %d\n", | ||
123 | freeze ? "freeze" : "unfreeze", rc); | ||
124 | panic("Timebase freeze failed !\n"); | ||
125 | } | ||
126 | } | ||
127 | |||
128 | |||
129 | static void smp_core99_give_timebase(void) | ||
130 | { | ||
131 | /* Open i2c bus for synchronous access */ | ||
132 | if (pmac_low_i2c_open(pmac_tb_clock_chip_host, 0)) | ||
133 | panic("Can't open i2c for TB sync !\n"); | ||
134 | |||
135 | spin_lock(&timebase_lock); | ||
136 | (*pmac_tb_freeze)(1); | ||
137 | mb(); | ||
138 | timebase = get_tb(); | ||
139 | spin_unlock(&timebase_lock); | ||
140 | |||
141 | while (timebase) | ||
142 | barrier(); | ||
143 | |||
144 | spin_lock(&timebase_lock); | ||
145 | (*pmac_tb_freeze)(0); | ||
146 | spin_unlock(&timebase_lock); | ||
147 | |||
148 | /* Close i2c bus */ | ||
149 | pmac_low_i2c_close(pmac_tb_clock_chip_host); | ||
150 | } | ||
151 | |||
152 | |||
153 | static void __devinit smp_core99_take_timebase(void) | ||
154 | { | ||
155 | while (!timebase) | ||
156 | barrier(); | ||
157 | spin_lock(&timebase_lock); | ||
158 | set_tb(timebase >> 32, timebase & 0xffffffff); | ||
159 | timebase = 0; | ||
160 | spin_unlock(&timebase_lock); | ||
161 | } | ||
162 | |||
163 | |||
164 | static int __init smp_core99_probe(void) | ||
165 | { | ||
166 | struct device_node *cpus; | ||
167 | struct device_node *cc; | ||
168 | int ncpus = 0; | ||
169 | |||
170 | /* Maybe use systemconfiguration here ? */ | ||
171 | if (ppc_md.progress) ppc_md.progress("smp_core99_probe", 0x345); | ||
172 | |||
173 | /* Count CPUs in the device-tree */ | ||
174 | for (cpus = NULL; (cpus = of_find_node_by_type(cpus, "cpu")) != NULL;) | ||
175 | ++ncpus; | ||
176 | |||
177 | printk(KERN_INFO "PowerMac SMP probe found %d cpus\n", ncpus); | ||
178 | |||
179 | /* Nothing more to do if less than 2 of them */ | ||
180 | if (ncpus <= 1) | ||
181 | return 1; | ||
182 | |||
183 | /* HW sync only on these platforms */ | ||
184 | if (!machine_is_compatible("PowerMac7,2") && | ||
185 | !machine_is_compatible("PowerMac7,3") && | ||
186 | !machine_is_compatible("RackMac3,1")) | ||
187 | goto nohwsync; | ||
188 | |||
189 | /* Look for the clock chip */ | ||
190 | for (cc = NULL; (cc = of_find_node_by_name(cc, "i2c-hwclock")) != NULL;) { | ||
191 | struct device_node *p = of_get_parent(cc); | ||
192 | u32 *reg; | ||
193 | int ok; | ||
194 | ok = p && device_is_compatible(p, "uni-n-i2c"); | ||
195 | if (!ok) | ||
196 | goto next; | ||
197 | reg = (u32 *)get_property(cc, "reg", NULL); | ||
198 | if (reg == NULL) | ||
199 | goto next; | ||
200 | switch (*reg) { | ||
201 | case 0xd2: | ||
202 | if (device_is_compatible(cc, "pulsar-legacy-slewing")) { | ||
203 | pmac_tb_freeze = smp_core99_pulsar_tb_freeze; | ||
204 | pmac_tb_pulsar_addr = 0xd2; | ||
205 | printk(KERN_INFO "Timebase clock is Pulsar chip\n"); | ||
206 | } else if (device_is_compatible(cc, "cy28508")) { | ||
207 | pmac_tb_freeze = smp_core99_cypress_tb_freeze; | ||
208 | printk(KERN_INFO "Timebase clock is Cypress chip\n"); | ||
209 | } | ||
210 | break; | ||
211 | case 0xd4: | ||
212 | pmac_tb_freeze = smp_core99_pulsar_tb_freeze; | ||
213 | pmac_tb_pulsar_addr = 0xd4; | ||
214 | printk(KERN_INFO "Timebase clock is Pulsar chip\n"); | ||
215 | break; | ||
216 | } | ||
217 | if (pmac_tb_freeze != NULL) { | ||
218 | pmac_tb_clock_chip_host = p; | ||
219 | smp_ops->give_timebase = smp_core99_give_timebase; | ||
220 | smp_ops->take_timebase = smp_core99_take_timebase; | ||
221 | of_node_put(cc); | ||
222 | of_node_put(p); | ||
223 | break; | ||
224 | } | ||
225 | next: | ||
226 | of_node_put(p); | ||
227 | } | ||
228 | |||
229 | nohwsync: | ||
230 | mpic_request_ipis(); | ||
231 | |||
232 | return ncpus; | ||
233 | } | ||
234 | |||
235 | static void __init smp_core99_kick_cpu(int nr) | ||
236 | { | ||
237 | unsigned int save_vector, j; | ||
238 | unsigned long new_vector; | ||
239 | unsigned long flags; | ||
240 | volatile unsigned int *vector | ||
241 | = ((volatile unsigned int *)(KERNELBASE+0x100)); | ||
242 | |||
243 | if (nr < 1 || nr > 3) | ||
244 | return; | ||
245 | if (ppc_md.progress) ppc_md.progress("smp_core99_kick_cpu", 0x346); | ||
246 | |||
247 | local_irq_save(flags); | ||
248 | local_irq_disable(); | ||
249 | |||
250 | /* Save reset vector */ | ||
251 | save_vector = *vector; | ||
252 | |||
253 | /* Setup fake reset vector that does | ||
254 | * b __secondary_start_pmac_0 + nr*8 - KERNELBASE | ||
255 | */ | ||
256 | new_vector = (unsigned long) __secondary_start_pmac_0 + nr * 8; | ||
257 | *vector = 0x48000002 + (new_vector - KERNELBASE); | ||
258 | |||
259 | /* flush data cache and inval instruction cache */ | ||
260 | flush_icache_range((unsigned long) vector, (unsigned long) vector + 4); | ||
261 | |||
262 | /* Put some life in our friend */ | ||
263 | pmac_call_feature(PMAC_FTR_RESET_CPU, NULL, nr, 0); | ||
264 | paca[nr].cpu_start = 1; | ||
265 | |||
266 | /* FIXME: We wait a bit for the CPU to take the exception, I should | ||
267 | * instead wait for the entry code to set something for me. Well, | ||
268 | * ideally, all that crap will be done in prom.c and the CPU left | ||
269 | * in a RAM-based wait loop like CHRP. | ||
270 | */ | ||
271 | for (j = 1; j < 1000000; j++) | ||
272 | mb(); | ||
273 | |||
274 | /* Restore our exception vector */ | ||
275 | *vector = save_vector; | ||
276 | flush_icache_range((unsigned long) vector, (unsigned long) vector + 4); | ||
277 | |||
278 | local_irq_restore(flags); | ||
279 | if (ppc_md.progress) ppc_md.progress("smp_core99_kick_cpu done", 0x347); | ||
280 | } | ||
281 | |||
282 | static void __init smp_core99_setup_cpu(int cpu_nr) | ||
283 | { | ||
284 | /* Setup MPIC */ | ||
285 | mpic_setup_this_cpu(); | ||
286 | |||
287 | if (cpu_nr == 0) { | ||
288 | extern void g5_phy_disable_cpu1(void); | ||
289 | |||
290 | /* If we didn't start the second CPU, we must take | ||
291 | * it off the bus | ||
292 | */ | ||
293 | if (num_online_cpus() < 2) | ||
294 | g5_phy_disable_cpu1(); | ||
295 | if (ppc_md.progress) ppc_md.progress("smp_core99_setup_cpu 0 done", 0x349); | ||
296 | } | ||
297 | } | ||
298 | |||
299 | struct smp_ops_t core99_smp_ops = { | ||
300 | .message_pass = smp_mpic_message_pass, | ||
301 | .probe = smp_core99_probe, | ||
302 | .kick_cpu = smp_core99_kick_cpu, | ||
303 | .setup_cpu = smp_core99_setup_cpu, | ||
304 | .give_timebase = smp_generic_give_timebase, | ||
305 | .take_timebase = smp_generic_take_timebase, | ||
306 | }; | ||
307 | |||
308 | void __init pmac_setup_smp(void) | ||
309 | { | ||
310 | smp_ops = &core99_smp_ops; | ||
311 | #ifdef CONFIG_HOTPLUG_CPU | ||
312 | smp_ops->cpu_enable = generic_cpu_enable; | ||
313 | smp_ops->cpu_disable = generic_cpu_disable; | ||
314 | smp_ops->cpu_die = generic_cpu_die; | ||
315 | #endif | ||
316 | } | ||
diff --git a/arch/ppc64/kernel/pmac_time.c b/arch/ppc64/kernel/pmac_time.c deleted file mode 100644 index 928bf213ec4e..000000000000 --- a/arch/ppc64/kernel/pmac_time.c +++ /dev/null | |||
@@ -1,174 +0,0 @@ | |||
1 | /* | ||
2 | * Support for periodic interrupts (100 per second) and for getting | ||
3 | * the current time from the RTC on Power Macintoshes. | ||
4 | * | ||
5 | * We use the decrementer register for our periodic interrupts. | ||
6 | * | ||
7 | * Paul Mackerras August 1996. | ||
8 | * Copyright (C) 1996 Paul Mackerras. | ||
9 | * Copyright (C) 2003-2005 Benjamin Herrenschmidt. | ||
10 | * | ||
11 | */ | ||
12 | #include <linux/config.h> | ||
13 | #include <linux/errno.h> | ||
14 | #include <linux/sched.h> | ||
15 | #include <linux/kernel.h> | ||
16 | #include <linux/param.h> | ||
17 | #include <linux/string.h> | ||
18 | #include <linux/mm.h> | ||
19 | #include <linux/init.h> | ||
20 | #include <linux/time.h> | ||
21 | #include <linux/adb.h> | ||
22 | #include <linux/pmu.h> | ||
23 | #include <linux/interrupt.h> | ||
24 | #include <linux/rtc.h> | ||
25 | |||
26 | #include <asm/sections.h> | ||
27 | #include <asm/prom.h> | ||
28 | #include <asm/system.h> | ||
29 | #include <asm/io.h> | ||
30 | #include <asm/pgtable.h> | ||
31 | #include <asm/machdep.h> | ||
32 | #include <asm/time.h> | ||
33 | #include <asm/nvram.h> | ||
34 | #include <asm/smu.h> | ||
35 | |||
36 | #undef DEBUG | ||
37 | |||
38 | #ifdef DEBUG | ||
39 | #define DBG(x...) printk(x) | ||
40 | #else | ||
41 | #define DBG(x...) | ||
42 | #endif | ||
43 | |||
44 | /* Apparently the RTC stores seconds since 1 Jan 1904 */ | ||
45 | #define RTC_OFFSET 2082844800 | ||
46 | |||
47 | /* | ||
48 | * Calibrate the decrementer frequency with the VIA timer 1. | ||
49 | */ | ||
50 | #define VIA_TIMER_FREQ_6 4700000 /* time 1 frequency * 6 */ | ||
51 | |||
52 | extern struct timezone sys_tz; | ||
53 | extern void to_tm(int tim, struct rtc_time * tm); | ||
54 | |||
55 | void pmac_get_rtc_time(struct rtc_time *tm) | ||
56 | { | ||
57 | switch(sys_ctrler) { | ||
58 | #ifdef CONFIG_ADB_PMU | ||
59 | case SYS_CTRLER_PMU: { | ||
60 | /* TODO: Move that to a function in the PMU driver */ | ||
61 | struct adb_request req; | ||
62 | unsigned int now; | ||
63 | |||
64 | if (pmu_request(&req, NULL, 1, PMU_READ_RTC) < 0) | ||
65 | return; | ||
66 | pmu_wait_complete(&req); | ||
67 | if (req.reply_len != 4) | ||
68 | printk(KERN_ERR "pmac_get_rtc_time: PMU returned a %d" | ||
69 | " bytes reply\n", req.reply_len); | ||
70 | now = (req.reply[0] << 24) + (req.reply[1] << 16) | ||
71 | + (req.reply[2] << 8) + req.reply[3]; | ||
72 | DBG("get: %u -> %u\n", (int)now, (int)(now - RTC_OFFSET)); | ||
73 | now -= RTC_OFFSET; | ||
74 | |||
75 | to_tm(now, tm); | ||
76 | tm->tm_year -= 1900; | ||
77 | tm->tm_mon -= 1; | ||
78 | |||
79 | DBG("-> tm_mday: %d, tm_mon: %d, tm_year: %d, %d:%02d:%02d\n", | ||
80 | tm->tm_mday, tm->tm_mon, tm->tm_year, | ||
81 | tm->tm_hour, tm->tm_min, tm->tm_sec); | ||
82 | break; | ||
83 | } | ||
84 | #endif /* CONFIG_ADB_PMU */ | ||
85 | |||
86 | #ifdef CONFIG_PMAC_SMU | ||
87 | case SYS_CTRLER_SMU: | ||
88 | smu_get_rtc_time(tm, 1); | ||
89 | break; | ||
90 | #endif /* CONFIG_PMAC_SMU */ | ||
91 | default: | ||
92 | ; | ||
93 | } | ||
94 | } | ||
95 | |||
96 | int pmac_set_rtc_time(struct rtc_time *tm) | ||
97 | { | ||
98 | switch(sys_ctrler) { | ||
99 | #ifdef CONFIG_ADB_PMU | ||
100 | case SYS_CTRLER_PMU: { | ||
101 | /* TODO: Move that to a function in the PMU driver */ | ||
102 | struct adb_request req; | ||
103 | unsigned int nowtime; | ||
104 | |||
105 | DBG("set: tm_mday: %d, tm_mon: %d, tm_year: %d," | ||
106 | " %d:%02d:%02d\n", | ||
107 | tm->tm_mday, tm->tm_mon, tm->tm_year, | ||
108 | tm->tm_hour, tm->tm_min, tm->tm_sec); | ||
109 | |||
110 | nowtime = mktime(tm->tm_year + 1900, tm->tm_mon + 1, | ||
111 | tm->tm_mday, tm->tm_hour, tm->tm_min, | ||
112 | tm->tm_sec); | ||
113 | |||
114 | DBG("-> %u -> %u\n", (int)nowtime, | ||
115 | (int)(nowtime + RTC_OFFSET)); | ||
116 | nowtime += RTC_OFFSET; | ||
117 | |||
118 | if (pmu_request(&req, NULL, 5, PMU_SET_RTC, | ||
119 | nowtime >> 24, nowtime >> 16, | ||
120 | nowtime >> 8, nowtime) < 0) | ||
121 | return -ENXIO; | ||
122 | pmu_wait_complete(&req); | ||
123 | if (req.reply_len != 0) | ||
124 | printk(KERN_ERR "pmac_set_rtc_time: PMU returned a %d" | ||
125 | " bytes reply\n", req.reply_len); | ||
126 | return 0; | ||
127 | } | ||
128 | #endif /* CONFIG_ADB_PMU */ | ||
129 | |||
130 | #ifdef CONFIG_PMAC_SMU | ||
131 | case SYS_CTRLER_SMU: | ||
132 | return smu_set_rtc_time(tm, 1); | ||
133 | #endif /* CONFIG_PMAC_SMU */ | ||
134 | default: | ||
135 | return -ENODEV; | ||
136 | } | ||
137 | } | ||
138 | |||
139 | unsigned long __init pmac_get_boot_time(void) | ||
140 | { | ||
141 | struct rtc_time tm; | ||
142 | |||
143 | pmac_get_rtc_time(&tm); | ||
144 | return mktime(tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday, | ||
145 | tm.tm_hour, tm.tm_min, tm.tm_sec); | ||
146 | } | ||
147 | |||
148 | /* | ||
149 | * Query the OF and get the decr frequency. | ||
150 | * FIXME: merge this with generic_calibrate_decr | ||
151 | */ | ||
152 | void __init pmac_calibrate_decr(void) | ||
153 | { | ||
154 | struct device_node *cpu; | ||
155 | unsigned int *fp; | ||
156 | |||
157 | /* | ||
158 | * The cpu node should have a timebase-frequency property | ||
159 | * to tell us the rate at which the decrementer counts. | ||
160 | */ | ||
161 | cpu = find_type_devices("cpu"); | ||
162 | if (cpu == 0) | ||
163 | panic("can't find cpu node in time_init"); | ||
164 | fp = (unsigned int *) get_property(cpu, "timebase-frequency", NULL); | ||
165 | if (fp == 0) | ||
166 | panic("can't get cpu timebase frequency"); | ||
167 | ppc_tb_freq = *fp; | ||
168 | |||
169 | fp = (unsigned int *)get_property(cpu, "clock-frequency", NULL); | ||
170 | if (fp == 0) | ||
171 | panic("can't get cpu processor frequency"); | ||
172 | ppc_proc_freq = *fp; | ||
173 | } | ||
174 | |||