mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-30 19:51:31 -04:00
irqchip: Add GICv2 specific ACPI boot support
ACPI kernel uses MADT table for proper GIC initialization. It needs to parse GIC related subtables, collect CPU interface and distributor addresses and call driver initialization function (which is hardware abstraction agnostic). In a similar way, FDT initialize GICv1/2. NOTE: This commit allow to initialize GICv1/2 basic functionality. While now simple GICv2 init call is used, any further GIC features require generic infrastructure for proper ACPI irqchip initialization. That mechanism and stacked irqdomains to support GICv2 MSI/virtualization extension, GICv3/4 and its ITS are considered as next steps. CC: Jason Cooper <[email protected]> CC: Marc Zyngier <[email protected]> CC: Thomas Gleixner <[email protected]> Tested-by: Suravee Suthikulpanit <[email protected]> Tested-by: Yijing Wang <[email protected]> Tested-by: Mark Langsdorf <[email protected]> Tested-by: Jon Masters <[email protected]> Tested-by: Timur Tabi <[email protected]> Tested-by: Robert Richter <[email protected]> Acked-by: Robert Richter <[email protected]> Acked-by: Marc Zyngier <[email protected]> Acked-by: Jason Cooper <[email protected]> Reviewed-by: Grant Likely <[email protected]> Signed-off-by: Tomasz Nowicki <[email protected]> Signed-off-by: Hanjun Guo <[email protected]> Signed-off-by: Will Deacon <[email protected]>
This commit is contained in:
parent
fbe61ec71a
commit
d60fc3892c
7 changed files with 186 additions and 0 deletions
|
|
@ -33,12 +33,14 @@
|
|||
#include <linux/of.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/of_irq.h>
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/irqdomain.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/percpu.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/irqchip/chained_irq.h>
|
||||
#include <linux/irqchip/arm-gic.h>
|
||||
#include <linux/irqchip/arm-gic-acpi.h>
|
||||
|
||||
#include <asm/cputype.h>
|
||||
#include <asm/irq.h>
|
||||
|
|
@ -1090,3 +1092,103 @@ IRQCHIP_DECLARE(msm_8660_qgic, "qcom,msm-8660-qgic", gic_of_init);
|
|||
IRQCHIP_DECLARE(msm_qgic2, "qcom,msm-qgic2", gic_of_init);
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_ACPI
|
||||
static phys_addr_t dist_phy_base, cpu_phy_base __initdata;
|
||||
|
||||
static int __init
|
||||
gic_acpi_parse_madt_cpu(struct acpi_subtable_header *header,
|
||||
const unsigned long end)
|
||||
{
|
||||
struct acpi_madt_generic_interrupt *processor;
|
||||
phys_addr_t gic_cpu_base;
|
||||
static int cpu_base_assigned;
|
||||
|
||||
processor = (struct acpi_madt_generic_interrupt *)header;
|
||||
|
||||
if (BAD_MADT_ENTRY(processor, end))
|
||||
return -EINVAL;
|
||||
|
||||
/*
|
||||
* There is no support for non-banked GICv1/2 register in ACPI spec.
|
||||
* All CPU interface addresses have to be the same.
|
||||
*/
|
||||
gic_cpu_base = processor->base_address;
|
||||
if (cpu_base_assigned && gic_cpu_base != cpu_phy_base)
|
||||
return -EINVAL;
|
||||
|
||||
cpu_phy_base = gic_cpu_base;
|
||||
cpu_base_assigned = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __init
|
||||
gic_acpi_parse_madt_distributor(struct acpi_subtable_header *header,
|
||||
const unsigned long end)
|
||||
{
|
||||
struct acpi_madt_generic_distributor *dist;
|
||||
|
||||
dist = (struct acpi_madt_generic_distributor *)header;
|
||||
|
||||
if (BAD_MADT_ENTRY(dist, end))
|
||||
return -EINVAL;
|
||||
|
||||
dist_phy_base = dist->base_address;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int __init
|
||||
gic_v2_acpi_init(struct acpi_table_header *table)
|
||||
{
|
||||
void __iomem *cpu_base, *dist_base;
|
||||
int count;
|
||||
|
||||
/* Collect CPU base addresses */
|
||||
count = acpi_parse_entries(ACPI_SIG_MADT,
|
||||
sizeof(struct acpi_table_madt),
|
||||
gic_acpi_parse_madt_cpu, table,
|
||||
ACPI_MADT_TYPE_GENERIC_INTERRUPT, 0);
|
||||
if (count <= 0) {
|
||||
pr_err("No valid GICC entries exist\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Find distributor base address. We expect one distributor entry since
|
||||
* ACPI 5.1 spec neither support multi-GIC instances nor GIC cascade.
|
||||
*/
|
||||
count = acpi_parse_entries(ACPI_SIG_MADT,
|
||||
sizeof(struct acpi_table_madt),
|
||||
gic_acpi_parse_madt_distributor, table,
|
||||
ACPI_MADT_TYPE_GENERIC_DISTRIBUTOR, 0);
|
||||
if (count <= 0) {
|
||||
pr_err("No valid GICD entries exist\n");
|
||||
return -EINVAL;
|
||||
} else if (count > 1) {
|
||||
pr_err("More than one GICD entry detected\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
cpu_base = ioremap(cpu_phy_base, ACPI_GIC_CPU_IF_MEM_SIZE);
|
||||
if (!cpu_base) {
|
||||
pr_err("Unable to map GICC registers\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
dist_base = ioremap(dist_phy_base, ACPI_GICV2_DIST_MEM_SIZE);
|
||||
if (!dist_base) {
|
||||
pr_err("Unable to map GICD registers\n");
|
||||
iounmap(cpu_base);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize zero GIC instance (no multi-GIC support). Also, set GIC
|
||||
* as default IRQ domain to allow for GSI registration and GSI to IRQ
|
||||
* number translation (see acpi_register_gsi() and acpi_gsi_to_irq()).
|
||||
*/
|
||||
gic_init_bases(0, -1, dist_base, cpu_base, 0, NULL);
|
||||
irq_set_default_host(gic_data[0].domain);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@
|
|||
* warranty of any kind, whether express or implied.
|
||||
*/
|
||||
|
||||
#include <linux/acpi_irq.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/of_irq.h>
|
||||
#include <linux/irqchip.h>
|
||||
|
|
@ -26,4 +27,6 @@ extern struct of_device_id __irqchip_of_table[];
|
|||
void __init irqchip_init(void)
|
||||
{
|
||||
of_irq_init(__irqchip_of_table);
|
||||
|
||||
acpi_irq_init();
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue