mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-15 16:24:13 +08:00
phy: qcom-qmp-ufs: add support for updated sc8280xp binding
Add support for the new SC8280XP binding. Note that the binding does not try to describe every register subregion and instead the driver holds the corresponding offsets. Also note that the driver will continue to accept the old binding, at least for the time being. Signed-off-by: Johan Hovold <johan+linaro@kernel.org> Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org> Link: https://lore.kernel.org/r/20221024090041.19574-11-johan+linaro@kernel.org Signed-off-by: Vinod Koul <vkoul@kernel.org>
This commit is contained in:
parent
c64d39b403
commit
0e089bb8b3
@ -520,10 +520,21 @@ static const struct qmp_phy_init_tbl sm8350_ufsphy_pcs_tbl[] = {
|
||||
QMP_PHY_INIT_CFG(QPHY_V5_PCS_UFS_MULTI_LANE_CTRL1, 0x02),
|
||||
};
|
||||
|
||||
struct qmp_ufs_offsets {
|
||||
u16 serdes;
|
||||
u16 pcs;
|
||||
u16 tx;
|
||||
u16 rx;
|
||||
u16 tx2;
|
||||
u16 rx2;
|
||||
};
|
||||
|
||||
/* struct qmp_phy_cfg - per-PHY initialization config */
|
||||
struct qmp_phy_cfg {
|
||||
int lanes;
|
||||
|
||||
const struct qmp_ufs_offsets *offsets;
|
||||
|
||||
/* Init sequence for PHY blocks - serdes, tx, rx, pcs */
|
||||
const struct qmp_phy_init_tbl *serdes_tbl;
|
||||
int serdes_tbl_num;
|
||||
@ -611,6 +622,15 @@ static const char * const qmp_phy_vreg_l[] = {
|
||||
"vdda-phy", "vdda-pll",
|
||||
};
|
||||
|
||||
static const struct qmp_ufs_offsets qmp_ufs_offsets_v5 = {
|
||||
.serdes = 0,
|
||||
.pcs = 0xc00,
|
||||
.tx = 0x400,
|
||||
.rx = 0x600,
|
||||
.tx2 = 0x800,
|
||||
.rx2 = 0xa00,
|
||||
};
|
||||
|
||||
static const struct qmp_phy_cfg msm8996_ufs_cfg = {
|
||||
.lanes = 1,
|
||||
|
||||
@ -632,6 +652,26 @@ static const struct qmp_phy_cfg msm8996_ufs_cfg = {
|
||||
.no_pcs_sw_reset = true,
|
||||
};
|
||||
|
||||
static const struct qmp_phy_cfg sc8280xp_ufsphy_cfg = {
|
||||
.lanes = 2,
|
||||
|
||||
.offsets = &qmp_ufs_offsets_v5,
|
||||
|
||||
.serdes_tbl = sm8350_ufsphy_serdes_tbl,
|
||||
.serdes_tbl_num = ARRAY_SIZE(sm8350_ufsphy_serdes_tbl),
|
||||
.tx_tbl = sm8350_ufsphy_tx_tbl,
|
||||
.tx_tbl_num = ARRAY_SIZE(sm8350_ufsphy_tx_tbl),
|
||||
.rx_tbl = sm8350_ufsphy_rx_tbl,
|
||||
.rx_tbl_num = ARRAY_SIZE(sm8350_ufsphy_rx_tbl),
|
||||
.pcs_tbl = sm8350_ufsphy_pcs_tbl,
|
||||
.pcs_tbl_num = ARRAY_SIZE(sm8350_ufsphy_pcs_tbl),
|
||||
.clk_list = sdm845_ufs_phy_clk_l,
|
||||
.num_clks = ARRAY_SIZE(sdm845_ufs_phy_clk_l),
|
||||
.vreg_list = qmp_phy_vreg_l,
|
||||
.num_vregs = ARRAY_SIZE(qmp_phy_vreg_l),
|
||||
.regs = sm8150_ufsphy_regs_layout,
|
||||
};
|
||||
|
||||
static const struct qmp_phy_cfg sdm845_ufsphy_cfg = {
|
||||
.lanes = 2,
|
||||
|
||||
@ -1031,11 +1071,38 @@ static int qmp_ufs_parse_dt_legacy(struct qmp_ufs *qmp, struct device_node *np)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int qmp_ufs_parse_dt(struct qmp_ufs *qmp)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(qmp->dev);
|
||||
const struct qmp_phy_cfg *cfg = qmp->cfg;
|
||||
const struct qmp_ufs_offsets *offs = cfg->offsets;
|
||||
void __iomem *base;
|
||||
|
||||
if (!offs)
|
||||
return -EINVAL;
|
||||
|
||||
base = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(base))
|
||||
return PTR_ERR(base);
|
||||
|
||||
qmp->serdes = base + offs->serdes;
|
||||
qmp->pcs = base + offs->pcs;
|
||||
qmp->tx = base + offs->tx;
|
||||
qmp->rx = base + offs->rx;
|
||||
|
||||
if (cfg->lanes >= 2) {
|
||||
qmp->tx2 = base + offs->tx2;
|
||||
qmp->rx2 = base + offs->rx2;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int qmp_ufs_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct device_node *child;
|
||||
struct phy_provider *phy_provider;
|
||||
struct device_node *np;
|
||||
struct qmp_ufs *qmp;
|
||||
int ret;
|
||||
|
||||
@ -1057,15 +1124,18 @@ static int qmp_ufs_probe(struct platform_device *pdev)
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
child = of_get_next_available_child(dev->of_node, NULL);
|
||||
if (!child)
|
||||
return -EINVAL;
|
||||
|
||||
ret = qmp_ufs_parse_dt_legacy(qmp, child);
|
||||
/* Check for legacy binding with child node. */
|
||||
np = of_get_next_available_child(dev->of_node, NULL);
|
||||
if (np) {
|
||||
ret = qmp_ufs_parse_dt_legacy(qmp, np);
|
||||
} else {
|
||||
np = of_node_get(dev->of_node);
|
||||
ret = qmp_ufs_parse_dt(qmp);
|
||||
}
|
||||
if (ret)
|
||||
goto err_node_put;
|
||||
|
||||
qmp->phy = devm_phy_create(dev, child, &qcom_qmp_ufs_phy_ops);
|
||||
qmp->phy = devm_phy_create(dev, np, &qcom_qmp_ufs_phy_ops);
|
||||
if (IS_ERR(qmp->phy)) {
|
||||
ret = PTR_ERR(qmp->phy);
|
||||
dev_err(dev, "failed to create PHY: %d\n", ret);
|
||||
@ -1074,14 +1144,14 @@ static int qmp_ufs_probe(struct platform_device *pdev)
|
||||
|
||||
phy_set_drvdata(qmp->phy, qmp);
|
||||
|
||||
of_node_put(child);
|
||||
of_node_put(np);
|
||||
|
||||
phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
|
||||
|
||||
return PTR_ERR_OR_ZERO(phy_provider);
|
||||
|
||||
err_node_put:
|
||||
of_node_put(child);
|
||||
of_node_put(np);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -1097,7 +1167,7 @@ static const struct of_device_id qmp_ufs_of_match_table[] = {
|
||||
.data = &sm8150_ufsphy_cfg,
|
||||
}, {
|
||||
.compatible = "qcom,sc8280xp-qmp-ufs-phy",
|
||||
.data = &sm8350_ufsphy_cfg,
|
||||
.data = &sc8280xp_ufsphy_cfg,
|
||||
}, {
|
||||
.compatible = "qcom,sdm845-qmp-ufs-phy",
|
||||
.data = &sdm845_ufsphy_cfg,
|
||||
|
Loading…
Reference in New Issue
Block a user