crypto: algif_hash - Require setkey before accept(2)
[linux-drm-fsl-dcu.git] / drivers / irqchip / irq-bcm2836.c
index f68708281fcf4a821071f6d84246e34b016db4c5..963065a0d774149da62a5a1d5cac9152bfa9e696 100644 (file)
@@ -21,6 +21,9 @@
 #include <linux/irqdomain.h>
 #include <asm/exception.h>
 
+#define LOCAL_CONTROL                  0x000
+#define LOCAL_PRESCALER                        0x008
+
 /*
  * The low 2 bits identify the CPU that the GPU IRQ goes to, and the
  * next 2 bits identify the CPU that the GPU FIQ goes to.
 /* Same status bits as above, but for FIQ. */
 #define LOCAL_FIQ_PENDING0             0x070
 /*
- * Mailbox0 write-to-set bits.  There are 16 mailboxes, 4 per CPU, and
+ * Mailbox write-to-set bits.  There are 16 mailboxes, 4 per CPU, and
  * these bits are organized by mailbox number and then CPU number.  We
  * use mailbox 0 for IPIs.  The mailbox's interrupt is raised while
  * any bit is set.
  */
 #define LOCAL_MAILBOX0_SET0            0x080
-/* Mailbox0 write-to-clear bits. */
+#define LOCAL_MAILBOX3_SET0            0x08c
+/* Mailbox write-to-clear bits. */
 #define LOCAL_MAILBOX0_CLR0            0x0c0
+#define LOCAL_MAILBOX3_CLR0            0x0cc
 
 #define LOCAL_IRQ_CNTPSIRQ     0
 #define LOCAL_IRQ_CNTPNSIRQ    1
@@ -162,7 +167,7 @@ __exception_irq_entry bcm2836_arm_irqchip_handle_irq(struct pt_regs *regs)
        u32 stat;
 
        stat = readl_relaxed(intc.base + LOCAL_IRQ_PENDING0 + 4 * cpu);
-       if (stat & 0x10) {
+       if (stat & BIT(LOCAL_IRQ_MAILBOX0)) {
 #ifdef CONFIG_SMP
                void __iomem *mailbox0 = (intc.base +
                                          LOCAL_MAILBOX0_CLR0 + 16 * cpu);
@@ -172,7 +177,7 @@ __exception_irq_entry bcm2836_arm_irqchip_handle_irq(struct pt_regs *regs)
                writel(1 << ipi, mailbox0);
                handle_IPI(ipi, regs);
 #endif
-       } else {
+       } else if (stat) {
                u32 hwirq = ffs(stat) - 1;
 
                handle_IRQ(irq_linear_revmap(intc.domain, hwirq), regs);
@@ -217,6 +222,24 @@ static struct notifier_block bcm2836_arm_irqchip_cpu_notifier = {
        .notifier_call = bcm2836_arm_irqchip_cpu_notify,
        .priority = 100,
 };
+
+int __init bcm2836_smp_boot_secondary(unsigned int cpu,
+                                     struct task_struct *idle)
+{
+       unsigned long secondary_startup_phys =
+               (unsigned long)virt_to_phys((void *)secondary_startup);
+
+       dsb();
+       writel(secondary_startup_phys,
+              intc.base + LOCAL_MAILBOX3_SET0 + 16 * cpu);
+
+       return 0;
+}
+
+static const struct smp_operations bcm2836_smp_ops __initconst = {
+       .smp_boot_secondary     = bcm2836_smp_boot_secondary,
+};
+
 #endif
 
 static const struct irq_domain_ops bcm2836_arm_irqchip_intc_ops = {
@@ -234,9 +257,31 @@ bcm2836_arm_irqchip_smp_init(void)
        register_cpu_notifier(&bcm2836_arm_irqchip_cpu_notifier);
 
        set_smp_cross_call(bcm2836_arm_irqchip_send_ipi);
+       smp_set_ops(&bcm2836_smp_ops);
 #endif
 }
 
+/*
+ * The LOCAL_IRQ_CNT* timer firings are based off of the external
+ * oscillator with some scaling.  The firmware sets up CNTFRQ to
+ * report 19.2Mhz, but doesn't set up the scaling registers.
+ */
+static void bcm2835_init_local_timer_frequency(void)
+{
+       /*
+        * Set the timer to source from the 19.2Mhz crystal clock (bit
+        * 8 unset), and only increment by 1 instead of 2 (bit 9
+        * unset).
+        */
+       writel(0, intc.base + LOCAL_CONTROL);
+
+       /*
+        * Set the timer prescaler to 1:1 (timer freq = input freq *
+        * 2**31 / prescaler)
+        */
+       writel(0x80000000, intc.base + LOCAL_PRESCALER);
+}
+
 static int __init bcm2836_arm_irqchip_l1_intc_of_init(struct device_node *node,
                                                      struct device_node *parent)
 {
@@ -246,6 +291,8 @@ static int __init bcm2836_arm_irqchip_l1_intc_of_init(struct device_node *node,
                        node->full_name);
        }
 
+       bcm2835_init_local_timer_frequency();
+
        intc.domain = irq_domain_add_linear(node, LAST_IRQ + 1,
                                            &bcm2836_arm_irqchip_intc_ops,
                                            NULL);