diff options
Diffstat (limited to 'arch/sparc64/kernel/time.c')
-rw-r--r-- | arch/sparc64/kernel/time.c | 386 |
1 files changed, 204 insertions, 182 deletions
diff --git a/arch/sparc64/kernel/time.c b/arch/sparc64/kernel/time.c index 0f00a99927e9..348b82035561 100644 --- a/arch/sparc64/kernel/time.c +++ b/arch/sparc64/kernel/time.c | |||
@@ -48,6 +48,7 @@ | |||
48 | #include <asm/sections.h> | 48 | #include <asm/sections.h> |
49 | #include <asm/cpudata.h> | 49 | #include <asm/cpudata.h> |
50 | #include <asm/uaccess.h> | 50 | #include <asm/uaccess.h> |
51 | #include <asm/prom.h> | ||
51 | 52 | ||
52 | DEFINE_SPINLOCK(mostek_lock); | 53 | DEFINE_SPINLOCK(mostek_lock); |
53 | DEFINE_SPINLOCK(rtc_lock); | 54 | DEFINE_SPINLOCK(rtc_lock); |
@@ -755,24 +756,200 @@ retry: | |||
755 | return -EOPNOTSUPP; | 756 | return -EOPNOTSUPP; |
756 | } | 757 | } |
757 | 758 | ||
758 | void __init clock_probe(void) | 759 | static int __init clock_model_matches(char *model) |
759 | { | 760 | { |
760 | struct linux_prom_registers clk_reg[2]; | 761 | if (strcmp(model, "mk48t02") && |
761 | char model[128]; | 762 | strcmp(model, "mk48t08") && |
762 | int node, busnd = -1, err; | 763 | strcmp(model, "mk48t59") && |
763 | unsigned long flags; | 764 | strcmp(model, "m5819") && |
764 | struct linux_central *cbus; | 765 | strcmp(model, "m5819p") && |
766 | strcmp(model, "m5823") && | ||
767 | strcmp(model, "ds1287")) | ||
768 | return 0; | ||
769 | |||
770 | return 1; | ||
771 | } | ||
772 | |||
773 | static void __init __clock_assign_common(void __iomem *addr, char *model) | ||
774 | { | ||
775 | if (model[5] == '0' && model[6] == '2') { | ||
776 | mstk48t02_regs = addr; | ||
777 | } else if(model[5] == '0' && model[6] == '8') { | ||
778 | mstk48t08_regs = addr; | ||
779 | mstk48t02_regs = mstk48t08_regs + MOSTEK_48T08_48T02; | ||
780 | } else { | ||
781 | mstk48t59_regs = addr; | ||
782 | mstk48t02_regs = mstk48t59_regs + MOSTEK_48T59_48T02; | ||
783 | } | ||
784 | } | ||
785 | |||
786 | static void __init clock_assign_clk_reg(struct linux_prom_registers *clk_reg, | ||
787 | char *model) | ||
788 | { | ||
789 | unsigned long addr; | ||
790 | |||
791 | addr = ((unsigned long) clk_reg[0].phys_addr | | ||
792 | (((unsigned long) clk_reg[0].which_io) << 32UL)); | ||
793 | |||
794 | __clock_assign_common((void __iomem *) addr, model); | ||
795 | } | ||
796 | |||
797 | static int __init clock_probe_central(void) | ||
798 | { | ||
799 | struct linux_prom_registers clk_reg[2], *pr; | ||
800 | struct device_node *dp; | ||
801 | char *model; | ||
802 | |||
803 | if (!central_bus) | ||
804 | return 0; | ||
805 | |||
806 | /* Get Central FHC's prom node. */ | ||
807 | dp = central_bus->child->prom_node; | ||
808 | |||
809 | /* Then get the first child device below it. */ | ||
810 | dp = dp->child; | ||
811 | |||
812 | while (dp) { | ||
813 | model = of_get_property(dp, "model", NULL); | ||
814 | if (!model || !clock_model_matches(model)) | ||
815 | goto next_sibling; | ||
816 | |||
817 | pr = of_get_property(dp, "reg", NULL); | ||
818 | memcpy(clk_reg, pr, sizeof(clk_reg)); | ||
819 | |||
820 | apply_fhc_ranges(central_bus->child, clk_reg, 1); | ||
821 | apply_central_ranges(central_bus, clk_reg, 1); | ||
822 | |||
823 | clock_assign_clk_reg(clk_reg, model); | ||
824 | return 1; | ||
825 | |||
826 | next_sibling: | ||
827 | dp = dp->sibling; | ||
828 | } | ||
829 | |||
830 | return 0; | ||
831 | } | ||
832 | |||
765 | #ifdef CONFIG_PCI | 833 | #ifdef CONFIG_PCI |
766 | struct linux_ebus *ebus = NULL; | 834 | static void __init clock_isa_ebus_assign_regs(struct resource *res, char *model) |
767 | struct sparc_isa_bridge *isa_br = NULL; | 835 | { |
836 | if (!strcmp(model, "ds1287") || | ||
837 | !strcmp(model, "m5819") || | ||
838 | !strcmp(model, "m5819p") || | ||
839 | !strcmp(model, "m5823")) { | ||
840 | ds1287_regs = res->start; | ||
841 | } else { | ||
842 | mstk48t59_regs = (void __iomem *) res->start; | ||
843 | mstk48t02_regs = mstk48t59_regs + MOSTEK_48T59_48T02; | ||
844 | } | ||
845 | } | ||
846 | |||
847 | static int __init clock_probe_one_ebus_dev(struct linux_ebus_device *edev) | ||
848 | { | ||
849 | struct device_node *dp = edev->prom_node; | ||
850 | char *model; | ||
851 | |||
852 | model = of_get_property(dp, "model", NULL); | ||
853 | if (!clock_model_matches(model)) | ||
854 | return 0; | ||
855 | |||
856 | clock_isa_ebus_assign_regs(&edev->resource[0], model); | ||
857 | |||
858 | return 1; | ||
859 | } | ||
860 | |||
861 | static int __init clock_probe_ebus(void) | ||
862 | { | ||
863 | struct linux_ebus *ebus; | ||
864 | |||
865 | for_each_ebus(ebus) { | ||
866 | struct linux_ebus_device *edev; | ||
867 | |||
868 | for_each_ebusdev(edev, ebus) { | ||
869 | if (clock_probe_one_ebus_dev(edev)) | ||
870 | return 1; | ||
871 | } | ||
872 | } | ||
873 | |||
874 | return 0; | ||
875 | } | ||
876 | |||
877 | static int __init clock_probe_one_isa_dev(struct sparc_isa_device *idev) | ||
878 | { | ||
879 | struct device_node *dp = idev->prom_node; | ||
880 | char *model; | ||
881 | |||
882 | model = of_get_property(dp, "model", NULL); | ||
883 | if (!clock_model_matches(model)) | ||
884 | return 0; | ||
885 | |||
886 | clock_isa_ebus_assign_regs(&idev->resource, model); | ||
887 | |||
888 | return 1; | ||
889 | } | ||
890 | |||
891 | static int __init clock_probe_isa(void) | ||
892 | { | ||
893 | struct sparc_isa_bridge *isa_br; | ||
894 | |||
895 | for_each_isa(isa_br) { | ||
896 | struct sparc_isa_device *isa_dev; | ||
897 | |||
898 | for_each_isadev(isa_dev, isa_br) { | ||
899 | if (clock_probe_one_isa_dev(isa_dev)) | ||
900 | return 1; | ||
901 | } | ||
902 | } | ||
903 | |||
904 | return 0; | ||
905 | } | ||
906 | #endif /* CONFIG_PCI */ | ||
907 | |||
908 | #ifdef CONFIG_SBUS | ||
909 | static int __init clock_probe_one_sbus_dev(struct sbus_bus *sbus, struct sbus_dev *sdev) | ||
910 | { | ||
911 | struct resource *res; | ||
912 | char model[64]; | ||
913 | void __iomem *addr; | ||
914 | |||
915 | prom_getstring(sdev->prom_node, "model", model, sizeof(model)); | ||
916 | if (!clock_model_matches(model)) | ||
917 | return 0; | ||
918 | |||
919 | res = &sdev->resource[0]; | ||
920 | addr = sbus_ioremap(res, 0, 0x800UL, "eeprom"); | ||
921 | |||
922 | __clock_assign_common(addr, model); | ||
923 | |||
924 | return 1; | ||
925 | } | ||
926 | |||
927 | static int __init clock_probe_sbus(void) | ||
928 | { | ||
929 | struct sbus_bus *sbus; | ||
930 | |||
931 | for_each_sbus(sbus) { | ||
932 | struct sbus_dev *sdev; | ||
933 | |||
934 | for_each_sbusdev(sdev, sbus) { | ||
935 | if (clock_probe_one_sbus_dev(sbus, sdev)) | ||
936 | return 1; | ||
937 | } | ||
938 | } | ||
939 | |||
940 | return 0; | ||
941 | } | ||
768 | #endif | 942 | #endif |
943 | |||
944 | void __init clock_probe(void) | ||
945 | { | ||
769 | static int invoked; | 946 | static int invoked; |
947 | unsigned long flags; | ||
770 | 948 | ||
771 | if (invoked) | 949 | if (invoked) |
772 | return; | 950 | return; |
773 | invoked = 1; | 951 | invoked = 1; |
774 | 952 | ||
775 | |||
776 | if (this_is_starfire) { | 953 | if (this_is_starfire) { |
777 | xtime.tv_sec = starfire_get_time(); | 954 | xtime.tv_sec = starfire_get_time(); |
778 | xtime.tv_nsec = (INITIAL_JIFFIES % HZ) * (NSEC_PER_SEC / HZ); | 955 | xtime.tv_nsec = (INITIAL_JIFFIES % HZ) * (NSEC_PER_SEC / HZ); |
@@ -788,183 +965,27 @@ void __init clock_probe(void) | |||
788 | return; | 965 | return; |
789 | } | 966 | } |
790 | 967 | ||
791 | local_irq_save(flags); | ||
792 | |||
793 | cbus = central_bus; | ||
794 | if (cbus != NULL) | ||
795 | busnd = central_bus->child->prom_node; | ||
796 | |||
797 | /* Check FHC Central then EBUSs then ISA bridges then SBUSs. | 968 | /* Check FHC Central then EBUSs then ISA bridges then SBUSs. |
798 | * That way we handle the presence of multiple properly. | 969 | * That way we handle the presence of multiple properly. |
799 | * | 970 | * |
800 | * As a special case, machines with Central must provide the | 971 | * As a special case, machines with Central must provide the |
801 | * timer chip there. | 972 | * timer chip there. |
802 | */ | 973 | */ |
974 | if (!clock_probe_central() && | ||
803 | #ifdef CONFIG_PCI | 975 | #ifdef CONFIG_PCI |
804 | if (ebus_chain != NULL) { | 976 | !clock_probe_ebus() && |
805 | ebus = ebus_chain; | 977 | !clock_probe_isa() && |
806 | if (busnd == -1) | ||
807 | busnd = ebus->prom_node; | ||
808 | } | ||
809 | if (isa_chain != NULL) { | ||
810 | isa_br = isa_chain; | ||
811 | if (busnd == -1) | ||
812 | busnd = isa_br->prom_node; | ||
813 | } | ||
814 | #endif | ||
815 | if (sbus_root != NULL && busnd == -1) | ||
816 | busnd = sbus_root->prom_node; | ||
817 | |||
818 | if (busnd == -1) { | ||
819 | prom_printf("clock_probe: problem, cannot find bus to search.\n"); | ||
820 | prom_halt(); | ||
821 | } | ||
822 | |||
823 | node = prom_getchild(busnd); | ||
824 | |||
825 | while (1) { | ||
826 | if (!node) | ||
827 | model[0] = 0; | ||
828 | else | ||
829 | prom_getstring(node, "model", model, sizeof(model)); | ||
830 | if (strcmp(model, "mk48t02") && | ||
831 | strcmp(model, "mk48t08") && | ||
832 | strcmp(model, "mk48t59") && | ||
833 | strcmp(model, "m5819") && | ||
834 | strcmp(model, "m5819p") && | ||
835 | strcmp(model, "m5823") && | ||
836 | strcmp(model, "ds1287")) { | ||
837 | if (cbus != NULL) { | ||
838 | prom_printf("clock_probe: Central bus lacks timer chip.\n"); | ||
839 | prom_halt(); | ||
840 | } | ||
841 | |||
842 | if (node != 0) | ||
843 | node = prom_getsibling(node); | ||
844 | #ifdef CONFIG_PCI | ||
845 | while ((node == 0) && ebus != NULL) { | ||
846 | ebus = ebus->next; | ||
847 | if (ebus != NULL) { | ||
848 | busnd = ebus->prom_node; | ||
849 | node = prom_getchild(busnd); | ||
850 | } | ||
851 | } | ||
852 | while ((node == 0) && isa_br != NULL) { | ||
853 | isa_br = isa_br->next; | ||
854 | if (isa_br != NULL) { | ||
855 | busnd = isa_br->prom_node; | ||
856 | node = prom_getchild(busnd); | ||
857 | } | ||
858 | } | ||
859 | #endif | 978 | #endif |
860 | if (node == 0) { | 979 | #ifdef CONFIG_SBUS |
861 | prom_printf("clock_probe: Cannot find timer chip\n"); | 980 | !clock_probe_sbus() |
862 | prom_halt(); | ||
863 | } | ||
864 | continue; | ||
865 | } | ||
866 | |||
867 | err = prom_getproperty(node, "reg", (char *)clk_reg, | ||
868 | sizeof(clk_reg)); | ||
869 | if(err == -1) { | ||
870 | prom_printf("clock_probe: Cannot get Mostek reg property\n"); | ||
871 | prom_halt(); | ||
872 | } | ||
873 | |||
874 | if (cbus != NULL) { | ||
875 | apply_fhc_ranges(central_bus->child, clk_reg, 1); | ||
876 | apply_central_ranges(central_bus, clk_reg, 1); | ||
877 | } | ||
878 | #ifdef CONFIG_PCI | ||
879 | else if (ebus != NULL) { | ||
880 | struct linux_ebus_device *edev; | ||
881 | |||
882 | for_each_ebusdev(edev, ebus) | ||
883 | if (edev->prom_node == node) | ||
884 | break; | ||
885 | if (edev == NULL) { | ||
886 | if (isa_chain != NULL) | ||
887 | goto try_isa_clock; | ||
888 | prom_printf("%s: Mostek not probed by EBUS\n", | ||
889 | __FUNCTION__); | ||
890 | prom_halt(); | ||
891 | } | ||
892 | |||
893 | if (!strcmp(model, "ds1287") || | ||
894 | !strcmp(model, "m5819") || | ||
895 | !strcmp(model, "m5819p") || | ||
896 | !strcmp(model, "m5823")) { | ||
897 | ds1287_regs = edev->resource[0].start; | ||
898 | } else { | ||
899 | mstk48t59_regs = (void __iomem *) | ||
900 | edev->resource[0].start; | ||
901 | mstk48t02_regs = mstk48t59_regs + MOSTEK_48T59_48T02; | ||
902 | } | ||
903 | break; | ||
904 | } | ||
905 | else if (isa_br != NULL) { | ||
906 | struct sparc_isa_device *isadev; | ||
907 | |||
908 | try_isa_clock: | ||
909 | for_each_isadev(isadev, isa_br) | ||
910 | if (isadev->prom_node == node) | ||
911 | break; | ||
912 | if (isadev == NULL) { | ||
913 | prom_printf("%s: Mostek not probed by ISA\n"); | ||
914 | prom_halt(); | ||
915 | } | ||
916 | if (!strcmp(model, "ds1287") || | ||
917 | !strcmp(model, "m5819") || | ||
918 | !strcmp(model, "m5819p") || | ||
919 | !strcmp(model, "m5823")) { | ||
920 | ds1287_regs = isadev->resource.start; | ||
921 | } else { | ||
922 | mstk48t59_regs = (void __iomem *) | ||
923 | isadev->resource.start; | ||
924 | mstk48t02_regs = mstk48t59_regs + MOSTEK_48T59_48T02; | ||
925 | } | ||
926 | break; | ||
927 | } | ||
928 | #endif | 981 | #endif |
929 | else { | 982 | ) { |
930 | if (sbus_root->num_sbus_ranges) { | 983 | printk(KERN_WARNING "No clock chip found.\n"); |
931 | int nranges = sbus_root->num_sbus_ranges; | 984 | return; |
932 | int rngc; | ||
933 | |||
934 | for (rngc = 0; rngc < nranges; rngc++) | ||
935 | if (clk_reg[0].which_io == | ||
936 | sbus_root->sbus_ranges[rngc].ot_child_space) | ||
937 | break; | ||
938 | if (rngc == nranges) { | ||
939 | prom_printf("clock_probe: Cannot find ranges for " | ||
940 | "clock regs.\n"); | ||
941 | prom_halt(); | ||
942 | } | ||
943 | clk_reg[0].which_io = | ||
944 | sbus_root->sbus_ranges[rngc].ot_parent_space; | ||
945 | clk_reg[0].phys_addr += | ||
946 | sbus_root->sbus_ranges[rngc].ot_parent_base; | ||
947 | } | ||
948 | } | ||
949 | |||
950 | if(model[5] == '0' && model[6] == '2') { | ||
951 | mstk48t02_regs = (void __iomem *) | ||
952 | (((u64)clk_reg[0].phys_addr) | | ||
953 | (((u64)clk_reg[0].which_io)<<32UL)); | ||
954 | } else if(model[5] == '0' && model[6] == '8') { | ||
955 | mstk48t08_regs = (void __iomem *) | ||
956 | (((u64)clk_reg[0].phys_addr) | | ||
957 | (((u64)clk_reg[0].which_io)<<32UL)); | ||
958 | mstk48t02_regs = mstk48t08_regs + MOSTEK_48T08_48T02; | ||
959 | } else { | ||
960 | mstk48t59_regs = (void __iomem *) | ||
961 | (((u64)clk_reg[0].phys_addr) | | ||
962 | (((u64)clk_reg[0].which_io)<<32UL)); | ||
963 | mstk48t02_regs = mstk48t59_regs + MOSTEK_48T59_48T02; | ||
964 | } | ||
965 | break; | ||
966 | } | 985 | } |
967 | 986 | ||
987 | local_irq_save(flags); | ||
988 | |||
968 | if (mstk48t02_regs != NULL) { | 989 | if (mstk48t02_regs != NULL) { |
969 | /* Report a low battery voltage condition. */ | 990 | /* Report a low battery voltage condition. */ |
970 | if (has_low_battery()) | 991 | if (has_low_battery()) |
@@ -983,12 +1004,14 @@ try_isa_clock: | |||
983 | /* This is gets the master TICK_INT timer going. */ | 1004 | /* This is gets the master TICK_INT timer going. */ |
984 | static unsigned long sparc64_init_timers(void) | 1005 | static unsigned long sparc64_init_timers(void) |
985 | { | 1006 | { |
1007 | struct device_node *dp; | ||
1008 | struct property *prop; | ||
986 | unsigned long clock; | 1009 | unsigned long clock; |
987 | int node; | ||
988 | #ifdef CONFIG_SMP | 1010 | #ifdef CONFIG_SMP |
989 | extern void smp_tick_init(void); | 1011 | extern void smp_tick_init(void); |
990 | #endif | 1012 | #endif |
991 | 1013 | ||
1014 | dp = of_find_node_by_path("/"); | ||
992 | if (tlb_type == spitfire) { | 1015 | if (tlb_type == spitfire) { |
993 | unsigned long ver, manuf, impl; | 1016 | unsigned long ver, manuf, impl; |
994 | 1017 | ||
@@ -999,18 +1022,17 @@ static unsigned long sparc64_init_timers(void) | |||
999 | if (manuf == 0x17 && impl == 0x13) { | 1022 | if (manuf == 0x17 && impl == 0x13) { |
1000 | /* Hummingbird, aka Ultra-IIe */ | 1023 | /* Hummingbird, aka Ultra-IIe */ |
1001 | tick_ops = &hbtick_operations; | 1024 | tick_ops = &hbtick_operations; |
1002 | node = prom_root_node; | 1025 | prop = of_find_property(dp, "stick-frequency", NULL); |
1003 | clock = prom_getint(node, "stick-frequency"); | ||
1004 | } else { | 1026 | } else { |
1005 | tick_ops = &tick_operations; | 1027 | tick_ops = &tick_operations; |
1006 | cpu_find_by_instance(0, &node, NULL); | 1028 | cpu_find_by_instance(0, &dp, NULL); |
1007 | clock = prom_getint(node, "clock-frequency"); | 1029 | prop = of_find_property(dp, "clock-frequency", NULL); |
1008 | } | 1030 | } |
1009 | } else { | 1031 | } else { |
1010 | tick_ops = &stick_operations; | 1032 | tick_ops = &stick_operations; |
1011 | node = prom_root_node; | 1033 | prop = of_find_property(dp, "stick-frequency", NULL); |
1012 | clock = prom_getint(node, "stick-frequency"); | ||
1013 | } | 1034 | } |
1035 | clock = *(unsigned int *) prop->value; | ||
1014 | timer_tick_offset = clock / HZ; | 1036 | timer_tick_offset = clock / HZ; |
1015 | 1037 | ||
1016 | #ifdef CONFIG_SMP | 1038 | #ifdef CONFIG_SMP |