Loading drivers/video/msm/mdss/mdss_debug.c +105 −14 Original line number Diff line number Diff line /* Copyright (c) 2009-2015, The Linux Foundation. All rights reserved. /* Copyright (c) 2009-2016, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and Loading Loading @@ -1171,6 +1171,7 @@ static struct mdss_mdp_misr_map { u32 value_reg; u32 crc_op_mode; u32 crc_index; u32 last_misr; bool use_ping; bool is_ping_full; bool is_pong_full; Loading @@ -1183,6 +1184,7 @@ static struct mdss_mdp_misr_map { .value_reg = MDSS_MDP_LP_MISR_SIGN_DSI0, .crc_op_mode = 0, .crc_index = 0, .last_misr = 0, .use_ping = true, .is_ping_full = false, .is_pong_full = false, Loading @@ -1192,6 +1194,7 @@ static struct mdss_mdp_misr_map { .value_reg = MDSS_MDP_LP_MISR_SIGN_DSI1, .crc_op_mode = 0, .crc_index = 0, .last_misr = 0, .use_ping = true, .is_ping_full = false, .is_pong_full = false, Loading @@ -1201,6 +1204,7 @@ static struct mdss_mdp_misr_map { .value_reg = MDSS_MDP_LP_MISR_SIGN_EDP, .crc_op_mode = 0, .crc_index = 0, .last_misr = 0, .use_ping = true, .is_ping_full = false, .is_pong_full = false, Loading @@ -1210,6 +1214,7 @@ static struct mdss_mdp_misr_map { .value_reg = MDSS_MDP_LP_MISR_SIGN_HDMI, .crc_op_mode = 0, .crc_index = 0, .last_misr = 0, .use_ping = true, .is_ping_full = false, .is_pong_full = false, Loading @@ -1219,6 +1224,7 @@ static struct mdss_mdp_misr_map { .value_reg = MDSS_MDP_LP_MISR_SIGN_MDP, .crc_op_mode = 0, .crc_index = 0, .last_misr = 0, .use_ping = true, .is_ping_full = false, .is_pong_full = false, Loading @@ -1226,7 +1232,8 @@ static struct mdss_mdp_misr_map { }; static inline struct mdss_mdp_misr_map *mdss_misr_get_map(u32 block_id, struct mdss_mdp_ctl *ctl, struct mdss_data_type *mdata) struct mdss_mdp_ctl *ctl, struct mdss_data_type *mdata, bool is_video_mode) { struct mdss_mdp_misr_map *map; struct mdss_mdp_mixer *mixer; Loading Loading @@ -1259,11 +1266,23 @@ static inline struct mdss_mdp_misr_map *mdss_misr_get_map(u32 block_id, if ((block_id == DISPLAY_MISR_DSI0 || block_id == DISPLAY_MISR_DSI1) && (ctl && !ctl->is_video_mode)) { !is_video_mode) { ctrl_reg = intf_base + MDSS_MDP_INTF_CMD_MISR_CTRL; value_reg = intf_base + MDSS_MDP_INTF_CMD_MISR_SIGNATURE; /* * extra offset required for * cmd misr in 8996 */ if (IS_MDSS_MAJOR_MINOR_SAME( mdata->mdp_rev, MDSS_MDP_HW_REV_107)) { ctrl_reg += 0x8; value_reg += 0x8; } } else { ctrl_reg = intf_base + MDSS_MDP_INTF_MISR_CTRL; Loading Loading @@ -1325,6 +1344,33 @@ static bool switch_mdp_misr_offset(struct mdss_mdp_misr_map *map, u32 mdp_rev, return use_mdp_up_misr; } void mdss_misr_disable(struct mdss_data_type *mdata, struct mdp_misr *req, struct mdss_mdp_ctl *ctl) { struct mdss_mdp_misr_map *map; map = mdss_misr_get_map(req->block_id, ctl, mdata, ctl->is_video_mode); /* clear the map data */ memset(map->crc_ping, 0, sizeof(map->crc_ping)); memset(map->crc_pong, 0, sizeof(map->crc_pong)); map->crc_index = 0; map->use_ping = true; map->is_ping_full = false; map->is_pong_full = false; map->crc_op_mode = 0; map->last_misr = 0; /* disable MISR and clear the status */ writel_relaxed(MDSS_MDP_MISR_CTRL_STATUS_CLEAR, mdata->mdp_base + map->ctrl_reg); /* make sure status is clear */ wmb(); } int mdss_misr_set(struct mdss_data_type *mdata, struct mdp_misr *req, struct mdss_mdp_ctl *ctl) Loading @@ -1336,7 +1382,11 @@ int mdss_misr_set(struct mdss_data_type *mdata, bool is_valid_wb_mixer = true; bool use_mdp_up_misr = false; map = mdss_misr_get_map(req->block_id, ctl, mdata); pr_debug("req[block:%d frame:%d op_mode:%d]\n", req->block_id, req->frame_count, req->crc_op_mode); map = mdss_misr_get_map(req->block_id, ctl, mdata, ctl->is_video_mode); if (!map) { pr_err("Invalid MISR Block=%d\n", req->block_id); Loading Loading @@ -1409,8 +1459,9 @@ int mdss_misr_set(struct mdss_data_type *mdata, writel_relaxed(config, mdata->mdp_base + map->ctrl_reg); pr_debug("MISR_CTRL = 0x%x", readl_relaxed(mdata->mdp_base + map->ctrl_reg)); pr_debug("MISR_CTRL=0x%x [base:0x%p reg:0x%x config:0x%x]\n", readl_relaxed(mdata->mdp_base + map->ctrl_reg), mdata->mdp_base, map->ctrl_reg, config); } mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF); return 0; Loading @@ -1431,7 +1482,8 @@ char *get_misr_block_name(int misr_block_id) int mdss_misr_get(struct mdss_data_type *mdata, struct mdp_misr *resp, struct mdss_mdp_ctl *ctl) struct mdss_mdp_ctl *ctl, bool is_video_mode) { struct mdss_mdp_misr_map *map; struct mdss_mdp_mixer *mixer; Loading @@ -1439,7 +1491,11 @@ int mdss_misr_get(struct mdss_data_type *mdata, int ret = -1; int i; map = mdss_misr_get_map(resp->block_id, ctl, mdata); pr_debug("req[block:%d frame:%d op_mode:%d]\n", resp->block_id, resp->frame_count, resp->crc_op_mode); map = mdss_misr_get_map(resp->block_id, ctl, mdata, is_video_mode); if (!map) { pr_err("Invalid MISR Block=%d\n", resp->block_id); return -EINVAL; Loading Loading @@ -1515,31 +1571,37 @@ int mdss_misr_get(struct mdss_data_type *mdata, } /* This function is expected to be called from interrupt context */ void mdss_misr_crc_collect(struct mdss_data_type *mdata, int block_id) void mdss_misr_crc_collect(struct mdss_data_type *mdata, int block_id, bool is_video_mode) { struct mdss_mdp_misr_map *map; u32 status = 0; u32 crc = 0x0BAD0BAD; bool crc_stored = false; map = mdss_misr_get_map(block_id, NULL, mdata); map = mdss_misr_get_map(block_id, NULL, mdata, is_video_mode); if (!map || (map->crc_op_mode != MISR_OP_BM)) return; switch_mdp_misr_offset(map, mdata->mdp_rev, block_id); status = readl_relaxed(mdata->mdp_base + map->ctrl_reg); if (MDSS_MDP_MISR_CTRL_STATUS & status) { crc = readl_relaxed(mdata->mdp_base + map->value_reg); map->last_misr = crc; /* cache crc to get it from sysfs */ if (map->use_ping) { if (map->is_ping_full) { pr_err("PING Buffer FULL\n"); pr_err_once("PING Buffer FULL\n"); } else { map->crc_ping[map->crc_index] = crc; crc_stored = true; } } else { if (map->is_pong_full) { pr_err("PONG Buffer FULL\n"); pr_err_once("PONG Buffer FULL\n"); } else { map->crc_pong[map->crc_index] = crc; crc_stored = true; Loading @@ -1565,7 +1627,7 @@ void mdss_misr_crc_collect(struct mdss_data_type *mdata, int block_id) map->is_pong_full ? "FULL" : "EMPTRY"); } } else { pr_err("CRC(%d) Not saved\n", crc); pr_err_once("CRC(%d) Not saved\n", crc); } if (mdata->mdp_rev < MDSS_MDP_HW_REV_105) { Loading @@ -1574,7 +1636,9 @@ void mdss_misr_crc_collect(struct mdss_data_type *mdata, int block_id) writel_relaxed(MISR_CRC_BATCH_CFG, mdata->mdp_base + map->ctrl_reg); } } else if (0 == status) { if (mdata->mdp_rev < MDSS_MDP_HW_REV_105) writel_relaxed(MISR_CRC_BATCH_CFG, mdata->mdp_base + map->ctrl_reg); Loading @@ -1582,15 +1646,42 @@ void mdss_misr_crc_collect(struct mdss_data_type *mdata, int block_id) writel_relaxed(MISR_CRC_BATCH_CFG | MDSS_MDP_LP_MISR_CTRL_FREE_RUN_MASK, mdata->mdp_base + map->ctrl_reg); pr_debug("$$ Batch CRC Start $$\n"); } pr_debug("$$ Vsync Count = %d, CRC=0x%x Indx = %d$$\n", vsync_count, crc, map->crc_index); trace_mdp_misr_crc(block_id, vsync_count, crc); if (MAX_VSYNC_COUNT == vsync_count) { pr_err("RESET vsync_count(%d)\n", vsync_count); pr_debug("RESET vsync_count(%d)\n", vsync_count); vsync_count = 0; } else { vsync_count += 1; } } int mdss_dump_misr_data(char **buf, u32 size) { struct mdss_mdp_misr_map *dsi0_map; struct mdss_mdp_misr_map *dsi1_map; struct mdss_mdp_misr_map *hdmi_map; int ret; dsi0_map = &mdss_mdp_misr_table[DISPLAY_MISR_DSI0]; dsi1_map = &mdss_mdp_misr_table[DISPLAY_MISR_DSI1]; hdmi_map = &mdss_mdp_misr_table[DISPLAY_MISR_HDMI]; ret = scnprintf(*buf, PAGE_SIZE, "\tDSI0 mode:%02d MISR:0x%08x\n" "\tDSI1 mode:%02d MISR:0x%08x\n" "\tHDMI mode:%02d MISR:0x%08x\n", dsi0_map->crc_op_mode, dsi0_map->last_misr, dsi1_map->crc_op_mode, dsi1_map->last_misr, hdmi_map->crc_op_mode, hdmi_map->last_misr ); return ret; } drivers/video/msm/mdss/mdss_debug.h +21 −6 Original line number Diff line number Diff line /* Copyright (c) 2012-2015, The Linux Foundation. All rights reserved. /* Copyright (c) 2012-2016, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and Loading Loading @@ -146,11 +146,18 @@ void mdss_debug_register_dump_range(struct platform_device *pdev, const char *name_prop); int panel_debug_register_base(const char *name, void __iomem *base, size_t max_offset); int mdss_misr_set(struct mdss_data_type *mdata, struct mdp_misr *req, int mdss_misr_set(struct mdss_data_type *mdata, struct mdp_misr *req, struct mdss_mdp_ctl *ctl); int mdss_misr_get(struct mdss_data_type *mdata, struct mdp_misr *resp, int mdss_misr_get(struct mdss_data_type *mdata, struct mdp_misr *resp, struct mdss_mdp_ctl *ctl, bool is_video_mode); void mdss_misr_disable(struct mdss_data_type *mdata, struct mdp_misr *req, struct mdss_mdp_ctl *ctl); void mdss_misr_crc_collect(struct mdss_data_type *mdata, int block_id); void mdss_misr_crc_collect(struct mdss_data_type *mdata, int block_id, bool is_video_mode); int mdss_create_xlog_debug(struct mdss_debug_data *mdd); void mdss_xlog(const char *name, int line, int flag, ...); Loading Loading @@ -178,10 +185,16 @@ static inline int mdss_misr_set(struct mdss_data_type *mdata, { return 0; } static inline int mdss_misr_get(struct mdss_data_type *mdata, struct mdp_misr *resp, struct mdss_mdp_ctl *ctl) struct mdss_mdp_ctl *ctl, bool is_video_mode) { return 0; } static inline void mdss_misr_disable(struct mdss_data_type *mdata, struct mdp_misr *req, struct mdss_mdp_ctl *ctl) { return; } static inline void mdss_misr_crc_collect(struct mdss_data_type *mdata, int block_id) { } int block_id, bool is_video_mode) { } static inline int create_xlog_debug(struct mdss_data_type *mdata) { return 0; } static inline void mdss_xlog_dump(void) { } Loading @@ -192,6 +205,8 @@ static inline void mdss_xlog_tout_handler_default(bool queue, const char *name, ...) { } #endif int mdss_dump_misr_data(char **buf, u32 size); static inline int mdss_debug_register_io(const char *name, struct dss_io_data *io_data, struct mdss_debug_base **dbg_blk) { Loading drivers/video/msm/mdss/mdss_mdp_overlay.c +103 −1 Original line number Diff line number Diff line Loading @@ -3114,6 +3114,106 @@ static ssize_t mdss_mdp_cmd_autorefresh_store(struct device *dev, } /* Print the last CRC Value read for batch mode */ static ssize_t mdss_mdp_misr_show(struct device *dev, struct device_attribute *attr, char *buf) { ssize_t ret = 0; struct fb_info *fbi = dev_get_drvdata(dev); struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)fbi->par; struct mdss_mdp_ctl *ctl; if (!mfd) { pr_err("Invalid mfd structure\n"); return -EINVAL; } ctl = mfd_to_ctl(mfd); if (!ctl) { pr_err("Invalid ctl structure\n"); return -EINVAL; } ret = mdss_dump_misr_data(&buf, PAGE_SIZE); return ret; } /* * Enable crc batch mode. By enabling this mode through sysfs * driver will keep collecting the misr in ftrace during interrupts, * until disabled. */ static ssize_t mdss_mdp_misr_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t len) { int enable_misr, rc; struct fb_info *fbi = dev_get_drvdata(dev); struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)fbi->par; struct mdss_data_type *mdata = mdss_mdp_get_mdata(); struct mdss_mdp_ctl *ctl; struct mdp_misr req, sreq; if (!mfd) { pr_err("Invalid mfd structure\n"); rc = -EINVAL; return rc; } ctl = mfd_to_ctl(mfd); if (!ctl) { pr_err("Invalid ctl structure\n"); rc = -EINVAL; return rc; } rc = kstrtoint(buf, 10, &enable_misr); if (rc) { pr_err("kstrtoint failed. rc=%d\n", rc); return rc; } pr_debug("intf_type:%d enable:%d\n", ctl->intf_type, enable_misr); if (ctl->intf_type == MDSS_INTF_DSI) { req.block_id = DISPLAY_MISR_DSI0; req.crc_op_mode = MISR_OP_BM; req.frame_count = 1; if (is_panel_split(mfd)) { sreq.block_id = DISPLAY_MISR_DSI1; sreq.crc_op_mode = MISR_OP_BM; sreq.frame_count = 1; } } else if (ctl->intf_type == MDSS_INTF_HDMI) { req.block_id = DISPLAY_MISR_HDMI; req.crc_op_mode = MISR_OP_BM; req.frame_count = 1; } else { pr_err("misr not supported fo this fb:%d\n", mfd->index); } if (enable_misr) { mdss_misr_set(mdata, &req , ctl); if (is_panel_split(mfd)) mdss_misr_set(mdata, &sreq , ctl); } else { mdss_misr_disable(mdata, &req, ctl); if (is_panel_split(mfd)) mdss_misr_disable(mdata, &sreq , ctl); } pr_debug("misr %s\n", enable_misr ? "enabled" : "disabled"); return len; } static DEVICE_ATTR(msm_misr_en, S_IRUGO | S_IWUSR, mdss_mdp_misr_show, mdss_mdp_misr_store); static DEVICE_ATTR(msm_cmd_autorefresh_en, S_IRUGO | S_IWUSR, mdss_mdp_cmd_autorefresh_show, mdss_mdp_cmd_autorefresh_store); static DEVICE_ATTR(vsync_event, S_IRUGO, mdss_mdp_vsync_show_event, NULL); Loading @@ -3130,6 +3230,7 @@ static struct attribute *mdp_overlay_sysfs_attrs[] = { &dev_attr_vsync_event.attr, &dev_attr_ad.attr, &dev_attr_dyn_pu.attr, &dev_attr_msm_misr_en.attr, &dev_attr_msm_cmd_autorefresh_en.attr, &dev_attr_hist_event.attr, &dev_attr_bl_event.attr, Loading Loading @@ -3954,7 +4055,8 @@ static int mdss_fb_get_metadata(struct msm_fb_data_type *mfd, ctl = mfd_to_ctl(mfd); if (!ctl || mdss_fb_is_power_off(mfd)) return -EPERM; ret = mdss_misr_get(mdata, &metadata->data.misr_request, ctl); ret = mdss_misr_get(mdata, &metadata->data.misr_request, ctl, ctl->is_video_mode); break; default: pr_warn("Unsupported request to MDP META IOCTL.\n"); Loading drivers/video/msm/mdss/mdss_mdp_trace.h +18 −1 Original line number Diff line number Diff line /* * Copyright (c) 2014-2015, The Linux Foundation. All rights reserved. * Copyright (c) 2014-2016, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and Loading Loading @@ -295,6 +295,23 @@ TRACE_EVENT(mdp_perf_update_bus, __entry->ib_quota) ); TRACE_EVENT(mdp_misr_crc, TP_PROTO(u32 block_id, u32 vsync_cnt, u32 crc), TP_ARGS(block_id, vsync_cnt, crc), TP_STRUCT__entry( __field(u32, block_id) __field(u32, vsync_cnt) __field(u32, crc) ), TP_fast_assign( __entry->block_id = block_id; __entry->vsync_cnt = vsync_cnt; __entry->crc = crc; ), TP_printk("block_id:%d vsync_cnt:%d crc:0x%08x", __entry->block_id, __entry->vsync_cnt, __entry->crc) ); TRACE_EVENT(mdp_cmd_pingpong_done, TP_PROTO(struct mdss_mdp_ctl *ctl, u32 pp_num, int koff_cnt), TP_ARGS(ctl, pp_num, koff_cnt), Loading drivers/video/msm/mdss/mdss_mdp_util.c +13 −9 Original line number Diff line number Diff line Loading @@ -188,11 +188,15 @@ irqreturn_t mdss_mdp_isr(int irq, void *ptr) if (isr & MDSS_MDP_INTR_INTF_3_UNDERRUN) mdss_mdp_intr_done(MDP_INTR_UNDERRUN_INTF_3); if (isr & MDSS_MDP_INTR_PING_PONG_0_DONE) if (isr & MDSS_MDP_INTR_PING_PONG_0_DONE) { mdss_mdp_intr_done(MDP_INTR_PING_PONG_0); mdss_misr_crc_collect(mdata, DISPLAY_MISR_DSI0, false); } if (isr & MDSS_MDP_INTR_PING_PONG_1_DONE) if (isr & MDSS_MDP_INTR_PING_PONG_1_DONE) { mdss_mdp_intr_done(MDP_INTR_PING_PONG_1); mdss_misr_crc_collect(mdata, DISPLAY_MISR_DSI1, false); } if (isr & MDSS_MDP_INTR_PING_PONG_2_DONE) mdss_mdp_intr_done(MDP_INTR_PING_PONG_2); Loading @@ -214,38 +218,38 @@ irqreturn_t mdss_mdp_isr(int irq, void *ptr) if (isr & MDSS_MDP_INTR_INTF_0_VSYNC) { mdss_mdp_intr_done(MDP_INTR_VSYNC_INTF_0); mdss_misr_crc_collect(mdata, DISPLAY_MISR_EDP); mdss_misr_crc_collect(mdata, DISPLAY_MISR_EDP, true); } if (isr & MDSS_MDP_INTR_INTF_1_VSYNC) { mdss_mdp_intr_done(MDP_INTR_VSYNC_INTF_1); mdss_misr_crc_collect(mdata, DISPLAY_MISR_DSI0); mdss_misr_crc_collect(mdata, DISPLAY_MISR_DSI0, true); } if (isr & MDSS_MDP_INTR_INTF_2_VSYNC) { mdss_mdp_intr_done(MDP_INTR_VSYNC_INTF_2); mdss_misr_crc_collect(mdata, DISPLAY_MISR_DSI1); mdss_misr_crc_collect(mdata, DISPLAY_MISR_DSI1, true); } if (isr & MDSS_MDP_INTR_INTF_3_VSYNC) { mdss_mdp_intr_done(MDP_INTR_VSYNC_INTF_3); mdss_misr_crc_collect(mdata, DISPLAY_MISR_HDMI); mdss_misr_crc_collect(mdata, DISPLAY_MISR_HDMI, true); } if (isr & MDSS_MDP_INTR_WB_0_DONE) { mdss_mdp_intr_done(MDP_INTR_WB_0); mdss_misr_crc_collect(mdata, DISPLAY_MISR_MDP); mdss_misr_crc_collect(mdata, DISPLAY_MISR_MDP, true); } if (isr & MDSS_MDP_INTR_WB_1_DONE) { mdss_mdp_intr_done(MDP_INTR_WB_1); mdss_misr_crc_collect(mdata, DISPLAY_MISR_MDP); mdss_misr_crc_collect(mdata, DISPLAY_MISR_MDP, true); } if (isr & ((mdata->mdp_rev == MDSS_MDP_HW_REV_108) ? MDSS_MDP_INTR_WB_2_DONE >> 2 : MDSS_MDP_INTR_WB_2_DONE)) { mdss_mdp_intr_done(MDP_INTR_WB_2); mdss_misr_crc_collect(mdata, DISPLAY_MISR_MDP); mdss_misr_crc_collect(mdata, DISPLAY_MISR_MDP, true); } if (isr & MDSS_MDP_INTR_PING_PONG_0_AUTOREFRESH_DONE) Loading Loading
drivers/video/msm/mdss/mdss_debug.c +105 −14 Original line number Diff line number Diff line /* Copyright (c) 2009-2015, The Linux Foundation. All rights reserved. /* Copyright (c) 2009-2016, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and Loading Loading @@ -1171,6 +1171,7 @@ static struct mdss_mdp_misr_map { u32 value_reg; u32 crc_op_mode; u32 crc_index; u32 last_misr; bool use_ping; bool is_ping_full; bool is_pong_full; Loading @@ -1183,6 +1184,7 @@ static struct mdss_mdp_misr_map { .value_reg = MDSS_MDP_LP_MISR_SIGN_DSI0, .crc_op_mode = 0, .crc_index = 0, .last_misr = 0, .use_ping = true, .is_ping_full = false, .is_pong_full = false, Loading @@ -1192,6 +1194,7 @@ static struct mdss_mdp_misr_map { .value_reg = MDSS_MDP_LP_MISR_SIGN_DSI1, .crc_op_mode = 0, .crc_index = 0, .last_misr = 0, .use_ping = true, .is_ping_full = false, .is_pong_full = false, Loading @@ -1201,6 +1204,7 @@ static struct mdss_mdp_misr_map { .value_reg = MDSS_MDP_LP_MISR_SIGN_EDP, .crc_op_mode = 0, .crc_index = 0, .last_misr = 0, .use_ping = true, .is_ping_full = false, .is_pong_full = false, Loading @@ -1210,6 +1214,7 @@ static struct mdss_mdp_misr_map { .value_reg = MDSS_MDP_LP_MISR_SIGN_HDMI, .crc_op_mode = 0, .crc_index = 0, .last_misr = 0, .use_ping = true, .is_ping_full = false, .is_pong_full = false, Loading @@ -1219,6 +1224,7 @@ static struct mdss_mdp_misr_map { .value_reg = MDSS_MDP_LP_MISR_SIGN_MDP, .crc_op_mode = 0, .crc_index = 0, .last_misr = 0, .use_ping = true, .is_ping_full = false, .is_pong_full = false, Loading @@ -1226,7 +1232,8 @@ static struct mdss_mdp_misr_map { }; static inline struct mdss_mdp_misr_map *mdss_misr_get_map(u32 block_id, struct mdss_mdp_ctl *ctl, struct mdss_data_type *mdata) struct mdss_mdp_ctl *ctl, struct mdss_data_type *mdata, bool is_video_mode) { struct mdss_mdp_misr_map *map; struct mdss_mdp_mixer *mixer; Loading Loading @@ -1259,11 +1266,23 @@ static inline struct mdss_mdp_misr_map *mdss_misr_get_map(u32 block_id, if ((block_id == DISPLAY_MISR_DSI0 || block_id == DISPLAY_MISR_DSI1) && (ctl && !ctl->is_video_mode)) { !is_video_mode) { ctrl_reg = intf_base + MDSS_MDP_INTF_CMD_MISR_CTRL; value_reg = intf_base + MDSS_MDP_INTF_CMD_MISR_SIGNATURE; /* * extra offset required for * cmd misr in 8996 */ if (IS_MDSS_MAJOR_MINOR_SAME( mdata->mdp_rev, MDSS_MDP_HW_REV_107)) { ctrl_reg += 0x8; value_reg += 0x8; } } else { ctrl_reg = intf_base + MDSS_MDP_INTF_MISR_CTRL; Loading Loading @@ -1325,6 +1344,33 @@ static bool switch_mdp_misr_offset(struct mdss_mdp_misr_map *map, u32 mdp_rev, return use_mdp_up_misr; } void mdss_misr_disable(struct mdss_data_type *mdata, struct mdp_misr *req, struct mdss_mdp_ctl *ctl) { struct mdss_mdp_misr_map *map; map = mdss_misr_get_map(req->block_id, ctl, mdata, ctl->is_video_mode); /* clear the map data */ memset(map->crc_ping, 0, sizeof(map->crc_ping)); memset(map->crc_pong, 0, sizeof(map->crc_pong)); map->crc_index = 0; map->use_ping = true; map->is_ping_full = false; map->is_pong_full = false; map->crc_op_mode = 0; map->last_misr = 0; /* disable MISR and clear the status */ writel_relaxed(MDSS_MDP_MISR_CTRL_STATUS_CLEAR, mdata->mdp_base + map->ctrl_reg); /* make sure status is clear */ wmb(); } int mdss_misr_set(struct mdss_data_type *mdata, struct mdp_misr *req, struct mdss_mdp_ctl *ctl) Loading @@ -1336,7 +1382,11 @@ int mdss_misr_set(struct mdss_data_type *mdata, bool is_valid_wb_mixer = true; bool use_mdp_up_misr = false; map = mdss_misr_get_map(req->block_id, ctl, mdata); pr_debug("req[block:%d frame:%d op_mode:%d]\n", req->block_id, req->frame_count, req->crc_op_mode); map = mdss_misr_get_map(req->block_id, ctl, mdata, ctl->is_video_mode); if (!map) { pr_err("Invalid MISR Block=%d\n", req->block_id); Loading Loading @@ -1409,8 +1459,9 @@ int mdss_misr_set(struct mdss_data_type *mdata, writel_relaxed(config, mdata->mdp_base + map->ctrl_reg); pr_debug("MISR_CTRL = 0x%x", readl_relaxed(mdata->mdp_base + map->ctrl_reg)); pr_debug("MISR_CTRL=0x%x [base:0x%p reg:0x%x config:0x%x]\n", readl_relaxed(mdata->mdp_base + map->ctrl_reg), mdata->mdp_base, map->ctrl_reg, config); } mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF); return 0; Loading @@ -1431,7 +1482,8 @@ char *get_misr_block_name(int misr_block_id) int mdss_misr_get(struct mdss_data_type *mdata, struct mdp_misr *resp, struct mdss_mdp_ctl *ctl) struct mdss_mdp_ctl *ctl, bool is_video_mode) { struct mdss_mdp_misr_map *map; struct mdss_mdp_mixer *mixer; Loading @@ -1439,7 +1491,11 @@ int mdss_misr_get(struct mdss_data_type *mdata, int ret = -1; int i; map = mdss_misr_get_map(resp->block_id, ctl, mdata); pr_debug("req[block:%d frame:%d op_mode:%d]\n", resp->block_id, resp->frame_count, resp->crc_op_mode); map = mdss_misr_get_map(resp->block_id, ctl, mdata, is_video_mode); if (!map) { pr_err("Invalid MISR Block=%d\n", resp->block_id); return -EINVAL; Loading Loading @@ -1515,31 +1571,37 @@ int mdss_misr_get(struct mdss_data_type *mdata, } /* This function is expected to be called from interrupt context */ void mdss_misr_crc_collect(struct mdss_data_type *mdata, int block_id) void mdss_misr_crc_collect(struct mdss_data_type *mdata, int block_id, bool is_video_mode) { struct mdss_mdp_misr_map *map; u32 status = 0; u32 crc = 0x0BAD0BAD; bool crc_stored = false; map = mdss_misr_get_map(block_id, NULL, mdata); map = mdss_misr_get_map(block_id, NULL, mdata, is_video_mode); if (!map || (map->crc_op_mode != MISR_OP_BM)) return; switch_mdp_misr_offset(map, mdata->mdp_rev, block_id); status = readl_relaxed(mdata->mdp_base + map->ctrl_reg); if (MDSS_MDP_MISR_CTRL_STATUS & status) { crc = readl_relaxed(mdata->mdp_base + map->value_reg); map->last_misr = crc; /* cache crc to get it from sysfs */ if (map->use_ping) { if (map->is_ping_full) { pr_err("PING Buffer FULL\n"); pr_err_once("PING Buffer FULL\n"); } else { map->crc_ping[map->crc_index] = crc; crc_stored = true; } } else { if (map->is_pong_full) { pr_err("PONG Buffer FULL\n"); pr_err_once("PONG Buffer FULL\n"); } else { map->crc_pong[map->crc_index] = crc; crc_stored = true; Loading @@ -1565,7 +1627,7 @@ void mdss_misr_crc_collect(struct mdss_data_type *mdata, int block_id) map->is_pong_full ? "FULL" : "EMPTRY"); } } else { pr_err("CRC(%d) Not saved\n", crc); pr_err_once("CRC(%d) Not saved\n", crc); } if (mdata->mdp_rev < MDSS_MDP_HW_REV_105) { Loading @@ -1574,7 +1636,9 @@ void mdss_misr_crc_collect(struct mdss_data_type *mdata, int block_id) writel_relaxed(MISR_CRC_BATCH_CFG, mdata->mdp_base + map->ctrl_reg); } } else if (0 == status) { if (mdata->mdp_rev < MDSS_MDP_HW_REV_105) writel_relaxed(MISR_CRC_BATCH_CFG, mdata->mdp_base + map->ctrl_reg); Loading @@ -1582,15 +1646,42 @@ void mdss_misr_crc_collect(struct mdss_data_type *mdata, int block_id) writel_relaxed(MISR_CRC_BATCH_CFG | MDSS_MDP_LP_MISR_CTRL_FREE_RUN_MASK, mdata->mdp_base + map->ctrl_reg); pr_debug("$$ Batch CRC Start $$\n"); } pr_debug("$$ Vsync Count = %d, CRC=0x%x Indx = %d$$\n", vsync_count, crc, map->crc_index); trace_mdp_misr_crc(block_id, vsync_count, crc); if (MAX_VSYNC_COUNT == vsync_count) { pr_err("RESET vsync_count(%d)\n", vsync_count); pr_debug("RESET vsync_count(%d)\n", vsync_count); vsync_count = 0; } else { vsync_count += 1; } } int mdss_dump_misr_data(char **buf, u32 size) { struct mdss_mdp_misr_map *dsi0_map; struct mdss_mdp_misr_map *dsi1_map; struct mdss_mdp_misr_map *hdmi_map; int ret; dsi0_map = &mdss_mdp_misr_table[DISPLAY_MISR_DSI0]; dsi1_map = &mdss_mdp_misr_table[DISPLAY_MISR_DSI1]; hdmi_map = &mdss_mdp_misr_table[DISPLAY_MISR_HDMI]; ret = scnprintf(*buf, PAGE_SIZE, "\tDSI0 mode:%02d MISR:0x%08x\n" "\tDSI1 mode:%02d MISR:0x%08x\n" "\tHDMI mode:%02d MISR:0x%08x\n", dsi0_map->crc_op_mode, dsi0_map->last_misr, dsi1_map->crc_op_mode, dsi1_map->last_misr, hdmi_map->crc_op_mode, hdmi_map->last_misr ); return ret; }
drivers/video/msm/mdss/mdss_debug.h +21 −6 Original line number Diff line number Diff line /* Copyright (c) 2012-2015, The Linux Foundation. All rights reserved. /* Copyright (c) 2012-2016, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and Loading Loading @@ -146,11 +146,18 @@ void mdss_debug_register_dump_range(struct platform_device *pdev, const char *name_prop); int panel_debug_register_base(const char *name, void __iomem *base, size_t max_offset); int mdss_misr_set(struct mdss_data_type *mdata, struct mdp_misr *req, int mdss_misr_set(struct mdss_data_type *mdata, struct mdp_misr *req, struct mdss_mdp_ctl *ctl); int mdss_misr_get(struct mdss_data_type *mdata, struct mdp_misr *resp, int mdss_misr_get(struct mdss_data_type *mdata, struct mdp_misr *resp, struct mdss_mdp_ctl *ctl, bool is_video_mode); void mdss_misr_disable(struct mdss_data_type *mdata, struct mdp_misr *req, struct mdss_mdp_ctl *ctl); void mdss_misr_crc_collect(struct mdss_data_type *mdata, int block_id); void mdss_misr_crc_collect(struct mdss_data_type *mdata, int block_id, bool is_video_mode); int mdss_create_xlog_debug(struct mdss_debug_data *mdd); void mdss_xlog(const char *name, int line, int flag, ...); Loading Loading @@ -178,10 +185,16 @@ static inline int mdss_misr_set(struct mdss_data_type *mdata, { return 0; } static inline int mdss_misr_get(struct mdss_data_type *mdata, struct mdp_misr *resp, struct mdss_mdp_ctl *ctl) struct mdss_mdp_ctl *ctl, bool is_video_mode) { return 0; } static inline void mdss_misr_disable(struct mdss_data_type *mdata, struct mdp_misr *req, struct mdss_mdp_ctl *ctl) { return; } static inline void mdss_misr_crc_collect(struct mdss_data_type *mdata, int block_id) { } int block_id, bool is_video_mode) { } static inline int create_xlog_debug(struct mdss_data_type *mdata) { return 0; } static inline void mdss_xlog_dump(void) { } Loading @@ -192,6 +205,8 @@ static inline void mdss_xlog_tout_handler_default(bool queue, const char *name, ...) { } #endif int mdss_dump_misr_data(char **buf, u32 size); static inline int mdss_debug_register_io(const char *name, struct dss_io_data *io_data, struct mdss_debug_base **dbg_blk) { Loading
drivers/video/msm/mdss/mdss_mdp_overlay.c +103 −1 Original line number Diff line number Diff line Loading @@ -3114,6 +3114,106 @@ static ssize_t mdss_mdp_cmd_autorefresh_store(struct device *dev, } /* Print the last CRC Value read for batch mode */ static ssize_t mdss_mdp_misr_show(struct device *dev, struct device_attribute *attr, char *buf) { ssize_t ret = 0; struct fb_info *fbi = dev_get_drvdata(dev); struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)fbi->par; struct mdss_mdp_ctl *ctl; if (!mfd) { pr_err("Invalid mfd structure\n"); return -EINVAL; } ctl = mfd_to_ctl(mfd); if (!ctl) { pr_err("Invalid ctl structure\n"); return -EINVAL; } ret = mdss_dump_misr_data(&buf, PAGE_SIZE); return ret; } /* * Enable crc batch mode. By enabling this mode through sysfs * driver will keep collecting the misr in ftrace during interrupts, * until disabled. */ static ssize_t mdss_mdp_misr_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t len) { int enable_misr, rc; struct fb_info *fbi = dev_get_drvdata(dev); struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)fbi->par; struct mdss_data_type *mdata = mdss_mdp_get_mdata(); struct mdss_mdp_ctl *ctl; struct mdp_misr req, sreq; if (!mfd) { pr_err("Invalid mfd structure\n"); rc = -EINVAL; return rc; } ctl = mfd_to_ctl(mfd); if (!ctl) { pr_err("Invalid ctl structure\n"); rc = -EINVAL; return rc; } rc = kstrtoint(buf, 10, &enable_misr); if (rc) { pr_err("kstrtoint failed. rc=%d\n", rc); return rc; } pr_debug("intf_type:%d enable:%d\n", ctl->intf_type, enable_misr); if (ctl->intf_type == MDSS_INTF_DSI) { req.block_id = DISPLAY_MISR_DSI0; req.crc_op_mode = MISR_OP_BM; req.frame_count = 1; if (is_panel_split(mfd)) { sreq.block_id = DISPLAY_MISR_DSI1; sreq.crc_op_mode = MISR_OP_BM; sreq.frame_count = 1; } } else if (ctl->intf_type == MDSS_INTF_HDMI) { req.block_id = DISPLAY_MISR_HDMI; req.crc_op_mode = MISR_OP_BM; req.frame_count = 1; } else { pr_err("misr not supported fo this fb:%d\n", mfd->index); } if (enable_misr) { mdss_misr_set(mdata, &req , ctl); if (is_panel_split(mfd)) mdss_misr_set(mdata, &sreq , ctl); } else { mdss_misr_disable(mdata, &req, ctl); if (is_panel_split(mfd)) mdss_misr_disable(mdata, &sreq , ctl); } pr_debug("misr %s\n", enable_misr ? "enabled" : "disabled"); return len; } static DEVICE_ATTR(msm_misr_en, S_IRUGO | S_IWUSR, mdss_mdp_misr_show, mdss_mdp_misr_store); static DEVICE_ATTR(msm_cmd_autorefresh_en, S_IRUGO | S_IWUSR, mdss_mdp_cmd_autorefresh_show, mdss_mdp_cmd_autorefresh_store); static DEVICE_ATTR(vsync_event, S_IRUGO, mdss_mdp_vsync_show_event, NULL); Loading @@ -3130,6 +3230,7 @@ static struct attribute *mdp_overlay_sysfs_attrs[] = { &dev_attr_vsync_event.attr, &dev_attr_ad.attr, &dev_attr_dyn_pu.attr, &dev_attr_msm_misr_en.attr, &dev_attr_msm_cmd_autorefresh_en.attr, &dev_attr_hist_event.attr, &dev_attr_bl_event.attr, Loading Loading @@ -3954,7 +4055,8 @@ static int mdss_fb_get_metadata(struct msm_fb_data_type *mfd, ctl = mfd_to_ctl(mfd); if (!ctl || mdss_fb_is_power_off(mfd)) return -EPERM; ret = mdss_misr_get(mdata, &metadata->data.misr_request, ctl); ret = mdss_misr_get(mdata, &metadata->data.misr_request, ctl, ctl->is_video_mode); break; default: pr_warn("Unsupported request to MDP META IOCTL.\n"); Loading
drivers/video/msm/mdss/mdss_mdp_trace.h +18 −1 Original line number Diff line number Diff line /* * Copyright (c) 2014-2015, The Linux Foundation. All rights reserved. * Copyright (c) 2014-2016, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and Loading Loading @@ -295,6 +295,23 @@ TRACE_EVENT(mdp_perf_update_bus, __entry->ib_quota) ); TRACE_EVENT(mdp_misr_crc, TP_PROTO(u32 block_id, u32 vsync_cnt, u32 crc), TP_ARGS(block_id, vsync_cnt, crc), TP_STRUCT__entry( __field(u32, block_id) __field(u32, vsync_cnt) __field(u32, crc) ), TP_fast_assign( __entry->block_id = block_id; __entry->vsync_cnt = vsync_cnt; __entry->crc = crc; ), TP_printk("block_id:%d vsync_cnt:%d crc:0x%08x", __entry->block_id, __entry->vsync_cnt, __entry->crc) ); TRACE_EVENT(mdp_cmd_pingpong_done, TP_PROTO(struct mdss_mdp_ctl *ctl, u32 pp_num, int koff_cnt), TP_ARGS(ctl, pp_num, koff_cnt), Loading
drivers/video/msm/mdss/mdss_mdp_util.c +13 −9 Original line number Diff line number Diff line Loading @@ -188,11 +188,15 @@ irqreturn_t mdss_mdp_isr(int irq, void *ptr) if (isr & MDSS_MDP_INTR_INTF_3_UNDERRUN) mdss_mdp_intr_done(MDP_INTR_UNDERRUN_INTF_3); if (isr & MDSS_MDP_INTR_PING_PONG_0_DONE) if (isr & MDSS_MDP_INTR_PING_PONG_0_DONE) { mdss_mdp_intr_done(MDP_INTR_PING_PONG_0); mdss_misr_crc_collect(mdata, DISPLAY_MISR_DSI0, false); } if (isr & MDSS_MDP_INTR_PING_PONG_1_DONE) if (isr & MDSS_MDP_INTR_PING_PONG_1_DONE) { mdss_mdp_intr_done(MDP_INTR_PING_PONG_1); mdss_misr_crc_collect(mdata, DISPLAY_MISR_DSI1, false); } if (isr & MDSS_MDP_INTR_PING_PONG_2_DONE) mdss_mdp_intr_done(MDP_INTR_PING_PONG_2); Loading @@ -214,38 +218,38 @@ irqreturn_t mdss_mdp_isr(int irq, void *ptr) if (isr & MDSS_MDP_INTR_INTF_0_VSYNC) { mdss_mdp_intr_done(MDP_INTR_VSYNC_INTF_0); mdss_misr_crc_collect(mdata, DISPLAY_MISR_EDP); mdss_misr_crc_collect(mdata, DISPLAY_MISR_EDP, true); } if (isr & MDSS_MDP_INTR_INTF_1_VSYNC) { mdss_mdp_intr_done(MDP_INTR_VSYNC_INTF_1); mdss_misr_crc_collect(mdata, DISPLAY_MISR_DSI0); mdss_misr_crc_collect(mdata, DISPLAY_MISR_DSI0, true); } if (isr & MDSS_MDP_INTR_INTF_2_VSYNC) { mdss_mdp_intr_done(MDP_INTR_VSYNC_INTF_2); mdss_misr_crc_collect(mdata, DISPLAY_MISR_DSI1); mdss_misr_crc_collect(mdata, DISPLAY_MISR_DSI1, true); } if (isr & MDSS_MDP_INTR_INTF_3_VSYNC) { mdss_mdp_intr_done(MDP_INTR_VSYNC_INTF_3); mdss_misr_crc_collect(mdata, DISPLAY_MISR_HDMI); mdss_misr_crc_collect(mdata, DISPLAY_MISR_HDMI, true); } if (isr & MDSS_MDP_INTR_WB_0_DONE) { mdss_mdp_intr_done(MDP_INTR_WB_0); mdss_misr_crc_collect(mdata, DISPLAY_MISR_MDP); mdss_misr_crc_collect(mdata, DISPLAY_MISR_MDP, true); } if (isr & MDSS_MDP_INTR_WB_1_DONE) { mdss_mdp_intr_done(MDP_INTR_WB_1); mdss_misr_crc_collect(mdata, DISPLAY_MISR_MDP); mdss_misr_crc_collect(mdata, DISPLAY_MISR_MDP, true); } if (isr & ((mdata->mdp_rev == MDSS_MDP_HW_REV_108) ? MDSS_MDP_INTR_WB_2_DONE >> 2 : MDSS_MDP_INTR_WB_2_DONE)) { mdss_mdp_intr_done(MDP_INTR_WB_2); mdss_misr_crc_collect(mdata, DISPLAY_MISR_MDP); mdss_misr_crc_collect(mdata, DISPLAY_MISR_MDP, true); } if (isr & MDSS_MDP_INTR_PING_PONG_0_AUTOREFRESH_DONE) Loading