Loading Documentation/devicetree/bindings/pci/msm_ep_pcie.txt +14 −0 Original line number Diff line number Diff line Loading @@ -40,6 +40,11 @@ Optional Properties: - max-clock-frequency-hz: list of the maximum operating frequencies stored in the same order of clock names; - qcom,pcie-phy-ver: version of PCIe PHY. - qcom,phy-init: The initialization sequence to bring up the PCIe PHY. Should be specified in groups (offset, value, delay, direction). - qcom,phy-status-reg: Register offset for PHY status. - qcom,dbi-base-reg: Register offset for DBI base address. - qcom,slv-space-reg: Register offset for slave address space size. - qcom,pcie-link-speed: generation of PCIe link speed. The value could be 1, 2 or 3. - qcom,pcie-active-config: boolean type; active configuration of PCIe Loading Loading @@ -110,4 +115,13 @@ Example: qcom,pcie-link-speed = <1>; qcom,pcie-active-config; qcom,pcie-aggregated-irq; qcom,phy-status-reg = <0x728>; qcom,dbi-base-reg = <0x168>; qcom,slv-space-reg = <0x16c>; qcom,phy-init = <0x604 0x03 0x0 0x1 0x048 0x08 0x0 0x1 0x64c 0x4d 0x0 0x1 0x600 0x00 0x0 0x1 0x608 0x03 0x0 0x1>; }; drivers/platform/msm/ep_pcie/ep_pcie_com.h +15 −1 Original line number Diff line number Diff line /* Copyright (c) 2015, The Linux Foundation. All rights reserved. /* Copyright (c) 2015-2016, 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 Loading @@ -21,6 +21,7 @@ #include <linux/regulator/consumer.h> #include <linux/types.h> #include <linux/uaccess.h> #include <linux/delay.h> #include <linux/msm_ep_pcie.h> #define PCIE20_PARF_SYS_CTRL 0x00 Loading Loading @@ -255,6 +256,14 @@ struct ep_pcie_irq_info_t { u32 num; }; /* phy info structure */ struct ep_pcie_phy_info_t { u32 offset; u32 val; u32 delay; u32 direction; }; /* pcie endpoint device structure */ struct ep_pcie_dev_t { struct platform_device *pdev; Loading @@ -278,6 +287,11 @@ struct ep_pcie_dev_t { u32 link_speed; bool active_config; bool aggregated_irq; u32 dbi_base_reg; u32 slv_space_reg; u32 phy_status_reg; u32 phy_init_len; struct ep_pcie_phy_info_t *phy_init; u32 rev; u32 phy_rev; Loading drivers/platform/msm/ep_pcie/ep_pcie_core.c +89 −11 Original line number Diff line number Diff line /* Copyright (c) 2015, The Linux Foundation. All rights reserved. /* Copyright (c) 2015-2016, 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 Loading Loading @@ -131,12 +131,19 @@ static int ep_pcie_gpio_init(struct ep_pcie_dev_t *dev) info = &dev->gpio[i]; if (!info->num) { if (i == EP_PCIE_GPIO_MDM2AP) { EP_PCIE_DBG(dev, "PCIe V%d: gpio %s does not exist.\n", dev->rev, info->name); continue; } else { EP_PCIE_ERR(dev, "PCIe V%d: the number of gpio %s is invalid\n", dev->rev, info->name); rc = -EINVAL; break; } } rc = gpio_request(info->num, info->name); if (rc) { Loading Loading @@ -463,9 +470,17 @@ static void ep_pcie_core_init(struct ep_pcie_dev_t *dev) ep_pcie_write_reg(dev->parf, PCIE20_PARF_DEVICE_TYPE, 0x0); /* adjust DBI base address */ writel_relaxed(0x3FFFE000, dev->parf + PCIE20_PARF_DBI_BASE_ADDR); if (dev->dbi_base_reg) writel_relaxed(0x3FFFE000, dev->parf + dev->dbi_base_reg); else writel_relaxed(0x3FFFE000, dev->parf + PCIE20_PARF_DBI_BASE_ADDR); /* Configure PCIe core to support 1GB aperture */ if (dev->slv_space_reg) ep_pcie_write_reg(dev->parf, dev->slv_space_reg, 0x40000000); else ep_pcie_write_reg(dev->parf, PCIE20_PARF_SLV_ADDR_SPACE_SIZE, 0x40000000); Loading Loading @@ -576,6 +591,7 @@ static void ep_pcie_core_init(struct ep_pcie_dev_t *dev) readl_relaxed(dev->parf + PCIE20_PARF_INT_ALL_MASK)); } if (dev->active_config) ep_pcie_write_reg(dev->dm_core, PCIE20_AUX_CLK_FREQ_REG, 0x14); } Loading Loading @@ -681,7 +697,7 @@ static void ep_pcie_notify_event(struct ep_pcie_dev_t *dev, static int ep_pcie_get_resources(struct ep_pcie_dev_t *dev, struct platform_device *pdev) { int i, len, cnt, ret = 0; int i, len, cnt, ret = 0, size = 0; struct ep_pcie_vreg_info_t *vreg_info; struct ep_pcie_gpio_info_t *gpio_info; struct ep_pcie_clk_info_t *clk_info; Loading @@ -694,6 +710,34 @@ static int ep_pcie_get_resources(struct ep_pcie_dev_t *dev, EP_PCIE_DBG(dev, "PCIe V%d\n", dev->rev); of_get_property(pdev->dev.of_node, "qcom,phy-init", &size); if (size) { dev->phy_init = (struct ep_pcie_phy_info_t *) devm_kzalloc(&pdev->dev, size, GFP_KERNEL); if (dev->phy_init) { dev->phy_init_len = size / sizeof(*dev->phy_init); EP_PCIE_DBG(dev, "PCIe V%d: phy init length is 0x%x.\n", dev->rev, dev->phy_init_len); of_property_read_u32_array(pdev->dev.of_node, "qcom,phy-init", (unsigned int *)dev->phy_init, size / sizeof(dev->phy_init->offset)); } else { EP_PCIE_ERR(dev, "PCIe V%d: Could not allocate memory for phy init sequence.\n", dev->rev); return -ENOMEM; } } else { EP_PCIE_DBG(dev, "PCIe V%d: PHY V%d: phy init sequence is not present in DT.\n", dev->rev, dev->phy_rev); } cnt = of_property_count_strings((&pdev->dev)->of_node, "clock-names"); if (cnt > 0) { Loading Loading @@ -782,6 +826,7 @@ static int ep_pcie_get_resources(struct ep_pcie_dev_t *dev, EP_PCIE_DBG(dev, "GPIO %s is not supported in this configuration.\n", gpio_info->name); ret = 0; } } Loading Loading @@ -1977,6 +2022,39 @@ static int ep_pcie_probe(struct platform_device *pdev) EP_PCIE_DBG(&ep_pcie_dev, "PCIe V%d: pcie-link-speed:%d.\n", ep_pcie_dev.rev, ep_pcie_dev.link_speed); ret = of_property_read_u32((&pdev->dev)->of_node, "qcom,dbi-base-reg", &ep_pcie_dev.dbi_base_reg); if (ret) EP_PCIE_DBG(&ep_pcie_dev, "PCIe V%d: dbi-base-reg does not exist.\n", ep_pcie_dev.rev); else EP_PCIE_DBG(&ep_pcie_dev, "PCIe V%d: dbi-base-reg:0x%x.\n", ep_pcie_dev.rev, ep_pcie_dev.dbi_base_reg); ret = of_property_read_u32((&pdev->dev)->of_node, "qcom,slv-space-reg", &ep_pcie_dev.slv_space_reg); if (ret) EP_PCIE_DBG(&ep_pcie_dev, "PCIe V%d: slv-space-reg does not exist.\n", ep_pcie_dev.rev); else EP_PCIE_DBG(&ep_pcie_dev, "PCIe V%d: slv-space-reg:0x%x.\n", ep_pcie_dev.rev, ep_pcie_dev.slv_space_reg); ret = of_property_read_u32((&pdev->dev)->of_node, "qcom,phy-status-reg", &ep_pcie_dev.phy_status_reg); if (ret) EP_PCIE_DBG(&ep_pcie_dev, "PCIe V%d: phy-status-reg does not exist.\n", ep_pcie_dev.rev); else EP_PCIE_DBG(&ep_pcie_dev, "PCIe V%d: phy-status-reg:0x%x.\n", ep_pcie_dev.rev, ep_pcie_dev.phy_status_reg); ep_pcie_dev.phy_rev = 1; ret = of_property_read_u32((&pdev->dev)->of_node, "qcom,pcie-phy-ver", Loading @@ -2002,7 +2080,7 @@ static int ep_pcie_probe(struct platform_device *pdev) "PCIe V%d: aggregated IRQ is %s enabled.\n", ep_pcie_dev.rev, ep_pcie_dev.aggregated_irq ? "" : "not"); ep_pcie_dev.rev = 1511053; ep_pcie_dev.rev = 1610071; ep_pcie_dev.pdev = pdev; memcpy(ep_pcie_dev.vreg, ep_pcie_vreg_info, sizeof(ep_pcie_vreg_info)); Loading drivers/platform/msm/ep_pcie/ep_pcie_dbg.c +1 −1 Original line number Diff line number Diff line Loading @@ -232,7 +232,7 @@ void ep_pcie_reg_dump(struct ep_pcie_dev_t *dev, u32 sel, bool linkdown) if (!(sel & BIT(r))) continue; if (r == EP_PCIE_RES_PHY) if ((r == EP_PCIE_RES_PHY) && (dev->phy_rev > 3)) ep_pcie_phy_dump(dev); size = resource_size(dev->res[r].resource); Loading drivers/platform/msm/ep_pcie/ep_pcie_phy.c +52 −5 Original line number Diff line number Diff line /* Copyright (c) 2015, The Linux Foundation. All rights reserved. /* Copyright (c) 2015-2016, 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 Loading @@ -19,9 +19,49 @@ void ep_pcie_phy_init(struct ep_pcie_dev_t *dev) { switch (dev->phy_rev) { case 3: EP_PCIE_DBG(dev, "PCIe V%d: PHY V%d: Initializing 20nm QMP phy - 100MHz\n", dev->rev, dev->phy_rev); break; case 4: EP_PCIE_DBG(dev, "PCIe V%d: PHY V%d: Initializing 14nm QMP phy - 100MHz\n", dev->rev, dev->phy_rev); break; case 5: EP_PCIE_DBG(dev, "PCIe V%d: PHY V%d: Initializing 10nm QMP phy - 100MHz\n", dev->rev, dev->phy_rev); break; default: EP_PCIE_ERR(dev, "PCIe V%d: Unexpected phy version %d is caught!\n", dev->rev, dev->phy_rev); } if (dev->phy_init_len && dev->phy_init) { int i; struct ep_pcie_phy_info_t *phy_init; EP_PCIE_DBG(dev, "PCIe V%d: PHY V%d: process the sequence specified by DT.\n", dev->rev, dev->phy_rev); i = dev->phy_init_len; phy_init = dev->phy_init; while (i--) { ep_pcie_write_reg(dev->phy, phy_init->offset, phy_init->val); if (phy_init->delay) usleep_range(phy_init->delay, phy_init->delay + 1); phy_init++; } return; } ep_pcie_write_reg(dev->phy, PCIE_PHY_SW_RESET, 0x01); ep_pcie_write_reg(dev->phy, PCIE_PHY_POWER_DOWN_CONTROL, 0x01); Loading Loading @@ -106,7 +146,14 @@ void ep_pcie_phy_init(struct ep_pcie_dev_t *dev) bool ep_pcie_phy_is_ready(struct ep_pcie_dev_t *dev) { if (readl_relaxed(dev->phy + PCIE_PHY_PCS_STATUS) & BIT(6)) u32 offset; if (dev->phy_status_reg) offset = dev->phy_status_reg; else offset = PCIE_PHY_PCS_STATUS; if (readl_relaxed(dev->phy + offset) & BIT(6)) return false; else return true; Loading Loading
Documentation/devicetree/bindings/pci/msm_ep_pcie.txt +14 −0 Original line number Diff line number Diff line Loading @@ -40,6 +40,11 @@ Optional Properties: - max-clock-frequency-hz: list of the maximum operating frequencies stored in the same order of clock names; - qcom,pcie-phy-ver: version of PCIe PHY. - qcom,phy-init: The initialization sequence to bring up the PCIe PHY. Should be specified in groups (offset, value, delay, direction). - qcom,phy-status-reg: Register offset for PHY status. - qcom,dbi-base-reg: Register offset for DBI base address. - qcom,slv-space-reg: Register offset for slave address space size. - qcom,pcie-link-speed: generation of PCIe link speed. The value could be 1, 2 or 3. - qcom,pcie-active-config: boolean type; active configuration of PCIe Loading Loading @@ -110,4 +115,13 @@ Example: qcom,pcie-link-speed = <1>; qcom,pcie-active-config; qcom,pcie-aggregated-irq; qcom,phy-status-reg = <0x728>; qcom,dbi-base-reg = <0x168>; qcom,slv-space-reg = <0x16c>; qcom,phy-init = <0x604 0x03 0x0 0x1 0x048 0x08 0x0 0x1 0x64c 0x4d 0x0 0x1 0x600 0x00 0x0 0x1 0x608 0x03 0x0 0x1>; };
drivers/platform/msm/ep_pcie/ep_pcie_com.h +15 −1 Original line number Diff line number Diff line /* Copyright (c) 2015, The Linux Foundation. All rights reserved. /* Copyright (c) 2015-2016, 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 Loading @@ -21,6 +21,7 @@ #include <linux/regulator/consumer.h> #include <linux/types.h> #include <linux/uaccess.h> #include <linux/delay.h> #include <linux/msm_ep_pcie.h> #define PCIE20_PARF_SYS_CTRL 0x00 Loading Loading @@ -255,6 +256,14 @@ struct ep_pcie_irq_info_t { u32 num; }; /* phy info structure */ struct ep_pcie_phy_info_t { u32 offset; u32 val; u32 delay; u32 direction; }; /* pcie endpoint device structure */ struct ep_pcie_dev_t { struct platform_device *pdev; Loading @@ -278,6 +287,11 @@ struct ep_pcie_dev_t { u32 link_speed; bool active_config; bool aggregated_irq; u32 dbi_base_reg; u32 slv_space_reg; u32 phy_status_reg; u32 phy_init_len; struct ep_pcie_phy_info_t *phy_init; u32 rev; u32 phy_rev; Loading
drivers/platform/msm/ep_pcie/ep_pcie_core.c +89 −11 Original line number Diff line number Diff line /* Copyright (c) 2015, The Linux Foundation. All rights reserved. /* Copyright (c) 2015-2016, 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 Loading Loading @@ -131,12 +131,19 @@ static int ep_pcie_gpio_init(struct ep_pcie_dev_t *dev) info = &dev->gpio[i]; if (!info->num) { if (i == EP_PCIE_GPIO_MDM2AP) { EP_PCIE_DBG(dev, "PCIe V%d: gpio %s does not exist.\n", dev->rev, info->name); continue; } else { EP_PCIE_ERR(dev, "PCIe V%d: the number of gpio %s is invalid\n", dev->rev, info->name); rc = -EINVAL; break; } } rc = gpio_request(info->num, info->name); if (rc) { Loading Loading @@ -463,9 +470,17 @@ static void ep_pcie_core_init(struct ep_pcie_dev_t *dev) ep_pcie_write_reg(dev->parf, PCIE20_PARF_DEVICE_TYPE, 0x0); /* adjust DBI base address */ writel_relaxed(0x3FFFE000, dev->parf + PCIE20_PARF_DBI_BASE_ADDR); if (dev->dbi_base_reg) writel_relaxed(0x3FFFE000, dev->parf + dev->dbi_base_reg); else writel_relaxed(0x3FFFE000, dev->parf + PCIE20_PARF_DBI_BASE_ADDR); /* Configure PCIe core to support 1GB aperture */ if (dev->slv_space_reg) ep_pcie_write_reg(dev->parf, dev->slv_space_reg, 0x40000000); else ep_pcie_write_reg(dev->parf, PCIE20_PARF_SLV_ADDR_SPACE_SIZE, 0x40000000); Loading Loading @@ -576,6 +591,7 @@ static void ep_pcie_core_init(struct ep_pcie_dev_t *dev) readl_relaxed(dev->parf + PCIE20_PARF_INT_ALL_MASK)); } if (dev->active_config) ep_pcie_write_reg(dev->dm_core, PCIE20_AUX_CLK_FREQ_REG, 0x14); } Loading Loading @@ -681,7 +697,7 @@ static void ep_pcie_notify_event(struct ep_pcie_dev_t *dev, static int ep_pcie_get_resources(struct ep_pcie_dev_t *dev, struct platform_device *pdev) { int i, len, cnt, ret = 0; int i, len, cnt, ret = 0, size = 0; struct ep_pcie_vreg_info_t *vreg_info; struct ep_pcie_gpio_info_t *gpio_info; struct ep_pcie_clk_info_t *clk_info; Loading @@ -694,6 +710,34 @@ static int ep_pcie_get_resources(struct ep_pcie_dev_t *dev, EP_PCIE_DBG(dev, "PCIe V%d\n", dev->rev); of_get_property(pdev->dev.of_node, "qcom,phy-init", &size); if (size) { dev->phy_init = (struct ep_pcie_phy_info_t *) devm_kzalloc(&pdev->dev, size, GFP_KERNEL); if (dev->phy_init) { dev->phy_init_len = size / sizeof(*dev->phy_init); EP_PCIE_DBG(dev, "PCIe V%d: phy init length is 0x%x.\n", dev->rev, dev->phy_init_len); of_property_read_u32_array(pdev->dev.of_node, "qcom,phy-init", (unsigned int *)dev->phy_init, size / sizeof(dev->phy_init->offset)); } else { EP_PCIE_ERR(dev, "PCIe V%d: Could not allocate memory for phy init sequence.\n", dev->rev); return -ENOMEM; } } else { EP_PCIE_DBG(dev, "PCIe V%d: PHY V%d: phy init sequence is not present in DT.\n", dev->rev, dev->phy_rev); } cnt = of_property_count_strings((&pdev->dev)->of_node, "clock-names"); if (cnt > 0) { Loading Loading @@ -782,6 +826,7 @@ static int ep_pcie_get_resources(struct ep_pcie_dev_t *dev, EP_PCIE_DBG(dev, "GPIO %s is not supported in this configuration.\n", gpio_info->name); ret = 0; } } Loading Loading @@ -1977,6 +2022,39 @@ static int ep_pcie_probe(struct platform_device *pdev) EP_PCIE_DBG(&ep_pcie_dev, "PCIe V%d: pcie-link-speed:%d.\n", ep_pcie_dev.rev, ep_pcie_dev.link_speed); ret = of_property_read_u32((&pdev->dev)->of_node, "qcom,dbi-base-reg", &ep_pcie_dev.dbi_base_reg); if (ret) EP_PCIE_DBG(&ep_pcie_dev, "PCIe V%d: dbi-base-reg does not exist.\n", ep_pcie_dev.rev); else EP_PCIE_DBG(&ep_pcie_dev, "PCIe V%d: dbi-base-reg:0x%x.\n", ep_pcie_dev.rev, ep_pcie_dev.dbi_base_reg); ret = of_property_read_u32((&pdev->dev)->of_node, "qcom,slv-space-reg", &ep_pcie_dev.slv_space_reg); if (ret) EP_PCIE_DBG(&ep_pcie_dev, "PCIe V%d: slv-space-reg does not exist.\n", ep_pcie_dev.rev); else EP_PCIE_DBG(&ep_pcie_dev, "PCIe V%d: slv-space-reg:0x%x.\n", ep_pcie_dev.rev, ep_pcie_dev.slv_space_reg); ret = of_property_read_u32((&pdev->dev)->of_node, "qcom,phy-status-reg", &ep_pcie_dev.phy_status_reg); if (ret) EP_PCIE_DBG(&ep_pcie_dev, "PCIe V%d: phy-status-reg does not exist.\n", ep_pcie_dev.rev); else EP_PCIE_DBG(&ep_pcie_dev, "PCIe V%d: phy-status-reg:0x%x.\n", ep_pcie_dev.rev, ep_pcie_dev.phy_status_reg); ep_pcie_dev.phy_rev = 1; ret = of_property_read_u32((&pdev->dev)->of_node, "qcom,pcie-phy-ver", Loading @@ -2002,7 +2080,7 @@ static int ep_pcie_probe(struct platform_device *pdev) "PCIe V%d: aggregated IRQ is %s enabled.\n", ep_pcie_dev.rev, ep_pcie_dev.aggregated_irq ? "" : "not"); ep_pcie_dev.rev = 1511053; ep_pcie_dev.rev = 1610071; ep_pcie_dev.pdev = pdev; memcpy(ep_pcie_dev.vreg, ep_pcie_vreg_info, sizeof(ep_pcie_vreg_info)); Loading
drivers/platform/msm/ep_pcie/ep_pcie_dbg.c +1 −1 Original line number Diff line number Diff line Loading @@ -232,7 +232,7 @@ void ep_pcie_reg_dump(struct ep_pcie_dev_t *dev, u32 sel, bool linkdown) if (!(sel & BIT(r))) continue; if (r == EP_PCIE_RES_PHY) if ((r == EP_PCIE_RES_PHY) && (dev->phy_rev > 3)) ep_pcie_phy_dump(dev); size = resource_size(dev->res[r].resource); Loading
drivers/platform/msm/ep_pcie/ep_pcie_phy.c +52 −5 Original line number Diff line number Diff line /* Copyright (c) 2015, The Linux Foundation. All rights reserved. /* Copyright (c) 2015-2016, 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 Loading @@ -19,9 +19,49 @@ void ep_pcie_phy_init(struct ep_pcie_dev_t *dev) { switch (dev->phy_rev) { case 3: EP_PCIE_DBG(dev, "PCIe V%d: PHY V%d: Initializing 20nm QMP phy - 100MHz\n", dev->rev, dev->phy_rev); break; case 4: EP_PCIE_DBG(dev, "PCIe V%d: PHY V%d: Initializing 14nm QMP phy - 100MHz\n", dev->rev, dev->phy_rev); break; case 5: EP_PCIE_DBG(dev, "PCIe V%d: PHY V%d: Initializing 10nm QMP phy - 100MHz\n", dev->rev, dev->phy_rev); break; default: EP_PCIE_ERR(dev, "PCIe V%d: Unexpected phy version %d is caught!\n", dev->rev, dev->phy_rev); } if (dev->phy_init_len && dev->phy_init) { int i; struct ep_pcie_phy_info_t *phy_init; EP_PCIE_DBG(dev, "PCIe V%d: PHY V%d: process the sequence specified by DT.\n", dev->rev, dev->phy_rev); i = dev->phy_init_len; phy_init = dev->phy_init; while (i--) { ep_pcie_write_reg(dev->phy, phy_init->offset, phy_init->val); if (phy_init->delay) usleep_range(phy_init->delay, phy_init->delay + 1); phy_init++; } return; } ep_pcie_write_reg(dev->phy, PCIE_PHY_SW_RESET, 0x01); ep_pcie_write_reg(dev->phy, PCIE_PHY_POWER_DOWN_CONTROL, 0x01); Loading Loading @@ -106,7 +146,14 @@ void ep_pcie_phy_init(struct ep_pcie_dev_t *dev) bool ep_pcie_phy_is_ready(struct ep_pcie_dev_t *dev) { if (readl_relaxed(dev->phy + PCIE_PHY_PCS_STATUS) & BIT(6)) u32 offset; if (dev->phy_status_reg) offset = dev->phy_status_reg; else offset = PCIE_PHY_PCS_STATUS; if (readl_relaxed(dev->phy + offset) & BIT(6)) return false; else return true; Loading