diff options
author | Paul Mackerras <paulus@samba.org> | 2005-10-22 02:02:39 -0400 |
---|---|---|
committer | Paul Mackerras <paulus@samba.org> | 2005-10-22 02:02:39 -0400 |
commit | 35499c0195e46f479cf6ac16ad8d3f394b5fcc10 (patch) | |
tree | 25660acd2425de5236a1eff7a25dc931e6f86492 /arch/powerpc/platforms/powermac | |
parent | b6ba92819dc1304a4e5a0bf06b297c657b58168a (diff) |
powerpc: Merge in 64-bit powermac support.
This brings in a lot of changes from arch/ppc64/kernel/pmac_*.c to
arch/powerpc/platforms/powermac/*.c and makes various minor tweaks
elsewhere. On the powermac we now initialize ppc_md by copying
the whole pmac_md structure into it, which required some changes in
the ordering of initializations of individual fields of it.
Signed-off-by: Paul Mackerras <paulus@samba.org>
Diffstat (limited to 'arch/powerpc/platforms/powermac')
-rw-r--r-- | arch/powerpc/platforms/powermac/Makefile | 6 | ||||
-rw-r--r-- | arch/powerpc/platforms/powermac/feature.c | 5 | ||||
-rw-r--r-- | arch/powerpc/platforms/powermac/nvram.c | 183 | ||||
-rw-r--r-- | arch/powerpc/platforms/powermac/pci.c | 472 | ||||
-rw-r--r-- | arch/powerpc/platforms/powermac/pic.c | 2 | ||||
-rw-r--r-- | arch/powerpc/platforms/powermac/pmac.h | 4 | ||||
-rw-r--r-- | arch/powerpc/platforms/powermac/setup.c | 458 | ||||
-rw-r--r-- | arch/powerpc/platforms/powermac/smp.c | 530 | ||||
-rw-r--r-- | arch/powerpc/platforms/powermac/time.c | 250 |
9 files changed, 1119 insertions, 791 deletions
diff --git a/arch/powerpc/platforms/powermac/Makefile b/arch/powerpc/platforms/powermac/Makefile index 74712ede16df..4369676f1d54 100644 --- a/arch/powerpc/platforms/powermac/Makefile +++ b/arch/powerpc/platforms/powermac/Makefile | |||
@@ -1,8 +1,8 @@ | |||
1 | obj-$(CONFIG_PPC_PMAC) += pic.o setup.o time.o feature.o pci.o \ | 1 | obj-y += pic.o setup.o time.o feature.o pci.o \ |
2 | sleep.o low_i2c.o cache.o | 2 | sleep.o low_i2c.o cache.o |
3 | obj-$(CONFIG_PMAC_BACKLIGHT) += backlight.o | 3 | obj-$(CONFIG_PMAC_BACKLIGHT) += backlight.o |
4 | obj-$(CONFIG_CPU_FREQ_PMAC) += cpufreq.o | 4 | obj-$(CONFIG_CPU_FREQ_PMAC) += cpufreq.o |
5 | ifeq ($(CONFIG_PPC_PMAC),y) | ||
6 | obj-$(CONFIG_NVRAM) += nvram.o | 5 | obj-$(CONFIG_NVRAM) += nvram.o |
6 | # ppc64 pmac doesn't define CONFIG_NVRAM but needs nvram stuff | ||
7 | obj-$(CONFIG_PPC64) += nvram.o | ||
7 | obj-$(CONFIG_SMP) += smp.o | 8 | obj-$(CONFIG_SMP) += smp.o |
8 | endif | ||
diff --git a/arch/powerpc/platforms/powermac/feature.c b/arch/powerpc/platforms/powermac/feature.c index 243a24fd025a..10f1d942c661 100644 --- a/arch/powerpc/platforms/powermac/feature.c +++ b/arch/powerpc/platforms/powermac/feature.c | |||
@@ -2960,7 +2960,6 @@ static void dump_HT_speeds(char *name, u32 cfg, u32 frq) | |||
2960 | 2960 | ||
2961 | void __init pmac_check_ht_link(void) | 2961 | void __init pmac_check_ht_link(void) |
2962 | { | 2962 | { |
2963 | #if 0 /* Disabled for now */ | ||
2964 | u32 ufreq, freq, ucfg, cfg; | 2963 | u32 ufreq, freq, ucfg, cfg; |
2965 | struct device_node *pcix_node; | 2964 | struct device_node *pcix_node; |
2966 | u8 px_bus, px_devfn; | 2965 | u8 px_bus, px_devfn; |
@@ -2991,10 +2990,8 @@ void __init pmac_check_ht_link(void) | |||
2991 | early_read_config_dword(px_hose, px_bus, px_devfn, 0xc8, &cfg); | 2990 | early_read_config_dword(px_hose, px_bus, px_devfn, 0xc8, &cfg); |
2992 | early_read_config_dword(px_hose, px_bus, px_devfn, 0xd0, &freq); | 2991 | early_read_config_dword(px_hose, px_bus, px_devfn, 0xd0, &freq); |
2993 | dump_HT_speeds("PCI-X HT Downlink", cfg, freq); | 2992 | dump_HT_speeds("PCI-X HT Downlink", cfg, freq); |
2994 | #endif | ||
2995 | } | 2993 | } |
2996 | 2994 | #endif /* 0 */ | |
2997 | #endif /* CONFIG_POWER4 */ | ||
2998 | 2995 | ||
2999 | /* | 2996 | /* |
3000 | * Early video resume hook | 2997 | * Early video resume hook |
diff --git a/arch/powerpc/platforms/powermac/nvram.c b/arch/powerpc/platforms/powermac/nvram.c index 8c9b008c7226..4042e2f06ee0 100644 --- a/arch/powerpc/platforms/powermac/nvram.c +++ b/arch/powerpc/platforms/powermac/nvram.c | |||
@@ -47,7 +47,8 @@ | |||
47 | 47 | ||
48 | /* On Core99, nvram is either a sharp, a micron or an AMD flash */ | 48 | /* On Core99, nvram is either a sharp, a micron or an AMD flash */ |
49 | #define SM_FLASH_STATUS_DONE 0x80 | 49 | #define SM_FLASH_STATUS_DONE 0x80 |
50 | #define SM_FLASH_STATUS_ERR 0x38 | 50 | #define SM_FLASH_STATUS_ERR 0x38 |
51 | |||
51 | #define SM_FLASH_CMD_ERASE_CONFIRM 0xd0 | 52 | #define SM_FLASH_CMD_ERASE_CONFIRM 0xd0 |
52 | #define SM_FLASH_CMD_ERASE_SETUP 0x20 | 53 | #define SM_FLASH_CMD_ERASE_SETUP 0x20 |
53 | #define SM_FLASH_CMD_RESET 0xff | 54 | #define SM_FLASH_CMD_RESET 0xff |
@@ -75,11 +76,11 @@ struct core99_header { | |||
75 | * Read and write the non-volatile RAM on PowerMacs and CHRP machines. | 76 | * Read and write the non-volatile RAM on PowerMacs and CHRP machines. |
76 | */ | 77 | */ |
77 | static int nvram_naddrs; | 78 | static int nvram_naddrs; |
78 | static volatile unsigned char *nvram_addr; | ||
79 | static volatile unsigned char *nvram_data; | 79 | static volatile unsigned char *nvram_data; |
80 | static int nvram_mult, is_core_99; | 80 | static int is_core_99; |
81 | static int core99_bank = 0; | 81 | static int core99_bank = 0; |
82 | static int nvram_partitions[3]; | 82 | static int nvram_partitions[3]; |
83 | // XXX Turn that into a sem | ||
83 | static DEFINE_SPINLOCK(nv_lock); | 84 | static DEFINE_SPINLOCK(nv_lock); |
84 | 85 | ||
85 | extern int pmac_newworld; | 86 | extern int pmac_newworld; |
@@ -105,6 +106,52 @@ static void core99_nvram_write_byte(int addr, unsigned char val) | |||
105 | nvram_image[addr] = val; | 106 | nvram_image[addr] = val; |
106 | } | 107 | } |
107 | 108 | ||
109 | static ssize_t core99_nvram_read(char *buf, size_t count, loff_t *index) | ||
110 | { | ||
111 | int i; | ||
112 | |||
113 | if (nvram_image == NULL) | ||
114 | return -ENODEV; | ||
115 | if (*index > NVRAM_SIZE) | ||
116 | return 0; | ||
117 | |||
118 | i = *index; | ||
119 | if (i + count > NVRAM_SIZE) | ||
120 | count = NVRAM_SIZE - i; | ||
121 | |||
122 | memcpy(buf, &nvram_image[i], count); | ||
123 | *index = i + count; | ||
124 | return count; | ||
125 | } | ||
126 | |||
127 | static ssize_t core99_nvram_write(char *buf, size_t count, loff_t *index) | ||
128 | { | ||
129 | int i; | ||
130 | |||
131 | if (nvram_image == NULL) | ||
132 | return -ENODEV; | ||
133 | if (*index > NVRAM_SIZE) | ||
134 | return 0; | ||
135 | |||
136 | i = *index; | ||
137 | if (i + count > NVRAM_SIZE) | ||
138 | count = NVRAM_SIZE - i; | ||
139 | |||
140 | memcpy(&nvram_image[i], buf, count); | ||
141 | *index = i + count; | ||
142 | return count; | ||
143 | } | ||
144 | |||
145 | static ssize_t core99_nvram_size(void) | ||
146 | { | ||
147 | if (nvram_image == NULL) | ||
148 | return -ENODEV; | ||
149 | return NVRAM_SIZE; | ||
150 | } | ||
151 | |||
152 | #ifdef CONFIG_PPC32 | ||
153 | static volatile unsigned char *nvram_addr; | ||
154 | static int nvram_mult; | ||
108 | 155 | ||
109 | static unsigned char direct_nvram_read_byte(int addr) | 156 | static unsigned char direct_nvram_read_byte(int addr) |
110 | { | 157 | { |
@@ -181,7 +228,7 @@ static void pmu_nvram_write_byte(int addr, unsigned char val) | |||
181 | } | 228 | } |
182 | 229 | ||
183 | #endif /* CONFIG_ADB_PMU */ | 230 | #endif /* CONFIG_ADB_PMU */ |
184 | 231 | #endif /* CONFIG_PPC32 */ | |
185 | 232 | ||
186 | static u8 chrp_checksum(struct chrp_header* hdr) | 233 | static u8 chrp_checksum(struct chrp_header* hdr) |
187 | { | 234 | { |
@@ -249,7 +296,7 @@ static int sm_erase_bank(int bank) | |||
249 | timeout = 0; | 296 | timeout = 0; |
250 | do { | 297 | do { |
251 | if (++timeout > 1000000) { | 298 | if (++timeout > 1000000) { |
252 | printk(KERN_ERR "nvram: Sharp/Miron flash erase timeout !\n"); | 299 | printk(KERN_ERR "nvram: Sharp/Micron flash erase timeout !\n"); |
253 | break; | 300 | break; |
254 | } | 301 | } |
255 | out_8(base, SM_FLASH_CMD_READ_STATUS); | 302 | out_8(base, SM_FLASH_CMD_READ_STATUS); |
@@ -411,7 +458,7 @@ static void __init lookup_partitions(void) | |||
411 | buffer[16] = 0; | 458 | buffer[16] = 0; |
412 | do { | 459 | do { |
413 | for (i=0;i<16;i++) | 460 | for (i=0;i<16;i++) |
414 | buffer[i] = nvram_read_byte(offset+i); | 461 | buffer[i] = ppc_md.nvram_read_val(offset+i); |
415 | if (!strcmp(hdr->name, "common")) | 462 | if (!strcmp(hdr->name, "common")) |
416 | nvram_partitions[pmac_nvram_OF] = offset + 0x10; | 463 | nvram_partitions[pmac_nvram_OF] = offset + 0x10; |
417 | if (!strcmp(hdr->name, "APL,MacOS75")) { | 464 | if (!strcmp(hdr->name, "APL,MacOS75")) { |
@@ -467,65 +514,76 @@ static void core99_nvram_sync(void) | |||
467 | #endif | 514 | #endif |
468 | } | 515 | } |
469 | 516 | ||
470 | void __init pmac_nvram_init(void) | 517 | static int __init core99_nvram_setup(struct device_node *dp) |
518 | { | ||
519 | int i; | ||
520 | u32 gen_bank0, gen_bank1; | ||
521 | |||
522 | if (nvram_naddrs < 1) { | ||
523 | printk(KERN_ERR "nvram: no address\n"); | ||
524 | return -EINVAL; | ||
525 | } | ||
526 | nvram_image = alloc_bootmem(NVRAM_SIZE); | ||
527 | if (nvram_image == NULL) { | ||
528 | printk(KERN_ERR "nvram: can't allocate ram image\n"); | ||
529 | return -ENOMEM; | ||
530 | } | ||
531 | nvram_data = ioremap(dp->addrs[0].address, NVRAM_SIZE*2); | ||
532 | nvram_naddrs = 1; /* Make sure we get the correct case */ | ||
533 | |||
534 | DBG("nvram: Checking bank 0...\n"); | ||
535 | |||
536 | gen_bank0 = core99_check((u8 *)nvram_data); | ||
537 | gen_bank1 = core99_check((u8 *)nvram_data + NVRAM_SIZE); | ||
538 | core99_bank = (gen_bank0 < gen_bank1) ? 1 : 0; | ||
539 | |||
540 | DBG("nvram: gen0=%d, gen1=%d\n", gen_bank0, gen_bank1); | ||
541 | DBG("nvram: Active bank is: %d\n", core99_bank); | ||
542 | |||
543 | for (i=0; i<NVRAM_SIZE; i++) | ||
544 | nvram_image[i] = nvram_data[i + core99_bank*NVRAM_SIZE]; | ||
545 | |||
546 | ppc_md.nvram_read_val = core99_nvram_read_byte; | ||
547 | ppc_md.nvram_write_val = core99_nvram_write_byte; | ||
548 | ppc_md.nvram_read = core99_nvram_read; | ||
549 | ppc_md.nvram_write = core99_nvram_write; | ||
550 | ppc_md.nvram_size = core99_nvram_size; | ||
551 | ppc_md.nvram_sync = core99_nvram_sync; | ||
552 | /* | ||
553 | * Maybe we could be smarter here though making an exclusive list | ||
554 | * of known flash chips is a bit nasty as older OF didn't provide us | ||
555 | * with a useful "compatible" entry. A solution would be to really | ||
556 | * identify the chip using flash id commands and base ourselves on | ||
557 | * a list of known chips IDs | ||
558 | */ | ||
559 | if (device_is_compatible(dp, "amd-0137")) { | ||
560 | core99_erase_bank = amd_erase_bank; | ||
561 | core99_write_bank = amd_write_bank; | ||
562 | } else { | ||
563 | core99_erase_bank = sm_erase_bank; | ||
564 | core99_write_bank = sm_write_bank; | ||
565 | } | ||
566 | return 0; | ||
567 | } | ||
568 | |||
569 | int __init pmac_nvram_init(void) | ||
471 | { | 570 | { |
472 | struct device_node *dp; | 571 | struct device_node *dp; |
572 | int err = 0; | ||
473 | 573 | ||
474 | nvram_naddrs = 0; | 574 | nvram_naddrs = 0; |
475 | 575 | ||
476 | dp = find_devices("nvram"); | 576 | dp = find_devices("nvram"); |
477 | if (dp == NULL) { | 577 | if (dp == NULL) { |
478 | printk(KERN_ERR "Can't find NVRAM device\n"); | 578 | printk(KERN_ERR "Can't find NVRAM device\n"); |
479 | return; | 579 | return -ENODEV; |
480 | } | 580 | } |
481 | nvram_naddrs = dp->n_addrs; | 581 | nvram_naddrs = dp->n_addrs; |
482 | is_core_99 = device_is_compatible(dp, "nvram,flash"); | 582 | is_core_99 = device_is_compatible(dp, "nvram,flash"); |
483 | if (is_core_99) { | 583 | if (is_core_99) |
484 | int i; | 584 | err = core99_nvram_setup(dp); |
485 | u32 gen_bank0, gen_bank1; | 585 | #ifdef CONFIG_PPC32 |
486 | 586 | else if (_machine == _MACH_chrp && nvram_naddrs == 1) { | |
487 | if (nvram_naddrs < 1) { | ||
488 | printk(KERN_ERR "nvram: no address\n"); | ||
489 | return; | ||
490 | } | ||
491 | nvram_image = alloc_bootmem(NVRAM_SIZE); | ||
492 | if (nvram_image == NULL) { | ||
493 | printk(KERN_ERR "nvram: can't allocate ram image\n"); | ||
494 | return; | ||
495 | } | ||
496 | nvram_data = ioremap(dp->addrs[0].address, NVRAM_SIZE*2); | ||
497 | nvram_naddrs = 1; /* Make sure we get the correct case */ | ||
498 | |||
499 | DBG("nvram: Checking bank 0...\n"); | ||
500 | |||
501 | gen_bank0 = core99_check((u8 *)nvram_data); | ||
502 | gen_bank1 = core99_check((u8 *)nvram_data + NVRAM_SIZE); | ||
503 | core99_bank = (gen_bank0 < gen_bank1) ? 1 : 0; | ||
504 | |||
505 | DBG("nvram: gen0=%d, gen1=%d\n", gen_bank0, gen_bank1); | ||
506 | DBG("nvram: Active bank is: %d\n", core99_bank); | ||
507 | |||
508 | for (i=0; i<NVRAM_SIZE; i++) | ||
509 | nvram_image[i] = nvram_data[i + core99_bank*NVRAM_SIZE]; | ||
510 | |||
511 | ppc_md.nvram_read_val = core99_nvram_read_byte; | ||
512 | ppc_md.nvram_write_val = core99_nvram_write_byte; | ||
513 | ppc_md.nvram_sync = core99_nvram_sync; | ||
514 | /* | ||
515 | * Maybe we could be smarter here though making an exclusive list | ||
516 | * of known flash chips is a bit nasty as older OF didn't provide us | ||
517 | * with a useful "compatible" entry. A solution would be to really | ||
518 | * identify the chip using flash id commands and base ourselves on | ||
519 | * a list of known chips IDs | ||
520 | */ | ||
521 | if (device_is_compatible(dp, "amd-0137")) { | ||
522 | core99_erase_bank = amd_erase_bank; | ||
523 | core99_write_bank = amd_write_bank; | ||
524 | } else { | ||
525 | core99_erase_bank = sm_erase_bank; | ||
526 | core99_write_bank = sm_write_bank; | ||
527 | } | ||
528 | } else if (_machine == _MACH_chrp && nvram_naddrs == 1) { | ||
529 | nvram_data = ioremap(dp->addrs[0].address + isa_mem_base, | 587 | nvram_data = ioremap(dp->addrs[0].address + isa_mem_base, |
530 | dp->addrs[0].size); | 588 | dp->addrs[0].size); |
531 | nvram_mult = 1; | 589 | nvram_mult = 1; |
@@ -547,11 +605,14 @@ void __init pmac_nvram_init(void) | |||
547 | ppc_md.nvram_read_val = pmu_nvram_read_byte; | 605 | ppc_md.nvram_read_val = pmu_nvram_read_byte; |
548 | ppc_md.nvram_write_val = pmu_nvram_write_byte; | 606 | ppc_md.nvram_write_val = pmu_nvram_write_byte; |
549 | #endif /* CONFIG_ADB_PMU */ | 607 | #endif /* CONFIG_ADB_PMU */ |
550 | } else { | 608 | } |
551 | printk(KERN_ERR "Don't know how to access NVRAM with %d addresses\n", | 609 | #endif |
552 | nvram_naddrs); | 610 | else { |
611 | printk(KERN_ERR "Incompatible type of NVRAM\n"); | ||
612 | return -ENXIO; | ||
553 | } | 613 | } |
554 | lookup_partitions(); | 614 | lookup_partitions(); |
615 | return err; | ||
555 | } | 616 | } |
556 | 617 | ||
557 | int pmac_get_partition(int partition) | 618 | int pmac_get_partition(int partition) |
@@ -561,9 +622,9 @@ int pmac_get_partition(int partition) | |||
561 | 622 | ||
562 | u8 pmac_xpram_read(int xpaddr) | 623 | u8 pmac_xpram_read(int xpaddr) |
563 | { | 624 | { |
564 | int offset = nvram_partitions[pmac_nvram_XPRAM]; | 625 | int offset = pmac_get_partition(pmac_nvram_XPRAM); |
565 | 626 | ||
566 | if (offset < 0) | 627 | if (offset < 0 || xpaddr < 0 || xpaddr > 0x100) |
567 | return 0xff; | 628 | return 0xff; |
568 | 629 | ||
569 | return ppc_md.nvram_read_val(xpaddr + offset); | 630 | return ppc_md.nvram_read_val(xpaddr + offset); |
@@ -571,9 +632,9 @@ u8 pmac_xpram_read(int xpaddr) | |||
571 | 632 | ||
572 | void pmac_xpram_write(int xpaddr, u8 data) | 633 | void pmac_xpram_write(int xpaddr, u8 data) |
573 | { | 634 | { |
574 | int offset = nvram_partitions[pmac_nvram_XPRAM]; | 635 | int offset = pmac_get_partition(pmac_nvram_XPRAM); |
575 | 636 | ||
576 | if (offset < 0) | 637 | if (offset < 0 || xpaddr < 0 || xpaddr > 0x100) |
577 | return; | 638 | return; |
578 | 639 | ||
579 | ppc_md.nvram_write_val(xpaddr + offset, data); | 640 | ppc_md.nvram_write_val(xpaddr + offset, data); |
diff --git a/arch/powerpc/platforms/powermac/pci.c b/arch/powerpc/platforms/powermac/pci.c index 34dfe1e9706f..ebe22a2267d2 100644 --- a/arch/powerpc/platforms/powermac/pci.c +++ b/arch/powerpc/platforms/powermac/pci.c | |||
@@ -37,14 +37,14 @@ | |||
37 | #endif | 37 | #endif |
38 | 38 | ||
39 | static int add_bridge(struct device_node *dev); | 39 | static int add_bridge(struct device_node *dev); |
40 | extern void pmac_check_ht_link(void); | ||
41 | 40 | ||
42 | /* XXX Could be per-controller, but I don't think we risk anything by | 41 | /* XXX Could be per-controller, but I don't think we risk anything by |
43 | * assuming we won't have both UniNorth and Bandit */ | 42 | * assuming we won't have both UniNorth and Bandit */ |
44 | static int has_uninorth; | 43 | static int has_uninorth; |
45 | #ifdef CONFIG_POWER4 | 44 | #ifdef CONFIG_PPC64 |
46 | static struct pci_controller *u3_agp; | 45 | static struct pci_controller *u3_agp; |
47 | #endif /* CONFIG_POWER4 */ | 46 | static struct pci_controller *u3_ht; |
47 | #endif /* CONFIG_PPC64 */ | ||
48 | 48 | ||
49 | extern u8 pci_cache_line_size; | 49 | extern u8 pci_cache_line_size; |
50 | extern int pcibios_assign_bus_offset; | 50 | extern int pcibios_assign_bus_offset; |
@@ -229,6 +229,7 @@ static struct pci_ops macrisc_pci_ops = | |||
229 | macrisc_write_config | 229 | macrisc_write_config |
230 | }; | 230 | }; |
231 | 231 | ||
232 | #ifdef CONFIG_PPC32 | ||
232 | /* | 233 | /* |
233 | * Verify that a specific (bus, dev_fn) exists on chaos | 234 | * Verify that a specific (bus, dev_fn) exists on chaos |
234 | */ | 235 | */ |
@@ -282,7 +283,19 @@ static struct pci_ops chaos_pci_ops = | |||
282 | chaos_write_config | 283 | chaos_write_config |
283 | }; | 284 | }; |
284 | 285 | ||
285 | #ifdef CONFIG_POWER4 | 286 | static void __init setup_chaos(struct pci_controller *hose, |
287 | struct reg_property *addr) | ||
288 | { | ||
289 | /* assume a `chaos' bridge */ | ||
290 | hose->ops = &chaos_pci_ops; | ||
291 | hose->cfg_addr = ioremap(addr->address + 0x800000, 0x1000); | ||
292 | hose->cfg_data = ioremap(addr->address + 0xc00000, 0x1000); | ||
293 | } | ||
294 | #else | ||
295 | #define setup_chaos(hose, addr) | ||
296 | #endif /* CONFIG_PPC32 */ | ||
297 | |||
298 | #ifdef CONFIG_PPC64 | ||
286 | /* | 299 | /* |
287 | * These versions of U3 HyperTransport config space access ops do not | 300 | * These versions of U3 HyperTransport config space access ops do not |
288 | * implement self-view of the HT host yet | 301 | * implement self-view of the HT host yet |
@@ -445,8 +458,9 @@ static struct pci_ops u3_ht_pci_ops = | |||
445 | u3_ht_read_config, | 458 | u3_ht_read_config, |
446 | u3_ht_write_config | 459 | u3_ht_write_config |
447 | }; | 460 | }; |
448 | #endif /* CONFIG_POWER4 */ | 461 | #endif /* CONFIG_PPC64 */ |
449 | 462 | ||
463 | #ifdef CONFIG_PPC32 | ||
450 | /* | 464 | /* |
451 | * For a bandit bridge, turn on cache coherency if necessary. | 465 | * For a bandit bridge, turn on cache coherency if necessary. |
452 | * N.B. we could clean this up using the hose ops directly. | 466 | * N.B. we could clean this up using the hose ops directly. |
@@ -487,7 +501,6 @@ static void __init init_bandit(struct pci_controller *bp) | |||
487 | printk(KERN_INFO "Cache coherency enabled for bandit/PSX\n"); | 501 | printk(KERN_INFO "Cache coherency enabled for bandit/PSX\n"); |
488 | } | 502 | } |
489 | 503 | ||
490 | |||
491 | /* | 504 | /* |
492 | * Tweak the PCI-PCI bridge chip on the blue & white G3s. | 505 | * Tweak the PCI-PCI bridge chip on the blue & white G3s. |
493 | */ | 506 | */ |
@@ -539,7 +552,7 @@ static void __init fixup_nec_usb2(void) | |||
539 | struct pci_controller *hose; | 552 | struct pci_controller *hose; |
540 | u32 data, *prop; | 553 | u32 data, *prop; |
541 | u8 bus, devfn; | 554 | u8 bus, devfn; |
542 | 555 | ||
543 | prop = (u32 *)get_property(nec, "vendor-id", NULL); | 556 | prop = (u32 *)get_property(nec, "vendor-id", NULL); |
544 | if (prop == NULL) | 557 | if (prop == NULL) |
545 | continue; | 558 | continue; |
@@ -605,20 +618,18 @@ static inline void grackle_set_loop_snoop(struct pci_controller *bp, int enable) | |||
605 | (void)in_le32(bp->cfg_data); | 618 | (void)in_le32(bp->cfg_data); |
606 | } | 619 | } |
607 | 620 | ||
608 | static int __init | 621 | void __init setup_grackle(struct pci_controller *hose) |
609 | setup_uninorth(struct pci_controller* hose, struct reg_property* addr) | ||
610 | { | 622 | { |
611 | pci_assign_all_buses = 1; | 623 | setup_indirect_pci(hose, 0xfec00000, 0xfee00000); |
612 | has_uninorth = 1; | 624 | if (machine_is_compatible("AAPL,PowerBook1998")) |
613 | hose->ops = ¯isc_pci_ops; | 625 | grackle_set_loop_snoop(hose, 1); |
614 | hose->cfg_addr = ioremap(addr->address + 0x800000, 0x1000); | 626 | #if 0 /* Disabled for now, HW problems ??? */ |
615 | hose->cfg_data = ioremap(addr->address + 0xc00000, 0x1000); | 627 | grackle_set_stg(hose, 1); |
616 | /* We "know" that the bridge at f2000000 has the PCI slots. */ | 628 | #endif |
617 | return addr->address == 0xf2000000; | ||
618 | } | 629 | } |
619 | 630 | ||
620 | static void __init | 631 | static void __init setup_bandit(struct pci_controller *hose, |
621 | setup_bandit(struct pci_controller* hose, struct reg_property* addr) | 632 | struct reg_property *addr) |
622 | { | 633 | { |
623 | hose->ops = ¯isc_pci_ops; | 634 | hose->ops = ¯isc_pci_ops; |
624 | hose->cfg_addr = ioremap(addr->address + 0x800000, 0x1000); | 635 | hose->cfg_addr = ioremap(addr->address + 0x800000, 0x1000); |
@@ -626,21 +637,25 @@ setup_bandit(struct pci_controller* hose, struct reg_property* addr) | |||
626 | init_bandit(hose); | 637 | init_bandit(hose); |
627 | } | 638 | } |
628 | 639 | ||
629 | static void __init | 640 | static int __init setup_uninorth(struct pci_controller *hose, |
630 | setup_chaos(struct pci_controller* hose, struct reg_property* addr) | 641 | struct reg_property *addr) |
631 | { | 642 | { |
632 | /* assume a `chaos' bridge */ | 643 | pci_assign_all_buses = 1; |
633 | hose->ops = &chaos_pci_ops; | 644 | has_uninorth = 1; |
645 | hose->ops = ¯isc_pci_ops; | ||
634 | hose->cfg_addr = ioremap(addr->address + 0x800000, 0x1000); | 646 | hose->cfg_addr = ioremap(addr->address + 0x800000, 0x1000); |
635 | hose->cfg_data = ioremap(addr->address + 0xc00000, 0x1000); | 647 | hose->cfg_data = ioremap(addr->address + 0xc00000, 0x1000); |
648 | /* We "know" that the bridge at f2000000 has the PCI slots. */ | ||
649 | return addr->address == 0xf2000000; | ||
636 | } | 650 | } |
651 | #endif | ||
637 | 652 | ||
638 | #ifdef CONFIG_POWER4 | 653 | #ifdef CONFIG_PPC64 |
639 | static void __init setup_u3_agp(struct pci_controller* hose) | 654 | static void __init setup_u3_agp(struct pci_controller* hose) |
640 | { | 655 | { |
641 | /* On G5, we move AGP up to high bus number so we don't need | 656 | /* On G5, we move AGP up to high bus number so we don't need |
642 | * to reassign bus numbers for HT. If we ever have P2P bridges | 657 | * to reassign bus numbers for HT. If we ever have P2P bridges |
643 | * on AGP, we'll have to move pci_assign_all_buses to the | 658 | * on AGP, we'll have to move pci_assign_all_busses to the |
644 | * pci_controller structure so we enable it for AGP and not for | 659 | * pci_controller structure so we enable it for AGP and not for |
645 | * HT childs. | 660 | * HT childs. |
646 | * We hard code the address because of the different size of | 661 | * We hard code the address because of the different size of |
@@ -679,8 +694,7 @@ static void __init setup_u3_ht(struct pci_controller* hose) | |||
679 | * then read its configuration register (if any). | 694 | * then read its configuration register (if any). |
680 | */ | 695 | */ |
681 | hose->io_base_phys = 0xf4000000; | 696 | hose->io_base_phys = 0xf4000000; |
682 | hose->io_base_virt = ioremap(hose->io_base_phys, 0x00400000); | 697 | hose->pci_io_size = 0x00400000; |
683 | isa_io_base = pci_io_base = (unsigned long) hose->io_base_virt; | ||
684 | hose->io_resource.name = np->full_name; | 698 | hose->io_resource.name = np->full_name; |
685 | hose->io_resource.start = 0; | 699 | hose->io_resource.start = 0; |
686 | hose->io_resource.end = 0x003fffff; | 700 | hose->io_resource.end = 0x003fffff; |
@@ -693,6 +707,8 @@ static void __init setup_u3_ht(struct pci_controller* hose) | |||
693 | hose->mem_resources[0].end = 0xefffffff; | 707 | hose->mem_resources[0].end = 0xefffffff; |
694 | hose->mem_resources[0].flags = IORESOURCE_MEM; | 708 | hose->mem_resources[0].flags = IORESOURCE_MEM; |
695 | 709 | ||
710 | u3_ht = hose; | ||
711 | |||
696 | if (u3_agp == NULL) { | 712 | if (u3_agp == NULL) { |
697 | DBG("U3 has no AGP, using full resource range\n"); | 713 | DBG("U3 has no AGP, using full resource range\n"); |
698 | return; | 714 | return; |
@@ -730,7 +746,7 @@ static void __init setup_u3_ht(struct pci_controller* hose) | |||
730 | printk(KERN_WARNING "Running out of resources for /ht host !\n"); | 746 | printk(KERN_WARNING "Running out of resources for /ht host !\n"); |
731 | hose->mem_resources[cur].end = res->start - 1; | 747 | hose->mem_resources[cur].end = res->start - 1; |
732 | continue; | 748 | continue; |
733 | } | 749 | } |
734 | cur++; | 750 | cur++; |
735 | DBG("U3/HT: hole, %d end at %08lx, %d start at %08lx\n", | 751 | DBG("U3/HT: hole, %d end at %08lx, %d start at %08lx\n", |
736 | cur-1, res->start - 1, cur, res->end + 1); | 752 | cur-1, res->start - 1, cur, res->end + 1); |
@@ -742,126 +758,17 @@ static void __init setup_u3_ht(struct pci_controller* hose) | |||
742 | } | 758 | } |
743 | } | 759 | } |
744 | 760 | ||
745 | #endif /* CONFIG_POWER4 */ | 761 | /* XXX this needs to be converged between ppc32 and ppc64... */ |
746 | 762 | static struct pci_controller * __init pcibios_alloc_controller(void) | |
747 | void __init | ||
748 | setup_grackle(struct pci_controller *hose) | ||
749 | { | 763 | { |
750 | setup_indirect_pci(hose, 0xfec00000, 0xfee00000); | 764 | struct pci_controller *hose; |
751 | if (machine_is_compatible("AAPL,PowerBook1998")) | ||
752 | grackle_set_loop_snoop(hose, 1); | ||
753 | #if 0 /* Disabled for now, HW problems ??? */ | ||
754 | grackle_set_stg(hose, 1); | ||
755 | #endif | ||
756 | } | ||
757 | |||
758 | static void __init pmac_process_bridge_OF_ranges(struct pci_controller *hose, | ||
759 | struct device_node *dev, int primary) | ||
760 | { | ||
761 | static unsigned int static_lc_ranges[2024]; | ||
762 | unsigned int *dt_ranges, *lc_ranges, *ranges, *prev; | ||
763 | unsigned int size; | ||
764 | int rlen = 0, orig_rlen; | ||
765 | int memno = 0; | ||
766 | struct resource *res; | ||
767 | int np, na = prom_n_addr_cells(dev); | ||
768 | |||
769 | np = na + 5; | ||
770 | |||
771 | /* First we try to merge ranges to fix a problem with some pmacs | ||
772 | * that can have more than 3 ranges, fortunately using contiguous | ||
773 | * addresses -- BenH | ||
774 | */ | ||
775 | dt_ranges = (unsigned int *) get_property(dev, "ranges", &rlen); | ||
776 | if (!dt_ranges) | ||
777 | return; | ||
778 | /* lc_ranges = alloc_bootmem(rlen);*/ | ||
779 | lc_ranges = static_lc_ranges; | ||
780 | if (!lc_ranges) | ||
781 | return; /* what can we do here ? */ | ||
782 | memcpy(lc_ranges, dt_ranges, rlen); | ||
783 | orig_rlen = rlen; | ||
784 | |||
785 | /* Let's work on a copy of the "ranges" property instead of damaging | ||
786 | * the device-tree image in memory | ||
787 | */ | ||
788 | ranges = lc_ranges; | ||
789 | prev = NULL; | ||
790 | while ((rlen -= np * sizeof(unsigned int)) >= 0) { | ||
791 | if (prev) { | ||
792 | if (prev[0] == ranges[0] && prev[1] == ranges[1] && | ||
793 | (prev[2] + prev[na+4]) == ranges[2] && | ||
794 | (prev[na+2] + prev[na+4]) == ranges[na+2]) { | ||
795 | prev[na+4] += ranges[na+4]; | ||
796 | ranges[0] = 0; | ||
797 | ranges += np; | ||
798 | continue; | ||
799 | } | ||
800 | } | ||
801 | prev = ranges; | ||
802 | ranges += np; | ||
803 | } | ||
804 | 765 | ||
805 | /* | 766 | hose = alloc_bootmem(sizeof(struct pci_controller)); |
806 | * The ranges property is laid out as an array of elements, | 767 | if (hose) |
807 | * each of which comprises: | 768 | pci_setup_pci_controller(hose); |
808 | * cells 0 - 2: a PCI address | 769 | return hose; |
809 | * cells 3 or 3+4: a CPU physical address | ||
810 | * (size depending on dev->n_addr_cells) | ||
811 | * cells 4+5 or 5+6: the size of the range | ||
812 | */ | ||
813 | ranges = lc_ranges; | ||
814 | rlen = orig_rlen; | ||
815 | while (ranges && (rlen -= np * sizeof(unsigned int)) >= 0) { | ||
816 | res = NULL; | ||
817 | size = ranges[na+4]; | ||
818 | switch (ranges[0] >> 24) { | ||
819 | case 1: /* I/O space */ | ||
820 | if (ranges[2] != 0) | ||
821 | break; | ||
822 | hose->io_base_phys = ranges[na+2]; | ||
823 | /* limit I/O space to 16MB */ | ||
824 | if (size > 0x01000000) | ||
825 | size = 0x01000000; | ||
826 | hose->io_base_virt = ioremap(ranges[na+2], size); | ||
827 | if (primary) | ||
828 | isa_io_base = (unsigned long) hose->io_base_virt; | ||
829 | res = &hose->io_resource; | ||
830 | res->flags = IORESOURCE_IO; | ||
831 | res->start = ranges[2]; | ||
832 | break; | ||
833 | case 2: /* memory space */ | ||
834 | memno = 0; | ||
835 | if (ranges[1] == 0 && ranges[2] == 0 | ||
836 | && ranges[na+4] <= (16 << 20)) { | ||
837 | /* 1st 16MB, i.e. ISA memory area */ | ||
838 | #if 0 | ||
839 | if (primary) | ||
840 | isa_mem_base = ranges[na+2]; | ||
841 | #endif | ||
842 | memno = 1; | ||
843 | } | ||
844 | while (memno < 3 && hose->mem_resources[memno].flags) | ||
845 | ++memno; | ||
846 | if (memno == 0) | ||
847 | hose->pci_mem_offset = ranges[na+2] - ranges[2]; | ||
848 | if (memno < 3) { | ||
849 | res = &hose->mem_resources[memno]; | ||
850 | res->flags = IORESOURCE_MEM; | ||
851 | res->start = ranges[na+2]; | ||
852 | } | ||
853 | break; | ||
854 | } | ||
855 | if (res != NULL) { | ||
856 | res->name = dev->full_name; | ||
857 | res->end = res->start + size - 1; | ||
858 | res->parent = NULL; | ||
859 | res->sibling = NULL; | ||
860 | res->child = NULL; | ||
861 | } | ||
862 | ranges += np; | ||
863 | } | ||
864 | } | 770 | } |
771 | #endif | ||
865 | 772 | ||
866 | /* | 773 | /* |
867 | * We assume that if we have a G3 powermac, we have one bridge called | 774 | * We assume that if we have a G3 powermac, we have one bridge called |
@@ -872,70 +779,78 @@ static int __init add_bridge(struct device_node *dev) | |||
872 | { | 779 | { |
873 | int len; | 780 | int len; |
874 | struct pci_controller *hose; | 781 | struct pci_controller *hose; |
782 | #ifdef CONFIG_PPC32 | ||
875 | struct reg_property *addr; | 783 | struct reg_property *addr; |
876 | char* disp_name; | 784 | #endif |
785 | char *disp_name; | ||
877 | int *bus_range; | 786 | int *bus_range; |
878 | int primary = 1; | 787 | int primary = 1; |
879 | 788 | ||
880 | DBG("Adding PCI host bridge %s\n", dev->full_name); | 789 | DBG("Adding PCI host bridge %s\n", dev->full_name); |
881 | 790 | ||
882 | addr = (struct reg_property *) get_property(dev, "reg", &len); | 791 | #ifdef CONFIG_PPC32 |
883 | if (addr == NULL || len < sizeof(*addr)) { | 792 | /* XXX fix this */ |
884 | printk(KERN_WARNING "Can't use %s: no address\n", | 793 | addr = (struct reg_property *) get_property(dev, "reg", &len); |
885 | dev->full_name); | 794 | if (addr == NULL || len < sizeof(*addr)) { |
886 | return -ENODEV; | 795 | printk(KERN_WARNING "Can't use %s: no address\n", |
887 | } | 796 | dev->full_name); |
888 | bus_range = (int *) get_property(dev, "bus-range", &len); | 797 | return -ENODEV; |
889 | if (bus_range == NULL || len < 2 * sizeof(int)) { | 798 | } |
890 | printk(KERN_WARNING "Can't get bus-range for %s, assume bus 0\n", | 799 | #endif |
891 | dev->full_name); | 800 | bus_range = (int *) get_property(dev, "bus-range", &len); |
892 | } | 801 | if (bus_range == NULL || len < 2 * sizeof(int)) { |
893 | 802 | printk(KERN_WARNING "Can't get bus-range for %s, assume bus 0\n", | |
894 | hose = pcibios_alloc_controller(); | 803 | dev->full_name); |
895 | if (!hose) | 804 | } |
896 | return -ENOMEM; | 805 | |
897 | hose->arch_data = dev; | 806 | hose = pcibios_alloc_controller(); |
898 | hose->first_busno = bus_range ? bus_range[0] : 0; | 807 | if (!hose) |
899 | hose->last_busno = bus_range ? bus_range[1] : 0xff; | 808 | return -ENOMEM; |
809 | hose->arch_data = dev; | ||
810 | hose->first_busno = bus_range ? bus_range[0] : 0; | ||
811 | hose->last_busno = bus_range ? bus_range[1] : 0xff; | ||
900 | 812 | ||
901 | disp_name = NULL; | 813 | disp_name = NULL; |
902 | #ifdef CONFIG_POWER4 | 814 | #ifdef CONFIG_POWER4 |
903 | if (device_is_compatible(dev, "u3-agp")) { | 815 | if (device_is_compatible(dev, "u3-agp")) { |
904 | setup_u3_agp(hose, addr); | 816 | setup_u3_agp(hose); |
905 | disp_name = "U3-AGP"; | 817 | disp_name = "U3-AGP"; |
906 | primary = 0; | 818 | primary = 0; |
907 | } else if (device_is_compatible(dev, "u3-ht")) { | 819 | } else if (device_is_compatible(dev, "u3-ht")) { |
908 | setup_u3_ht(hose, addr); | 820 | setup_u3_ht(hose); |
909 | disp_name = "U3-HT"; | 821 | disp_name = "U3-HT"; |
910 | primary = 1; | 822 | primary = 1; |
911 | } else | 823 | } |
912 | #endif /* CONFIG_POWER4 */ | 824 | printk(KERN_INFO "Found %s PCI host bridge. Firmware bus number: %d->%d\n", |
825 | disp_name, hose->first_busno, hose->last_busno); | ||
826 | #else | ||
913 | if (device_is_compatible(dev, "uni-north")) { | 827 | if (device_is_compatible(dev, "uni-north")) { |
914 | primary = setup_uninorth(hose, addr); | 828 | primary = setup_uninorth(hose, addr); |
915 | disp_name = "UniNorth"; | 829 | disp_name = "UniNorth"; |
916 | } else if (strcmp(dev->name, "pci") == 0) { | 830 | } else if (strcmp(dev->name, "pci") == 0) { |
917 | /* XXX assume this is a mpc106 (grackle) */ | 831 | /* XXX assume this is a mpc106 (grackle) */ |
918 | setup_grackle(hose); | 832 | setup_grackle(hose); |
919 | disp_name = "Grackle (MPC106)"; | 833 | disp_name = "Grackle (MPC106)"; |
920 | } else if (strcmp(dev->name, "bandit") == 0) { | 834 | } else if (strcmp(dev->name, "bandit") == 0) { |
921 | setup_bandit(hose, addr); | 835 | setup_bandit(hose, addr); |
922 | disp_name = "Bandit"; | 836 | disp_name = "Bandit"; |
923 | } else if (strcmp(dev->name, "chaos") == 0) { | 837 | } else if (strcmp(dev->name, "chaos") == 0) { |
924 | setup_chaos(hose, addr); | 838 | setup_chaos(hose, addr); |
925 | disp_name = "Chaos"; | 839 | disp_name = "Chaos"; |
926 | primary = 0; | 840 | primary = 0; |
927 | } | 841 | } |
928 | printk(KERN_INFO "Found %s PCI host bridge at 0x%08lx. Firmware bus number: %d->%d\n", | 842 | printk(KERN_INFO "Found %s PCI host bridge at 0x%08lx. Firmware bus number: %d->%d\n", |
929 | disp_name, addr->address, hose->first_busno, hose->last_busno); | 843 | disp_name, addr->address, hose->first_busno, hose->last_busno); |
930 | DBG(" ->Hose at 0x%p, cfg_addr=0x%p,cfg_data=0x%p\n", | 844 | #endif |
931 | hose, hose->cfg_addr, hose->cfg_data); | 845 | DBG(" ->Hose at 0x%p, cfg_addr=0x%p,cfg_data=0x%p\n", |
932 | 846 | hose, hose->cfg_addr, hose->cfg_data); | |
933 | /* Interpret the "ranges" property */ | 847 | |
934 | /* This also maps the I/O region and sets isa_io/mem_base */ | 848 | /* Interpret the "ranges" property */ |
935 | pci_process_bridge_OF_ranges(hose, dev, primary); | 849 | /* This also maps the I/O region and sets isa_io/mem_base */ |
936 | 850 | pci_process_bridge_OF_ranges(hose, dev, primary); | |
937 | /* Fixup "bus-range" OF property */ | 851 | |
938 | fixup_bus_range(dev); | 852 | /* Fixup "bus-range" OF property */ |
853 | fixup_bus_range(dev); | ||
939 | 854 | ||
940 | return 0; | 855 | return 0; |
941 | } | 856 | } |
@@ -968,14 +883,28 @@ pmac_pcibios_fixup(void) | |||
968 | pcibios_fixup_OF_interrupts(); | 883 | pcibios_fixup_OF_interrupts(); |
969 | } | 884 | } |
970 | 885 | ||
971 | void __init pmac_find_bridges(void) | 886 | #ifdef CONFIG_PPC64 |
887 | static void __init pmac_fixup_phb_resources(void) | ||
888 | { | ||
889 | struct pci_controller *hose, *tmp; | ||
890 | |||
891 | list_for_each_entry_safe(hose, tmp, &hose_list, list_node) { | ||
892 | printk(KERN_INFO "PCI Host %d, io start: %lx; io end: %lx\n", | ||
893 | hose->global_number, | ||
894 | hose->io_resource.start, hose->io_resource.end); | ||
895 | } | ||
896 | } | ||
897 | #endif | ||
898 | |||
899 | void __init pmac_pci_init(void) | ||
972 | { | 900 | { |
973 | struct device_node *np, *root; | 901 | struct device_node *np, *root; |
974 | struct device_node *ht = NULL; | 902 | struct device_node *ht = NULL; |
975 | 903 | ||
976 | root = of_find_node_by_path("/"); | 904 | root = of_find_node_by_path("/"); |
977 | if (root == NULL) { | 905 | if (root == NULL) { |
978 | printk(KERN_CRIT "pmac_find_bridges: can't find root of device tree\n"); | 906 | printk(KERN_CRIT "pmac_pci_init: can't find root " |
907 | "of device tree\n"); | ||
979 | return; | 908 | return; |
980 | } | 909 | } |
981 | for (np = NULL; (np = of_get_next_child(root, np)) != NULL;) { | 910 | for (np = NULL; (np = of_get_next_child(root, np)) != NULL;) { |
@@ -994,22 +923,66 @@ void __init pmac_find_bridges(void) | |||
994 | } | 923 | } |
995 | of_node_put(root); | 924 | of_node_put(root); |
996 | 925 | ||
926 | #ifdef CONFIG_PPC64 | ||
997 | /* Probe HT last as it relies on the agp resources to be already | 927 | /* Probe HT last as it relies on the agp resources to be already |
998 | * setup | 928 | * setup |
999 | */ | 929 | */ |
1000 | if (ht && add_bridge(ht) != 0) | 930 | if (ht && add_bridge(ht) != 0) |
1001 | of_node_put(ht); | 931 | of_node_put(ht); |
1002 | 932 | ||
933 | /* | ||
934 | * We need to call pci_setup_phb_io for the HT bridge first | ||
935 | * so it gets the I/O port numbers starting at 0, and we | ||
936 | * need to call it for the AGP bridge after that so it gets | ||
937 | * small positive I/O port numbers. | ||
938 | */ | ||
939 | if (u3_ht) | ||
940 | pci_setup_phb_io(u3_ht, 1); | ||
941 | if (u3_agp) | ||
942 | pci_setup_phb_io(u3_agp, 0); | ||
943 | |||
944 | /* | ||
945 | * On ppc64, fixup the IO resources on our host bridges as | ||
946 | * the common code does it only for children of the host bridges | ||
947 | */ | ||
948 | pmac_fixup_phb_resources(); | ||
949 | |||
950 | /* Setup the linkage between OF nodes and PHBs */ | ||
951 | pci_devs_phb_init(); | ||
952 | |||
953 | /* Fixup the PCI<->OF mapping for U3 AGP due to bus renumbering. We | ||
954 | * assume there is no P2P bridge on the AGP bus, which should be a | ||
955 | * safe assumptions hopefully. | ||
956 | */ | ||
957 | if (u3_agp) { | ||
958 | struct device_node *np = u3_agp->arch_data; | ||
959 | PCI_DN(np)->busno = 0xf0; | ||
960 | for (np = np->child; np; np = np->sibling) | ||
961 | PCI_DN(np)->busno = 0xf0; | ||
962 | } | ||
963 | |||
964 | /* map in PCI I/O space */ | ||
965 | phbs_remap_io(); | ||
966 | |||
967 | /* pmac_check_ht_link(); */ | ||
968 | |||
969 | /* Tell pci.c to not use the common resource allocation mechanism */ | ||
970 | pci_probe_only = 1; | ||
971 | |||
972 | /* Allow all IO */ | ||
973 | io_page_mask = -1; | ||
974 | |||
975 | #else /* CONFIG_PPC64 */ | ||
1003 | init_p2pbridge(); | 976 | init_p2pbridge(); |
1004 | fixup_nec_usb2(); | 977 | fixup_nec_usb2(); |
1005 | 978 | ||
1006 | /* We are still having some issues with the Xserve G4, enabling | 979 | /* We are still having some issues with the Xserve G4, enabling |
1007 | * some offset between bus number and domains for now when we | 980 | * some offset between bus number and domains for now when we |
1008 | * assign all busses should help for now | 981 | * assign all busses should help for now |
1009 | */ | 982 | */ |
1010 | if (pci_assign_all_buses) | 983 | if (pci_assign_all_buses) |
1011 | pcibios_assign_bus_offset = 0x10; | 984 | pcibios_assign_bus_offset = 0x10; |
1012 | 985 | #endif | |
1013 | } | 986 | } |
1014 | 987 | ||
1015 | int | 988 | int |
@@ -1037,7 +1010,7 @@ pmac_pci_enable_device_hook(struct pci_dev *dev, int initial) | |||
1037 | 1010 | ||
1038 | uninorth_child = node->parent && | 1011 | uninorth_child = node->parent && |
1039 | device_is_compatible(node->parent, "uni-north"); | 1012 | device_is_compatible(node->parent, "uni-north"); |
1040 | 1013 | ||
1041 | /* Firewire & GMAC were disabled after PCI probe, the driver is | 1014 | /* Firewire & GMAC were disabled after PCI probe, the driver is |
1042 | * claiming them, we must re-enable them now. | 1015 | * claiming them, we must re-enable them now. |
1043 | */ | 1016 | */ |
@@ -1057,7 +1030,7 @@ pmac_pci_enable_device_hook(struct pci_dev *dev, int initial) | |||
1057 | 1030 | ||
1058 | if (updatecfg) { | 1031 | if (updatecfg) { |
1059 | u16 cmd; | 1032 | u16 cmd; |
1060 | 1033 | ||
1061 | /* | 1034 | /* |
1062 | * Make sure PCI is correctly configured | 1035 | * Make sure PCI is correctly configured |
1063 | * | 1036 | * |
@@ -1069,10 +1042,12 @@ pmac_pci_enable_device_hook(struct pci_dev *dev, int initial) | |||
1069 | * register the device. | 1042 | * register the device. |
1070 | */ | 1043 | */ |
1071 | pci_read_config_word(dev, PCI_COMMAND, &cmd); | 1044 | pci_read_config_word(dev, PCI_COMMAND, &cmd); |
1072 | cmd |= PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER | PCI_COMMAND_INVALIDATE; | 1045 | cmd |= PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER |
1073 | pci_write_config_word(dev, PCI_COMMAND, cmd); | 1046 | | PCI_COMMAND_INVALIDATE; |
1074 | pci_write_config_byte(dev, PCI_LATENCY_TIMER, 16); | 1047 | pci_write_config_word(dev, PCI_COMMAND, cmd); |
1075 | pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, pci_cache_line_size); | 1048 | pci_write_config_byte(dev, PCI_LATENCY_TIMER, 16); |
1049 | pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, | ||
1050 | L1_CACHE_BYTES >> 2); | ||
1076 | } | 1051 | } |
1077 | 1052 | ||
1078 | return 0; | 1053 | return 0; |
@@ -1081,8 +1056,7 @@ pmac_pci_enable_device_hook(struct pci_dev *dev, int initial) | |||
1081 | /* We power down some devices after they have been probed. They'll | 1056 | /* We power down some devices after they have been probed. They'll |
1082 | * be powered back on later on | 1057 | * be powered back on later on |
1083 | */ | 1058 | */ |
1084 | void __init | 1059 | void __init pmac_pcibios_after_init(void) |
1085 | pmac_pcibios_after_init(void) | ||
1086 | { | 1060 | { |
1087 | struct device_node* nd; | 1061 | struct device_node* nd; |
1088 | 1062 | ||
@@ -1125,84 +1099,6 @@ pmac_pcibios_after_init(void) | |||
1125 | } | 1099 | } |
1126 | } | 1100 | } |
1127 | 1101 | ||
1128 | #ifdef CONFIG_PPC64 | ||
1129 | static void __init pmac_fixup_phb_resources(void) | ||
1130 | { | ||
1131 | struct pci_controller *hose, *tmp; | ||
1132 | |||
1133 | list_for_each_entry_safe(hose, tmp, &hose_list, list_node) { | ||
1134 | unsigned long offset = (unsigned long)hose->io_base_virt - pci_io_base; | ||
1135 | hose->io_resource.start += offset; | ||
1136 | hose->io_resource.end += offset; | ||
1137 | printk(KERN_INFO "PCI Host %d, io start: %lx; io end: %lx\n", | ||
1138 | hose->global_number, | ||
1139 | hose->io_resource.start, hose->io_resource.end); | ||
1140 | } | ||
1141 | } | ||
1142 | |||
1143 | void __init pmac_pci_init(void) | ||
1144 | { | ||
1145 | struct device_node *np, *root; | ||
1146 | struct device_node *ht = NULL; | ||
1147 | |||
1148 | /* Probe root PCI hosts, that is on U3 the AGP host and the | ||
1149 | * HyperTransport host. That one is actually "kept" around | ||
1150 | * and actually added last as it's resource management relies | ||
1151 | * on the AGP resources to have been setup first | ||
1152 | */ | ||
1153 | root = of_find_node_by_path("/"); | ||
1154 | if (root == NULL) { | ||
1155 | printk(KERN_CRIT "pmac_find_bridges: can't find root of device tree\n"); | ||
1156 | return; | ||
1157 | } | ||
1158 | for (np = NULL; (np = of_get_next_child(root, np)) != NULL;) { | ||
1159 | if (np->name == NULL) | ||
1160 | continue; | ||
1161 | if (strcmp(np->name, "pci") == 0) { | ||
1162 | if (add_bridge(np) == 0) | ||
1163 | of_node_get(np); | ||
1164 | } | ||
1165 | if (strcmp(np->name, "ht") == 0) { | ||
1166 | of_node_get(np); | ||
1167 | ht = np; | ||
1168 | } | ||
1169 | } | ||
1170 | of_node_put(root); | ||
1171 | |||
1172 | /* Now setup the HyperTransport host if we found any | ||
1173 | */ | ||
1174 | if (ht && add_bridge(ht) != 0) | ||
1175 | of_node_put(ht); | ||
1176 | |||
1177 | /* Fixup the IO resources on our host bridges as the common code | ||
1178 | * does it only for childs of the host bridges | ||
1179 | */ | ||
1180 | pmac_fixup_phb_resources(); | ||
1181 | |||
1182 | /* Setup the linkage between OF nodes and PHBs */ | ||
1183 | pci_devs_phb_init(); | ||
1184 | |||
1185 | /* Fixup the PCI<->OF mapping for U3 AGP due to bus renumbering. We | ||
1186 | * assume there is no P2P bridge on the AGP bus, which should be a | ||
1187 | * safe assumptions hopefully. | ||
1188 | */ | ||
1189 | if (u3_agp) { | ||
1190 | struct device_node *np = u3_agp->arch_data; | ||
1191 | PCI_DN(np)->busno = 0xf0; | ||
1192 | for (np = np->child; np; np = np->sibling) | ||
1193 | PCI_DN(np)->busno = 0xf0; | ||
1194 | } | ||
1195 | |||
1196 | pmac_check_ht_link(); | ||
1197 | |||
1198 | /* Tell pci.c to not use the common resource allocation mecanism */ | ||
1199 | pci_probe_only = 1; | ||
1200 | |||
1201 | /* Allow all IO */ | ||
1202 | io_page_mask = -1; | ||
1203 | } | ||
1204 | #endif | ||
1205 | |||
1206 | #ifdef CONFIG_PPC32 | 1102 | #ifdef CONFIG_PPC32 |
1207 | void pmac_pci_fixup_cardbus(struct pci_dev* dev) | 1103 | void pmac_pci_fixup_cardbus(struct pci_dev* dev) |
1208 | { | 1104 | { |
@@ -1217,7 +1113,7 @@ void pmac_pci_fixup_cardbus(struct pci_dev* dev) | |||
1217 | if (dev->device == PCI_DEVICE_ID_TI_1130 || | 1113 | if (dev->device == PCI_DEVICE_ID_TI_1130 || |
1218 | dev->device == PCI_DEVICE_ID_TI_1131) { | 1114 | dev->device == PCI_DEVICE_ID_TI_1131) { |
1219 | u8 val; | 1115 | u8 val; |
1220 | /* Enable PCI interrupt */ | 1116 | /* Enable PCI interrupt */ |
1221 | if (pci_read_config_byte(dev, 0x91, &val) == 0) | 1117 | if (pci_read_config_byte(dev, 0x91, &val) == 0) |
1222 | pci_write_config_byte(dev, 0x91, val | 0x30); | 1118 | pci_write_config_byte(dev, 0x91, val | 0x30); |
1223 | /* Disable ISA interrupt mode */ | 1119 | /* Disable ISA interrupt mode */ |
diff --git a/arch/powerpc/platforms/powermac/pic.c b/arch/powerpc/platforms/powermac/pic.c index 58017d18db70..0eca17df239e 100644 --- a/arch/powerpc/platforms/powermac/pic.c +++ b/arch/powerpc/platforms/powermac/pic.c | |||
@@ -430,7 +430,6 @@ void __init pmac_pic_init(void) | |||
430 | 430 | ||
431 | printk(KERN_INFO "PowerMac using OpenPIC irq controller at 0x%08x\n", | 431 | printk(KERN_INFO "PowerMac using OpenPIC irq controller at 0x%08x\n", |
432 | (unsigned int)irqctrler->addrs[0].address); | 432 | (unsigned int)irqctrler->addrs[0].address); |
433 | ppc_md.get_irq = mpic_get_irq; | ||
434 | pmac_call_feature(PMAC_FTR_ENABLE_MPIC, irqctrler, 0, 0); | 433 | pmac_call_feature(PMAC_FTR_ENABLE_MPIC, irqctrler, 0, 0); |
435 | 434 | ||
436 | prom_get_irq_senses(senses, 0, 128); | 435 | prom_get_irq_senses(senses, 0, 128); |
@@ -483,6 +482,7 @@ void __init pmac_pic_init(void) | |||
483 | * a Grand Central nor an OHare, then it's an Heathrow | 482 | * a Grand Central nor an OHare, then it's an Heathrow |
484 | * (or Paddington). | 483 | * (or Paddington). |
485 | */ | 484 | */ |
485 | ppc_md.get_irq = pmac_get_irq; | ||
486 | if (find_devices("gc")) | 486 | if (find_devices("gc")) |
487 | level_mask[0] = GC_LEVEL_MASK; | 487 | level_mask[0] = GC_LEVEL_MASK; |
488 | else if (find_devices("ohare")) { | 488 | else if (find_devices("ohare")) { |
diff --git a/arch/powerpc/platforms/powermac/pmac.h b/arch/powerpc/platforms/powermac/pmac.h index 0a9ba704865e..2ad25e13423e 100644 --- a/arch/powerpc/platforms/powermac/pmac.h +++ b/arch/powerpc/platforms/powermac/pmac.h | |||
@@ -19,7 +19,7 @@ extern int pmac_set_rtc_time(struct rtc_time *); | |||
19 | extern void pmac_read_rtc_time(void); | 19 | extern void pmac_read_rtc_time(void); |
20 | extern void pmac_calibrate_decr(void); | 20 | extern void pmac_calibrate_decr(void); |
21 | extern void pmac_pcibios_fixup(void); | 21 | extern void pmac_pcibios_fixup(void); |
22 | extern void pmac_find_bridges(void); | 22 | extern void pmac_pci_init(void); |
23 | extern unsigned long pmac_ide_get_base(int index); | 23 | extern unsigned long pmac_ide_get_base(int index); |
24 | extern void pmac_ide_init_hwif_ports(hw_regs_t *hw, | 24 | extern void pmac_ide_init_hwif_ports(hw_regs_t *hw, |
25 | unsigned long data_port, unsigned long ctrl_port, int *irq); | 25 | unsigned long data_port, unsigned long ctrl_port, int *irq); |
@@ -41,7 +41,7 @@ extern unsigned long pmac_ide_get_base(int index); | |||
41 | extern void pmac_ide_init_hwif_ports(hw_regs_t *hw, | 41 | extern void pmac_ide_init_hwif_ports(hw_regs_t *hw, |
42 | unsigned long data_port, unsigned long ctrl_port, int *irq); | 42 | unsigned long data_port, unsigned long ctrl_port, int *irq); |
43 | 43 | ||
44 | extern void pmac_nvram_init(void); | 44 | extern int pmac_nvram_init(void); |
45 | 45 | ||
46 | extern struct hw_interrupt_type pmac_pic; | 46 | extern struct hw_interrupt_type pmac_pic; |
47 | 47 | ||
diff --git a/arch/powerpc/platforms/powermac/setup.c b/arch/powerpc/platforms/powermac/setup.c index 0bad53fa36ef..da0cb165dfc6 100644 --- a/arch/powerpc/platforms/powermac/setup.c +++ b/arch/powerpc/platforms/powermac/setup.c | |||
@@ -1,11 +1,11 @@ | |||
1 | /* | 1 | /* |
2 | * arch/ppc/platforms/setup.c | 2 | * Powermac setup and early boot code plus other random bits. |
3 | * | 3 | * |
4 | * PowerPC version | 4 | * PowerPC version |
5 | * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) | 5 | * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) |
6 | * | 6 | * |
7 | * Adapted for Power Macintosh by Paul Mackerras | 7 | * Adapted for Power Macintosh by Paul Mackerras |
8 | * Copyright (C) 1996 Paul Mackerras (paulus@cs.anu.edu.au) | 8 | * Copyright (C) 1996 Paul Mackerras (paulus@samba.org) |
9 | * | 9 | * |
10 | * Derived from "arch/alpha/kernel/setup.c" | 10 | * Derived from "arch/alpha/kernel/setup.c" |
11 | * Copyright (C) 1995 Linus Torvalds | 11 | * Copyright (C) 1995 Linus Torvalds |
@@ -65,13 +65,16 @@ | |||
65 | #include <asm/mediabay.h> | 65 | #include <asm/mediabay.h> |
66 | #include <asm/machdep.h> | 66 | #include <asm/machdep.h> |
67 | #include <asm/dma.h> | 67 | #include <asm/dma.h> |
68 | #include <asm/bootx.h> | ||
69 | #include <asm/cputable.h> | 68 | #include <asm/cputable.h> |
70 | #include <asm/btext.h> | 69 | #include <asm/btext.h> |
71 | #include <asm/pmac_feature.h> | 70 | #include <asm/pmac_feature.h> |
72 | #include <asm/time.h> | 71 | #include <asm/time.h> |
73 | #include <asm/of_device.h> | 72 | #include <asm/of_device.h> |
74 | #include <asm/mmu_context.h> | 73 | #include <asm/mmu_context.h> |
74 | #include <asm/iommu.h> | ||
75 | #include <asm/smu.h> | ||
76 | #include <asm/pmc.h> | ||
77 | #include <asm/mpic.h> | ||
75 | 78 | ||
76 | #include "pmac.h" | 79 | #include "pmac.h" |
77 | 80 | ||
@@ -88,16 +91,24 @@ int pmac_newworld = 1; | |||
88 | static int current_root_goodness = -1; | 91 | static int current_root_goodness = -1; |
89 | 92 | ||
90 | extern int pmac_newworld; | 93 | extern int pmac_newworld; |
94 | extern struct machdep_calls pmac_md; | ||
91 | 95 | ||
92 | #define DEFAULT_ROOT_DEVICE Root_SDA1 /* sda1 - slightly silly choice */ | 96 | #define DEFAULT_ROOT_DEVICE Root_SDA1 /* sda1 - slightly silly choice */ |
93 | 97 | ||
94 | extern void zs_kgdb_hook(int tty_num); | 98 | #ifdef CONFIG_PPC64 |
95 | static void ohare_init(void); | 99 | #include <asm/udbg.h> |
96 | #ifdef CONFIG_BOOTX_TEXT | 100 | int sccdbg; |
97 | static void pmac_progress(char *s, unsigned short hex); | ||
98 | #endif | 101 | #endif |
99 | 102 | ||
103 | extern void zs_kgdb_hook(int tty_num); | ||
104 | |||
100 | sys_ctrler_t sys_ctrler = SYS_CTRLER_UNKNOWN; | 105 | sys_ctrler_t sys_ctrler = SYS_CTRLER_UNKNOWN; |
106 | EXPORT_SYMBOL(sys_ctrler); | ||
107 | |||
108 | #ifdef CONFIG_PMAC_SMU | ||
109 | unsigned long smu_cmdbuf_abs; | ||
110 | EXPORT_SYMBOL(smu_cmdbuf_abs); | ||
111 | #endif | ||
101 | 112 | ||
102 | #ifdef CONFIG_SMP | 113 | #ifdef CONFIG_SMP |
103 | extern struct smp_ops_t psurge_smp_ops; | 114 | extern struct smp_ops_t psurge_smp_ops; |
@@ -191,44 +202,69 @@ static void pmac_show_percpuinfo(struct seq_file *m, int i) | |||
191 | return; | 202 | return; |
192 | } | 203 | } |
193 | #endif /* CONFIG_CPU_FREQ_PMAC */ | 204 | #endif /* CONFIG_CPU_FREQ_PMAC */ |
205 | #ifdef CONFIG_PPC32 | ||
194 | of_show_percpuinfo(m, i); | 206 | of_show_percpuinfo(m, i); |
207 | #endif | ||
195 | } | 208 | } |
196 | 209 | ||
197 | static volatile u32 *sysctrl_regs; | 210 | #ifndef CONFIG_ADB_CUDA |
211 | int find_via_cuda(void) | ||
212 | { | ||
213 | if (!find_devices("via-cuda")) | ||
214 | return 0; | ||
215 | printk("WARNING ! Your machine is CUDA-based but your kernel\n"); | ||
216 | printk(" wasn't compiled with CONFIG_ADB_CUDA option !\n"); | ||
217 | return 0; | ||
218 | } | ||
219 | #endif | ||
198 | 220 | ||
199 | void __init | 221 | #ifndef CONFIG_ADB_PMU |
200 | pmac_setup_arch(void) | 222 | int find_via_pmu(void) |
201 | { | 223 | { |
202 | struct device_node *cpu; | 224 | if (!find_devices("via-pmu")) |
203 | int *fp; | 225 | return 0; |
204 | unsigned long pvr; | 226 | printk("WARNING ! Your machine is PMU-based but your kernel\n"); |
227 | printk(" wasn't compiled with CONFIG_ADB_PMU option !\n"); | ||
228 | return; | ||
229 | } | ||
230 | #endif | ||
205 | 231 | ||
206 | pvr = PVR_VER(mfspr(SPRN_PVR)); | 232 | #ifndef CONFIG_PMAC_SMU |
233 | int smu_init(void) | ||
234 | { | ||
235 | /* should check and warn if SMU is present */ | ||
236 | return 0; | ||
237 | } | ||
238 | #endif | ||
207 | 239 | ||
208 | /* Set loops_per_jiffy to a half-way reasonable value, | 240 | #ifdef CONFIG_PPC32 |
209 | for use until calibrate_delay gets called. */ | 241 | static volatile u32 *sysctrl_regs; |
210 | cpu = find_type_devices("cpu"); | ||
211 | if (cpu != 0) { | ||
212 | fp = (int *) get_property(cpu, "clock-frequency", NULL); | ||
213 | if (fp != 0) { | ||
214 | if (pvr == 4 || pvr >= 8) | ||
215 | /* 604, G3, G4 etc. */ | ||
216 | loops_per_jiffy = *fp / HZ; | ||
217 | else | ||
218 | /* 601, 603, etc. */ | ||
219 | loops_per_jiffy = *fp / (2*HZ); | ||
220 | } else | ||
221 | loops_per_jiffy = 50000000 / HZ; | ||
222 | } | ||
223 | 242 | ||
243 | static void __init ohare_init(void) | ||
244 | { | ||
224 | /* this area has the CPU identification register | 245 | /* this area has the CPU identification register |
225 | and some registers used by smp boards */ | 246 | and some registers used by smp boards */ |
226 | sysctrl_regs = (volatile u32 *) ioremap(0xf8000000, 0x1000); | 247 | sysctrl_regs = (volatile u32 *) ioremap(0xf8000000, 0x1000); |
227 | ohare_init(); | ||
228 | 248 | ||
229 | /* Lookup PCI hosts */ | 249 | /* |
230 | pmac_find_bridges(); | 250 | * Turn on the L2 cache. |
251 | * We assume that we have a PSX memory controller iff | ||
252 | * we have an ohare I/O controller. | ||
253 | */ | ||
254 | if (find_devices("ohare") != NULL) { | ||
255 | if (((sysctrl_regs[2] >> 24) & 0xf) >= 3) { | ||
256 | if (sysctrl_regs[4] & 0x10) | ||
257 | sysctrl_regs[4] |= 0x04000020; | ||
258 | else | ||
259 | sysctrl_regs[4] |= 0x04000000; | ||
260 | if(has_l2cache) | ||
261 | printk(KERN_INFO "Level 2 cache enabled\n"); | ||
262 | } | ||
263 | } | ||
264 | } | ||
231 | 265 | ||
266 | static void __init l2cr_init(void) | ||
267 | { | ||
232 | /* Checks "l2cr-value" property in the registry */ | 268 | /* Checks "l2cr-value" property in the registry */ |
233 | if (cpu_has_feature(CPU_FTR_L2CR)) { | 269 | if (cpu_has_feature(CPU_FTR_L2CR)) { |
234 | struct device_node *np = find_devices("cpus"); | 270 | struct device_node *np = find_devices("cpus"); |
@@ -247,68 +283,90 @@ pmac_setup_arch(void) | |||
247 | } | 283 | } |
248 | 284 | ||
249 | if (ppc_override_l2cr) | 285 | if (ppc_override_l2cr) |
250 | printk(KERN_INFO "L2CR overriden (0x%x), backside cache is %s\n", | 286 | printk(KERN_INFO "L2CR overridden (0x%x), " |
251 | ppc_override_l2cr_value, (ppc_override_l2cr_value & 0x80000000) | 287 | "backside cache is %s\n", |
288 | ppc_override_l2cr_value, | ||
289 | (ppc_override_l2cr_value & 0x80000000) | ||
252 | ? "enabled" : "disabled"); | 290 | ? "enabled" : "disabled"); |
291 | } | ||
292 | #endif | ||
293 | |||
294 | void __init pmac_setup_arch(void) | ||
295 | { | ||
296 | struct device_node *cpu; | ||
297 | int *fp; | ||
298 | unsigned long pvr; | ||
299 | |||
300 | pvr = PVR_VER(mfspr(SPRN_PVR)); | ||
301 | |||
302 | /* Set loops_per_jiffy to a half-way reasonable value, | ||
303 | for use until calibrate_delay gets called. */ | ||
304 | loops_per_jiffy = 50000000 / HZ; | ||
305 | cpu = of_find_node_by_type(NULL, "cpu"); | ||
306 | if (cpu != NULL) { | ||
307 | fp = (int *) get_property(cpu, "clock-frequency", NULL); | ||
308 | if (fp != NULL) { | ||
309 | if (pvr >= 0x30 && pvr < 0x80) | ||
310 | /* PPC970 etc. */ | ||
311 | loops_per_jiffy = *fp / (3 * HZ); | ||
312 | else if (pvr == 4 || pvr >= 8) | ||
313 | /* 604, G3, G4 etc. */ | ||
314 | loops_per_jiffy = *fp / HZ; | ||
315 | else | ||
316 | /* 601, 603, etc. */ | ||
317 | loops_per_jiffy = *fp / (2 * HZ); | ||
318 | } | ||
319 | of_node_put(cpu); | ||
320 | } | ||
321 | |||
322 | /* Lookup PCI hosts */ | ||
323 | pmac_pci_init(); | ||
324 | |||
325 | #ifdef CONFIG_PPC32 | ||
326 | ohare_init(); | ||
327 | l2cr_init(); | ||
328 | #endif /* CONFIG_PPC32 */ | ||
329 | |||
330 | #ifdef CONFIG_PPC64 | ||
331 | /* Probe motherboard chipset */ | ||
332 | /* this is done earlier in setup_arch for 32-bit */ | ||
333 | pmac_feature_init(); | ||
334 | |||
335 | /* We can NAP */ | ||
336 | powersave_nap = 1; | ||
337 | printk(KERN_INFO "Using native/NAP idle loop\n"); | ||
338 | #endif | ||
253 | 339 | ||
254 | #ifdef CONFIG_KGDB | 340 | #ifdef CONFIG_KGDB |
255 | zs_kgdb_hook(0); | 341 | zs_kgdb_hook(0); |
256 | #endif | 342 | #endif |
257 | 343 | ||
258 | #ifdef CONFIG_ADB_CUDA | ||
259 | find_via_cuda(); | 344 | find_via_cuda(); |
260 | #else | ||
261 | if (find_devices("via-cuda")) { | ||
262 | printk("WARNING ! Your machine is Cuda based but your kernel\n"); | ||
263 | printk(" wasn't compiled with CONFIG_ADB_CUDA option !\n"); | ||
264 | } | ||
265 | #endif | ||
266 | #ifdef CONFIG_ADB_PMU | ||
267 | find_via_pmu(); | 345 | find_via_pmu(); |
268 | #else | 346 | smu_init(); |
269 | if (find_devices("via-pmu")) { | 347 | |
270 | printk("WARNING ! Your machine is PMU based but your kernel\n"); | ||
271 | printk(" wasn't compiled with CONFIG_ADB_PMU option !\n"); | ||
272 | } | ||
273 | #endif | ||
274 | #ifdef CONFIG_NVRAM | 348 | #ifdef CONFIG_NVRAM |
275 | pmac_nvram_init(); | 349 | pmac_nvram_init(); |
276 | #endif | 350 | #endif |
351 | |||
352 | #ifdef CONFIG_PPC32 | ||
277 | #ifdef CONFIG_BLK_DEV_INITRD | 353 | #ifdef CONFIG_BLK_DEV_INITRD |
278 | if (initrd_start) | 354 | if (initrd_start) |
279 | ROOT_DEV = Root_RAM0; | 355 | ROOT_DEV = Root_RAM0; |
280 | else | 356 | else |
281 | #endif | 357 | #endif |
282 | ROOT_DEV = DEFAULT_ROOT_DEVICE; | 358 | ROOT_DEV = DEFAULT_ROOT_DEVICE; |
359 | #endif | ||
283 | 360 | ||
284 | #ifdef CONFIG_SMP | 361 | #ifdef CONFIG_SMP |
285 | /* Check for Core99 */ | 362 | /* Check for Core99 */ |
286 | if (find_devices("uni-n") || find_devices("u3")) | 363 | if (find_devices("uni-n") || find_devices("u3")) |
287 | smp_ops = &core99_smp_ops; | 364 | smp_ops = &core99_smp_ops; |
365 | #ifdef CONFIG_PPC32 | ||
288 | else | 366 | else |
289 | smp_ops = &psurge_smp_ops; | 367 | smp_ops = &psurge_smp_ops; |
368 | #endif | ||
290 | #endif /* CONFIG_SMP */ | 369 | #endif /* CONFIG_SMP */ |
291 | |||
292 | pci_create_OF_bus_map(); | ||
293 | } | ||
294 | |||
295 | static void __init ohare_init(void) | ||
296 | { | ||
297 | /* | ||
298 | * Turn on the L2 cache. | ||
299 | * We assume that we have a PSX memory controller iff | ||
300 | * we have an ohare I/O controller. | ||
301 | */ | ||
302 | if (find_devices("ohare") != NULL) { | ||
303 | if (((sysctrl_regs[2] >> 24) & 0xf) >= 3) { | ||
304 | if (sysctrl_regs[4] & 0x10) | ||
305 | sysctrl_regs[4] |= 0x04000020; | ||
306 | else | ||
307 | sysctrl_regs[4] |= 0x04000000; | ||
308 | if(has_l2cache) | ||
309 | printk(KERN_INFO "Level 2 cache enabled\n"); | ||
310 | } | ||
311 | } | ||
312 | } | 370 | } |
313 | 371 | ||
314 | char *bootpath; | 372 | char *bootpath; |
@@ -319,8 +377,7 @@ int boot_part; | |||
319 | extern dev_t boot_dev; | 377 | extern dev_t boot_dev; |
320 | 378 | ||
321 | #ifdef CONFIG_SCSI | 379 | #ifdef CONFIG_SCSI |
322 | void __init | 380 | void __init note_scsi_host(struct device_node *node, void *host) |
323 | note_scsi_host(struct device_node *node, void *host) | ||
324 | { | 381 | { |
325 | int l; | 382 | int l; |
326 | char *p; | 383 | char *p; |
@@ -351,8 +408,7 @@ EXPORT_SYMBOL(note_scsi_host); | |||
351 | #endif | 408 | #endif |
352 | 409 | ||
353 | #if defined(CONFIG_BLK_DEV_IDE) && defined(CONFIG_BLK_DEV_IDE_PMAC) | 410 | #if defined(CONFIG_BLK_DEV_IDE) && defined(CONFIG_BLK_DEV_IDE_PMAC) |
354 | static dev_t __init | 411 | static dev_t __init find_ide_boot(void) |
355 | find_ide_boot(void) | ||
356 | { | 412 | { |
357 | char *p; | 413 | char *p; |
358 | int n; | 414 | int n; |
@@ -369,15 +425,13 @@ find_ide_boot(void) | |||
369 | } | 425 | } |
370 | #endif /* CONFIG_BLK_DEV_IDE && CONFIG_BLK_DEV_IDE_PMAC */ | 426 | #endif /* CONFIG_BLK_DEV_IDE && CONFIG_BLK_DEV_IDE_PMAC */ |
371 | 427 | ||
372 | static void __init | 428 | static void __init find_boot_device(void) |
373 | find_boot_device(void) | ||
374 | { | 429 | { |
375 | #if defined(CONFIG_BLK_DEV_IDE) && defined(CONFIG_BLK_DEV_IDE_PMAC) | 430 | #if defined(CONFIG_BLK_DEV_IDE) && defined(CONFIG_BLK_DEV_IDE_PMAC) |
376 | boot_dev = find_ide_boot(); | 431 | boot_dev = find_ide_boot(); |
377 | #endif | 432 | #endif |
378 | } | 433 | } |
379 | 434 | ||
380 | static int initializing = 1; | ||
381 | /* TODO: Merge the suspend-to-ram with the common code !!! | 435 | /* TODO: Merge the suspend-to-ram with the common code !!! |
382 | * currently, this is a stub implementation for suspend-to-disk | 436 | * currently, this is a stub implementation for suspend-to-disk |
383 | * only | 437 | * only |
@@ -428,6 +482,8 @@ static struct pm_ops pmac_pm_ops = { | |||
428 | 482 | ||
429 | #endif /* CONFIG_SOFTWARE_SUSPEND */ | 483 | #endif /* CONFIG_SOFTWARE_SUSPEND */ |
430 | 484 | ||
485 | static int initializing = 1; | ||
486 | |||
431 | static int pmac_late_init(void) | 487 | static int pmac_late_init(void) |
432 | { | 488 | { |
433 | initializing = 0; | 489 | initializing = 0; |
@@ -440,8 +496,7 @@ static int pmac_late_init(void) | |||
440 | late_initcall(pmac_late_init); | 496 | late_initcall(pmac_late_init); |
441 | 497 | ||
442 | /* can't be __init - can be called whenever a disk is first accessed */ | 498 | /* can't be __init - can be called whenever a disk is first accessed */ |
443 | void | 499 | void note_bootable_part(dev_t dev, int part, int goodness) |
444 | note_bootable_part(dev_t dev, int part, int goodness) | ||
445 | { | 500 | { |
446 | static int found_boot = 0; | 501 | static int found_boot = 0; |
447 | char *p; | 502 | char *p; |
@@ -466,52 +521,68 @@ note_bootable_part(dev_t dev, int part, int goodness) | |||
466 | } | 521 | } |
467 | } | 522 | } |
468 | 523 | ||
469 | static void | ||
470 | pmac_restart(char *cmd) | ||
471 | { | ||
472 | #ifdef CONFIG_ADB_CUDA | 524 | #ifdef CONFIG_ADB_CUDA |
525 | static void cuda_restart(void) | ||
526 | { | ||
473 | struct adb_request req; | 527 | struct adb_request req; |
474 | #endif /* CONFIG_ADB_CUDA */ | ||
475 | 528 | ||
529 | cuda_request(&req, NULL, 2, CUDA_PACKET, CUDA_RESET_SYSTEM); | ||
530 | for (;;) | ||
531 | cuda_poll(); | ||
532 | } | ||
533 | |||
534 | static void cuda_shutdown(void) | ||
535 | { | ||
536 | struct adb_request req; | ||
537 | |||
538 | cuda_request(&req, NULL, 2, CUDA_PACKET, CUDA_POWERDOWN); | ||
539 | for (;;) | ||
540 | cuda_poll(); | ||
541 | } | ||
542 | |||
543 | #else | ||
544 | #define cuda_restart() | ||
545 | #define cuda_shutdown() | ||
546 | #endif | ||
547 | |||
548 | #ifndef CONFIG_ADB_PMU | ||
549 | #define pmu_restart() | ||
550 | #define pmu_shutdown() | ||
551 | #endif | ||
552 | |||
553 | #ifndef CONFIG_PMAC_SMU | ||
554 | #define smu_restart() | ||
555 | #define smu_shutdown() | ||
556 | #endif | ||
557 | |||
558 | static void pmac_restart(char *cmd) | ||
559 | { | ||
476 | switch (sys_ctrler) { | 560 | switch (sys_ctrler) { |
477 | #ifdef CONFIG_ADB_CUDA | ||
478 | case SYS_CTRLER_CUDA: | 561 | case SYS_CTRLER_CUDA: |
479 | cuda_request(&req, NULL, 2, CUDA_PACKET, | 562 | cuda_restart(); |
480 | CUDA_RESET_SYSTEM); | ||
481 | for (;;) | ||
482 | cuda_poll(); | ||
483 | break; | 563 | break; |
484 | #endif /* CONFIG_ADB_CUDA */ | ||
485 | #ifdef CONFIG_ADB_PMU | ||
486 | case SYS_CTRLER_PMU: | 564 | case SYS_CTRLER_PMU: |
487 | pmu_restart(); | 565 | pmu_restart(); |
488 | break; | 566 | break; |
489 | #endif /* CONFIG_ADB_PMU */ | 567 | case SYS_CTRLER_SMU: |
568 | smu_restart(); | ||
569 | break; | ||
490 | default: ; | 570 | default: ; |
491 | } | 571 | } |
492 | } | 572 | } |
493 | 573 | ||
494 | static void | 574 | static void pmac_power_off(void) |
495 | pmac_power_off(void) | ||
496 | { | 575 | { |
497 | #ifdef CONFIG_ADB_CUDA | ||
498 | struct adb_request req; | ||
499 | #endif /* CONFIG_ADB_CUDA */ | ||
500 | |||
501 | switch (sys_ctrler) { | 576 | switch (sys_ctrler) { |
502 | #ifdef CONFIG_ADB_CUDA | ||
503 | case SYS_CTRLER_CUDA: | 577 | case SYS_CTRLER_CUDA: |
504 | cuda_request(&req, NULL, 2, CUDA_PACKET, | 578 | cuda_shutdown(); |
505 | CUDA_POWERDOWN); | ||
506 | for (;;) | ||
507 | cuda_poll(); | ||
508 | break; | 579 | break; |
509 | #endif /* CONFIG_ADB_CUDA */ | ||
510 | #ifdef CONFIG_ADB_PMU | ||
511 | case SYS_CTRLER_PMU: | 580 | case SYS_CTRLER_PMU: |
512 | pmu_shutdown(); | 581 | pmu_shutdown(); |
513 | break; | 582 | break; |
514 | #endif /* CONFIG_ADB_PMU */ | 583 | case SYS_CTRLER_SMU: |
584 | smu_shutdown(); | ||
585 | break; | ||
515 | default: ; | 586 | default: ; |
516 | } | 587 | } |
517 | } | 588 | } |
@@ -522,37 +593,17 @@ pmac_halt(void) | |||
522 | pmac_power_off(); | 593 | pmac_power_off(); |
523 | } | 594 | } |
524 | 595 | ||
596 | #ifdef CONFIG_PPC32 | ||
525 | void __init pmac_init(void) | 597 | void __init pmac_init(void) |
526 | { | 598 | { |
527 | /* isa_io_base gets set in pmac_find_bridges */ | 599 | /* isa_io_base gets set in pmac_pci_init */ |
528 | isa_mem_base = PMAC_ISA_MEM_BASE; | 600 | isa_mem_base = PMAC_ISA_MEM_BASE; |
529 | pci_dram_offset = PMAC_PCI_DRAM_OFFSET; | 601 | pci_dram_offset = PMAC_PCI_DRAM_OFFSET; |
530 | ISA_DMA_THRESHOLD = ~0L; | 602 | ISA_DMA_THRESHOLD = ~0L; |
531 | DMA_MODE_READ = 1; | 603 | DMA_MODE_READ = 1; |
532 | DMA_MODE_WRITE = 2; | 604 | DMA_MODE_WRITE = 2; |
533 | 605 | ||
534 | ppc_md.setup_arch = pmac_setup_arch; | 606 | ppc_md = pmac_md; |
535 | ppc_md.show_cpuinfo = pmac_show_cpuinfo; | ||
536 | ppc_md.show_percpuinfo = pmac_show_percpuinfo; | ||
537 | ppc_md.init_IRQ = pmac_pic_init; | ||
538 | ppc_md.get_irq = pmac_get_irq; /* Changed later on ... */ | ||
539 | |||
540 | ppc_md.pcibios_fixup = pmac_pcibios_fixup; | ||
541 | ppc_md.pcibios_enable_device_hook = pmac_pci_enable_device_hook; | ||
542 | ppc_md.pcibios_after_init = pmac_pcibios_after_init; | ||
543 | ppc_md.phys_mem_access_prot = pci_phys_mem_access_prot; | ||
544 | |||
545 | ppc_md.restart = pmac_restart; | ||
546 | ppc_md.power_off = pmac_power_off; | ||
547 | ppc_md.halt = pmac_halt; | ||
548 | |||
549 | ppc_md.time_init = pmac_time_init; | ||
550 | ppc_md.set_rtc_time = pmac_set_rtc_time; | ||
551 | ppc_md.get_rtc_time = pmac_get_rtc_time; | ||
552 | ppc_md.get_boot_time = pmac_get_boot_time; | ||
553 | ppc_md.calibrate_decr = pmac_calibrate_decr; | ||
554 | |||
555 | ppc_md.feature_call = pmac_do_feature_call; | ||
556 | 607 | ||
557 | #if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE) | 608 | #if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE) |
558 | #ifdef CONFIG_BLK_DEV_IDE_PMAC | 609 | #ifdef CONFIG_BLK_DEV_IDE_PMAC |
@@ -561,27 +612,62 @@ void __init pmac_init(void) | |||
561 | #endif /* CONFIG_BLK_DEV_IDE_PMAC */ | 612 | #endif /* CONFIG_BLK_DEV_IDE_PMAC */ |
562 | #endif /* defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE) */ | 613 | #endif /* defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE) */ |
563 | 614 | ||
564 | #ifdef CONFIG_BOOTX_TEXT | ||
565 | ppc_md.progress = pmac_progress; | ||
566 | #endif /* CONFIG_BOOTX_TEXT */ | ||
567 | |||
568 | if (ppc_md.progress) ppc_md.progress("pmac_init(): exit", 0); | 615 | if (ppc_md.progress) ppc_md.progress("pmac_init(): exit", 0); |
569 | 616 | ||
570 | } | 617 | } |
618 | #endif | ||
571 | 619 | ||
572 | #ifdef CONFIG_BOOTX_TEXT | 620 | /* |
573 | static void __init | 621 | * Early initialization. |
574 | pmac_progress(char *s, unsigned short hex) | 622 | */ |
623 | static void __init pmac_init_early(void) | ||
624 | { | ||
625 | #ifdef CONFIG_PPC64 | ||
626 | /* Initialize hash table, from now on, we can take hash faults | ||
627 | * and call ioremap | ||
628 | */ | ||
629 | hpte_init_native(); | ||
630 | |||
631 | /* Init SCC */ | ||
632 | if (strstr(cmd_line, "sccdbg")) { | ||
633 | sccdbg = 1; | ||
634 | udbg_init_scc(NULL); | ||
635 | } | ||
636 | |||
637 | /* Setup interrupt mapping options */ | ||
638 | ppc64_interrupt_controller = IC_OPEN_PIC; | ||
639 | |||
640 | iommu_init_early_u3(); | ||
641 | #endif | ||
642 | } | ||
643 | |||
644 | static void __init pmac_progress(char *s, unsigned short hex) | ||
575 | { | 645 | { |
646 | #ifdef CONFIG_PPC64 | ||
647 | if (sccdbg) { | ||
648 | udbg_puts(s); | ||
649 | udbg_puts("\n"); | ||
650 | return; | ||
651 | } | ||
652 | #endif | ||
653 | #ifdef CONFIG_BOOTX_TEXT | ||
576 | if (boot_text_mapped) { | 654 | if (boot_text_mapped) { |
577 | btext_drawstring(s); | 655 | btext_drawstring(s); |
578 | btext_drawchar('\n'); | 656 | btext_drawchar('\n'); |
579 | } | 657 | } |
580 | } | ||
581 | #endif /* CONFIG_BOOTX_TEXT */ | 658 | #endif /* CONFIG_BOOTX_TEXT */ |
659 | } | ||
582 | 660 | ||
583 | static int __init | 661 | /* |
584 | pmac_declare_of_platform_devices(void) | 662 | * pmac has no legacy IO, anything calling this function has to |
663 | * fail or bad things will happen | ||
664 | */ | ||
665 | static int pmac_check_legacy_ioport(unsigned int baseport) | ||
666 | { | ||
667 | return -ENODEV; | ||
668 | } | ||
669 | |||
670 | static int __init pmac_declare_of_platform_devices(void) | ||
585 | { | 671 | { |
586 | struct device_node *np; | 672 | struct device_node *np; |
587 | 673 | ||
@@ -594,6 +680,13 @@ pmac_declare_of_platform_devices(void) | |||
594 | break; | 680 | break; |
595 | } | 681 | } |
596 | } | 682 | } |
683 | np = find_devices("valkyrie"); | ||
684 | if (np) | ||
685 | of_platform_device_create(np, "valkyrie", NULL); | ||
686 | np = find_devices("platinum"); | ||
687 | if (np) | ||
688 | of_platform_device_create(np, "platinum", NULL); | ||
689 | |||
597 | np = find_devices("u3"); | 690 | np = find_devices("u3"); |
598 | if (np) { | 691 | if (np) { |
599 | for (np = np->child; np != NULL; np = np->sibling) | 692 | for (np = np->child; np != NULL; np = np->sibling) |
@@ -603,15 +696,92 @@ pmac_declare_of_platform_devices(void) | |||
603 | break; | 696 | break; |
604 | } | 697 | } |
605 | } | 698 | } |
606 | 699 | np = of_find_node_by_type(NULL, "smu"); | |
607 | np = find_devices("valkyrie"); | 700 | if (np) { |
608 | if (np) | 701 | of_platform_device_create(np, "smu", NULL); |
609 | of_platform_device_create(np, "valkyrie", NULL); | 702 | of_node_put(np); |
610 | np = find_devices("platinum"); | 703 | } |
611 | if (np) | ||
612 | of_platform_device_create(np, "platinum", NULL); | ||
613 | 704 | ||
614 | return 0; | 705 | return 0; |
615 | } | 706 | } |
616 | 707 | ||
617 | device_initcall(pmac_declare_of_platform_devices); | 708 | device_initcall(pmac_declare_of_platform_devices); |
709 | |||
710 | /* | ||
711 | * Called very early, MMU is off, device-tree isn't unflattened | ||
712 | */ | ||
713 | static int __init pmac_probe(int platform) | ||
714 | { | ||
715 | #ifdef CONFIG_PPC64 | ||
716 | if (platform != PLATFORM_POWERMAC) | ||
717 | return 0; | ||
718 | |||
719 | /* | ||
720 | * On U3, the DART (iommu) must be allocated now since it | ||
721 | * has an impact on htab_initialize (due to the large page it | ||
722 | * occupies having to be broken up so the DART itself is not | ||
723 | * part of the cacheable linar mapping | ||
724 | */ | ||
725 | alloc_u3_dart_table(); | ||
726 | #endif | ||
727 | |||
728 | #ifdef CONFIG_PMAC_SMU | ||
729 | /* | ||
730 | * SMU based G5s need some memory below 2Gb, at least the current | ||
731 | * driver needs that. We have to allocate it now. We allocate 4k | ||
732 | * (1 small page) for now. | ||
733 | */ | ||
734 | smu_cmdbuf_abs = lmb_alloc_base(4096, 4096, 0x80000000UL); | ||
735 | #endif /* CONFIG_PMAC_SMU */ | ||
736 | |||
737 | return 1; | ||
738 | } | ||
739 | |||
740 | #ifdef CONFIG_PPC64 | ||
741 | static int pmac_probe_mode(struct pci_bus *bus) | ||
742 | { | ||
743 | struct device_node *node = bus->sysdata; | ||
744 | |||
745 | /* We need to use normal PCI probing for the AGP bus, | ||
746 | since the device for the AGP bridge isn't in the tree. */ | ||
747 | if (bus->self == NULL && device_is_compatible(node, "u3-agp")) | ||
748 | return PCI_PROBE_NORMAL; | ||
749 | |||
750 | return PCI_PROBE_DEVTREE; | ||
751 | } | ||
752 | #endif | ||
753 | |||
754 | struct machdep_calls __initdata pmac_md = { | ||
755 | #if defined(CONFIG_HOTPLUG_CPU) && defined(CONFIG_PPC64) | ||
756 | .cpu_die = generic_mach_cpu_die, | ||
757 | #endif | ||
758 | .probe = pmac_probe, | ||
759 | .setup_arch = pmac_setup_arch, | ||
760 | .init_early = pmac_init_early, | ||
761 | .show_cpuinfo = pmac_show_cpuinfo, | ||
762 | .show_percpuinfo = pmac_show_percpuinfo, | ||
763 | .init_IRQ = pmac_pic_init, | ||
764 | .get_irq = mpic_get_irq, /* changed later */ | ||
765 | .pcibios_fixup = pmac_pcibios_fixup, | ||
766 | .restart = pmac_restart, | ||
767 | .power_off = pmac_power_off, | ||
768 | .halt = pmac_halt, | ||
769 | .time_init = pmac_time_init, | ||
770 | .get_boot_time = pmac_get_boot_time, | ||
771 | .set_rtc_time = pmac_set_rtc_time, | ||
772 | .get_rtc_time = pmac_get_rtc_time, | ||
773 | .calibrate_decr = pmac_calibrate_decr, | ||
774 | .feature_call = pmac_do_feature_call, | ||
775 | .check_legacy_ioport = pmac_check_legacy_ioport, | ||
776 | .progress = pmac_progress, | ||
777 | #ifdef CONFIG_PPC64 | ||
778 | .pci_probe_mode = pmac_probe_mode, | ||
779 | .idle_loop = native_idle, | ||
780 | .enable_pmcs = power4_enable_pmcs, | ||
781 | #endif | ||
782 | #ifdef CONFIG_PPC32 | ||
783 | .pcibios_enable_device_hook = pmac_pci_enable_device_hook, | ||
784 | .pcibios_after_init = pmac_pcibios_after_init, | ||
785 | .phys_mem_access_prot = pci_phys_mem_access_prot, | ||
786 | #endif | ||
787 | }; | ||
diff --git a/arch/powerpc/platforms/powermac/smp.c b/arch/powerpc/platforms/powermac/smp.c index ccaa0534d60f..e1f9443cc872 100644 --- a/arch/powerpc/platforms/powermac/smp.c +++ b/arch/powerpc/platforms/powermac/smp.c | |||
@@ -44,20 +44,33 @@ | |||
44 | #include <asm/io.h> | 44 | #include <asm/io.h> |
45 | #include <asm/prom.h> | 45 | #include <asm/prom.h> |
46 | #include <asm/smp.h> | 46 | #include <asm/smp.h> |
47 | #include <asm/residual.h> | ||
48 | #include <asm/machdep.h> | 47 | #include <asm/machdep.h> |
49 | #include <asm/pmac_feature.h> | 48 | #include <asm/pmac_feature.h> |
50 | #include <asm/time.h> | 49 | #include <asm/time.h> |
51 | #include <asm/mpic.h> | 50 | #include <asm/mpic.h> |
52 | #include <asm/cacheflush.h> | 51 | #include <asm/cacheflush.h> |
53 | #include <asm/keylargo.h> | 52 | #include <asm/keylargo.h> |
53 | #include <asm/pmac_low_i2c.h> | ||
54 | |||
55 | #undef DEBUG | ||
56 | |||
57 | #ifdef DEBUG | ||
58 | #define DBG(fmt...) udbg_printf(fmt) | ||
59 | #else | ||
60 | #define DBG(fmt...) | ||
61 | #endif | ||
62 | |||
63 | extern void __secondary_start_pmac_0(void); | ||
64 | |||
65 | #ifdef CONFIG_PPC32 | ||
66 | |||
67 | /* Sync flag for HW tb sync */ | ||
68 | static volatile int sec_tb_reset = 0; | ||
54 | 69 | ||
55 | /* | 70 | /* |
56 | * Powersurge (old powermac SMP) support. | 71 | * Powersurge (old powermac SMP) support. |
57 | */ | 72 | */ |
58 | 73 | ||
59 | extern void __secondary_start_pmac_0(void); | ||
60 | |||
61 | /* Addresses for powersurge registers */ | 74 | /* Addresses for powersurge registers */ |
62 | #define HAMMERHEAD_BASE 0xf8000000 | 75 | #define HAMMERHEAD_BASE 0xf8000000 |
63 | #define HHEAD_CONFIG 0x90 | 76 | #define HHEAD_CONFIG 0x90 |
@@ -106,47 +119,6 @@ static volatile u32 __iomem *psurge_start; | |||
106 | /* what sort of powersurge board we have */ | 119 | /* what sort of powersurge board we have */ |
107 | static int psurge_type = PSURGE_NONE; | 120 | static int psurge_type = PSURGE_NONE; |
108 | 121 | ||
109 | /* L2 and L3 cache settings to pass from CPU0 to CPU1 */ | ||
110 | volatile static long int core99_l2_cache; | ||
111 | volatile static long int core99_l3_cache; | ||
112 | |||
113 | /* Timebase freeze GPIO */ | ||
114 | static unsigned int core99_tb_gpio; | ||
115 | |||
116 | /* Sync flag for HW tb sync */ | ||
117 | static volatile int sec_tb_reset = 0; | ||
118 | static unsigned int pri_tb_hi, pri_tb_lo; | ||
119 | static unsigned int pri_tb_stamp; | ||
120 | |||
121 | static void __devinit core99_init_caches(int cpu) | ||
122 | { | ||
123 | if (!cpu_has_feature(CPU_FTR_L2CR)) | ||
124 | return; | ||
125 | |||
126 | if (cpu == 0) { | ||
127 | core99_l2_cache = _get_L2CR(); | ||
128 | printk("CPU0: L2CR is %lx\n", core99_l2_cache); | ||
129 | } else { | ||
130 | printk("CPU%d: L2CR was %lx\n", cpu, _get_L2CR()); | ||
131 | _set_L2CR(0); | ||
132 | _set_L2CR(core99_l2_cache); | ||
133 | printk("CPU%d: L2CR set to %lx\n", cpu, core99_l2_cache); | ||
134 | } | ||
135 | |||
136 | if (!cpu_has_feature(CPU_FTR_L3CR)) | ||
137 | return; | ||
138 | |||
139 | if (cpu == 0){ | ||
140 | core99_l3_cache = _get_L3CR(); | ||
141 | printk("CPU0: L3CR is %lx\n", core99_l3_cache); | ||
142 | } else { | ||
143 | printk("CPU%d: L3CR was %lx\n", cpu, _get_L3CR()); | ||
144 | _set_L3CR(0); | ||
145 | _set_L3CR(core99_l3_cache); | ||
146 | printk("CPU%d: L3CR set to %lx\n", cpu, core99_l3_cache); | ||
147 | } | ||
148 | } | ||
149 | |||
150 | /* | 122 | /* |
151 | * Set and clear IPIs for powersurge. | 123 | * Set and clear IPIs for powersurge. |
152 | */ | 124 | */ |
@@ -436,151 +408,188 @@ void __init smp_psurge_give_timebase(void) | |||
436 | /* Dummy implementation */ | 408 | /* Dummy implementation */ |
437 | } | 409 | } |
438 | 410 | ||
439 | static int __init smp_core99_probe(void) | 411 | /* PowerSurge-style Macs */ |
440 | { | 412 | struct smp_ops_t psurge_smp_ops = { |
441 | #ifdef CONFIG_6xx | 413 | .message_pass = smp_psurge_message_pass, |
442 | extern int powersave_nap; | 414 | .probe = smp_psurge_probe, |
443 | #endif | 415 | .kick_cpu = smp_psurge_kick_cpu, |
444 | struct device_node *cpus, *firstcpu; | 416 | .setup_cpu = smp_psurge_setup_cpu, |
445 | int i, ncpus = 0, boot_cpu = -1; | 417 | .give_timebase = smp_psurge_give_timebase, |
446 | u32 *tbprop = NULL; | 418 | .take_timebase = smp_psurge_take_timebase, |
447 | 419 | }; | |
448 | if (ppc_md.progress) ppc_md.progress("smp_core99_probe", 0x345); | 420 | #endif /* CONFIG_PPC32 - actually powersurge support */ |
449 | cpus = firstcpu = find_type_devices("cpu"); | ||
450 | while(cpus != NULL) { | ||
451 | u32 *regprop = (u32 *)get_property(cpus, "reg", NULL); | ||
452 | char *stateprop = (char *)get_property(cpus, "state", NULL); | ||
453 | if (regprop != NULL && stateprop != NULL && | ||
454 | !strncmp(stateprop, "running", 7)) | ||
455 | boot_cpu = *regprop; | ||
456 | ++ncpus; | ||
457 | cpus = cpus->next; | ||
458 | } | ||
459 | if (boot_cpu == -1) | ||
460 | printk(KERN_WARNING "Couldn't detect boot CPU !\n"); | ||
461 | if (boot_cpu != 0) | ||
462 | printk(KERN_WARNING "Boot CPU is %d, unsupported setup !\n", boot_cpu); | ||
463 | 421 | ||
464 | if (machine_is_compatible("MacRISC4")) { | 422 | #ifdef CONFIG_PPC64 |
465 | extern struct smp_ops_t core99_smp_ops; | 423 | /* |
424 | * G5s enable/disable the timebase via an i2c-connected clock chip. | ||
425 | */ | ||
426 | static struct device_node *pmac_tb_clock_chip_host; | ||
427 | static u8 pmac_tb_pulsar_addr; | ||
428 | static void (*pmac_tb_freeze)(int freeze); | ||
429 | static DEFINE_SPINLOCK(timebase_lock); | ||
430 | static unsigned long timebase; | ||
466 | 431 | ||
467 | core99_smp_ops.take_timebase = smp_generic_take_timebase; | 432 | static void smp_core99_cypress_tb_freeze(int freeze) |
468 | core99_smp_ops.give_timebase = smp_generic_give_timebase; | 433 | { |
469 | } else { | 434 | u8 data; |
470 | if (firstcpu != NULL) | 435 | int rc; |
471 | tbprop = (u32 *)get_property(firstcpu, "timebase-enable", NULL); | ||
472 | if (tbprop) | ||
473 | core99_tb_gpio = *tbprop; | ||
474 | else | ||
475 | core99_tb_gpio = KL_GPIO_TB_ENABLE; | ||
476 | } | ||
477 | 436 | ||
478 | if (ncpus > 1) { | 437 | /* Strangely, the device-tree says address is 0xd2, but darwin |
479 | mpic_request_ipis(); | 438 | * accesses 0xd0 ... |
480 | for (i = 1; i < ncpus; ++i) | 439 | */ |
481 | smp_hw_index[i] = i; | 440 | pmac_low_i2c_setmode(pmac_tb_clock_chip_host, pmac_low_i2c_mode_combined); |
482 | #ifdef CONFIG_6xx | 441 | rc = pmac_low_i2c_xfer(pmac_tb_clock_chip_host, |
483 | powersave_nap = 0; | 442 | 0xd0 | pmac_low_i2c_read, |
484 | #endif | 443 | 0x81, &data, 1); |
485 | core99_init_caches(0); | 444 | if (rc != 0) |
445 | goto bail; | ||
446 | |||
447 | data = (data & 0xf3) | (freeze ? 0x00 : 0x0c); | ||
448 | |||
449 | pmac_low_i2c_setmode(pmac_tb_clock_chip_host, pmac_low_i2c_mode_stdsub); | ||
450 | rc = pmac_low_i2c_xfer(pmac_tb_clock_chip_host, | ||
451 | 0xd0 | pmac_low_i2c_write, | ||
452 | 0x81, &data, 1); | ||
453 | |||
454 | bail: | ||
455 | if (rc != 0) { | ||
456 | printk("Cypress Timebase %s rc: %d\n", | ||
457 | freeze ? "freeze" : "unfreeze", rc); | ||
458 | panic("Timebase freeze failed !\n"); | ||
486 | } | 459 | } |
487 | |||
488 | return ncpus; | ||
489 | } | 460 | } |
490 | 461 | ||
491 | static void __devinit smp_core99_kick_cpu(int nr) | ||
492 | { | ||
493 | unsigned long save_vector, new_vector; | ||
494 | unsigned long flags; | ||
495 | 462 | ||
496 | volatile unsigned long *vector | 463 | static void smp_core99_pulsar_tb_freeze(int freeze) |
497 | = ((volatile unsigned long *)(KERNELBASE+0x100)); | 464 | { |
498 | if (nr < 0 || nr > 3) | 465 | u8 data; |
499 | return; | 466 | int rc; |
500 | if (ppc_md.progress) ppc_md.progress("smp_core99_kick_cpu", 0x346); | 467 | |
468 | pmac_low_i2c_setmode(pmac_tb_clock_chip_host, pmac_low_i2c_mode_combined); | ||
469 | rc = pmac_low_i2c_xfer(pmac_tb_clock_chip_host, | ||
470 | pmac_tb_pulsar_addr | pmac_low_i2c_read, | ||
471 | 0x2e, &data, 1); | ||
472 | if (rc != 0) | ||
473 | goto bail; | ||
474 | |||
475 | data = (data & 0x88) | (freeze ? 0x11 : 0x22); | ||
476 | |||
477 | pmac_low_i2c_setmode(pmac_tb_clock_chip_host, pmac_low_i2c_mode_stdsub); | ||
478 | rc = pmac_low_i2c_xfer(pmac_tb_clock_chip_host, | ||
479 | pmac_tb_pulsar_addr | pmac_low_i2c_write, | ||
480 | 0x2e, &data, 1); | ||
481 | bail: | ||
482 | if (rc != 0) { | ||
483 | printk(KERN_ERR "Pulsar Timebase %s rc: %d\n", | ||
484 | freeze ? "freeze" : "unfreeze", rc); | ||
485 | panic("Timebase freeze failed !\n"); | ||
486 | } | ||
487 | } | ||
501 | 488 | ||
502 | local_irq_save(flags); | ||
503 | local_irq_disable(); | ||
504 | 489 | ||
505 | /* Save reset vector */ | 490 | static void smp_core99_give_timebase(void) |
506 | save_vector = *vector; | 491 | { |
492 | /* Open i2c bus for synchronous access */ | ||
493 | if (pmac_low_i2c_open(pmac_tb_clock_chip_host, 0)) | ||
494 | panic("Can't open i2c for TB sync !\n"); | ||
507 | 495 | ||
508 | /* Setup fake reset vector that does | 496 | spin_lock(&timebase_lock); |
509 | * b __secondary_start_pmac_0 + nr*8 - KERNELBASE | 497 | (*pmac_tb_freeze)(1); |
510 | */ | 498 | mb(); |
511 | new_vector = (unsigned long) __secondary_start_pmac_0 + nr * 8; | 499 | timebase = get_tb(); |
512 | *vector = 0x48000002 + new_vector - KERNELBASE; | 500 | spin_unlock(&timebase_lock); |
513 | 501 | ||
514 | /* flush data cache and inval instruction cache */ | 502 | while (timebase) |
515 | flush_icache_range((unsigned long) vector, (unsigned long) vector + 4); | 503 | barrier(); |
516 | 504 | ||
517 | /* Put some life in our friend */ | 505 | spin_lock(&timebase_lock); |
518 | pmac_call_feature(PMAC_FTR_RESET_CPU, NULL, nr, 0); | 506 | (*pmac_tb_freeze)(0); |
507 | spin_unlock(&timebase_lock); | ||
519 | 508 | ||
520 | /* FIXME: We wait a bit for the CPU to take the exception, I should | 509 | /* Close i2c bus */ |
521 | * instead wait for the entry code to set something for me. Well, | 510 | pmac_low_i2c_close(pmac_tb_clock_chip_host); |
522 | * ideally, all that crap will be done in prom.c and the CPU left | 511 | } |
523 | * in a RAM-based wait loop like CHRP. | ||
524 | */ | ||
525 | mdelay(1); | ||
526 | 512 | ||
527 | /* Restore our exception vector */ | ||
528 | *vector = save_vector; | ||
529 | flush_icache_range((unsigned long) vector, (unsigned long) vector + 4); | ||
530 | 513 | ||
531 | local_irq_restore(flags); | 514 | static void __devinit smp_core99_take_timebase(void) |
532 | if (ppc_md.progress) ppc_md.progress("smp_core99_kick_cpu done", 0x347); | 515 | { |
516 | while (!timebase) | ||
517 | barrier(); | ||
518 | spin_lock(&timebase_lock); | ||
519 | set_tb(timebase >> 32, timebase & 0xffffffff); | ||
520 | timebase = 0; | ||
521 | spin_unlock(&timebase_lock); | ||
533 | } | 522 | } |
534 | 523 | ||
535 | static void __devinit smp_core99_setup_cpu(int cpu_nr) | 524 | static void __init smp_core99_setup(int ncpus) |
536 | { | 525 | { |
537 | /* Setup L2/L3 */ | 526 | struct device_node *cc = NULL; |
538 | if (cpu_nr != 0) | 527 | struct device_node *p; |
539 | core99_init_caches(cpu_nr); | 528 | u32 *reg; |
529 | int ok; | ||
530 | |||
531 | /* HW sync only on these platforms */ | ||
532 | if (!machine_is_compatible("PowerMac7,2") && | ||
533 | !machine_is_compatible("PowerMac7,3") && | ||
534 | !machine_is_compatible("RackMac3,1")) | ||
535 | return; | ||
540 | 536 | ||
541 | /* Setup openpic */ | 537 | /* Look for the clock chip */ |
542 | mpic_setup_this_cpu(); | 538 | while ((cc = of_find_node_by_name(cc, "i2c-hwclock")) != NULL) { |
539 | p = of_get_parent(cc); | ||
540 | ok = p && device_is_compatible(p, "uni-n-i2c"); | ||
541 | of_node_put(p); | ||
542 | if (!ok) | ||
543 | continue; | ||
543 | 544 | ||
544 | if (cpu_nr == 0) { | 545 | reg = (u32 *)get_property(cc, "reg", NULL); |
545 | #ifdef CONFIG_POWER4 | 546 | if (reg == NULL) |
546 | extern void g5_phy_disable_cpu1(void); | 547 | continue; |
547 | 548 | ||
548 | /* If we didn't start the second CPU, we must take | 549 | switch (*reg) { |
549 | * it off the bus | 550 | case 0xd2: |
550 | */ | 551 | if (device_is_compatible(cc, "pulsar-legacy-slewing")) { |
551 | if (machine_is_compatible("MacRISC4") && | 552 | pmac_tb_freeze = smp_core99_pulsar_tb_freeze; |
552 | num_online_cpus() < 2) | 553 | pmac_tb_pulsar_addr = 0xd2; |
553 | g5_phy_disable_cpu1(); | 554 | printk(KERN_INFO "Timebase clock is Pulsar chip\n"); |
554 | #endif /* CONFIG_POWER4 */ | 555 | } else if (device_is_compatible(cc, "cy28508")) { |
555 | if (ppc_md.progress) ppc_md.progress("core99_setup_cpu 0 done", 0x349); | 556 | pmac_tb_freeze = smp_core99_cypress_tb_freeze; |
557 | printk(KERN_INFO "Timebase clock is Cypress chip\n"); | ||
558 | } | ||
559 | break; | ||
560 | case 0xd4: | ||
561 | pmac_tb_freeze = smp_core99_pulsar_tb_freeze; | ||
562 | pmac_tb_pulsar_addr = 0xd4; | ||
563 | printk(KERN_INFO "Timebase clock is Pulsar chip\n"); | ||
564 | break; | ||
565 | } | ||
566 | if (pmac_tb_freeze != NULL) { | ||
567 | pmac_tb_clock_chip_host = of_get_parent(cc); | ||
568 | of_node_put(cc); | ||
569 | break; | ||
570 | } | ||
571 | } | ||
572 | if (pmac_tb_freeze == NULL) { | ||
573 | smp_ops->give_timebase = smp_generic_give_timebase; | ||
574 | smp_ops->take_timebase = smp_generic_take_timebase; | ||
556 | } | 575 | } |
557 | } | 576 | } |
558 | 577 | ||
559 | /* not __init, called in sleep/wakeup code */ | 578 | /* nothing to do here, caches are already set up by service processor */ |
560 | void smp_core99_take_timebase(void) | 579 | static inline void __devinit core99_init_caches(int cpu) |
561 | { | 580 | { |
562 | unsigned long flags; | 581 | } |
563 | 582 | ||
564 | /* tell the primary we're here */ | 583 | #else /* CONFIG_PPC64 */ |
565 | sec_tb_reset = 1; | ||
566 | mb(); | ||
567 | 584 | ||
568 | /* wait for the primary to set pri_tb_hi/lo */ | 585 | /* |
569 | while (sec_tb_reset < 2) | 586 | * SMP G4 powermacs use a GPIO to enable/disable the timebase. |
570 | mb(); | 587 | */ |
571 | 588 | ||
572 | /* set our stuff the same as the primary */ | 589 | static unsigned int core99_tb_gpio; /* Timebase freeze GPIO */ |
573 | local_irq_save(flags); | ||
574 | set_dec(1); | ||
575 | set_tb(pri_tb_hi, pri_tb_lo); | ||
576 | last_jiffy_stamp(smp_processor_id()) = pri_tb_stamp; | ||
577 | mb(); | ||
578 | 590 | ||
579 | /* tell the primary we're done */ | 591 | static unsigned int pri_tb_hi, pri_tb_lo; |
580 | sec_tb_reset = 0; | 592 | static unsigned int pri_tb_stamp; |
581 | mb(); | ||
582 | local_irq_restore(flags); | ||
583 | } | ||
584 | 593 | ||
585 | /* not __init, called in sleep/wakeup code */ | 594 | /* not __init, called in sleep/wakeup code */ |
586 | void smp_core99_give_timebase(void) | 595 | void smp_core99_give_timebase(void) |
@@ -626,43 +635,184 @@ void smp_core99_give_timebase(void) | |||
626 | local_irq_restore(flags); | 635 | local_irq_restore(flags); |
627 | } | 636 | } |
628 | 637 | ||
629 | void smp_core99_message_pass(int target, int msg) | 638 | /* not __init, called in sleep/wakeup code */ |
639 | void smp_core99_take_timebase(void) | ||
640 | { | ||
641 | unsigned long flags; | ||
642 | |||
643 | /* tell the primary we're here */ | ||
644 | sec_tb_reset = 1; | ||
645 | mb(); | ||
646 | |||
647 | /* wait for the primary to set pri_tb_hi/lo */ | ||
648 | while (sec_tb_reset < 2) | ||
649 | mb(); | ||
650 | |||
651 | /* set our stuff the same as the primary */ | ||
652 | local_irq_save(flags); | ||
653 | set_dec(1); | ||
654 | set_tb(pri_tb_hi, pri_tb_lo); | ||
655 | last_jiffy_stamp(smp_processor_id()) = pri_tb_stamp; | ||
656 | mb(); | ||
657 | |||
658 | /* tell the primary we're done */ | ||
659 | sec_tb_reset = 0; | ||
660 | mb(); | ||
661 | local_irq_restore(flags); | ||
662 | } | ||
663 | |||
664 | /* L2 and L3 cache settings to pass from CPU0 to CPU1 on G4 cpus */ | ||
665 | volatile static long int core99_l2_cache; | ||
666 | volatile static long int core99_l3_cache; | ||
667 | |||
668 | static void __devinit core99_init_caches(int cpu) | ||
630 | { | 669 | { |
631 | cpumask_t mask = CPU_MASK_ALL; | 670 | if (!cpu_has_feature(CPU_FTR_L2CR)) |
632 | /* make sure we're sending something that translates to an IPI */ | ||
633 | if (msg > 0x3) { | ||
634 | printk("SMP %d: smp_message_pass: unknown msg %d\n", | ||
635 | smp_processor_id(), msg); | ||
636 | return; | 671 | return; |
672 | |||
673 | if (cpu == 0) { | ||
674 | core99_l2_cache = _get_L2CR(); | ||
675 | printk("CPU0: L2CR is %lx\n", core99_l2_cache); | ||
676 | } else { | ||
677 | printk("CPU%d: L2CR was %lx\n", cpu, _get_L2CR()); | ||
678 | _set_L2CR(0); | ||
679 | _set_L2CR(core99_l2_cache); | ||
680 | printk("CPU%d: L2CR set to %lx\n", cpu, core99_l2_cache); | ||
637 | } | 681 | } |
638 | switch (target) { | 682 | |
639 | case MSG_ALL: | 683 | if (!cpu_has_feature(CPU_FTR_L3CR)) |
640 | mpic_send_ipi(msg, cpus_addr(mask)[0]); | 684 | return; |
641 | break; | 685 | |
642 | case MSG_ALL_BUT_SELF: | 686 | if (cpu == 0){ |
643 | cpu_clear(smp_processor_id(), mask); | 687 | core99_l3_cache = _get_L3CR(); |
644 | mpic_send_ipi(msg, cpus_addr(mask)[0]); | 688 | printk("CPU0: L3CR is %lx\n", core99_l3_cache); |
645 | break; | 689 | } else { |
646 | default: | 690 | printk("CPU%d: L3CR was %lx\n", cpu, _get_L3CR()); |
647 | mpic_send_ipi(msg, 1 << target); | 691 | _set_L3CR(0); |
648 | break; | 692 | _set_L3CR(core99_l3_cache); |
693 | printk("CPU%d: L3CR set to %lx\n", cpu, core99_l3_cache); | ||
649 | } | 694 | } |
650 | } | 695 | } |
651 | 696 | ||
697 | static void __init smp_core99_setup(int ncpus) | ||
698 | { | ||
699 | struct device_node *cpu; | ||
700 | u32 *tbprop = NULL; | ||
701 | int i; | ||
702 | |||
703 | core99_tb_gpio = KL_GPIO_TB_ENABLE; /* default value */ | ||
704 | cpu = of_find_node_by_type(NULL, "cpu"); | ||
705 | if (cpu != NULL) { | ||
706 | tbprop = (u32 *)get_property(cpu, "timebase-enable", NULL); | ||
707 | if (tbprop) | ||
708 | core99_tb_gpio = *tbprop; | ||
709 | of_node_put(cpu); | ||
710 | } | ||
711 | |||
712 | /* XXX should get this from reg properties */ | ||
713 | for (i = 1; i < ncpus; ++i) | ||
714 | smp_hw_index[i] = i; | ||
715 | powersave_nap = 0; | ||
716 | } | ||
717 | #endif | ||
718 | |||
719 | static int __init smp_core99_probe(void) | ||
720 | { | ||
721 | struct device_node *cpus; | ||
722 | int ncpus = 0; | ||
723 | |||
724 | if (ppc_md.progress) ppc_md.progress("smp_core99_probe", 0x345); | ||
725 | |||
726 | /* Count CPUs in the device-tree */ | ||
727 | for (cpus = NULL; (cpus = of_find_node_by_type(cpus, "cpu")) != NULL;) | ||
728 | ++ncpus; | ||
729 | |||
730 | printk(KERN_INFO "PowerMac SMP probe found %d cpus\n", ncpus); | ||
731 | |||
732 | /* Nothing more to do if less than 2 of them */ | ||
733 | if (ncpus <= 1) | ||
734 | return 1; | ||
735 | |||
736 | smp_core99_setup(ncpus); | ||
737 | mpic_request_ipis(); | ||
738 | core99_init_caches(0); | ||
739 | |||
740 | return ncpus; | ||
741 | } | ||
742 | |||
743 | static void __devinit smp_core99_kick_cpu(int nr) | ||
744 | { | ||
745 | unsigned int save_vector; | ||
746 | unsigned long new_vector; | ||
747 | unsigned long flags; | ||
748 | volatile unsigned int *vector | ||
749 | = ((volatile unsigned int *)(KERNELBASE+0x100)); | ||
750 | |||
751 | if (nr < 0 || nr > 3) | ||
752 | return; | ||
753 | if (ppc_md.progress) ppc_md.progress("smp_core99_kick_cpu", 0x346); | ||
754 | |||
755 | local_irq_save(flags); | ||
756 | local_irq_disable(); | ||
757 | |||
758 | /* Save reset vector */ | ||
759 | save_vector = *vector; | ||
760 | |||
761 | /* Setup fake reset vector that does | ||
762 | * b __secondary_start_pmac_0 + nr*8 - KERNELBASE | ||
763 | */ | ||
764 | new_vector = (unsigned long) __secondary_start_pmac_0 + nr * 8; | ||
765 | *vector = 0x48000002 + new_vector - KERNELBASE; | ||
766 | |||
767 | /* flush data cache and inval instruction cache */ | ||
768 | flush_icache_range((unsigned long) vector, (unsigned long) vector + 4); | ||
769 | |||
770 | /* Put some life in our friend */ | ||
771 | pmac_call_feature(PMAC_FTR_RESET_CPU, NULL, nr, 0); | ||
772 | |||
773 | /* FIXME: We wait a bit for the CPU to take the exception, I should | ||
774 | * instead wait for the entry code to set something for me. Well, | ||
775 | * ideally, all that crap will be done in prom.c and the CPU left | ||
776 | * in a RAM-based wait loop like CHRP. | ||
777 | */ | ||
778 | mdelay(1); | ||
779 | |||
780 | /* Restore our exception vector */ | ||
781 | *vector = save_vector; | ||
782 | flush_icache_range((unsigned long) vector, (unsigned long) vector + 4); | ||
783 | |||
784 | local_irq_restore(flags); | ||
785 | if (ppc_md.progress) ppc_md.progress("smp_core99_kick_cpu done", 0x347); | ||
786 | } | ||
787 | |||
788 | static void __devinit smp_core99_setup_cpu(int cpu_nr) | ||
789 | { | ||
790 | /* Setup L2/L3 */ | ||
791 | if (cpu_nr != 0) | ||
792 | core99_init_caches(cpu_nr); | ||
793 | |||
794 | /* Setup openpic */ | ||
795 | mpic_setup_this_cpu(); | ||
796 | |||
797 | if (cpu_nr == 0) { | ||
798 | #ifdef CONFIG_POWER4 | ||
799 | extern void g5_phy_disable_cpu1(void); | ||
800 | |||
801 | /* If we didn't start the second CPU, we must take | ||
802 | * it off the bus | ||
803 | */ | ||
804 | if (machine_is_compatible("MacRISC4") && | ||
805 | num_online_cpus() < 2) | ||
806 | g5_phy_disable_cpu1(); | ||
807 | #endif /* CONFIG_POWER4 */ | ||
808 | if (ppc_md.progress) ppc_md.progress("core99_setup_cpu 0 done", 0x349); | ||
809 | } | ||
810 | } | ||
652 | 811 | ||
653 | /* PowerSurge-style Macs */ | ||
654 | struct smp_ops_t psurge_smp_ops = { | ||
655 | .message_pass = smp_psurge_message_pass, | ||
656 | .probe = smp_psurge_probe, | ||
657 | .kick_cpu = smp_psurge_kick_cpu, | ||
658 | .setup_cpu = smp_psurge_setup_cpu, | ||
659 | .give_timebase = smp_psurge_give_timebase, | ||
660 | .take_timebase = smp_psurge_take_timebase, | ||
661 | }; | ||
662 | 812 | ||
663 | /* Core99 Macs (dual G4s) */ | 813 | /* Core99 Macs (dual G4s and G5s) */ |
664 | struct smp_ops_t core99_smp_ops = { | 814 | struct smp_ops_t core99_smp_ops = { |
665 | .message_pass = smp_core99_message_pass, | 815 | .message_pass = smp_mpic_message_pass, |
666 | .probe = smp_core99_probe, | 816 | .probe = smp_core99_probe, |
667 | .kick_cpu = smp_core99_kick_cpu, | 817 | .kick_cpu = smp_core99_kick_cpu, |
668 | .setup_cpu = smp_core99_setup_cpu, | 818 | .setup_cpu = smp_core99_setup_cpu, |
@@ -670,7 +820,7 @@ struct smp_ops_t core99_smp_ops = { | |||
670 | .take_timebase = smp_core99_take_timebase, | 820 | .take_timebase = smp_core99_take_timebase, |
671 | }; | 821 | }; |
672 | 822 | ||
673 | #ifdef CONFIG_HOTPLUG_CPU | 823 | #if defined(CONFIG_HOTPLUG_CPU) && defined(CONFIG_PPC32) |
674 | 824 | ||
675 | int __cpu_disable(void) | 825 | int __cpu_disable(void) |
676 | { | 826 | { |
@@ -685,7 +835,7 @@ int __cpu_disable(void) | |||
685 | return 0; | 835 | return 0; |
686 | } | 836 | } |
687 | 837 | ||
688 | extern void low_cpu_die(void) __attribute__((noreturn)); /* in pmac_sleep.S */ | 838 | extern void low_cpu_die(void) __attribute__((noreturn)); /* in sleep.S */ |
689 | static int cpu_dead[NR_CPUS]; | 839 | static int cpu_dead[NR_CPUS]; |
690 | 840 | ||
691 | void cpu_die(void) | 841 | void cpu_die(void) |
diff --git a/arch/powerpc/platforms/powermac/time.c b/arch/powerpc/platforms/powermac/time.c index a6d2d231d5a0..82982bf6453c 100644 --- a/arch/powerpc/platforms/powermac/time.c +++ b/arch/powerpc/platforms/powermac/time.c | |||
@@ -33,6 +33,7 @@ | |||
33 | #include <asm/machdep.h> | 33 | #include <asm/machdep.h> |
34 | #include <asm/time.h> | 34 | #include <asm/time.h> |
35 | #include <asm/nvram.h> | 35 | #include <asm/nvram.h> |
36 | #include <asm/smu.h> | ||
36 | 37 | ||
37 | #undef DEBUG | 38 | #undef DEBUG |
38 | 39 | ||
@@ -68,8 +69,8 @@ | |||
68 | 69 | ||
69 | long __init pmac_time_init(void) | 70 | long __init pmac_time_init(void) |
70 | { | 71 | { |
71 | #ifdef CONFIG_NVRAM | ||
72 | s32 delta = 0; | 72 | s32 delta = 0; |
73 | #ifdef CONFIG_NVRAM | ||
73 | int dst; | 74 | int dst; |
74 | 75 | ||
75 | delta = ((s32)pmac_xpram_read(PMAC_XPRAM_MACHINE_LOC + 0x9)) << 16; | 76 | delta = ((s32)pmac_xpram_read(PMAC_XPRAM_MACHINE_LOC + 0x9)) << 16; |
@@ -80,110 +81,181 @@ long __init pmac_time_init(void) | |||
80 | dst = ((pmac_xpram_read(PMAC_XPRAM_MACHINE_LOC + 0x8) & 0x80) != 0); | 81 | dst = ((pmac_xpram_read(PMAC_XPRAM_MACHINE_LOC + 0x8) & 0x80) != 0); |
81 | printk("GMT Delta read from XPRAM: %d minutes, DST: %s\n", delta/60, | 82 | printk("GMT Delta read from XPRAM: %d minutes, DST: %s\n", delta/60, |
82 | dst ? "on" : "off"); | 83 | dst ? "on" : "off"); |
83 | return delta; | ||
84 | #else | ||
85 | return 0; | ||
86 | #endif | 84 | #endif |
85 | return delta; | ||
87 | } | 86 | } |
88 | 87 | ||
89 | unsigned long pmac_get_boot_time(void) | 88 | static void to_rtc_time(unsigned long now, struct rtc_time *tm) |
89 | { | ||
90 | to_tm(now, tm); | ||
91 | tm->tm_year -= 1900; | ||
92 | tm->tm_mon -= 1; | ||
93 | } | ||
94 | |||
95 | static unsigned long from_rtc_time(struct rtc_time *tm) | ||
96 | { | ||
97 | return mktime(tm->tm_year+1900, tm->tm_mon+1, tm->tm_mday, | ||
98 | tm->tm_hour, tm->tm_min, tm->tm_sec); | ||
99 | } | ||
100 | |||
101 | #ifdef CONFIG_ADB_CUDA | ||
102 | static unsigned long cuda_get_time(void) | ||
90 | { | 103 | { |
91 | #if defined(CONFIG_ADB_CUDA) || defined(CONFIG_ADB_PMU) | ||
92 | struct adb_request req; | 104 | struct adb_request req; |
93 | unsigned long now; | 105 | unsigned long now; |
94 | #endif | ||
95 | 106 | ||
96 | /* Get the time from the RTC */ | 107 | if (cuda_request(&req, NULL, 2, CUDA_PACKET, CUDA_GET_TIME) < 0) |
97 | switch (sys_ctrler) { | 108 | return 0; |
98 | #ifdef CONFIG_ADB_CUDA | 109 | while (!req.complete) |
99 | case SYS_CTRLER_CUDA: | 110 | cuda_poll(); |
100 | if (cuda_request(&req, NULL, 2, CUDA_PACKET, CUDA_GET_TIME) < 0) | 111 | if (req.reply_len != 7) |
101 | return 0; | 112 | printk(KERN_ERR "cuda_get_time: got %d byte reply\n", |
102 | while (!req.complete) | 113 | req.reply_len); |
103 | cuda_poll(); | 114 | now = (req.reply[3] << 24) + (req.reply[4] << 16) |
104 | if (req.reply_len != 7) | 115 | + (req.reply[5] << 8) + req.reply[6]; |
105 | printk(KERN_ERR "pmac_get_rtc_time: got %d byte reply\n", | 116 | if (now < RTC_OFFSET) |
106 | req.reply_len); | 117 | return 0; |
107 | now = (req.reply[3] << 24) + (req.reply[4] << 16) | 118 | return now - RTC_OFFSET; |
108 | + (req.reply[5] << 8) + req.reply[6]; | 119 | } |
109 | return now - RTC_OFFSET; | 120 | |
110 | #endif /* CONFIG_ADB_CUDA */ | 121 | #define cuda_get_rtc_time(tm) to_rtc_time(cuda_get_time(), (tm)) |
111 | #ifdef CONFIG_ADB_PMU | 122 | |
112 | case SYS_CTRLER_PMU: | 123 | static int cuda_set_rtc_time(struct rtc_time *tm) |
113 | if (pmu_request(&req, NULL, 1, PMU_READ_RTC) < 0) | 124 | { |
114 | return 0; | 125 | unsigned int nowtime; |
115 | while (!req.complete) | 126 | struct adb_request req; |
116 | pmu_poll(); | 127 | |
117 | if (req.reply_len != 4) | 128 | nowtime = from_rtc_time(tm) + RTC_OFFSET; |
118 | printk(KERN_ERR "pmac_get_rtc_time: got %d byte reply\n", | 129 | if (cuda_request(&req, NULL, 6, CUDA_PACKET, CUDA_SET_TIME, |
119 | req.reply_len); | 130 | nowtime >> 24, nowtime >> 16, nowtime >> 8, |
120 | now = (req.reply[0] << 24) + (req.reply[1] << 16) | 131 | nowtime) < 0) |
121 | + (req.reply[2] << 8) + req.reply[3]; | 132 | return -ENXIO; |
122 | return now - RTC_OFFSET; | 133 | while (!req.complete) |
123 | #endif /* CONFIG_ADB_PMU */ | 134 | cuda_poll(); |
124 | default: ; | 135 | if ((req.reply_len != 3) && (req.reply_len != 7)) |
125 | } | 136 | printk(KERN_ERR "cuda_set_rtc_time: got %d byte reply\n", |
137 | req.reply_len); | ||
126 | return 0; | 138 | return 0; |
127 | } | 139 | } |
128 | 140 | ||
129 | void pmac_get_rtc_time(struct rtc_time *tm) | 141 | #else |
142 | #define cuda_get_time() 0 | ||
143 | #define cuda_get_rtc_time(tm) | ||
144 | #define cuda_set_rtc_time(tm) 0 | ||
145 | #endif | ||
146 | |||
147 | #ifdef CONFIG_ADB_PMU | ||
148 | static unsigned long pmu_get_time(void) | ||
130 | { | 149 | { |
150 | struct adb_request req; | ||
131 | unsigned long now; | 151 | unsigned long now; |
132 | 152 | ||
133 | now = pmac_get_boot_time(); | 153 | if (pmu_request(&req, NULL, 1, PMU_READ_RTC) < 0) |
134 | to_tm(now, tm); | 154 | return 0; |
135 | tm->tm_year -= 1900; | 155 | pmu_wait_complete(&req); |
136 | tm->tm_mon -= 1; /* month is 0-based */ | 156 | if (req.reply_len != 4) |
157 | printk(KERN_ERR "pmu_get_time: got %d byte reply from PMU\n", | ||
158 | req.reply_len); | ||
159 | now = (req.reply[0] << 24) + (req.reply[1] << 16) | ||
160 | + (req.reply[2] << 8) + req.reply[3]; | ||
161 | if (now < RTC_OFFSET) | ||
162 | return 0; | ||
163 | return now - RTC_OFFSET; | ||
137 | } | 164 | } |
138 | 165 | ||
139 | int pmac_set_rtc_time(struct rtc_time *tm) | 166 | #define pmu_get_rtc_time(tm) to_rtc_time(pmu_get_time(), (tm)) |
167 | |||
168 | static int pmu_set_rtc_time(struct rtc_time *tm) | ||
140 | { | 169 | { |
141 | unsigned long nowtime; | 170 | unsigned int nowtime; |
142 | #if defined(CONFIG_ADB_CUDA) || defined(CONFIG_ADB_PMU) | ||
143 | struct adb_request req; | 171 | struct adb_request req; |
172 | |||
173 | nowtime = from_rtc_time(tm) + RTC_OFFSET; | ||
174 | if (pmu_request(&req, NULL, 5, PMU_SET_RTC, nowtime >> 24, | ||
175 | nowtime >> 16, nowtime >> 8, nowtime) < 0) | ||
176 | return -ENXIO; | ||
177 | pmu_wait_complete(&req); | ||
178 | if (req.reply_len != 0) | ||
179 | printk(KERN_ERR "pmu_set_rtc_time: %d byte reply from PMU\n", | ||
180 | req.reply_len); | ||
181 | return 0; | ||
182 | } | ||
183 | |||
184 | #else | ||
185 | #define pmu_get_time() 0 | ||
186 | #define pmu_get_rtc_time(tm) | ||
187 | #define pmu_set_rtc_time(tm) 0 | ||
144 | #endif | 188 | #endif |
145 | 189 | ||
146 | nowtime = mktime(tm->tm_year+1900, tm->tm_mon+1, tm->tm_mday, | 190 | #ifdef CONFIG_PMAC_SMU |
147 | tm->tm_hour, tm->tm_min, tm->tm_sec); | 191 | static unsigned long smu_get_time(void) |
148 | nowtime += RTC_OFFSET; | 192 | { |
193 | struct rtc_time tm; | ||
194 | |||
195 | if (smu_get_rtc_time(&tm, 1)) | ||
196 | return 0; | ||
197 | return from_rtc_time(&tm); | ||
198 | } | ||
199 | |||
200 | #else | ||
201 | #define smu_get_time() 0 | ||
202 | #define smu_get_rtc_time(tm, spin) | ||
203 | #define smu_set_rtc_time(tm, spin) 0 | ||
204 | #endif | ||
149 | 205 | ||
206 | unsigned long pmac_get_boot_time(void) | ||
207 | { | ||
208 | /* Get the time from the RTC, used only at boot time */ | ||
150 | switch (sys_ctrler) { | 209 | switch (sys_ctrler) { |
151 | #ifdef CONFIG_ADB_CUDA | ||
152 | case SYS_CTRLER_CUDA: | 210 | case SYS_CTRLER_CUDA: |
153 | if (cuda_request(&req, NULL, 6, CUDA_PACKET, CUDA_SET_TIME, | 211 | return cuda_get_time(); |
154 | nowtime >> 24, nowtime >> 16, nowtime >> 8, | ||
155 | nowtime) < 0) | ||
156 | return 0; | ||
157 | while (!req.complete) | ||
158 | cuda_poll(); | ||
159 | if ((req.reply_len != 3) && (req.reply_len != 7)) | ||
160 | printk(KERN_ERR "pmac_set_rtc_time: got %d byte reply\n", | ||
161 | req.reply_len); | ||
162 | return 1; | ||
163 | #endif /* CONFIG_ADB_CUDA */ | ||
164 | #ifdef CONFIG_ADB_PMU | ||
165 | case SYS_CTRLER_PMU: | 212 | case SYS_CTRLER_PMU: |
166 | if (pmu_request(&req, NULL, 5, PMU_SET_RTC, | 213 | return pmu_get_time(); |
167 | nowtime >> 24, nowtime >> 16, nowtime >> 8, nowtime) < 0) | 214 | case SYS_CTRLER_SMU: |
168 | return 0; | 215 | return smu_get_time(); |
169 | while (!req.complete) | ||
170 | pmu_poll(); | ||
171 | if (req.reply_len != 0) | ||
172 | printk(KERN_ERR "pmac_set_rtc_time: got %d byte reply\n", | ||
173 | req.reply_len); | ||
174 | return 1; | ||
175 | #endif /* CONFIG_ADB_PMU */ | ||
176 | default: | 216 | default: |
177 | return 0; | 217 | return 0; |
178 | } | 218 | } |
179 | } | 219 | } |
180 | 220 | ||
221 | void pmac_get_rtc_time(struct rtc_time *tm) | ||
222 | { | ||
223 | /* Get the time from the RTC, used only at boot time */ | ||
224 | switch (sys_ctrler) { | ||
225 | case SYS_CTRLER_CUDA: | ||
226 | cuda_get_rtc_time(tm); | ||
227 | break; | ||
228 | case SYS_CTRLER_PMU: | ||
229 | pmu_get_rtc_time(tm); | ||
230 | break; | ||
231 | case SYS_CTRLER_SMU: | ||
232 | smu_get_rtc_time(tm, 1); | ||
233 | break; | ||
234 | default: | ||
235 | ; | ||
236 | } | ||
237 | } | ||
238 | |||
239 | int pmac_set_rtc_time(struct rtc_time *tm) | ||
240 | { | ||
241 | switch (sys_ctrler) { | ||
242 | case SYS_CTRLER_CUDA: | ||
243 | return cuda_set_rtc_time(tm); | ||
244 | case SYS_CTRLER_PMU: | ||
245 | return pmu_set_rtc_time(tm); | ||
246 | case SYS_CTRLER_SMU: | ||
247 | return smu_set_rtc_time(tm, 1); | ||
248 | default: | ||
249 | return -ENODEV; | ||
250 | } | ||
251 | } | ||
252 | |||
253 | #ifdef CONFIG_PPC32 | ||
181 | /* | 254 | /* |
182 | * Calibrate the decrementer register using VIA timer 1. | 255 | * Calibrate the decrementer register using VIA timer 1. |
183 | * This is used both on powermacs and CHRP machines. | 256 | * This is used both on powermacs and CHRP machines. |
184 | */ | 257 | */ |
185 | int __init | 258 | int __init via_calibrate_decr(void) |
186 | via_calibrate_decr(void) | ||
187 | { | 259 | { |
188 | struct device_node *vias; | 260 | struct device_node *vias; |
189 | volatile unsigned char __iomem *via; | 261 | volatile unsigned char __iomem *via; |
@@ -217,15 +289,12 @@ via_calibrate_decr(void) | |||
217 | dend = get_dec(); | 289 | dend = get_dec(); |
218 | 290 | ||
219 | ppc_tb_freq = (dstart - dend) * 100 / 6; | 291 | ppc_tb_freq = (dstart - dend) * 100 / 6; |
220 | tb_ticks_per_jiffy = (dstart - dend) / ((6 * HZ)/100); | ||
221 | |||
222 | printk(KERN_INFO "via_calibrate_decr: ticks per jiffy = %lu (%u ticks)\n", | ||
223 | tb_ticks_per_jiffy, dstart - dend); | ||
224 | 292 | ||
225 | iounmap(via); | 293 | iounmap(via); |
226 | 294 | ||
227 | return 1; | 295 | return 1; |
228 | } | 296 | } |
297 | #endif | ||
229 | 298 | ||
230 | #ifdef CONFIG_PM | 299 | #ifdef CONFIG_PM |
231 | /* | 300 | /* |
@@ -262,19 +331,17 @@ static struct pmu_sleep_notifier time_sleep_notifier = { | |||
262 | 331 | ||
263 | /* | 332 | /* |
264 | * Query the OF and get the decr frequency. | 333 | * Query the OF and get the decr frequency. |
265 | * This was taken from the pmac time_init() when merging the prep/pmac | ||
266 | * time functions. | ||
267 | */ | 334 | */ |
268 | void __init | 335 | void __init pmac_calibrate_decr(void) |
269 | pmac_calibrate_decr(void) | ||
270 | { | 336 | { |
271 | struct device_node *cpu; | ||
272 | unsigned int freq, *fp; | ||
273 | |||
274 | #ifdef CONFIG_PM | 337 | #ifdef CONFIG_PM |
338 | /* XXX why here? */ | ||
275 | pmu_register_sleep_notifier(&time_sleep_notifier); | 339 | pmu_register_sleep_notifier(&time_sleep_notifier); |
276 | #endif /* CONFIG_PM */ | 340 | #endif /* CONFIG_PM */ |
277 | 341 | ||
342 | generic_calibrate_decr(); | ||
343 | |||
344 | #ifdef CONFIG_PPC32 | ||
278 | /* We assume MacRISC2 machines have correct device-tree | 345 | /* We assume MacRISC2 machines have correct device-tree |
279 | * calibration. That's better since the VIA itself seems | 346 | * calibration. That's better since the VIA itself seems |
280 | * to be slightly off. --BenH | 347 | * to be slightly off. --BenH |
@@ -293,18 +360,5 @@ pmac_calibrate_decr(void) | |||
293 | if (machine_is_compatible("PowerMac3,5")) | 360 | if (machine_is_compatible("PowerMac3,5")) |
294 | if (via_calibrate_decr()) | 361 | if (via_calibrate_decr()) |
295 | return; | 362 | return; |
296 | /* | 363 | #endif |
297 | * The cpu node should have a timebase-frequency property | ||
298 | * to tell us the rate at which the decrementer counts. | ||
299 | */ | ||
300 | cpu = find_type_devices("cpu"); | ||
301 | if (cpu == 0) | ||
302 | panic("can't find cpu node in time_init"); | ||
303 | fp = (unsigned int *) get_property(cpu, "timebase-frequency", NULL); | ||
304 | if (fp == 0) | ||
305 | panic("can't get cpu timebase frequency"); | ||
306 | freq = *fp; | ||
307 | printk("time_init: decrementer frequency = %u.%.6u MHz\n", | ||
308 | freq/1000000, freq%1000000); | ||
309 | ppc_tb_freq = freq; | ||
310 | } | 364 | } |