Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 7108a7bc authored by qctecmdr's avatar qctecmdr Committed by Gerrit - the friendly Code Review server
Browse files

Merge "ARM: dts: msm: add SPI to support PCIe Synopsys IRQ 1 for sdxprairie"

parents df36e143 9d0f348b
Loading
Loading
Loading
Loading
+3 −2
Original line number Diff line number Diff line
/*
 * Copyright (c) 2019, The Linux Foundation. All rights reserved.
 * Copyright (c) 2019-2020, The Linux Foundation. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 and
@@ -268,7 +268,8 @@
		msi-controller;
		reg = <0xa0000000 0x0>;
		interrupt-parent = <&intc>;
		interrupts = <GIC_SPI 119 IRQ_TYPE_LEVEL_HIGH>;
		interrupts = <GIC_SPI 119 IRQ_TYPE_LEVEL_HIGH>,
			<GIC_SPI 120 IRQ_TYPE_LEVEL_HIGH>;
		qcom,snps;
	};
};
+121 −98
Original line number Diff line number Diff line
/* Copyright (c) 2014-2019, The Linux Foundation. All rights reserved.
/* Copyright (c) 2014-2020, The Linux Foundation. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 and
@@ -34,7 +34,6 @@
#define PCIE_MSI_CTRL_INT_N_MASK_OFFS(n) (PCIE_MSI_CTRL_BASE + 0xc + 0xc * n)
#define PCIE_MSI_CTRL_INT_N_STATUS_OFFS(n) (PCIE_MSI_CTRL_BASE + 0x10 + 0xc * n)

#define MSI_IRQ_NR_GRP (2)
#define MSI_IRQ_PER_GRP (32)

enum msi_type {
@@ -95,22 +94,15 @@ struct msm_msi_client {
static void msm_msi_snps_handler(struct irq_desc *desc)
{
	struct irq_chip *chip = irq_desc_get_chip(desc);
	struct msm_msi *msi;
	struct msm_msi_grp *msi_grp;
	int i;
	u32 status, mask;

	chained_irq_enter(chip, desc);

	msi = irq_desc_get_handler_data(desc);

	for (i = 0; i < msi->nr_grps; i++) {
		struct msm_msi_grp *msi_grp = &msi->grps[i];
		u32 mask = msi_grp->mask;
		u32 status;
		u32 index;
	msi_grp = irq_desc_get_handler_data(desc);

	status = readl_relaxed(msi_grp->int_status_reg);
		if (!status)
			continue;

	/* always update the mask set in msm_msi_snps_mask_irq */
	mask = msi_grp->mask;
@@ -120,10 +112,9 @@ static void msm_msi_snps_handler(struct irq_desc *desc)
	status ^= (status & mask);
	writel_relaxed(status, msi_grp->int_status_reg);

		for (index = 0; status; index++, status >>= 1)
	for (i = 0; status; i++, status >>= 1)
		if (status & 0x1)
				generic_handle_irq(msi_grp->irqs[index].virq);
	}
			generic_handle_irq(msi_grp->irqs[i].virq);

	chained_irq_exit(chip, desc);
}
@@ -483,6 +474,103 @@ static int msm_msi_alloc_domains(struct msm_msi *msi)
	return 0;
}

static int msm_msi_snps_irq_setup(struct msm_msi *msi)
{
	int i, index, ret;
	struct msm_msi_grp *msi_grp;
	struct msm_msi_irq *msi_irq;
	unsigned int irq = 0;

	/* setup each MSI group. nr_hwirqs == nr_grps */
	for (i = 0; i < msi->nr_hwirqs; i++) {
		irq = irq_of_parse_and_map(msi->of_node, i);
		if (!irq) {
			dev_err(msi->dev,
				"MSI: failed to parse/map interrupt\n");
			ret = -ENODEV;
			goto free_irqs;
		}

		msi_grp = &msi->grps[i];
		msi_grp->int_en_reg = msi->pcie_cfg +
				PCIE_MSI_CTRL_INT_N_EN_OFFS(i);
		msi_grp->int_mask_reg = msi->pcie_cfg +
				PCIE_MSI_CTRL_INT_N_MASK_OFFS(i);
		msi_grp->int_status_reg = msi->pcie_cfg +
				PCIE_MSI_CTRL_INT_N_STATUS_OFFS(i);

		for (index = 0; index < MSI_IRQ_PER_GRP; index++) {
			msi_irq = &msi_grp->irqs[index];

			msi_irq->grp = msi_grp;
			msi_irq->grp_index = index;
			msi_irq->pos = (i * MSI_IRQ_PER_GRP) + index;
			msi_irq->hwirq = irq;
		}

		irq_set_chained_handler_and_data(irq, msm_msi_snps_handler,
						msi_grp);
	}

	return 0;

free_irqs:
	for (--i; i >= 0; i--) {
		irq = msi->grps[i].irqs[0].hwirq;

		irq_set_chained_handler_and_data(irq, NULL, NULL);
		irq_dispose_mapping(irq);
	}

	return ret;
}

