diff --git a/Documentation/devicetree/bindings/pci/msm_pcie.txt b/Documentation/devicetree/bindings/pci/msm_pcie.txt index b9b8de467f65390f314671b33a4bb1b5070bd650..24a2be704775776934fa65187adf5e0cbecff27c 100644 --- a/Documentation/devicetree/bindings/pci/msm_pcie.txt +++ b/Documentation/devicetree/bindings/pci/msm_pcie.txt @@ -71,6 +71,10 @@ Optional Properties: - qcom,msm-bus,num-cases - qcom,msm-bus,num-paths - qcom,msm-bus,vectors-KBps + - qcom,scm-dev-id: If present then device id value is passed to secure channel + manager(scm) driver. scm driver uses this device id to restore PCIe + controller related security configuration after coming out of the controller + power collapse. Example: @@ -155,4 +159,6 @@ Example: qcom,msm-bus,vectors-KBps = <45 512 0 0>, <45 512 500 800>; + + qcom,scm-dev-id = <11>; }; diff --git a/drivers/pci/host/pci-msm.c b/drivers/pci/host/pci-msm.c index 0c2aea71e737f0c5668d9d3fa9e60fc23ce32ddb..fed8f207cc386770069189d6dad7e6b2a002be98 100644 --- a/drivers/pci/host/pci-msm.c +++ b/drivers/pci/host/pci-msm.c @@ -38,6 +38,7 @@ #include <linux/irqdomain.h> #include <linux/pm_wakeup.h> #include <linux/compiler.h> +#include <soc/qcom/scm.h> #include <linux/ipc_logging.h> #include <linux/msm_pcie.h> @@ -226,6 +227,7 @@ #define MAX_BUS_NUM 3 #define MAX_PROP_SIZE 32 #define MAX_RC_NAME_LEN 15 +#define PCIE_MSM_RESTORE_SCM_CFG_CMD 0x2 #define MSM_PCIE_MAX_VREG 3 #define MSM_PCIE_MAX_CLK 7 #define MSM_PCIE_MAX_PIPE_CLK 1 @@ -457,6 +459,7 @@ struct msm_pcie_dev_t { u32 rc_shadow[PCIE_CONF_SPACE_DW]; bool shadow_en; struct msm_pcie_register_event *event_reg; + unsigned int scm_dev_id; bool power_on; void *ipc_log; struct msm_pcie_device_info pcidev_table[MAX_DEVICE_NUM]; @@ -765,6 +768,36 @@ static bool pcie_phy_is_ready(struct msm_pcie_dev_t *dev) return true; } +static int msm_pcie_restore_sec_config(struct msm_pcie_dev_t *dev) +{ + /* scm command buffer structrue */ + struct msm_pcie_scm_cmd_buf { + unsigned int device_id; + unsigned int spare; + } cbuf; + + int ret, scm_ret = 0; + + if (!dev) { + pr_err("PCIe: the input pcie dev is NULL.\n"); + return -ENODEV; + } + + cbuf.device_id = dev->scm_dev_id; + + ret = scm_call(SCM_SVC_MP, PCIE_MSM_RESTORE_SCM_CFG_CMD, &cbuf, + sizeof(cbuf), &scm_ret, sizeof(scm_ret)); + + if (ret || scm_ret) { + PCIE_ERR(dev, + "PCIe: RC%d failed(%d) to restore sec config, scm_ret=%d\n", + dev->rc_idx, ret, scm_ret); + return ret ? ret : -EINVAL; + } + + return 0; +} + static bool msm_pcie_confirm_linkup(struct msm_pcie_dev_t *dev, bool check_sw_stts, bool check_ep) @@ -1927,6 +1960,11 @@ int msm_pcie_enable(struct msm_pcie_dev_t *dev, u32 options) goto clk_fail; } + if (dev->scm_dev_id) { + PCIE_DBG(dev, "RC%d: restoring sec config\n", dev->rc_idx); + msm_pcie_restore_sec_config(dev); + } + /* enable PCIe clocks and resets */ msm_pcie_write_mask(dev->parf + PCIE20_PARF_PHY_CTRL, BIT(0), 0); @@ -3008,6 +3046,11 @@ static int msm_pcie_probe(struct platform_device *pdev) } } + msm_pcie_dev[rc_idx].scm_dev_id = 0; + ret = of_property_read_u32((&pdev->dev)->of_node, + "qcom,scm-dev-id", + &msm_pcie_dev[rc_idx].scm_dev_id); + msm_pcie_dev[rc_idx].rc_idx = rc_idx; msm_pcie_dev[rc_idx].pdev = pdev; msm_pcie_dev[rc_idx].vreg_n = 0;