/* logging a event related with VPP */ static inline void disp_ss_event_log_vpp (disp_ss_event_t type, struct v4l2_subdev *sd, ktime_t time) { struct decon_device *decon = get_decon_drvdata(__get_decon_id_for_vpp(sd)); int idx = atomic_inc_return(&decon->disp_ss_log_idx) % DISP_EVENT_LOG_MAX; struct disp_ss_log *log = &decon->disp_ss_log[idx]; struct vpp_dev *vpp = v4l2_get_subdevdata(sd); if (time.tv64) log->time = time; else log->time = ktime_get(); log->type = type; switch (type) { case DISP_EVT_VPP_SUSPEND: case DISP_EVT_VPP_RESUME: log->data.pm.pm_status = pm_runtime_active(&vpp->pdev->dev); log->data.pm.elapsed = ktime_sub(ktime_get(), log->time); break; case DISP_EVT_VPP_FRAMEDONE: case DISP_EVT_VPP_STOP: case DISP_EVT_VPP_WINCON: log->data.vpp.id = vpp->id; log->data.vpp.start_cnt = vpp->start_count; log->data.vpp.done_cnt = vpp->done_count; break; default: log->data.vpp.id = vpp->id; break; } return; }
/* get decon's id used by vpp */ static int __get_decon_id_for_vpp(struct v4l2_subdev *sd) { struct decon_device *decon = get_decon_drvdata(0); struct vpp_dev *vpp = v4l2_get_subdevdata(sd); return decon->vpp_used[vpp->id]? 0 : 1; }
/* logging a event related with DSIM */ static inline void disp_ss_event_log_dsim (disp_ss_event_t type, struct v4l2_subdev *sd, ktime_t time) { struct dsim_device *dsim = container_of(sd, struct dsim_device, sd); struct decon_device *decon = get_decon_drvdata(dsim->id); int idx = atomic_inc_return(&decon->disp_ss_log_idx) % DISP_EVENT_LOG_MAX; struct disp_ss_log *log = &decon->disp_ss_log[idx]; if (time.tv64) log->time = time; else log->time = ktime_get(); log->type = type; switch (type) { case DISP_EVT_DSIM_SUSPEND: case DISP_EVT_DSIM_RESUME: case DISP_EVT_ENTER_ULPS: case DISP_EVT_EXIT_ULPS: case DISP_EVT_FRAMEDONE: log->data.pm.pm_status = pm_runtime_active(dsim->dev); log->data.pm.elapsed = ktime_sub(ktime_get(), log->time); break; default: /* Any remaining types will be log just time and type */ break; } }
dma_addr_t decon_map_sec_dma_buf(struct dma_buf *dbuf, int plane) { struct decon_device *decon = get_decon_drvdata(0); /* 0: decon Int ID */ if (!dbuf || (plane >= MAX_BUF_PLANE_CNT) || (plane < 0)) return -EINVAL; dma.ion_handle = NULL; dma.fence = NULL; dma.dma_buf = dbuf; dma.attachment = dma_buf_attach(dbuf, decon->dev); if (IS_ERR(dma.attachment)) { decon_err("dma_buf_attach() failed: %ld\n", PTR_ERR(dma.attachment)); goto err_buf_map_attach; } dma.sg_table = dma_buf_map_attachment(dma.attachment, DMA_TO_DEVICE); if (IS_ERR(dma.sg_table)) { decon_err("dma_buf_map_attachment() failed: %ld\n", PTR_ERR(dma.sg_table)); goto err_buf_map_attachment; } dma.dma_addr = ion_iovmm_map(dma.attachment, 0, dma.dma_buf->size, DMA_TO_DEVICE, plane); if (IS_ERR_VALUE(dma.dma_addr)) { decon_err("iovmm_map() failed: %pa\n", &dma.dma_addr); goto err_iovmm_map; } exynos_ion_sync_dmabuf_for_device(decon->dev, dma.dma_buf, dma.dma_buf->size, DMA_TO_DEVICE); return dma.dma_addr; err_iovmm_map: dma_buf_unmap_attachment(dma.attachment, dma.sg_table, DMA_TO_DEVICE); err_buf_map_attachment: dma_buf_detach(dma.dma_buf, dma.attachment); err_buf_map_attach: return 0; }
void decon_free_sec_dma_buf(int plane) { struct decon_device *decon = get_decon_drvdata(0); /* 0: decon Int ID */ if (IS_ERR_VALUE(dma.dma_addr) || !dma.dma_buf) return; ion_iovmm_unmap(dma.attachment, dma.dma_addr); dma_buf_unmap_attachment(dma.attachment, dma.sg_table, DMA_TO_DEVICE); exynos_ion_sync_dmabuf_for_cpu(decon->dev, dma.dma_buf, dma.dma_buf->size, DMA_FROM_DEVICE); dma_buf_detach(dma.dma_buf, dma.attachment); memset(&dma, 0, sizeof(dma)); }
void DISP_SS_EVENT_LOG_DSIM_FRAMEDONE(struct v4l2_subdev *sd, struct disp_log_decon_frm_done* decon_sfr) { struct dsim_device *dsim = container_of(sd, struct dsim_device, sd); struct decon_device *decon = get_decon_drvdata(dsim->id); int idx; struct disp_ss_log *log; if (!decon || IS_ERR_OR_NULL(decon->debug_event)) return; idx = atomic_inc_return(&decon->disp_ss_log_idx) % DISP_EVENT_LOG_MAX; log = &decon->disp_ss_log[idx]; log->time = ktime_get(); log->type = DISP_EVT_DSIM_FRAMEDONE; memcpy(&log->data.decon_sfr, decon_sfr, sizeof(struct disp_log_decon_frm_done)); }
/* Common API to log a event related with DSIM COMMAND */ void DISP_SS_EVENT_LOG_CMD(struct v4l2_subdev *sd, u32 cmd_id, unsigned long data) { struct dsim_device *dsim = container_of(sd, struct dsim_device, sd); struct decon_device *decon = get_decon_drvdata(dsim->id); int idx; struct disp_ss_log *log; if (!decon || IS_ERR_OR_NULL(decon->debug_event)) return; idx = atomic_inc_return(&decon->disp_ss_log_idx) % DISP_EVENT_LOG_MAX; log = &decon->disp_ss_log[idx]; log->time = ktime_get(); log->type = DISP_EVT_DSIM_COMMAND; log->data.cmd_buf.id = cmd_id; if (cmd_id == MIPI_DSI_DCS_LONG_WRITE) log->data.cmd_buf.buf = *(u8 *)(data); else log->data.cmd_buf.buf = (u8)data; }
/* Common API to log a event related with DECON/DSIM/VPP */ void DISP_SS_EVENT_LOG(disp_ss_event_t type, struct v4l2_subdev *sd, ktime_t time) { struct decon_device *decon = get_decon_drvdata(0); if (!decon || IS_ERR_OR_NULL(decon->debug_event)) return; /* log a eventy softly */ switch (type) { case DISP_EVT_TE_INTERRUPT: case DISP_EVT_UNDERRUN: /* If occurs continuously, skipped. It is a burden */ if (disp_ss_event_ignore(type, decon)) break; case DISP_EVT_BLANK: case DISP_EVT_UNBLANK: case DISP_EVT_ENTER_LPD: case DISP_EVT_EXIT_LPD: case DISP_EVT_DECON_SUSPEND: case DISP_EVT_DECON_RESUME: case DISP_EVT_LINECNT_ZERO: case DISP_EVT_TRIG_MASK: case DISP_EVT_DECON_FRAMEDONE_WAIT: case DISP_EVT_WB_SET_BUFFER: case DISP_EVT_WB_SW_TRIGGER: case DISP_EVT_WB_TIMELINE_INC: case DISP_EVT_WB_FRAME_DONE: case DISP_EVT_TRIG_UNMASK: case DISP_EVT_TE_WAIT_DONE: case DISP_EVT_DECON_UPDATE_WAIT_DONE: case DISP_EVT_GIC_TE_ENABLE: case DISP_EVT_GIC_TE_DISABLE: case DISP_EVT_DECON_FRAMEDONE: disp_ss_event_log_decon(type, sd, time); break; case DISP_EVT_ENTER_ULPS: case DISP_EVT_EXIT_ULPS: case DISP_EVT_DSIM_FRAMEDONE: case DISP_EVT_FRAMEDONE: disp_ss_event_log_dsim(type, sd, time); break; case DISP_EVT_VPP_FRAMEDONE: case DISP_EVT_VPP_STOP: case DISP_EVT_VPP_WINCON: case DISP_EVT_VPP_UPDATE_DONE: case DISP_EVT_VPP_SHADOW_UPDATE: disp_ss_event_log_vpp(type, sd, time); break; default: break; } if (decon->disp_ss_log_level == DISP_EVENT_LEVEL_LOW) return; /* additionally logging hardly */ switch (type) { case DISP_EVT_ACT_VSYNC: case DISP_EVT_DEACT_VSYNC: case DISP_EVT_WIN_CONFIG: disp_ss_event_log_decon(type, sd, time); break; case DISP_EVT_DSIM_SUSPEND: case DISP_EVT_DSIM_RESUME: disp_ss_event_log_dsim(type, sd, time); break; case DISP_EVT_VPP_SUSPEND: case DISP_EVT_VPP_RESUME: disp_ss_event_log_vpp(type, sd, time); default: break; } }