From b28be59a2e2668b35507553e0de135c29ebd71ef Mon Sep 17 00:00:00 2001 From: CK Hu Date: Mon, 13 May 2019 10:22:25 +0800 Subject: phy: mediatek: Move mtk_hdmi_phy driver into drivers/phy/mediatek folder mtk_hdmi_phy is currently placed inside mediatek drm driver, but it's more suitable to place a phy driver into phy driver folder, so move mtk_hdmi_phy driver into phy driver folder. Signed-off-by: CK Hu Signed-off-by: Chun-Kuang Hu Acked-by: Chunfeng Yun Tested-by: Frank Wunderlich --- drivers/gpu/drm/mediatek/Kconfig | 7 - drivers/gpu/drm/mediatek/Makefile | 6 - drivers/gpu/drm/mediatek/mtk_hdmi_phy.c | 211 ------------------ drivers/gpu/drm/mediatek/mtk_hdmi_phy.h | 55 ----- drivers/gpu/drm/mediatek/mtk_mt2701_hdmi_phy.c | 248 ---------------------- drivers/gpu/drm/mediatek/mtk_mt8173_hdmi_phy.c | 282 ------------------------- drivers/phy/mediatek/Kconfig | 7 + drivers/phy/mediatek/Makefile | 5 + drivers/phy/mediatek/phy-mtk-hdmi-mt2701.c | 248 ++++++++++++++++++++++ drivers/phy/mediatek/phy-mtk-hdmi-mt8173.c | 282 +++++++++++++++++++++++++ drivers/phy/mediatek/phy-mtk-hdmi.c | 211 ++++++++++++++++++ drivers/phy/mediatek/phy-mtk-hdmi.h | 55 +++++ 12 files changed, 808 insertions(+), 809 deletions(-) delete mode 100644 drivers/gpu/drm/mediatek/mtk_hdmi_phy.c delete mode 100644 drivers/gpu/drm/mediatek/mtk_hdmi_phy.h delete mode 100644 drivers/gpu/drm/mediatek/mtk_mt2701_hdmi_phy.c delete mode 100644 drivers/gpu/drm/mediatek/mtk_mt8173_hdmi_phy.c create mode 100644 drivers/phy/mediatek/phy-mtk-hdmi-mt2701.c create mode 100644 drivers/phy/mediatek/phy-mtk-hdmi-mt8173.c create mode 100644 drivers/phy/mediatek/phy-mtk-hdmi.c create mode 100644 drivers/phy/mediatek/phy-mtk-hdmi.h diff --git a/drivers/gpu/drm/mediatek/Kconfig b/drivers/gpu/drm/mediatek/Kconfig index 6363f2c1cdbc..65cd03a4be29 100644 --- a/drivers/gpu/drm/mediatek/Kconfig +++ b/drivers/gpu/drm/mediatek/Kconfig @@ -27,10 +27,3 @@ config DRM_MEDIATEK_HDMI select PHY_MTK_HDMI help DRM/KMS HDMI driver for Mediatek SoCs - -config PHY_MTK_HDMI - tristate "MediaTek HDMI-PHY Driver" - depends on ARCH_MEDIATEK && OF - select GENERIC_PHY - help - Support HDMI PHY for Mediatek SoCs. diff --git a/drivers/gpu/drm/mediatek/Makefile b/drivers/gpu/drm/mediatek/Makefile index fcbef23aa6ce..77b0fd86063d 100644 --- a/drivers/gpu/drm/mediatek/Makefile +++ b/drivers/gpu/drm/mediatek/Makefile @@ -22,9 +22,3 @@ mediatek-drm-hdmi-objs := mtk_cec.o \ mtk_hdmi_ddc.o obj-$(CONFIG_DRM_MEDIATEK_HDMI) += mediatek-drm-hdmi.o - -phy-mtk-hdmi-drv-objs := mtk_hdmi_phy.o \ - mtk_mt2701_hdmi_phy.o \ - mtk_mt8173_hdmi_phy.o - -obj-$(CONFIG_PHY_MTK_HDMI) += phy-mtk-hdmi-drv.o diff --git a/drivers/gpu/drm/mediatek/mtk_hdmi_phy.c b/drivers/gpu/drm/mediatek/mtk_hdmi_phy.c deleted file mode 100644 index fe022acddbef..000000000000 --- a/drivers/gpu/drm/mediatek/mtk_hdmi_phy.c +++ /dev/null @@ -1,211 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Copyright (c) 2018 MediaTek Inc. - * Author: Jie Qiu - */ - -#include "mtk_hdmi_phy.h" - -static int mtk_hdmi_phy_power_on(struct phy *phy); -static int mtk_hdmi_phy_power_off(struct phy *phy); - -static const struct phy_ops mtk_hdmi_phy_dev_ops = { - .power_on = mtk_hdmi_phy_power_on, - .power_off = mtk_hdmi_phy_power_off, - .owner = THIS_MODULE, -}; - -void mtk_hdmi_phy_clear_bits(struct mtk_hdmi_phy *hdmi_phy, u32 offset, - u32 bits) -{ - void __iomem *reg = hdmi_phy->regs + offset; - u32 tmp; - - tmp = readl(reg); - tmp &= ~bits; - writel(tmp, reg); -} - -void mtk_hdmi_phy_set_bits(struct mtk_hdmi_phy *hdmi_phy, u32 offset, - u32 bits) -{ - void __iomem *reg = hdmi_phy->regs + offset; - u32 tmp; - - tmp = readl(reg); - tmp |= bits; - writel(tmp, reg); -} - -void mtk_hdmi_phy_mask(struct mtk_hdmi_phy *hdmi_phy, u32 offset, - u32 val, u32 mask) -{ - void __iomem *reg = hdmi_phy->regs + offset; - u32 tmp; - - tmp = readl(reg); - tmp = (tmp & ~mask) | (val & mask); - writel(tmp, reg); -} - -inline struct mtk_hdmi_phy *to_mtk_hdmi_phy(struct clk_hw *hw) -{ - return container_of(hw, struct mtk_hdmi_phy, pll_hw); -} - -static int mtk_hdmi_phy_power_on(struct phy *phy) -{ - struct mtk_hdmi_phy *hdmi_phy = phy_get_drvdata(phy); - int ret; - - ret = clk_prepare_enable(hdmi_phy->pll); - if (ret < 0) - return ret; - - hdmi_phy->conf->hdmi_phy_enable_tmds(hdmi_phy); - return 0; -} - -static int mtk_hdmi_phy_power_off(struct phy *phy) -{ - struct mtk_hdmi_phy *hdmi_phy = phy_get_drvdata(phy); - - hdmi_phy->conf->hdmi_phy_disable_tmds(hdmi_phy); - clk_disable_unprepare(hdmi_phy->pll); - - return 0; -} - -static const struct phy_ops * -mtk_hdmi_phy_dev_get_ops(const struct mtk_hdmi_phy *hdmi_phy) -{ - if (hdmi_phy && hdmi_phy->conf && - hdmi_phy->conf->hdmi_phy_enable_tmds && - hdmi_phy->conf->hdmi_phy_disable_tmds) - return &mtk_hdmi_phy_dev_ops; - - dev_err(hdmi_phy->dev, "Failed to get dev ops of phy\n"); - return NULL; -} - -static void mtk_hdmi_phy_clk_get_data(struct mtk_hdmi_phy *hdmi_phy, - struct clk_init_data *clk_init) -{ - clk_init->flags = hdmi_phy->conf->flags; - clk_init->ops = hdmi_phy->conf->hdmi_phy_clk_ops; -} - -static int mtk_hdmi_phy_probe(struct platform_device *pdev) -{ - struct device *dev = &pdev->dev; - struct mtk_hdmi_phy *hdmi_phy; - struct resource *mem; - struct clk *ref_clk; - const char *ref_clk_name; - struct clk_init_data clk_init = { - .num_parents = 1, - .parent_names = (const char * const *)&ref_clk_name, - }; - - struct phy *phy; - struct phy_provider *phy_provider; - int ret; - - hdmi_phy = devm_kzalloc(dev, sizeof(*hdmi_phy), GFP_KERNEL); - if (!hdmi_phy) - return -ENOMEM; - - mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); - hdmi_phy->regs = devm_ioremap_resource(dev, mem); - if (IS_ERR(hdmi_phy->regs)) { - ret = PTR_ERR(hdmi_phy->regs); - dev_err(dev, "Failed to get memory resource: %d\n", ret); - return ret; - } - - ref_clk = devm_clk_get(dev, "pll_ref"); - if (IS_ERR(ref_clk)) { - ret = PTR_ERR(ref_clk); - dev_err(&pdev->dev, "Failed to get PLL reference clock: %d\n", - ret); - return ret; - } - ref_clk_name = __clk_get_name(ref_clk); - - ret = of_property_read_string(dev->of_node, "clock-output-names", - &clk_init.name); - if (ret < 0) { - dev_err(dev, "Failed to read clock-output-names: %d\n", ret); - return ret; - } - - hdmi_phy->dev = dev; - hdmi_phy->conf = - (struct mtk_hdmi_phy_conf *)of_device_get_match_data(dev); - mtk_hdmi_phy_clk_get_data(hdmi_phy, &clk_init); - hdmi_phy->pll_hw.init = &clk_init; - hdmi_phy->pll = devm_clk_register(dev, &hdmi_phy->pll_hw); - if (IS_ERR(hdmi_phy->pll)) { - ret = PTR_ERR(hdmi_phy->pll); - dev_err(dev, "Failed to register PLL: %d\n", ret); - return ret; - } - - ret = of_property_read_u32(dev->of_node, "mediatek,ibias", - &hdmi_phy->ibias); - if (ret < 0) { - dev_err(&pdev->dev, "Failed to get ibias: %d\n", ret); - return ret; - } - - ret = of_property_read_u32(dev->of_node, "mediatek,ibias_up", - &hdmi_phy->ibias_up); - if (ret < 0) { - dev_err(&pdev->dev, "Failed to get ibias up: %d\n", ret); - return ret; - } - - dev_info(dev, "Using default TX DRV impedance: 4.2k/36\n"); - hdmi_phy->drv_imp_clk = 0x30; - hdmi_phy->drv_imp_d2 = 0x30; - hdmi_phy->drv_imp_d1 = 0x30; - hdmi_phy->drv_imp_d0 = 0x30; - - phy = devm_phy_create(dev, NULL, mtk_hdmi_phy_dev_get_ops(hdmi_phy)); - if (IS_ERR(phy)) { - dev_err(dev, "Failed to create HDMI PHY\n"); - return PTR_ERR(phy); - } - phy_set_drvdata(phy, hdmi_phy); - - phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); - if (IS_ERR(phy_provider)) { - dev_err(dev, "Failed to register HDMI PHY\n"); - return PTR_ERR(phy_provider); - } - - return of_clk_add_provider(dev->of_node, of_clk_src_simple_get, - hdmi_phy->pll); -} - -static const struct of_device_id mtk_hdmi_phy_match[] = { - { .compatible = "mediatek,mt2701-hdmi-phy", - .data = &mtk_hdmi_phy_2701_conf, - }, - { .compatible = "mediatek,mt8173-hdmi-phy", - .data = &mtk_hdmi_phy_8173_conf, - }, - {}, -}; - -struct platform_driver mtk_hdmi_phy_driver = { - .probe = mtk_hdmi_phy_probe, - .driver = { - .name = "mediatek-hdmi-phy", - .of_match_table = mtk_hdmi_phy_match, - }, -}; -module_platform_driver(mtk_hdmi_phy_driver); - -MODULE_DESCRIPTION("MediaTek HDMI PHY Driver"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/gpu/drm/mediatek/mtk_hdmi_phy.h b/drivers/gpu/drm/mediatek/mtk_hdmi_phy.h deleted file mode 100644 index b13e1d5f8e78..000000000000 --- a/drivers/gpu/drm/mediatek/mtk_hdmi_phy.h +++ /dev/null @@ -1,55 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * Copyright (c) 2018 MediaTek Inc. - * Author: Chunhui Dai - */ - -#ifndef _MTK_HDMI_PHY_H -#define _MTK_HDMI_PHY_H -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -struct mtk_hdmi_phy; - -struct mtk_hdmi_phy_conf { - unsigned long flags; - const struct clk_ops *hdmi_phy_clk_ops; - void (*hdmi_phy_enable_tmds)(struct mtk_hdmi_phy *hdmi_phy); - void (*hdmi_phy_disable_tmds)(struct mtk_hdmi_phy *hdmi_phy); -}; - -struct mtk_hdmi_phy { - void __iomem *regs; - struct device *dev; - struct mtk_hdmi_phy_conf *conf; - struct clk *pll; - struct clk_hw pll_hw; - unsigned long pll_rate; - unsigned char drv_imp_clk; - unsigned char drv_imp_d2; - unsigned char drv_imp_d1; - unsigned char drv_imp_d0; - unsigned int ibias; - unsigned int ibias_up; -}; - -void mtk_hdmi_phy_clear_bits(struct mtk_hdmi_phy *hdmi_phy, u32 offset, - u32 bits); -void mtk_hdmi_phy_set_bits(struct mtk_hdmi_phy *hdmi_phy, u32 offset, - u32 bits); -void mtk_hdmi_phy_mask(struct mtk_hdmi_phy *hdmi_phy, u32 offset, - u32 val, u32 mask); -struct mtk_hdmi_phy *to_mtk_hdmi_phy(struct clk_hw *hw); - -extern struct mtk_hdmi_phy_conf mtk_hdmi_phy_8173_conf; -extern struct mtk_hdmi_phy_conf mtk_hdmi_phy_2701_conf; - -#endif /* _MTK_HDMI_PHY_H */ diff --git a/drivers/gpu/drm/mediatek/mtk_mt2701_hdmi_phy.c b/drivers/gpu/drm/mediatek/mtk_mt2701_hdmi_phy.c deleted file mode 100644 index 99fe05cd3598..000000000000 --- a/drivers/gpu/drm/mediatek/mtk_mt2701_hdmi_phy.c +++ /dev/null @@ -1,248 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Copyright (c) 2018 MediaTek Inc. - * Author: Chunhui Dai - */ - -#include "mtk_hdmi_phy.h" - -#define HDMI_CON0 0x00 -#define RG_HDMITX_DRV_IBIAS 0 -#define RG_HDMITX_DRV_IBIAS_MASK (0x3f << 0) -#define RG_HDMITX_EN_SER 12 -#define RG_HDMITX_EN_SER_MASK (0x0f << 12) -#define RG_HDMITX_EN_SLDO 16 -#define RG_HDMITX_EN_SLDO_MASK (0x0f << 16) -#define RG_HDMITX_EN_PRED 20 -#define RG_HDMITX_EN_PRED_MASK (0x0f << 20) -#define RG_HDMITX_EN_IMP 24 -#define RG_HDMITX_EN_IMP_MASK (0x0f << 24) -#define RG_HDMITX_EN_DRV 28 -#define RG_HDMITX_EN_DRV_MASK (0x0f << 28) - -#define HDMI_CON1 0x04 -#define RG_HDMITX_PRED_IBIAS 18 -#define RG_HDMITX_PRED_IBIAS_MASK (0x0f << 18) -#define RG_HDMITX_PRED_IMP (0x01 << 22) -#define RG_HDMITX_DRV_IMP 26 -#define RG_HDMITX_DRV_IMP_MASK (0x3f << 26) - -#define HDMI_CON2 0x08 -#define RG_HDMITX_EN_TX_CKLDO (0x01 << 0) -#define RG_HDMITX_EN_TX_POSDIV (0x01 << 1) -#define RG_HDMITX_TX_POSDIV 3 -#define RG_HDMITX_TX_POSDIV_MASK (0x03 << 3) -#define RG_HDMITX_EN_MBIAS (0x01 << 6) -#define RG_HDMITX_MBIAS_LPF_EN (0x01 << 7) - -#define HDMI_CON4 0x10 -#define RG_HDMITX_RESERVE_MASK (0xffffffff << 0) - -#define HDMI_CON6 0x18 -#define RG_HTPLL_BR 0 -#define RG_HTPLL_BR_MASK (0x03 << 0) -#define RG_HTPLL_BC 2 -#define RG_HTPLL_BC_MASK (0x03 << 2) -#define RG_HTPLL_BP 4 -#define RG_HTPLL_BP_MASK (0x0f << 4) -#define RG_HTPLL_IR 8 -#define RG_HTPLL_IR_MASK (0x0f << 8) -#define RG_HTPLL_IC 12 -#define RG_HTPLL_IC_MASK (0x0f << 12) -#define RG_HTPLL_POSDIV 16 -#define RG_HTPLL_POSDIV_MASK (0x03 << 16) -#define RG_HTPLL_PREDIV 18 -#define RG_HTPLL_PREDIV_MASK (0x03 << 18) -#define RG_HTPLL_FBKSEL 20 -#define RG_HTPLL_FBKSEL_MASK (0x03 << 20) -#define RG_HTPLL_RLH_EN (0x01 << 22) -#define RG_HTPLL_FBKDIV 24 -#define RG_HTPLL_FBKDIV_MASK (0x7f << 24) -#define RG_HTPLL_EN (0x01 << 31) - -#define HDMI_CON7 0x1c -#define RG_HTPLL_AUTOK_EN (0x01 << 23) -#define RG_HTPLL_DIVEN 28 -#define RG_HTPLL_DIVEN_MASK (0x07 << 28) - -static int mtk_hdmi_pll_prepare(struct clk_hw *hw) -{ - struct mtk_hdmi_phy *hdmi_phy = to_mtk_hdmi_phy(hw); - - mtk_hdmi_phy_set_bits(hdmi_phy, HDMI_CON7, RG_HTPLL_AUTOK_EN); - mtk_hdmi_phy_clear_bits(hdmi_phy, HDMI_CON6, RG_HTPLL_RLH_EN); - mtk_hdmi_phy_set_bits(hdmi_phy, HDMI_CON6, RG_HTPLL_POSDIV_MASK); - mtk_hdmi_phy_set_bits(hdmi_phy, HDMI_CON2, RG_HDMITX_EN_MBIAS); - usleep_range(80, 100); - mtk_hdmi_phy_set_bits(hdmi_phy, HDMI_CON6, RG_HTPLL_EN); - mtk_hdmi_phy_set_bits(hdmi_phy, HDMI_CON2, RG_HDMITX_EN_TX_CKLDO); - mtk_hdmi_phy_set_bits(hdmi_phy, HDMI_CON0, RG_HDMITX_EN_SLDO_MASK); - usleep_range(80, 100); - mtk_hdmi_phy_set_bits(hdmi_phy, HDMI_CON2, RG_HDMITX_MBIAS_LPF_EN); - mtk_hdmi_phy_set_bits(hdmi_phy, HDMI_CON0, RG_HDMITX_EN_SER_MASK); - mtk_hdmi_phy_set_bits(hdmi_phy, HDMI_CON0, RG_HDMITX_EN_PRED_MASK); - mtk_hdmi_phy_set_bits(hdmi_phy, HDMI_CON0, RG_HDMITX_EN_DRV_MASK); - usleep_range(80, 100); - return 0; -} - -static void mtk_hdmi_pll_unprepare(struct clk_hw *hw) -{ - struct mtk_hdmi_phy *hdmi_phy = to_mtk_hdmi_phy(hw); - - mtk_hdmi_phy_clear_bits(hdmi_phy, HDMI_CON0, RG_HDMITX_EN_DRV_MASK); - mtk_hdmi_phy_clear_bits(hdmi_phy, HDMI_CON0, RG_HDMITX_EN_PRED_MASK); - mtk_hdmi_phy_clear_bits(hdmi_phy, HDMI_CON0, RG_HDMITX_EN_SER_MASK); - mtk_hdmi_phy_clear_bits(hdmi_phy, HDMI_CON2, RG_HDMITX_MBIAS_LPF_EN); - usleep_range(80, 100); - mtk_hdmi_phy_clear_bits(hdmi_phy, HDMI_CON0, RG_HDMITX_EN_SLDO_MASK); - mtk_hdmi_phy_clear_bits(hdmi_phy, HDMI_CON2, RG_HDMITX_EN_TX_CKLDO); - mtk_hdmi_phy_clear_bits(hdmi_phy, HDMI_CON6, RG_HTPLL_EN); - usleep_range(80, 100); - mtk_hdmi_phy_clear_bits(hdmi_phy, HDMI_CON2, RG_HDMITX_EN_MBIAS); - mtk_hdmi_phy_clear_bits(hdmi_phy, HDMI_CON6, RG_HTPLL_POSDIV_MASK); - mtk_hdmi_phy_clear_bits(hdmi_phy, HDMI_CON6, RG_HTPLL_RLH_EN); - mtk_hdmi_phy_clear_bits(hdmi_phy, HDMI_CON7, RG_HTPLL_AUTOK_EN); - usleep_range(80, 100); -} - -static long mtk_hdmi_pll_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *parent_rate) -{ - return rate; -} - -static int mtk_hdmi_pll_set_rate(struct clk_hw *hw, unsigned long rate, - unsigned long parent_rate) -{ - struct mtk_hdmi_phy *hdmi_phy = to_mtk_hdmi_phy(hw); - u32 pos_div; - - if (rate <= 64000000) - pos_div = 3; - else if (rate <= 128000000) - pos_div = 2; - else - pos_div = 1; - - mtk_hdmi_phy_set_bits(hdmi_phy, HDMI_CON6, RG_HTPLL_PREDIV_MASK); - mtk_hdmi_phy_set_bits(hdmi_phy, HDMI_CON6, RG_HTPLL_POSDIV_MASK); - mtk_hdmi_phy_set_bits(hdmi_phy, HDMI_CON2, RG_HDMITX_EN_TX_POSDIV); - mtk_hdmi_phy_mask(hdmi_phy, HDMI_CON6, (0x1 << RG_HTPLL_IC), - RG_HTPLL_IC_MASK); - mtk_hdmi_phy_mask(hdmi_phy, HDMI_CON6, (0x1 << RG_HTPLL_IR), - RG_HTPLL_IR_MASK); - mtk_hdmi_phy_mask(hdmi_phy, HDMI_CON2, (pos_div << RG_HDMITX_TX_POSDIV), - RG_HDMITX_TX_POSDIV_MASK); - mtk_hdmi_phy_mask(hdmi_phy, HDMI_CON6, (1 << RG_HTPLL_FBKSEL), - RG_HTPLL_FBKSEL_MASK); - mtk_hdmi_phy_mask(hdmi_phy, HDMI_CON6, (19 << RG_HTPLL_FBKDIV), - RG_HTPLL_FBKDIV_MASK); - mtk_hdmi_phy_mask(hdmi_phy, HDMI_CON7, (0x2 << RG_HTPLL_DIVEN), - RG_HTPLL_DIVEN_MASK); - mtk_hdmi_phy_mask(hdmi_phy, HDMI_CON6, (0xc << RG_HTPLL_BP), - RG_HTPLL_BP_MASK); - mtk_hdmi_phy_mask(hdmi_phy, HDMI_CON6, (0x2 << RG_HTPLL_BC), - RG_HTPLL_BC_MASK); - mtk_hdmi_phy_mask(hdmi_phy, HDMI_CON6, (0x1 << RG_HTPLL_BR), - RG_HTPLL_BR_MASK); - - mtk_hdmi_phy_clear_bits(hdmi_phy, HDMI_CON1, RG_HDMITX_PRED_IMP); - mtk_hdmi_phy_mask(hdmi_phy, HDMI_CON1, (0x3 << RG_HDMITX_PRED_IBIAS), - RG_HDMITX_PRED_IBIAS_MASK); - mtk_hdmi_phy_clear_bits(hdmi_phy, HDMI_CON0, RG_HDMITX_EN_IMP_MASK); - mtk_hdmi_phy_mask(hdmi_phy, HDMI_CON1, (0x28 << RG_HDMITX_DRV_IMP), - RG_HDMITX_DRV_IMP_MASK); - mtk_hdmi_phy_mask(hdmi_phy, HDMI_CON4, 0x28, RG_HDMITX_RESERVE_MASK); - mtk_hdmi_phy_mask(hdmi_phy, HDMI_CON0, (0xa << RG_HDMITX_DRV_IBIAS), - RG_HDMITX_DRV_IBIAS_MASK); - return 0; -} - -static unsigned long mtk_hdmi_pll_recalc_rate(struct clk_hw *hw, - unsigned long parent_rate) -{ - struct mtk_hdmi_phy *hdmi_phy = to_mtk_hdmi_phy(hw); - unsigned long out_rate, val; - - val = (readl(hdmi_phy->regs + HDMI_CON6) - & RG_HTPLL_PREDIV_MASK) >> RG_HTPLL_PREDIV; - switch (val) { - case 0x00: - out_rate = parent_rate; - break; - case 0x01: - out_rate = parent_rate / 2; - break; - default: - out_rate = parent_rate / 4; - break; - } - - val = (readl(hdmi_phy->regs + HDMI_CON6) - & RG_HTPLL_FBKDIV_MASK) >> RG_HTPLL_FBKDIV; - out_rate *= (val + 1) * 2; - val = (readl(hdmi_phy->regs + HDMI_CON2) - & RG_HDMITX_TX_POSDIV_MASK); - out_rate >>= (val >> RG_HDMITX_TX_POSDIV); - - if (readl(hdmi_phy->regs + HDMI_CON2) & RG_HDMITX_EN_TX_POSDIV) - out_rate /= 5; - - return out_rate; -} - -static const struct clk_ops mtk_hdmi_phy_pll_ops = { - .prepare = mtk_hdmi_pll_prepare, - .unprepare = mtk_hdmi_pll_unprepare, - .set_rate = mtk_hdmi_pll_set_rate, - .round_rate = mtk_hdmi_pll_round_rate, - .recalc_rate = mtk_hdmi_pll_recalc_rate, -}; - -static void mtk_hdmi_phy_enable_tmds(struct mtk_hdmi_phy *hdmi_phy) -{ - mtk_hdmi_phy_set_bits(hdmi_phy, HDMI_CON7, RG_HTPLL_AUTOK_EN); - mtk_hdmi_phy_clear_bits(hdmi_phy, HDMI_CON6, RG_HTPLL_RLH_EN); - mtk_hdmi_phy_set_bits(hdmi_phy, HDMI_CON6, RG_HTPLL_POSDIV_MASK); - mtk_hdmi_phy_set_bits(hdmi_phy, HDMI_CON2, RG_HDMITX_EN_MBIAS); - usleep_range(80, 100); - mtk_hdmi_phy_set_bits(hdmi_phy, HDMI_CON6, RG_HTPLL_EN); - mtk_hdmi_phy_set_bits(hdmi_phy, HDMI_CON2, RG_HDMITX_EN_TX_CKLDO); - mtk_hdmi_phy_set_bits(hdmi_phy, HDMI_CON0, RG_HDMITX_EN_SLDO_MASK); - usleep_range(80, 100); - mtk_hdmi_phy_set_bits(hdmi_phy, HDMI_CON2, RG_HDMITX_MBIAS_LPF_EN); - mtk_hdmi_phy_set_bits(hdmi_phy, HDMI_CON0, RG_HDMITX_EN_SER_MASK); - mtk_hdmi_phy_set_bits(hdmi_phy, HDMI_CON0, RG_HDMITX_EN_PRED_MASK); - mtk_hdmi_phy_set_bits(hdmi_phy, HDMI_CON0, RG_HDMITX_EN_DRV_MASK); - usleep_range(80, 100); -} - -static void mtk_hdmi_phy_disable_tmds(struct mtk_hdmi_phy *hdmi_phy) -{ - mtk_hdmi_phy_clear_bits(hdmi_phy, HDMI_CON0, RG_HDMITX_EN_DRV_MASK); - mtk_hdmi_phy_clear_bits(hdmi_phy, HDMI_CON0, RG_HDMITX_EN_PRED_MASK); - mtk_hdmi_phy_clear_bits(hdmi_phy, HDMI_CON0, RG_HDMITX_EN_SER_MASK); - mtk_hdmi_phy_clear_bits(hdmi_phy, HDMI_CON2, RG_HDMITX_MBIAS_LPF_EN); - usleep_range(80, 100); - mtk_hdmi_phy_clear_bits(hdmi_phy, HDMI_CON0, RG_HDMITX_EN_SLDO_MASK); - mtk_hdmi_phy_clear_bits(hdmi_phy, HDMI_CON2, RG_HDMITX_EN_TX_CKLDO); - mtk_hdmi_phy_clear_bits(hdmi_phy, HDMI_CON6, RG_HTPLL_EN); - usleep_range(80, 100); - mtk_hdmi_phy_clear_bits(hdmi_phy, HDMI_CON2, RG_HDMITX_EN_MBIAS); - mtk_hdmi_phy_clear_bits(hdmi_phy, HDMI_CON6, RG_HTPLL_POSDIV_MASK); - mtk_hdmi_phy_clear_bits(hdmi_phy, HDMI_CON6, RG_HTPLL_RLH_EN); - mtk_hdmi_phy_clear_bits(hdmi_phy, HDMI_CON7, RG_HTPLL_AUTOK_EN); - usleep_range(80, 100); -} - -struct mtk_hdmi_phy_conf mtk_hdmi_phy_2701_conf = { - .flags = CLK_SET_RATE_GATE, - .hdmi_phy_clk_ops = &mtk_hdmi_phy_pll_ops, - .hdmi_phy_enable_tmds = mtk_hdmi_phy_enable_tmds, - .hdmi_phy_disable_tmds = mtk_hdmi_phy_disable_tmds, -}; - -MODULE_AUTHOR("Chunhui Dai "); -MODULE_DESCRIPTION("MediaTek HDMI PHY Driver"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/gpu/drm/mediatek/mtk_mt8173_hdmi_phy.c b/drivers/gpu/drm/mediatek/mtk_mt8173_hdmi_phy.c deleted file mode 100644 index 827b93786fac..000000000000 --- a/drivers/gpu/drm/mediatek/mtk_mt8173_hdmi_phy.c +++ /dev/null @@ -1,282 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Copyright (c) 2014 MediaTek Inc. - * Author: Jie Qiu - */ - -#include "mtk_hdmi_phy.h" - -#define HDMI_CON0 0x00 -#define RG_HDMITX_PLL_EN BIT(31) -#define RG_HDMITX_PLL_FBKDIV (0x7f << 24) -#define PLL_FBKDIV_SHIFT 24 -#define RG_HDMITX_PLL_FBKSEL (0x3 << 22) -#define PLL_FBKSEL_SHIFT 22 -#define RG_HDMITX_PLL_PREDIV (0x3 << 20) -#define PREDIV_SHIFT 20 -#define RG_HDMITX_PLL_POSDIV (0x3 << 18) -#define POSDIV_SHIFT 18 -#define RG_HDMITX_PLL_RST_DLY (0x3 << 16) -#define RG_HDMITX_PLL_IR (0xf << 12) -#define PLL_IR_SHIFT 12 -#define RG_HDMITX_PLL_IC (0xf << 8) -#define PLL_IC_SHIFT 8 -#define RG_HDMITX_PLL_BP (0xf << 4) -#define PLL_BP_SHIFT 4 -#define RG_HDMITX_PLL_BR (0x3 << 2) -#define PLL_BR_SHIFT 2 -#define RG_HDMITX_PLL_BC (0x3 << 0) -#define PLL_BC_SHIFT 0 -#define HDMI_CON1 0x04 -#define RG_HDMITX_PLL_DIVEN (0x7 << 29) -#define PLL_DIVEN_SHIFT 29 -#define RG_HDMITX_PLL_AUTOK_EN BIT(28) -#define RG_HDMITX_PLL_AUTOK_KF (0x3 << 26) -#define RG_HDMITX_PLL_AUTOK_KS (0x3 << 24) -#define RG_HDMITX_PLL_AUTOK_LOAD BIT(23) -#define RG_HDMITX_PLL_BAND (0x3f << 16) -#define RG_HDMITX_PLL_REF_SEL BIT(15) -#define RG_HDMITX_PLL_BIAS_EN BIT(14) -#define RG_HDMITX_PLL_BIAS_LPF_EN BIT(13) -#define RG_HDMITX_PLL_TXDIV_EN BIT(12) -#define RG_HDMITX_PLL_TXDIV (0x3 << 10) -#define PLL_TXDIV_SHIFT 10 -#define RG_HDMITX_PLL_LVROD_EN BIT(9) -#define RG_HDMITX_PLL_MONVC_EN BIT(8) -#define RG_HDMITX_PLL_MONCK_EN BIT(7) -#define RG_HDMITX_PLL_MONREF_EN BIT(6) -#define RG_HDMITX_PLL_TST_EN BIT(5) -#define RG_HDMITX_PLL_TST_CK_EN BIT(4) -#define RG_HDMITX_PLL_TST_SEL (0xf << 0) -#define HDMI_CON2 0x08 -#define RGS_HDMITX_PLL_AUTOK_BAND (0x7f << 8) -#define RGS_HDMITX_PLL_AUTOK_FAIL BIT(1) -#define RG_HDMITX_EN_TX_CKLDO BIT(0) -#define HDMI_CON3 0x0c -#define RG_HDMITX_SER_EN (0xf << 28) -#define RG_HDMITX_PRD_EN (0xf << 24) -#define RG_HDMITX_PRD_IMP_EN (0xf << 20) -#define RG_HDMITX_DRV_EN (0xf << 16) -#define RG_HDMITX_DRV_IMP_EN (0xf << 12) -#define DRV_IMP_EN_SHIFT 12 -#define RG_HDMITX_MHLCK_FORCE BIT(10) -#define RG_HDMITX_MHLCK_PPIX_EN BIT(9) -#define RG_HDMITX_MHLCK_EN BIT(8) -#define RG_HDMITX_SER_DIN_SEL (0xf << 4) -#define RG_HDMITX_SER_5T1_BIST_EN BIT(3) -#define RG_HDMITX_SER_BIST_TOG BIT(2) -#define RG_HDMITX_SER_DIN_TOG BIT(1) -#define RG_HDMITX_SER_CLKDIG_INV BIT(0) -#define HDMI_CON4 0x10 -#define RG_HDMITX_PRD_IBIAS_CLK (0xf << 24) -#define RG_HDMITX_PRD_IBIAS_D2 (0xf << 16) -#define RG_HDMITX_PRD_IBIAS_D1 (0xf << 8) -#define RG_HDMITX_PRD_IBIAS_D0 (0xf << 0) -#define PRD_IBIAS_CLK_SHIFT 24 -#define PRD_IBIAS_D2_SHIFT 16 -#define PRD_IBIAS_D1_SHIFT 8 -#define PRD_IBIAS_D0_SHIFT 0 -#define HDMI_CON5 0x14 -#define RG_HDMITX_DRV_IBIAS_CLK (0x3f << 24) -#define RG_HDMITX_DRV_IBIAS_D2 (0x3f << 16) -#define RG_HDMITX_DRV_IBIAS_D1 (0x3f << 8) -#define RG_HDMITX_DRV_IBIAS_D0 (0x3f << 0) -#define DRV_IBIAS_CLK_SHIFT 24 -#define DRV_IBIAS_D2_SHIFT 16 -#define DRV_IBIAS_D1_SHIFT 8 -#define DRV_IBIAS_D0_SHIFT 0 -#define HDMI_CON6 0x18 -#define RG_HDMITX_DRV_IMP_CLK (0x3f << 24) -#define RG_HDMITX_DRV_IMP_D2 (0x3f << 16) -#define RG_HDMITX_DRV_IMP_D1 (0x3f << 8) -#define RG_HDMITX_DRV_IMP_D0 (0x3f << 0) -#define DRV_IMP_CLK_SHIFT 24 -#define DRV_IMP_D2_SHIFT 16 -#define DRV_IMP_D1_SHIFT 8 -#define DRV_IMP_D0_SHIFT 0 -#define HDMI_CON7 0x1c -#define RG_HDMITX_MHLCK_DRV_IBIAS (0x1f << 27) -#define RG_HDMITX_SER_DIN (0x3ff << 16) -#define RG_HDMITX_CHLDC_TST (0xf << 12) -#define RG_HDMITX_CHLCK_TST (0xf << 8) -#define RG_HDMITX_RESERVE (0xff << 0) -#define HDMI_CON8 0x20 -#define RGS_HDMITX_2T1_LEV (0xf << 16) -#define RGS_HDMITX_2T1_EDG (0xf << 12) -#define RGS_HDMITX_5T1_LEV (0xf << 8) -#define RGS_HDMITX_5T1_EDG (0xf << 4) -#define RGS_HDMITX_PLUG_TST BIT(0) - -static int mtk_hdmi_pll_prepare(struct clk_hw *hw) -{ - struct mtk_hdmi_phy *hdmi_phy = to_mtk_hdmi_phy(hw); - - mtk_hdmi_phy_set_bits(hdmi_phy, HDMI_CON1, RG_HDMITX_PLL_AUTOK_EN); - mtk_hdmi_phy_set_bits(hdmi_phy, HDMI_CON0, RG_HDMITX_PLL_POSDIV); - mtk_hdmi_phy_clear_bits(hdmi_phy, HDMI_CON3, RG_HDMITX_MHLCK_EN); - mtk_hdmi_phy_set_bits(hdmi_phy, HDMI_CON1, RG_HDMITX_PLL_BIAS_EN); - usleep_range(100, 150); - mtk_hdmi_phy_set_bits(hdmi_phy, HDMI_CON0, RG_HDMITX_PLL_EN); - usleep_range(100, 150); - mtk_hdmi_phy_set_bits(hdmi_phy, HDMI_CON1, RG_HDMITX_PLL_BIAS_LPF_EN); - mtk_hdmi_phy_set_bits(hdmi_phy, HDMI_CON1, RG_HDMITX_PLL_TXDIV_EN); - - return 0; -} - -static void mtk_hdmi_pll_unprepare(struct clk_hw *hw) -{ - struct mtk_hdmi_phy *hdmi_phy = to_mtk_hdmi_phy(hw); - - mtk_hdmi_phy_clear_bits(hdmi_phy, HDMI_CON1, RG_HDMITX_PLL_TXDIV_EN); - mtk_hdmi_phy_clear_bits(hdmi_phy, HDMI_CON1, RG_HDMITX_PLL_BIAS_LPF_EN); - usleep_range(100, 150); - mtk_hdmi_phy_clear_bits(hdmi_phy, HDMI_CON0, RG_HDMITX_PLL_EN); - usleep_range(100, 150); - mtk_hdmi_phy_clear_bits(hdmi_phy, HDMI_CON1, RG_HDMITX_PLL_BIAS_EN); - mtk_hdmi_phy_clear_bits(hdmi_phy, HDMI_CON0, RG_HDMITX_PLL_POSDIV); - mtk_hdmi_phy_clear_bits(hdmi_phy, HDMI_CON1, RG_HDMITX_PLL_AUTOK_EN); - usleep_range(100, 150); -} - -static long mtk_hdmi_pll_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *parent_rate) -{ - struct mtk_hdmi_phy *hdmi_phy = to_mtk_hdmi_phy(hw); - - hdmi_phy->pll_rate = rate; - if (rate <= 74250000) - *parent_rate = rate; - else - *parent_rate = rate / 2; - - return rate; -} - -static int mtk_hdmi_pll_set_rate(struct clk_hw *hw, unsigned long rate, - unsigned long parent_rate) -{ - struct mtk_hdmi_phy *hdmi_phy = to_mtk_hdmi_phy(hw); - unsigned int pre_div; - unsigned int div; - unsigned int pre_ibias; - unsigned int hdmi_ibias; - unsigned int imp_en; - - dev_dbg(hdmi_phy->dev, "%s: %lu Hz, parent: %lu Hz\n", __func__, - rate, parent_rate); - - if (rate <= 27000000) { - pre_div = 0; - div = 3; - } else if (rate <= 74250000) { - pre_div = 1; - div = 2; - } else { - pre_div = 1; - div = 1; - } - - mtk_hdmi_phy_mask(hdmi_phy, HDMI_CON0, - (pre_div << PREDIV_SHIFT), RG_HDMITX_PLL_PREDIV); - mtk_hdmi_phy_set_bits(hdmi_phy, HDMI_CON0, RG_HDMITX_PLL_POSDIV); - mtk_hdmi_phy_mask(hdmi_phy, HDMI_CON0, - (0x1 << PLL_IC_SHIFT) | (0x1 << PLL_IR_SHIFT), - RG_HDMITX_PLL_IC | RG_HDMITX_PLL_IR); - mtk_hdmi_phy_mask(hdmi_phy, HDMI_CON1, - (div << PLL_TXDIV_SHIFT), RG_HDMITX_PLL_TXDIV); - mtk_hdmi_phy_mask(hdmi_phy, HDMI_CON0, - (0x1 << PLL_FBKSEL_SHIFT) | (19 << PLL_FBKDIV_SHIFT), - RG_HDMITX_PLL_FBKSEL | RG_HDMITX_PLL_FBKDIV); - mtk_hdmi_phy_mask(hdmi_phy, HDMI_CON1, - (0x2 << PLL_DIVEN_SHIFT), RG_HDMITX_PLL_DIVEN); - mtk_hdmi_phy_mask(hdmi_phy, HDMI_CON0, - (0xc << PLL_BP_SHIFT) | (0x2 << PLL_BC_SHIFT) | - (0x1 << PLL_BR_SHIFT), - RG_HDMITX_PLL_BP | RG_HDMITX_PLL_BC | - RG_HDMITX_PLL_BR); - if (rate < 165000000) { - mtk_hdmi_phy_clear_bits(hdmi_phy, HDMI_CON3, - RG_HDMITX_PRD_IMP_EN); - pre_ibias = 0x3; - imp_en = 0x0; - hdmi_ibias = hdmi_phy->ibias; - } else { - mtk_hdmi_phy_set_bits(hdmi_phy, HDMI_CON3, - RG_HDMITX_PRD_IMP_EN); - pre_ibias = 0x6; - imp_en = 0xf; - hdmi_ibias = hdmi_phy->ibias_up; - } - mtk_hdmi_phy_mask(hdmi_phy, HDMI_CON4, - (pre_ibias << PRD_IBIAS_CLK_SHIFT) | - (pre_ibias << PRD_IBIAS_D2_SHIFT) | - (pre_ibias << PRD_IBIAS_D1_SHIFT) | - (pre_ibias << PRD_IBIAS_D0_SHIFT), - RG_HDMITX_PRD_IBIAS_CLK | - RG_HDMITX_PRD_IBIAS_D2 | - RG_HDMITX_PRD_IBIAS_D1 | - RG_HDMITX_PRD_IBIAS_D0); - mtk_hdmi_phy_mask(hdmi_phy, HDMI_CON3, - (imp_en << DRV_IMP_EN_SHIFT), - RG_HDMITX_DRV_IMP_EN); - mtk_hdmi_phy_mask(hdmi_phy, HDMI_CON6, - (hdmi_phy->drv_imp_clk << DRV_IMP_CLK_SHIFT) | - (hdmi_phy->drv_imp_d2 << DRV_IMP_D2_SHIFT) | - (hdmi_phy->drv_imp_d1 << DRV_IMP_D1_SHIFT) | - (hdmi_phy->drv_imp_d0 << DRV_IMP_D0_SHIFT), - RG_HDMITX_DRV_IMP_CLK | RG_HDMITX_DRV_IMP_D2 | - RG_HDMITX_DRV_IMP_D1 | RG_HDMITX_DRV_IMP_D0); - mtk_hdmi_phy_mask(hdmi_phy, HDMI_CON5, - (hdmi_ibias << DRV_IBIAS_CLK_SHIFT) | - (hdmi_ibias << DRV_IBIAS_D2_SHIFT) | - (hdmi_ibias << DRV_IBIAS_D1_SHIFT) | - (hdmi_ibias << DRV_IBIAS_D0_SHIFT), - RG_HDMITX_DRV_IBIAS_CLK | - RG_HDMITX_DRV_IBIAS_D2 | - RG_HDMITX_DRV_IBIAS_D1 | - RG_HDMITX_DRV_IBIAS_D0); - return 0; -} - -static unsigned long mtk_hdmi_pll_recalc_rate(struct clk_hw *hw, - unsigned long parent_rate) -{ - struct mtk_hdmi_phy *hdmi_phy = to_mtk_hdmi_phy(hw); - - return hdmi_phy->pll_rate; -} - -static const struct clk_ops mtk_hdmi_phy_pll_ops = { - .prepare = mtk_hdmi_pll_prepare, - .unprepare = mtk_hdmi_pll_unprepare, - .set_rate = mtk_hdmi_pll_set_rate, - .round_rate = mtk_hdmi_pll_round_rate, - .recalc_rate = mtk_hdmi_pll_recalc_rate, -}; - -static void mtk_hdmi_phy_enable_tmds(struct mtk_hdmi_phy *hdmi_phy) -{ - mtk_hdmi_phy_set_bits(hdmi_phy, HDMI_CON3, - RG_HDMITX_SER_EN | RG_HDMITX_PRD_EN | - RG_HDMITX_DRV_EN); - usleep_range(100, 150); -} - -static void mtk_hdmi_phy_disable_tmds(struct mtk_hdmi_phy *hdmi_phy) -{ - mtk_hdmi_phy_clear_bits(hdmi_phy, HDMI_CON3, - RG_HDMITX_DRV_EN | RG_HDMITX_PRD_EN | - RG_HDMITX_SER_EN); -} - -struct mtk_hdmi_phy_conf mtk_hdmi_phy_8173_conf = { - .flags = CLK_SET_RATE_PARENT | CLK_SET_RATE_GATE, - .hdmi_phy_clk_ops = &mtk_hdmi_phy_pll_ops, - .hdmi_phy_enable_tmds = mtk_hdmi_phy_enable_tmds, - .hdmi_phy_disable_tmds = mtk_hdmi_phy_disable_tmds, -}; - -MODULE_AUTHOR("Jie Qiu "); -MODULE_DESCRIPTION("MediaTek MT8173 HDMI PHY Driver"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/phy/mediatek/Kconfig b/drivers/phy/mediatek/Kconfig index dee757c957f2..50c5e9306e19 100644 --- a/drivers/phy/mediatek/Kconfig +++ b/drivers/phy/mediatek/Kconfig @@ -35,3 +35,10 @@ config PHY_MTK_XSPHY Enable this to support the SuperSpeedPlus XS-PHY transceiver for USB3.1 GEN2 controllers on MediaTek chips. The driver supports multiple USB2.0, USB3.1 GEN2 ports. + +config PHY_MTK_HDMI + tristate "MediaTek HDMI-PHY Driver" + depends on ARCH_MEDIATEK && OF + select GENERIC_PHY + help + Support HDMI PHY for Mediatek SoCs. diff --git a/drivers/phy/mediatek/Makefile b/drivers/phy/mediatek/Makefile index 08a8e6a97b1e..6325e38709ed 100644 --- a/drivers/phy/mediatek/Makefile +++ b/drivers/phy/mediatek/Makefile @@ -6,3 +6,8 @@ obj-$(CONFIG_PHY_MTK_TPHY) += phy-mtk-tphy.o obj-$(CONFIG_PHY_MTK_UFS) += phy-mtk-ufs.o obj-$(CONFIG_PHY_MTK_XSPHY) += phy-mtk-xsphy.o + +phy-mtk-hdmi-drv-y := phy-mtk-hdmi.o +phy-mtk-hdmi-drv-y += phy-mtk-hdmi-mt2701.o +phy-mtk-hdmi-drv-y += phy-mtk-hdmi-mt8173.o +obj-$(CONFIG_PHY_MTK_HDMI) += phy-mtk-hdmi-drv.o diff --git a/drivers/phy/mediatek/phy-mtk-hdmi-mt2701.c b/drivers/phy/mediatek/phy-mtk-hdmi-mt2701.c new file mode 100644 index 000000000000..a6cb1dea3d0c --- /dev/null +++ b/drivers/phy/mediatek/phy-mtk-hdmi-mt2701.c @@ -0,0 +1,248 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2018 MediaTek Inc. + * Author: Chunhui Dai + */ + +#include "phy-mtk-hdmi.h" + +#define HDMI_CON0 0x00 +#define RG_HDMITX_DRV_IBIAS 0 +#define RG_HDMITX_DRV_IBIAS_MASK (0x3f << 0) +#define RG_HDMITX_EN_SER 12 +#define RG_HDMITX_EN_SER_MASK (0x0f << 12) +#define RG_HDMITX_EN_SLDO 16 +#define RG_HDMITX_EN_SLDO_MASK (0x0f << 16) +#define RG_HDMITX_EN_PRED 20 +#define RG_HDMITX_EN_PRED_MASK (0x0f << 20) +#define RG_HDMITX_EN_IMP 24 +#define RG_HDMITX_EN_IMP_MASK (0x0f << 24) +#define RG_HDMITX_EN_DRV 28 +#define RG_HDMITX_EN_DRV_MASK (0x0f << 28) + +#define HDMI_CON1 0x04 +#define RG_HDMITX_PRED_IBIAS 18 +#define RG_HDMITX_PRED_IBIAS_MASK (0x0f << 18) +#define RG_HDMITX_PRED_IMP (0x01 << 22) +#define RG_HDMITX_DRV_IMP 26 +#define RG_HDMITX_DRV_IMP_MASK (0x3f << 26) + +#define HDMI_CON2 0x08 +#define RG_HDMITX_EN_TX_CKLDO (0x01 << 0) +#define RG_HDMITX_EN_TX_POSDIV (0x01 << 1) +#define RG_HDMITX_TX_POSDIV 3 +#define RG_HDMITX_TX_POSDIV_MASK (0x03 << 3) +#define RG_HDMITX_EN_MBIAS (0x01 << 6) +#define RG_HDMITX_MBIAS_LPF_EN (0x01 << 7) + +#define HDMI_CON4 0x10 +#define RG_HDMITX_RESERVE_MASK (0xffffffff << 0) + +#define HDMI_CON6 0x18 +#define RG_HTPLL_BR 0 +#define RG_HTPLL_BR_MASK (0x03 << 0) +#define RG_HTPLL_BC 2 +#define RG_HTPLL_BC_MASK (0x03 << 2) +#define RG_HTPLL_BP 4 +#define RG_HTPLL_BP_MASK (0x0f << 4) +#define RG_HTPLL_IR 8 +#define RG_HTPLL_IR_MASK (0x0f << 8) +#define RG_HTPLL_IC 12 +#define RG_HTPLL_IC_MASK (0x0f << 12) +#define RG_HTPLL_POSDIV 16 +#define RG_HTPLL_POSDIV_MASK (0x03 << 16) +#define RG_HTPLL_PREDIV 18 +#define RG_HTPLL_PREDIV_MASK (0x03 << 18) +#define RG_HTPLL_FBKSEL 20 +#define RG_HTPLL_FBKSEL_MASK (0x03 << 20) +#define RG_HTPLL_RLH_EN (0x01 << 22) +#define RG_HTPLL_FBKDIV 24 +#define RG_HTPLL_FBKDIV_MASK (0x7f << 24) +#define RG_HTPLL_EN (0x01 << 31) + +#define HDMI_CON7 0x1c +#define RG_HTPLL_AUTOK_EN (0x01 << 23) +#define RG_HTPLL_DIVEN 28 +#define RG_HTPLL_DIVEN_MASK (0x07 << 28) + +static int mtk_hdmi_pll_prepare(struct clk_hw *hw) +{ + struct mtk_hdmi_phy *hdmi_phy = to_mtk_hdmi_phy(hw); + + mtk_hdmi_phy_set_bits(hdmi_phy, HDMI_CON7, RG_HTPLL_AUTOK_EN); + mtk_hdmi_phy_clear_bits(hdmi_phy, HDMI_CON6, RG_HTPLL_RLH_EN); + mtk_hdmi_phy_set_bits(hdmi_phy, HDMI_CON6, RG_HTPLL_POSDIV_MASK); + mtk_hdmi_phy_set_bits(hdmi_phy, HDMI_CON2, RG_HDMITX_EN_MBIAS); + usleep_range(80, 100); + mtk_hdmi_phy_set_bits(hdmi_phy, HDMI_CON6, RG_HTPLL_EN); + mtk_hdmi_phy_set_bits(hdmi_phy, HDMI_CON2, RG_HDMITX_EN_TX_CKLDO); + mtk_hdmi_phy_set_bits(hdmi_phy, HDMI_CON0, RG_HDMITX_EN_SLDO_MASK); + usleep_range(80, 100); + mtk_hdmi_phy_set_bits(hdmi_phy, HDMI_CON2, RG_HDMITX_MBIAS_LPF_EN); + mtk_hdmi_phy_set_bits(hdmi_phy, HDMI_CON0, RG_HDMITX_EN_SER_MASK); + mtk_hdmi_phy_set_bits(hdmi_phy, HDMI_CON0, RG_HDMITX_EN_PRED_MASK); + mtk_hdmi_phy_set_bits(hdmi_phy, HDMI_CON0, RG_HDMITX_EN_DRV_MASK); + usleep_range(80, 100); + return 0; +} + +static void mtk_hdmi_pll_unprepare(struct clk_hw *hw) +{ + struct mtk_hdmi_phy *hdmi_phy = to_mtk_hdmi_phy(hw); + + mtk_hdmi_phy_clear_bits(hdmi_phy, HDMI_CON0, RG_HDMITX_EN_DRV_MASK); + mtk_hdmi_phy_clear_bits(hdmi_phy, HDMI_CON0, RG_HDMITX_EN_PRED_MASK); + mtk_hdmi_phy_clear_bits(hdmi_phy, HDMI_CON0, RG_HDMITX_EN_SER_MASK); + mtk_hdmi_phy_clear_bits(hdmi_phy, HDMI_CON2, RG_HDMITX_MBIAS_LPF_EN); + usleep_range(80, 100); + mtk_hdmi_phy_clear_bits(hdmi_phy, HDMI_CON0, RG_HDMITX_EN_SLDO_MASK); + mtk_hdmi_phy_clear_bits(hdmi_phy, HDMI_CON2, RG_HDMITX_EN_TX_CKLDO); + mtk_hdmi_phy_clear_bits(hdmi_phy, HDMI_CON6, RG_HTPLL_EN); + usleep_range(80, 100); + mtk_hdmi_phy_clear_bits(hdmi_phy, HDMI_CON2, RG_HDMITX_EN_MBIAS); + mtk_hdmi_phy_clear_bits(hdmi_phy, HDMI_CON6, RG_HTPLL_POSDIV_MASK); + mtk_hdmi_phy_clear_bits(hdmi_phy, HDMI_CON6, RG_HTPLL_RLH_EN); + mtk_hdmi_phy_clear_bits(hdmi_phy, HDMI_CON7, RG_HTPLL_AUTOK_EN); + usleep_range(80, 100); +} + +static long mtk_hdmi_pll_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *parent_rate) +{ + return rate; +} + +static int mtk_hdmi_pll_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct mtk_hdmi_phy *hdmi_phy = to_mtk_hdmi_phy(hw); + u32 pos_div; + + if (rate <= 64000000) + pos_div = 3; + else if (rate <= 128000000) + pos_div = 2; + else + pos_div = 1; + + mtk_hdmi_phy_set_bits(hdmi_phy, HDMI_CON6, RG_HTPLL_PREDIV_MASK); + mtk_hdmi_phy_set_bits(hdmi_phy, HDMI_CON6, RG_HTPLL_POSDIV_MASK); + mtk_hdmi_phy_set_bits(hdmi_phy, HDMI_CON2, RG_HDMITX_EN_TX_POSDIV); + mtk_hdmi_phy_mask(hdmi_phy, HDMI_CON6, (0x1 << RG_HTPLL_IC), + RG_HTPLL_IC_MASK); + mtk_hdmi_phy_mask(hdmi_phy, HDMI_CON6, (0x1 << RG_HTPLL_IR), + RG_HTPLL_IR_MASK); + mtk_hdmi_phy_mask(hdmi_phy, HDMI_CON2, (pos_div << RG_HDMITX_TX_POSDIV), + RG_HDMITX_TX_POSDIV_MASK); + mtk_hdmi_phy_mask(hdmi_phy, HDMI_CON6, (1 << RG_HTPLL_FBKSEL), + RG_HTPLL_FBKSEL_MASK); + mtk_hdmi_phy_mask(hdmi_phy, HDMI_CON6, (19 << RG_HTPLL_FBKDIV), + RG_HTPLL_FBKDIV_MASK); + mtk_hdmi_phy_mask(hdmi_phy, HDMI_CON7, (0x2 << RG_HTPLL_DIVEN), + RG_HTPLL_DIVEN_MASK); + mtk_hdmi_phy_mask(hdmi_phy, HDMI_CON6, (0xc << RG_HTPLL_BP), + RG_HTPLL_BP_MASK); + mtk_hdmi_phy_mask(hdmi_phy, HDMI_CON6, (0x2 << RG_HTPLL_BC), + RG_HTPLL_BC_MASK); + mtk_hdmi_phy_mask(hdmi_phy, HDMI_CON6, (0x1 << RG_HTPLL_BR), + RG_HTPLL_BR_MASK); + + mtk_hdmi_phy_clear_bits(hdmi_phy, HDMI_CON1, RG_HDMITX_PRED_IMP); + mtk_hdmi_phy_mask(hdmi_phy, HDMI_CON1, (0x3 << RG_HDMITX_PRED_IBIAS), + RG_HDMITX_PRED_IBIAS_MASK); + mtk_hdmi_phy_clear_bits(hdmi_phy, HDMI_CON0, RG_HDMITX_EN_IMP_MASK); + mtk_hdmi_phy_mask(hdmi_phy, HDMI_CON1, (0x28 << RG_HDMITX_DRV_IMP), + RG_HDMITX_DRV_IMP_MASK); + mtk_hdmi_phy_mask(hdmi_phy, HDMI_CON4, 0x28, RG_HDMITX_RESERVE_MASK); + mtk_hdmi_phy_mask(hdmi_phy, HDMI_CON0, (0xa << RG_HDMITX_DRV_IBIAS), + RG_HDMITX_DRV_IBIAS_MASK); + return 0; +} + +static unsigned long mtk_hdmi_pll_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct mtk_hdmi_phy *hdmi_phy = to_mtk_hdmi_phy(hw); + unsigned long out_rate, val; + + val = (readl(hdmi_phy->regs + HDMI_CON6) + & RG_HTPLL_PREDIV_MASK) >> RG_HTPLL_PREDIV; + switch (val) { + case 0x00: + out_rate = parent_rate; + break; + case 0x01: + out_rate = parent_rate / 2; + break; + default: + out_rate = parent_rate / 4; + break; + } + + val = (readl(hdmi_phy->regs + HDMI_CON6) + & RG_HTPLL_FBKDIV_MASK) >> RG_HTPLL_FBKDIV; + out_rate *= (val + 1) * 2; + val = (readl(hdmi_phy->regs + HDMI_CON2) + & RG_HDMITX_TX_POSDIV_MASK); + out_rate >>= (val >> RG_HDMITX_TX_POSDIV); + + if (readl(hdmi_phy->regs + HDMI_CON2) & RG_HDMITX_EN_TX_POSDIV) + out_rate /= 5; + + return out_rate; +} + +static const struct clk_ops mtk_hdmi_phy_pll_ops = { + .prepare = mtk_hdmi_pll_prepare, + .unprepare = mtk_hdmi_pll_unprepare, + .set_rate = mtk_hdmi_pll_set_rate, + .round_rate = mtk_hdmi_pll_round_rate, + .recalc_rate = mtk_hdmi_pll_recalc_rate, +}; + +static void mtk_hdmi_phy_enable_tmds(struct mtk_hdmi_phy *hdmi_phy) +{ + mtk_hdmi_phy_set_bits(hdmi_phy, HDMI_CON7, RG_HTPLL_AUTOK_EN); + mtk_hdmi_phy_clear_bits(hdmi_phy, HDMI_CON6, RG_HTPLL_RLH_EN); + mtk_hdmi_phy_set_bits(hdmi_phy, HDMI_CON6, RG_HTPLL_POSDIV_MASK); + mtk_hdmi_phy_set_bits(hdmi_phy, HDMI_CON2, RG_HDMITX_EN_MBIAS); + usleep_range(80, 100); + mtk_hdmi_phy_set_bits(hdmi_phy, HDMI_CON6, RG_HTPLL_EN); + mtk_hdmi_phy_set_bits(hdmi_phy, HDMI_CON2, RG_HDMITX_EN_TX_CKLDO); + mtk_hdmi_phy_set_bits(hdmi_phy, HDMI_CON0, RG_HDMITX_EN_SLDO_MASK); + usleep_range(80, 100); + mtk_hdmi_phy_set_bits(hdmi_phy, HDMI_CON2, RG_HDMITX_MBIAS_LPF_EN); + mtk_hdmi_phy_set_bits(hdmi_phy, HDMI_CON0, RG_HDMITX_EN_SER_MASK); + mtk_hdmi_phy_set_bits(hdmi_phy, HDMI_CON0, RG_HDMITX_EN_PRED_MASK); + mtk_hdmi_phy_set_bits(hdmi_phy, HDMI_CON0, RG_HDMITX_EN_DRV_MASK); + usleep_range(80, 100); +} + +static void mtk_hdmi_phy_disable_tmds(struct mtk_hdmi_phy *hdmi_phy) +{ + mtk_hdmi_phy_clear_bits(hdmi_phy, HDMI_CON0, RG_HDMITX_EN_DRV_MASK); + mtk_hdmi_phy_clear_bits(hdmi_phy, HDMI_CON0, RG_HDMITX_EN_PRED_MASK); + mtk_hdmi_phy_clear_bits(hdmi_phy, HDMI_CON0, RG_HDMITX_EN_SER_MASK); + mtk_hdmi_phy_clear_bits(hdmi_phy, HDMI_CON2, RG_HDMITX_MBIAS_LPF_EN); + usleep_range(80, 100); + mtk_hdmi_phy_clear_bits(hdmi_phy, HDMI_CON0, RG_HDMITX_EN_SLDO_MASK); + mtk_hdmi_phy_clear_bits(hdmi_phy, HDMI_CON2, RG_HDMITX_EN_TX_CKLDO); + mtk_hdmi_phy_clear_bits(hdmi_phy, HDMI_CON6, RG_HTPLL_EN); + usleep_range(80, 100); + mtk_hdmi_phy_clear_bits(hdmi_phy, HDMI_CON2, RG_HDMITX_EN_MBIAS); + mtk_hdmi_phy_clear_bits(hdmi_phy, HDMI_CON6, RG_HTPLL_POSDIV_MASK); + mtk_hdmi_phy_clear_bits(hdmi_phy, HDMI_CON6, RG_HTPLL_RLH_EN); + mtk_hdmi_phy_clear_bits(hdmi_phy, HDMI_CON7, RG_HTPLL_AUTOK_EN); + usleep_range(80, 100); +} + +struct mtk_hdmi_phy_conf mtk_hdmi_phy_2701_conf = { + .flags = CLK_SET_RATE_GATE, + .hdmi_phy_clk_ops = &mtk_hdmi_phy_pll_ops, + .hdmi_phy_enable_tmds = mtk_hdmi_phy_enable_tmds, + .hdmi_phy_disable_tmds = mtk_hdmi_phy_disable_tmds, +}; + +MODULE_AUTHOR("Chunhui Dai "); +MODULE_DESCRIPTION("MediaTek HDMI PHY Driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/phy/mediatek/phy-mtk-hdmi-mt8173.c b/drivers/phy/mediatek/phy-mtk-hdmi-mt8173.c new file mode 100644 index 000000000000..6cdfdf5a698a --- /dev/null +++ b/drivers/phy/mediatek/phy-mtk-hdmi-mt8173.c @@ -0,0 +1,282 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2014 MediaTek Inc. + * Author: Jie Qiu + */ + +#include "phy-mtk-hdmi.h" + +#define HDMI_CON0 0x00 +#define RG_HDMITX_PLL_EN BIT(31) +#define RG_HDMITX_PLL_FBKDIV (0x7f << 24) +#define PLL_FBKDIV_SHIFT 24 +#define RG_HDMITX_PLL_FBKSEL (0x3 << 22) +#define PLL_FBKSEL_SHIFT 22 +#define RG_HDMITX_PLL_PREDIV (0x3 << 20) +#define PREDIV_SHIFT 20 +#define RG_HDMITX_PLL_POSDIV (0x3 << 18) +#define POSDIV_SHIFT 18 +#define RG_HDMITX_PLL_RST_DLY (0x3 << 16) +#define RG_HDMITX_PLL_IR (0xf << 12) +#define PLL_IR_SHIFT 12 +#define RG_HDMITX_PLL_IC (0xf << 8) +#define PLL_IC_SHIFT 8 +#define RG_HDMITX_PLL_BP (0xf << 4) +#define PLL_BP_SHIFT 4 +#define RG_HDMITX_PLL_BR (0x3 << 2) +#define PLL_BR_SHIFT 2 +#define RG_HDMITX_PLL_BC (0x3 << 0) +#define PLL_BC_SHIFT 0 +#define HDMI_CON1 0x04 +#define RG_HDMITX_PLL_DIVEN (0x7 << 29) +#define PLL_DIVEN_SHIFT 29 +#define RG_HDMITX_PLL_AUTOK_EN BIT(28) +#define RG_HDMITX_PLL_AUTOK_KF (0x3 << 26) +#define RG_HDMITX_PLL_AUTOK_KS (0x3 << 24) +#define RG_HDMITX_PLL_AUTOK_LOAD BIT(23) +#define RG_HDMITX_PLL_BAND (0x3f << 16) +#define RG_HDMITX_PLL_REF_SEL BIT(15) +#define RG_HDMITX_PLL_BIAS_EN BIT(14) +#define RG_HDMITX_PLL_BIAS_LPF_EN BIT(13) +#define RG_HDMITX_PLL_TXDIV_EN BIT(12) +#define RG_HDMITX_PLL_TXDIV (0x3 << 10) +#define PLL_TXDIV_SHIFT 10 +#define RG_HDMITX_PLL_LVROD_EN BIT(9) +#define RG_HDMITX_PLL_MONVC_EN BIT(8) +#define RG_HDMITX_PLL_MONCK_EN BIT(7) +#define RG_HDMITX_PLL_MONREF_EN BIT(6) +#define RG_HDMITX_PLL_TST_EN BIT(5) +#define RG_HDMITX_PLL_TST_CK_EN BIT(4) +#define RG_HDMITX_PLL_TST_SEL (0xf << 0) +#define HDMI_CON2 0x08 +#define RGS_HDMITX_PLL_AUTOK_BAND (0x7f << 8) +#define RGS_HDMITX_PLL_AUTOK_FAIL BIT(1) +#define RG_HDMITX_EN_TX_CKLDO BIT(0) +#define HDMI_CON3 0x0c +#define RG_HDMITX_SER_EN (0xf << 28) +#define RG_HDMITX_PRD_EN (0xf << 24) +#define RG_HDMITX_PRD_IMP_EN (0xf << 20) +#define RG_HDMITX_DRV_EN (0xf << 16) +#define RG_HDMITX_DRV_IMP_EN (0xf << 12) +#define DRV_IMP_EN_SHIFT 12 +#define RG_HDMITX_MHLCK_FORCE BIT(10) +#define RG_HDMITX_MHLCK_PPIX_EN BIT(9) +#define RG_HDMITX_MHLCK_EN BIT(8) +#define RG_HDMITX_SER_DIN_SEL (0xf << 4) +#define RG_HDMITX_SER_5T1_BIST_EN BIT(3) +#define RG_HDMITX_SER_BIST_TOG BIT(2) +#define RG_HDMITX_SER_DIN_TOG BIT(1) +#define RG_HDMITX_SER_CLKDIG_INV BIT(0) +#define HDMI_CON4 0x10 +#define RG_HDMITX_PRD_IBIAS_CLK (0xf << 24) +#define RG_HDMITX_PRD_IBIAS_D2 (0xf << 16) +#define RG_HDMITX_PRD_IBIAS_D1 (0xf << 8) +#define RG_HDMITX_PRD_IBIAS_D0 (0xf << 0) +#define PRD_IBIAS_CLK_SHIFT 24 +#define PRD_IBIAS_D2_SHIFT 16 +#define PRD_IBIAS_D1_SHIFT 8 +#define PRD_IBIAS_D0_SHIFT 0 +#define HDMI_CON5 0x14 +#define RG_HDMITX_DRV_IBIAS_CLK (0x3f << 24) +#define RG_HDMITX_DRV_IBIAS_D2 (0x3f << 16) +#define RG_HDMITX_DRV_IBIAS_D1 (0x3f << 8) +#define RG_HDMITX_DRV_IBIAS_D0 (0x3f << 0) +#define DRV_IBIAS_CLK_SHIFT 24 +#define DRV_IBIAS_D2_SHIFT 16 +#define DRV_IBIAS_D1_SHIFT 8 +#define DRV_IBIAS_D0_SHIFT 0 +#define HDMI_CON6 0x18 +#define RG_HDMITX_DRV_IMP_CLK (0x3f << 24) +#define RG_HDMITX_DRV_IMP_D2 (0x3f << 16) +#define RG_HDMITX_DRV_IMP_D1 (0x3f << 8) +#define RG_HDMITX_DRV_IMP_D0 (0x3f << 0) +#define DRV_IMP_CLK_SHIFT 24 +#define DRV_IMP_D2_SHIFT 16 +#define DRV_IMP_D1_SHIFT 8 +#define DRV_IMP_D0_SHIFT 0 +#define HDMI_CON7 0x1c +#define RG_HDMITX_MHLCK_DRV_IBIAS (0x1f << 27) +#define RG_HDMITX_SER_DIN (0x3ff << 16) +#define RG_HDMITX_CHLDC_TST (0xf << 12) +#define RG_HDMITX_CHLCK_TST (0xf << 8) +#define RG_HDMITX_RESERVE (0xff << 0) +#define HDMI_CON8 0x20 +#define RGS_HDMITX_2T1_LEV (0xf << 16) +#define RGS_HDMITX_2T1_EDG (0xf << 12) +#define RGS_HDMITX_5T1_LEV (0xf << 8) +#define RGS_HDMITX_5T1_EDG (0xf << 4) +#define RGS_HDMITX_PLUG_TST BIT(0) + +static int mtk_hdmi_pll_prepare(struct clk_hw *hw) +{ + struct mtk_hdmi_phy *hdmi_phy = to_mtk_hdmi_phy(hw); + + mtk_hdmi_phy_set_bits(hdmi_phy, HDMI_CON1, RG_HDMITX_PLL_AUTOK_EN); + mtk_hdmi_phy_set_bits(hdmi_phy, HDMI_CON0, RG_HDMITX_PLL_POSDIV); + mtk_hdmi_phy_clear_bits(hdmi_phy, HDMI_CON3, RG_HDMITX_MHLCK_EN); + mtk_hdmi_phy_set_bits(hdmi_phy, HDMI_CON1, RG_HDMITX_PLL_BIAS_EN); + usleep_range(100, 150); + mtk_hdmi_phy_set_bits(hdmi_phy, HDMI_CON0, RG_HDMITX_PLL_EN); + usleep_range(100, 150); + mtk_hdmi_phy_set_bits(hdmi_phy, HDMI_CON1, RG_HDMITX_PLL_BIAS_LPF_EN); + mtk_hdmi_phy_set_bits(hdmi_phy, HDMI_CON1, RG_HDMITX_PLL_TXDIV_EN); + + return 0; +} + +static void mtk_hdmi_pll_unprepare(struct clk_hw *hw) +{ + struct mtk_hdmi_phy *hdmi_phy = to_mtk_hdmi_phy(hw); + + mtk_hdmi_phy_clear_bits(hdmi_phy, HDMI_CON1, RG_HDMITX_PLL_TXDIV_EN); + mtk_hdmi_phy_clear_bits(hdmi_phy, HDMI_CON1, RG_HDMITX_PLL_BIAS_LPF_EN); + usleep_range(100, 150); + mtk_hdmi_phy_clear_bits(hdmi_phy, HDMI_CON0, RG_HDMITX_PLL_EN); + usleep_range(100, 150); + mtk_hdmi_phy_clear_bits(hdmi_phy, HDMI_CON1, RG_HDMITX_PLL_BIAS_EN); + mtk_hdmi_phy_clear_bits(hdmi_phy, HDMI_CON0, RG_HDMITX_PLL_POSDIV); + mtk_hdmi_phy_clear_bits(hdmi_phy, HDMI_CON1, RG_HDMITX_PLL_AUTOK_EN); + usleep_range(100, 150); +} + +static long mtk_hdmi_pll_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *parent_rate) +{ + struct mtk_hdmi_phy *hdmi_phy = to_mtk_hdmi_phy(hw); + + hdmi_phy->pll_rate = rate; + if (rate <= 74250000) + *parent_rate = rate; + else + *parent_rate = rate / 2; + + return rate; +} + +static int mtk_hdmi_pll_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct mtk_hdmi_phy *hdmi_phy = to_mtk_hdmi_phy(hw); + unsigned int pre_div; + unsigned int div; + unsigned int pre_ibias; + unsigned int hdmi_ibias; + unsigned int imp_en; + + dev_dbg(hdmi_phy->dev, "%s: %lu Hz, parent: %lu Hz\n", __func__, + rate, parent_rate); + + if (rate <= 27000000) { + pre_div = 0; + div = 3; + } else if (rate <= 74250000) { + pre_div = 1; + div = 2; + } else { + pre_div = 1; + div = 1; + } + + mtk_hdmi_phy_mask(hdmi_phy, HDMI_CON0, + (pre_div << PREDIV_SHIFT), RG_HDMITX_PLL_PREDIV); + mtk_hdmi_phy_set_bits(hdmi_phy, HDMI_CON0, RG_HDMITX_PLL_POSDIV); + mtk_hdmi_phy_mask(hdmi_phy, HDMI_CON0, + (0x1 << PLL_IC_SHIFT) | (0x1 << PLL_IR_SHIFT), + RG_HDMITX_PLL_IC | RG_HDMITX_PLL_IR); + mtk_hdmi_phy_mask(hdmi_phy, HDMI_CON1, + (div << PLL_TXDIV_SHIFT), RG_HDMITX_PLL_TXDIV); + mtk_hdmi_phy_mask(hdmi_phy, HDMI_CON0, + (0x1 << PLL_FBKSEL_SHIFT) | (19 << PLL_FBKDIV_SHIFT), + RG_HDMITX_PLL_FBKSEL | RG_HDMITX_PLL_FBKDIV); + mtk_hdmi_phy_mask(hdmi_phy, HDMI_CON1, + (0x2 << PLL_DIVEN_SHIFT), RG_HDMITX_PLL_DIVEN); + mtk_hdmi_phy_mask(hdmi_phy, HDMI_CON0, + (0xc << PLL_BP_SHIFT) | (0x2 << PLL_BC_SHIFT) | + (0x1 << PLL_BR_SHIFT), + RG_HDMITX_PLL_BP | RG_HDMITX_PLL_BC | + RG_HDMITX_PLL_BR); + if (rate < 165000000) { + mtk_hdmi_phy_clear_bits(hdmi_phy, HDMI_CON3, + RG_HDMITX_PRD_IMP_EN); + pre_ibias = 0x3; + imp_en = 0x0; + hdmi_ibias = hdmi_phy->ibias; + } else { + mtk_hdmi_phy_set_bits(hdmi_phy, HDMI_CON3, + RG_HDMITX_PRD_IMP_EN); + pre_ibias = 0x6; + imp_en = 0xf; + hdmi_ibias = hdmi_phy->ibias_up; + } + mtk_hdmi_phy_mask(hdmi_phy, HDMI_CON4, + (pre_ibias << PRD_IBIAS_CLK_SHIFT) | + (pre_ibias << PRD_IBIAS_D2_SHIFT) | + (pre_ibias << PRD_IBIAS_D1_SHIFT) | + (pre_ibias << PRD_IBIAS_D0_SHIFT), + RG_HDMITX_PRD_IBIAS_CLK | + RG_HDMITX_PRD_IBIAS_D2 | + RG_HDMITX_PRD_IBIAS_D1 | + RG_HDMITX_PRD_IBIAS_D0); + mtk_hdmi_phy_mask(hdmi_phy, HDMI_CON3, + (imp_en << DRV_IMP_EN_SHIFT), + RG_HDMITX_DRV_IMP_EN); + mtk_hdmi_phy_mask(hdmi_phy, HDMI_CON6, + (hdmi_phy->drv_imp_clk << DRV_IMP_CLK_SHIFT) | + (hdmi_phy->drv_imp_d2 << DRV_IMP_D2_SHIFT) | + (hdmi_phy->drv_imp_d1 << DRV_IMP_D1_SHIFT) | + (hdmi_phy->drv_imp_d0 << DRV_IMP_D0_SHIFT), + RG_HDMITX_DRV_IMP_CLK | RG_HDMITX_DRV_IMP_D2 | + RG_HDMITX_DRV_IMP_D1 | RG_HDMITX_DRV_IMP_D0); + mtk_hdmi_phy_mask(hdmi_phy, HDMI_CON5, + (hdmi_ibias << DRV_IBIAS_CLK_SHIFT) | + (hdmi_ibias << DRV_IBIAS_D2_SHIFT) | + (hdmi_ibias << DRV_IBIAS_D1_SHIFT) | + (hdmi_ibias << DRV_IBIAS_D0_SHIFT), + RG_HDMITX_DRV_IBIAS_CLK | + RG_HDMITX_DRV_IBIAS_D2 | + RG_HDMITX_DRV_IBIAS_D1 | + RG_HDMITX_DRV_IBIAS_D0); + return 0; +} + +static unsigned long mtk_hdmi_pll_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct mtk_hdmi_phy *hdmi_phy = to_mtk_hdmi_phy(hw); + + return hdmi_phy->pll_rate; +} + +static const struct clk_ops mtk_hdmi_phy_pll_ops = { + .prepare = mtk_hdmi_pll_prepare, + .unprepare = mtk_hdmi_pll_unprepare, + .set_rate = mtk_hdmi_pll_set_rate, + .round_rate = mtk_hdmi_pll_round_rate, + .recalc_rate = mtk_hdmi_pll_recalc_rate, +}; + +static void mtk_hdmi_phy_enable_tmds(struct mtk_hdmi_phy *hdmi_phy) +{ + mtk_hdmi_phy_set_bits(hdmi_phy, HDMI_CON3, + RG_HDMITX_SER_EN | RG_HDMITX_PRD_EN | + RG_HDMITX_DRV_EN); + usleep_range(100, 150); +} + +static void mtk_hdmi_phy_disable_tmds(struct mtk_hdmi_phy *hdmi_phy) +{ + mtk_hdmi_phy_clear_bits(hdmi_phy, HDMI_CON3, + RG_HDMITX_DRV_EN | RG_HDMITX_PRD_EN | + RG_HDMITX_SER_EN); +} + +struct mtk_hdmi_phy_conf mtk_hdmi_phy_8173_conf = { + .flags = CLK_SET_RATE_PARENT | CLK_SET_RATE_GATE, + .hdmi_phy_clk_ops = &mtk_hdmi_phy_pll_ops, + .hdmi_phy_enable_tmds = mtk_hdmi_phy_enable_tmds, + .hdmi_phy_disable_tmds = mtk_hdmi_phy_disable_tmds, +}; + +MODULE_AUTHOR("Jie Qiu "); +MODULE_DESCRIPTION("MediaTek MT8173 HDMI PHY Driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/phy/mediatek/phy-mtk-hdmi.c b/drivers/phy/mediatek/phy-mtk-hdmi.c new file mode 100644 index 000000000000..8fc83f01a720 --- /dev/null +++ b/drivers/phy/mediatek/phy-mtk-hdmi.c @@ -0,0 +1,211 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2018 MediaTek Inc. + * Author: Jie Qiu + */ + +#include "phy-mtk-hdmi.h" + +static int mtk_hdmi_phy_power_on(struct phy *phy); +static int mtk_hdmi_phy_power_off(struct phy *phy); + +static const struct phy_ops mtk_hdmi_phy_dev_ops = { + .power_on = mtk_hdmi_phy_power_on, + .power_off = mtk_hdmi_phy_power_off, + .owner = THIS_MODULE, +}; + +void mtk_hdmi_phy_clear_bits(struct mtk_hdmi_phy *hdmi_phy, u32 offset, + u32 bits) +{ + void __iomem *reg = hdmi_phy->regs + offset; + u32 tmp; + + tmp = readl(reg); + tmp &= ~bits; + writel(tmp, reg); +} + +void mtk_hdmi_phy_set_bits(struct mtk_hdmi_phy *hdmi_phy, u32 offset, + u32 bits) +{ + void __iomem *reg = hdmi_phy->regs + offset; + u32 tmp; + + tmp = readl(reg); + tmp |= bits; + writel(tmp, reg); +} + +void mtk_hdmi_phy_mask(struct mtk_hdmi_phy *hdmi_phy, u32 offset, + u32 val, u32 mask) +{ + void __iomem *reg = hdmi_phy->regs + offset; + u32 tmp; + + tmp = readl(reg); + tmp = (tmp & ~mask) | (val & mask); + writel(tmp, reg); +} + +inline struct mtk_hdmi_phy *to_mtk_hdmi_phy(struct clk_hw *hw) +{ + return container_of(hw, struct mtk_hdmi_phy, pll_hw); +} + +static int mtk_hdmi_phy_power_on(struct phy *phy) +{ + struct mtk_hdmi_phy *hdmi_phy = phy_get_drvdata(phy); + int ret; + + ret = clk_prepare_enable(hdmi_phy->pll); + if (ret < 0) + return ret; + + hdmi_phy->conf->hdmi_phy_enable_tmds(hdmi_phy); + return 0; +} + +static int mtk_hdmi_phy_power_off(struct phy *phy) +{ + struct mtk_hdmi_phy *hdmi_phy = phy_get_drvdata(phy); + + hdmi_phy->conf->hdmi_phy_disable_tmds(hdmi_phy); + clk_disable_unprepare(hdmi_phy->pll); + + return 0; +} + +static const struct phy_ops * +mtk_hdmi_phy_dev_get_ops(const struct mtk_hdmi_phy *hdmi_phy) +{ + if (hdmi_phy && hdmi_phy->conf && + hdmi_phy->conf->hdmi_phy_enable_tmds && + hdmi_phy->conf->hdmi_phy_disable_tmds) + return &mtk_hdmi_phy_dev_ops; + + dev_err(hdmi_phy->dev, "Failed to get dev ops of phy\n"); + return NULL; +} + +static void mtk_hdmi_phy_clk_get_data(struct mtk_hdmi_phy *hdmi_phy, + struct clk_init_data *clk_init) +{ + clk_init->flags = hdmi_phy->conf->flags; + clk_init->ops = hdmi_phy->conf->hdmi_phy_clk_ops; +} + +static int mtk_hdmi_phy_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct mtk_hdmi_phy *hdmi_phy; + struct resource *mem; + struct clk *ref_clk; + const char *ref_clk_name; + struct clk_init_data clk_init = { + .num_parents = 1, + .parent_names = (const char * const *)&ref_clk_name, + }; + + struct phy *phy; + struct phy_provider *phy_provider; + int ret; + + hdmi_phy = devm_kzalloc(dev, sizeof(*hdmi_phy), GFP_KERNEL); + if (!hdmi_phy) + return -ENOMEM; + + mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + hdmi_phy->regs = devm_ioremap_resource(dev, mem); + if (IS_ERR(hdmi_phy->regs)) { + ret = PTR_ERR(hdmi_phy->regs); + dev_err(dev, "Failed to get memory resource: %d\n", ret); + return ret; + } + + ref_clk = devm_clk_get(dev, "pll_ref"); + if (IS_ERR(ref_clk)) { + ret = PTR_ERR(ref_clk); + dev_err(&pdev->dev, "Failed to get PLL reference clock: %d\n", + ret); + return ret; + } + ref_clk_name = __clk_get_name(ref_clk); + + ret = of_property_read_string(dev->of_node, "clock-output-names", + &clk_init.name); + if (ret < 0) { + dev_err(dev, "Failed to read clock-output-names: %d\n", ret); + return ret; + } + + hdmi_phy->dev = dev; + hdmi_phy->conf = + (struct mtk_hdmi_phy_conf *)of_device_get_match_data(dev); + mtk_hdmi_phy_clk_get_data(hdmi_phy, &clk_init); + hdmi_phy->pll_hw.init = &clk_init; + hdmi_phy->pll = devm_clk_register(dev, &hdmi_phy->pll_hw); + if (IS_ERR(hdmi_phy->pll)) { + ret = PTR_ERR(hdmi_phy->pll); + dev_err(dev, "Failed to register PLL: %d\n", ret); + return ret; + } + + ret = of_property_read_u32(dev->of_node, "mediatek,ibias", + &hdmi_phy->ibias); + if (ret < 0) { + dev_err(&pdev->dev, "Failed to get ibias: %d\n", ret); + return ret; + } + + ret = of_property_read_u32(dev->of_node, "mediatek,ibias_up", + &hdmi_phy->ibias_up); + if (ret < 0) { + dev_err(&pdev->dev, "Failed to get ibias up: %d\n", ret); + return ret; + } + + dev_info(dev, "Using default TX DRV impedance: 4.2k/36\n"); + hdmi_phy->drv_imp_clk = 0x30; + hdmi_phy->drv_imp_d2 = 0x30; + hdmi_phy->drv_imp_d1 = 0x30; + hdmi_phy->drv_imp_d0 = 0x30; + + phy = devm_phy_create(dev, NULL, mtk_hdmi_phy_dev_get_ops(hdmi_phy)); + if (IS_ERR(phy)) { + dev_err(dev, "Failed to create HDMI PHY\n"); + return PTR_ERR(phy); + } + phy_set_drvdata(phy, hdmi_phy); + + phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); + if (IS_ERR(phy_provider)) { + dev_err(dev, "Failed to register HDMI PHY\n"); + return PTR_ERR(phy_provider); + } + + return of_clk_add_provider(dev->of_node, of_clk_src_simple_get, + hdmi_phy->pll); +} + +static const struct of_device_id mtk_hdmi_phy_match[] = { + { .compatible = "mediatek,mt2701-hdmi-phy", + .data = &mtk_hdmi_phy_2701_conf, + }, + { .compatible = "mediatek,mt8173-hdmi-phy", + .data = &mtk_hdmi_phy_8173_conf, + }, + {}, +}; + +struct platform_driver mtk_hdmi_phy_driver = { + .probe = mtk_hdmi_phy_probe, + .driver = { + .name = "mediatek-hdmi-phy", + .of_match_table = mtk_hdmi_phy_match, + }, +}; +module_platform_driver(mtk_hdmi_phy_driver); + +MODULE_DESCRIPTION("MediaTek HDMI PHY Driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/phy/mediatek/phy-mtk-hdmi.h b/drivers/phy/mediatek/phy-mtk-hdmi.h new file mode 100644 index 000000000000..b13e1d5f8e78 --- /dev/null +++ b/drivers/phy/mediatek/phy-mtk-hdmi.h @@ -0,0 +1,55 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2018 MediaTek Inc. + * Author: Chunhui Dai + */ + +#ifndef _MTK_HDMI_PHY_H +#define _MTK_HDMI_PHY_H +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct mtk_hdmi_phy; + +struct mtk_hdmi_phy_conf { + unsigned long flags; + const struct clk_ops *hdmi_phy_clk_ops; + void (*hdmi_phy_enable_tmds)(struct mtk_hdmi_phy *hdmi_phy); + void (*hdmi_phy_disable_tmds)(struct mtk_hdmi_phy *hdmi_phy); +}; + +struct mtk_hdmi_phy { + void __iomem *regs; + struct device *dev; + struct mtk_hdmi_phy_conf *conf; + struct clk *pll; + struct clk_hw pll_hw; + unsigned long pll_rate; + unsigned char drv_imp_clk; + unsigned char drv_imp_d2; + unsigned char drv_imp_d1; + unsigned char drv_imp_d0; + unsigned int ibias; + unsigned int ibias_up; +}; + +void mtk_hdmi_phy_clear_bits(struct mtk_hdmi_phy *hdmi_phy, u32 offset, + u32 bits); +void mtk_hdmi_phy_set_bits(struct mtk_hdmi_phy *hdmi_phy, u32 offset, + u32 bits); +void mtk_hdmi_phy_mask(struct mtk_hdmi_phy *hdmi_phy, u32 offset, + u32 val, u32 mask); +struct mtk_hdmi_phy *to_mtk_hdmi_phy(struct clk_hw *hw); + +extern struct mtk_hdmi_phy_conf mtk_hdmi_phy_8173_conf; +extern struct mtk_hdmi_phy_conf mtk_hdmi_phy_2701_conf; + +#endif /* _MTK_HDMI_PHY_H */ -- cgit v1.2.3