arm64: dts: qcom: sm8550: add TRNG node
[linux-modified.git] / arch / powerpc / platforms / 512x / mpc5121_ads_cpld.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * Copyright (C) 2008 Freescale Semiconductor, Inc. All rights reserved.
4  *
5  * Author: John Rigby, <jrigby@freescale.com>
6  *
7  * Description:
8  * MPC5121ADS CPLD irq handling
9  */
10
11 #undef DEBUG
12
13 #include <linux/kernel.h>
14 #include <linux/interrupt.h>
15 #include <linux/irq.h>
16 #include <linux/io.h>
17 #include <linux/of_address.h>
18 #include <linux/of_irq.h>
19
20 static struct device_node *cpld_pic_node;
21 static struct irq_domain *cpld_pic_host;
22
23 /*
24  * Bits to ignore in the misc_status register
25  * 0x10 touch screen pendown is hard routed to irq1
26  * 0x02 pci status is read from pci status register
27  */
28 #define MISC_IGNORE 0x12
29
30 /*
31  * Nothing to ignore in pci status register
32  */
33 #define PCI_IGNORE 0x00
34
35 struct cpld_pic {
36         u8 pci_mask;
37         u8 pci_status;
38         u8 route;
39         u8 misc_mask;
40         u8 misc_status;
41         u8 misc_control;
42 };
43
44 static struct cpld_pic __iomem *cpld_regs;
45
46 static void __iomem *
47 irq_to_pic_mask(unsigned int irq)
48 {
49         return irq <= 7 ? &cpld_regs->pci_mask : &cpld_regs->misc_mask;
50 }
51
52 static unsigned int
53 irq_to_pic_bit(unsigned int irq)
54 {
55         return 1 << (irq & 0x7);
56 }
57
58 static void
59 cpld_mask_irq(struct irq_data *d)
60 {
61         unsigned int cpld_irq = (unsigned int)irqd_to_hwirq(d);
62         void __iomem *pic_mask = irq_to_pic_mask(cpld_irq);
63
64         out_8(pic_mask,
65               in_8(pic_mask) | irq_to_pic_bit(cpld_irq));
66 }
67
68 static void
69 cpld_unmask_irq(struct irq_data *d)
70 {
71         unsigned int cpld_irq = (unsigned int)irqd_to_hwirq(d);
72         void __iomem *pic_mask = irq_to_pic_mask(cpld_irq);
73
74         out_8(pic_mask,
75               in_8(pic_mask) & ~irq_to_pic_bit(cpld_irq));
76 }
77
78 static struct irq_chip cpld_pic = {
79         .name = "CPLD PIC",
80         .irq_mask = cpld_mask_irq,
81         .irq_ack = cpld_mask_irq,
82         .irq_unmask = cpld_unmask_irq,
83 };
84
85 static unsigned int
86 cpld_pic_get_irq(int offset, u8 ignore, u8 __iomem *statusp,
87                             u8 __iomem *maskp)
88 {
89         u8 status = in_8(statusp);
90         u8 mask = in_8(maskp);
91
92         /* ignore don't cares and masked irqs */
93         status |= (ignore | mask);
94
95         if (status == 0xff)
96                 return ~0;
97
98         return ffz(status) + offset;
99 }
100
101 static void cpld_pic_cascade(struct irq_desc *desc)
102 {
103         unsigned int hwirq;
104
105         hwirq = cpld_pic_get_irq(0, PCI_IGNORE, &cpld_regs->pci_status,
106                 &cpld_regs->pci_mask);
107         if (hwirq != ~0) {
108                 generic_handle_domain_irq(cpld_pic_host, hwirq);
109                 return;
110         }
111
112         hwirq = cpld_pic_get_irq(8, MISC_IGNORE, &cpld_regs->misc_status,
113                 &cpld_regs->misc_mask);
114         if (hwirq != ~0) {
115                 generic_handle_domain_irq(cpld_pic_host, hwirq);
116                 return;
117         }
118 }
119
120 static int
121 cpld_pic_host_match(struct irq_domain *h, struct device_node *node,
122                     enum irq_domain_bus_token bus_token)
123 {
124         return cpld_pic_node == node;
125 }
126
127 static int
128 cpld_pic_host_map(struct irq_domain *h, unsigned int virq,
129                              irq_hw_number_t hw)
130 {
131         irq_set_status_flags(virq, IRQ_LEVEL);
132         irq_set_chip_and_handler(virq, &cpld_pic, handle_level_irq);
133         return 0;
134 }
135
136 static const struct irq_domain_ops cpld_pic_host_ops = {
137         .match = cpld_pic_host_match,
138         .map = cpld_pic_host_map,
139 };
140
141 void __init
142 mpc5121_ads_cpld_map(void)
143 {
144         struct device_node *np = NULL;
145
146         np = of_find_compatible_node(NULL, NULL, "fsl,mpc5121ads-cpld-pic");
147         if (!np) {
148                 printk(KERN_ERR "CPLD PIC init: can not find cpld-pic node\n");
149                 return;
150         }
151
152         cpld_regs = of_iomap(np, 0);
153         of_node_put(np);
154 }
155
156 void __init
157 mpc5121_ads_cpld_pic_init(void)
158 {
159         unsigned int cascade_irq;
160         struct device_node *np = NULL;
161
162         pr_debug("cpld_ic_init\n");
163
164         np = of_find_compatible_node(NULL, NULL, "fsl,mpc5121ads-cpld-pic");
165         if (!np) {
166                 printk(KERN_ERR "CPLD PIC init: can not find cpld-pic node\n");
167                 return;
168         }
169
170         if (!cpld_regs)
171                 goto end;
172
173         cascade_irq = irq_of_parse_and_map(np, 0);
174         if (!cascade_irq)
175                 goto end;
176
177         /*
178          * statically route touch screen pendown through 1
179          * and ignore it here
180          * route all others through our cascade irq
181          */
182         out_8(&cpld_regs->route, 0xfd);
183         out_8(&cpld_regs->pci_mask, 0xff);
184         /* unmask pci ints in misc mask */
185         out_8(&cpld_regs->misc_mask, ~(MISC_IGNORE));
186
187         cpld_pic_node = of_node_get(np);
188
189         cpld_pic_host = irq_domain_add_linear(np, 16, &cpld_pic_host_ops, NULL);
190         if (!cpld_pic_host) {
191                 printk(KERN_ERR "CPLD PIC: failed to allocate irq host!\n");
192                 goto end;
193         }
194
195         irq_set_chained_handler(cascade_irq, cpld_pic_cascade);
196 end:
197         of_node_put(np);
198 }