From f4f03dca92b45616ef0325051fdc7627c16fdd62 Mon Sep 17 00:00:00 2001 From: Christian Marangi Date: Tue, 7 May 2024 20:21:17 +0200 Subject: [PATCH] PCI: qcom: add hack compatible for ipq4019 Lantiq DSL Add hack compatible for ipq4019 Lantiq DSL This change the PCIe vendor/device ID to the values from Lantiq GRX500 SoCs. We also program the ATU to fake the CPU ID as a Lantiq CPU by providing to the Lantiq firmware custom crafted value in the address the firmware would expect the CPU ID to be readable. Signed-off-by: Christian Marangi Signed-off-by: Florian Maurer --- drivers/pci/controller/dwc/pcie-qcom.c | 94 +++++++++++++++++++++++++- 1 file changed, 93 insertions(+), 1 deletion(-) --- a/drivers/pci/controller/dwc/pcie-qcom.c +++ b/drivers/pci/controller/dwc/pcie-qcom.c @@ -184,11 +184,24 @@ struct qcom_pcie_resources_2_3_3 { #define QCOM_PCIE_2_4_0_MAX_CLOCKS 4 #define QCOM_PCIE_2_4_0_MAX_RESETS 12 +/* + * This value is the manufacturer ID of Lantiq. The address where + * it will be visible for the PCIe device matches the location of + * CPU ID registers on Lantiq SocS (MPS base address is 0x1f107000). + */ +#define QCOM_PCIE_2_4_0_CPU_ID_BASE_REG 0x1f107000 +#define QCOM_PCIE_2_4_0_CPU_ID_REG 0x340 +#define QCOM_PCIE_2_4_0_CPU_ID_REG_OFFSET (QCOM_PCIE_2_4_0_CPU_ID_REG / sizeof(u32)) +#define QCOM_PCIE_2_4_0_CPU_ID_REG_VAL (0x389 << 5) +#define QCOM_PCIE_2_4_0_GRX500_VENDOR_ID 0x1bef +#define QCOM_PCIE_2_4_0_GRX500_DEVICE_ID 0x0030 struct qcom_pcie_resources_2_4_0 { struct clk_bulk_data clks[QCOM_PCIE_2_4_0_MAX_CLOCKS]; int num_clks; struct reset_control_bulk_data resets[QCOM_PCIE_2_4_0_MAX_RESETS]; int num_resets; + void *lantiq_hack_virt; + dma_addr_t lantiq_hack_phys; }; #define QCOM_PCIE_2_7_0_MAX_CLOCKS 15 @@ -629,12 +642,65 @@ static int qcom_pcie_post_init_2_3_2(str return 0; } +static void qcom_pcie_host_post_init_2_3_2_lantiq_hack(struct qcom_pcie *pcie) +{ + struct qcom_pcie_resources_2_4_0 *res = &pcie->res.v2_4_0; + struct dw_pcie *pci = pcie->pci; + struct dw_pcie_rp *pp = &pci->pp; + struct device *dev = pci->dev; + struct resource_entry *entry; + int ret, index = 0; + u64 addr, phys; + u32 *val; + + res->lantiq_hack_virt = dma_alloc_coherent(dev, SZ_4K, + &res->lantiq_hack_phys, + GFP_ATOMIC); + if (!res->lantiq_hack_virt) { + dev_err(dev, "failed to allocate DMA for lantiq hack\n"); + return; + } + + /* Fake Lantiq CPU ID register */ + val = (u32 *)res->lantiq_hack_virt; + val[QCOM_PCIE_2_4_0_CPU_ID_REG_OFFSET] = QCOM_PCIE_2_4_0_CPU_ID_REG_VAL; + + /* Increment index based on used iATU */ + resource_list_for_each_entry(entry, &pp->bridge->dma_ranges) + if (resource_type(entry->res) == IORESOURCE_MEM) + index++; + + /* Check if there is space for an additional iATU */ + if (index >= pci->num_ib_windows) { + dev_err(dev, "No inbound iATU window available for magic\n"); + return; + } + + addr = QCOM_PCIE_2_4_0_CPU_ID_BASE_REG; + phys = res->lantiq_hack_phys; + + /* Make it visible to PCIe devices using address translation unit */ + ret = dw_pcie_prog_inbound_atu(pci, index, PCIE_ATU_TYPE_MEM, + phys, addr, SZ_4K); + if (ret) { + dev_err(dev, "timeout waiting for IATU for lantiq hack: %d\n", ret); + return; + } + + /* Set vendor/device ID of GRX500 PCIe host */ + dw_pcie_dbi_ro_wr_en(pci); + dw_pcie_writew_dbi(pci, PCI_VENDOR_ID, QCOM_PCIE_2_4_0_GRX500_VENDOR_ID); + dw_pcie_writew_dbi(pci, PCI_DEVICE_ID, QCOM_PCIE_2_4_0_GRX500_DEVICE_ID); + dw_pcie_dbi_ro_wr_dis(pci); +} + static int qcom_pcie_get_resources_2_4_0(struct qcom_pcie *pcie) { struct qcom_pcie_resources_2_4_0 *res = &pcie->res.v2_4_0; struct dw_pcie *pci = pcie->pci; struct device *dev = pci->dev; - bool is_ipq = of_device_is_compatible(dev->of_node, "qcom,pcie-ipq4019"); + bool is_ipq = of_device_is_compatible(dev->of_node, "qcom,pcie-ipq4019") || + of_device_is_compatible(dev->of_node, "qcom,pcie-ipq4019-lantiq-hack"); int ret; res->clks[0].id = "aux"; @@ -679,6 +745,17 @@ static void qcom_pcie_deinit_2_4_0(struc clk_bulk_disable_unprepare(res->num_clks, res->clks); } +static void qcom_pcie_deinit_2_4_0_lantiq_hack(struct qcom_pcie *pcie) +{ + struct qcom_pcie_resources_2_4_0 *res = &pcie->res.v2_4_0; + struct dw_pcie *pci = pcie->pci; + struct device *dev = pci->dev; + + dma_free_coherent(dev, SZ_4K, res->lantiq_hack_virt, res->lantiq_hack_phys); + + qcom_pcie_deinit_2_4_0(pcie); +} + static int qcom_pcie_init_2_4_0(struct qcom_pcie *pcie) { struct qcom_pcie_resources_2_4_0 *res = &pcie->res.v2_4_0; @@ -1292,6 +1369,16 @@ static const struct qcom_pcie_ops ops_2_ .ltssm_enable = qcom_pcie_2_3_2_ltssm_enable, }; +/* Qcom IP rev.: 2.4.0 Synopsys IP rev.: 4.20a Lantiq DSL Hack */ +static const struct qcom_pcie_ops ops_2_4_0_lantiq_hack = { + .get_resources = qcom_pcie_get_resources_2_4_0, + .init = qcom_pcie_init_2_4_0, + .post_init = qcom_pcie_post_init_2_3_2, + .host_post_init = qcom_pcie_host_post_init_2_3_2_lantiq_hack, + .deinit = qcom_pcie_deinit_2_4_0_lantiq_hack, + .ltssm_enable = qcom_pcie_2_3_2_ltssm_enable, +}; + /* Qcom IP rev.: 2.3.3 Synopsys IP rev.: 4.30a */ static const struct qcom_pcie_ops ops_2_3_3 = { .get_resources = qcom_pcie_get_resources_2_3_3, @@ -1354,6 +1441,10 @@ static const struct qcom_pcie_cfg cfg_2_ .ops = &ops_2_4_0, }; +static const struct qcom_pcie_cfg cfg_2_4_0_lantiq_hack = { + .ops = &ops_2_4_0_lantiq_hack, +}; + static const struct qcom_pcie_cfg cfg_2_7_0 = { .ops = &ops_2_7_0, }; @@ -1641,6 +1732,7 @@ static const struct of_device_id qcom_pc { .compatible = "qcom,pcie-apq8064", .data = &cfg_2_1_0 }, { .compatible = "qcom,pcie-apq8084", .data = &cfg_1_0_0 }, { .compatible = "qcom,pcie-ipq4019", .data = &cfg_2_4_0 }, + { .compatible = "qcom,pcie-ipq4019-lantiq-hack", .data = &cfg_2_4_0_lantiq_hack }, { .compatible = "qcom,pcie-ipq6018", .data = &cfg_2_9_0 }, { .compatible = "qcom,pcie-ipq8064", .data = &cfg_2_1_0 }, { .compatible = "qcom,pcie-ipq8064-v2", .data = &cfg_2_1_0 },