diff options
Diffstat (limited to 'arch/powerpc/kernel/setup_64.c')
-rw-r--r-- | arch/powerpc/kernel/setup_64.c | 207 |
1 files changed, 21 insertions, 186 deletions
diff --git a/arch/powerpc/kernel/setup_64.c b/arch/powerpc/kernel/setup_64.c index e3fb78397dc6..98e9f0595dd8 100644 --- a/arch/powerpc/kernel/setup_64.c +++ b/arch/powerpc/kernel/setup_64.c | |||
@@ -34,6 +34,7 @@ | |||
34 | #include <linux/serial.h> | 34 | #include <linux/serial.h> |
35 | #include <linux/serial_8250.h> | 35 | #include <linux/serial_8250.h> |
36 | #include <asm/io.h> | 36 | #include <asm/io.h> |
37 | #include <asm/kdump.h> | ||
37 | #include <asm/prom.h> | 38 | #include <asm/prom.h> |
38 | #include <asm/processor.h> | 39 | #include <asm/processor.h> |
39 | #include <asm/pgtable.h> | 40 | #include <asm/pgtable.h> |
@@ -268,6 +269,10 @@ void __init early_setup(unsigned long dt_ptr) | |||
268 | } | 269 | } |
269 | ppc_md = **mach; | 270 | ppc_md = **mach; |
270 | 271 | ||
272 | #ifdef CONFIG_CRASH_DUMP | ||
273 | kdump_setup(); | ||
274 | #endif | ||
275 | |||
271 | DBG("Found, Initializing memory management...\n"); | 276 | DBG("Found, Initializing memory management...\n"); |
272 | 277 | ||
273 | /* | 278 | /* |
@@ -317,6 +322,7 @@ void early_setup_secondary(void) | |||
317 | void smp_release_cpus(void) | 322 | void smp_release_cpus(void) |
318 | { | 323 | { |
319 | extern unsigned long __secondary_hold_spinloop; | 324 | extern unsigned long __secondary_hold_spinloop; |
325 | unsigned long *ptr; | ||
320 | 326 | ||
321 | DBG(" -> smp_release_cpus()\n"); | 327 | DBG(" -> smp_release_cpus()\n"); |
322 | 328 | ||
@@ -327,7 +333,9 @@ void smp_release_cpus(void) | |||
327 | * This is useless but harmless on iSeries, secondaries are already | 333 | * This is useless but harmless on iSeries, secondaries are already |
328 | * waiting on their paca spinloops. */ | 334 | * waiting on their paca spinloops. */ |
329 | 335 | ||
330 | __secondary_hold_spinloop = 1; | 336 | ptr = (unsigned long *)((unsigned long)&__secondary_hold_spinloop |
337 | - PHYSICAL_START); | ||
338 | *ptr = 1; | ||
331 | mb(); | 339 | mb(); |
332 | 340 | ||
333 | DBG(" <- smp_release_cpus()\n"); | 341 | DBG(" <- smp_release_cpus()\n"); |
@@ -459,16 +467,21 @@ void __init setup_system(void) | |||
459 | */ | 467 | */ |
460 | ppc_md.init_early(); | 468 | ppc_md.init_early(); |
461 | 469 | ||
470 | /* | ||
471 | * We can discover serial ports now since the above did setup the | ||
472 | * hash table management for us, thus ioremap works. We do that early | ||
473 | * so that further code can be debugged | ||
474 | */ | ||
475 | #ifdef CONFIG_SERIAL_8250 | ||
476 | find_legacy_serial_ports(); | ||
477 | #endif | ||
478 | |||
462 | /* | 479 | /* |
463 | * "Finish" the device-tree, that is do the actual parsing of | 480 | * "Finish" the device-tree, that is do the actual parsing of |
464 | * some of the properties like the interrupt map | 481 | * some of the properties like the interrupt map |
465 | */ | 482 | */ |
466 | finish_device_tree(); | 483 | finish_device_tree(); |
467 | 484 | ||
468 | #ifdef CONFIG_BOOTX_TEXT | ||
469 | init_boot_display(); | ||
470 | #endif | ||
471 | |||
472 | /* | 485 | /* |
473 | * Initialize xmon | 486 | * Initialize xmon |
474 | */ | 487 | */ |
@@ -507,6 +520,9 @@ void __init setup_system(void) | |||
507 | ppc64_caches.iline_size); | 520 | ppc64_caches.iline_size); |
508 | printk("htab_address = 0x%p\n", htab_address); | 521 | printk("htab_address = 0x%p\n", htab_address); |
509 | printk("htab_hash_mask = 0x%lx\n", htab_hash_mask); | 522 | printk("htab_hash_mask = 0x%lx\n", htab_hash_mask); |
523 | #if PHYSICAL_START > 0 | ||
524 | printk("physical_start = 0x%x\n", PHYSICAL_START); | ||
525 | #endif | ||
510 | printk("-----------------------------------------------------\n"); | 526 | printk("-----------------------------------------------------\n"); |
511 | 527 | ||
512 | mm_init_ppc64(); | 528 | mm_init_ppc64(); |
@@ -657,187 +673,6 @@ void ppc64_terminate_msg(unsigned int src, const char *msg) | |||
657 | printk("[terminate]%04x %s\n", src, msg); | 673 | printk("[terminate]%04x %s\n", src, msg); |
658 | } | 674 | } |
659 | 675 | ||
660 | #ifndef CONFIG_PPC_ISERIES | ||
661 | /* | ||
662 | * This function can be used by platforms to "find" legacy serial ports. | ||
663 | * It works for "serial" nodes under an "isa" node, and will try to | ||
664 | * respect the "ibm,aix-loc" property if any. It works with up to 8 | ||
665 | * ports. | ||
666 | */ | ||
667 | |||
668 | #define MAX_LEGACY_SERIAL_PORTS 8 | ||
669 | static struct plat_serial8250_port serial_ports[MAX_LEGACY_SERIAL_PORTS+1]; | ||
670 | static unsigned int old_serial_count; | ||
671 | |||
672 | void __init generic_find_legacy_serial_ports(u64 *physport, | ||
673 | unsigned int *default_speed) | ||
674 | { | ||
675 | struct device_node *np; | ||
676 | u32 *sizeprop; | ||
677 | |||
678 | struct isa_reg_property { | ||
679 | u32 space; | ||
680 | u32 address; | ||
681 | u32 size; | ||
682 | }; | ||
683 | struct pci_reg_property { | ||
684 | struct pci_address addr; | ||
685 | u32 size_hi; | ||
686 | u32 size_lo; | ||
687 | }; | ||
688 | |||
689 | DBG(" -> generic_find_legacy_serial_port()\n"); | ||
690 | |||
691 | *physport = 0; | ||
692 | if (default_speed) | ||
693 | *default_speed = 0; | ||
694 | |||
695 | np = of_find_node_by_path("/"); | ||
696 | if (!np) | ||
697 | return; | ||
698 | |||
699 | /* First fill our array */ | ||
700 | for (np = NULL; (np = of_find_node_by_type(np, "serial"));) { | ||
701 | struct device_node *isa, *pci; | ||
702 | struct isa_reg_property *reg; | ||
703 | unsigned long phys_size, addr_size, io_base; | ||
704 | u32 *rangesp; | ||
705 | u32 *interrupts, *clk, *spd; | ||
706 | char *typep; | ||
707 | int index, rlen, rentsize; | ||
708 | |||
709 | /* Ok, first check if it's under an "isa" parent */ | ||
710 | isa = of_get_parent(np); | ||
711 | if (!isa || strcmp(isa->name, "isa")) { | ||
712 | DBG("%s: no isa parent found\n", np->full_name); | ||
713 | continue; | ||
714 | } | ||
715 | |||
716 | /* Now look for an "ibm,aix-loc" property that gives us ordering | ||
717 | * if any... | ||
718 | */ | ||
719 | typep = (char *)get_property(np, "ibm,aix-loc", NULL); | ||
720 | |||
721 | /* Get the ISA port number */ | ||
722 | reg = (struct isa_reg_property *)get_property(np, "reg", NULL); | ||
723 | if (reg == NULL) | ||
724 | goto next_port; | ||
725 | /* We assume the interrupt number isn't translated ... */ | ||
726 | interrupts = (u32 *)get_property(np, "interrupts", NULL); | ||
727 | /* get clock freq. if present */ | ||
728 | clk = (u32 *)get_property(np, "clock-frequency", NULL); | ||
729 | /* get default speed if present */ | ||
730 | spd = (u32 *)get_property(np, "current-speed", NULL); | ||
731 | /* Default to locate at end of array */ | ||
732 | index = old_serial_count; /* end of the array by default */ | ||
733 | |||
734 | /* If we have a location index, then use it */ | ||
735 | if (typep && *typep == 'S') { | ||
736 | index = simple_strtol(typep+1, NULL, 0) - 1; | ||
737 | /* if index is out of range, use end of array instead */ | ||
738 | if (index >= MAX_LEGACY_SERIAL_PORTS) | ||
739 | index = old_serial_count; | ||
740 | /* if our index is still out of range, that mean that | ||
741 | * array is full, we could scan for a free slot but that | ||
742 | * make little sense to bother, just skip the port | ||
743 | */ | ||
744 | if (index >= MAX_LEGACY_SERIAL_PORTS) | ||
745 | goto next_port; | ||
746 | if (index >= old_serial_count) | ||
747 | old_serial_count = index + 1; | ||
748 | /* Check if there is a port who already claimed our slot */ | ||
749 | if (serial_ports[index].iobase != 0) { | ||
750 | /* if we still have some room, move it, else override */ | ||
751 | if (old_serial_count < MAX_LEGACY_SERIAL_PORTS) { | ||
752 | DBG("Moved legacy port %d -> %d\n", index, | ||
753 | old_serial_count); | ||
754 | serial_ports[old_serial_count++] = | ||
755 | serial_ports[index]; | ||
756 | } else { | ||
757 | DBG("Replacing legacy port %d\n", index); | ||
758 | } | ||
759 | } | ||
760 | } | ||
761 | if (index >= MAX_LEGACY_SERIAL_PORTS) | ||
762 | goto next_port; | ||
763 | if (index >= old_serial_count) | ||
764 | old_serial_count = index + 1; | ||
765 | |||
766 | /* Now fill the entry */ | ||
767 | memset(&serial_ports[index], 0, sizeof(struct plat_serial8250_port)); | ||
768 | serial_ports[index].uartclk = clk ? *clk : BASE_BAUD * 16; | ||
769 | serial_ports[index].iobase = reg->address; | ||
770 | serial_ports[index].irq = interrupts ? interrupts[0] : 0; | ||
771 | serial_ports[index].flags = ASYNC_BOOT_AUTOCONF; | ||
772 | |||
773 | DBG("Added legacy port, index: %d, port: %x, irq: %d, clk: %d\n", | ||
774 | index, | ||
775 | serial_ports[index].iobase, | ||
776 | serial_ports[index].irq, | ||
777 | serial_ports[index].uartclk); | ||
778 | |||
779 | /* Get phys address of IO reg for port 1 */ | ||
780 | if (index != 0) | ||
781 | goto next_port; | ||
782 | |||
783 | pci = of_get_parent(isa); | ||
784 | if (!pci) { | ||
785 | DBG("%s: no pci parent found\n", np->full_name); | ||
786 | goto next_port; | ||
787 | } | ||
788 | |||
789 | rangesp = (u32 *)get_property(pci, "ranges", &rlen); | ||
790 | if (rangesp == NULL) { | ||
791 | of_node_put(pci); | ||
792 | goto next_port; | ||
793 | } | ||
794 | rlen /= 4; | ||
795 | |||
796 | /* we need the #size-cells of the PCI bridge node itself */ | ||
797 | phys_size = 1; | ||
798 | sizeprop = (u32 *)get_property(pci, "#size-cells", NULL); | ||
799 | if (sizeprop != NULL) | ||
800 | phys_size = *sizeprop; | ||
801 | /* we need the parent #addr-cells */ | ||
802 | addr_size = prom_n_addr_cells(pci); | ||
803 | rentsize = 3 + addr_size + phys_size; | ||
804 | io_base = 0; | ||
805 | for (;rlen >= rentsize; rlen -= rentsize,rangesp += rentsize) { | ||
806 | if (((rangesp[0] >> 24) & 0x3) != 1) | ||
807 | continue; /* not IO space */ | ||
808 | io_base = rangesp[3]; | ||
809 | if (addr_size == 2) | ||
810 | io_base = (io_base << 32) | rangesp[4]; | ||
811 | } | ||
812 | if (io_base != 0) { | ||
813 | *physport = io_base + reg->address; | ||
814 | if (default_speed && spd) | ||
815 | *default_speed = *spd; | ||
816 | } | ||
817 | of_node_put(pci); | ||
818 | next_port: | ||
819 | of_node_put(isa); | ||
820 | } | ||
821 | |||
822 | DBG(" <- generic_find_legacy_serial_port()\n"); | ||
823 | } | ||
824 | |||
825 | static struct platform_device serial_device = { | ||
826 | .name = "serial8250", | ||
827 | .id = PLAT8250_DEV_PLATFORM, | ||
828 | .dev = { | ||
829 | .platform_data = serial_ports, | ||
830 | }, | ||
831 | }; | ||
832 | |||
833 | static int __init serial_dev_init(void) | ||
834 | { | ||
835 | return platform_device_register(&serial_device); | ||
836 | } | ||
837 | arch_initcall(serial_dev_init); | ||
838 | |||
839 | #endif /* CONFIG_PPC_ISERIES */ | ||
840 | |||
841 | int check_legacy_ioport(unsigned long base_port) | 676 | int check_legacy_ioport(unsigned long base_port) |
842 | { | 677 | { |
843 | if (ppc_md.check_legacy_ioport == NULL) | 678 | if (ppc_md.check_legacy_ioport == NULL) |