Blame view

drivers/irqchip/irq-sirfsoc.c 3.64 KB
a636cd6c4   Thomas Gleixner   treewide: Replace...
1
  // SPDX-License-Identifier: GPL-2.0-or-later
60dbd7680   Arnd Bergmann   ARM: sirf: move i...
2
3
4
5
  /*
   * interrupt controller support for CSR SiRFprimaII
   *
   * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company.
60dbd7680   Arnd Bergmann   ARM: sirf: move i...
6
7
8
9
10
11
12
   */
  
  #include <linux/init.h>
  #include <linux/io.h>
  #include <linux/irq.h>
  #include <linux/of.h>
  #include <linux/of_address.h>
41a83e06e   Joel Porquet   irqchip: Prepare ...
13
  #include <linux/irqchip.h>
60dbd7680   Arnd Bergmann   ARM: sirf: move i...
14
15
16
17
  #include <linux/irqdomain.h>
  #include <linux/syscore_ops.h>
  #include <asm/mach/irq.h>
  #include <asm/exception.h>
60dbd7680   Arnd Bergmann   ARM: sirf: move i...
18

d452bca82   Thomas Gleixner   irqchip/sirfsoc: ...
19
20
21
22
  #define SIRFSOC_INT_RISC_MASK0		0x0018
  #define SIRFSOC_INT_RISC_MASK1		0x001C
  #define SIRFSOC_INT_RISC_LEVEL0		0x0020
  #define SIRFSOC_INT_RISC_LEVEL1		0x0024
60dbd7680   Arnd Bergmann   ARM: sirf: move i...
23
  #define SIRFSOC_INIT_IRQ_ID		0x0038
d452bca82   Thomas Gleixner   irqchip/sirfsoc: ...
24
  #define SIRFSOC_INT_BASE_OFFSET		0x0004
60dbd7680   Arnd Bergmann   ARM: sirf: move i...
25

29eb51a72   Barry Song   irqchip: sirf: mo...
26
  #define SIRFSOC_NUM_IRQS		64
d452bca82   Thomas Gleixner   irqchip/sirfsoc: ...
27
  #define SIRFSOC_NUM_BANKS		(SIRFSOC_NUM_IRQS / 32)
60dbd7680   Arnd Bergmann   ARM: sirf: move i...
28
29
  
  static struct irq_domain *sirfsoc_irqdomain;
4a3691ccb   Ben Dooks   irqchip/sirfsoc: ...
30
31
32
33
  static void __iomem *sirfsoc_irq_get_regbase(void)
  {
  	return (void __iomem __force *)sirfsoc_irqdomain->host_data;
  }
d452bca82   Thomas Gleixner   irqchip/sirfsoc: ...
34
  static __init void sirfsoc_alloc_gc(void __iomem *base)
60dbd7680   Arnd Bergmann   ARM: sirf: move i...
35
  {
29eb51a72   Barry Song   irqchip: sirf: mo...
36
  	unsigned int clr = IRQ_NOREQUEST | IRQ_NOPROBE | IRQ_NOAUTOEN;
a87010ef3   Barry Song   irqchip: sirf: se...
37
  	unsigned int set = IRQ_LEVEL;
d452bca82   Thomas Gleixner   irqchip/sirfsoc: ...
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
  	struct irq_chip_generic *gc;
  	struct irq_chip_type *ct;
  	int i;
  
  	irq_alloc_domain_generic_chips(sirfsoc_irqdomain, 32, 1, "irq_sirfsoc",
  				       handle_level_irq, clr, set,
  				       IRQ_GC_INIT_MASK_CACHE);
  
  	for (i = 0; i < SIRFSOC_NUM_BANKS; i++) {
  		gc = irq_get_domain_generic_chip(sirfsoc_irqdomain, i * 32);
  		gc->reg_base = base + i * SIRFSOC_INT_BASE_OFFSET;
  		ct = gc->chip_types;
  		ct->chip.irq_mask = irq_gc_mask_clr_bit;
  		ct->chip.irq_unmask = irq_gc_mask_set_bit;
  		ct->regs.mask = SIRFSOC_INT_RISC_MASK0;
  	}
60dbd7680   Arnd Bergmann   ARM: sirf: move i...
54
  }
8783dd3a3   Stephen Boyd   irqchip: Remove a...
55
  static void __exception_irq_entry sirfsoc_handle_irq(struct pt_regs *regs)
