0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012 #include <linux/interrupt.h>
0013 #include <linux/io.h>
0014 #include <linux/irq.h>
0015 #include <linux/irqchip.h>
0016 #include <linux/irqdomain.h>
0017 #include <linux/of.h>
0018 #include <linux/of_address.h>
0019 #include <linux/of_irq.h>
0020 #include <linux/platform_device.h>
0021
0022 #include <dt-bindings/interrupt-controller/arm-gic.h>
0023
0024 #define NUM_IRQS 32
0025
0026 #define EIMASK 0x00
0027 #define EISRCSEL 0x04
0028 #define EIREQSTA 0x08
0029 #define EIRAWREQSTA 0x0C
0030 #define EIREQCLR 0x10
0031 #define EILVL 0x14
0032 #define EIEDG 0x18
0033 #define EISIR 0x1C
0034
0035 struct exiu_irq_data {
0036 void __iomem *base;
0037 u32 spi_base;
0038 };
0039
0040 static void exiu_irq_ack(struct irq_data *d)
0041 {
0042 struct exiu_irq_data *data = irq_data_get_irq_chip_data(d);
0043
0044 writel(BIT(d->hwirq), data->base + EIREQCLR);
0045 }
0046
0047 static void exiu_irq_eoi(struct irq_data *d)
0048 {
0049 struct exiu_irq_data *data = irq_data_get_irq_chip_data(d);
0050
0051
0052
0053
0054
0055
0056
0057 if (irqd_is_level_type(d))
0058 writel(BIT(d->hwirq), data->base + EIREQCLR);
0059
0060 irq_chip_eoi_parent(d);
0061 }
0062
0063 static void exiu_irq_mask(struct irq_data *d)
0064 {
0065 struct exiu_irq_data *data = irq_data_get_irq_chip_data(d);
0066 u32 val;
0067
0068 val = readl_relaxed(data->base + EIMASK) | BIT(d->hwirq);
0069 writel_relaxed(val, data->base + EIMASK);
0070 irq_chip_mask_parent(d);
0071 }
0072
0073 static void exiu_irq_unmask(struct irq_data *d)
0074 {
0075 struct exiu_irq_data *data = irq_data_get_irq_chip_data(d);
0076 u32 val;
0077
0078 val = readl_relaxed(data->base + EIMASK) & ~BIT(d->hwirq);
0079 writel_relaxed(val, data->base + EIMASK);
0080 irq_chip_unmask_parent(d);
0081 }
0082
0083 static void exiu_irq_enable(struct irq_data *d)
0084 {
0085 struct exiu_irq_data *data = irq_data_get_irq_chip_data(d);
0086 u32 val;
0087
0088
0089 writel_relaxed(BIT(d->hwirq), data->base + EIREQCLR);
0090
0091 val = readl_relaxed(data->base + EIMASK) & ~BIT(d->hwirq);
0092 writel_relaxed(val, data->base + EIMASK);
0093 irq_chip_enable_parent(d);
0094 }
0095
0096 static int exiu_irq_set_type(struct irq_data *d, unsigned int type)
0097 {
0098 struct exiu_irq_data *data = irq_data_get_irq_chip_data(d);
0099 u32 val;
0100
0101 val = readl_relaxed(data->base + EILVL);
0102 if (type == IRQ_TYPE_EDGE_RISING || type == IRQ_TYPE_LEVEL_HIGH)
0103 val |= BIT(d->hwirq);
0104 else
0105 val &= ~BIT(d->hwirq);
0106 writel_relaxed(val, data->base + EILVL);
0107
0108 val = readl_relaxed(data->base + EIEDG);
0109 if (type == IRQ_TYPE_LEVEL_LOW || type == IRQ_TYPE_LEVEL_HIGH) {
0110 val &= ~BIT(d->hwirq);
0111 irq_set_handler_locked(d, handle_fasteoi_irq);
0112 } else {
0113 val |= BIT(d->hwirq);
0114 irq_set_handler_locked(d, handle_fasteoi_ack_irq);
0115 }
0116 writel_relaxed(val, data->base + EIEDG);
0117
0118 writel_relaxed(BIT(d->hwirq), data->base + EIREQCLR);
0119
0120 return irq_chip_set_type_parent(d, IRQ_TYPE_LEVEL_HIGH);
0121 }
0122
0123 static struct irq_chip exiu_irq_chip = {
0124 .name = "EXIU",
0125 .irq_ack = exiu_irq_ack,
0126 .irq_eoi = exiu_irq_eoi,
0127 .irq_enable = exiu_irq_enable,
0128 .irq_mask = exiu_irq_mask,
0129 .irq_unmask = exiu_irq_unmask,
0130 .irq_set_type = exiu_irq_set_type,
0131 .irq_set_affinity = irq_chip_set_affinity_parent,
0132 .flags = IRQCHIP_SET_TYPE_MASKED |
0133 IRQCHIP_SKIP_SET_WAKE |
0134 IRQCHIP_EOI_THREADED |
0135 IRQCHIP_MASK_ON_SUSPEND,
0136 };
0137
0138 static int exiu_domain_translate(struct irq_domain *domain,
0139 struct irq_fwspec *fwspec,
0140 unsigned long *hwirq,
0141 unsigned int *type)
0142 {
0143 struct exiu_irq_data *info = domain->host_data;
0144
0145 if (is_of_node(fwspec->fwnode)) {
0146 if (fwspec->param_count != 3)
0147 return -EINVAL;
0148
0149 if (fwspec->param[0] != GIC_SPI)
0150 return -EINVAL;
0151
0152 *hwirq = fwspec->param[1] - info->spi_base;
0153 *type = fwspec->param[2] & IRQ_TYPE_SENSE_MASK;
0154 } else {
0155 if (fwspec->param_count != 2)
0156 return -EINVAL;
0157 *hwirq = fwspec->param[0];
0158 *type = fwspec->param[1] & IRQ_TYPE_SENSE_MASK;
0159 }
0160 return 0;
0161 }
0162
0163 static int exiu_domain_alloc(struct irq_domain *dom, unsigned int virq,
0164 unsigned int nr_irqs, void *data)
0165 {
0166 struct irq_fwspec *fwspec = data;
0167 struct irq_fwspec parent_fwspec;
0168 struct exiu_irq_data *info = dom->host_data;
0169 irq_hw_number_t hwirq;
0170
0171 parent_fwspec = *fwspec;
0172 if (is_of_node(dom->parent->fwnode)) {
0173 if (fwspec->param_count != 3)
0174 return -EINVAL;
0175 if (fwspec->param[0] != GIC_SPI)
0176 return -EINVAL;
0177
0178 hwirq = fwspec->param[1] - info->spi_base;
0179 } else {
0180 hwirq = fwspec->param[0];
0181 parent_fwspec.param[0] = hwirq + info->spi_base + 32;
0182 }
0183 WARN_ON(nr_irqs != 1);
0184 irq_domain_set_hwirq_and_chip(dom, virq, hwirq, &exiu_irq_chip, info);
0185
0186 parent_fwspec.fwnode = dom->parent->fwnode;
0187 return irq_domain_alloc_irqs_parent(dom, virq, nr_irqs, &parent_fwspec);
0188 }
0189
0190 static const struct irq_domain_ops exiu_domain_ops = {
0191 .translate = exiu_domain_translate,
0192 .alloc = exiu_domain_alloc,
0193 .free = irq_domain_free_irqs_common,
0194 };
0195
0196 static struct exiu_irq_data *exiu_init(const struct fwnode_handle *fwnode,
0197 struct resource *res)
0198 {
0199 struct exiu_irq_data *data;
0200 int err;
0201
0202 data = kzalloc(sizeof(*data), GFP_KERNEL);
0203 if (!data)
0204 return ERR_PTR(-ENOMEM);
0205
0206 if (fwnode_property_read_u32_array(fwnode, "socionext,spi-base",
0207 &data->spi_base, 1)) {
0208 err = -ENODEV;
0209 goto out_free;
0210 }
0211
0212 data->base = ioremap(res->start, resource_size(res));
0213 if (!data->base) {
0214 err = -ENODEV;
0215 goto out_free;
0216 }
0217
0218
0219 writel_relaxed(0xFFFFFFFF, data->base + EIREQCLR);
0220 writel_relaxed(0xFFFFFFFF, data->base + EIMASK);
0221
0222 return data;
0223
0224 out_free:
0225 kfree(data);
0226 return ERR_PTR(err);
0227 }
0228
0229 static int __init exiu_dt_init(struct device_node *node,
0230 struct device_node *parent)
0231 {
0232 struct irq_domain *parent_domain, *domain;
0233 struct exiu_irq_data *data;
0234 struct resource res;
0235
0236 if (!parent) {
0237 pr_err("%pOF: no parent, giving up\n", node);
0238 return -ENODEV;
0239 }
0240
0241 parent_domain = irq_find_host(parent);
0242 if (!parent_domain) {
0243 pr_err("%pOF: unable to obtain parent domain\n", node);
0244 return -ENXIO;
0245 }
0246
0247 if (of_address_to_resource(node, 0, &res)) {
0248 pr_err("%pOF: failed to parse memory resource\n", node);
0249 return -ENXIO;
0250 }
0251
0252 data = exiu_init(of_node_to_fwnode(node), &res);
0253 if (IS_ERR(data))
0254 return PTR_ERR(data);
0255
0256 domain = irq_domain_add_hierarchy(parent_domain, 0, NUM_IRQS, node,
0257 &exiu_domain_ops, data);
0258 if (!domain) {
0259 pr_err("%pOF: failed to allocate domain\n", node);
0260 goto out_unmap;
0261 }
0262
0263 pr_info("%pOF: %d interrupts forwarded to %pOF\n", node, NUM_IRQS,
0264 parent);
0265
0266 return 0;
0267
0268 out_unmap:
0269 iounmap(data->base);
0270 kfree(data);
0271 return -ENOMEM;
0272 }
0273 IRQCHIP_DECLARE(exiu, "socionext,synquacer-exiu", exiu_dt_init);
0274
0275 #ifdef CONFIG_ACPI
0276 static int exiu_acpi_probe(struct platform_device *pdev)
0277 {
0278 struct irq_domain *domain;
0279 struct exiu_irq_data *data;
0280 struct resource *res;
0281
0282 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
0283 if (!res) {
0284 dev_err(&pdev->dev, "failed to parse memory resource\n");
0285 return -ENXIO;
0286 }
0287
0288 data = exiu_init(dev_fwnode(&pdev->dev), res);
0289 if (IS_ERR(data))
0290 return PTR_ERR(data);
0291
0292 domain = acpi_irq_create_hierarchy(0, NUM_IRQS, dev_fwnode(&pdev->dev),
0293 &exiu_domain_ops, data);
0294 if (!domain) {
0295 dev_err(&pdev->dev, "failed to create IRQ domain\n");
0296 goto out_unmap;
0297 }
0298
0299 dev_info(&pdev->dev, "%d interrupts forwarded\n", NUM_IRQS);
0300
0301 return 0;
0302
0303 out_unmap:
0304 iounmap(data->base);
0305 kfree(data);
0306 return -ENOMEM;
0307 }
0308
0309 static const struct acpi_device_id exiu_acpi_ids[] = {
0310 { "SCX0008" },
0311 { }
0312 };
0313 MODULE_DEVICE_TABLE(acpi, exiu_acpi_ids);
0314
0315 static struct platform_driver exiu_driver = {
0316 .driver = {
0317 .name = "exiu",
0318 .acpi_match_table = exiu_acpi_ids,
0319 },
0320 .probe = exiu_acpi_probe,
0321 };
0322 builtin_platform_driver(exiu_driver);
0323 #endif