Merge master.kernel.org:/pub/scm/linux/kernel/git/wim/linux-2.6-watchdog
[pandora-kernel.git] / arch / sparc64 / kernel / time.c
index 7d61f1b..348b820 100644 (file)
@@ -48,6 +48,7 @@
 #include <asm/sections.h>
 #include <asm/cpudata.h>
 #include <asm/uaccess.h>
+#include <asm/prom.h>
 
 DEFINE_SPINLOCK(mostek_lock);
 DEFINE_SPINLOCK(rtc_lock);
@@ -457,7 +458,7 @@ static inline void timer_check_rtc(void)
        }
 }
 
-static irqreturn_t timer_interrupt(int irq, void *dev_id, struct pt_regs * regs)
+irqreturn_t timer_interrupt(int irq, void *dev_id, struct pt_regs * regs)
 {
        unsigned long ticks, compare, pstate;
 
@@ -641,23 +642,8 @@ static void __init set_system_time(void)
                mon = MSTK_REG_MONTH(mregs);
                year = MSTK_CVT_YEAR( MSTK_REG_YEAR(mregs) );
        } else {
-               int i;
-
                /* Dallas 12887 RTC chip. */
 
-               /* Stolen from arch/i386/kernel/time.c, see there for
-                * credits and descriptive comments.
-                */
-               for (i = 0; i < 1000000; i++) {
-                       if (CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP)
-                               break;
-                       udelay(10);
-               }
-               for (i = 0; i < 1000000; i++) {
-                       if (!(CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP))
-                               break;
-                       udelay(10);
-               }
                do {
                        sec  = CMOS_READ(RTC_SECONDS);
                        min  = CMOS_READ(RTC_MINUTES);
@@ -666,6 +652,7 @@ static void __init set_system_time(void)
                        mon  = CMOS_READ(RTC_MONTH);
                        year = CMOS_READ(RTC_YEAR);
                } while (sec != CMOS_READ(RTC_SECONDS));
+
                if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY) || RTC_ALWAYS_BCD) {
                        BCD_TO_BIN(sec);
                        BCD_TO_BIN(min);
@@ -769,24 +756,200 @@ retry:
        return -EOPNOTSUPP;
 }
 
-void __init clock_probe(void)
+static int __init clock_model_matches(char *model)
 {
-       struct linux_prom_registers clk_reg[2];
-       char model[128];
-       int node, busnd = -1, err;
-       unsigned long flags;
-       struct linux_central *cbus;
+       if (strcmp(model, "mk48t02") &&
+           strcmp(model, "mk48t08") &&
+           strcmp(model, "mk48t59") &&
+           strcmp(model, "m5819") &&
+           strcmp(model, "m5819p") &&
+           strcmp(model, "m5823") &&
+           strcmp(model, "ds1287"))
+               return 0;
+
+       return 1;
+}
+
+static void __init __clock_assign_common(void __iomem *addr, char *model)
+{
+       if (model[5] == '0' && model[6] == '2') {
+               mstk48t02_regs = addr;
+       } else if(model[5] == '0' && model[6] == '8') {
+               mstk48t08_regs = addr;
+               mstk48t02_regs = mstk48t08_regs + MOSTEK_48T08_48T02;
+       } else {
+               mstk48t59_regs = addr;
+               mstk48t02_regs = mstk48t59_regs + MOSTEK_48T59_48T02;
+       }
+}
+
+static void __init clock_assign_clk_reg(struct linux_prom_registers *clk_reg,
+                                       char *model)
+{
+       unsigned long addr;
+
+       addr = ((unsigned long) clk_reg[0].phys_addr |
+               (((unsigned long) clk_reg[0].which_io) << 32UL));
+
+       __clock_assign_common((void __iomem *) addr, model);
+}
+
+static int __init clock_probe_central(void)
+{
+       struct linux_prom_registers clk_reg[2], *pr;
+       struct device_node *dp;
+       char *model;
+
+       if (!central_bus)
+               return 0;
+
+       /* Get Central FHC's prom node.  */
+       dp = central_bus->child->prom_node;
+
+       /* Then get the first child device below it.  */
+       dp = dp->child;
+
+       while (dp) {
+               model = of_get_property(dp, "model", NULL);
+               if (!model || !clock_model_matches(model))
+                       goto next_sibling;
+
+               pr = of_get_property(dp, "reg", NULL);
+               memcpy(clk_reg, pr, sizeof(clk_reg));
+
+               apply_fhc_ranges(central_bus->child, clk_reg, 1);
+               apply_central_ranges(central_bus, clk_reg, 1);
+
+               clock_assign_clk_reg(clk_reg, model);
+               return 1;
+
+       next_sibling:
+               dp = dp->sibling;
+       }
+
+       return 0;
+}
+
 #ifdef CONFIG_PCI