static int msm_msi_qgic_irq_setup(struct msm_msi *msi)
{
	int i, ret;
	u32 index, grp;
	struct msm_msi_grp *msi_grp;
	struct msm_msi_irq *msi_irq;
	unsigned int irq = 0;

	for (i = 0; i < msi->nr_hwirqs; i++) {
		irq = irq_of_parse_and_map(msi->of_node, i);
		if (!irq) {
			dev_err(msi->dev,
				"MSI: failed to parse/map interrupt\n");
			ret = -ENODEV;
			goto free_irqs;
		}

		grp = i / MSI_IRQ_PER_GRP;
		index = i % MSI_IRQ_PER_GRP;
		msi_grp = &msi->grps[grp];
		msi_irq = &msi_grp->irqs[index];

		msi_irq->grp = msi_grp;
		msi_irq->grp_index = index;
		msi_irq->pos = i;
		msi_irq->hwirq = irq;

		irq_set_chained_handler_and_data(irq, msm_msi_qgic_handler,
						msi);
	}

	return 0;

free_irqs:
	for (--i; i >= 0; i--) {
		grp = i / MSI_IRQ_PER_GRP;
		index = i % MSI_IRQ_PER_GRP;
		irq = msi->grps[grp].irqs[index].hwirq;

		irq_set_chained_handler_and_data(irq, NULL, NULL);
		irq_dispose_mapping(irq);
	}

	return ret;
}

/* control access to PCIe MSI registers */
void msm_msi_config_access(struct irq_domain *domain, bool allow)
{
@@ -524,14 +612,12 @@ EXPORT_SYMBOL(msm_msi_config);

int msm_msi_init(struct device *dev)
{
	int i, ret;
	int ret;
	struct msm_msi *msi;
	struct device_node *of_node;
	const __be32 *prop_val;
	struct resource *res;
	void (*msi_handler)(struct irq_desc *);
	u32 grp;
	u32 index;
	int (*msi_irq_setup)(struct msm_msi *);

	if (!dev->of_node) {
		dev_err(dev, "MSI: missing DT node\n");
@@ -599,17 +685,17 @@ int msm_msi_init(struct device *dev)
		if (!msi->pcie_cfg)
			return -ENOMEM;

		msi->nr_virqs = MSI_IRQ_NR_GRP * MSI_IRQ_PER_GRP;
		msi->nr_grps = MSI_IRQ_NR_GRP;
		msi->nr_virqs = msi->nr_hwirqs * MSI_IRQ_PER_GRP;
		msi->nr_grps = msi->nr_hwirqs;
		msi->mask_irq = msm_msi_snps_mask_irq;
		msi->unmask_irq = msm_msi_snps_unmask_irq;
		msi_handler = msm_msi_snps_handler;
		msi_irq_setup = msm_msi_snps_irq_setup;
	} else {
		msi->nr_virqs = msi->nr_hwirqs;
		msi->nr_grps = 1;
		msi->mask_irq = msm_msi_qgic_mask_irq;
		msi->unmask_irq = msm_msi_qgic_unmask_irq;
		msi_handler = msm_msi_qgic_handler;
		msi_irq_setup = msm_msi_qgic_irq_setup;
	}

	msi->grps = devm_kcalloc(msi->dev, msi->nr_grps,
@@ -628,78 +714,15 @@ int msm_msi_init(struct device *dev)
		return ret;
	}

	for (i = 0; i < msi->nr_hwirqs; i++) {
		unsigned int irq = irq_of_parse_and_map(msi->of_node, i);
		struct msm_msi_grp *msi_grp;
		struct msm_msi_irq *msi_irq;

		if (!irq) {
			dev_err(msi->dev,
				"MSI: failed to parse/map interrupt\n");
			ret = -ENODEV;
			goto free_irqs;
		}

		grp = i / MSI_IRQ_PER_GRP;
		index = i % MSI_IRQ_PER_GRP;
		msi_grp = &msi->grps[grp];
		msi_irq = &msi_grp->irqs[index];

		msi_irq->grp = msi_grp;
		msi_irq->grp_index = index;
		msi_irq->pos = i;
		msi_irq->hwirq = irq;

		irq_set_chained_handler_and_data(irq, msi_handler, msi);
	}

	if (msi->type == MSM_MSI_TYPE_SNPS) {
		struct msm_msi_grp *msi_grp;
		/* all SNPS VIRQs are mapped to one PCIe MSI HWIRQ */
		u32 snps_hwirq = msi->grps[0].irqs[0].hwirq;

		for (i = 0; i < msi->nr_grps; i++) {
			msi_grp = &msi->grps[i];

			msi_grp->int_en_reg = msi->pcie_cfg +
					PCIE_MSI_CTRL_INT_N_EN_OFFS(i);
			msi_grp->int_mask_reg = msi->pcie_cfg +
					PCIE_MSI_CTRL_INT_N_MASK_OFFS(i);
			msi_grp->int_status_reg = msi->pcie_cfg +
					PCIE_MSI_CTRL_INT_N_STATUS_OFFS(i);
		}

		for (i = 0; i < msi->nr_virqs; i++) {
			struct msm_msi_irq *msi_irq;

			grp = i / MSI_IRQ_PER_GRP;
			index = i % MSI_IRQ_PER_GRP;
			msi_grp = &msi->grps[grp];
			msi_irq = &msi_grp->irqs[index];

			msi_irq->grp = msi_grp;
			msi_irq->grp_index = index;
			msi_irq->pos = i;
			msi_irq->hwirq = snps_hwirq;
		}
	}
	ret = msi_irq_setup(msi);
	if (ret)
		goto remove_domains;

	msm_msi_config(msi->msi_domain);

	return 0;

free_irqs:
	for (--i; i >= 0; i--) {
		u32 hwirq;

		grp = i / MSI_IRQ_PER_GRP;
		index = i % MSI_IRQ_PER_GRP;
		hwirq = msi->grps[grp].irqs[index].hwirq;

		irq_set_chained_handler_and_data(hwirq, NULL, NULL);
		irq_dispose_mapping(hwirq);
	}

remove_domains:
	irq_domain_remove(msi->msi_domain);
	irq_domain_remove(msi->inner_domain);