0001
0002
0003 #define pr_fmt(fmt) "mvebu-sei: " fmt
0004
0005 #include <linux/interrupt.h>
0006 #include <linux/irq.h>
0007 #include <linux/irqchip.h>
0008 #include <linux/irqchip/chained_irq.h>
0009 #include <linux/irqdomain.h>
0010 #include <linux/kernel.h>
0011 #include <linux/msi.h>
0012 #include <linux/platform_device.h>
0013 #include <linux/of_address.h>
0014 #include <linux/of_irq.h>
0015 #include <linux/of_platform.h>
0016
0017
0018 #define GICP_SECR(idx) (0x0 + ((idx) * 0x4))
0019
0020 #define GICP_SEMR(idx) (0x20 + ((idx) * 0x4))
0021 #define GICP_SET_SEI_OFFSET 0x30
0022
0023 #define SEI_IRQ_COUNT_PER_REG 32
0024 #define SEI_IRQ_REG_COUNT 2
0025 #define SEI_IRQ_COUNT (SEI_IRQ_COUNT_PER_REG * SEI_IRQ_REG_COUNT)
0026 #define SEI_IRQ_REG_IDX(irq_id) ((irq_id) / SEI_IRQ_COUNT_PER_REG)
0027 #define SEI_IRQ_REG_BIT(irq_id) ((irq_id) % SEI_IRQ_COUNT_PER_REG)
0028
0029 struct mvebu_sei_interrupt_range {
0030 u32 first;
0031 u32 size;
0032 };
0033
0034 struct mvebu_sei_caps {
0035 struct mvebu_sei_interrupt_range ap_range;
0036 struct mvebu_sei_interrupt_range cp_range;
0037 };
0038
0039 struct mvebu_sei {
0040 struct device *dev;
0041 void __iomem *base;
0042 struct resource *res;
0043 struct irq_domain *sei_domain;
0044 struct irq_domain *ap_domain;
0045 struct irq_domain *cp_domain;
0046 const struct mvebu_sei_caps *caps;
0047
0048
0049 struct mutex cp_msi_lock;
0050 DECLARE_BITMAP(cp_msi_bitmap, SEI_IRQ_COUNT);
0051
0052
0053 raw_spinlock_t mask_lock;
0054 };
0055
0056 static void mvebu_sei_ack_irq(struct irq_data *d)
0057 {
0058 struct mvebu_sei *sei = irq_data_get_irq_chip_data(d);
0059 u32 reg_idx = SEI_IRQ_REG_IDX(d->hwirq);
0060
0061 writel_relaxed(BIT(SEI_IRQ_REG_BIT(d->hwirq)),
0062 sei->base + GICP_SECR(reg_idx));
0063 }
0064
0065 static void mvebu_sei_mask_irq(struct irq_data *d)
0066 {
0067 struct mvebu_sei *sei = irq_data_get_irq_chip_data(d);
0068 u32 reg, reg_idx = SEI_IRQ_REG_IDX(d->hwirq);
0069 unsigned long flags;
0070
0071
0072 raw_spin_lock_irqsave(&sei->mask_lock, flags);
0073 reg = readl_relaxed(sei->base + GICP_SEMR(reg_idx));
0074 reg |= BIT(SEI_IRQ_REG_BIT(d->hwirq));
0075 writel_relaxed(reg, sei->base + GICP_SEMR(reg_idx));
0076 raw_spin_unlock_irqrestore(&sei->mask_lock, flags);
0077 }
0078
0079 static void mvebu_sei_unmask_irq(struct irq_data *d)
0080 {
0081 struct mvebu_sei *sei = irq_data_get_irq_chip_data(d);
0082 u32 reg, reg_idx = SEI_IRQ_REG_IDX(d->hwirq);
0083 unsigned long flags;
0084
0085
0086 raw_spin_lock_irqsave(&sei->mask_lock, flags);
0087 reg = readl_relaxed(sei->base + GICP_SEMR(reg_idx));
0088 reg &= ~BIT(SEI_IRQ_REG_BIT(d->hwirq));
0089 writel_relaxed(reg, sei->base + GICP_SEMR(reg_idx));
0090 raw_spin_unlock_irqrestore(&sei->mask_lock, flags);
0091 }
0092
0093 static int mvebu_sei_set_affinity(struct irq_data *d,
0094 const struct cpumask *mask_val,
0095 bool force)
0096 {
0097 return -EINVAL;
0098 }
0099
0100 static int mvebu_sei_set_irqchip_state(struct irq_data *d,
0101 enum irqchip_irq_state which,
0102 bool state)
0103 {
0104
0105 if (which != IRQCHIP_STATE_PENDING || state)
0106 return -EINVAL;
0107
0108 mvebu_sei_ack_irq(d);
0109 return 0;
0110 }
0111
0112 static struct irq_chip mvebu_sei_irq_chip = {
0113 .name = "SEI",
0114 .irq_ack = mvebu_sei_ack_irq,
0115 .irq_mask = mvebu_sei_mask_irq,
0116 .irq_unmask = mvebu_sei_unmask_irq,
0117 .irq_set_affinity = mvebu_sei_set_affinity,
0118 .irq_set_irqchip_state = mvebu_sei_set_irqchip_state,
0119 };
0120
0121 static int mvebu_sei_ap_set_type(struct irq_data *data, unsigned int type)
0122 {
0123 if ((type & IRQ_TYPE_SENSE_MASK) != IRQ_TYPE_LEVEL_HIGH)
0124 return -EINVAL;
0125
0126 return 0;
0127 }
0128
0129 static struct irq_chip mvebu_sei_ap_irq_chip = {
0130 .name = "AP SEI",
0131 .irq_ack = irq_chip_ack_parent,
0132 .irq_mask = irq_chip_mask_parent,
0133 .irq_unmask = irq_chip_unmask_parent,
0134 .irq_set_affinity = irq_chip_set_affinity_parent,
0135 .irq_set_type = mvebu_sei_ap_set_type,
0136 };
0137
0138 static void mvebu_sei_cp_compose_msi_msg(struct irq_data *data,
0139 struct msi_msg *msg)
0140 {
0141 struct mvebu_sei *sei = data->chip_data;
0142 phys_addr_t set = sei->res->start + GICP_SET_SEI_OFFSET;
0143
0144 msg->data = data->hwirq + sei->caps->cp_range.first;
0145 msg->address_lo = lower_32_bits(set);
0146 msg->address_hi = upper_32_bits(set);
0147 }
0148
0149 static int mvebu_sei_cp_set_type(struct irq_data *data, unsigned int type)
0150 {
0151 if ((type & IRQ_TYPE_SENSE_MASK) != IRQ_TYPE_EDGE_RISING)
0152 return -EINVAL;
0153
0154 return 0;
0155 }
0156
0157 static struct irq_chip mvebu_sei_cp_irq_chip = {
0158 .name = "CP SEI",
0159 .irq_ack = irq_chip_ack_parent,
0160 .irq_mask = irq_chip_mask_parent,
0161 .irq_unmask = irq_chip_unmask_parent,
0162 .irq_set_affinity = irq_chip_set_affinity_parent,
0163 .irq_set_type = mvebu_sei_cp_set_type,
0164 .irq_compose_msi_msg = mvebu_sei_cp_compose_msi_msg,
0165 };
0166
0167 static int mvebu_sei_domain_alloc(struct irq_domain *domain, unsigned int virq,
0168 unsigned int nr_irqs, void *arg)
0169 {
0170 struct mvebu_sei *sei = domain->host_data;
0171 struct irq_fwspec *fwspec = arg;
0172
0173
0174 irq_domain_set_hwirq_and_chip(domain, virq, fwspec->param[0],
0175 &mvebu_sei_irq_chip, sei);
0176
0177 return 0;
0178 }
0179
0180 static void mvebu_sei_domain_free(struct irq_domain *domain, unsigned int virq,
0181 unsigned int nr_irqs)
0182 {
0183 int i;
0184
0185 for (i = 0; i < nr_irqs; i++) {
0186 struct irq_data *d = irq_domain_get_irq_data(domain, virq + i);
0187 irq_set_handler(virq + i, NULL);
0188 irq_domain_reset_irq_data(d);
0189 }
0190 }
0191
0192 static const struct irq_domain_ops mvebu_sei_domain_ops = {
0193 .alloc = mvebu_sei_domain_alloc,
0194 .free = mvebu_sei_domain_free,
0195 };
0196
0197 static int mvebu_sei_ap_translate(struct irq_domain *domain,
0198 struct irq_fwspec *fwspec,
0199 unsigned long *hwirq,
0200 unsigned int *type)
0201 {
0202 *hwirq = fwspec->param[0];
0203 *type = IRQ_TYPE_LEVEL_HIGH;
0204
0205 return 0;
0206 }
0207
0208 static int mvebu_sei_ap_alloc(struct irq_domain *domain, unsigned int virq,
0209 unsigned int nr_irqs, void *arg)
0210 {
0211 struct mvebu_sei *sei = domain->host_data;
0212 struct irq_fwspec fwspec;
0213 unsigned long hwirq;
0214 unsigned int type;
0215 int err;
0216
0217 mvebu_sei_ap_translate(domain, arg, &hwirq, &type);
0218
0219 fwspec.fwnode = domain->parent->fwnode;
0220 fwspec.param_count = 1;
0221 fwspec.param[0] = hwirq + sei->caps->ap_range.first;
0222
0223 err = irq_domain_alloc_irqs_parent(domain, virq, 1, &fwspec);
0224 if (err)
0225 return err;
0226
0227 irq_domain_set_info(domain, virq, hwirq,
0228 &mvebu_sei_ap_irq_chip, sei,
0229 handle_level_irq, NULL, NULL);
0230 irq_set_probe(virq);
0231
0232 return 0;
0233 }
0234
0235 static const struct irq_domain_ops mvebu_sei_ap_domain_ops = {
0236 .translate = mvebu_sei_ap_translate,
0237 .alloc = mvebu_sei_ap_alloc,
0238 .free = irq_domain_free_irqs_parent,
0239 };
0240
0241 static void mvebu_sei_cp_release_irq(struct mvebu_sei *sei, unsigned long hwirq)
0242 {
0243 mutex_lock(&sei->cp_msi_lock);
0244 clear_bit(hwirq, sei->cp_msi_bitmap);
0245 mutex_unlock(&sei->cp_msi_lock);
0246 }
0247
0248 static int mvebu_sei_cp_domain_alloc(struct irq_domain *domain,
0249 unsigned int virq, unsigned int nr_irqs,
0250 void *args)
0251 {
0252 struct mvebu_sei *sei = domain->host_data;
0253 struct irq_fwspec fwspec;
0254 unsigned long hwirq;
0255 int ret;
0256
0257
0258 if (nr_irqs != 1)
0259 return -ENOTSUPP;
0260
0261 mutex_lock(&sei->cp_msi_lock);
0262 hwirq = find_first_zero_bit(sei->cp_msi_bitmap,
0263 sei->caps->cp_range.size);
0264 if (hwirq < sei->caps->cp_range.size)
0265 set_bit(hwirq, sei->cp_msi_bitmap);
0266 mutex_unlock(&sei->cp_msi_lock);
0267
0268 if (hwirq == sei->caps->cp_range.size)
0269 return -ENOSPC;
0270
0271 fwspec.fwnode = domain->parent->fwnode;
0272 fwspec.param_count = 1;
0273 fwspec.param[0] = hwirq + sei->caps->cp_range.first;
0274
0275 ret = irq_domain_alloc_irqs_parent(domain, virq, 1, &fwspec);
0276 if (ret)
0277 goto free_irq;
0278
0279 irq_domain_set_info(domain, virq, hwirq,
0280 &mvebu_sei_cp_irq_chip, sei,
0281 handle_edge_irq, NULL, NULL);
0282
0283 return 0;
0284
0285 free_irq:
0286 mvebu_sei_cp_release_irq(sei, hwirq);
0287 return ret;
0288 }
0289
0290 static void mvebu_sei_cp_domain_free(struct irq_domain *domain,
0291 unsigned int virq, unsigned int nr_irqs)
0292 {
0293 struct mvebu_sei *sei = domain->host_data;
0294 struct irq_data *d = irq_domain_get_irq_data(domain, virq);
0295
0296 if (nr_irqs != 1 || d->hwirq >= sei->caps->cp_range.size) {
0297 dev_err(sei->dev, "Invalid hwirq %lu\n", d->hwirq);
0298 return;
0299 }
0300
0301 mvebu_sei_cp_release_irq(sei, d->hwirq);
0302 irq_domain_free_irqs_parent(domain, virq, 1);
0303 }
0304
0305 static const struct irq_domain_ops mvebu_sei_cp_domain_ops = {
0306 .alloc = mvebu_sei_cp_domain_alloc,
0307 .free = mvebu_sei_cp_domain_free,
0308 };
0309
0310 static struct irq_chip mvebu_sei_msi_irq_chip = {
0311 .name = "SEI pMSI",
0312 .irq_ack = irq_chip_ack_parent,
0313 .irq_set_type = irq_chip_set_type_parent,
0314 };
0315
0316 static struct msi_domain_ops mvebu_sei_msi_ops = {
0317 };
0318
0319 static struct msi_domain_info mvebu_sei_msi_domain_info = {
0320 .flags = MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS,
0321 .ops = &mvebu_sei_msi_ops,
0322 .chip = &mvebu_sei_msi_irq_chip,
0323 };
0324
0325 static void mvebu_sei_handle_cascade_irq(struct irq_desc *desc)
0326 {
0327 struct mvebu_sei *sei = irq_desc_get_handler_data(desc);
0328 struct irq_chip *chip = irq_desc_get_chip(desc);
0329 u32 idx;
0330
0331 chained_irq_enter(chip, desc);
0332
0333 for (idx = 0; idx < SEI_IRQ_REG_COUNT; idx++) {
0334 unsigned long irqmap;
0335 int bit;
0336
0337 irqmap = readl_relaxed(sei->base + GICP_SECR(idx));
0338 for_each_set_bit(bit, &irqmap, SEI_IRQ_COUNT_PER_REG) {
0339 unsigned long hwirq;
0340 int err;
0341
0342 hwirq = idx * SEI_IRQ_COUNT_PER_REG + bit;
0343 err = generic_handle_domain_irq(sei->sei_domain, hwirq);
0344 if (unlikely(err))
0345 dev_warn(sei->dev, "Spurious IRQ detected (hwirq %lu)\n", hwirq);
0346 }
0347 }
0348
0349 chained_irq_exit(chip, desc);
0350 }
0351
0352 static void mvebu_sei_reset(struct mvebu_sei *sei)
0353 {
0354 u32 reg_idx;
0355
0356
0357 for (reg_idx = 0; reg_idx < SEI_IRQ_REG_COUNT; reg_idx++) {
0358 writel_relaxed(0xFFFFFFFF, sei->base + GICP_SECR(reg_idx));
0359 writel_relaxed(0xFFFFFFFF, sei->base + GICP_SEMR(reg_idx));
0360 }
0361 }
0362
0363 static int mvebu_sei_probe(struct platform_device *pdev)
0364 {
0365 struct device_node *node = pdev->dev.of_node;
0366 struct irq_domain *plat_domain;
0367 struct mvebu_sei *sei;
0368 u32 parent_irq;
0369 int ret;
0370
0371 sei = devm_kzalloc(&pdev->dev, sizeof(*sei), GFP_KERNEL);
0372 if (!sei)
0373 return -ENOMEM;
0374
0375 sei->dev = &pdev->dev;
0376
0377 mutex_init(&sei->cp_msi_lock);
0378 raw_spin_lock_init(&sei->mask_lock);
0379
0380 sei->res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
0381 sei->base = devm_ioremap_resource(sei->dev, sei->res);
0382 if (IS_ERR(sei->base))
0383 return PTR_ERR(sei->base);
0384
0385
0386 sei->caps = of_device_get_match_data(&pdev->dev);
0387 if (!sei->caps) {
0388 dev_err(sei->dev,
0389 "Could not retrieve controller capabilities\n");
0390 return -EINVAL;
0391 }
0392
0393
0394
0395
0396
0397 parent_irq = irq_of_parse_and_map(node, 0);
0398 if (parent_irq <= 0) {
0399 dev_err(sei->dev, "Failed to retrieve top-level SPI IRQ\n");
0400 return -ENODEV;
0401 }
0402
0403
0404 sei->sei_domain = irq_domain_create_linear(of_node_to_fwnode(node),
0405 (sei->caps->ap_range.size +
0406 sei->caps->cp_range.size),
0407 &mvebu_sei_domain_ops,
0408 sei);
0409 if (!sei->sei_domain) {
0410 dev_err(sei->dev, "Failed to create SEI IRQ domain\n");
0411 ret = -ENOMEM;
0412 goto dispose_irq;
0413 }
0414
0415 irq_domain_update_bus_token(sei->sei_domain, DOMAIN_BUS_NEXUS);
0416
0417
0418 sei->ap_domain = irq_domain_create_hierarchy(sei->sei_domain, 0,
0419 sei->caps->ap_range.size,
0420 of_node_to_fwnode(node),
0421 &mvebu_sei_ap_domain_ops,
0422 sei);
0423 if (!sei->ap_domain) {
0424 dev_err(sei->dev, "Failed to create AP IRQ domain\n");
0425 ret = -ENOMEM;
0426 goto remove_sei_domain;
0427 }
0428
0429 irq_domain_update_bus_token(sei->ap_domain, DOMAIN_BUS_WIRED);
0430
0431
0432 sei->cp_domain = irq_domain_create_hierarchy(sei->sei_domain, 0,
0433 sei->caps->cp_range.size,
0434 of_node_to_fwnode(node),
0435 &mvebu_sei_cp_domain_ops,
0436 sei);
0437 if (!sei->cp_domain) {
0438 pr_err("Failed to create CPs IRQ domain\n");
0439 ret = -ENOMEM;
0440 goto remove_ap_domain;
0441 }
0442
0443 irq_domain_update_bus_token(sei->cp_domain, DOMAIN_BUS_GENERIC_MSI);
0444
0445 plat_domain = platform_msi_create_irq_domain(of_node_to_fwnode(node),
0446 &mvebu_sei_msi_domain_info,
0447 sei->cp_domain);
0448 if (!plat_domain) {
0449 pr_err("Failed to create CPs MSI domain\n");
0450 ret = -ENOMEM;
0451 goto remove_cp_domain;
0452 }
0453
0454 mvebu_sei_reset(sei);
0455
0456 irq_set_chained_handler_and_data(parent_irq,
0457 mvebu_sei_handle_cascade_irq,
0458 sei);
0459
0460 return 0;
0461
0462 remove_cp_domain:
0463 irq_domain_remove(sei->cp_domain);
0464 remove_ap_domain:
0465 irq_domain_remove(sei->ap_domain);
0466 remove_sei_domain:
0467 irq_domain_remove(sei->sei_domain);
0468 dispose_irq:
0469 irq_dispose_mapping(parent_irq);
0470
0471 return ret;
0472 }
0473
0474 static struct mvebu_sei_caps mvebu_sei_ap806_caps = {
0475 .ap_range = {
0476 .first = 0,
0477 .size = 21,
0478 },
0479 .cp_range = {
0480 .first = 21,
0481 .size = 43,
0482 },
0483 };
0484
0485 static const struct of_device_id mvebu_sei_of_match[] = {
0486 {
0487 .compatible = "marvell,ap806-sei",
0488 .data = &mvebu_sei_ap806_caps,
0489 },
0490 {},
0491 };
0492
0493 static struct platform_driver mvebu_sei_driver = {
0494 .probe = mvebu_sei_probe,
0495 .driver = {
0496 .name = "mvebu-sei",
0497 .of_match_table = mvebu_sei_of_match,
0498 },
0499 };
0500 builtin_platform_driver(mvebu_sei_driver);