Lines Matching +full:msi +full:- +full:base +full:- +full:spi
1 // SPDX-License-Identifier: GPL-2.0
3 #define pr_fmt(fmt) "mvebu-sei: " fmt
11 #include <linux/msi.h>
17 #include <linux/irqchip/irq-msi-lib.h>
43 void __iomem *base; member
50 /* Lock on MSI allocations/releases */
61 u32 reg_idx = SEI_IRQ_REG_IDX(d->hwirq); in mvebu_sei_ack_irq()
63 writel_relaxed(BIT(SEI_IRQ_REG_BIT(d->hwirq)), in mvebu_sei_ack_irq()
64 sei->base + GICP_SECR(reg_idx)); in mvebu_sei_ack_irq()
70 u32 reg, reg_idx = SEI_IRQ_REG_IDX(d->hwirq); in mvebu_sei_mask_irq()
74 raw_spin_lock_irqsave(&sei->mask_lock, flags); in mvebu_sei_mask_irq()
75 reg = readl_relaxed(sei->base + GICP_SEMR(reg_idx)); in mvebu_sei_mask_irq()
76 reg |= BIT(SEI_IRQ_REG_BIT(d->hwirq)); in mvebu_sei_mask_irq()
77 writel_relaxed(reg, sei->base + GICP_SEMR(reg_idx)); in mvebu_sei_mask_irq()
78 raw_spin_unlock_irqrestore(&sei->mask_lock, flags); in mvebu_sei_mask_irq()
84 u32 reg, reg_idx = SEI_IRQ_REG_IDX(d->hwirq); in mvebu_sei_unmask_irq()
88 raw_spin_lock_irqsave(&sei->mask_lock, flags); in mvebu_sei_unmask_irq()
89 reg = readl_relaxed(sei->base + GICP_SEMR(reg_idx)); in mvebu_sei_unmask_irq()
90 reg &= ~BIT(SEI_IRQ_REG_BIT(d->hwirq)); in mvebu_sei_unmask_irq()
91 writel_relaxed(reg, sei->base + GICP_SEMR(reg_idx)); in mvebu_sei_unmask_irq()
92 raw_spin_unlock_irqrestore(&sei->mask_lock, flags); in mvebu_sei_unmask_irq()
99 return -EINVAL; in mvebu_sei_set_affinity()
108 return -EINVAL; in mvebu_sei_set_irqchip_state()
126 return -EINVAL; in mvebu_sei_ap_set_type()
143 struct mvebu_sei *sei = data->chip_data; in mvebu_sei_cp_compose_msi_msg()
144 phys_addr_t set = sei->res->start + GICP_SET_SEI_OFFSET; in mvebu_sei_cp_compose_msi_msg()
146 msg->data = data->hwirq + sei->caps->cp_range.first; in mvebu_sei_cp_compose_msi_msg()
147 msg->address_lo = lower_32_bits(set); in mvebu_sei_cp_compose_msi_msg()
148 msg->address_hi = upper_32_bits(set); in mvebu_sei_cp_compose_msi_msg()
154 return -EINVAL; in mvebu_sei_cp_set_type()
172 struct mvebu_sei *sei = domain->host_data; in mvebu_sei_domain_alloc()
176 irq_domain_set_hwirq_and_chip(domain, virq, fwspec->param[0], in mvebu_sei_domain_alloc()
204 *hwirq = fwspec->param[0]; in mvebu_sei_ap_translate()
213 struct mvebu_sei *sei = domain->host_data; in mvebu_sei_ap_alloc()
221 fwspec.fwnode = domain->parent->fwnode; in mvebu_sei_ap_alloc()
223 fwspec.param[0] = hwirq + sei->caps->ap_range.first; in mvebu_sei_ap_alloc()
245 mutex_lock(&sei->cp_msi_lock); in mvebu_sei_cp_release_irq()
246 clear_bit(hwirq, sei->cp_msi_bitmap); in mvebu_sei_cp_release_irq()
247 mutex_unlock(&sei->cp_msi_lock); in mvebu_sei_cp_release_irq()
254 struct mvebu_sei *sei = domain->host_data; in mvebu_sei_cp_domain_alloc()
261 return -ENOTSUPP; in mvebu_sei_cp_domain_alloc()
263 mutex_lock(&sei->cp_msi_lock); in mvebu_sei_cp_domain_alloc()
264 hwirq = find_first_zero_bit(sei->cp_msi_bitmap, in mvebu_sei_cp_domain_alloc()
265 sei->caps->cp_range.size); in mvebu_sei_cp_domain_alloc()
266 if (hwirq < sei->caps->cp_range.size) in mvebu_sei_cp_domain_alloc()
267 set_bit(hwirq, sei->cp_msi_bitmap); in mvebu_sei_cp_domain_alloc()
268 mutex_unlock(&sei->cp_msi_lock); in mvebu_sei_cp_domain_alloc()
270 if (hwirq == sei->caps->cp_range.size) in mvebu_sei_cp_domain_alloc()
271 return -ENOSPC; in mvebu_sei_cp_domain_alloc()
273 fwspec.fwnode = domain->parent->fwnode; in mvebu_sei_cp_domain_alloc()
275 fwspec.param[0] = hwirq + sei->caps->cp_range.first; in mvebu_sei_cp_domain_alloc()
295 struct mvebu_sei *sei = domain->host_data; in mvebu_sei_cp_domain_free()
298 if (nr_irqs != 1 || d->hwirq >= sei->caps->cp_range.size) { in mvebu_sei_cp_domain_free()
299 dev_err(sei->dev, "Invalid hwirq %lu\n", d->hwirq); in mvebu_sei_cp_domain_free()
303 mvebu_sei_cp_release_irq(sei, d->hwirq); in mvebu_sei_cp_domain_free()
325 irqmap = readl_relaxed(sei->base + GICP_SECR(idx)); in mvebu_sei_handle_cascade_irq()
331 err = generic_handle_domain_irq(sei->sei_domain, hwirq); in mvebu_sei_handle_cascade_irq()
333 dev_warn(sei->dev, "Spurious IRQ detected (hwirq %lu)\n", hwirq); in mvebu_sei_handle_cascade_irq()
346 writel_relaxed(0xFFFFFFFF, sei->base + GICP_SECR(reg_idx)); in mvebu_sei_reset()
347 writel_relaxed(0xFFFFFFFF, sei->base + GICP_SEMR(reg_idx)); in mvebu_sei_reset()
362 .prefix = "SEI-",
368 struct device_node *node = pdev->dev.of_node; in mvebu_sei_probe()
377 sei = devm_kzalloc(&pdev->dev, sizeof(*sei), GFP_KERNEL); in mvebu_sei_probe()
379 return -ENOMEM; in mvebu_sei_probe()
381 sei->dev = &pdev->dev; in mvebu_sei_probe()
383 mutex_init(&sei->cp_msi_lock); in mvebu_sei_probe()
384 raw_spin_lock_init(&sei->mask_lock); in mvebu_sei_probe()
386 sei->base = devm_platform_get_and_ioremap_resource(pdev, 0, &sei->res); in mvebu_sei_probe()
387 if (IS_ERR(sei->base)) in mvebu_sei_probe()
388 return PTR_ERR(sei->base); in mvebu_sei_probe()
391 sei->caps = of_device_get_match_data(&pdev->dev); in mvebu_sei_probe()
392 if (!sei->caps) { in mvebu_sei_probe()
393 dev_err(sei->dev, in mvebu_sei_probe()
395 return -EINVAL; in mvebu_sei_probe()
399 * Reserve the single (top-level) parent SPI IRQ from which all the in mvebu_sei_probe()
404 dev_err(sei->dev, "Failed to retrieve top-level SPI IRQ\n"); in mvebu_sei_probe()
405 return -ENODEV; in mvebu_sei_probe()
409 sei->sei_domain = irq_domain_create_linear(of_fwnode_handle(node), in mvebu_sei_probe()
410 (sei->caps->ap_range.size + in mvebu_sei_probe()
411 sei->caps->cp_range.size), in mvebu_sei_probe()
414 if (!sei->sei_domain) { in mvebu_sei_probe()
415 dev_err(sei->dev, "Failed to create SEI IRQ domain\n"); in mvebu_sei_probe()
416 ret = -ENOMEM; in mvebu_sei_probe()
420 irq_domain_update_bus_token(sei->sei_domain, DOMAIN_BUS_NEXUS); in mvebu_sei_probe()
423 sei->ap_domain = irq_domain_create_hierarchy(sei->sei_domain, 0, in mvebu_sei_probe()
424 sei->caps->ap_range.size, in mvebu_sei_probe()
428 if (!sei->ap_domain) { in mvebu_sei_probe()
429 dev_err(sei->dev, "Failed to create AP IRQ domain\n"); in mvebu_sei_probe()
430 ret = -ENOMEM; in mvebu_sei_probe()
434 irq_domain_update_bus_token(sei->ap_domain, DOMAIN_BUS_WIRED); in mvebu_sei_probe()
436 /* Create the 'MSI' domain */ in mvebu_sei_probe()
437 info.size = sei->caps->cp_range.size; in mvebu_sei_probe()
439 info.parent = sei->sei_domain; in mvebu_sei_probe()
441 sei->cp_domain = msi_create_parent_irq_domain(&info, &sei_msi_parent_ops); in mvebu_sei_probe()
442 if (!sei->cp_domain) { in mvebu_sei_probe()
444 ret = -ENOMEM; in mvebu_sei_probe()
454 irq_domain_remove(sei->ap_domain); in mvebu_sei_probe()
456 irq_domain_remove(sei->sei_domain); in mvebu_sei_probe()
475 .compatible = "marvell,ap806-sei",
484 .name = "mvebu-sei",