0001
0002
0003
0004
0005
0006
0007
0008 #include <linux/acpi.h>
0009 #include <linux/interrupt.h>
0010 #include <linux/irqchip.h>
0011 #include <linux/module.h>
0012 #include <linux/msi.h>
0013 #include <linux/of_address.h>
0014 #include <linux/of_irq.h>
0015 #include <linux/of_platform.h>
0016 #include <linux/platform_device.h>
0017 #include <linux/slab.h>
0018
0019
0020 #define IRQS_PER_MBIGEN_NODE 128
0021
0022
0023 #define RESERVED_IRQ_PER_MBIGEN_CHIP 64
0024
0025
0026 #define MAXIMUM_IRQ_PIN_NUM 1407
0027
0028
0029
0030
0031
0032
0033 #define IRQ_EVENT_ID_SHIFT 12
0034 #define IRQ_EVENT_ID_MASK 0x3ff
0035
0036
0037 #define MBIGEN_NODE_OFFSET 0x1000
0038
0039
0040 #define REG_MBIGEN_VEC_OFFSET 0x200
0041
0042
0043
0044
0045
0046
0047 #define REG_MBIGEN_CLEAR_OFFSET 0xa000
0048
0049
0050
0051
0052
0053
0054 #define REG_MBIGEN_TYPE_OFFSET 0x0
0055
0056
0057
0058
0059
0060
0061
0062 struct mbigen_device {
0063 struct platform_device *pdev;
0064 void __iomem *base;
0065 };
0066
0067 static inline unsigned int get_mbigen_vec_reg(irq_hw_number_t hwirq)
0068 {
0069 unsigned int nid, pin;
0070
0071 hwirq -= RESERVED_IRQ_PER_MBIGEN_CHIP;
0072 nid = hwirq / IRQS_PER_MBIGEN_NODE + 1;
0073 pin = hwirq % IRQS_PER_MBIGEN_NODE;
0074
0075 return pin * 4 + nid * MBIGEN_NODE_OFFSET
0076 + REG_MBIGEN_VEC_OFFSET;
0077 }
0078
0079 static inline void get_mbigen_type_reg(irq_hw_number_t hwirq,
0080 u32 *mask, u32 *addr)
0081 {
0082 unsigned int nid, irq_ofst, ofst;
0083
0084 hwirq -= RESERVED_IRQ_PER_MBIGEN_CHIP;
0085 nid = hwirq / IRQS_PER_MBIGEN_NODE + 1;
0086 irq_ofst = hwirq % IRQS_PER_MBIGEN_NODE;
0087
0088 *mask = 1 << (irq_ofst % 32);
0089 ofst = irq_ofst / 32 * 4;
0090
0091 *addr = ofst + nid * MBIGEN_NODE_OFFSET
0092 + REG_MBIGEN_TYPE_OFFSET;
0093 }
0094
0095 static inline void get_mbigen_clear_reg(irq_hw_number_t hwirq,
0096 u32 *mask, u32 *addr)
0097 {
0098 unsigned int ofst = (hwirq / 32) * 4;
0099
0100 *mask = 1 << (hwirq % 32);
0101 *addr = ofst + REG_MBIGEN_CLEAR_OFFSET;
0102 }
0103
0104 static void mbigen_eoi_irq(struct irq_data *data)
0105 {
0106 void __iomem *base = data->chip_data;
0107 u32 mask, addr;
0108
0109 get_mbigen_clear_reg(data->hwirq, &mask, &addr);
0110
0111 writel_relaxed(mask, base + addr);
0112
0113 irq_chip_eoi_parent(data);
0114 }
0115
0116 static int mbigen_set_type(struct irq_data *data, unsigned int type)
0117 {
0118 void __iomem *base = data->chip_data;
0119 u32 mask, addr, val;
0120
0121 if (type != IRQ_TYPE_LEVEL_HIGH && type != IRQ_TYPE_EDGE_RISING)
0122 return -EINVAL;
0123
0124 get_mbigen_type_reg(data->hwirq, &mask, &addr);
0125
0126 val = readl_relaxed(base + addr);
0127
0128 if (type == IRQ_TYPE_LEVEL_HIGH)
0129 val |= mask;
0130 else
0131 val &= ~mask;
0132
0133 writel_relaxed(val, base + addr);
0134
0135 return 0;
0136 }
0137
0138 static struct irq_chip mbigen_irq_chip = {
0139 .name = "mbigen-v2",
0140 .irq_mask = irq_chip_mask_parent,
0141 .irq_unmask = irq_chip_unmask_parent,
0142 .irq_eoi = mbigen_eoi_irq,
0143 .irq_set_type = mbigen_set_type,
0144 .irq_set_affinity = irq_chip_set_affinity_parent,
0145 };
0146
0147 static void mbigen_write_msg(struct msi_desc *desc, struct msi_msg *msg)
0148 {
0149 struct irq_data *d = irq_get_irq_data(desc->irq);
0150 void __iomem *base = d->chip_data;
0151 u32 val;
0152
0153 if (!msg->address_lo && !msg->address_hi)
0154 return;
0155
0156 base += get_mbigen_vec_reg(d->hwirq);
0157 val = readl_relaxed(base);
0158
0159 val &= ~(IRQ_EVENT_ID_MASK << IRQ_EVENT_ID_SHIFT);
0160 val |= (msg->data << IRQ_EVENT_ID_SHIFT);
0161
0162
0163
0164
0165 writel_relaxed(val, base);
0166 }
0167
0168 static int mbigen_domain_translate(struct irq_domain *d,
0169 struct irq_fwspec *fwspec,
0170 unsigned long *hwirq,
0171 unsigned int *type)
0172 {
0173 if (is_of_node(fwspec->fwnode) || is_acpi_device_node(fwspec->fwnode)) {
0174 if (fwspec->param_count != 2)
0175 return -EINVAL;
0176
0177 if ((fwspec->param[0] > MAXIMUM_IRQ_PIN_NUM) ||
0178 (fwspec->param[0] < RESERVED_IRQ_PER_MBIGEN_CHIP))
0179 return -EINVAL;
0180 else
0181 *hwirq = fwspec->param[0];
0182
0183
0184 if ((fwspec->param[1] == IRQ_TYPE_EDGE_RISING) ||
0185 (fwspec->param[1] == IRQ_TYPE_LEVEL_HIGH))
0186 *type = fwspec->param[1];
0187 else
0188 return -EINVAL;
0189
0190 return 0;
0191 }
0192 return -EINVAL;
0193 }
0194
0195 static int mbigen_irq_domain_alloc(struct irq_domain *domain,
0196 unsigned int virq,
0197 unsigned int nr_irqs,
0198 void *args)
0199 {
0200 struct irq_fwspec *fwspec = args;
0201 irq_hw_number_t hwirq;
0202 unsigned int type;
0203 struct mbigen_device *mgn_chip;
0204 int i, err;
0205
0206 err = mbigen_domain_translate(domain, fwspec, &hwirq, &type);
0207 if (err)
0208 return err;
0209
0210 err = platform_msi_device_domain_alloc(domain, virq, nr_irqs);
0211 if (err)
0212 return err;
0213
0214 mgn_chip = platform_msi_get_host_data(domain);
0215
0216 for (i = 0; i < nr_irqs; i++)
0217 irq_domain_set_hwirq_and_chip(domain, virq + i, hwirq + i,
0218 &mbigen_irq_chip, mgn_chip->base);
0219
0220 return 0;
0221 }
0222
0223 static void mbigen_irq_domain_free(struct irq_domain *domain, unsigned int virq,
0224 unsigned int nr_irqs)
0225 {
0226 platform_msi_device_domain_free(domain, virq, nr_irqs);
0227 }
0228
0229 static const struct irq_domain_ops mbigen_domain_ops = {
0230 .translate = mbigen_domain_translate,
0231 .alloc = mbigen_irq_domain_alloc,
0232 .free = mbigen_irq_domain_free,
0233 };
0234
0235 static int mbigen_of_create_domain(struct platform_device *pdev,
0236 struct mbigen_device *mgn_chip)
0237 {
0238 struct device *parent;
0239 struct platform_device *child;
0240 struct irq_domain *domain;
0241 struct device_node *np;
0242 u32 num_pins;
0243
0244 for_each_child_of_node(pdev->dev.of_node, np) {
0245 if (!of_property_read_bool(np, "interrupt-controller"))
0246 continue;
0247
0248 parent = platform_bus_type.dev_root;
0249 child = of_platform_device_create(np, NULL, parent);
0250 if (!child) {
0251 of_node_put(np);
0252 return -ENOMEM;
0253 }
0254
0255 if (of_property_read_u32(child->dev.of_node, "num-pins",
0256 &num_pins) < 0) {
0257 dev_err(&pdev->dev, "No num-pins property\n");
0258 of_node_put(np);
0259 return -EINVAL;
0260 }
0261
0262 domain = platform_msi_create_device_domain(&child->dev, num_pins,
0263 mbigen_write_msg,
0264 &mbigen_domain_ops,
0265 mgn_chip);
0266 if (!domain) {
0267 of_node_put(np);
0268 return -ENOMEM;
0269 }
0270 }
0271
0272 return 0;
0273 }
0274
0275 #ifdef CONFIG_ACPI
0276 static const struct acpi_device_id mbigen_acpi_match[] = {
0277 { "HISI0152", 0 },
0278 {}
0279 };
0280 MODULE_DEVICE_TABLE(acpi, mbigen_acpi_match);
0281
0282 static int mbigen_acpi_create_domain(struct platform_device *pdev,
0283 struct mbigen_device *mgn_chip)
0284 {
0285 struct irq_domain *domain;
0286 u32 num_pins = 0;
0287 int ret;
0288
0289
0290
0291
0292
0293
0294
0295
0296
0297
0298
0299
0300
0301
0302
0303
0304
0305
0306
0307
0308
0309
0310
0311
0312 ret = device_property_read_u32(&pdev->dev, "num-pins", &num_pins);
0313 if (ret || num_pins == 0)
0314 return -EINVAL;
0315
0316 domain = platform_msi_create_device_domain(&pdev->dev, num_pins,
0317 mbigen_write_msg,
0318 &mbigen_domain_ops,
0319 mgn_chip);
0320 if (!domain)
0321 return -ENOMEM;
0322
0323 return 0;
0324 }
0325 #else
0326 static inline int mbigen_acpi_create_domain(struct platform_device *pdev,
0327 struct mbigen_device *mgn_chip)
0328 {
0329 return -ENODEV;
0330 }
0331 #endif
0332
0333 static int mbigen_device_probe(struct platform_device *pdev)
0334 {
0335 struct mbigen_device *mgn_chip;
0336 struct resource *res;
0337 int err;
0338
0339 mgn_chip = devm_kzalloc(&pdev->dev, sizeof(*mgn_chip), GFP_KERNEL);
0340 if (!mgn_chip)
0341 return -ENOMEM;
0342
0343 mgn_chip->pdev = pdev;
0344
0345 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
0346 if (!res)
0347 return -EINVAL;
0348
0349 mgn_chip->base = devm_ioremap(&pdev->dev, res->start,
0350 resource_size(res));
0351 if (!mgn_chip->base) {
0352 dev_err(&pdev->dev, "failed to ioremap %pR\n", res);
0353 return -ENOMEM;
0354 }
0355
0356 if (IS_ENABLED(CONFIG_OF) && pdev->dev.of_node)
0357 err = mbigen_of_create_domain(pdev, mgn_chip);
0358 else if (ACPI_COMPANION(&pdev->dev))
0359 err = mbigen_acpi_create_domain(pdev, mgn_chip);
0360 else
0361 err = -EINVAL;
0362
0363 if (err) {
0364 dev_err(&pdev->dev, "Failed to create mbi-gen irqdomain\n");
0365 return err;
0366 }
0367
0368 platform_set_drvdata(pdev, mgn_chip);
0369 return 0;
0370 }
0371
0372 static const struct of_device_id mbigen_of_match[] = {
0373 { .compatible = "hisilicon,mbigen-v2" },
0374 { }
0375 };
0376 MODULE_DEVICE_TABLE(of, mbigen_of_match);
0377
0378 static struct platform_driver mbigen_platform_driver = {
0379 .driver = {
0380 .name = "Hisilicon MBIGEN-V2",
0381 .of_match_table = mbigen_of_match,
0382 .acpi_match_table = ACPI_PTR(mbigen_acpi_match),
0383 .suppress_bind_attrs = true,
0384 },
0385 .probe = mbigen_device_probe,
0386 };
0387
0388 module_platform_driver(mbigen_platform_driver);
0389
0390 MODULE_AUTHOR("Jun Ma <majun258@huawei.com>");
0391 MODULE_AUTHOR("Yun Wu <wuyun.wu@huawei.com>");
0392 MODULE_LICENSE("GPL");
0393 MODULE_DESCRIPTION("HiSilicon MBI Generator driver");