-       struct linux_ebus *ebus = NULL;
-       struct sparc_isa_bridge *isa_br = NULL;
+static void __init clock_isa_ebus_assign_regs(struct resource *res, char *model)
+{
+       if (!strcmp(model, "ds1287") ||
+           !strcmp(model, "m5819") ||
+           !strcmp(model, "m5819p") ||
+           !strcmp(model, "m5823")) {
+               ds1287_regs = res->start;
+       } else {
+               mstk48t59_regs = (void __iomem *) res->start;
+               mstk48t02_regs = mstk48t59_regs + MOSTEK_48T59_48T02;
+       }
+}
+
+static int __init clock_probe_one_ebus_dev(struct linux_ebus_device *edev)
+{
+       struct device_node *dp = edev->prom_node;
+       char *model;
+
+       model = of_get_property(dp, "model", NULL);
+       if (!clock_model_matches(model))
+               return 0;
+
+       clock_isa_ebus_assign_regs(&edev->resource[0], model);
+
+       return 1;
+}
+
+static int __init clock_probe_ebus(void)
+{
+       struct linux_ebus *ebus;
+
+       for_each_ebus(ebus) {
+               struct linux_ebus_device *edev;
+
+               for_each_ebusdev(edev, ebus) {
+                       if (clock_probe_one_ebus_dev(edev))
+                               return 1;
+               }
+       }
+
+       return 0;
+}
+
+static int __init clock_probe_one_isa_dev(struct sparc_isa_device *idev)
+{
+       struct device_node *dp = idev->prom_node;
+       char *model;
+
+       model = of_get_property(dp, "model", NULL);
+       if (!clock_model_matches(model))
+               return 0;
+
+       clock_isa_ebus_assign_regs(&idev->resource, model);
+
+       return 1;
+}
+
+static int __init clock_probe_isa(void)
+{
+       struct sparc_isa_bridge *isa_br;
+
+       for_each_isa(isa_br) {
+               struct sparc_isa_device *isa_dev;
+
+               for_each_isadev(isa_dev, isa_br) {
+                       if (clock_probe_one_isa_dev(isa_dev))
+                               return 1;
+               }
+       }
+
+       return 0;
+}
+#endif /* CONFIG_PCI */
+
+#ifdef CONFIG_SBUS
+static int __init clock_probe_one_sbus_dev(struct sbus_bus *sbus, struct sbus_dev *sdev)
+{
+       struct resource *res;
+       char model[64];
+       void __iomem *addr;
+
+       prom_getstring(sdev->prom_node, "model", model, sizeof(model));
+       if (!clock_model_matches(model))
+               return 0;
+
+       res = &sdev->resource[0];
+       addr = sbus_ioremap(res, 0, 0x800UL, "eeprom");
+
+       __clock_assign_common(addr, model);
+
+       return 1;
+}
+
+static int __init clock_probe_sbus(void)
+{
+       struct sbus_bus *sbus;
+
+       for_each_sbus(sbus) {
+               struct sbus_dev *sdev;
+
+               for_each_sbusdev(sdev, sbus) {
+                       if (clock_probe_one_sbus_dev(sbus, sdev))
+                               return 1;
+               }
+       }
+
+       return 0;
+}
 #endif