60dbd7680   Arnd Bergmann   ARM: sirf: move i...
56
  {
4a3691ccb   Ben Dooks   irqchip/sirfsoc: ...
57
  	void __iomem *base = sirfsoc_irq_get_regbase();
c15018e91   Marc Zyngier   irqchip: sirfsoc:...
58
  	u32 irqstat;
60dbd7680   Arnd Bergmann   ARM: sirf: move i...
59
60
  
  	irqstat = readl_relaxed(base + SIRFSOC_INIT_IRQ_ID);
c15018e91   Marc Zyngier   irqchip: sirfsoc:...
61
  	handle_domain_irq(sirfsoc_irqdomain, irqstat & 0xff, regs);
60dbd7680   Arnd Bergmann   ARM: sirf: move i...
62
  }
7caf68520   Bin Shi   irqchip: sirf: fi...
63
64
  static int __init sirfsoc_irq_init(struct device_node *np,
  	struct device_node *parent)
60dbd7680   Arnd Bergmann   ARM: sirf: move i...
65
66
67
68
69
  {
  	void __iomem *base = of_iomap(np, 0);
  	if (!base)
  		panic("unable to map intc cpu registers
  ");
29eb51a72   Barry Song   irqchip: sirf: mo...
70
  	sirfsoc_irqdomain = irq_domain_add_linear(np, SIRFSOC_NUM_IRQS,
d452bca82   Thomas Gleixner   irqchip/sirfsoc: ...
71
72
  						  &irq_generic_chip_ops, base);
  	sirfsoc_alloc_gc(base);
60dbd7680   Arnd Bergmann   ARM: sirf: move i...
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
  
  	writel_relaxed(0, base + SIRFSOC_INT_RISC_LEVEL0);
  	writel_relaxed(0, base + SIRFSOC_INT_RISC_LEVEL1);
  
  	writel_relaxed(0, base + SIRFSOC_INT_RISC_MASK0);
  	writel_relaxed(0, base + SIRFSOC_INT_RISC_MASK1);
  
  	set_handle_irq(sirfsoc_handle_irq);
  
  	return 0;
  }
  IRQCHIP_DECLARE(sirfsoc_intc, "sirf,prima2-intc", sirfsoc_irq_init);
  
  struct sirfsoc_irq_status {
  	u32 mask0;
  	u32 mask1;
  	u32 level0;
  	u32 level1;
  };
  
  static struct sirfsoc_irq_status sirfsoc_irq_st;
  
  static int sirfsoc_irq_suspend(void)
  {
4a3691ccb   Ben Dooks   irqchip/sirfsoc: ...
97
  	void __iomem *base = sirfsoc_irq_get_regbase();
60dbd7680   Arnd Bergmann   ARM: sirf: move i...
98
99
100
101
102
103
104
105
106
107
108
  
  	sirfsoc_irq_st.mask0 = readl_relaxed(base + SIRFSOC_INT_RISC_MASK0);
  	sirfsoc_irq_st.mask1 = readl_relaxed(base + SIRFSOC_INT_RISC_MASK1);
  	sirfsoc_irq_st.level0 = readl_relaxed(base + SIRFSOC_INT_RISC_LEVEL0);
  	sirfsoc_irq_st.level1 = readl_relaxed(base + SIRFSOC_INT_RISC_LEVEL1);
  
  	return 0;
  }
  
  static void sirfsoc_irq_resume(void)
  {
4a3691ccb   Ben Dooks   irqchip/sirfsoc: ...
109
  	void __iomem *base = sirfsoc_irq_get_regbase();
60dbd7680   Arnd Bergmann   ARM: sirf: move i...
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
  
  	writel_relaxed(sirfsoc_irq_st.mask0, base + SIRFSOC_INT_RISC_MASK0);
  	writel_relaxed(sirfsoc_irq_st.mask1, base + SIRFSOC_INT_RISC_MASK1);
  	writel_relaxed(sirfsoc_irq_st.level0, base + SIRFSOC_INT_RISC_LEVEL0);
  	writel_relaxed(sirfsoc_irq_st.level1, base + SIRFSOC_INT_RISC_LEVEL1);
  }
  
  static struct syscore_ops sirfsoc_irq_syscore_ops = {
  	.suspend	= sirfsoc_irq_suspend,
  	.resume		= sirfsoc_irq_resume,
  };
  
  static int __init sirfsoc_irq_pm_init(void)
  {
  	if (!sirfsoc_irqdomain)
  		return 0;
  
  	register_syscore_ops(&sirfsoc_irq_syscore_ops);
  	return 0;
  }
  device_initcall(sirfsoc_irq_pm_init);