Loading msm/dsi/dsi_catalog.c +14 −0 Original line number Diff line number Diff line Loading @@ -80,6 +80,10 @@ 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.configure_cmddma_window = NULL; ctrl->ops.reset_trig_ctrl = 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 @@ -95,6 +99,10 @@ 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.configure_cmddma_window = NULL; ctrl->ops.reset_trig_ctrl = 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 +124,12 @@ 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.configure_cmddma_window = dsi_ctrl_hw_22_configure_cmddma_window; ctrl->ops.reset_trig_ctrl = dsi_ctrl_hw_22_reset_trigger_controls; 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 +9 −0 Original line number Diff line number Diff line Loading @@ -274,4 +274,13 @@ 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); void dsi_ctrl_hw_22_configure_cmddma_window(struct dsi_ctrl_hw *ctrl, struct dsi_ctrl_cmd_dma_info *cmd, u32 line_no, u32 window); void dsi_ctrl_hw_22_reset_trigger_controls(struct dsi_ctrl_hw *ctrl, struct dsi_host_common_cfg *cfg); 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 +190 −18 Original line number Diff line number Diff line Loading @@ -194,6 +194,58 @@ static ssize_t debugfs_reg_dump_read(struct file *file, return len; } static ssize_t debugfs_line_count_read(struct file *file, char __user *user_buf, size_t user_len, loff_t *ppos) { struct dsi_ctrl *dsi_ctrl = file->private_data; char *buf; int rc = 0; u32 len = 0; size_t max_len = min_t(size_t, user_len, SZ_4K); if (!dsi_ctrl) return -ENODEV; if (*ppos) return 0; buf = kzalloc(max_len, GFP_KERNEL); if (ZERO_OR_NULL_PTR(buf)) return -ENOMEM; mutex_lock(&dsi_ctrl->ctrl_lock); len += scnprintf(buf, max_len, "Command triggered at line: %04x\n", dsi_ctrl->cmd_trigger_line); len += scnprintf((buf + len), max_len - len, "Command triggered at frame: %04x\n", dsi_ctrl->cmd_trigger_frame); len += scnprintf((buf + len), max_len - len, "Command successful at line: %04x\n", dsi_ctrl->cmd_success_line); len += scnprintf((buf + len), max_len - len, "Command successful at frame: %04x\n", dsi_ctrl->cmd_success_frame); mutex_unlock(&dsi_ctrl->ctrl_lock); if (len > max_len) len = max_len; if (copy_to_user(user_buf, buf, len)) { rc = -EFAULT; goto error; } *ppos += len; error: kfree(buf); return len; } static const struct file_operations state_info_fops = { .open = simple_open, .read = debugfs_state_info_read, Loading @@ -204,11 +256,16 @@ static const struct file_operations reg_dump_fops = { .read = debugfs_reg_dump_read, }; static const struct file_operations cmd_dma_stats_fops = { .open = simple_open, .read = debugfs_line_count_read, }; static int dsi_ctrl_debugfs_init(struct dsi_ctrl *dsi_ctrl, struct dentry *parent) { int rc = 0; struct dentry *dir, *state_file, *reg_dump; struct dentry *dir, *state_file, *reg_dump, *cmd_dma_logs; char dbg_name[DSI_DEBUG_NAME_LEN]; if (!dsi_ctrl || !parent) { Loading Loading @@ -246,6 +303,30 @@ static int dsi_ctrl_debugfs_init(struct dsi_ctrl *dsi_ctrl, goto error_remove_dir; } cmd_dma_logs = debugfs_create_bool("enable_cmd_dma_stats", 0600, dir, &dsi_ctrl->enable_cmd_dma_stats); if (IS_ERR_OR_NULL(cmd_dma_logs)) { rc = PTR_ERR(cmd_dma_logs); DSI_CTRL_ERR(dsi_ctrl, "enable cmd dma stats failed, rc=%d\n", rc); goto error_remove_dir; } cmd_dma_logs = debugfs_create_file("cmd_dma_stats", 0444, dir, dsi_ctrl, &cmd_dma_stats_fops); if (IS_ERR_OR_NULL(cmd_dma_logs)) { rc = PTR_ERR(cmd_dma_logs); DSI_CTRL_ERR(dsi_ctrl, "Line count file failed, rc=%d\n", rc); goto error_remove_dir; } dsi_ctrl->debugfs_root = dir; snprintf(dbg_name, DSI_DEBUG_NAME_LEN, "dsi%d_ctrl", Loading Loading @@ -1177,6 +1258,60 @@ int dsi_message_validate_tx_mode(struct dsi_ctrl *dsi_ctrl, return rc; } static void dsi_configure_command_scheduling(struct dsi_ctrl *dsi_ctrl, struct dsi_ctrl_cmd_dma_info *cmd_mem) { u32 line_no = 0, window = 0, sched_line_no = 0; struct dsi_ctrl_hw_ops dsi_hw_ops = dsi_ctrl->hw.ops; struct dsi_mode_info *timing = &(dsi_ctrl->host_config.video_timing); line_no = dsi_ctrl->host_config.common_config.dma_sched_line; window = dsi_ctrl->host_config.common_config.dma_sched_window; SDE_EVT32(dsi_ctrl->cell_index, SDE_EVTLOG_FUNC_ENTRY, line_no, window); /* * In case of command scheduling in video mode, the line at which * the command is scheduled can revert to the default value i.e. 1 * for the following cases: * 1) No schedule line defined by the panel. * 2) schedule line defined is greater than VFP. */ 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)) { sched_line_no = (line_no == 0) ? 1 : line_no; if (timing) { if (sched_line_no >= timing->v_front_porch) sched_line_no = 1; sched_line_no += timing->v_back_porch + timing->v_sync_width + timing->v_active; } dsi_hw_ops.schedule_dma_cmd(&dsi_ctrl->hw, sched_line_no); } /* * In case of command scheduling in command mode, the window size * is reset to zero, if the total scheduling window is greater * than the panel height. */ if ((dsi_ctrl->host_config.panel_mode == DSI_OP_CMD_MODE) && dsi_hw_ops.configure_cmddma_window) { sched_line_no = line_no; if ((sched_line_no + window) > timing->v_active) window = 0; sched_line_no += timing->v_active; dsi_hw_ops.configure_cmddma_window(&dsi_ctrl->hw, cmd_mem, sched_line_no, window); } SDE_EVT32(dsi_ctrl->cell_index, SDE_EVTLOG_FUNC_EXIT, sched_line_no, window); } static void dsi_kickoff_msg_tx(struct dsi_ctrl *dsi_ctrl, const struct mipi_dsi_msg *msg, struct dsi_ctrl_cmd_dma_fifo_info *cmd, Loading @@ -1184,27 +1319,20 @@ static void dsi_kickoff_msg_tx(struct dsi_ctrl *dsi_ctrl, u32 flags) { 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); /* 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; 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)) dsi_hw_ops.schedule_dma_cmd(&dsi_ctrl->hw, line_no); if (dsi_ctrl->hw.reset_trig_ctrl) dsi_hw_ops.reset_trig_ctrl(&dsi_ctrl->hw, &dsi_ctrl->host_config.common_config); /* check if custom dma scheduling line needed */ if (flags & DSI_CTRL_CMD_CUSTOM_DMA_SCHED) dsi_configure_command_scheduling(dsi_ctrl, cmd_mem); 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 @@ -1259,6 +1387,17 @@ static void dsi_kickoff_msg_tx(struct dsi_ctrl *dsi_ctrl, cmd, hw_flags); } if (dsi_ctrl->enable_cmd_dma_stats) { u32 reg = dsi_hw_ops.log_line_count(&dsi_ctrl->hw, dsi_ctrl->cmd_mode); dsi_ctrl->cmd_trigger_line = (reg & 0xFFFF); dsi_ctrl->cmd_trigger_frame = ((reg >> 16) & 0xFFFF); SDE_EVT32(dsi_ctrl->cell_index, SDE_EVTLOG_FUNC_CASE1, dsi_ctrl->cmd_trigger_line, dsi_ctrl->cmd_trigger_frame); } if (flags & DSI_CTRL_CMD_ASYNC_WAIT) { dsi_ctrl->dma_wait_queued = true; queue_work(dsi_ctrl->dma_cmd_workq, Loading Loading @@ -1921,6 +2060,9 @@ static int dsi_ctrl_dev_probe(struct platform_device *pdev) goto fail_clks; } if (dsi_ctrl->hw.ops.map_mdp_regs) dsi_ctrl->hw.ops.map_mdp_regs(pdev, &dsi_ctrl->hw); item->ctrl = dsi_ctrl; sde_dbg_dsi_ctrl_register(dsi_ctrl->hw.base, dsi_ctrl->name); Loading Loading @@ -2584,6 +2726,15 @@ static irqreturn_t dsi_ctrl_isr(int irq, void *ptr) dsi_ctrl_handle_error_status(dsi_ctrl, errors); if (status & DSI_CMD_MODE_DMA_DONE) { if (dsi_ctrl->enable_cmd_dma_stats) { u32 reg = dsi_ctrl->hw.ops.log_line_count(&dsi_ctrl->hw, dsi_ctrl->cmd_mode); dsi_ctrl->cmd_success_line = (reg & 0xFFFF); dsi_ctrl->cmd_success_frame = ((reg >> 16) & 0xFFFF); SDE_EVT32(dsi_ctrl->cell_index, SDE_EVTLOG_FUNC_CASE1, dsi_ctrl->cmd_success_line, dsi_ctrl->cmd_success_frame); } atomic_set(&dsi_ctrl->dma_irq_trig, 1); dsi_ctrl_disable_status_interrupt(dsi_ctrl, DSI_SINT_CMD_MODE_DMA_DONE); Loading Loading @@ -3191,8 +3342,18 @@ int dsi_ctrl_cmd_tx_trigger(struct dsi_ctrl *dsi_ctrl, u32 flags) mutex_lock(&dsi_ctrl->ctrl_lock); if (!(flags & DSI_CTRL_CMD_BROADCAST_MASTER)) if (!(flags & DSI_CTRL_CMD_BROADCAST_MASTER)) { dsi_hw_ops.trigger_command_dma(&dsi_ctrl->hw); if (dsi_ctrl->enable_cmd_dma_stats) { u32 reg = dsi_hw_ops.log_line_count(&dsi_ctrl->hw, dsi_ctrl->cmd_mode); dsi_ctrl->cmd_trigger_line = (reg & 0xFFFF); dsi_ctrl->cmd_trigger_frame = ((reg >> 16) & 0xFFFF); SDE_EVT32(dsi_ctrl->cell_index, SDE_EVTLOG_FUNC_CASE1, dsi_ctrl->cmd_trigger_line, dsi_ctrl->cmd_trigger_frame); } } if ((flags & DSI_CTRL_CMD_BROADCAST) && (flags & DSI_CTRL_CMD_BROADCAST_MASTER)) { Loading @@ -3207,6 +3368,17 @@ int dsi_ctrl_cmd_tx_trigger(struct dsi_ctrl *dsi_ctrl, u32 flags) /* trigger command */ dsi_hw_ops.trigger_command_dma(&dsi_ctrl->hw); if (dsi_ctrl->enable_cmd_dma_stats) { u32 reg = dsi_hw_ops.log_line_count(&dsi_ctrl->hw, dsi_ctrl->cmd_mode); dsi_ctrl->cmd_trigger_line = (reg & 0xFFFF); dsi_ctrl->cmd_trigger_frame = ((reg >> 16) & 0xFFFF); SDE_EVT32(dsi_ctrl->cell_index, SDE_EVTLOG_FUNC_CASE1, dsi_ctrl->cmd_trigger_line, dsi_ctrl->cmd_trigger_frame); } 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 +19 −0 Original line number Diff line number Diff line Loading @@ -229,6 +229,19 @@ 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. * @enable_cmd_dma_stats: Boolean to indicate the verbose logging during * CMD transfer. * count. * @cmd_mode: Boolean to indicate if panel is running in * command mode. * @cmd_trigger_line: unsigned integer that indicates the line at * which command gets triggered. * @cmd_trigger_frame: unsigned integer that indicates the frame at * which command gets triggered. * @cmd_success_line: unsigned integer that indicates the line at * which command transfer is successful. * @cmd_success_frame: unsigned integer that indicates the frame at * which command transfer is successful. */ struct dsi_ctrl { struct platform_device *pdev; Loading Loading @@ -289,6 +302,12 @@ struct dsi_ctrl { bool null_insertion_enabled; bool modeupdated; bool split_link_supported; bool enable_cmd_dma_stats; bool cmd_mode; u32 cmd_trigger_line; u32 cmd_trigger_frame; u32 cmd_success_line; u32 cmd_success_frame; }; /** Loading msm/dsi/dsi_ctrl_hw.h +47 −0 Original line number Diff line number Diff line Loading @@ -831,6 +831,41 @@ 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.configure_cmddma_window() - configure DMA window for CMD TX * @ctrl: Pointer to the controller host hardware. * @cmd: Pointer to the DSI DMA command info. * @line_no: Line number at which the CMD needs to be triggered. * @window: Width of the DMA CMD window. */ void (*configure_cmddma_window)(struct dsi_ctrl_hw *ctrl, struct dsi_ctrl_cmd_dma_info *cmd, u32 line_no, u32 window); /** * hw.ops.reset_trig_ctrl() - resets trigger control of DSI controller * @ctrl: Pointer to the controller host hardware. * @cfg: Common configuration parameters. */ void (*reset_trig_ctrl)(struct dsi_ctrl_hw *ctrl, struct dsi_host_common_cfg *cfg); /** * 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 @@ -841,6 +876,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 @@ -852,6 +894,8 @@ struct dsi_ctrl_hw_ops { * @null_insertion_enabled: A boolean property to allow dsi controller to * insert null packet. * @widebus_support: 48 bit wide data bus is supported. * @reset_trig_ctrl: Boolean to indicate if trigger control needs to * be reset to default. */ struct dsi_ctrl_hw { void __iomem *base; Loading @@ -859,6 +903,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 @@ -873,6 +919,7 @@ struct dsi_ctrl_hw { bool phy_isolation_enabled; bool null_insertion_enabled; bool widebus_support; bool reset_trig_ctrl; }; #endif /* _DSI_CTRL_HW_H_ */ Loading
msm/dsi/dsi_catalog.c +14 −0 Original line number Diff line number Diff line Loading @@ -80,6 +80,10 @@ 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.configure_cmddma_window = NULL; ctrl->ops.reset_trig_ctrl = 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 @@ -95,6 +99,10 @@ 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.configure_cmddma_window = NULL; ctrl->ops.reset_trig_ctrl = 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 +124,12 @@ 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.configure_cmddma_window = dsi_ctrl_hw_22_configure_cmddma_window; ctrl->ops.reset_trig_ctrl = dsi_ctrl_hw_22_reset_trigger_controls; 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 +9 −0 Original line number Diff line number Diff line Loading @@ -274,4 +274,13 @@ 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); void dsi_ctrl_hw_22_configure_cmddma_window(struct dsi_ctrl_hw *ctrl, struct dsi_ctrl_cmd_dma_info *cmd, u32 line_no, u32 window); void dsi_ctrl_hw_22_reset_trigger_controls(struct dsi_ctrl_hw *ctrl, struct dsi_host_common_cfg *cfg); 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 +190 −18 Original line number Diff line number Diff line Loading @@ -194,6 +194,58 @@ static ssize_t debugfs_reg_dump_read(struct file *file, return len; } static ssize_t debugfs_line_count_read(struct file *file, char __user *user_buf, size_t user_len, loff_t *ppos) { struct dsi_ctrl *dsi_ctrl = file->private_data; char *buf; int rc = 0; u32 len = 0; size_t max_len = min_t(size_t, user_len, SZ_4K); if (!dsi_ctrl) return -ENODEV; if (*ppos) return 0; buf = kzalloc(max_len, GFP_KERNEL); if (ZERO_OR_NULL_PTR(buf)) return -ENOMEM; mutex_lock(&dsi_ctrl->ctrl_lock); len += scnprintf(buf, max_len, "Command triggered at line: %04x\n", dsi_ctrl->cmd_trigger_line); len += scnprintf((buf + len), max_len - len, "Command triggered at frame: %04x\n", dsi_ctrl->cmd_trigger_frame); len += scnprintf((buf + len), max_len - len, "Command successful at line: %04x\n", dsi_ctrl->cmd_success_line); len += scnprintf((buf + len), max_len - len, "Command successful at frame: %04x\n", dsi_ctrl->cmd_success_frame); mutex_unlock(&dsi_ctrl->ctrl_lock); if (len > max_len) len = max_len; if (copy_to_user(user_buf, buf, len)) { rc = -EFAULT; goto error; } *ppos += len; error: kfree(buf); return len; } static const struct file_operations state_info_fops = { .open = simple_open, .read = debugfs_state_info_read, Loading @@ -204,11 +256,16 @@ static const struct file_operations reg_dump_fops = { .read = debugfs_reg_dump_read, }; static const struct file_operations cmd_dma_stats_fops = { .open = simple_open, .read = debugfs_line_count_read, }; static int dsi_ctrl_debugfs_init(struct dsi_ctrl *dsi_ctrl, struct dentry *parent) { int rc = 0; struct dentry *dir, *state_file, *reg_dump; struct dentry *dir, *state_file, *reg_dump, *cmd_dma_logs; char dbg_name[DSI_DEBUG_NAME_LEN]; if (!dsi_ctrl || !parent) { Loading Loading @@ -246,6 +303,30 @@ static int dsi_ctrl_debugfs_init(struct dsi_ctrl *dsi_ctrl, goto error_remove_dir; } cmd_dma_logs = debugfs_create_bool("enable_cmd_dma_stats", 0600, dir, &dsi_ctrl->enable_cmd_dma_stats); if (IS_ERR_OR_NULL(cmd_dma_logs)) { rc = PTR_ERR(cmd_dma_logs); DSI_CTRL_ERR(dsi_ctrl, "enable cmd dma stats failed, rc=%d\n", rc); goto error_remove_dir; } cmd_dma_logs = debugfs_create_file("cmd_dma_stats", 0444, dir, dsi_ctrl, &cmd_dma_stats_fops); if (IS_ERR_OR_NULL(cmd_dma_logs)) { rc = PTR_ERR(cmd_dma_logs); DSI_CTRL_ERR(dsi_ctrl, "Line count file failed, rc=%d\n", rc); goto error_remove_dir; } dsi_ctrl->debugfs_root = dir; snprintf(dbg_name, DSI_DEBUG_NAME_LEN, "dsi%d_ctrl", Loading Loading @@ -1177,6 +1258,60 @@ int dsi_message_validate_tx_mode(struct dsi_ctrl *dsi_ctrl, return rc; } static void dsi_configure_command_scheduling(struct dsi_ctrl *dsi_ctrl, struct dsi_ctrl_cmd_dma_info *cmd_mem) { u32 line_no = 0, window = 0, sched_line_no = 0; struct dsi_ctrl_hw_ops dsi_hw_ops = dsi_ctrl->hw.ops; struct dsi_mode_info *timing = &(dsi_ctrl->host_config.video_timing); line_no = dsi_ctrl->host_config.common_config.dma_sched_line; window = dsi_ctrl->host_config.common_config.dma_sched_window; SDE_EVT32(dsi_ctrl->cell_index, SDE_EVTLOG_FUNC_ENTRY, line_no, window); /* * In case of command scheduling in video mode, the line at which * the command is scheduled can revert to the default value i.e. 1 * for the following cases: * 1) No schedule line defined by the panel. * 2) schedule line defined is greater than VFP. */ 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)) { sched_line_no = (line_no == 0) ? 1 : line_no; if (timing) { if (sched_line_no >= timing->v_front_porch) sched_line_no = 1; sched_line_no += timing->v_back_porch + timing->v_sync_width + timing->v_active; } dsi_hw_ops.schedule_dma_cmd(&dsi_ctrl->hw, sched_line_no); } /* * In case of command scheduling in command mode, the window size * is reset to zero, if the total scheduling window is greater * than the panel height. */ if ((dsi_ctrl->host_config.panel_mode == DSI_OP_CMD_MODE) && dsi_hw_ops.configure_cmddma_window) { sched_line_no = line_no; if ((sched_line_no + window) > timing->v_active) window = 0; sched_line_no += timing->v_active; dsi_hw_ops.configure_cmddma_window(&dsi_ctrl->hw, cmd_mem, sched_line_no, window); } SDE_EVT32(dsi_ctrl->cell_index, SDE_EVTLOG_FUNC_EXIT, sched_line_no, window); } static void dsi_kickoff_msg_tx(struct dsi_ctrl *dsi_ctrl, const struct mipi_dsi_msg *msg, struct dsi_ctrl_cmd_dma_fifo_info *cmd, Loading @@ -1184,27 +1319,20 @@ static void dsi_kickoff_msg_tx(struct dsi_ctrl *dsi_ctrl, u32 flags) { 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); /* 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; 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)) dsi_hw_ops.schedule_dma_cmd(&dsi_ctrl->hw, line_no); if (dsi_ctrl->hw.reset_trig_ctrl) dsi_hw_ops.reset_trig_ctrl(&dsi_ctrl->hw, &dsi_ctrl->host_config.common_config); /* check if custom dma scheduling line needed */ if (flags & DSI_CTRL_CMD_CUSTOM_DMA_SCHED) dsi_configure_command_scheduling(dsi_ctrl, cmd_mem); 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 @@ -1259,6 +1387,17 @@ static void dsi_kickoff_msg_tx(struct dsi_ctrl *dsi_ctrl, cmd, hw_flags); } if (dsi_ctrl->enable_cmd_dma_stats) { u32 reg = dsi_hw_ops.log_line_count(&dsi_ctrl->hw, dsi_ctrl->cmd_mode); dsi_ctrl->cmd_trigger_line = (reg & 0xFFFF); dsi_ctrl->cmd_trigger_frame = ((reg >> 16) & 0xFFFF); SDE_EVT32(dsi_ctrl->cell_index, SDE_EVTLOG_FUNC_CASE1, dsi_ctrl->cmd_trigger_line, dsi_ctrl->cmd_trigger_frame); } if (flags & DSI_CTRL_CMD_ASYNC_WAIT) { dsi_ctrl->dma_wait_queued = true; queue_work(dsi_ctrl->dma_cmd_workq, Loading Loading @@ -1921,6 +2060,9 @@ static int dsi_ctrl_dev_probe(struct platform_device *pdev) goto fail_clks; } if (dsi_ctrl->hw.ops.map_mdp_regs) dsi_ctrl->hw.ops.map_mdp_regs(pdev, &dsi_ctrl->hw); item->ctrl = dsi_ctrl; sde_dbg_dsi_ctrl_register(dsi_ctrl->hw.base, dsi_ctrl->name); Loading Loading @@ -2584,6 +2726,15 @@ static irqreturn_t dsi_ctrl_isr(int irq, void *ptr) dsi_ctrl_handle_error_status(dsi_ctrl, errors); if (status & DSI_CMD_MODE_DMA_DONE) { if (dsi_ctrl->enable_cmd_dma_stats) { u32 reg = dsi_ctrl->hw.ops.log_line_count(&dsi_ctrl->hw, dsi_ctrl->cmd_mode); dsi_ctrl->cmd_success_line = (reg & 0xFFFF); dsi_ctrl->cmd_success_frame = ((reg >> 16) & 0xFFFF); SDE_EVT32(dsi_ctrl->cell_index, SDE_EVTLOG_FUNC_CASE1, dsi_ctrl->cmd_success_line, dsi_ctrl->cmd_success_frame); } atomic_set(&dsi_ctrl->dma_irq_trig, 1); dsi_ctrl_disable_status_interrupt(dsi_ctrl, DSI_SINT_CMD_MODE_DMA_DONE); Loading Loading @@ -3191,8 +3342,18 @@ int dsi_ctrl_cmd_tx_trigger(struct dsi_ctrl *dsi_ctrl, u32 flags) mutex_lock(&dsi_ctrl->ctrl_lock); if (!(flags & DSI_CTRL_CMD_BROADCAST_MASTER)) if (!(flags & DSI_CTRL_CMD_BROADCAST_MASTER)) { dsi_hw_ops.trigger_command_dma(&dsi_ctrl->hw); if (dsi_ctrl->enable_cmd_dma_stats) { u32 reg = dsi_hw_ops.log_line_count(&dsi_ctrl->hw, dsi_ctrl->cmd_mode); dsi_ctrl->cmd_trigger_line = (reg & 0xFFFF); dsi_ctrl->cmd_trigger_frame = ((reg >> 16) & 0xFFFF); SDE_EVT32(dsi_ctrl->cell_index, SDE_EVTLOG_FUNC_CASE1, dsi_ctrl->cmd_trigger_line, dsi_ctrl->cmd_trigger_frame); } } if ((flags & DSI_CTRL_CMD_BROADCAST) && (flags & DSI_CTRL_CMD_BROADCAST_MASTER)) { Loading @@ -3207,6 +3368,17 @@ int dsi_ctrl_cmd_tx_trigger(struct dsi_ctrl *dsi_ctrl, u32 flags) /* trigger command */ dsi_hw_ops.trigger_command_dma(&dsi_ctrl->hw); if (dsi_ctrl->enable_cmd_dma_stats) { u32 reg = dsi_hw_ops.log_line_count(&dsi_ctrl->hw, dsi_ctrl->cmd_mode); dsi_ctrl->cmd_trigger_line = (reg & 0xFFFF); dsi_ctrl->cmd_trigger_frame = ((reg >> 16) & 0xFFFF); SDE_EVT32(dsi_ctrl->cell_index, SDE_EVTLOG_FUNC_CASE1, dsi_ctrl->cmd_trigger_line, dsi_ctrl->cmd_trigger_frame); } 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 +19 −0 Original line number Diff line number Diff line Loading @@ -229,6 +229,19 @@ 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. * @enable_cmd_dma_stats: Boolean to indicate the verbose logging during * CMD transfer. * count. * @cmd_mode: Boolean to indicate if panel is running in * command mode. * @cmd_trigger_line: unsigned integer that indicates the line at * which command gets triggered. * @cmd_trigger_frame: unsigned integer that indicates the frame at * which command gets triggered. * @cmd_success_line: unsigned integer that indicates the line at * which command transfer is successful. * @cmd_success_frame: unsigned integer that indicates the frame at * which command transfer is successful. */ struct dsi_ctrl { struct platform_device *pdev; Loading Loading @@ -289,6 +302,12 @@ struct dsi_ctrl { bool null_insertion_enabled; bool modeupdated; bool split_link_supported; bool enable_cmd_dma_stats; bool cmd_mode; u32 cmd_trigger_line; u32 cmd_trigger_frame; u32 cmd_success_line; u32 cmd_success_frame; }; /** Loading
msm/dsi/dsi_ctrl_hw.h +47 −0 Original line number Diff line number Diff line Loading @@ -831,6 +831,41 @@ 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.configure_cmddma_window() - configure DMA window for CMD TX * @ctrl: Pointer to the controller host hardware. * @cmd: Pointer to the DSI DMA command info. * @line_no: Line number at which the CMD needs to be triggered. * @window: Width of the DMA CMD window. */ void (*configure_cmddma_window)(struct dsi_ctrl_hw *ctrl, struct dsi_ctrl_cmd_dma_info *cmd, u32 line_no, u32 window); /** * hw.ops.reset_trig_ctrl() - resets trigger control of DSI controller * @ctrl: Pointer to the controller host hardware. * @cfg: Common configuration parameters. */ void (*reset_trig_ctrl)(struct dsi_ctrl_hw *ctrl, struct dsi_host_common_cfg *cfg); /** * 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 @@ -841,6 +876,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 @@ -852,6 +894,8 @@ struct dsi_ctrl_hw_ops { * @null_insertion_enabled: A boolean property to allow dsi controller to * insert null packet. * @widebus_support: 48 bit wide data bus is supported. * @reset_trig_ctrl: Boolean to indicate if trigger control needs to * be reset to default. */ struct dsi_ctrl_hw { void __iomem *base; Loading @@ -859,6 +903,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 @@ -873,6 +919,7 @@ struct dsi_ctrl_hw { bool phy_isolation_enabled; bool null_insertion_enabled; bool widebus_support; bool reset_trig_ctrl; }; #endif /* _DSI_CTRL_HW_H_ */