+
+void __init clock_probe(void)
+{
        static int invoked;
+       unsigned long flags;
 
        if (invoked)
                return;
        invoked = 1;
 
-
        if (this_is_starfire) {
                xtime.tv_sec = starfire_get_time();
                xtime.tv_nsec = (INITIAL_JIFFIES % HZ) * (NSEC_PER_SEC / HZ);
@@ -802,183 +965,27 @@ void __init clock_probe(void)
                return;
        }
 
-       local_irq_save(flags);
-
-       cbus = central_bus;
-       if (cbus != NULL)
-               busnd = central_bus->child->prom_node;
-
        /* Check FHC Central then EBUSs then ISA bridges then SBUSs.
         * That way we handle the presence of multiple properly.
         *
         * As a special case, machines with Central must provide the
         * timer chip there.
         */
+       if (!clock_probe_central() &&
 #ifdef CONFIG_PCI
-       if (ebus_chain != NULL) {
-               ebus = ebus_chain;
-               if (busnd == -1)
-                       busnd = ebus->prom_node;
-       }
-       if (isa_chain != NULL) {
-               isa_br = isa_chain;
-               if (busnd == -1)
-                       busnd = isa_br->prom_node;
-       }
-#endif
-       if (sbus_root != NULL && busnd == -1)
-               busnd = sbus_root->prom_node;
-
-       if (busnd == -1) {
-               prom_printf("clock_probe: problem, cannot find bus to search.\n");
-               prom_halt();
-       }
-
-       node = prom_getchild(busnd);
-
-       while (1) {
-               if (!node)
-                       model[0] = 0;
-               else
-                       prom_getstring(node, "model", model, sizeof(model));
-               if (strcmp(model, "mk48t02") &&
-                   strcmp(model, "mk48t08") &&
-                   strcmp(model, "mk48t59") &&
-                   strcmp(model, "m5819") &&
-                   strcmp(model, "m5819p") &&
-                   strcmp(model, "m5823") &&
-                   strcmp(model, "ds1287")) {
-                       if (cbus != NULL) {
-                               prom_printf("clock_probe: Central bus lacks timer chip.\n");
-                               prom_halt();
-                       }
-
-                       if (node != 0)
-                               node = prom_getsibling(node);
-#ifdef CONFIG_PCI
-                       while ((node == 0) && ebus != NULL) {
-                               ebus = ebus->next;
-                               if (ebus != NULL) {
-                                       busnd = ebus->prom_node;
-                                       node = prom_getchild(busnd);
-                               }
-                       }
-                       while ((node == 0) && isa_br != NULL) {
-                               isa_br = isa_br->next;
-                               if (isa_br != NULL) {
-                                       busnd = isa_br->prom_node;
-                                       node = prom_getchild(busnd);
-                               }
-                       }
+           !clock_probe_ebus() &&
+           !clock_probe_isa() &&
 #endif
-                       if (node == 0) {
-                               prom_printf("clock_probe: Cannot find timer chip\n");
-                               prom_halt();
-                       }
-                       continue;
-               }
-
-               err = prom_getproperty(node, "reg", (char *)clk_reg,
-                                      sizeof(clk_reg));
-               if(err == -1) {
-                       prom_printf("clock_probe: Cannot get Mostek reg property\n");
-                       prom_halt();
-               }
-
-               if (cbus != NULL) {
-                       apply_fhc_ranges(central_bus->child, clk_reg, 1);
-                       apply_central_ranges(central_bus, clk_reg, 1);
-               }
-#ifdef CONFIG_PCI
-               else if (ebus != NULL) {
-                       struct linux_ebus_device *edev;
-
-                       for_each_ebusdev(edev, ebus)
-                               if (edev->prom_node == node)
-                                       break;
-                       if (edev == NULL) {
-                               if (isa_chain != NULL)
-                                       goto try_isa_clock;
-                               prom_printf("%s: Mostek not probed by EBUS\n",
-                                           __FUNCTION__);
-                               prom_halt();
-                       }
-
-                       if (!strcmp(model, "ds1287") ||
-                           !strcmp(model, "m5819") ||
-                           !strcmp(model, "m5819p") ||
-                           !strcmp(model, "m5823")) {
-                               ds1287_regs = edev->resource[0].start;
-                       } else {
-                               mstk48t59_regs = (void __iomem *)
-                                       edev->resource[0].start;
-                               mstk48t02_regs = mstk48t59_regs + MOSTEK_48T59_48T02;
-                       }
-                       break;
-               }
-               else if (isa_br != NULL) {
-                       struct sparc_isa_device *isadev;
-
-try_isa_clock:
-                       for_each_isadev(isadev, isa_br)
-                               if (isadev->prom_node == node)
-                                       break;
-                       if (isadev == NULL) {
-                               prom_printf("%s: Mostek not probed by ISA\n");
-                               prom_halt();
-                       }
-                       if (!strcmp(model, "ds1287") ||
-                           !strcmp(model, "m5819") ||
-                           !strcmp(model, "m5819p") ||
-                           !strcmp(model, "m5823")) {
-                               ds1287_regs = isadev->resource.start;
-                       } else {
-                               mstk48t59_regs = (void __iomem *)
-                                       isadev->resource.start;
-                               mstk48t02_regs = mstk48t59_regs + MOSTEK_48T59_48T02;
-                       }
-                       break;
-               }
+#ifdef CONFIG_SBUS
+           !clock_probe_sbus()
 #endif
-               else {
-                       if (sbus_root->num_sbus_ranges) {
-                               int nranges = sbus_root->num_sbus_ranges;
-                               int rngc;
-
-                               for (rngc = 0; rngc < nranges; rngc++)
-                                       if (clk_reg[0].which_io ==
-                                           sbus_root->sbus_ranges[rngc].ot_child_space)
-                                               break;
-                               if (rngc == nranges) {
-                                       prom_printf("clock_probe: Cannot find ranges for "
-                                                   "clock regs.\n");
-                                       prom_halt();
-                               }
-                               clk_reg[0].which_io =
-                                       sbus_root->sbus_ranges[rngc].ot_parent_space;
-                               clk_reg[0].phys_addr +=
-                                       sbus_root->sbus_ranges[rngc].ot_parent_base;
-                       }
-               }
-
-               if(model[5] == '0' && model[6] == '2') {
-                       mstk48t02_regs = (void __iomem *)
-                               (((u64)clk_reg[0].phys_addr) |
-                                (((u64)clk_reg[0].which_io)<<32UL));
-               } else if(model[5] == '0' && model[6] == '8') {
-                       mstk48t08_regs = (void __iomem *)
-                               (((u64)clk_reg[0].phys_addr) |
-                                (((u64)clk_reg[0].which_io)<<32UL));
-                       mstk48t02_regs = mstk48t08_regs + MOSTEK_48T08_48T02;
-               } else {
-                       mstk48t59_regs = (void __iomem *)
-                               (((u64)clk_reg[0].phys_addr) |
-                                (((u64)clk_reg[0].which_io)<<32UL));
-                       mstk48t02_regs = mstk48t59_regs + MOSTEK_48T59_48T02;
-               }
-               break;
+               ) {
+               printk(KERN_WARNING "No clock chip found.\n");
+               return;
        }
 
+       local_irq_save(flags);
+
        if (mstk48t02_regs != NULL) {
                /* Report a low battery voltage condition. */
                if (has_low_battery())
@@ -997,12 +1004,14 @@ try_isa_clock:
 /* This is gets the master TICK_INT timer going. */
 static unsigned long sparc64_init_timers(void)
 {
+       struct device_node *dp;
+       struct property *prop;
        unsigned long clock;
-       int node;
 #ifdef CONFIG_SMP
        extern void smp_tick_init(void);
 #endif
 
+       dp = of_find_node_by_path("/");
        if (tlb_type == spitfire) {
                unsigned long ver, manuf, impl;
 
@@ -1013,18 +1022,17 @@ static unsigned long sparc64_init_timers(void)
                if (manuf == 0x17 && impl == 0x13) {
                        /* Hummingbird, aka Ultra-IIe */
                        tick_ops = &hbtick_operations;
-                       node = prom_root_node;
-                       clock = prom_getint(node, "stick-frequency");
+                       prop = of_find_property(dp, "stick-frequency", NULL);
                } else {
                        tick_ops = &tick_operations;
-                       cpu_find_by_instance(0, &node, NULL);
-                       clock = prom_getint(node, "clock-frequency");
+                       cpu_find_by_instance(0, &dp, NULL);
+                       prop = of_find_property(dp, "clock-frequency", NULL);
                }
        } else {
                tick_ops = &stick_operations;
-               node = prom_root_node;
-               clock = prom_getint(node, "stick-frequency");
+               prop = of_find_property(dp, "stick-frequency", NULL);
        }
+       clock = *(unsigned int *) prop->value;
        timer_tick_offset = clock / HZ;
 
 #ifdef CONFIG_SMP
@@ -1034,19 +1042,9 @@ static unsigned long sparc64_init_timers(void)
        return clock;
 }
 
-static void sparc64_start_timers(irqreturn_t (*cfunc)(int, void *, struct pt_regs *))
+static void sparc64_start_timers(void)
 {
        unsigned long pstate;
-       int err;
-
-       /* Register IRQ handler. */
-       err = request_irq(build_irq(0, 0, 0UL, 0UL), cfunc, 0,
-                         "timer", NULL);
-
-       if (err) {
-               prom_printf("Serious problem, cannot register TICK_INT\n");
-               prom_halt();
-       }
 
        /* Guarantee that the following sequences execute
         * uninterrupted.
@@ -1130,7 +1128,7 @@ void __init time_init(void)
        /* Now that the interpolator is registered, it is
         * safe to start the timer ticking.
         */
-       sparc64_start_timers(timer_interrupt);
+       sparc64_start_timers();
 
        timer_ticks_per_nsec_quotient =
                (((NSEC_PER_SEC << SPARC64_NSEC_PER_CYC_SHIFT) +