diff options
Diffstat (limited to 'drivers/gpu/drm/mediatek/mtk_dsi.c')
-rw-r--r-- | drivers/gpu/drm/mediatek/mtk_dsi.c | 174 |
1 files changed, 139 insertions, 35 deletions
diff --git a/drivers/gpu/drm/mediatek/mtk_dsi.c b/drivers/gpu/drm/mediatek/mtk_dsi.c index 9501f4019199..4fe1f38a3c4b 100644 --- a/drivers/gpu/drm/mediatek/mtk_dsi.c +++ b/drivers/gpu/drm/mediatek/mtk_dsi.c @@ -28,8 +28,8 @@ #include <drm/drm_probe_helper.h> #include <drm/drm_simple_kms_helper.h> +#include "mtk_ddp_comp.h" #include "mtk_disp_drv.h" -#include "mtk_drm_ddp_comp.h" #include "mtk_drm_drv.h" #define DSI_START 0x00 @@ -88,12 +88,15 @@ #define DSI_HSA_WC 0x50 #define DSI_HBP_WC 0x54 #define DSI_HFP_WC 0x58 +#define HFP_HS_VB_PS_WC GENMASK(30, 16) +#define HFP_HS_EN BIT(31) #define DSI_CMDQ_SIZE 0x60 #define CMDQ_SIZE 0x3f #define CMDQ_SIZE_SEL BIT(15) #define DSI_HSTX_CKL_WC 0x64 +#define HSTX_CKL_WC GENMASK(15, 2) #define DSI_RX_DATA0 0x74 #define DSI_RX_DATA1 0x78 @@ -136,11 +139,11 @@ #define CLK_HS_POST GENMASK(15, 8) #define CLK_HS_EXIT GENMASK(23, 16) -#define DSI_VM_CMD_CON 0x130 +/* DSI_VM_CMD_CON */ #define VM_CMD_EN BIT(0) #define TS_VFP_EN BIT(5) -#define DSI_SHADOW_DEBUG 0x190U +/* DSI_SHADOW_DEBUG */ #define FORCE_COMMIT BIT(0) #define BYPASS_SHADOW BIT(1) @@ -184,9 +187,12 @@ struct phy; struct mtk_dsi_driver_data { const u32 reg_cmdq_off; + const u32 reg_vm_cmd_off; + const u32 reg_shadow_dbg_off; bool has_shadow_ctl; bool has_size_ctl; bool cmdq_long_packet_ctl; + bool support_per_frame_lp; }; struct mtk_dsi { @@ -362,8 +368,8 @@ static void mtk_dsi_set_mode(struct mtk_dsi *dsi) static void mtk_dsi_set_vm_cmd(struct mtk_dsi *dsi) { - mtk_dsi_mask(dsi, DSI_VM_CMD_CON, VM_CMD_EN, VM_CMD_EN); - mtk_dsi_mask(dsi, DSI_VM_CMD_CON, TS_VFP_EN, TS_VFP_EN); + mtk_dsi_mask(dsi, dsi->driver_data->reg_vm_cmd_off, VM_CMD_EN, VM_CMD_EN); + mtk_dsi_mask(dsi, dsi->driver_data->reg_vm_cmd_off, TS_VFP_EN, TS_VFP_EN); } static void mtk_dsi_rxtx_control(struct mtk_dsi *dsi) @@ -425,7 +431,75 @@ static void mtk_dsi_ps_control(struct mtk_dsi *dsi, bool config_vact) writel(ps_val, dsi->regs + DSI_PSCTRL); } -static void mtk_dsi_config_vdo_timing(struct mtk_dsi *dsi) +static void mtk_dsi_config_vdo_timing_per_frame_lp(struct mtk_dsi *dsi) +{ + u32 horizontal_sync_active_byte; + u32 horizontal_backporch_byte; + u32 horizontal_frontporch_byte; + u32 hfp_byte_adjust, v_active_adjust; + u32 cklp_wc_min_adjust, cklp_wc_max_adjust; + u32 dsi_tmp_buf_bpp; + unsigned int da_hs_trail; + unsigned int ps_wc, hs_vb_ps_wc; + u32 v_active_roundup, hstx_cklp_wc; + u32 hstx_cklp_wc_max, hstx_cklp_wc_min; + struct videomode *vm = &dsi->vm; + + if (dsi->format == MIPI_DSI_FMT_RGB565) + dsi_tmp_buf_bpp = 2; + else + dsi_tmp_buf_bpp = 3; + + da_hs_trail = dsi->phy_timing.da_hs_trail; + ps_wc = vm->hactive * dsi_tmp_buf_bpp; + + if (dsi->mode_flags & MIPI_DSI_MODE_VIDEO_SYNC_PULSE) { + horizontal_sync_active_byte = + vm->hsync_len * dsi_tmp_buf_bpp - 10; + horizontal_backporch_byte = + vm->hback_porch * dsi_tmp_buf_bpp - 10; + hfp_byte_adjust = 12; + v_active_adjust = 32 + horizontal_sync_active_byte; + cklp_wc_min_adjust = 12 + 2 + 4 + horizontal_sync_active_byte; + cklp_wc_max_adjust = 20 + 6 + 4 + horizontal_sync_active_byte; + } else { + horizontal_sync_active_byte = vm->hsync_len * dsi_tmp_buf_bpp - 4; + horizontal_backporch_byte = (vm->hback_porch + vm->hsync_len) * + dsi_tmp_buf_bpp - 10; + cklp_wc_min_adjust = 4; + cklp_wc_max_adjust = 12 + 4 + 4; + if (dsi->mode_flags & MIPI_DSI_MODE_VIDEO_BURST) { + hfp_byte_adjust = 18; + v_active_adjust = 28; + } else { + hfp_byte_adjust = 12; + v_active_adjust = 22; + } + } + horizontal_frontporch_byte = vm->hfront_porch * dsi_tmp_buf_bpp - hfp_byte_adjust; + v_active_roundup = (v_active_adjust + horizontal_backporch_byte + ps_wc + + horizontal_frontporch_byte) % dsi->lanes; + if (v_active_roundup) + horizontal_backporch_byte += dsi->lanes - v_active_roundup; + hstx_cklp_wc_min = (DIV_ROUND_UP(cklp_wc_min_adjust, dsi->lanes) + da_hs_trail + 1) + * dsi->lanes / 6 - 1; + hstx_cklp_wc_max = (DIV_ROUND_UP((cklp_wc_max_adjust + horizontal_backporch_byte + + ps_wc), dsi->lanes) + da_hs_trail + 1) * dsi->lanes / 6 - 1; + + hstx_cklp_wc = FIELD_PREP(HSTX_CKL_WC, (hstx_cklp_wc_min + hstx_cklp_wc_max) / 2); + writel(hstx_cklp_wc, dsi->regs + DSI_HSTX_CKL_WC); + + hs_vb_ps_wc = ps_wc - (dsi->phy_timing.lpx + dsi->phy_timing.da_hs_exit + + dsi->phy_timing.da_hs_prepare + dsi->phy_timing.da_hs_zero + 2) * dsi->lanes; + horizontal_frontporch_byte |= FIELD_PREP(HFP_HS_EN, 1) | + FIELD_PREP(HFP_HS_VB_PS_WC, hs_vb_ps_wc); + + writel(horizontal_sync_active_byte, dsi->regs + DSI_HSA_WC); + writel(horizontal_backporch_byte, dsi->regs + DSI_HBP_WC); + writel(horizontal_frontporch_byte, dsi->regs + DSI_HFP_WC); +} + +static void mtk_dsi_config_vdo_timing_per_line_lp(struct mtk_dsi *dsi) { u32 horizontal_sync_active_byte; u32 horizontal_backporch_byte; @@ -435,7 +509,6 @@ static void mtk_dsi_config_vdo_timing(struct mtk_dsi *dsi) u32 dsi_tmp_buf_bpp, data_phy_cycles; u32 delta; struct mtk_phy_timing *timing = &dsi->phy_timing; - struct videomode *vm = &dsi->vm; if (dsi->format == MIPI_DSI_FMT_RGB565) @@ -443,16 +516,6 @@ static void mtk_dsi_config_vdo_timing(struct mtk_dsi *dsi) else dsi_tmp_buf_bpp = 3; - writel(vm->vsync_len, dsi->regs + DSI_VSA_NL); - writel(vm->vback_porch, dsi->regs + DSI_VBP_NL); - writel(vm->vfront_porch, dsi->regs + DSI_VFP_NL); - writel(vm->vactive, dsi->regs + DSI_VACT_NL); - - if (dsi->driver_data->has_size_ctl) - writel(FIELD_PREP(DSI_HEIGHT, vm->vactive) | - FIELD_PREP(DSI_WIDTH, vm->hactive), - dsi->regs + DSI_SIZE_CON); - horizontal_sync_active_byte = (vm->hsync_len * dsi_tmp_buf_bpp - 10); if (dsi->mode_flags & MIPI_DSI_MODE_VIDEO_SYNC_PULSE) @@ -498,6 +561,26 @@ static void mtk_dsi_config_vdo_timing(struct mtk_dsi *dsi) writel(horizontal_sync_active_byte, dsi->regs + DSI_HSA_WC); writel(horizontal_backporch_byte, dsi->regs + DSI_HBP_WC); writel(horizontal_frontporch_byte, dsi->regs + DSI_HFP_WC); +} + +static void mtk_dsi_config_vdo_timing(struct mtk_dsi *dsi) +{ + struct videomode *vm = &dsi->vm; + + writel(vm->vsync_len, dsi->regs + DSI_VSA_NL); + writel(vm->vback_porch, dsi->regs + DSI_VBP_NL); + writel(vm->vfront_porch, dsi->regs + DSI_VFP_NL); + writel(vm->vactive, dsi->regs + DSI_VACT_NL); + + if (dsi->driver_data->has_size_ctl) + writel(FIELD_PREP(DSI_HEIGHT, vm->vactive) | + FIELD_PREP(DSI_WIDTH, vm->hactive), + dsi->regs + DSI_SIZE_CON); + + if (dsi->driver_data->support_per_frame_lp) + mtk_dsi_config_vdo_timing_per_frame_lp(dsi); + else + mtk_dsi_config_vdo_timing_per_line_lp(dsi); mtk_dsi_ps_control(dsi, false); } @@ -632,7 +715,7 @@ static int mtk_dsi_poweron(struct mtk_dsi *dsi) if (dsi->driver_data->has_shadow_ctl) writel(FORCE_COMMIT | BYPASS_SHADOW, - dsi->regs + DSI_SHADOW_DEBUG); + dsi->regs + dsi->driver_data->reg_shadow_dbg_off); mtk_dsi_reset_engine(dsi); mtk_dsi_phy_timconfig(dsi); @@ -662,7 +745,7 @@ static void mtk_dsi_poweroff(struct mtk_dsi *dsi) /* * mtk_dsi_stop() and mtk_dsi_start() is asymmetric, since - * mtk_dsi_stop() should be called after mtk_drm_crtc_atomic_disable(), + * mtk_dsi_stop() should be called after mtk_crtc_atomic_disable(), * which needs irq for vblank, and mtk_dsi_stop() will disable irq. * mtk_dsi_start() needs to be called in mtk_output_dsi_enable(), * after dsi is fully set. @@ -724,12 +807,13 @@ static void mtk_output_dsi_disable(struct mtk_dsi *dsi) } static int mtk_dsi_bridge_attach(struct drm_bridge *bridge, + struct drm_encoder *encoder, enum drm_bridge_attach_flags flags) { struct mtk_dsi *dsi = bridge_to_dsi(bridge); /* Attach the panel or bridge to the dsi bridge */ - return drm_bridge_attach(bridge->encoder, dsi->next_bridge, + return drm_bridge_attach(encoder, dsi->next_bridge, &dsi->bridge, flags); } @@ -743,7 +827,7 @@ static void mtk_dsi_bridge_mode_set(struct drm_bridge *bridge, } static void mtk_dsi_bridge_atomic_disable(struct drm_bridge *bridge, - struct drm_bridge_state *old_bridge_state) + struct drm_atomic_state *state) { struct mtk_dsi *dsi = bridge_to_dsi(bridge); @@ -751,7 +835,7 @@ static void mtk_dsi_bridge_atomic_disable(struct drm_bridge *bridge, } static void mtk_dsi_bridge_atomic_enable(struct drm_bridge *bridge, - struct drm_bridge_state *old_bridge_state) + struct drm_atomic_state *state) { struct mtk_dsi *dsi = bridge_to_dsi(bridge); @@ -762,7 +846,7 @@ static void mtk_dsi_bridge_atomic_enable(struct drm_bridge *bridge, } static void mtk_dsi_bridge_atomic_pre_enable(struct drm_bridge *bridge, - struct drm_bridge_state *old_bridge_state) + struct drm_atomic_state *state) { struct mtk_dsi *dsi = bridge_to_dsi(bridge); int ret; @@ -773,7 +857,7 @@ static void mtk_dsi_bridge_atomic_pre_enable(struct drm_bridge *bridge, } static void mtk_dsi_bridge_atomic_post_disable(struct drm_bridge *bridge, - struct drm_bridge_state *old_bridge_state) + struct drm_atomic_state *state) { struct mtk_dsi *dsi = bridge_to_dsi(bridge); @@ -836,7 +920,10 @@ static int mtk_dsi_encoder_init(struct drm_device *drm, struct mtk_dsi *dsi) return ret; } - dsi->encoder.possible_crtcs = mtk_drm_find_possible_crtc_by_comp(drm, dsi->host.dev); + ret = mtk_find_possible_crtcs(drm, dsi->host.dev); + if (ret < 0) + goto err_cleanup_encoder; + dsi->encoder.possible_crtcs = ret; ret = drm_bridge_attach(&dsi->encoder, &dsi->bridge, NULL, DRM_BRIDGE_ATTACH_NO_CONNECTOR); @@ -903,9 +990,17 @@ static int mtk_dsi_host_attach(struct mipi_dsi_host *host, dsi->lanes = device->lanes; dsi->format = device->format; dsi->mode_flags = device->mode_flags; - dsi->next_bridge = devm_drm_of_get_bridge(dev, dev->of_node, 0, 0); - if (IS_ERR(dsi->next_bridge)) - return PTR_ERR(dsi->next_bridge); + dsi->next_bridge = devm_drm_of_get_bridge(dev, dev->of_node, 1, 0); + if (IS_ERR(dsi->next_bridge)) { + ret = PTR_ERR(dsi->next_bridge); + if (ret == -EPROBE_DEFER) + return ret; + + /* Old devicetree has only one endpoint */ + dsi->next_bridge = devm_drm_of_get_bridge(dev, dev->of_node, 0, 0); + if (IS_ERR(dsi->next_bridge)) + return PTR_ERR(dsi->next_bridge); + } drm_bridge_add(&dsi->bridge); @@ -1022,12 +1117,12 @@ static ssize_t mtk_dsi_host_transfer(struct mipi_dsi_host *host, const struct mipi_dsi_msg *msg) { struct mtk_dsi *dsi = host_to_dsi(host); - u32 recv_cnt, i; + ssize_t recv_cnt; u8 read_data[16]; void *src_addr; u8 irq_flag = CMD_DONE_INT_FLAG; u32 dsi_mode; - int ret; + int ret, i; dsi_mode = readl(dsi->regs + DSI_MODE_CTRL); if (dsi_mode & MODE) { @@ -1076,7 +1171,7 @@ static ssize_t mtk_dsi_host_transfer(struct mipi_dsi_host *host, if (recv_cnt) memcpy(msg->rx_buf, src_addr, recv_cnt); - DRM_INFO("dsi get %d byte data from the panel address(0x%x)\n", + DRM_INFO("dsi get %zd byte data from the panel address(0x%x)\n", recv_cnt, *((u8 *)(msg->tx_buf))); restore_dsi_mode: @@ -1098,7 +1193,6 @@ static int mtk_dsi_probe(struct platform_device *pdev) { struct mtk_dsi *dsi; struct device *dev = &pdev->dev; - struct resource *regs; int irq_num; int ret; @@ -1123,8 +1217,7 @@ static int mtk_dsi_probe(struct platform_device *pdev) if (IS_ERR(dsi->hs_clk)) return dev_err_probe(dev, PTR_ERR(dsi->hs_clk), "Failed to get hs clock\n"); - regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); - dsi->regs = devm_ioremap_resource(dev, regs); + dsi->regs = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(dsi->regs)) return dev_err_probe(dev, PTR_ERR(dsi->regs), "Failed to ioremap memory\n"); @@ -1170,29 +1263,40 @@ static void mtk_dsi_remove(struct platform_device *pdev) static const struct mtk_dsi_driver_data mt8173_dsi_driver_data = { .reg_cmdq_off = 0x200, + .reg_vm_cmd_off = 0x130, + .reg_shadow_dbg_off = 0x190 }; static const struct mtk_dsi_driver_data mt2701_dsi_driver_data = { .reg_cmdq_off = 0x180, + .reg_vm_cmd_off = 0x130, + .reg_shadow_dbg_off = 0x190 }; static const struct mtk_dsi_driver_data mt8183_dsi_driver_data = { .reg_cmdq_off = 0x200, + .reg_vm_cmd_off = 0x130, + .reg_shadow_dbg_off = 0x190, .has_shadow_ctl = true, .has_size_ctl = true, }; static const struct mtk_dsi_driver_data mt8186_dsi_driver_data = { .reg_cmdq_off = 0xd00, + .reg_vm_cmd_off = 0x200, + .reg_shadow_dbg_off = 0xc00, .has_shadow_ctl = true, .has_size_ctl = true, }; static const struct mtk_dsi_driver_data mt8188_dsi_driver_data = { .reg_cmdq_off = 0xd00, + .reg_vm_cmd_off = 0x200, + .reg_shadow_dbg_off = 0xc00, .has_shadow_ctl = true, .has_size_ctl = true, .cmdq_long_packet_ctl = true, + .support_per_frame_lp = true, }; static const struct of_device_id mtk_dsi_of_match[] = { @@ -1207,7 +1311,7 @@ MODULE_DEVICE_TABLE(of, mtk_dsi_of_match); struct platform_driver mtk_dsi_driver = { .probe = mtk_dsi_probe, - .remove_new = mtk_dsi_remove, + .remove = mtk_dsi_remove, .driver = { .name = "mtk-dsi", .of_match_table = mtk_dsi_of_match, |