/* * Copyright (C) 2017 Marvell * * Hanna Hawa <hannah@marvell.com> * Thomas Petazzoni <thomas.petazzoni@free-electrons.com> * * This file is licensed under the terms of the GNU General Public * License version 2. This program is licensed "as is" without any * warranty of any kind, whether express or implied.
*/
/* Check the count of the parameters in dt */ if (WARN_ON(fwspec->param_count != param_count)) {
dev_err(icu->dev, "wrong ICU parameter count %d\n",
fwspec->param_count); return -EINVAL;
}
if (static_branch_unlikely(&legacy_bindings)) {
*hwirq = fwspec->param[1];
*type = fwspec->param[2] & IRQ_TYPE_SENSE_MASK; if (fwspec->param[0] != ICU_GRP_NSR) {
dev_err(icu->dev, "wrong ICU group type %x\n",
fwspec->param[0]); return -EINVAL;
}
} else {
*hwirq = fwspec->param[0];
*type = fwspec->param[1] & IRQ_TYPE_SENSE_MASK;
/* * The ICU receives level interrupts. While the NSR are also * level interrupts, SEI are edge interrupts. Force the type * here in this case. Please note that this makes the interrupt * handling unreliable.
*/ if (msi_data->subset_data->icu_group == ICU_GRP_SEI)
*type = IRQ_TYPE_EDGE_RISING;
}
if (*hwirq >= ICU_MAX_IRQS) {
dev_err(icu->dev, "invalid interrupt number %ld\n", *hwirq); return -EINVAL;
}
/* * The SATA unit has 2 ports, and a dedicated ICU entry per * port. The ahci sata driver supports only one irq interrupt * per SATA unit. To solve this conflict, we configure the 2 * SATA wired interrupts in the south bridge into 1 GIC * interrupt in the north bridge. Even if only a single port * is enabled, if sata node is enabled, both interrupts are * configured (regardless of which port is actually in use).
*/ if (d->hwirq == ICU_SATA0_ICU_ID || d->hwirq == ICU_SATA1_ICU_ID) {
writel_relaxed(icu_int, icu->base + ICU_INT_CFG(ICU_SATA0_ICU_ID));
writel_relaxed(icu_int, icu->base + ICU_INT_CFG(ICU_SATA1_ICU_ID));
}
}
staticint mvebu_icu_probe(struct platform_device *pdev)
{ struct mvebu_icu *icu; int i;
icu = devm_kzalloc(&pdev->dev, sizeof(struct mvebu_icu),
GFP_KERNEL); if (!icu) return -ENOMEM;
icu->dev = &pdev->dev;
icu->base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(icu->base)) return PTR_ERR(icu->base);
/* * Legacy bindings: ICU is one node with one MSI parent: force manually * the probe of the NSR interrupts side. * New bindings: ICU node has children, one per interrupt controller * having its own MSI parent: call platform_populate(). * All ICU instances should use the same bindings.
*/ if (!of_get_child_count(pdev->dev.of_node))
static_branch_enable(&legacy_bindings);
/* * Clean all ICU interrupts of type NSR and SEI, required to * avoid unpredictable SPI assignments done by firmware.
*/ for (i = 0 ; i < ICU_MAX_IRQS ; i++) {
u32 icu_int, icu_grp;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.