*/
 
 #include <linux/clk.h>
+#include <linux/crc8.h>
 #include <linux/delay.h>
 #include <linux/gpio/consumer.h>
 #include <linux/interrupt.h>
 #define PCIE20_PARF_SID_OFFSET                 0x234
 #define PCIE20_PARF_BDF_TRANSLATE_CFG          0x24C
 #define PCIE20_PARF_DEVICE_TYPE                        0x1000
+#define PCIE20_PARF_BDF_TO_SID_TABLE_N         0x2000
 
 #define PCIE20_ELBI_SYS_CTRL                   0x04
 #define PCIE20_ELBI_SYS_CTRL_LT_ENABLE         BIT(0)
 
 #define QCOM_PCIE_2_1_0_MAX_SUPPLY     3
 #define QCOM_PCIE_2_1_0_MAX_CLOCKS     5
+
+#define QCOM_PCIE_CRC8_POLYNOMIAL (BIT(2) | BIT(1) | BIT(0))
+
 struct qcom_pcie_resources_2_1_0 {
        struct clk_bulk_data clks[QCOM_PCIE_2_1_0_MAX_CLOCKS];
        struct reset_control *pci_reset;
        void (*deinit)(struct qcom_pcie *pcie);
        void (*post_deinit)(struct qcom_pcie *pcie);
        void (*ltssm_enable)(struct qcom_pcie *pcie);
+       int (*config_sid)(struct qcom_pcie *pcie);
 };
 
 struct qcom_pcie {
        return !!(val & PCI_EXP_LNKSTA_DLLLA);
 }
 
+static int qcom_pcie_config_sid_sm8250(struct qcom_pcie *pcie)
+{
+       /* iommu map structure */
+       struct {
+               u32 bdf;
+               u32 phandle;
+               u32 smmu_sid;
+               u32 smmu_sid_len;
+       } *map;
+       void __iomem *bdf_to_sid_base = pcie->parf + PCIE20_PARF_BDF_TO_SID_TABLE_N;
+       struct device *dev = pcie->pci->dev;
+       u8 qcom_pcie_crc8_table[CRC8_TABLE_SIZE];
+       int i, nr_map, size = 0;
+       u32 smmu_sid_base;
+
+       of_get_property(dev->of_node, "iommu-map", &size);
+       if (!size)
+               return 0;
+
+       map = kzalloc(size, GFP_KERNEL);
+       if (!map)
+               return -ENOMEM;
+
+       of_property_read_u32_array(dev->of_node,
+               "iommu-map", (u32 *)map, size / sizeof(u32));
+
+       nr_map = size / (sizeof(*map));
+
+       crc8_populate_msb(qcom_pcie_crc8_table, QCOM_PCIE_CRC8_POLYNOMIAL);
+
+       /* Registers need to be zero out first */
+       memset_io(bdf_to_sid_base, 0, CRC8_TABLE_SIZE * sizeof(u32));
+
+       /* Extract the SMMU SID base from the first entry of iommu-map */
+       smmu_sid_base = map[0].smmu_sid;
+
+       /* Look for an available entry to hold the mapping */
+       for (i = 0; i < nr_map; i++) {
+               u16 bdf_be = cpu_to_be16(map[i].bdf);
+               u32 val;
+               u8 hash;
+
+               hash = crc8(qcom_pcie_crc8_table, (u8 *)&bdf_be, sizeof(bdf_be),
+                       0);
+
+               val = readl(bdf_to_sid_base + hash * sizeof(u32));
+
+               /* If the register is already populated, look for next available entry */
+               while (val) {
+                       u8 current_hash = hash++;
+                       u8 next_mask = 0xff;
+
+                       /* If NEXT field is NULL then update it with next hash */
+                       if (!(val & next_mask)) {
+                               val |= (u32)hash;
+                               writel(val, bdf_to_sid_base + current_hash * sizeof(u32));
+                       }
+
+                       val = readl(bdf_to_sid_base + hash * sizeof(u32));
+               }
+
+               /* BDF [31:16] | SID [15:8] | NEXT [7:0] */
+               val = map[i].bdf << 16 | (map[i].smmu_sid - smmu_sid_base) << 8 | 0;
+               writel(val, bdf_to_sid_base + hash * sizeof(u32));
+       }
+
+       kfree(map);
+
+       return 0;
+}
+
 static int qcom_pcie_host_init(struct pcie_port *pp)
 {
        struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
 
        qcom_ep_reset_deassert(pcie);
 
+       if (pcie->ops->config_sid) {
+               ret = pcie->ops->config_sid(pcie);
+               if (ret)
+                       goto err;
+       }
+
        return 0;
 
+err:
+       qcom_ep_reset_assert(pcie);
+       if (pcie->ops->post_deinit)
+               pcie->ops->post_deinit(pcie);
 err_disable_phy:
        phy_power_off(pcie->phy);
 err_deinit:
        .ltssm_enable = qcom_pcie_2_3_2_ltssm_enable,
        .post_init = qcom_pcie_post_init_2_7_0,
        .post_deinit = qcom_pcie_post_deinit_2_7_0,
+       .config_sid = qcom_pcie_config_sid_sm8250,
 };
 
 static const struct dw_pcie_ops dw_pcie_ops = {