From 4e90a6eb769a2041a81efb3c288a087790ae885d Mon Sep 17 00:00:00 2001 From: chunhui dai Date: Wed, 3 Oct 2018 11:41:41 +0800 Subject: drm/mediatek: add refcount for DPI power on/off After the kernel 4.4, the DRM disable flow was changed, if DPI was disableed before CRTC, it will cause warning message as following: ------------[ cut here ]------------ WARNING: CPU: 0 PID: 1339 at ../../linux/linux-4.4.24-mtk/drivers/gpu/drm/drm_irq.c:1326 drm_wait_one_vblank+0x188/0x18c() vblank wait timed out on crtc 0 Modules linked in: bridge mt8521p_ir_shim(O) i2c_eeprom(O) mtk_m4(O) fuse_ctrl(O) virtual_block(O) caamkeys(PO) chk(PO) amperctl(O) ledctl(O) apple_auth(PO) micctl(O) sensors(PO) lla(O) sdd(PO) ice40_fpga(O) psmon(O) event_queue(PO) utils(O) blackbox(O) CPU: 0 PID: 1339 Comm: kworker/0:1 Tainted: P W O 4.4.24 #1 Hardware name: Mediatek Cortex-A7 (Device Tree) Workqueue: events drm_mode_rmfb_work_fn [] (unwind_backtrace) from [] (show_stack+0x20/0x24) [] (show_stack) from [] (dump_stack+0x98/0xac) [] (dump_stack) from [] (warn_slowpath_common+0x94/0xc4) [] (warn_slowpath_common) from [] (warn_slowpath_fmt+0x40/0x48) [] (warn_slowpath_fmt) from [] (drm_wait_one_vblank+0x188/0x18c) [] (drm_wait_one_vblank) from [] (drm_crtc_wait_one_vblank+0x28/0x2c) [] (drm_crtc_wait_one_vblank) from [] (mtk_drm_crtc_disable+0x78/0x240) [] (mtk_drm_crtc_disable) from [] (drm_atomic_helper_commit_modeset_disables+0x128/0x3b8) [] (drm_atomic_helper_commit_modeset_disables) from [] (mtk_atomic_complete+0x74/0xb4) [] (mtk_atomic_complete) from [] (mtk_atomic_commit+0x68/0x98) [] (mtk_atomic_commit) from [] (drm_atomic_commit+0x54/0x74) [] (drm_atomic_commit) from [] (drm_atomic_helper_set_config+0x7c/0xa0) [] (drm_atomic_helper_set_config) from [] (drm_mode_set_config_internal+0x68/0xe4) [] (drm_mode_set_config_internal) from [] (drm_framebuffer_remove+0xe4/0x120) [] (drm_framebuffer_remove) from [] (drm_mode_rmfb_work_fn+0x48/0x58) [] (drm_mode_rmfb_work_fn) from [] (process_one_work+0x154/0x50c) [] (process_one_work) from [] (worker_thread+0x284/0x568) [] (worker_thread) from [] (kthread+0xec/0x104) [] (kthread) from [] (ret_from_fork+0x14/0x3c) ---[ end trace 12ae5358e992abd5 ]--- so, we add refcount for DPI power on/off to protect the flow. Signed-off-by: Bibby Hsieh Signed-off-by: chunhui dai Signed-off-by: CK Hu --- drivers/gpu/drm/mediatek/mtk_dpi.c | 43 ++++++++++++-------------------------- 1 file changed, 13 insertions(+), 30 deletions(-) (limited to 'drivers/gpu/drm/mediatek') diff --git a/drivers/gpu/drm/mediatek/mtk_dpi.c b/drivers/gpu/drm/mediatek/mtk_dpi.c index 6c0ea39d5739..5ede1ddbaa1a 100644 --- a/drivers/gpu/drm/mediatek/mtk_dpi.c +++ b/drivers/gpu/drm/mediatek/mtk_dpi.c @@ -76,8 +76,7 @@ struct mtk_dpi { enum mtk_dpi_out_yc_map yc_map; enum mtk_dpi_out_bit_num bit_num; enum mtk_dpi_out_channel_swap channel_swap; - bool power_sta; - u8 power_ctl; + int refcount; }; static inline struct mtk_dpi *mtk_dpi_from_encoder(struct drm_encoder *e) @@ -90,11 +89,6 @@ enum mtk_dpi_polarity { MTK_DPI_POLARITY_FALLING, }; -enum mtk_dpi_power_ctl { - DPI_POWER_START = BIT(0), - DPI_POWER_ENABLE = BIT(1), -}; - struct mtk_dpi_polarities { enum mtk_dpi_polarity de_pol; enum mtk_dpi_polarity ck_pol; @@ -367,40 +361,30 @@ static void mtk_dpi_config_color_format(struct mtk_dpi *dpi, } } -static void mtk_dpi_power_off(struct mtk_dpi *dpi, enum mtk_dpi_power_ctl pctl) +static void mtk_dpi_power_off(struct mtk_dpi *dpi) { - dpi->power_ctl &= ~pctl; - - if ((dpi->power_ctl & DPI_POWER_START) || - (dpi->power_ctl & DPI_POWER_ENABLE)) + if (WARN_ON(dpi->refcount == 0)) return; - if (!dpi->power_sta) + if (--dpi->refcount != 0) return; mtk_dpi_disable(dpi); clk_disable_unprepare(dpi->pixel_clk); clk_disable_unprepare(dpi->engine_clk); - dpi->power_sta = false; } -static int mtk_dpi_power_on(struct mtk_dpi *dpi, enum mtk_dpi_power_ctl pctl) +static int mtk_dpi_power_on(struct mtk_dpi *dpi) { int ret; - dpi->power_ctl |= pctl; - - if (!(dpi->power_ctl & DPI_POWER_START) && - !(dpi->power_ctl & DPI_POWER_ENABLE)) - return 0; - - if (dpi->power_sta) + if (++dpi->refcount != 1) return 0; ret = clk_prepare_enable(dpi->engine_clk); if (ret) { dev_err(dpi->dev, "Failed to enable engine clock: %d\n", ret); - goto err_eng; + goto err_refcount; } ret = clk_prepare_enable(dpi->pixel_clk); @@ -410,13 +394,12 @@ static int mtk_dpi_power_on(struct mtk_dpi *dpi, enum mtk_dpi_power_ctl pctl) } mtk_dpi_enable(dpi); - dpi->power_sta = true; return 0; err_pixel: clk_disable_unprepare(dpi->engine_clk); -err_eng: - dpi->power_ctl &= ~pctl; +err_refcount: + dpi->refcount--; return ret; } @@ -552,14 +535,14 @@ static void mtk_dpi_encoder_disable(struct drm_encoder *encoder) { struct mtk_dpi *dpi = mtk_dpi_from_encoder(encoder); - mtk_dpi_power_off(dpi, DPI_POWER_ENABLE); + mtk_dpi_power_off(dpi); } static void mtk_dpi_encoder_enable(struct drm_encoder *encoder) { struct mtk_dpi *dpi = mtk_dpi_from_encoder(encoder); - mtk_dpi_power_on(dpi, DPI_POWER_ENABLE); + mtk_dpi_power_on(dpi); mtk_dpi_set_display_mode(dpi, &dpi->mode); } @@ -582,14 +565,14 @@ static void mtk_dpi_start(struct mtk_ddp_comp *comp) { struct mtk_dpi *dpi = container_of(comp, struct mtk_dpi, ddp_comp); - mtk_dpi_power_on(dpi, DPI_POWER_START); + mtk_dpi_power_on(dpi); } static void mtk_dpi_stop(struct mtk_ddp_comp *comp) { struct mtk_dpi *dpi = container_of(comp, struct mtk_dpi, ddp_comp); - mtk_dpi_power_off(dpi, DPI_POWER_START); + mtk_dpi_power_off(dpi); } static const struct mtk_ddp_comp_funcs mtk_dpi_funcs = { -- cgit From 0ace4b993c7a524962c6c17f3956a2d3cf2454e1 Mon Sep 17 00:00:00 2001 From: chunhui dai Date: Wed, 3 Oct 2018 11:41:42 +0800 Subject: drm/mediatek: move hardware register to node data The address of register DPI_H_FRE_CON is different in different IC. Using of_node data to find this address. Signed-off-by: chunhui dai Signed-off-by: CK Hu --- drivers/gpu/drm/mediatek/mtk_dpi.c | 19 ++++++++++++++++--- drivers/gpu/drm/mediatek/mtk_dpi_regs.h | 1 - 2 files changed, 16 insertions(+), 4 deletions(-) (limited to 'drivers/gpu/drm/mediatek') diff --git a/drivers/gpu/drm/mediatek/mtk_dpi.c b/drivers/gpu/drm/mediatek/mtk_dpi.c index 5ede1ddbaa1a..72aa43187731 100644 --- a/drivers/gpu/drm/mediatek/mtk_dpi.c +++ b/drivers/gpu/drm/mediatek/mtk_dpi.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -72,6 +73,7 @@ struct mtk_dpi { struct clk *tvd_clk; int irq; struct drm_display_mode mode; + const struct mtk_dpi_conf *conf; enum mtk_dpi_out_color_format color_format; enum mtk_dpi_out_yc_map yc_map; enum mtk_dpi_out_bit_num bit_num; @@ -110,6 +112,10 @@ struct mtk_dpi_yc_limit { u16 c_bottom; }; +struct mtk_dpi_conf { + u32 reg_h_fre_con; +}; + static void mtk_dpi_mask(struct mtk_dpi *dpi, u32 offset, u32 val, u32 mask) { u32 tmp = readl(dpi->regs + offset) & ~mask; @@ -335,7 +341,7 @@ static void mtk_dpi_config_swap_input(struct mtk_dpi *dpi, bool enable) static void mtk_dpi_config_2n_h_fre(struct mtk_dpi *dpi) { - mtk_dpi_mask(dpi, DPI_H_FRE_CON, H_FRE_2N, H_FRE_2N); + mtk_dpi_mask(dpi, dpi->conf->reg_h_fre_con, H_FRE_2N, H_FRE_2N); } static void mtk_dpi_config_color_format(struct mtk_dpi *dpi, @@ -639,6 +645,10 @@ static const struct component_ops mtk_dpi_component_ops = { .unbind = mtk_dpi_unbind, }; +static const struct mtk_dpi_conf mt8173_conf = { + .reg_h_fre_con = 0xe0, +}; + static int mtk_dpi_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -653,6 +663,7 @@ static int mtk_dpi_probe(struct platform_device *pdev) return -ENOMEM; dpi->dev = dev; + dpi->conf = (struct mtk_dpi_conf *)of_device_get_match_data(dev); mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); dpi->regs = devm_ioremap_resource(dev, mem); @@ -732,8 +743,10 @@ static int mtk_dpi_remove(struct platform_device *pdev) } static const struct of_device_id mtk_dpi_of_ids[] = { - { .compatible = "mediatek,mt8173-dpi", }, - {} + { .compatible = "mediatek,mt8173-dpi", + .data = &mt8173_conf, + }, + { }, }; struct platform_driver mtk_dpi_driver = { diff --git a/drivers/gpu/drm/mediatek/mtk_dpi_regs.h b/drivers/gpu/drm/mediatek/mtk_dpi_regs.h index 4b6ad4751a31..040444d7718d 100644 --- a/drivers/gpu/drm/mediatek/mtk_dpi_regs.h +++ b/drivers/gpu/drm/mediatek/mtk_dpi_regs.h @@ -223,6 +223,5 @@ #define ESAV_CODE2 (0xFFF << 0) #define ESAV_CODE3_MSB BIT(16) -#define DPI_H_FRE_CON 0xE0 #define H_FRE_2N BIT(25) #endif /* __MTK_DPI_REGS_H */ -- cgit From 79080159a7c1bcf7cd78713f920a42991bd3c871 Mon Sep 17 00:00:00 2001 From: chunhui dai Date: Wed, 3 Oct 2018 11:41:43 +0800 Subject: drm/mediatek: adjust EDGE to match clock and data The default timing of DPI data and clock is not match. We could adjust this bit to make them match. Signed-off-by: chunhui dai Signed-off-by: CK Hu --- drivers/gpu/drm/mediatek/mtk_dpi.c | 8 ++++++++ drivers/gpu/drm/mediatek/mtk_dpi_regs.h | 1 + 2 files changed, 9 insertions(+) (limited to 'drivers/gpu/drm/mediatek') diff --git a/drivers/gpu/drm/mediatek/mtk_dpi.c b/drivers/gpu/drm/mediatek/mtk_dpi.c index 72aa43187731..0ce4b61efaeb 100644 --- a/drivers/gpu/drm/mediatek/mtk_dpi.c +++ b/drivers/gpu/drm/mediatek/mtk_dpi.c @@ -114,6 +114,7 @@ struct mtk_dpi_yc_limit { struct mtk_dpi_conf { u32 reg_h_fre_con; + bool edge_sel_en; }; static void mtk_dpi_mask(struct mtk_dpi *dpi, u32 offset, u32 val, u32 mask) @@ -344,6 +345,12 @@ static void mtk_dpi_config_2n_h_fre(struct mtk_dpi *dpi) mtk_dpi_mask(dpi, dpi->conf->reg_h_fre_con, H_FRE_2N, H_FRE_2N); } +static void mtk_dpi_config_disable_edge(struct mtk_dpi *dpi) +{ + if (dpi->conf->edge_sel_en) + mtk_dpi_mask(dpi, dpi->conf->reg_h_fre_con, 0, EDGE_SEL_EN); +} + static void mtk_dpi_config_color_format(struct mtk_dpi *dpi, enum mtk_dpi_out_color_format format) { @@ -507,6 +514,7 @@ static int mtk_dpi_set_display_mode(struct mtk_dpi *dpi, mtk_dpi_config_yc_map(dpi, dpi->yc_map); mtk_dpi_config_color_format(dpi, dpi->color_format); mtk_dpi_config_2n_h_fre(dpi); + mtk_dpi_config_disable_edge(dpi); mtk_dpi_sw_reset(dpi, false); return 0; diff --git a/drivers/gpu/drm/mediatek/mtk_dpi_regs.h b/drivers/gpu/drm/mediatek/mtk_dpi_regs.h index 040444d7718d..d9db8c4cacd7 100644 --- a/drivers/gpu/drm/mediatek/mtk_dpi_regs.h +++ b/drivers/gpu/drm/mediatek/mtk_dpi_regs.h @@ -223,5 +223,6 @@ #define ESAV_CODE2 (0xFFF << 0) #define ESAV_CODE3_MSB BIT(16) +#define EDGE_SEL_EN BIT(5) #define H_FRE_2N BIT(25) #endif /* __MTK_DPI_REGS_H */ -- cgit From 55c78aa5c808ba7a95bf271a3486f0d14be519ce Mon Sep 17 00:00:00 2001 From: chunhui dai Date: Wed, 3 Oct 2018 11:41:44 +0800 Subject: drm/mediatek: add clock factor for different IC different IC has different clock designed in HDMI, the factor for calculate clock should be different. Usinng the data in of_node to find this factor. Signed-off-by: chunhui dai Signed-off-by: CK Hu --- drivers/gpu/drm/mediatek/mtk_dpi.c | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) (limited to 'drivers/gpu/drm/mediatek') diff --git a/drivers/gpu/drm/mediatek/mtk_dpi.c b/drivers/gpu/drm/mediatek/mtk_dpi.c index 0ce4b61efaeb..0dbe9345fa2e 100644 --- a/drivers/gpu/drm/mediatek/mtk_dpi.c +++ b/drivers/gpu/drm/mediatek/mtk_dpi.c @@ -113,6 +113,7 @@ struct mtk_dpi_yc_limit { }; struct mtk_dpi_conf { + unsigned int (*cal_factor)(int clock); u32 reg_h_fre_con; bool edge_sel_en; }; @@ -431,15 +432,7 @@ static int mtk_dpi_set_display_mode(struct mtk_dpi *dpi, unsigned int factor; /* let pll_rate can fix the valid range of tvdpll (1G~2GHz) */ - - if (mode->clock <= 27000) - factor = 3 << 4; - else if (mode->clock <= 84000) - factor = 3 << 3; - else if (mode->clock <= 167000) - factor = 3 << 2; - else - factor = 3 << 1; + factor = dpi->conf->cal_factor(mode->clock); drm_display_mode_to_videomode(mode, &vm); pll_rate = vm.pixelclock * factor; @@ -653,7 +646,20 @@ static const struct component_ops mtk_dpi_component_ops = { .unbind = mtk_dpi_unbind, }; +static unsigned int mt8173_calculate_factor(int clock) +{ + if (clock <= 27000) + return 3 << 4; + else if (clock <= 84000) + return 3 << 3; + else if (clock <= 167000) + return 3 << 2; + else + return 3 << 1; +} + static const struct mtk_dpi_conf mt8173_conf = { + .cal_factor = mt8173_calculate_factor, .reg_h_fre_con = 0xe0, }; -- cgit From bcc97daee6b8120d1ffeee0073b49bfbd3df026d Mon Sep 17 00:00:00 2001 From: chunhui dai Date: Wed, 3 Oct 2018 11:41:45 +0800 Subject: drm/mediatek: convert dpi driver to use drm_of_find_panel_or_bridge Convert dpi driver to use drm_of_find_panel_or_bridge. This changes some error messages to debug messages (in the graph core). Graph connections are often "no connects" depending on the particular board, so we want to avoid spurious messages. Plus the kernel is not a DT validator. related links: [1] https://lkml.org/lkml/2017/2/3/716 [2] https://lkml.org/lkml/2017/2/3/719 Signed-off-by: chunhui dai Signed-off-by: CK Hu --- drivers/gpu/drm/mediatek/mtk_dpi.c | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) (limited to 'drivers/gpu/drm/mediatek') diff --git a/drivers/gpu/drm/mediatek/mtk_dpi.c b/drivers/gpu/drm/mediatek/mtk_dpi.c index 0dbe9345fa2e..08915e1765f8 100644 --- a/drivers/gpu/drm/mediatek/mtk_dpi.c +++ b/drivers/gpu/drm/mediatek/mtk_dpi.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -668,7 +669,6 @@ static int mtk_dpi_probe(struct platform_device *pdev) struct device *dev = &pdev->dev; struct mtk_dpi *dpi; struct resource *mem; - struct device_node *bridge_node; int comp_id; int ret; @@ -714,16 +714,12 @@ static int mtk_dpi_probe(struct platform_device *pdev) return -EINVAL; } - bridge_node = of_graph_get_remote_node(dev->of_node, 0, 0); - if (!bridge_node) - return -ENODEV; - - dev_info(dev, "Found bridge node: %pOF\n", bridge_node); + ret = drm_of_find_panel_or_bridge(dev->of_node, 0, 0, + NULL, &dpi->bridge); + if (ret) + return ret; - dpi->bridge = of_drm_find_bridge(bridge_node); - of_node_put(bridge_node); - if (!dpi->bridge) - return -EPROBE_DEFER; + dev_info(dev, "Found bridge node: %pOF\n", dpi->bridge->of_node); comp_id = mtk_ddp_comp_get_id(dev->of_node, MTK_DPI); if (comp_id < 0) { -- cgit From d08b5ab972449b0ab494600fa985979e91e090ca Mon Sep 17 00:00:00 2001 From: chunhui dai Date: Wed, 3 Oct 2018 11:41:46 +0800 Subject: drm/mediatek: add dpi driver for mt2701 and mt7623 This patch adds dpi dirver suppot for both mt2701 and mt7623. And also support other (existing or future) chips that use the same binding and driver. Signed-off-by: chunhui dai Signed-off-by: CK Hu --- drivers/gpu/drm/mediatek/mtk_dpi.c | 21 +++++++++++++++++++++ drivers/gpu/drm/mediatek/mtk_drm_drv.c | 2 ++ 2 files changed, 23 insertions(+) (limited to 'drivers/gpu/drm/mediatek') diff --git a/drivers/gpu/drm/mediatek/mtk_dpi.c b/drivers/gpu/drm/mediatek/mtk_dpi.c index 08915e1765f8..62a9d47df948 100644 --- a/drivers/gpu/drm/mediatek/mtk_dpi.c +++ b/drivers/gpu/drm/mediatek/mtk_dpi.c @@ -659,11 +659,29 @@ static unsigned int mt8173_calculate_factor(int clock) return 3 << 1; } +static unsigned int mt2701_calculate_factor(int clock) +{ + if (clock <= 64000) + return 16; + else if (clock <= 128000) + return 8; + else if (clock <= 256000) + return 4; + else + return 2; +} + static const struct mtk_dpi_conf mt8173_conf = { .cal_factor = mt8173_calculate_factor, .reg_h_fre_con = 0xe0, }; +static const struct mtk_dpi_conf mt2701_conf = { + .cal_factor = mt2701_calculate_factor, + .reg_h_fre_con = 0xb0, + .edge_sel_en = true, +}; + static int mtk_dpi_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -753,6 +771,9 @@ static int mtk_dpi_remove(struct platform_device *pdev) } static const struct of_device_id mtk_dpi_of_ids[] = { + { .compatible = "mediatek,mt2701-dpi", + .data = &mt2701_conf, + }, { .compatible = "mediatek,mt8173-dpi", .data = &mt8173_conf, }, diff --git a/drivers/gpu/drm/mediatek/mtk_drm_drv.c b/drivers/gpu/drm/mediatek/mtk_drm_drv.c index 47ec604289b7..6422e99952fe 100644 --- a/drivers/gpu/drm/mediatek/mtk_drm_drv.c +++ b/drivers/gpu/drm/mediatek/mtk_drm_drv.c @@ -424,6 +424,8 @@ static const struct of_device_id mtk_ddp_comp_dt_ids[] = { .data = (void *)MTK_DSI }, { .compatible = "mediatek,mt8173-dsi", .data = (void *)MTK_DSI }, + { .compatible = "mediatek,mt2701-dpi", + .data = (void *)MTK_DPI }, { .compatible = "mediatek,mt8173-dpi", .data = (void *)MTK_DPI }, { .compatible = "mediatek,mt2701-disp-mutex", -- cgit From be28b6507c46050f5b7244d9d98a19c03b9cf074 Mon Sep 17 00:00:00 2001 From: chunhui dai Date: Wed, 3 Oct 2018 11:41:47 +0800 Subject: drm/mediatek: separate hdmi phy to different file Different IC has different phy setting of HDMI. This patch separates the phy hardware relate part for mt8173. Signed-off-by: chunhui dai Signed-off-by: CK Hu --- drivers/gpu/drm/mediatek/Makefile | 6 +- drivers/gpu/drm/mediatek/mtk_hdmi.c | 1 + drivers/gpu/drm/mediatek/mtk_hdmi.h | 2 +- drivers/gpu/drm/mediatek/mtk_hdmi_phy.c | 232 +++++++++++++++++++++++++ drivers/gpu/drm/mediatek/mtk_hdmi_phy.h | 58 +++++++ drivers/gpu/drm/mediatek/mtk_mt8173_hdmi_phy.c | 226 +----------------------- 6 files changed, 302 insertions(+), 223 deletions(-) create mode 100644 drivers/gpu/drm/mediatek/mtk_hdmi_phy.c create mode 100644 drivers/gpu/drm/mediatek/mtk_hdmi_phy.h (limited to 'drivers/gpu/drm/mediatek') diff --git a/drivers/gpu/drm/mediatek/Makefile b/drivers/gpu/drm/mediatek/Makefile index ce83c396a742..61cf0d2ab28a 100644 --- a/drivers/gpu/drm/mediatek/Makefile +++ b/drivers/gpu/drm/mediatek/Makefile @@ -1,4 +1,5 @@ # SPDX-License-Identifier: GPL-2.0 + mediatek-drm-y := mtk_disp_color.o \ mtk_disp_ovl.o \ mtk_disp_rdma.o \ @@ -18,6 +19,7 @@ obj-$(CONFIG_DRM_MEDIATEK) += mediatek-drm.o mediatek-drm-hdmi-objs := mtk_cec.o \ mtk_hdmi.o \ mtk_hdmi_ddc.o \ - mtk_mt8173_hdmi_phy.o + mtk_mt8173_hdmi_phy.o \ + mtk_hdmi_phy.o -obj-$(CONFIG_DRM_MEDIATEK_HDMI) += mediatek-drm-hdmi.o +obj-$(CONFIG_DRM_MEDIATEK_HDMI) += mediatek-drm-hdmi.o \ No newline at end of file diff --git a/drivers/gpu/drm/mediatek/mtk_hdmi.c b/drivers/gpu/drm/mediatek/mtk_hdmi.c index 2d45d1dd9554..2ca9f6a64dab 100644 --- a/drivers/gpu/drm/mediatek/mtk_hdmi.c +++ b/drivers/gpu/drm/mediatek/mtk_hdmi.c @@ -233,6 +233,7 @@ static void mtk_hdmi_hw_vid_black(struct mtk_hdmi *hdmi, bool black) static void mtk_hdmi_hw_make_reg_writable(struct mtk_hdmi *hdmi, bool enable) { struct arm_smccc_res res; + struct mtk_hdmi_phy *hdmi_phy = phy_get_drvdata(hdmi->phy); /* * MT8173 HDMI hardware has an output control bit to enable/disable HDMI diff --git a/drivers/gpu/drm/mediatek/mtk_hdmi.h b/drivers/gpu/drm/mediatek/mtk_hdmi.h index 6371b3de1ff6..3e9fb8d19802 100644 --- a/drivers/gpu/drm/mediatek/mtk_hdmi.h +++ b/drivers/gpu/drm/mediatek/mtk_hdmi.h @@ -13,11 +13,11 @@ */ #ifndef _MTK_HDMI_CTRL_H #define _MTK_HDMI_CTRL_H +#include "mtk_hdmi_phy.h" struct platform_driver; extern struct platform_driver mtk_cec_driver; extern struct platform_driver mtk_hdmi_ddc_driver; -extern struct platform_driver mtk_hdmi_phy_driver; #endif /* _MTK_HDMI_CTRL_H */ diff --git a/drivers/gpu/drm/mediatek/mtk_hdmi_phy.c b/drivers/gpu/drm/mediatek/mtk_hdmi_phy.c new file mode 100644 index 000000000000..514f3e9a8767 --- /dev/null +++ b/drivers/gpu/drm/mediatek/mtk_hdmi_phy.c @@ -0,0 +1,232 @@ +// 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, +}; + +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; +} + +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; +} + +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_ops(struct mtk_hdmi_phy *hdmi_phy, + const struct clk_ops **ops) +{ + if (hdmi_phy && hdmi_phy->conf && hdmi_phy->conf->hdmi_phy_clk_ops) + *ops = hdmi_phy->conf->hdmi_phy_clk_ops; + else + dev_err(hdmi_phy->dev, "Failed to get clk ops of phy\n"); +} + +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, + .flags = CLK_SET_RATE_PARENT | CLK_SET_RATE_GATE, + }; + + 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_ops(hdmi_phy, &clk_init.ops); + 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,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_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 new file mode 100644 index 000000000000..09b8f525e6b8 --- /dev/null +++ b/drivers/gpu/drm/mediatek/mtk_hdmi_phy.h @@ -0,0 +1,58 @@ +/* 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 { + 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); +long mtk_hdmi_pll_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *parent_rate); +unsigned long mtk_hdmi_pll_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate); + +extern struct platform_driver mtk_hdmi_phy_driver; +extern struct mtk_hdmi_phy_conf mtk_hdmi_phy_8173_conf; + +#endif /* _MTK_HDMI_PHY_H */ diff --git a/drivers/gpu/drm/mediatek/mtk_mt8173_hdmi_phy.c b/drivers/gpu/drm/mediatek/mtk_mt8173_hdmi_phy.c index 51cb9cfb6646..ed5916b27658 100644 --- a/drivers/gpu/drm/mediatek/mtk_mt8173_hdmi_phy.c +++ b/drivers/gpu/drm/mediatek/mtk_mt8173_hdmi_phy.c @@ -12,15 +12,7 @@ * GNU General Public License for more details. */ -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include "mtk_hdmi_phy.h" #define HDMI_CON0 0x00 #define RG_HDMITX_PLL_EN BIT(31) @@ -123,20 +115,6 @@ #define RGS_HDMITX_5T1_EDG (0xf << 4) #define RGS_HDMITX_PLUG_TST BIT(0) -struct mtk_hdmi_phy { - void __iomem *regs; - struct device *dev; - struct clk *pll; - struct clk_hw pll_hw; - unsigned long pll_rate; - u8 drv_imp_clk; - u8 drv_imp_d2; - u8 drv_imp_d1; - u8 drv_imp_d0; - u32 ibias; - u32 ibias_up; -}; - static const u8 PREDIV[3][4] = { {0x0, 0x0, 0x0, 0x0}, /* 27Mhz */ {0x1, 0x1, 0x1, 0x1}, /* 74Mhz */ @@ -185,44 +163,6 @@ static const u8 HTPLLBR[3][4] = { {0x1, 0x2, 0x2, 0x1} /* 148Mhz */ }; -static 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); -} - -static 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); -} - -static 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); -} - -static 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_pll_prepare(struct clk_hw *hw) { struct mtk_hdmi_phy *hdmi_phy = to_mtk_hdmi_phy(hw); @@ -345,29 +285,7 @@ static int mtk_hdmi_pll_set_rate(struct clk_hw *hw, unsigned long rate, return 0; } -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 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_pll_ops = { +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, @@ -390,142 +308,10 @@ static void mtk_hdmi_phy_disable_tmds(struct mtk_hdmi_phy *hdmi_phy) RG_HDMITX_SER_EN); } -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; - - mtk_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); - - mtk_hdmi_phy_disable_tmds(hdmi_phy); - clk_disable_unprepare(hdmi_phy->pll); - - return 0; -} - -static const struct phy_ops mtk_hdmi_phy_ops = { - .power_on = mtk_hdmi_phy_power_on, - .power_off = mtk_hdmi_phy_power_off, - .owner = THIS_MODULE, -}; - -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 = { - .ops = &mtk_hdmi_pll_ops, - .num_parents = 1, - .parent_names = (const char * const *)&ref_clk_name, - .flags = CLK_SET_RATE_PARENT | CLK_SET_RATE_GATE, - }; - 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->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_ops); - 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)) - return PTR_ERR(phy_provider); - - hdmi_phy->dev = dev; - return of_clk_add_provider(dev->of_node, of_clk_src_simple_get, - hdmi_phy->pll); -} - -static int mtk_hdmi_phy_remove(struct platform_device *pdev) -{ - return 0; -} - -static const struct of_device_id mtk_hdmi_phy_match[] = { - { .compatible = "mediatek,mt8173-hdmi-phy", }, - {}, -}; - -struct platform_driver mtk_hdmi_phy_driver = { - .probe = mtk_hdmi_phy_probe, - .remove = mtk_hdmi_phy_remove, - .driver = { - .name = "mediatek-hdmi-phy", - .of_match_table = mtk_hdmi_phy_match, - }, +struct mtk_hdmi_phy_conf mtk_hdmi_phy_8173_conf = { + .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 "); -- cgit From d1ef028d95ffd0f114f2d42ef4f141664abbf1f6 Mon Sep 17 00:00:00 2001 From: chunhui dai Date: Wed, 3 Oct 2018 11:41:48 +0800 Subject: drm/mediatek: add support for SPDIF audio in HDMI add support for SPDIF audio in HDMI Signed-off-by: chunhui dai Signed-off-by: CK Hu --- drivers/gpu/drm/mediatek/mtk_hdmi.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers/gpu/drm/mediatek') diff --git a/drivers/gpu/drm/mediatek/mtk_hdmi.c b/drivers/gpu/drm/mediatek/mtk_hdmi.c index 2ca9f6a64dab..d62e685cec73 100644 --- a/drivers/gpu/drm/mediatek/mtk_hdmi.c +++ b/drivers/gpu/drm/mediatek/mtk_hdmi.c @@ -1576,6 +1576,11 @@ static int mtk_hdmi_audio_hw_params(struct device *dev, void *data, hdmi_params.aud_i2s_fmt = HDMI_I2S_MODE_I2S_24BIT; hdmi_params.aud_mclk = HDMI_AUD_MCLK_128FS; break; + case HDMI_SPDIF: + hdmi_params.aud_codec = HDMI_AUDIO_CODING_TYPE_PCM; + hdmi_params.aud_sampe_size = HDMI_AUDIO_SAMPLE_SIZE_16; + hdmi_params.aud_input_type = HDMI_AUD_INPUT_SPDIF; + break; default: dev_err(hdmi->dev, "%s: Invalid DAI format %d\n", __func__, daifmt->fmt); -- cgit From 0fc721b2968e3cadec520c60d2fc63498d865055 Mon Sep 17 00:00:00 2001 From: chunhui dai Date: Wed, 3 Oct 2018 11:41:49 +0800 Subject: drm/mediatek: add hdmi driver for MT2701 and MT7623 This patch adds hdmi dirver suppot for both MT2701 and MT7623. And also support other (existing or future) chips that use the same binding and driver. Signed-off-by: chunhui dai Signed-off-by: CK Hu --- drivers/gpu/drm/mediatek/Makefile | 3 +- drivers/gpu/drm/mediatek/mtk_hdmi.c | 9 +- drivers/gpu/drm/mediatek/mtk_hdmi_phy.c | 3 + drivers/gpu/drm/mediatek/mtk_hdmi_phy.h | 2 + drivers/gpu/drm/mediatek/mtk_mt2701_hdmi_phy.c | 212 +++++++++++++++++++++++++ 5 files changed, 226 insertions(+), 3 deletions(-) create mode 100644 drivers/gpu/drm/mediatek/mtk_mt2701_hdmi_phy.c (limited to 'drivers/gpu/drm/mediatek') diff --git a/drivers/gpu/drm/mediatek/Makefile b/drivers/gpu/drm/mediatek/Makefile index 61cf0d2ab28a..82ae49c64221 100644 --- a/drivers/gpu/drm/mediatek/Makefile +++ b/drivers/gpu/drm/mediatek/Makefile @@ -19,7 +19,8 @@ obj-$(CONFIG_DRM_MEDIATEK) += mediatek-drm.o mediatek-drm-hdmi-objs := mtk_cec.o \ mtk_hdmi.o \ mtk_hdmi_ddc.o \ + mtk_mt2701_hdmi_phy.o \ mtk_mt8173_hdmi_phy.o \ mtk_hdmi_phy.o -obj-$(CONFIG_DRM_MEDIATEK_HDMI) += mediatek-drm-hdmi.o \ No newline at end of file +obj-$(CONFIG_DRM_MEDIATEK_HDMI) += mediatek-drm-hdmi.o diff --git a/drivers/gpu/drm/mediatek/mtk_hdmi.c b/drivers/gpu/drm/mediatek/mtk_hdmi.c index d62e685cec73..11e3644da79a 100644 --- a/drivers/gpu/drm/mediatek/mtk_hdmi.c +++ b/drivers/gpu/drm/mediatek/mtk_hdmi.c @@ -241,8 +241,13 @@ static void mtk_hdmi_hw_make_reg_writable(struct mtk_hdmi *hdmi, bool enable) * The ARM trusted firmware provides an API for the HDMI driver to set * this control bit to enable HDMI output in supervisor mode. */ - arm_smccc_smc(MTK_SIP_SET_AUTHORIZED_SECURE_REG, 0x14000904, 0x80000000, - 0, 0, 0, 0, 0, &res); + if (hdmi_phy->conf && hdmi_phy->conf->tz_disabled) + regmap_update_bits(hdmi->sys_regmap, + hdmi->sys_offset + HDMI_SYS_CFG20, + 0x80008005, enable ? 0x80000005 : 0x8000); + else + arm_smccc_smc(MTK_SIP_SET_AUTHORIZED_SECURE_REG, 0x14000904, + 0x80000000, 0, 0, 0, 0, 0, &res); regmap_update_bits(hdmi->sys_regmap, hdmi->sys_offset + HDMI_SYS_CFG20, HDMI_PCLK_FREE_RUN, enable ? HDMI_PCLK_FREE_RUN : 0); diff --git a/drivers/gpu/drm/mediatek/mtk_hdmi_phy.c b/drivers/gpu/drm/mediatek/mtk_hdmi_phy.c index 514f3e9a8767..4ef9c57ffd44 100644 --- a/drivers/gpu/drm/mediatek/mtk_hdmi_phy.c +++ b/drivers/gpu/drm/mediatek/mtk_hdmi_phy.c @@ -214,6 +214,9 @@ static int mtk_hdmi_phy_probe(struct platform_device *pdev) } 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, }, diff --git a/drivers/gpu/drm/mediatek/mtk_hdmi_phy.h b/drivers/gpu/drm/mediatek/mtk_hdmi_phy.h index 09b8f525e6b8..f39b1fc66612 100644 --- a/drivers/gpu/drm/mediatek/mtk_hdmi_phy.h +++ b/drivers/gpu/drm/mediatek/mtk_hdmi_phy.h @@ -20,6 +20,7 @@ struct mtk_hdmi_phy; struct mtk_hdmi_phy_conf { + bool tz_disabled; 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); @@ -54,5 +55,6 @@ unsigned long mtk_hdmi_pll_recalc_rate(struct clk_hw *hw, extern struct platform_driver mtk_hdmi_phy_driver; 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 new file mode 100644 index 000000000000..fcc42dc6ea7f --- /dev/null +++ b/drivers/gpu/drm/mediatek/mtk_mt2701_hdmi_phy.c @@ -0,0 +1,212 @@ +// 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_CON2, RG_HDMITX_EN_TX_POSDIV); + 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_EN_TX_POSDIV); + 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 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 <= 12800000) + pos_div = 1; + 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_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 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_CON2, RG_HDMITX_EN_TX_POSDIV); + 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_EN_TX_POSDIV); + 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 = { + .tz_disabled = true, + .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"); -- cgit From 014e604196bddbd3a0186775e02bc5574bed18d4 Mon Sep 17 00:00:00 2001 From: Bibby Hsieh Date: Wed, 3 Oct 2018 11:41:50 +0800 Subject: drm/mediatek: implement connection from BLS to DPI0 Modify display driver to support connection from BLS to DPI. Signed-off-by: Bibby Hsieh Signed-off-by: CK Hu --- drivers/gpu/drm/mediatek/mtk_drm_ddp.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) (limited to 'drivers/gpu/drm/mediatek') diff --git a/drivers/gpu/drm/mediatek/mtk_drm_ddp.c b/drivers/gpu/drm/mediatek/mtk_drm_ddp.c index 546b3e3b300b..579ce28d801d 100644 --- a/drivers/gpu/drm/mediatek/mtk_drm_ddp.c +++ b/drivers/gpu/drm/mediatek/mtk_drm_ddp.c @@ -39,6 +39,7 @@ #define DISP_REG_CONFIG_DISP_OVL_MOUT_EN 0x030 #define DISP_REG_CONFIG_OUT_SEL 0x04c #define DISP_REG_CONFIG_DSI_SEL 0x050 +#define DISP_REG_CONFIG_DPI_SEL 0x064 #define DISP_REG_MUTEX_EN(n) (0x20 + 0x20 * (n)) #define DISP_REG_MUTEX(n) (0x24 + 0x20 * (n)) @@ -136,7 +137,10 @@ #define OVL_MOUT_EN_RDMA 0x1 #define BLS_TO_DSI_RDMA1_TO_DPI1 0x8 +#define BLS_TO_DPI_RDMA1_TO_DSI 0x2 #define DSI_SEL_IN_BLS 0x0 +#define DPI_SEL_IN_BLS 0x0 +#define DSI_SEL_IN_RDMA 0x1 struct mtk_disp_mutex { int id; @@ -339,9 +343,17 @@ static void mtk_ddp_sout_sel(void __iomem *config_regs, enum mtk_ddp_comp_id cur, enum mtk_ddp_comp_id next) { - if (cur == DDP_COMPONENT_BLS && next == DDP_COMPONENT_DSI0) + if (cur == DDP_COMPONENT_BLS && next == DDP_COMPONENT_DSI0) { writel_relaxed(BLS_TO_DSI_RDMA1_TO_DPI1, config_regs + DISP_REG_CONFIG_OUT_SEL); + } else if (cur == DDP_COMPONENT_BLS && next == DDP_COMPONENT_DPI0) { + writel_relaxed(BLS_TO_DPI_RDMA1_TO_DSI, + config_regs + DISP_REG_CONFIG_OUT_SEL); + writel_relaxed(DSI_SEL_IN_RDMA, + config_regs + DISP_REG_CONFIG_DSI_SEL); + writel_relaxed(DPI_SEL_IN_BLS, + config_regs + DISP_REG_CONFIG_DPI_SEL); + } } void mtk_ddp_add_comp_to_path(void __iomem *config_regs, -- cgit From 84dacb9cad2804a9f5434b775ccea6aa5d9fc6ca Mon Sep 17 00:00:00 2001 From: Bibby Hsieh Date: Wed, 3 Oct 2018 11:41:51 +0800 Subject: drm/mediatek: add a error return value when clock driver has been prepared DRM driver get the comp->clk by of_clk_get(), we only assign NULL to comp->clk when error happened, but do not return the error number. Signed-off-by: Bibby Hsieh Signed-off-by: CK Hu --- drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/gpu/drm/mediatek') diff --git a/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c b/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c index ff974d82a4a6..54ca794db3e9 100644 --- a/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c +++ b/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c @@ -294,7 +294,7 @@ int mtk_ddp_comp_init(struct device *dev, struct device_node *node, comp->irq = of_irq_get(node, 0); comp->clk = of_clk_get(node, 0); if (IS_ERR(comp->clk)) - comp->clk = NULL; + return PTR_ERR(comp->clk); /* Only DMA capable components need the LARB property */ comp->larb_dev = NULL; -- cgit