Loading msm/dsi/dsi_catalog.c +7 −1 Original line number Diff line number Diff line // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2015-2019, The Linux Foundation. All rights reserved. * Copyright (c) 2015-2020, The Linux Foundation. All rights reserved. */ #include <linux/errno.h> Loading Loading @@ -81,6 +81,8 @@ static void dsi_catalog_cmn_init(struct dsi_ctrl_hw *ctrl, ctrl->ops.schedule_dma_cmd = NULL; ctrl->ops.kickoff_command_non_embedded_mode = NULL; ctrl->ops.config_clk_gating = NULL; ctrl->ops.map_mdp_regs = NULL; ctrl->ops.log_line_count = NULL; break; case DSI_CTRL_VERSION_2_0: ctrl->ops.setup_lane_map = dsi_ctrl_hw_20_setup_lane_map; Loading @@ -96,6 +98,8 @@ static void dsi_catalog_cmn_init(struct dsi_ctrl_hw *ctrl, ctrl->ops.schedule_dma_cmd = NULL; ctrl->ops.kickoff_command_non_embedded_mode = NULL; ctrl->ops.config_clk_gating = NULL; ctrl->ops.map_mdp_regs = NULL; ctrl->ops.log_line_count = NULL; break; case DSI_CTRL_VERSION_2_2: case DSI_CTRL_VERSION_2_3: Loading @@ -116,6 +120,8 @@ static void dsi_catalog_cmn_init(struct dsi_ctrl_hw *ctrl, ctrl->ops.schedule_dma_cmd = dsi_ctrl_hw_22_schedule_dma_cmd; ctrl->ops.kickoff_command_non_embedded_mode = dsi_ctrl_hw_kickoff_non_embedded_mode; ctrl->ops.map_mdp_regs = dsi_ctrl_hw_22_map_mdp_regs; ctrl->ops.log_line_count = dsi_ctrl_hw_22_log_line_count; break; default: break; Loading msm/dsi/dsi_catalog.h +6 −1 Original line number Diff line number Diff line /* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (c) 2015-2019, The Linux Foundation. All rights reserved. * Copyright (c) 2015-2020, The Linux Foundation. All rights reserved. */ #ifndef _DSI_CATALOG_H_ Loading Loading @@ -270,4 +270,9 @@ void dsi_phy_hw_v4_0_dyn_refresh_pipe_delay(struct dsi_phy_hw *phy, int dsi_phy_hw_v4_0_cache_phy_timings(struct dsi_phy_per_lane_cfgs *timings, u32 *dst, u32 size); int dsi_ctrl_hw_22_map_mdp_regs(struct platform_device *pdev, struct dsi_ctrl_hw *ctrl); u32 dsi_ctrl_hw_22_log_line_count(struct dsi_ctrl_hw *ctrl, bool cmd_mode); #endif /* _DSI_CATALOG_H_ */ msm/dsi/dsi_ctrl.c +71 −10 Original line number Diff line number Diff line Loading @@ -1219,6 +1219,24 @@ int dsi_message_validate_tx_mode(struct dsi_ctrl *dsi_ctrl, return rc; } static u32 calculate_schedule_line(struct dsi_ctrl *dsi_ctrl, u32 flags) { u32 line_no = 0x1; struct dsi_mode_info *timing; /* check if custom dma scheduling line needed */ if ((dsi_ctrl->host_config.panel_mode == DSI_OP_VIDEO_MODE) && (flags & DSI_CTRL_CMD_CUSTOM_DMA_SCHED)) line_no = dsi_ctrl->host_config.u.video_engine.dma_sched_line; timing = &(dsi_ctrl->host_config.video_timing); if (timing) line_no += timing->v_back_porch + timing->v_sync_width + timing->v_active; return line_no; } static void dsi_kickoff_msg_tx(struct dsi_ctrl *dsi_ctrl, const struct mipi_dsi_msg *msg, Loading @@ -1228,20 +1246,13 @@ static void dsi_kickoff_msg_tx(struct dsi_ctrl *dsi_ctrl, { u32 hw_flags = 0; u32 line_no = 0x1; struct dsi_mode_info *timing; struct dsi_ctrl_hw_ops dsi_hw_ops = dsi_ctrl->hw.ops; SDE_EVT32(dsi_ctrl->cell_index, SDE_EVTLOG_FUNC_ENTRY, flags, msg->flags); /* check if custom dma scheduling line needed */ if ((dsi_ctrl->host_config.panel_mode == DSI_OP_VIDEO_MODE) && (flags & DSI_CTRL_CMD_CUSTOM_DMA_SCHED)) line_no = dsi_ctrl->host_config.u.video_engine.dma_sched_line; timing = &(dsi_ctrl->host_config.video_timing); if (timing) line_no += timing->v_back_porch + timing->v_sync_width + timing->v_active; line_no = calculate_schedule_line(dsi_ctrl, flags); if ((dsi_ctrl->host_config.panel_mode == DSI_OP_VIDEO_MODE) && dsi_hw_ops.schedule_dma_cmd && (dsi_ctrl->current_state.vid_engine_state == Loading @@ -1249,6 +1260,8 @@ static void dsi_kickoff_msg_tx(struct dsi_ctrl *dsi_ctrl, dsi_hw_ops.schedule_dma_cmd(&dsi_ctrl->hw, line_no); dsi_ctrl->cmd_mode = (dsi_ctrl->host_config.panel_mode == DSI_OP_CMD_MODE); hw_flags |= (flags & DSI_CTRL_CMD_DEFER_TRIGGER) ? DSI_CTRL_HW_CMD_WAIT_FOR_TRIGGER : 0; Loading Loading @@ -1967,6 +1980,9 @@ static int dsi_ctrl_dev_probe(struct platform_device *pdev) DSI_CTRL_DEBUG(dsi_ctrl, "failed to init axi bus client, rc = %d\n", rc); if (dsi_ctrl->hw.ops.map_mdp_regs) dsi_ctrl->hw.ops.map_mdp_regs(pdev, &dsi_ctrl->hw); item->ctrl = dsi_ctrl; mutex_lock(&dsi_ctrl_list_lock); Loading Loading @@ -3298,6 +3314,10 @@ int dsi_ctrl_cmd_tx_trigger(struct dsi_ctrl *dsi_ctrl, u32 flags) { int rc = 0; struct dsi_ctrl_hw_ops dsi_hw_ops; u32 v_total = 0, fps = 0, cur_line = 0, mem_latency_us = 100; u32 line_time = 0, schedule_line = 0x1, latency_by_line = 0; struct dsi_mode_info *timing; unsigned long flag; if (!dsi_ctrl) { DSI_CTRL_ERR(dsi_ctrl, "Invalid params\n"); Loading @@ -3313,6 +3333,18 @@ int dsi_ctrl_cmd_tx_trigger(struct dsi_ctrl *dsi_ctrl, u32 flags) mutex_lock(&dsi_ctrl->ctrl_lock); timing = &(dsi_ctrl->host_config.video_timing); if (timing && (dsi_ctrl->host_config.panel_mode == DSI_OP_VIDEO_MODE)) { v_total = timing->v_sync_width + timing->v_back_porch + timing->v_front_porch + timing->v_active; fps = timing->refresh_rate; schedule_line = calculate_schedule_line(dsi_ctrl, flags); line_time = (1000000 / fps) / v_total; latency_by_line = CEIL(mem_latency_us, line_time); } if (!(flags & DSI_CTRL_CMD_BROADCAST_MASTER)) dsi_hw_ops.trigger_command_dma(&dsi_ctrl->hw); Loading @@ -3325,7 +3357,36 @@ int dsi_ctrl_cmd_tx_trigger(struct dsi_ctrl *dsi_ctrl, u32 flags) reinit_completion(&dsi_ctrl->irq_info.cmd_dma_done); /* trigger command */ if ((dsi_ctrl->host_config.panel_mode == DSI_OP_VIDEO_MODE) && dsi_hw_ops.schedule_dma_cmd && (dsi_ctrl->current_state.vid_engine_state == DSI_CTRL_ENGINE_ON)) { /* * This change reads the video line count from * MDP_INTF_LINE_COUNT register and checks whether * DMA trigger happens close to the schedule line. * If it is not close to the schedule line, then DMA * command transfer is triggered. */ while (1) { local_irq_save(flag); cur_line = dsi_hw_ops.log_line_count(&dsi_ctrl->hw, dsi_ctrl->cmd_mode); if (cur_line < (schedule_line - latency_by_line) || cur_line > (schedule_line + 1)) { dsi_hw_ops.trigger_command_dma( &dsi_ctrl->hw); local_irq_restore(flag); break; } local_irq_restore(flag); udelay(1000); } } else dsi_hw_ops.trigger_command_dma(&dsi_ctrl->hw); if (flags & DSI_CTRL_CMD_ASYNC_WAIT) { dsi_ctrl->dma_wait_queued = true; queue_work(dsi_ctrl->dma_cmd_workq, Loading msm/dsi/dsi_ctrl.h +3 −0 Original line number Diff line number Diff line Loading @@ -239,6 +239,8 @@ struct dsi_ctrl_interrupts { * insert null packet. * @modeupdated: Boolean to send new roi if mode is updated. * @split_link_supported: Boolean to check if hw supports split link. * @cmd_mode: Boolean to indicate if panel is running in command mode. */ struct dsi_ctrl { struct platform_device *pdev; Loading Loading @@ -299,6 +301,7 @@ struct dsi_ctrl { bool null_insertion_enabled; bool modeupdated; bool split_link_supported; bool cmd_mode; }; /** Loading msm/dsi/dsi_ctrl_hw.h +25 −0 Original line number Diff line number Diff line Loading @@ -838,6 +838,22 @@ struct dsi_ctrl_hw_ops { * @sel_phy: Bool to control whether to select phy or controller */ void (*hs_req_sel)(struct dsi_ctrl_hw *ctrl, bool sel_phy); /** * hw.ops.map_mdp_regs() - maps MDP interface line count registers. * @pdev:» Pointer to platform device. * @ctrl:» Pointer to the controller host hardware. */ int (*map_mdp_regs)(struct platform_device *pdev, struct dsi_ctrl_hw *ctrl); /** * hw.ops.log_line_count() - reads the MDP interface line count * registers. * @ctrl:» Pointer to the controller host hardware. * @cmd_mode:» Boolean to indicate command mode operation. */ u32 (*log_line_count)(struct dsi_ctrl_hw *ctrl, bool cmd_mode); }; /* Loading @@ -848,6 +864,13 @@ struct dsi_ctrl_hw_ops { * @mmss_misc_length: Length of mmss_misc register map. * @disp_cc_base: Base address of disp_cc register map. * @disp_cc_length: Length of disp_cc register map. * @te_rd_ptr_reg: Address of MDP_TEAR_INTF_TEAR_LINE_COUNT. This * register is used for testing and validating the RD * ptr value when a CMD is triggered and it succeeds. * @line_count_reg: Address of MDP_TEAR_INTF_LINE_COUNT. This * register is used for testing and validating the * line count value when a CMD is triggered and it * succeeds. * @index: Instance ID of the controller. * @feature_map: Features supported by the DSI controller. * @ops: Function pointers to the operations supported by the Loading @@ -865,6 +888,8 @@ struct dsi_ctrl_hw { void __iomem *mmss_misc_base; u32 mmss_misc_length; void __iomem *disp_cc_base; void __iomem *te_rd_ptr_reg; void __iomem *line_count_reg; u32 disp_cc_length; u32 index; Loading Loading
msm/dsi/dsi_catalog.c +7 −1 Original line number Diff line number Diff line // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2015-2019, The Linux Foundation. All rights reserved. * Copyright (c) 2015-2020, The Linux Foundation. All rights reserved. */ #include <linux/errno.h> Loading Loading @@ -81,6 +81,8 @@ static void dsi_catalog_cmn_init(struct dsi_ctrl_hw *ctrl, ctrl->ops.schedule_dma_cmd = NULL; ctrl->ops.kickoff_command_non_embedded_mode = NULL; ctrl->ops.config_clk_gating = NULL; ctrl->ops.map_mdp_regs = NULL; ctrl->ops.log_line_count = NULL; break; case DSI_CTRL_VERSION_2_0: ctrl->ops.setup_lane_map = dsi_ctrl_hw_20_setup_lane_map; Loading @@ -96,6 +98,8 @@ static void dsi_catalog_cmn_init(struct dsi_ctrl_hw *ctrl, ctrl->ops.schedule_dma_cmd = NULL; ctrl->ops.kickoff_command_non_embedded_mode = NULL; ctrl->ops.config_clk_gating = NULL; ctrl->ops.map_mdp_regs = NULL; ctrl->ops.log_line_count = NULL; break; case DSI_CTRL_VERSION_2_2: case DSI_CTRL_VERSION_2_3: Loading @@ -116,6 +120,8 @@ static void dsi_catalog_cmn_init(struct dsi_ctrl_hw *ctrl, ctrl->ops.schedule_dma_cmd = dsi_ctrl_hw_22_schedule_dma_cmd; ctrl->ops.kickoff_command_non_embedded_mode = dsi_ctrl_hw_kickoff_non_embedded_mode; ctrl->ops.map_mdp_regs = dsi_ctrl_hw_22_map_mdp_regs; ctrl->ops.log_line_count = dsi_ctrl_hw_22_log_line_count; break; default: break; Loading
msm/dsi/dsi_catalog.h +6 −1 Original line number Diff line number Diff line /* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (c) 2015-2019, The Linux Foundation. All rights reserved. * Copyright (c) 2015-2020, The Linux Foundation. All rights reserved. */ #ifndef _DSI_CATALOG_H_ Loading Loading @@ -270,4 +270,9 @@ void dsi_phy_hw_v4_0_dyn_refresh_pipe_delay(struct dsi_phy_hw *phy, int dsi_phy_hw_v4_0_cache_phy_timings(struct dsi_phy_per_lane_cfgs *timings, u32 *dst, u32 size); int dsi_ctrl_hw_22_map_mdp_regs(struct platform_device *pdev, struct dsi_ctrl_hw *ctrl); u32 dsi_ctrl_hw_22_log_line_count(struct dsi_ctrl_hw *ctrl, bool cmd_mode); #endif /* _DSI_CATALOG_H_ */
msm/dsi/dsi_ctrl.c +71 −10 Original line number Diff line number Diff line Loading @@ -1219,6 +1219,24 @@ int dsi_message_validate_tx_mode(struct dsi_ctrl *dsi_ctrl, return rc; } static u32 calculate_schedule_line(struct dsi_ctrl *dsi_ctrl, u32 flags) { u32 line_no = 0x1; struct dsi_mode_info *timing; /* check if custom dma scheduling line needed */ if ((dsi_ctrl->host_config.panel_mode == DSI_OP_VIDEO_MODE) && (flags & DSI_CTRL_CMD_CUSTOM_DMA_SCHED)) line_no = dsi_ctrl->host_config.u.video_engine.dma_sched_line; timing = &(dsi_ctrl->host_config.video_timing); if (timing) line_no += timing->v_back_porch + timing->v_sync_width + timing->v_active; return line_no; } static void dsi_kickoff_msg_tx(struct dsi_ctrl *dsi_ctrl, const struct mipi_dsi_msg *msg, Loading @@ -1228,20 +1246,13 @@ static void dsi_kickoff_msg_tx(struct dsi_ctrl *dsi_ctrl, { u32 hw_flags = 0; u32 line_no = 0x1; struct dsi_mode_info *timing; struct dsi_ctrl_hw_ops dsi_hw_ops = dsi_ctrl->hw.ops; SDE_EVT32(dsi_ctrl->cell_index, SDE_EVTLOG_FUNC_ENTRY, flags, msg->flags); /* check if custom dma scheduling line needed */ if ((dsi_ctrl->host_config.panel_mode == DSI_OP_VIDEO_MODE) && (flags & DSI_CTRL_CMD_CUSTOM_DMA_SCHED)) line_no = dsi_ctrl->host_config.u.video_engine.dma_sched_line; timing = &(dsi_ctrl->host_config.video_timing); if (timing) line_no += timing->v_back_porch + timing->v_sync_width + timing->v_active; line_no = calculate_schedule_line(dsi_ctrl, flags); if ((dsi_ctrl->host_config.panel_mode == DSI_OP_VIDEO_MODE) && dsi_hw_ops.schedule_dma_cmd && (dsi_ctrl->current_state.vid_engine_state == Loading @@ -1249,6 +1260,8 @@ static void dsi_kickoff_msg_tx(struct dsi_ctrl *dsi_ctrl, dsi_hw_ops.schedule_dma_cmd(&dsi_ctrl->hw, line_no); dsi_ctrl->cmd_mode = (dsi_ctrl->host_config.panel_mode == DSI_OP_CMD_MODE); hw_flags |= (flags & DSI_CTRL_CMD_DEFER_TRIGGER) ? DSI_CTRL_HW_CMD_WAIT_FOR_TRIGGER : 0; Loading Loading @@ -1967,6 +1980,9 @@ static int dsi_ctrl_dev_probe(struct platform_device *pdev) DSI_CTRL_DEBUG(dsi_ctrl, "failed to init axi bus client, rc = %d\n", rc); if (dsi_ctrl->hw.ops.map_mdp_regs) dsi_ctrl->hw.ops.map_mdp_regs(pdev, &dsi_ctrl->hw); item->ctrl = dsi_ctrl; mutex_lock(&dsi_ctrl_list_lock); Loading Loading @@ -3298,6 +3314,10 @@ int dsi_ctrl_cmd_tx_trigger(struct dsi_ctrl *dsi_ctrl, u32 flags) { int rc = 0; struct dsi_ctrl_hw_ops dsi_hw_ops; u32 v_total = 0, fps = 0, cur_line = 0, mem_latency_us = 100; u32 line_time = 0, schedule_line = 0x1, latency_by_line = 0; struct dsi_mode_info *timing; unsigned long flag; if (!dsi_ctrl) { DSI_CTRL_ERR(dsi_ctrl, "Invalid params\n"); Loading @@ -3313,6 +3333,18 @@ int dsi_ctrl_cmd_tx_trigger(struct dsi_ctrl *dsi_ctrl, u32 flags) mutex_lock(&dsi_ctrl->ctrl_lock); timing = &(dsi_ctrl->host_config.video_timing); if (timing && (dsi_ctrl->host_config.panel_mode == DSI_OP_VIDEO_MODE)) { v_total = timing->v_sync_width + timing->v_back_porch + timing->v_front_porch + timing->v_active; fps = timing->refresh_rate; schedule_line = calculate_schedule_line(dsi_ctrl, flags); line_time = (1000000 / fps) / v_total; latency_by_line = CEIL(mem_latency_us, line_time); } if (!(flags & DSI_CTRL_CMD_BROADCAST_MASTER)) dsi_hw_ops.trigger_command_dma(&dsi_ctrl->hw); Loading @@ -3325,7 +3357,36 @@ int dsi_ctrl_cmd_tx_trigger(struct dsi_ctrl *dsi_ctrl, u32 flags) reinit_completion(&dsi_ctrl->irq_info.cmd_dma_done); /* trigger command */ if ((dsi_ctrl->host_config.panel_mode == DSI_OP_VIDEO_MODE) && dsi_hw_ops.schedule_dma_cmd && (dsi_ctrl->current_state.vid_engine_state == DSI_CTRL_ENGINE_ON)) { /* * This change reads the video line count from * MDP_INTF_LINE_COUNT register and checks whether * DMA trigger happens close to the schedule line. * If it is not close to the schedule line, then DMA * command transfer is triggered. */ while (1) { local_irq_save(flag); cur_line = dsi_hw_ops.log_line_count(&dsi_ctrl->hw, dsi_ctrl->cmd_mode); if (cur_line < (schedule_line - latency_by_line) || cur_line > (schedule_line + 1)) { dsi_hw_ops.trigger_command_dma( &dsi_ctrl->hw); local_irq_restore(flag); break; } local_irq_restore(flag); udelay(1000); } } else dsi_hw_ops.trigger_command_dma(&dsi_ctrl->hw); if (flags & DSI_CTRL_CMD_ASYNC_WAIT) { dsi_ctrl->dma_wait_queued = true; queue_work(dsi_ctrl->dma_cmd_workq, Loading
msm/dsi/dsi_ctrl.h +3 −0 Original line number Diff line number Diff line Loading @@ -239,6 +239,8 @@ struct dsi_ctrl_interrupts { * insert null packet. * @modeupdated: Boolean to send new roi if mode is updated. * @split_link_supported: Boolean to check if hw supports split link. * @cmd_mode: Boolean to indicate if panel is running in command mode. */ struct dsi_ctrl { struct platform_device *pdev; Loading Loading @@ -299,6 +301,7 @@ struct dsi_ctrl { bool null_insertion_enabled; bool modeupdated; bool split_link_supported; bool cmd_mode; }; /** Loading
msm/dsi/dsi_ctrl_hw.h +25 −0 Original line number Diff line number Diff line Loading @@ -838,6 +838,22 @@ struct dsi_ctrl_hw_ops { * @sel_phy: Bool to control whether to select phy or controller */ void (*hs_req_sel)(struct dsi_ctrl_hw *ctrl, bool sel_phy); /** * hw.ops.map_mdp_regs() - maps MDP interface line count registers. * @pdev:» Pointer to platform device. * @ctrl:» Pointer to the controller host hardware. */ int (*map_mdp_regs)(struct platform_device *pdev, struct dsi_ctrl_hw *ctrl); /** * hw.ops.log_line_count() - reads the MDP interface line count * registers. * @ctrl:» Pointer to the controller host hardware. * @cmd_mode:» Boolean to indicate command mode operation. */ u32 (*log_line_count)(struct dsi_ctrl_hw *ctrl, bool cmd_mode); }; /* Loading @@ -848,6 +864,13 @@ struct dsi_ctrl_hw_ops { * @mmss_misc_length: Length of mmss_misc register map. * @disp_cc_base: Base address of disp_cc register map. * @disp_cc_length: Length of disp_cc register map. * @te_rd_ptr_reg: Address of MDP_TEAR_INTF_TEAR_LINE_COUNT. This * register is used for testing and validating the RD * ptr value when a CMD is triggered and it succeeds. * @line_count_reg: Address of MDP_TEAR_INTF_LINE_COUNT. This * register is used for testing and validating the * line count value when a CMD is triggered and it * succeeds. * @index: Instance ID of the controller. * @feature_map: Features supported by the DSI controller. * @ops: Function pointers to the operations supported by the Loading @@ -865,6 +888,8 @@ struct dsi_ctrl_hw { void __iomem *mmss_misc_base; u32 mmss_misc_length; void __iomem *disp_cc_base; void __iomem *te_rd_ptr_reg; void __iomem *line_count_reg; u32 disp_cc_length; u32 index; Loading