From b0c8c241c0667e9f66a8d98dcd064e8f0ccd1b39 Mon Sep 17 00:00:00 2001 From: ChiHun Won Date: Wed, 4 Jul 2018 14:41:15 +0900 Subject: [PATCH] fbdev: dpu20: parse DPU count and HW limitation Change-Id: Ibbddefc595cf19142a3c2cdfcba508e1af2bd86c Signed-off-by: ChiHun Won --- drivers/video/fbdev/exynos/dpu20/bts.c | 16 ++- drivers/video/fbdev/exynos/dpu20/cursor.c | 9 +- drivers/video/fbdev/exynos/dpu20/decon.h | 7 + drivers/video/fbdev/exynos/dpu20/decon_core.c | 50 ++++--- drivers/video/fbdev/exynos/dpu20/dpp.h | 54 +++++++- drivers/video/fbdev/exynos/dpu20/dpp_drv.c | 127 +++++++++++++++++- drivers/video/fbdev/exynos/dpu20/dsim.h | 1 + drivers/video/fbdev/exynos/dpu20/dsim_drv.c | 6 +- drivers/video/fbdev/exynos/dpu20/event_log.c | 9 +- drivers/video/fbdev/exynos/dpu20/fence.c | 4 +- drivers/video/fbdev/exynos/dpu20/helper.c | 17 ++- drivers/video/fbdev/exynos/dpu20/win_update.c | 10 +- 12 files changed, 260 insertions(+), 50 deletions(-) diff --git a/drivers/video/fbdev/exynos/dpu20/bts.c b/drivers/video/fbdev/exynos/dpu20/bts.c index 7c2be5f0d5b6..178c2d48edc1 100644 --- a/drivers/video/fbdev/exynos/dpu20/bts.c +++ b/drivers/video/fbdev/exynos/dpu20/bts.c @@ -57,7 +57,7 @@ static void dpu_bts_sum_all_decon_bw(struct decon_device *decon, u32 ch_bw[]) { int i, j; - if (decon->id < 0 || decon->id >= MAX_DECON_CNT) { + if (decon->id < 0 || decon->id >= decon->dt.decon_cnt) { decon_warn("[%s] undefined decon id(%d)!\n", __func__, decon->id); return; } @@ -65,7 +65,7 @@ static void dpu_bts_sum_all_decon_bw(struct decon_device *decon, u32 ch_bw[]) for (i = 0; i < BTS_DPU_MAX; ++i) decon->bts.ch_bw[decon->id][i] = ch_bw[i]; - for (i = 0; i < MAX_DECON_CNT; ++i) { + for (i = 0; i < decon->dt.decon_cnt; ++i) { if (decon->id == i) continue; @@ -121,7 +121,7 @@ static void dpu_bts_find_max_disp_freq(struct decon_device *decon, DPU_DEBUG_BTS("\tDECON%d : resol clock = %d Khz\n", decon->id, decon->bts.resol_clk); - for (i = 0; i < MAX_DECON_WIN; ++i) { + for (i = 0; i < decon->dt.max_win; ++i) { idx = config[i].idma_type; if ((config[i].state != DECON_WIN_STATE_BUFFER) && (config[i].state != DECON_WIN_STATE_COLOR)) @@ -145,11 +145,17 @@ static void dpu_bts_share_bw_info(int id) { int i, j; struct decon_device *decon[3]; + int decon_cnt; + + decon_cnt = get_decon_drvdata(0)->dt.decon_cnt; for (i = 0; i < MAX_DECON_CNT; i++) + decon[i] = NULL; + + for (i = 0; i < decon_cnt; i++) decon[i] = get_decon_drvdata(i); - for (i = 0; i < MAX_DECON_CNT; ++i) { + for (i = 0; i < decon_cnt; ++i) { if (id == i || decon[i] == NULL) continue; @@ -172,7 +178,7 @@ void dpu_bts_calc_bw(struct decon_device *decon, struct decon_reg_data *regs) DPU_DEBUG_BTS("%s + : DECON%d\n", __func__, decon->id); memset(&bts_info, 0, sizeof(struct bts_decon_info)); - for (i = 0; i < MAX_DECON_WIN; ++i) { + for (i = 0; i < decon->dt.max_win; ++i) { if (config[i].state == DECON_WIN_STATE_BUFFER) { idx = config[i].idma_type; bts_info.dpp[idx].used = true; diff --git a/drivers/video/fbdev/exynos/dpu20/cursor.c b/drivers/video/fbdev/exynos/dpu20/cursor.c index b940b5b2dfe6..913c85cc0571 100644 --- a/drivers/video/fbdev/exynos/dpu20/cursor.c +++ b/drivers/video/fbdev/exynos/dpu20/cursor.c @@ -88,6 +88,8 @@ void dpu_cursor_win_update_config(struct decon_device *decon, struct decon_reg_data *regs) { struct decon_frame src, dst; + struct v4l2_subdev *sd; + struct dpp_restriction res; unsigned short cur = regs->cursor_win; if (!decon->cursor.enabled) @@ -109,6 +111,9 @@ void dpu_cursor_win_update_config(struct decon_device *decon, return; } + sd = decon->dpp_sd[0]; + v4l2_subdev_call(sd, core, ioctl, DPP_GET_RESTRICTION, &res); + memcpy(&src, ®s->dpp_config[cur].src, sizeof(struct decon_frame)); memcpy(&dst, ®s->dpp_config[cur].dst, sizeof(struct decon_frame)); @@ -120,8 +125,8 @@ void dpu_cursor_win_update_config(struct decon_device *decon, if ((dst.y + dst.h) > decon->lcd_info->yres) dst.h = dst.h - ((dst.y + dst.h) - decon->lcd_info->yres); - if (dst.w > SRC_WIDTH_MAX || dst.w < SRC_WIDTH_MIN || - dst.h > SRC_HEIGHT_MAX || dst.h < SRC_HEIGHT_MIN) { + if (dst.w > res.src_f_w.max || dst.w < res.src_f_w.min || + dst.h > res.src_f_h.max || dst.h < res.src_f_h.min) { decon_info("not supported cursor: [%d] [%d %d] ", cur, decon->lcd_info->xres, decon->lcd_info->yres); diff --git a/drivers/video/fbdev/exynos/dpu20/decon.h b/drivers/video/fbdev/exynos/dpu20/decon.h index 0dcb7f74ca8a..3b200079cfbf 100644 --- a/drivers/video/fbdev/exynos/dpu20/decon.h +++ b/drivers/video/fbdev/exynos/dpu20/decon.h @@ -57,6 +57,8 @@ #define SUCCESS_EXYNOS_SMC 0 +#define MAX_DECON_CNT 3 + #if defined(CONFIG_SUPPORT_LEGACY_ION) extern struct ion_device *ion_exynos; #endif @@ -691,6 +693,10 @@ struct decon_dt_info { int dft_win; int dft_idma; const char *pd_name; + int dpp_cnt; + int dsim_cnt; + int decon_cnt; + int chip_ver; }; struct decon_win { @@ -872,6 +878,7 @@ struct decon_device { struct v4l2_subdev *out_sd[MAX_DSIM_CNT]; struct v4l2_subdev *dsim_sd[MAX_DSIM_CNT]; + /* TODO: MAX_DPP_SUBDEV wil be changed to MAX_DPP_CNT */ struct v4l2_subdev *dpp_sd[MAX_DPP_SUBDEV]; struct v4l2_subdev *displayport_sd; struct v4l2_device v4l2_dev; diff --git a/drivers/video/fbdev/exynos/dpu20/decon_core.c b/drivers/video/fbdev/exynos/dpu20/decon_core.c index 6d4d31e247d7..1984ab51af86 100644 --- a/drivers/video/fbdev/exynos/dpu20/decon_core.c +++ b/drivers/video/fbdev/exynos/dpu20/decon_core.c @@ -109,7 +109,7 @@ static void decon_dump_using_dpp(struct decon_device *decon) { int i; - for (i = 0; i < MAX_DPP_SUBDEV; i++) { + for (i = 0; i < decon->dt.dpp_cnt; i++) { if (test_bit(i, &decon->prev_used_dpp)) { struct v4l2_subdev *sd = NULL; sd = decon->dpp_sd[i]; @@ -123,8 +123,11 @@ static void decon_up_list_saved(void) { int i; struct decon_device *decon; + int decon_cnt; - for (i = 0; i < MAX_DECON_CNT; i++) { + decon_cnt = get_decon_drvdata(0)->dt.decon_cnt; + + for (i = 0; i < decon_cnt; i++) { decon = get_decon_drvdata(i); if (decon) { if (!list_empty(&decon->up.list) || !list_empty(&decon->up.saved_list)) { @@ -233,7 +236,7 @@ void decon_dpp_stop(struct decon_device *decon, bool do_reset) bool rst = false; struct v4l2_subdev *sd; - for (i = 0; i < MAX_DPP_SUBDEV; i++) { + for (i = 0; i < decon->dt.dpp_cnt; i++) { if (test_bit(i, &decon->prev_used_dpp) && !test_bit(i, &decon->cur_using_dpp)) { sd = decon->dpp_sd[i]; @@ -1053,7 +1056,7 @@ static int decon_find_biggest_block_rect(struct decon_device *decon, r1.bottom = r1.top + config->dst.h - 1; /* Find the biggest block region from overlays by the top windows */ - for (j = win_no + 1; j < MAX_DECON_WIN; j++) { + for (j = win_no + 1; j < decon->dt.max_win; j++) { config = &win_config[j]; if (config->state != DECON_WIN_STATE_BUFFER) continue; @@ -1557,7 +1560,7 @@ static int decon_set_dpp_config(struct decon_device *decon, if (decon->dt.out_type == DECON_OUT_WB) { sd = decon->dpp_sd[ODMA_WB]; - memcpy(&dpp_config.config, ®s->dpp_config[MAX_DECON_WIN], + memcpy(&dpp_config.config, ®s->dpp_config[decon->dt.max_win], sizeof(struct decon_win_config)); dpp_config.rcv_num = aclk_khz; ret = v4l2_subdev_call(sd, core, ioctl, DPP_WIN_CONFIG, @@ -1841,7 +1844,7 @@ static void decon_release_old_bufs(struct decon_device *decon, if (decon->dt.out_type == DECON_OUT_WB) { for (j = 0; j < plane_cnt[0]; ++j) decon_free_dma_buf(decon, - ®s->dma_buf_data[MAX_DECON_WIN][j]); + ®s->dma_buf_data[decon->dt.max_win][j]); } } @@ -2301,12 +2304,12 @@ static int decon_prepare_win_config(struct decon_device *decon, } if (decon->dt.out_type == DECON_OUT_WB) { - regs->protection[MAX_DECON_WIN] = win_config[MAX_DECON_WIN].protection; - ret = decon_import_buffer(decon, MAX_DECON_WIN, - &win_config[MAX_DECON_WIN], regs); + regs->protection[decon->dt.max_win] = win_config[decon->dt.max_win].protection; + ret = decon_import_buffer(decon, decon->dt.max_win, + &win_config[decon->dt.max_win], regs); } - for (i = 0; i < MAX_DPP_SUBDEV; i++) { + for (i = 0; i < decon->dt.dpp_cnt; i++) { memcpy(®s->dpp_config[i], &win_config[i], sizeof(struct decon_win_config)); regs->dpp_config[i].format = @@ -2586,7 +2589,7 @@ static int decon_ioctl(struct fb_info *info, unsigned int cmd, decon_info("HWC version %d.0 is operating\n", disp_info.ver); disp_info.psr_mode = decon->dt.psr_mode; - disp_info.chip_ver = CHIP_VER; + disp_info.chip_ver = decon->dt.chip_ver; disp_info.mres_info = *mres_info; if (copy_to_user(argp_info, @@ -2886,7 +2889,7 @@ static int decon_register_subdevs(struct decon_device *decon) return ret; } - for (i = 0; i < MAX_DPP_SUBDEV; ++i) + for (i = 0; i < MAX_DPP_CNT; ++i) decon->dpp_sd[i] = NULL; ret = dpu_get_sd_by_drvname(decon, DPP_MODULE_NAME); if (ret) @@ -2904,7 +2907,7 @@ static int decon_register_subdevs(struct decon_device *decon) #endif if (!decon->id) { - for (i = 0; i < MAX_DPP_SUBDEV; i++) { + for (i = 0; i < decon->dt.dpp_cnt; i++) { if (IS_ERR_OR_NULL(decon->dpp_sd[i])) continue; ret = v4l2_device_register_subdev(v4l2_dev, @@ -2915,7 +2918,7 @@ static int decon_register_subdevs(struct decon_device *decon) } } - for (i = 0; i < MAX_DSIM_CNT; i++) { + for (i = 0; i < decon->dt.dsim_cnt; i++) { if (decon->dsim_sd[i] == NULL || i == 1) continue; @@ -2960,13 +2963,13 @@ static void decon_unregister_subdevs(struct decon_device *decon) int i; if (!decon->id) { - for (i = 0; i < MAX_DPP_SUBDEV; i++) { + for (i = 0; i < decon->dt.dpp_cnt; i++) { if (decon->dpp_sd[i] == NULL) continue; v4l2_device_unregister_subdev(decon->dpp_sd[i]); } - for (i = 0; i < MAX_DSIM_CNT; i++) { + for (i = 0; i < decon->dt.dsim_cnt; i++) { if (decon->dsim_sd[i] == NULL || i == 1) continue; v4l2_device_unregister_subdev(decon->dsim_sd[i]); @@ -3299,11 +3302,9 @@ static void decon_parse_dt(struct decon_device *decon) of_property_read_u32(dev->of_node, "psr_mode", &decon->dt.psr_mode); /* H/W trigger: 0, S/W trigger: 1 */ - of_property_read_u32(dev->of_node, "trig_mode", - &decon->dt.trig_mode); - decon_info("decon-%s: max win%d, %s mode, %s trigger\n", - (decon->id == 0) ? "f" : ((decon->id == 1) ? "s" : "t"), - decon->dt.max_win, + of_property_read_u32(dev->of_node, "trig_mode", &decon->dt.trig_mode); + decon_info("decon%d: max win%d, %s mode, %s trigger\n", + decon->id, decon->dt.max_win, decon->dt.psr_mode ? "command" : "video", decon->dt.trig_mode ? "sw" : "hw"); @@ -3322,6 +3323,13 @@ static void decon_parse_dt(struct decon_device *decon) decon_info("PPC(%llu)\n", decon->bts.ppc); + of_property_read_u32(dev->of_node, "chip_ver", &decon->dt.chip_ver); + of_property_read_u32(dev->of_node, "dpp_cnt", &decon->dt.dpp_cnt); + of_property_read_u32(dev->of_node, "dsim_cnt", &decon->dt.dsim_cnt); + of_property_read_u32(dev->of_node, "decon_cnt", &decon->dt.decon_cnt); + decon_info("chip_ver %d, dpp cnt %d, dsim cnt %d\n", decon->dt.chip_ver, + decon->dt.dpp_cnt, decon->dt.dsim_cnt); + if (decon->dt.out_type == DECON_OUT_DSI) { ret = of_property_read_u32_index(dev->of_node, "out_idx", 0, &decon->dt.out_idx[0]); diff --git a/drivers/video/fbdev/exynos/dpu20/dpp.h b/drivers/video/fbdev/exynos/dpu20/dpp.h index b30378514860..266d6c81e1eb 100644 --- a/drivers/video/fbdev/exynos/dpu20/dpp.h +++ b/drivers/video/fbdev/exynos/dpu20/dpp.h @@ -41,6 +41,7 @@ extern int dpp_log_level; #define DPP_MODULE_NAME "exynos-dpp" +#define MAX_DPP_CNT 7 /* + ODMA case */ /* about 1msec @ ACLK=630MHz */ #define INIT_RCV_NUM 630000 @@ -146,6 +147,52 @@ struct dpp_config { unsigned long rcv_num; }; +struct dpp_size_range { + u32 min; + u32 max; + u32 align; +}; + +struct dpp_restriction { + struct dpp_size_range src_f_w; + struct dpp_size_range src_f_h; + struct dpp_size_range src_w; + struct dpp_size_range src_h; + u32 src_x_align; + u32 src_y_align; + + struct dpp_size_range dst_f_w; + struct dpp_size_range dst_f_h; + struct dpp_size_range dst_w; + struct dpp_size_range dst_h; + u32 dst_x_align; + u32 dst_y_align; + + struct dpp_size_range blk_w; + struct dpp_size_range blk_h; + u32 blk_x_align; + u32 blk_y_align; + + u32 src_h_rot_max; /* limit of source img height in case of rotation */ + + u32 *format; /* supported format list for each DPP channel */ + u32 reserved[8]; +}; + +struct dpp_ch_restriction { + int id; + unsigned long attr; + + struct dpp_restriction restriction; + u32 reserved[4]; +}; + +struct dpp_restrictions_info { + u32 ver; /* version of dpp_restrictions_info structure */ + struct dpp_ch_restriction dpp_ch[MAX_DPP_CNT]; + u32 reserved[4]; +}; + struct dpp_device { int id; int port; @@ -160,16 +207,14 @@ struct dpp_device { spinlock_t slock; spinlock_t dma_slock; struct mutex lock; + struct dpp_restriction restriction; }; extern struct dpp_device *dpp_drvdata[MAX_DPP_CNT]; static inline struct dpp_device *get_dpp_drvdata(u32 id) { - if (id >= MAX_DPP_CNT) - return NULL; - else - return dpp_drvdata[id]; + return dpp_drvdata[id]; } static inline u32 dpp_read(u32 id, u32 reg_id) @@ -284,5 +329,6 @@ void dpp_dump(struct dpp_device *dpp); #define DPP_WAIT_IDLE _IOR('P', 4, unsigned long) #define DPP_SET_RECOVERY_NUM _IOR('P', 5, unsigned long) #define DPP_GET_PORT_NUM _IOR('P', 7, unsigned long) +#define DPP_GET_RESTRICTION _IOR('P', 8, unsigned long) #endif /* __SAMSUNG_DPP_H__ */ diff --git a/drivers/video/fbdev/exynos/dpu20/dpp_drv.c b/drivers/video/fbdev/exynos/dpu20/dpp_drv.c index e9631456f794..3400c34c6147 100644 --- a/drivers/video/fbdev/exynos/dpu20/dpp_drv.c +++ b/drivers/video/fbdev/exynos/dpu20/dpp_drv.c @@ -79,6 +79,7 @@ static void dpp_get_params(struct dpp_device *dpp, struct dpp_params_info *p) { u64 src_w, src_h, dst_w, dst_h; struct decon_win_config *config = &dpp->dpp_config->config; + struct dpp_restriction *res = &dpp->restriction; p->rcv_num = dpp->dpp_config->rcv_num; memcpy(&p->src, &config->src, sizeof(struct decon_frame)); @@ -145,7 +146,7 @@ static void dpp_get_params(struct dpp_device *dpp, struct dpp_params_info *p) if ((config->dpp_parm.rot != DPP_ROT_NORMAL) || (p->is_scale) || (p->format >= DECON_PIXEL_FORMAT_NV16) || - (p->block.w < BLK_WIDTH_MIN) || (p->block.h < BLK_HEIGHT_MIN)) + (p->block.w < res->blk_w.min) || (p->block.h < res->blk_h.min)) p->is_block = false; else p->is_block = true; @@ -158,7 +159,7 @@ static int dpp_check_size(struct dpp_device *dpp, struct dpp_img_format *vi) struct decon_frame *dst = &config->dst; struct dpp_size_constraints vc; - dpp_constraints_params(&vc, vi); + dpp_constraints_params(&vc, vi, &dpp->restriction); if ((!check_align(src->x, src->y, vc.src_mul_x, vc.src_mul_y)) || (!check_align(src->f_w, src->f_h, vc.src_mul_w, vc.src_mul_h)) || @@ -524,6 +525,11 @@ static long dpp_subdev_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg *(int *)arg = dpp->port; break; + case DPP_GET_RESTRICTION: + memcpy((struct dpp_restriction *)arg, &dpp->restriction, + sizeof(struct dpp_restriction)); + break; + default: break; } @@ -550,15 +556,128 @@ static void dpp_init_subdev(struct dpp_device *dpp) v4l2_set_subdevdata(sd, dpp); } +static void dpp_parse_restriction(struct dpp_device *dpp, struct device_node *n) +{ + u32 range[3] = {0, }; + u32 align[2] = {0, }; + + dpp_info("dpp restriction\n"); + of_property_read_u32_array(n, "src_f_w", range, 3); + dpp->restriction.src_f_w.min = range[0]; + dpp->restriction.src_f_w.max = range[1]; + dpp->restriction.src_f_w.align = range[2]; + + of_property_read_u32_array(n, "src_f_h", range, 3); + dpp->restriction.src_f_h.min = range[0]; + dpp->restriction.src_f_h.max = range[1]; + dpp->restriction.src_f_h.align = range[2]; + + of_property_read_u32_array(n, "src_w", range, 3); + dpp->restriction.src_w.min = range[0]; + dpp->restriction.src_w.max = range[1]; + dpp->restriction.src_w.align = range[2]; + + of_property_read_u32_array(n, "src_h", range, 3); + dpp->restriction.src_h.min = range[0]; + dpp->restriction.src_h.max = range[1]; + dpp->restriction.src_h.align = range[2]; + + of_property_read_u32_array(n, "src_xy_align", align, 2); + dpp->restriction.src_x_align = align[0]; + dpp->restriction.src_y_align = align[1]; + + of_property_read_u32_array(n, "dst_f_w", range, 3); + dpp->restriction.dst_f_w.min = range[0]; + dpp->restriction.dst_f_w.max = range[1]; + dpp->restriction.dst_f_w.align = range[2]; + + of_property_read_u32_array(n, "dst_f_h", range, 3); + dpp->restriction.dst_f_h.min = range[0]; + dpp->restriction.dst_f_h.max = range[1]; + dpp->restriction.dst_f_h.align = range[2]; + + of_property_read_u32_array(n, "dst_w", range, 3); + dpp->restriction.dst_w.min = range[0]; + dpp->restriction.dst_w.max = range[1]; + dpp->restriction.dst_w.align = range[2]; + + of_property_read_u32_array(n, "dst_h", range, 3); + dpp->restriction.dst_h.min = range[0]; + dpp->restriction.dst_h.max = range[1]; + dpp->restriction.dst_h.align = range[2]; + + of_property_read_u32_array(n, "dst_xy_align", align, 2); + dpp->restriction.dst_x_align = align[0]; + dpp->restriction.dst_y_align = align[1]; + + of_property_read_u32_array(n, "blk_w", range, 3); + dpp->restriction.blk_w.min = range[0]; + dpp->restriction.blk_w.max = range[1]; + dpp->restriction.blk_w.align = range[2]; + + of_property_read_u32_array(n, "blk_h", range, 3); + dpp->restriction.blk_h.min = range[0]; + dpp->restriction.blk_h.max = range[1]; + dpp->restriction.blk_h.align = range[2]; + + of_property_read_u32_array(n, "blk_xy_align", align, 2); + dpp->restriction.blk_x_align = align[0]; + dpp->restriction.blk_y_align = align[1]; + + if (of_property_read_u32(n, "src_h_rot_max", + &dpp->restriction.src_h_rot_max)) + dpp->restriction.src_h_rot_max = dpp->restriction.src_h.max; +} + +static void dpp_print_restriction(struct dpp_device *dpp) +{ + struct dpp_restriction *res = &dpp->restriction; + + dpp_info("src_f_w[%d %d %d] src_f_h[%d %d %d]\n", + res->src_f_w.min, res->src_f_w.max, res->src_f_w.align, + res->src_f_h.min, res->src_f_h.max, res->src_f_h.align); + dpp_info("src_w[%d %d %d] src_h[%d %d %d] src_x_y_align[%d %d]\n", + res->src_w.min, res->src_w.max, res->src_w.align, + res->src_h.min, res->src_h.max, res->src_h.align, + res->src_x_align, res->src_y_align); + + dpp_info("dst_f_w[%d %d %d] dst_f_h[%d %d %d]\n", + res->dst_f_w.min, res->dst_f_w.max, res->dst_f_w.align, + res->dst_f_h.min, res->dst_f_h.max, res->dst_f_h.align); + dpp_info("dst_w[%d %d %d] dst_h[%d %d %d] dst_x_y_align[%d %d]\n", + res->dst_w.min, res->dst_w.max, res->dst_w.align, + res->dst_h.min, res->dst_h.max, res->dst_h.align, + res->dst_x_align, res->dst_y_align); + + dpp_info("blk_w[%d %d %d] blk_h[%d %d %d] blk_x_y_align[%d %d]\n", + res->blk_w.min, res->blk_w.max, res->blk_w.align, + res->blk_h.min, res->blk_h.max, res->blk_h.align, + res->blk_x_align, res->blk_y_align); + + dpp_info("src_h_rot_max[%d]\n", res->src_h_rot_max); +} + static void dpp_parse_dt(struct dpp_device *dpp, struct device *dev) { + struct device_node *node = dev->of_node; + struct dpp_device *dpp0 = get_dpp_drvdata(0); + dpp->id = of_alias_get_id(dev->of_node, "dpp"); dpp_info("dpp(%d) probe start..\n", dpp->id); - of_property_read_u32(dev->of_node, "attr", (u32 *)&dpp->attr); + of_property_read_u32(node, "attr", (u32 *)&dpp->attr); dpp_info("attributes = 0x%lx\n", dpp->attr); - of_property_read_u32(dev->of_node, "port", (u32 *)&dpp->port); + of_property_read_u32(node, "port", (u32 *)&dpp->port); dpp_info("AXI port = %d\n", dpp->port); + if (dpp->id == 0) { + dpp_parse_restriction(dpp, node); + dpp_print_restriction(dpp); + } else { + memcpy(&dpp->restriction, &dpp0->restriction, + sizeof(struct dpp_restriction)); + dpp_print_restriction(dpp); + } + dpp->dev = dev; } diff --git a/drivers/video/fbdev/exynos/dpu20/dsim.h b/drivers/video/fbdev/exynos/dpu20/dsim.h index fb402f95c3ea..6e1c0e63d0ac 100644 --- a/drivers/video/fbdev/exynos/dpu20/dsim.h +++ b/drivers/video/fbdev/exynos/dpu20/dsim.h @@ -42,6 +42,7 @@ extern int dsim_log_level; #define DSIM_MODULE_NAME "exynos-dsim" +#define MAX_DSIM_CNT 2 #define DSIM_DDI_ID_LEN 3 #define DSIM_PIXEL_FORMAT_RGB24 0x3E diff --git a/drivers/video/fbdev/exynos/dpu20/dsim_drv.c b/drivers/video/fbdev/exynos/dpu20/dsim_drv.c index 93a1c379b664..e1be71c31e02 100644 --- a/drivers/video/fbdev/exynos/dpu20/dsim_drv.c +++ b/drivers/video/fbdev/exynos/dpu20/dsim_drv.c @@ -424,14 +424,16 @@ static void dsim_underrun_info(struct dsim_device *dsim) { #if defined(CONFIG_EXYNOS9610_BTS) struct decon_device *decon; - int i; + int i, decon_cnt; dsim_info("\tMIF(%lu), INT(%lu), DISP(%lu)\n", cal_dfs_get_rate(ACPM_DVFS_MIF), cal_dfs_get_rate(ACPM_DVFS_INT), cal_dfs_get_rate(ACPM_DVFS_DISP)); - for (i = 0; i < MAX_DECON_CNT; ++i) { + decon_cnt = get_decon_drvdata(0)->dt.decon_cnt; + + for (i = 0; i < decon_cnt; ++i) { decon = get_decon_drvdata(i); if (decon) { diff --git a/drivers/video/fbdev/exynos/dpu20/event_log.c b/drivers/video/fbdev/exynos/dpu20/event_log.c index 6f118d8c6f81..e194c25858e8 100644 --- a/drivers/video/fbdev/exynos/dpu20/event_log.c +++ b/drivers/video/fbdev/exynos/dpu20/event_log.c @@ -124,8 +124,11 @@ static int __get_decon_id_for_dpp(struct v4l2_subdev *sd) struct dpp_device *dpp = v4l2_get_subdevdata(sd); int idx; int ret = 0; + int decon_cnt; - for (idx = 0; idx < MAX_DECON_CNT; idx++) { + decon_cnt = get_decon_drvdata(0)->dt.decon_cnt; + + for (idx = 0; idx < decon_cnt; idx++) { decon = get_decon_drvdata(idx); if (!decon || IS_ERR_OR_NULL(decon->d.debug_event)) continue; @@ -310,7 +313,7 @@ void DPU_EVENT_LOG_WINCON(struct v4l2_subdev *sd, struct decon_reg_data *regs) log->time = ktime_get(); log->type = DPU_EVT_UPDATE_HANDLER; - for (win = 0; win < MAX_DECON_WIN; win++) { + for (win = 0; win < decon->dt.max_win; win++) { if (regs->win_regs[win].wincon & WIN_EN_F(win)) { memcpy(&log->data.reg.win_regs[win], ®s->win_regs[win], sizeof(struct decon_window_regs)); @@ -393,7 +396,7 @@ void DPU_EVENT_LOG_CURSOR(struct v4l2_subdev *sd, struct decon_reg_data *regs) log->time = ktime_get(); log->type = DPU_EVT_CURSOR_UPDATE; - for (win = 0; win < MAX_DECON_WIN; win++) { + for (win = 0; win < decon->dt.max_win; win++) { if (regs->is_cursor_win[win] && regs->win_regs[win].wincon & WIN_EN_F(win)) { memcpy(&log->data.reg.win_regs[win], ®s->win_regs[win], sizeof(struct decon_window_regs)); diff --git a/drivers/video/fbdev/exynos/dpu20/fence.c b/drivers/video/fbdev/exynos/dpu20/fence.c index 40ea61c4874a..14d4132a8667 100644 --- a/drivers/video/fbdev/exynos/dpu20/fence.c +++ b/drivers/video/fbdev/exynos/dpu20/fence.c @@ -72,7 +72,7 @@ void decon_create_release_fences(struct decon_device *decon, { int i = 0; - for (i = 0; i < MAX_DECON_WIN; i++) { + for (i = 0; i < decon->dt.max_win; i++) { int state = win_data->config[i].state; int rel_fence = -1; @@ -201,7 +201,7 @@ void decon_create_release_fences(struct decon_device *decon, { int i = 0; - for (i = 0; i < MAX_DECON_WIN; i++) { + for (i = 0; i < decon->dt.max_win; i++) { int state = win_data->config[i].state; int rel_fence = -1; diff --git a/drivers/video/fbdev/exynos/dpu20/helper.c b/drivers/video/fbdev/exynos/dpu20/helper.c index 0d22eb714336..21e42c180712 100644 --- a/drivers/video/fbdev/exynos/dpu20/helper.c +++ b/drivers/video/fbdev/exynos/dpu20/helper.c @@ -543,12 +543,16 @@ void decon_set_protected_content(struct decon_device *decon, /* ODMA protection config (WB: writeback) */ if (decon->dt.out_type == DECON_OUT_WB) if (regs) - cur_protect_bits |= (regs->protection[MAX_DECON_WIN] << ODMA_WB); + cur_protect_bits |= (regs->protection[decon->dt.max_win] << ODMA_WB); if (decon->prev_protection_bitmask != cur_protect_bits) { /* apply protection configs for each DMA */ - for (dma_id = 0; dma_id < MAX_DPP_CNT; dma_id++) { + for (dma_id = 0; dma_id < decon->dt.max_win; dma_id++) { + /* + * This loop should use max_win instead of dpp_cnt, + * because dpp_cnt includes writeback case + */ en = cur_protect_bits & (1 << dma_id); change = (cur_protect_bits & (1 << dma_id)) ^ @@ -582,7 +586,7 @@ void dpu_dump_afbc_info(void) void *v_addr[2]; int size[2]; - for (i = 0; i < MAX_DECON_CNT; i++) { + for (i = 0; i < 3; i++) { decon = get_decon_drvdata(i); if (decon == NULL) continue; @@ -624,13 +628,16 @@ static int dpu_dump_buffer_data(struct dpp_device *dpp) int i; int id_idx = 0; int dump_size = 128; + int decon_cnt; struct decon_device *decon; struct dpu_afbc_info *afbc_info; void *v_addr; + decon_cnt = get_decon_drvdata(0)->dt.decon_cnt; + if (dpp->state == DPP_STATE_ON) { - for (i = 0; i < MAX_DECON_CNT; i++) { + for (i = 0; i < decon_cnt; i++) { decon = get_decon_drvdata(i); if (decon == NULL) continue; @@ -681,7 +688,7 @@ int dpu_sysmmu_fault_handler(struct iommu_domain *domain, return -EINVAL; } - for (i = 0; i < MAX_DPP_SUBDEV; i++) { + for (i = 0; i < decon->dt.dpp_cnt; i++) { if (test_bit(i, &decon->prev_used_dpp)) { dpp = get_dpp_drvdata(i); #if defined(CONFIG_EXYNOS_AFBC_DEBUG) diff --git a/drivers/video/fbdev/exynos/dpu20/win_update.c b/drivers/video/fbdev/exynos/dpu20/win_update.c index 06c7efe8b9f2..a144bda6d585 100644 --- a/drivers/video/fbdev/exynos/dpu20/win_update.c +++ b/drivers/video/fbdev/exynos/dpu20/win_update.c @@ -94,6 +94,8 @@ static void win_update_check_limitation(struct decon_device *decon, struct decon_win_config *config; struct decon_win_rect update; struct decon_rect r; + struct v4l2_subdev *sd; + struct dpp_restriction res; int i; int sz_align = 1; int adj_src_x = 0, adj_src_y = 0; @@ -103,6 +105,7 @@ static void win_update_check_limitation(struct decon_device *decon, if (config->state == DECON_WIN_STATE_DISABLED) continue; + r.left = config->dst.x; r.top = config->dst.y; r.right = config->dst.w + config->dst.x - 1; @@ -131,8 +134,11 @@ static void win_update_check_limitation(struct decon_device *decon, goto change_full; } - if (((r.right - r.left) < (SRC_WIDTH_MIN * sz_align)) || - ((r.bottom - r.top) < (SRC_HEIGHT_MIN * sz_align))) { + sd = decon->dpp_sd[0]; + v4l2_subdev_call(sd, core, ioctl, DPP_GET_RESTRICTION, &res); + + if (((r.right - r.left) < (res.src_f_w.min * sz_align)) || + ((r.bottom - r.top) < (res.src_f_h.min * sz_align))) { goto change_full; } -- 2.20.1