// SPDX-License-Identifier: GPL-2.0 /* * MediaTek DisplayPort PHY driver * * Copyright (c) 2022, BayLibre Inc. * Copyright (c) 2022, MediaTek Inc. */ #include #include #include #include #include #include #include #define PHY_OFFSET 0x1000 #define MTK_DP_PHY_DIG_PLL_CTL_1 (PHY_OFFSET + 0x14) #define TPLL_SSC_EN BIT(3) #define MTK_DP_PHY_DIG_BIT_RATE (PHY_OFFSET + 0x3C) #define BIT_RATE_RBR 0 #define BIT_RATE_HBR 1 #define BIT_RATE_HBR2 2 #define BIT_RATE_HBR3 3 #define MTK_DP_PHY_DIG_SW_RST (PHY_OFFSET + 0x38) #define DP_GLB_SW_RST_PHYD BIT(0) #define MTK_DP_LANE0_DRIVING_PARAM_3 (PHY_OFFSET + 0x138) #define MTK_DP_LANE1_DRIVING_PARAM_3 (PHY_OFFSET + 0x238) #define MTK_DP_LANE2_DRIVING_PARAM_3 (PHY_OFFSET + 0x338) #define MTK_DP_LANE3_DRIVING_PARAM_3 (PHY_OFFSET + 0x438) #define XTP_LN_TX_LCTXC0_SW0_PRE0_DEFAULT BIT(4) #define XTP_LN_TX_LCTXC0_SW0_PRE1_DEFAULT (BIT(10) | BIT(12)) #define XTP_LN_TX_LCTXC0_SW0_PRE2_DEFAULT GENMASK(20, 19) #define XTP_LN_TX_LCTXC0_SW0_PRE3_DEFAULT GENMASK(29, 29) #define DRIVING_PARAM_3_DEFAULT (XTP_LN_TX_LCTXC0_SW0_PRE0_DEFAULT | \ XTP_LN_TX_LCTXC0_SW0_PRE1_DEFAULT | \ XTP_LN_TX_LCTXC0_SW0_PRE2_DEFAULT | \ XTP_LN_TX_LCTXC0_SW0_PRE3_DEFAULT) #define XTP_LN_TX_LCTXC0_SW1_PRE0_DEFAULT GENMASK(4, 3) #define XTP_LN_TX_LCTXC0_SW1_PRE1_DEFAULT GENMASK(12, 9) #define XTP_LN_TX_LCTXC0_SW1_PRE2_DEFAULT (BIT(18) | BIT(21)) #define XTP_LN_TX_LCTXC0_SW2_PRE0_DEFAULT GENMASK(29, 29) #define DRIVING_PARAM_4_DEFAULT (XTP_LN_TX_LCTXC0_SW1_PRE0_DEFAULT | \ XTP_LN_TX_LCTXC0_SW1_PRE1_DEFAULT | \ XTP_LN_TX_LCTXC0_SW1_PRE2_DEFAULT | \ XTP_LN_TX_LCTXC0_SW2_PRE0_DEFAULT) #define XTP_LN_TX_LCTXC0_SW2_PRE1_DEFAULT (BIT(3) | BIT(5)) #define XTP_LN_TX_LCTXC0_SW3_PRE0_DEFAULT GENMASK(13, 12) #define DRIVING_PARAM_5_DEFAULT (XTP_LN_TX_LCTXC0_SW2_PRE1_DEFAULT | \ XTP_LN_TX_LCTXC0_SW3_PRE0_DEFAULT) #define XTP_LN_TX_LCTXCP1_SW0_PRE0_DEFAULT 0 #define XTP_LN_TX_LCTXCP1_SW0_PRE1_DEFAULT GENMASK(10, 10) #define XTP_LN_TX_LCTXCP1_SW0_PRE2_DEFAULT GENMASK(19, 19) #define XTP_LN_TX_LCTXCP1_SW0_PRE3_DEFAULT GENMASK(28, 28) #define DRIVING_PARAM_6_DEFAULT (XTP_LN_TX_LCTXCP1_SW0_PRE0_DEFAULT | \ XTP_LN_TX_LCTXCP1_SW0_PRE1_DEFAULT | \ XTP_LN_TX_LCTXCP1_SW0_PRE2_DEFAULT | \ XTP_LN_TX_LCTXCP1_SW0_PRE3_DEFAULT) #define XTP_LN_TX_LCTXCP1_SW1_PRE0_DEFAULT 0 #define XTP_LN_TX_LCTXCP1_SW1_PRE1_DEFAULT GENMASK(10, 9) #define XTP_LN_TX_LCTXCP1_SW1_PRE2_DEFAULT GENMASK(19, 18) #define XTP_LN_TX_LCTXCP1_SW2_PRE0_DEFAULT 0 #define DRIVING_PARAM_7_DEFAULT (XTP_LN_TX_LCTXCP1_SW1_PRE0_DEFAULT | \ XTP_LN_TX_LCTXCP1_SW1_PRE1_DEFAULT | \ XTP_LN_TX_LCTXCP1_SW1_PRE2_DEFAULT | \ XTP_LN_TX_LCTXCP1_SW2_PRE0_DEFAULT) #define XTP_LN_TX_LCTXCP1_SW2_PRE1_DEFAULT GENMASK(3, 3) #define XTP_LN_TX_LCTXCP1_SW3_PRE0_DEFAULT 0 #define DRIVING_PARAM_8_DEFAULT (XTP_LN_TX_LCTXCP1_SW2_PRE1_DEFAULT | \ XTP_LN_TX_LCTXCP1_SW3_PRE0_DEFAULT) struct mtk_dp_phy { struct regmap *regs; }; static int mtk_dp_phy_init(struct phy *phy) { struct mtk_dp_phy *dp_phy = phy_get_drvdata(phy); static const u32 driving_params[] = { DRIVING_PARAM_3_DEFAULT, DRIVING_PARAM_4_DEFAULT, DRIVING_PARAM_5_DEFAULT, DRIVING_PARAM_6_DEFAULT, DRIVING_PARAM_7_DEFAULT, DRIVING_PARAM_8_DEFAULT }; regmap_bulk_write(dp_phy->regs, MTK_DP_LANE0_DRIVING_PARAM_3, driving_params, ARRAY_SIZE(driving_params)); regmap_bulk_write(dp_phy->regs, MTK_DP_LANE1_DRIVING_PARAM_3, driving_params, ARRAY_SIZE(driving_params)); regmap_bulk_write(dp_phy->regs, MTK_DP_LANE2_DRIVING_PARAM_3, driving_params, ARRAY_SIZE(driving_params)); regmap_bulk_write(dp_phy->regs, MTK_DP_LANE3_DRIVING_PARAM_3, driving_params, ARRAY_SIZE(driving_params)); return 0; } static int mtk_dp_phy_configure(struct phy *phy, union phy_configure_opts *opts) { struct mtk_dp_phy *dp_phy = phy_get_drvdata(phy); u32 val; if (opts->dp.set_rate) { switch (opts->dp.link_rate) { default: dev_err(&phy->dev, "Implementation error, unknown linkrate %x\n", opts->dp.link_rate); return -EINVAL; case 1620: val = BIT_RATE_RBR; break; case 2700: val = BIT_RATE_HBR; break; case 5400: val = BIT_RATE_HBR2; break; case 8100: val = BIT_RATE_HBR3; break; } regmap_write(dp_phy->regs, MTK_DP_PHY_DIG_BIT_RATE, val); } regmap_update_bits(dp_phy->regs, MTK_DP_PHY_DIG_PLL_CTL_1, TPLL_SSC_EN, opts->dp.ssc ? TPLL_SSC_EN : 0); return 0; } static int mtk_dp_phy_reset(struct phy *phy) { struct mtk_dp_phy *dp_phy = phy_get_drvdata(phy); regmap_update_bits(dp_phy->regs, MTK_DP_PHY_DIG_SW_RST, DP_GLB_SW_RST_PHYD, 0); usleep_range(50, 200); regmap_update_bits(dp_phy->regs, MTK_DP_PHY_DIG_SW_RST, DP_GLB_SW_RST_PHYD, 1); return 0; } static const struct phy_ops mtk_dp_phy_dev_ops = { .init = mtk_dp_phy_init, .configure = mtk_dp_phy_configure, .reset = mtk_dp_phy_reset, .owner = THIS_MODULE, }; static int mtk_dp_phy_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct mtk_dp_phy *dp_phy; struct phy *phy; struct regmap *regs; regs = *(struct regmap **)dev->platform_data; if (!regs) return dev_err_probe(dev, -EINVAL, "No data passed, requires struct regmap**\n"); dp_phy = devm_kzalloc(dev, sizeof(*dp_phy), GFP_KERNEL); if (!dp_phy) return -ENOMEM; dp_phy->regs = regs; phy = devm_phy_create(dev, NULL, &mtk_dp_phy_dev_ops); if (IS_ERR(phy)) return dev_err_probe(dev, PTR_ERR(phy), "Failed to create DP PHY\n"); phy_set_drvdata(phy, dp_phy); if (!dev->of_node) phy_create_lookup(phy, "dp", dev_name(dev)); return 0; } static struct platform_driver mtk_dp_phy_driver = { .probe = mtk_dp_phy_probe, .driver = { .name = "mediatek-dp-phy", }, }; module_platform_driver(mtk_dp_phy_driver); MODULE_AUTHOR("Markus Schneider-Pargmann "); MODULE_DESCRIPTION("MediaTek DP PHY Driver"); MODULE_LICENSE("GPL");