Lines Matching +full:sc8280xp +full:- +full:qmp +full:- +full:ufs +full:- +full:phy

1 // SPDX-License-Identifier: GPL-2.0
7 #include <linux/clk-provider.h>
17 #include <linux/phy/phy.h>
23 #include <dt-bindings/phy/phy.h>
25 #include "phy-qcom-qmp.h"
46 * if yes, then offset gives index in the reg-layout
78 /* set of registers with offsets different per-PHY */
534 /* struct qmp_phy_cfg - per-PHY initialization config */
538 /* Init sequence for PHY blocks - serdes, tx, rx, pcs */
568 * struct qmp_phy - per-lane phy descriptor
570 * @phy: generic phy
571 * @cfg: phy specific configuration
572 * @serdes: iomapped memory space for phy's serdes (i.e. PLL)
579 * @qmp: QMP phy to which this lane belongs
582 struct phy *phy; member
591 struct qcom_qmp *qmp; member
595 * struct qcom_qmp - structure holding QMP phy block attributes
599 * @clks: array of clocks required by phy
600 * @resets: array of resets required by phy
603 * @phys: array of per-lane phy descriptors
604 * @ufs_reset: optional UFS PHY reset handle
641 /* list of clocks required by phy */
646 /* the primary usb3 phy on sm8250 doesn't have a ref clock */
657 "vdda-phy", "vdda-pll",
811 if (!(t->lane_mask & lane_mask)) in qmp_ufs_configure_lane()
814 if (t->in_layout) in qmp_ufs_configure_lane()
815 writel(t->val, base + regs[t->offset]); in qmp_ufs_configure_lane()
817 writel(t->val, base + t->offset); in qmp_ufs_configure_lane()
831 const struct qmp_phy_cfg *cfg = qphy->cfg; in qmp_ufs_serdes_init()
832 void __iomem *serdes = qphy->serdes; in qmp_ufs_serdes_init()
833 const struct qmp_phy_init_tbl *serdes_tbl = cfg->serdes_tbl; in qmp_ufs_serdes_init()
834 int serdes_tbl_num = cfg->serdes_tbl_num; in qmp_ufs_serdes_init()
836 qmp_ufs_configure(serdes, cfg->regs, serdes_tbl, serdes_tbl_num); in qmp_ufs_serdes_init()
843 struct qcom_qmp *qmp = qphy->qmp; in qmp_ufs_com_init() local
844 const struct qmp_phy_cfg *cfg = qphy->cfg; in qmp_ufs_com_init()
845 void __iomem *pcs = qphy->pcs; in qmp_ufs_com_init()
849 ret = regulator_bulk_enable(cfg->num_vregs, qmp->vregs); in qmp_ufs_com_init()
851 dev_err(qmp->dev, "failed to enable regulators, err=%d\n", ret); in qmp_ufs_com_init()
855 ret = clk_bulk_prepare_enable(cfg->num_clks, qmp->clks); in qmp_ufs_com_init()
859 if (cfg->regs[QPHY_PCS_POWER_DOWN_CONTROL]) in qmp_ufs_com_init()
861 cfg->regs[QPHY_PCS_POWER_DOWN_CONTROL], in qmp_ufs_com_init()
862 cfg->pwrdn_ctrl); in qmp_ufs_com_init()
865 cfg->pwrdn_ctrl); in qmp_ufs_com_init()
870 regulator_bulk_disable(cfg->num_vregs, qmp->vregs); in qmp_ufs_com_init()
877 struct qcom_qmp *qmp = qphy->qmp; in qmp_ufs_com_exit() local
878 const struct qmp_phy_cfg *cfg = qphy->cfg; in qmp_ufs_com_exit()
880 reset_control_assert(qmp->ufs_reset); in qmp_ufs_com_exit()
882 clk_bulk_disable_unprepare(cfg->num_clks, qmp->clks); in qmp_ufs_com_exit()
884 regulator_bulk_disable(cfg->num_vregs, qmp->vregs); in qmp_ufs_com_exit()
889 static int qmp_ufs_init(struct phy *phy) in qmp_ufs_init() argument
891 struct qmp_phy *qphy = phy_get_drvdata(phy); in qmp_ufs_init()
892 struct qcom_qmp *qmp = qphy->qmp; in qmp_ufs_init() local
893 const struct qmp_phy_cfg *cfg = qphy->cfg; in qmp_ufs_init()
895 dev_vdbg(qmp->dev, "Initializing QMP phy\n"); in qmp_ufs_init()
897 if (cfg->no_pcs_sw_reset) { in qmp_ufs_init()
899 * Get UFS reset, which is delayed until now to avoid a in qmp_ufs_init()
900 * circular dependency where UFS needs its PHY, but the PHY in qmp_ufs_init()
901 * needs this UFS reset. in qmp_ufs_init()
903 if (!qmp->ufs_reset) { in qmp_ufs_init()
904 qmp->ufs_reset = in qmp_ufs_init()
905 devm_reset_control_get_exclusive(qmp->dev, in qmp_ufs_init()
908 if (IS_ERR(qmp->ufs_reset)) { in qmp_ufs_init()
909 ret = PTR_ERR(qmp->ufs_reset); in qmp_ufs_init()
910 dev_err(qmp->dev, in qmp_ufs_init()
911 "failed to get UFS reset: %d\n", in qmp_ufs_init()
914 qmp->ufs_reset = NULL; in qmp_ufs_init()
919 ret = reset_control_assert(qmp->ufs_reset); in qmp_ufs_init()
931 static int qmp_ufs_power_on(struct phy *phy) in qmp_ufs_power_on() argument
933 struct qmp_phy *qphy = phy_get_drvdata(phy); in qmp_ufs_power_on()
934 struct qcom_qmp *qmp = qphy->qmp; in qmp_ufs_power_on() local
935 const struct qmp_phy_cfg *cfg = qphy->cfg; in qmp_ufs_power_on()
936 void __iomem *tx = qphy->tx; in qmp_ufs_power_on()
937 void __iomem *rx = qphy->rx; in qmp_ufs_power_on()
938 void __iomem *pcs = qphy->pcs; in qmp_ufs_power_on()
946 qmp_ufs_configure_lane(tx, cfg->regs, cfg->tx_tbl, cfg->tx_tbl_num, 1); in qmp_ufs_power_on()
948 if (cfg->lanes >= 2) { in qmp_ufs_power_on()
949 qmp_ufs_configure_lane(qphy->tx2, cfg->regs, in qmp_ufs_power_on()
950 cfg->tx_tbl, cfg->tx_tbl_num, 2); in qmp_ufs_power_on()
953 qmp_ufs_configure_lane(rx, cfg->regs, cfg->rx_tbl, cfg->rx_tbl_num, 1); in qmp_ufs_power_on()
955 if (cfg->lanes >= 2) { in qmp_ufs_power_on()
956 qmp_ufs_configure_lane(qphy->rx2, cfg->regs, in qmp_ufs_power_on()
957 cfg->rx_tbl, cfg->rx_tbl_num, 2); in qmp_ufs_power_on()
960 qmp_ufs_configure(pcs, cfg->regs, cfg->pcs_tbl, cfg->pcs_tbl_num); in qmp_ufs_power_on()
962 ret = reset_control_deassert(qmp->ufs_reset); in qmp_ufs_power_on()
966 /* Pull PHY out of reset state */ in qmp_ufs_power_on()
967 if (!cfg->no_pcs_sw_reset) in qmp_ufs_power_on()
968 qphy_clrbits(pcs, cfg->regs[QPHY_SW_RESET], SW_RESET); in qmp_ufs_power_on()
969 /* start SerDes and Phy-Coding-Sublayer */ in qmp_ufs_power_on()
970 qphy_setbits(pcs, cfg->regs[QPHY_START_CTRL], cfg->start_ctrl); in qmp_ufs_power_on()
972 status = pcs + cfg->regs[QPHY_PCS_READY_STATUS]; in qmp_ufs_power_on()
979 dev_err(qmp->dev, "phy initialization timed-out\n"); in qmp_ufs_power_on()
986 static int qmp_ufs_power_off(struct phy *phy) in qmp_ufs_power_off() argument
988 struct qmp_phy *qphy = phy_get_drvdata(phy); in qmp_ufs_power_off()
989 const struct qmp_phy_cfg *cfg = qphy->cfg; in qmp_ufs_power_off()
991 /* PHY reset */ in qmp_ufs_power_off()
992 if (!cfg->no_pcs_sw_reset) in qmp_ufs_power_off()
993 qphy_setbits(qphy->pcs, cfg->regs[QPHY_SW_RESET], SW_RESET); in qmp_ufs_power_off()
995 /* stop SerDes and Phy-Coding-Sublayer */ in qmp_ufs_power_off()
996 qphy_clrbits(qphy->pcs, cfg->regs[QPHY_START_CTRL], cfg->start_ctrl); in qmp_ufs_power_off()
998 /* Put PHY into POWER DOWN state: active low */ in qmp_ufs_power_off()
999 if (cfg->regs[QPHY_PCS_POWER_DOWN_CONTROL]) { in qmp_ufs_power_off()
1000 qphy_clrbits(qphy->pcs, cfg->regs[QPHY_PCS_POWER_DOWN_CONTROL], in qmp_ufs_power_off()
1001 cfg->pwrdn_ctrl); in qmp_ufs_power_off()
1003 qphy_clrbits(qphy->pcs, QPHY_V2_PCS_POWER_DOWN_CONTROL, in qmp_ufs_power_off()
1004 cfg->pwrdn_ctrl); in qmp_ufs_power_off()
1010 static int qmp_ufs_exit(struct phy *phy) in qmp_ufs_exit() argument
1012 struct qmp_phy *qphy = phy_get_drvdata(phy); in qmp_ufs_exit()
1019 static int qmp_ufs_enable(struct phy *phy) in qmp_ufs_enable() argument
1023 ret = qmp_ufs_init(phy); in qmp_ufs_enable()
1027 ret = qmp_ufs_power_on(phy); in qmp_ufs_enable()
1029 qmp_ufs_exit(phy); in qmp_ufs_enable()
1034 static int qmp_ufs_disable(struct phy *phy) in qmp_ufs_disable() argument
1038 ret = qmp_ufs_power_off(phy); in qmp_ufs_disable()
1041 return qmp_ufs_exit(phy); in qmp_ufs_disable()
1046 struct qcom_qmp *qmp = dev_get_drvdata(dev); in qmp_ufs_vreg_init() local
1047 int num = cfg->num_vregs; in qmp_ufs_vreg_init()
1050 qmp->vregs = devm_kcalloc(dev, num, sizeof(*qmp->vregs), GFP_KERNEL); in qmp_ufs_vreg_init()
1051 if (!qmp->vregs) in qmp_ufs_vreg_init()
1052 return -ENOMEM; in qmp_ufs_vreg_init()
1055 qmp->vregs[i].supply = cfg->vreg_list[i]; in qmp_ufs_vreg_init()
1057 return devm_regulator_bulk_get(dev, num, qmp->vregs); in qmp_ufs_vreg_init()
1062 struct qcom_qmp *qmp = dev_get_drvdata(dev); in qmp_ufs_clk_init() local
1063 int num = cfg->num_clks; in qmp_ufs_clk_init()
1066 qmp->clks = devm_kcalloc(dev, num, sizeof(*qmp->clks), GFP_KERNEL); in qmp_ufs_clk_init()
1067 if (!qmp->clks) in qmp_ufs_clk_init()
1068 return -ENOMEM; in qmp_ufs_clk_init()
1071 qmp->clks[i].id = cfg->clk_list[i]; in qmp_ufs_clk_init()
1073 return devm_clk_bulk_get(dev, num, qmp->clks); in qmp_ufs_clk_init()
1085 struct qcom_qmp *qmp = dev_get_drvdata(dev); in qmp_ufs_create() local
1086 struct phy *generic_phy; in qmp_ufs_create()
1092 return -ENOMEM; in qmp_ufs_create()
1094 qphy->cfg = cfg; in qmp_ufs_create()
1095 qphy->serdes = serdes; in qmp_ufs_create()
1097 * Get memory resources for each phy lane: in qmp_ufs_create()
1098 * Resources are indexed as: tx -> 0; rx -> 1; pcs -> 2. in qmp_ufs_create()
1099 * For dual lane PHYs: tx2 -> 3, rx2 -> 4, pcs_misc (optional) -> 5 in qmp_ufs_create()
1100 * For single lane PHYs: pcs_misc (optional) -> 3. in qmp_ufs_create()
1102 qphy->tx = devm_of_iomap(dev, np, 0, NULL); in qmp_ufs_create()
1103 if (IS_ERR(qphy->tx)) in qmp_ufs_create()
1104 return PTR_ERR(qphy->tx); in qmp_ufs_create()
1106 qphy->rx = devm_of_iomap(dev, np, 1, NULL); in qmp_ufs_create()
1107 if (IS_ERR(qphy->rx)) in qmp_ufs_create()
1108 return PTR_ERR(qphy->rx); in qmp_ufs_create()
1110 qphy->pcs = devm_of_iomap(dev, np, 2, NULL); in qmp_ufs_create()
1111 if (IS_ERR(qphy->pcs)) in qmp_ufs_create()
1112 return PTR_ERR(qphy->pcs); in qmp_ufs_create()
1114 if (cfg->lanes >= 2) { in qmp_ufs_create()
1115 qphy->tx2 = devm_of_iomap(dev, np, 3, NULL); in qmp_ufs_create()
1116 if (IS_ERR(qphy->tx2)) in qmp_ufs_create()
1117 return PTR_ERR(qphy->tx2); in qmp_ufs_create()
1119 qphy->rx2 = devm_of_iomap(dev, np, 4, NULL); in qmp_ufs_create()
1120 if (IS_ERR(qphy->rx2)) in qmp_ufs_create()
1121 return PTR_ERR(qphy->rx2); in qmp_ufs_create()
1123 qphy->pcs_misc = devm_of_iomap(dev, np, 5, NULL); in qmp_ufs_create()
1125 qphy->pcs_misc = devm_of_iomap(dev, np, 3, NULL); in qmp_ufs_create()
1128 if (IS_ERR(qphy->pcs_misc)) in qmp_ufs_create()
1129 dev_vdbg(dev, "PHY pcs_misc-reg not used\n"); in qmp_ufs_create()
1138 qphy->phy = generic_phy; in qmp_ufs_create()
1139 qphy->qmp = qmp; in qmp_ufs_create()
1140 qmp->phys[id] = qphy; in qmp_ufs_create()
1148 .compatible = "qcom,msm8996-qmp-ufs-phy",
1151 .compatible = "qcom,msm8998-qmp-ufs-phy",
1154 .compatible = "qcom,sc8180x-qmp-ufs-phy",
1157 .compatible = "qcom,sc8280xp-qmp-ufs-phy",
1160 .compatible = "qcom,sdm845-qmp-ufs-phy",
1163 .compatible = "qcom,sm6115-qmp-ufs-phy",
1166 .compatible = "qcom,sm6350-qmp-ufs-phy",
1169 .compatible = "qcom,sm8150-qmp-ufs-phy",
1172 .compatible = "qcom,sm8250-qmp-ufs-phy",
1175 .compatible = "qcom,sm8350-qmp-ufs-phy",
1178 .compatible = "qcom,sm8450-qmp-ufs-phy",
1187 struct qcom_qmp *qmp; in qmp_ufs_probe() local
1188 struct device *dev = &pdev->dev; in qmp_ufs_probe()
1196 qmp = devm_kzalloc(dev, sizeof(*qmp), GFP_KERNEL); in qmp_ufs_probe()
1197 if (!qmp) in qmp_ufs_probe()
1198 return -ENOMEM; in qmp_ufs_probe()
1200 qmp->dev = dev; in qmp_ufs_probe()
1201 dev_set_drvdata(dev, qmp); in qmp_ufs_probe()
1203 /* Get the specific init parameters of QMP phy */ in qmp_ufs_probe()
1206 return -EINVAL; in qmp_ufs_probe()
1208 /* per PHY serdes; usually located at base address */ in qmp_ufs_probe()
1222 num = of_get_available_child_count(dev->of_node); in qmp_ufs_probe()
1225 return -EINVAL; in qmp_ufs_probe()
1227 qmp->phys = devm_kcalloc(dev, num, sizeof(*qmp->phys), GFP_KERNEL); in qmp_ufs_probe()
1228 if (!qmp->phys) in qmp_ufs_probe()
1229 return -ENOMEM; in qmp_ufs_probe()
1232 for_each_available_child_of_node(dev->of_node, child) { in qmp_ufs_probe()
1233 /* Create per-lane phy */ in qmp_ufs_probe()
1236 dev_err(dev, "failed to create lane%d phy, %d\n", in qmp_ufs_probe()
1256 .name = "qcom-qmp-ufs-phy",
1264 MODULE_DESCRIPTION("Qualcomm QMP UFS PHY driver");