From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752807AbdBGChb (ORCPT ); Mon, 6 Feb 2017 21:37:31 -0500 Received: from szxga02-in.huawei.com ([119.145.14.65]:19478 "EHLO szxga02-in.huawei.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752579AbdBGChZ (ORCPT ); Mon, 6 Feb 2017 21:37:25 -0500 From: cailiwei To: , , , CC: , , , , , Subject: [PATCH 7/8] fb: hisilicon: Add framebuffer driver for hi3660 SoC Date: Tue, 7 Feb 2017 10:35:58 +0800 Message-ID: <20170207023559.79455-7-cailiwei@hisilicon.com> X-Mailer: git-send-email 2.11.1 In-Reply-To: <20170207023559.79455-1-cailiwei@hisilicon.com> References: <20170207023559.79455-1-cailiwei@hisilicon.com> MIME-Version: 1.0 Content-Type: text/plain X-Originating-IP: [100.106.171.187] X-CFilter-Loop: Reflected X-Mirapoint-Virus-RAPID-Raw: score=unknown(0), refid=str=0001.0A020201.589932CD.0114,ss=1,re=0.000,recu=0.000,reip=0.000,cl=1,cld=1,fgs=0, ip=0.0.0.0, so=2013-06-18 04:22:30, dmn=2013-03-21 17:37:32 X-Mirapoint-Loop-Id: 3bc359a30bc5c8cca416397d27813765 Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org From: Levy-Cai Add framebuffer driver for hi3660 SoC, this driver include lcd driver & Hdmi adv7533/adv7535 driver, support lcd display at 1080p@60 and hdmi display at 1080p@60. Signed-off-by: cailiwei --- drivers/video/fbdev/hisi/dss/hisi_overlay_online.c | 733 ++ drivers/video/fbdev/hisi/dss/hisi_overlay_utils.c | 8495 ++++++++++++++++++++ drivers/video/fbdev/hisi/dss/hisi_overlay_utils.h | 269 + .../fbdev/hisi/dss/hisi_overlay_utils_hi3660.c | 2741 +++++++ .../fbdev/hisi/dss/hisi_overlay_utils_hi3660.h | 73 + 5 files changed, 12311 insertions(+) create mode 100755 drivers/video/fbdev/hisi/dss/hisi_overlay_online.c create mode 100755 drivers/video/fbdev/hisi/dss/hisi_overlay_utils.c create mode 100755 drivers/video/fbdev/hisi/dss/hisi_overlay_utils.h create mode 100755 drivers/video/fbdev/hisi/dss/hisi_overlay_utils_hi3660.c create mode 100755 drivers/video/fbdev/hisi/dss/hisi_overlay_utils_hi3660.h diff --git a/drivers/video/fbdev/hisi/dss/hisi_overlay_online.c b/drivers/video/fbdev/hisi/dss/hisi_overlay_online.c new file mode 100755 index 000000000000..9cb65225dc63 --- /dev/null +++ b/drivers/video/fbdev/hisi/dss/hisi_overlay_online.c @@ -0,0 +1,733 @@ +/* Copyright (c) 2013-2014, Hisilicon Tech. Co., Ltd. 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 + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include "hisi_overlay_utils.h" +#include "hisi_dpe_utils.h" + +static int hisi_get_ov_data_from_user(struct hisi_fb_data_type *hisifd, + dss_overlay_t *pov_req, + void __user *argp) +{ + int ret = 0; + dss_overlay_block_t *pov_h_block_infos = NULL; + + BUG_ON(hisifd == NULL); + BUG_ON(pov_req == NULL); + + if (NULL == argp) { + HISI_FB_ERR("user data is invalid\n"); + return -EINVAL; + } + pov_h_block_infos = hisifd->ov_block_infos; + + ret = copy_from_user(pov_req, argp, sizeof(dss_overlay_t)); + if (ret) { + HISI_FB_ERR("fb%d, copy_from_user failed!\n", hisifd->index); + return -EINVAL; + } + + if ((pov_req->ov_block_nums <= 0) || + (pov_req->ov_block_nums > HISI_DSS_OV_BLOCK_NUMS)) { + HISI_FB_ERR("fb%d, ov_block_nums(%d) is out of range!\n", + hisifd->index, pov_req->ov_block_nums); + return -EINVAL; + } + + ret = + copy_from_user(pov_h_block_infos, + (dss_overlay_block_t *) pov_req->ov_block_infos_ptr, + pov_req->ov_block_nums * + sizeof(dss_overlay_block_t)); + if (ret) { + HISI_FB_ERR + ("fb%d, dss_overlay_block_t copy_from_user failed!\n", + hisifd->index); + return -EINVAL; + } + + ret = hisi_dss_check_userdata(hisifd, pov_req, pov_h_block_infos); + if (ret != 0) { + HISI_FB_ERR("fb%d, hisi_dss_check_userdata failed!\n", + hisifd->index); + return -EINVAL; + } + + pov_req->ov_block_infos_ptr = (uint64_t) pov_h_block_infos; + + return ret; +} + +int hisi_overlay_pan_display(struct hisi_fb_data_type *hisifd) +{ + int ret = 0; + struct fb_info *fbi = NULL; + dss_overlay_t *pov_req = NULL; + dss_overlay_t *pov_req_prev = NULL; + dss_overlay_block_t *pov_h_block_infos = NULL; + dss_overlay_block_t *pov_h_block = NULL; + dss_layer_t *layer = NULL; + dss_rect_ltrb_t clip_rect; + dss_rect_t aligned_rect; + bool rdma_stretch_enable = false; + uint32_t offset = 0; + uint32_t addr = 0; + int hal_format = 0; + uint32_t cmdlist_pre_idxs = 0; + uint32_t cmdlist_idxs = 0; + int enable_cmdlist = 0; + bool has_base = false; + + if (NULL == hisifd) { + HISI_FB_ERR("hisi fd is invalid\n"); + return -EINVAL; + } + fbi = hisifd->fbi; + if (NULL == fbi) { + HISI_FB_ERR("hisifd fbi is invalid\n"); + return -EINVAL; + } + + pov_req = &(hisifd->ov_req); + pov_req_prev = &(hisifd->ov_req_prev); + + if (!hisifd->panel_power_on) { + HISI_FB_INFO("fb%d, panel is power off!", hisifd->index); + return 0; + } + + if (g_debug_ldi_underflow) { + if (g_err_status & + (DSS_PDP_LDI_UNDERFLOW | DSS_SDP_LDI_UNDERFLOW)) + return 0; + } + + offset = fbi->var.xoffset * (fbi->var.bits_per_pixel >> 3) + + fbi->var.yoffset * fbi->fix.line_length; + addr = fbi->fix.smem_start + offset; + if (!fbi->fix.smem_start) { + HISI_FB_ERR("fb%d, smem_start is null!\n", hisifd->index); + return -EINVAL; + } + + if (fbi->fix.smem_len <= 0) { + HISI_FB_ERR("fb%d, smem_len(%d) is out of range!\n", + hisifd->index, fbi->fix.smem_len); + return -EINVAL; + } + + hal_format = hisi_get_hal_format(fbi); + if (hal_format < 0) { + HISI_FB_ERR("fb%d, not support this fb_info's format!\n", + hisifd->index); + return -EINVAL; + } + + enable_cmdlist = g_enable_ovl_cmdlist_online; + if ((hisifd->index == EXTERNAL_PANEL_IDX) + && hisifd->panel_info.fake_hdmi) + enable_cmdlist = 0; + + hisifb_activate_vsync(hisifd); + + ret = hisi_vactive0_start_config(hisifd, pov_req); + if (ret != 0) { + HISI_FB_ERR + ("fb%d, hisi_vactive0_start_config failed! ret = %d\n", + hisifd->index, ret); + goto err_return; + } + + if (g_debug_ovl_online_composer == 1) { + dumpDssOverlay(hisifd, pov_req, false); + } + + memset(pov_req, 0, sizeof(dss_overlay_t)); + pov_req->ov_block_infos_ptr = (uint64_t) (&(hisifd->ov_block_infos)); + pov_req->ov_block_nums = 1; + pov_req->ovl_idx = DSS_OVL0; + pov_req->dirty_rect.x = 0; + pov_req->dirty_rect.y = 0; + pov_req->dirty_rect.w = fbi->var.xres; + pov_req->dirty_rect.h = fbi->var.yres; + + pov_req->res_updt_rect.x = 0; + pov_req->res_updt_rect.y = 0; + pov_req->res_updt_rect.w = fbi->var.xres; + pov_req->res_updt_rect.h = fbi->var.yres; + + pov_h_block_infos = + (dss_overlay_block_t *) (pov_req->ov_block_infos_ptr); + pov_h_block = &(pov_h_block_infos[0]); + pov_h_block->layer_nums = 1; + + layer = &(pov_h_block->layer_infos[0]); + layer->img.format = hal_format; + layer->img.width = fbi->var.xres; + layer->img.height = fbi->var.yres; + layer->img.bpp = fbi->var.bits_per_pixel >> 3; + layer->img.stride = fbi->fix.line_length; + layer->img.buf_size = layer->img.stride * layer->img.height; + layer->img.phy_addr = addr; + layer->img.vir_addr = addr; + layer->img.mmu_enable = 1; + layer->src_rect.x = 0; + layer->src_rect.y = 0; + layer->src_rect.w = fbi->var.xres; + layer->src_rect.h = fbi->var.yres; + layer->dst_rect.x = 0; + layer->dst_rect.y = 0; + layer->dst_rect.w = fbi->var.xres; + layer->dst_rect.h = fbi->var.yres; + layer->transform = HISI_FB_TRANSFORM_NOP; + layer->blending = HISI_FB_BLENDING_NONE; + layer->glb_alpha = 0xFF; + layer->color = 0x0; + layer->layer_idx = 0x0; + layer->chn_idx = DSS_RCHN_D2; + layer->need_cap = 0; + + hisi_dss_handle_cur_ovl_req(hisifd, pov_req); + + ret = hisi_dss_module_init(hisifd); + if (ret != 0) { + HISI_FB_ERR("fb%d, hisi_dss_module_init failed! ret = %d\n", + hisifd->index, ret); + goto err_return; + } + + hisi_mmbuf_info_get_online(hisifd); + + if (enable_cmdlist) { + hisifd->set_reg = hisi_cmdlist_set_reg; + + hisi_cmdlist_data_get_online(hisifd); + + ret = + hisi_cmdlist_get_cmdlist_idxs(pov_req_prev, + &cmdlist_pre_idxs, NULL); + if (ret != 0) { + HISI_FB_ERR + ("fb%d, hisi_cmdlist_get_cmdlist_idxs pov_req_prev failed! " + "ret = %d\n", + hisifd->index, ret); + goto err_return; + } + + ret = + hisi_cmdlist_get_cmdlist_idxs(pov_req, &cmdlist_pre_idxs, + &cmdlist_idxs); + if (ret != 0) { + HISI_FB_ERR + ("fb%d, hisi_cmdlist_get_cmdlist_idxs pov_req failed! " + "ret = %d\n", + hisifd->index, ret); + goto err_return; + } + + hisi_cmdlist_add_nop_node(hisifd, cmdlist_pre_idxs, 0, 0); + hisi_cmdlist_add_nop_node(hisifd, cmdlist_idxs, 0, 0); + } else { + hisifd->set_reg = hisifb_set_reg; + + hisi_dss_mctl_mutex_lock(hisifd, pov_req->ovl_idx); + cmdlist_pre_idxs = ~0; + } + + hisi_dss_prev_module_set_regs(hisifd, pov_req_prev, cmdlist_pre_idxs, + enable_cmdlist, NULL); + + hisi_dss_aif_handler(hisifd, pov_req, pov_h_block); + + ret = + hisi_dss_ovl_base_config(hisifd, pov_req, NULL, NULL, + pov_req->ovl_idx, 0); + if (ret != 0) { + HISI_FB_ERR("fb%d, hisi_dss_ovl_init failed! ret = %d\n", + hisifd->index, ret); + goto err_return; + } + + ret = + hisi_ov_compose_handler(hisifd, pov_req, pov_h_block, layer, NULL, + NULL, &clip_rect, &aligned_rect, + &rdma_stretch_enable, &has_base, true, + enable_cmdlist); + if (ret != 0) { + HISI_FB_ERR("hisi_ov_compose_handler failed! ret = %d\n", ret); + goto err_return; + } + + ret = + hisi_dss_mctl_ov_config(hisifd, pov_req, pov_req->ovl_idx, has_base, + true); + if (ret != 0) { + HISI_FB_ERR("fb%d, hisi_dss_mctl_config failed! ret = %d\n", + hisifd->index, ret); + goto err_return; + } + + if (hisifd->panel_info.dirty_region_updt_support) { + ret = hisi_dss_dirty_region_dbuf_config(hisifd, pov_req); + if (ret != 0) { + HISI_FB_ERR + ("fb%d, hisi_dss_dirty_region_dbuf_config failed! ret = %d\n", + hisifd->index, ret); + goto err_return; + } + } + + ret = hisi_dss_post_scf_config(hisifd, pov_req); + if (ret != 0) { + HISI_FB_ERR("fb%d, hisi_dss_post_scf_config failed! ret = %d\n", + hisifd->index, ret); + goto err_return; + } + + ret = + hisi_dss_ov_module_set_regs(hisifd, pov_req, pov_req->ovl_idx, + enable_cmdlist, 0, 0, true); + if (ret != 0) { + HISI_FB_ERR("fb%d, hisi_dss_module_config failed! ret = %d\n", + hisifd->index, ret); + goto err_return; + } + hisi_dss_unflow_handler(hisifd, pov_req, true); + + if (enable_cmdlist) { + hisi_cmdlist_add_nop_node(hisifd, cmdlist_idxs, 0, 0); + hisi_cmdlist_config_stop(hisifd, cmdlist_pre_idxs); + + cmdlist_idxs |= cmdlist_pre_idxs; + hisi_cmdlist_flush_cache(hisifd, hisifd->ion_client, + cmdlist_idxs); + + if (g_debug_ovl_cmdlist) { + hisi_cmdlist_dump_all_node(hisifd, NULL, cmdlist_idxs); + } + + hisi_cmdlist_config_start(hisifd, pov_req->ovl_idx, + cmdlist_idxs, 0); + } else { + hisi_dss_mctl_mutex_unlock(hisifd, pov_req->ovl_idx); + } + + if (hisifd->panel_info.dirty_region_updt_support) { + hisi_dss_dirty_region_updt_config(hisifd, pov_req); + } + + single_frame_update(hisifd); + hisifb_frame_updated(hisifd); + + hisifb_deactivate_vsync(hisifd); + + hisifd->frame_count++; + memcpy(&hisifd->ov_req_prev_prev, &hisifd->ov_req_prev, + sizeof(dss_overlay_t)); + memcpy(&(hisifd->ov_block_infos_prev_prev), + &(hisifd->ov_block_infos_prev), + hisifd->ov_req_prev.ov_block_nums * sizeof(dss_overlay_block_t)); + hisifd->ov_req_prev_prev.ov_block_infos_ptr = + (uint64_t) (&(hisifd->ov_block_infos_prev_prev)); + + memcpy(&hisifd->ov_req_prev, pov_req, sizeof(dss_overlay_t)); + memcpy(&(hisifd->ov_block_infos_prev), &(hisifd->ov_block_infos), + pov_req->ov_block_nums * sizeof(dss_overlay_block_t)); + hisifd->ov_req_prev.ov_block_infos_ptr = + (uint64_t) (&(hisifd->ov_block_infos_prev)); + + return 0; + + err_return: + if (is_mipi_cmd_panel(hisifd)) { + hisifd->vactive0_start_flag = 1; + } else { + single_frame_update(hisifd); + } + hisifb_deactivate_vsync(hisifd); + + return ret; +} + +int hisi_ov_online_play(struct hisi_fb_data_type *hisifd, void __user *argp) +{ + static int dss_free_buffer_refcount; + dss_overlay_t *pov_req = NULL; + dss_overlay_t *pov_req_prev = NULL; + dss_overlay_block_t *pov_h_block_infos = NULL; + dss_overlay_block_t *pov_h_block = NULL; + dss_layer_t *layer = NULL; + dss_rect_ltrb_t clip_rect; + dss_rect_t aligned_rect; + bool rdma_stretch_enable = false; + uint32_t cmdlist_pre_idxs = 0; + uint32_t cmdlist_idxs = 0; + int enable_cmdlist = 0; + bool has_base = false; +#ifdef CONFIG_BUF_SYNC_USED + unsigned long flags = 0; +#endif + int need_skip = 0; + int i = 0; + int m = 0; + int ret = 0; + uint32_t timediff = 0; + struct list_head lock_list; + struct timeval tv0; + struct timeval tv1; + struct timeval tv2; + struct timeval tv3; + + if (NULL == hisifd) { + HISI_FB_ERR("NULL Pointer!\n"); + return -EINVAL; + } + + if (NULL == argp) { + HISI_FB_ERR("NULL Pointer!\n"); + return -EINVAL; + } + + pov_req = &(hisifd->ov_req); + pov_req_prev = &(hisifd->ov_req_prev); + INIT_LIST_HEAD(&lock_list); + + if (!hisifd->panel_power_on) { + HISI_FB_INFO("fb%d, panel is power off!\n", hisifd->index); + return 0; + } + + if (g_debug_ovl_online_composer_return) { + return 0; + } + + if (g_debug_ovl_online_composer_timediff & 0x2) { + hisifb_get_timestamp(&tv0); + } + + enable_cmdlist = g_enable_ovl_cmdlist_online; + if ((hisifd->index == EXTERNAL_PANEL_IDX) + && hisifd->panel_info.fake_hdmi) { + enable_cmdlist = 0; + } + + hisifb_activate_vsync(hisifd); + + if (g_debug_ovl_online_composer_timediff & 0x4) { + hisifb_get_timestamp(&tv2); + } + + ret = hisi_get_ov_data_from_user(hisifd, pov_req, argp); + if (ret != 0) { + HISI_FB_ERR("fb%d, hisi_get_ov_data_from_user failed! ret=%d\n", + hisifd->index, ret); + need_skip = 1; + goto err_return; + } +#ifdef CONFIG_BUF_SYNC_USED + if (is_mipi_video_panel(hisifd)) { + ret = hisifb_buf_sync_handle(hisifd, pov_req); + if (ret < 0) { + HISI_FB_ERR + ("fb%d, hisifb_buf_sync_handle failed! ret=%d\n", + hisifd->index, ret); + need_skip = 1; + goto err_return; + } + } +#endif + + ret = hisi_vactive0_start_config(hisifd, pov_req); + if (ret != 0) { + HISI_FB_ERR("fb%d, hisi_vactive0_start_config failed! ret=%d\n", + hisifd->index, ret); + need_skip = 1; + goto err_return; + } + down(&hisifd->blank_sem0); + + if (g_debug_ovl_online_composer_timediff & 0x4) { + hisifb_get_timestamp(&tv3); + timediff = hisifb_timestamp_diff(&tv2, &tv3); + if (timediff >= g_debug_ovl_online_composer_time_threshold) + HISI_FB_ERR("ONLINE_VACTIVE_TIMEDIFF is %u us!\n", + timediff); + } + + if (g_debug_ovl_online_composer == 1) { + dumpDssOverlay(hisifd, pov_req, false); + } + + ret = hisifb_layerbuf_lock(hisifd, pov_req, &lock_list); + if (ret != 0) { + HISI_FB_ERR("fb%d, hisifb_layerbuf_lock failed! ret=%d\n", + hisifd->index, ret); + goto err_return; + } + + hisi_dss_handle_cur_ovl_req(hisifd, pov_req); + + ret = hisi_dss_module_init(hisifd); + if (ret != 0) { + HISI_FB_ERR("fb%d, hisi_dss_module_init failed! ret = %d\n", + hisifd->index, ret); + goto err_return; + } + hisi_mmbuf_info_get_online(hisifd); + + if (enable_cmdlist) { + hisifd->set_reg = hisi_cmdlist_set_reg; + hisi_cmdlist_data_get_online(hisifd); + + ret = + hisi_cmdlist_get_cmdlist_idxs(pov_req_prev, + &cmdlist_pre_idxs, NULL); + if (ret != 0) { + HISI_FB_ERR + ("fb%d, hisi_cmdlist_get_cmdlist_idxs pov_req_prev failed! " + "ret = %d\n", + hisifd->index, ret); + goto err_return; + } + + ret = + hisi_cmdlist_get_cmdlist_idxs(pov_req, &cmdlist_pre_idxs, + &cmdlist_idxs); + if (ret != 0) { + HISI_FB_ERR + ("fb%d, hisi_cmdlist_get_cmdlist_idxs pov_req failed! ret = %d\n", + hisifd->index, ret); + goto err_return; + } + + hisi_cmdlist_add_nop_node(hisifd, cmdlist_pre_idxs, 0, 0); + hisi_cmdlist_add_nop_node(hisifd, cmdlist_idxs, 0, 0); + } else { + hisifd->set_reg = hisifb_set_reg; + hisi_dss_mctl_mutex_lock(hisifd, pov_req->ovl_idx); + cmdlist_pre_idxs = ~0; + } + + hisi_dss_prev_module_set_regs(hisifd, pov_req_prev, cmdlist_pre_idxs, + enable_cmdlist, NULL); + + pov_h_block_infos = + (dss_overlay_block_t *) (pov_req->ov_block_infos_ptr); + for (m = 0; m < pov_req->ov_block_nums; m++) { + pov_h_block = &(pov_h_block_infos[m]); + + ret = hisi_dss_module_init(hisifd); + if (ret != 0) { + HISI_FB_ERR + ("fb%d, hisi_dss_module_init failed! ret = %d\n", + hisifd->index, ret); + goto err_return; + } + hisi_dss_aif_handler(hisifd, pov_req, pov_h_block); + + ret = + hisi_dss_ovl_base_config(hisifd, pov_req, pov_h_block, NULL, + pov_req->ovl_idx, m); + if (ret != 0) { + HISI_FB_ERR + ("fb%d, hisi_dss_ovl_init failed! ret = %d\n", + hisifd->index, ret); + goto err_return; + } + + for (i = 0; i < pov_h_block->layer_nums; i++) { + layer = &(pov_h_block->layer_infos[i]); + memset(&clip_rect, 0, sizeof(dss_rect_ltrb_t)); + memset(&aligned_rect, 0, sizeof(dss_rect_ltrb_t)); + rdma_stretch_enable = false; + + ret = + hisi_ov_compose_handler(hisifd, pov_req, + pov_h_block, layer, NULL, + NULL, &clip_rect, + &aligned_rect, + &rdma_stretch_enable, + &has_base, true, + enable_cmdlist); + if (ret != 0) { + HISI_FB_ERR + ("fb%d, hisi_ov_compose_handler failed! ret = %d\n", + hisifd->index, ret); + goto err_return; + } + } + + ret = + hisi_dss_mctl_ov_config(hisifd, pov_req, pov_req->ovl_idx, + has_base, (m == 0)); + if (ret != 0) { + HISI_FB_ERR + ("fb%d, hisi_dss_mctl_config failed! ret = %d\n", + hisifd->index, ret); + goto err_return; + } + + if (m == 0) { + if (hisifd->panel_info.dirty_region_updt_support) { + ret = + hisi_dss_dirty_region_dbuf_config(hisifd, pov_req); + if (ret != 0) { + HISI_FB_ERR + ("fb%d, hisi_dss_dirty_region_dbuf_config failed! ret = %d\n", + hisifd->index, ret); + goto err_return; + } + } + } + + ret = hisi_dss_post_scf_config(hisifd, pov_req); + if (ret != 0) { + HISI_FB_ERR + ("fb%d, hisi_dss_post_scf_config failed! ret = %d\n", + hisifd->index, ret); + goto err_return; + } + + ret = + hisi_dss_ov_module_set_regs(hisifd, pov_req, + pov_req->ovl_idx, + enable_cmdlist, 0, 0, (m == 0)); + if (ret != 0) { + HISI_FB_ERR + ("fb%d, hisi_dss_module_config failed! ret = %d\n", + hisifd->index, ret); + goto err_return; + } + } + + if (enable_cmdlist) { + g_online_cmdlist_idxs |= cmdlist_idxs; + hisi_cmdlist_add_nop_node(hisifd, cmdlist_idxs, 0, 0); + hisi_cmdlist_config_stop(hisifd, cmdlist_pre_idxs); + + cmdlist_idxs |= cmdlist_pre_idxs; + hisi_cmdlist_flush_cache(hisifd, hisifd->ion_client, + cmdlist_idxs); + } + + ret = hisi_crc_enable(hisifd, pov_req); + if (ret != 0) { + HISI_FB_ERR("fb%d, hisi_crc_enable failed!\n", hisifd->index); + goto err_return; + } + hisi_dss_unflow_handler(hisifd, pov_req, true); + +#ifdef CONFIG_BUF_SYNC_USED + if (is_mipi_cmd_panel(hisifd)) { + ret = hisifb_buf_sync_handle(hisifd, pov_req); + if (ret < 0) { + HISI_FB_ERR + ("fb%d, hisifb_buf_sync_handle failed! ret=%d\n", + hisifd->index, ret); + goto err_return; + } + } + + pov_req->release_fence = + hisifb_buf_sync_create_fence(hisifd, + ++hisifd->buf_sync_ctrl.timeline_max); + if (pov_req->release_fence < 0) { + HISI_FB_INFO + ("fb%d, hisi_create_fence failed! pov_req->release_fence = 0x%x\n", + hisifd->index, pov_req->release_fence); + } + + spin_lock_irqsave(&hisifd->buf_sync_ctrl.refresh_lock, flags); + hisifd->buf_sync_ctrl.refresh++; + spin_unlock_irqrestore(&hisifd->buf_sync_ctrl.refresh_lock, flags); +#endif + + if (enable_cmdlist) { + hisi_cmdlist_config_start(hisifd, pov_req->ovl_idx, + cmdlist_idxs, 0); + } else { + hisi_dss_mctl_mutex_unlock(hisifd, pov_req->ovl_idx); + } + + if (hisifd->panel_info.dirty_region_updt_support) { + hisi_dss_dirty_region_updt_config(hisifd, pov_req); + } + + single_frame_update(hisifd); + hisifb_frame_updated(hisifd); + hisi_crc_config(hisifd, pov_req); + + if (copy_to_user((struct dss_overlay_t __user *)argp, + pov_req, sizeof(dss_overlay_t))) { + ret = -EFAULT; + + if (pov_req->release_fence >= 0) + put_unused_fd(pov_req->release_fence); + + goto err_return; + } + + hisifb_deactivate_vsync(hisifd); + hisifb_layerbuf_flush(hisifd, &lock_list); + + if ((hisifd->index == PRIMARY_PANEL_IDX) + && (dss_free_buffer_refcount > 1)) { + if (!hisifd->fb_mem_free_flag) { + hisifb_free_fb_buffer(hisifd); + hisifd->fb_mem_free_flag = true; + } + } + + if (g_debug_ovl_online_composer == 2) { + dumpDssOverlay(hisifd, pov_req, true); + } + + if (g_debug_ovl_cmdlist && enable_cmdlist) + hisi_cmdlist_dump_all_node(hisifd, NULL, cmdlist_idxs); + + hisifd->frame_count++; + dss_free_buffer_refcount++; + memcpy(&hisifd->ov_req_prev_prev, &hisifd->ov_req_prev, + sizeof(dss_overlay_t)); + memcpy(&(hisifd->ov_block_infos_prev_prev), + &(hisifd->ov_block_infos_prev), + hisifd->ov_req_prev.ov_block_nums * sizeof(dss_overlay_block_t)); + hisifd->ov_req_prev_prev.ov_block_infos_ptr = + (uint64_t) (&(hisifd->ov_block_infos_prev_prev)); + + memcpy(&hisifd->ov_req_prev, pov_req, sizeof(dss_overlay_t)); + memcpy(&(hisifd->ov_block_infos_prev), &(hisifd->ov_block_infos), + pov_req->ov_block_nums * sizeof(dss_overlay_block_t)); + hisifd->ov_req_prev.ov_block_infos_ptr = + (uint64_t) (&(hisifd->ov_block_infos_prev)); + + if (g_debug_ovl_online_composer_timediff & 0x2) { + hisifb_get_timestamp(&tv1); + timediff = hisifb_timestamp_diff(&tv0, &tv1); + if (timediff >= g_debug_ovl_online_composer_time_threshold) + HISI_FB_ERR("ONLINE_TIMEDIFF is %u us!\n", timediff); + } + up(&hisifd->blank_sem0); + + return 0; + + err_return: + if (is_mipi_cmd_panel(hisifd)) { + hisifd->vactive0_start_flag = 1; + } + hisifb_layerbuf_lock_exception(hisifd, &lock_list); + hisifb_deactivate_vsync(hisifd); + if (!need_skip) { + up(&hisifd->blank_sem0); + } + return ret; +} diff --git a/drivers/video/fbdev/hisi/dss/hisi_overlay_utils.c b/drivers/video/fbdev/hisi/dss/hisi_overlay_utils.c new file mode 100755 index 000000000000..97d71df5a38d --- /dev/null +++ b/drivers/video/fbdev/hisi/dss/hisi_overlay_utils.c @@ -0,0 +1,8495 @@ +/* Copyright (c) 2013-2014, Hisilicon Tech. Co., Ltd. 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 + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ +/*lint -e778 -e732*/ + +#include "hisi_overlay_utils.h" +#include "hisi_dpe_utils.h" + +#define SMMU_RW_ERR_ADDR_SIZE (128) + +/* mmbuf gen pool */ +static struct gen_pool *g_mmbuf_gen_pool = NULL; +static dss_mmbuf_t g_pre_online_mmbuf[DSS_CHN_MAX_DEFINE] = { {0, 0} }; + +static uint32_t vactive_timeout_count = 0; + +static inline bool hisi_dss_is_sharpness_support(int32_t width, int32_t height) +{ + return ((16 <= width) && (width <= 1600) && (4 <= height) + && (height <= 2560)); +} + +/******************************************************************************* + ** + */ +static int32_t hisi_transform2degree(uint32_t transform) +{ + int ret = 0; + + switch (transform) { + case HISI_FB_TRANSFORM_NOP: + case HISI_FB_TRANSFORM_FLIP_H: + case HISI_FB_TRANSFORM_FLIP_V: + ret = 0; + break; + case HISI_FB_TRANSFORM_ROT_90: + ret = 90; + break; + case HISI_FB_TRANSFORM_ROT_180: + ret = 180; + break; + case HISI_FB_TRANSFORM_ROT_270: + ret = 270; + break; + default: + ret = -1; + HISI_FB_ERR("not support transform(%d)!", transform); + break; + } + + return ret; +} + +#define DUMP_BUF_SIZE SZ_256K + +struct dss_dump_data_type { + char *dss_buf; + uint32_t dss_buf_len; + char dss_filename[256]; + + char *scene_buf; + uint32_t scene_buf_len; + char scene_filename[256]; + + char image_bin_filename[MAX_DSS_SRC_NUM][256]; +}; + +void dumpDssOverlay(struct hisi_fb_data_type *hisifd, dss_overlay_t *pov_req, + bool isNeedSaveFile) +{ + uint32_t i = 0; + uint32_t k = 0; + dss_layer_t const *layer = NULL; + dss_wb_layer_t const *wb_layer = NULL; + struct timeval tv; + dss_overlay_block_t *pov_h_block_infos = NULL; + dss_overlay_block_t *pov_block_info = NULL; + + struct dss_dump_data_type *dumpDss = NULL; + char *image_src_addr = NULL; + struct ion_handle *ionhnd = NULL; + + static const char *const layer_format[] = { + "RGB565", "RGBX4444", "RGBA4444", "RGBX5551", "RGBA5551", + "RGBX8888", "RGBA8888", + "BGR565", "BGRX4444", "BGRA4444", "BGRX5551", "BGRA5551", + "BGRX8888", "BGRA8888", + "YCbYCr", "", "", "NV12", "NV21", "", "", "", "YV12", "", "" + }; + + BUG_ON(hisifd == NULL); + BUG_ON(pov_req == NULL); + BUG_ON((pov_req->ovl_idx < DSS_OVL0) + || (pov_req->ovl_idx >= DSS_OVL_IDX_MAX)); + + dumpDss = kmalloc(sizeof(struct dss_dump_data_type), GFP_KERNEL); + if (IS_ERR_OR_NULL(dumpDss)) { + HISI_FB_ERR("alloc dumpDss failed!\n"); + goto alloc_dump_dss_data_err; + } + memset(dumpDss, 0, sizeof(struct dss_dump_data_type)); + + if (isNeedSaveFile) { + hisifb_get_timestamp(&tv); + snprintf(dumpDss->scene_filename, + sizeof(dumpDss->scene_filename), + "/data/dssdump/Scene_%ld.sce", tv.tv_sec); + snprintf(dumpDss->dss_filename, sizeof(dumpDss->dss_filename), + "/data/dssdump/Dss_%ld.txt", tv.tv_sec); + + + dumpDss->scene_buf_len = 0; + dumpDss->scene_buf = kmalloc(DUMP_BUF_SIZE, GFP_KERNEL); + if (IS_ERR_OR_NULL(dumpDss->scene_buf)) { + HISI_FB_ERR("alloc scene_buf failed!\n"); + goto alloc_scene_buf_err; + } + memset(dumpDss->scene_buf, 0, DUMP_BUF_SIZE); + } + + dumpDss->dss_buf_len = 0; + dumpDss->dss_buf = kmalloc(DUMP_BUF_SIZE, GFP_KERNEL); + if (IS_ERR_OR_NULL(dumpDss->dss_buf)) { + HISI_FB_ERR("alloc dss_buf failed!\n"); + goto alloc_dss_buf_err; + } + memset(dumpDss->dss_buf, 0, DUMP_BUF_SIZE); + + dumpDss->dss_buf_len += + snprintf(dumpDss->dss_buf + dumpDss->dss_buf_len, 4 * SZ_1K, + "\n\n--------------------------------------------------------\n" + "frame_no=%d\n" "ovl_idx=%d\n" + "res_updt_rect(%d, %d, %d, %d)\n" + "dirty_rect(%d,%d, %d,%d)\n" "release_fence=%d\n" + "crc_enable_status=%d\n" "crc_info(%d,%d)\n" + "ov_block_nums=%d\n" "ov_block_infos_ptr=0x%llx\n" + "wb_enable=%d\n" "wb_layer_nums=%d\n" + "wb_ov_rect(%d,%d, %d,%d)\n", pov_req->frame_no, + pov_req->ovl_idx, pov_req->res_updt_rect.x, + pov_req->res_updt_rect.y, pov_req->res_updt_rect.w, + pov_req->res_updt_rect.h, pov_req->dirty_rect.x, + pov_req->dirty_rect.y, pov_req->dirty_rect.w, + pov_req->dirty_rect.h, pov_req->release_fence, + pov_req->crc_enable_status, + pov_req->crc_info.crc_ov_result, + pov_req->crc_info.err_status, pov_req->ov_block_nums, + pov_req->ov_block_infos_ptr, pov_req->wb_enable, + pov_req->wb_layer_nums, pov_req->wb_ov_rect.x, + pov_req->wb_ov_rect.y, pov_req->wb_ov_rect.w, + pov_req->wb_ov_rect.h); + + for (i = 0; i < pov_req->ov_block_nums; i++) { + pov_h_block_infos = + (dss_overlay_block_t *) (pov_req->ov_block_infos_ptr); + pov_block_info = &(pov_h_block_infos[i]); + + dumpDss->dss_buf_len += + snprintf(dumpDss->dss_buf + dumpDss->dss_buf_len, 4 * SZ_1K, + "\nov_block_rect(%d,%d, %d,%d)\n" + "layer_nums=%d\n", pov_block_info->ov_block_rect.x, + pov_block_info->ov_block_rect.y, + pov_block_info->ov_block_rect.w, + pov_block_info->ov_block_rect.h, + pov_block_info->layer_nums); + + for (k = 0; k < pov_block_info->layer_nums; k++) { + layer = &(pov_block_info->layer_infos[k]); + + dumpDss->dss_buf_len += + snprintf(dumpDss->dss_buf + dumpDss->dss_buf_len, + 4 * SZ_1K, + "\nLayerInfo[%d]:\n" "format=%d\n" + "width=%d\n" "height=%d\n" "bpp=%d\n" + "buf_size=%d\n" "stride=%d\n" + "stride_plane1=0x%x\n" + "stride_plane2=0x%x\n" "phy_addr=0x%llx\n" + "vir_addr=0x%llx\n" "offset_plane1=%d\n" + "offset_plane2=%d\n" + "afbc_header_addr=0x%llx\n" + "afbc_payload_addr=0x%llx\n" + "afbc_header_stride=%d\n" + "afbc_payload_stride=%d\n" + "afbc_scramble_mode=%d\n" + "mmbuf_base=0x%x\n" "mmbuf_size=%d\n" + "mmu_enable=%d\n" "csc_mode=%d\n" + "secure_mode=%d\n" "shared_fd=%d\n" + "src_rect(%d,%d, %d,%d)\n" + "src_rect_mask(%d,%d, %d,%d)\n" + "dst_rect(%d,%d, %d,%d)\n" "transform=%d\n" + "blending=%d\n" "glb_alpha=0x%x\n" + "color=0x%x\n" "layer_idx=%d\n" + "chn_idx=%d\n" "need_cap=0x%x\n" + "acquire_fence=%d\n", k, layer->img.format, + layer->img.width, layer->img.height, + layer->img.bpp, layer->img.buf_size, + layer->img.stride, + layer->img.stride_plane1, + layer->img.stride_plane2, + layer->img.phy_addr, layer->img.vir_addr, + layer->img.offset_plane1, + layer->img.offset_plane2, + layer->img.afbc_header_addr, + layer->img.afbc_payload_addr, + layer->img.afbc_header_stride, + layer->img.afbc_payload_stride, + layer->img.afbc_scramble_mode, + layer->img.mmbuf_base, + layer->img.mmbuf_size, + layer->img.mmu_enable, layer->img.csc_mode, + layer->img.secure_mode, + layer->img.shared_fd, layer->src_rect.x, + layer->src_rect.y, layer->src_rect.w, + layer->src_rect.h, layer->src_rect_mask.x, + layer->src_rect_mask.y, + layer->src_rect_mask.w, + layer->src_rect_mask.h, layer->dst_rect.x, + layer->dst_rect.y, layer->dst_rect.w, + layer->dst_rect.h, layer->transform, + layer->blending, layer->glb_alpha, + layer->color, layer->layer_idx, + layer->chn_idx, layer->need_cap, + layer->acquire_fence); + + + if (isNeedSaveFile) { + if (layer->dst_rect.y < + pov_block_info->ov_block_rect.y) + continue; + + dumpDss->scene_buf_len += + snprintf(dumpDss->scene_buf + + dumpDss->scene_buf_len, SZ_1K, + "[BaseColor]=0x%x\n" + "[ScreenSize]=(%u,%u)\n\n" + "[BlendMode]=%d\n" "[Caption]=\n" + "[Channel]=%u\n" + "[CropLoc]=(%u,%u)\n" + "[CropSize]=(%u,%u)\n" + "[FlipHV]=(%u,%u)\n" + "[Format]=%s\n" + "[GlobalAlpha]=%u\n", + hisifd->dss_module.ov[pov_req-> + ovl_idx]. + ovl_bg_color, + get_panel_xres(hisifd), + get_panel_yres(hisifd), + layer->blending, layer->chn_idx, 0, + 0, layer->src_rect.w, + layer->src_rect.h, + (layer-> + transform & + HISI_FB_TRANSFORM_FLIP_H), + (layer-> + transform & + HISI_FB_TRANSFORM_FLIP_V), + layer_format[layer->img.format], + layer->glb_alpha); + + if (layer->need_cap & (CAP_DIM | CAP_PURE_COLOR | + CAP_BASE)) { + if (layer->need_cap & CAP_BASE) { + dumpDss->scene_buf_len += + snprintf(dumpDss->scene_buf + + dumpDss->scene_buf_len, + SZ_1K, + "[BaseColor]=0x%x\n", + layer->color); + } else if (layer->need_cap & CAP_PURE_COLOR) { + dumpDss->scene_buf_len += + snprintf(dumpDss->scene_buf + + dumpDss->scene_buf_len, + SZ_1K, + "[Color]=0x%x\n", + layer->color); + } + } else { + dumpDss->scene_buf_len += + snprintf(dumpDss->scene_buf + + dumpDss->scene_buf_len, + SZ_1K, + "[ImageSource]=pic%d_%ld.bin\n", + k, tv.tv_sec); + } + + dumpDss->scene_buf_len += + snprintf(dumpDss->scene_buf + + dumpDss->scene_buf_len, SZ_1K, + "[Location]=(%u,%u)\n" + "[Rotate]=%u\n" "[Scale]=(%u,%u)\n" + "[Size]=(%u,%u)\n\n", + layer->dst_rect.x, + layer->dst_rect.y, + hisi_transform2degree(layer->transform), + layer->dst_rect.w, + layer->dst_rect.h, + layer->dst_rect.w, + layer->dst_rect.h); + + + if (layer->need_cap & (CAP_DIM | CAP_PURE_COLOR | + CAP_BASE)) + continue; + + if (layer->img.shared_fd < 0) + continue; + + ionhnd = + ion_import_dma_buf(hisifd->ion_client, + layer->img.shared_fd); + if (IS_ERR(ionhnd)) { + HISI_FB_ERR + ("ion import dma buf err, ionclient %p, share_fd %d, layer index %d", + hisifd->ion_client, + layer->img.shared_fd, i); + continue; + } + + snprintf(dumpDss->image_bin_filename[k], + sizeof(dumpDss->image_bin_filename[k]), + "/data/dssdump/pic%d_%ld.bin", k, + tv.tv_sec); + + image_src_addr = + ion_map_kernel(hisifd->ion_client, ionhnd); + if (image_src_addr) { + hisifb_save_file(dumpDss->image_bin_filename[k], + image_src_addr, + layer->img.buf_size); + ion_unmap_kernel(hisifd->ion_client, ionhnd); + } + + ion_free(hisifd->ion_client, ionhnd); + ionhnd = NULL; + } + } + } + + for (k = 0; k < pov_req->wb_layer_nums; k++) { + wb_layer = &(pov_req->wb_layer_infos[k]); + + dumpDss->dss_buf_len += + snprintf(dumpDss->dss_buf + dumpDss->dss_buf_len, 4 * SZ_1K, + "\nWbLayerInfo[%d]:\n" "format=%d\n" "width=%d\n" + "height=%d\n" "bpp=%d\n" "buf_size=%d\n" + "stride=%d\n" "stride_plane1=%d\n" + "stride_plane2=%d\n" "phy_addr=0x%llx\n" + "vir_addr=0x%llx\n" "offset_plane1=%d\n" + "offset_plane2=%d\n" "afbc_header_addr=0x%llx\n" + "afbc_payload_addr=0x%llx\n" + "afbc_header_stride=%d\n" + "afbc_payload_stride=%d\n" + "afbc_scramble_mode=%d\n" "mmbuf_base=0x%x\n" + "mmbuf_size=%d\n" "mmu_enable=%d\n" "csc_mode=%d\n" + "secure_mode=%d\n" "shared_fd=%d\n" + "src_rect(%d,%d, %d,%d)\n" + "dst_rect(%d,%d, %d,%d)\n" "transform=%d\n" + "chn_idx=%d\n" "need_cap=0x%x\n" + "acquire_fence=%d\n" "release_fence=%d\n", k, + wb_layer->dst.format, wb_layer->dst.width, + wb_layer->dst.height, wb_layer->dst.bpp, + wb_layer->dst.buf_size, wb_layer->dst.stride, + wb_layer->dst.stride_plane1, + wb_layer->dst.stride_plane2, + wb_layer->dst.phy_addr, wb_layer->dst.vir_addr, + wb_layer->dst.offset_plane1, + wb_layer->dst.offset_plane2, + wb_layer->dst.afbc_header_addr, + wb_layer->dst.afbc_payload_addr, + wb_layer->dst.afbc_header_stride, + wb_layer->dst.afbc_payload_stride, + wb_layer->dst.afbc_scramble_mode, + wb_layer->dst.mmbuf_base, wb_layer->dst.mmbuf_size, + wb_layer->dst.mmu_enable, wb_layer->dst.csc_mode, + wb_layer->dst.secure_mode, wb_layer->dst.shared_fd, + wb_layer->src_rect.x, wb_layer->src_rect.y, + wb_layer->src_rect.w, wb_layer->src_rect.h, + wb_layer->dst_rect.x, wb_layer->dst_rect.y, + wb_layer->dst_rect.w, wb_layer->dst_rect.h, + wb_layer->transform, wb_layer->chn_idx, + wb_layer->need_cap, wb_layer->acquire_fence, + wb_layer->release_fence); + } + + dumpDss->dss_buf_len += + snprintf(dumpDss->dss_buf + dumpDss->dss_buf_len, 4 * SZ_1K, + "--------------------------------------------------------\n\n"); + + for (k = 0; k < dumpDss->dss_buf_len; k += 255) { + printk("%.255s", dumpDss->dss_buf + k); + } + + if (isNeedSaveFile) { + if (dumpDss->scene_buf) + hisifb_save_file(dumpDss->scene_filename, + dumpDss->scene_buf, + dumpDss->scene_buf_len); + + if (dumpDss->dss_buf) + hisifb_save_file(dumpDss->dss_filename, + dumpDss->dss_buf, + dumpDss->dss_buf_len); + } + + if (dumpDss->dss_buf) { + kfree(dumpDss->dss_buf); + dumpDss->dss_buf = NULL; + dumpDss->dss_buf_len = 0; + } + + alloc_dss_buf_err: + if (dumpDss->scene_buf) { + kfree(dumpDss->scene_buf); + dumpDss->scene_buf = NULL; + dumpDss->scene_buf_len = 0; + } + + alloc_scene_buf_err: + if (dumpDss) { + kfree(dumpDss); + dumpDss = NULL; + } + + alloc_dump_dss_data_err: + return; +} + +static int hisi_dss_lcd_refresh_direction_layer(struct hisi_fb_data_type + *hisifd, + dss_overlay_t *pov_req, + dss_layer_t *layer) +{ + struct hisi_panel_info *pinfo = NULL; + int ret = 0; + + BUG_ON(hisifd == NULL); + BUG_ON(pov_req == NULL); + BUG_ON(layer == NULL); + + pinfo = &(hisifd->panel_info); + + if ((pov_req->ovl_idx != DSS_OVL0) && (pov_req->ovl_idx != DSS_OVL1)) + return 0; + + if (pinfo->lcd_refresh_direction_ctrl == LCD_REFRESH_LEFT_TOP) { + ; + } else if (pinfo->lcd_refresh_direction_ctrl == LCD_REFRESH_RIGHT_TOP) { + switch (layer->transform) { + case HISI_FB_TRANSFORM_NOP: + layer->transform = HISI_FB_TRANSFORM_FLIP_H; + break; + case HISI_FB_TRANSFORM_FLIP_H: + layer->transform = HISI_FB_TRANSFORM_NOP; + break; + case HISI_FB_TRANSFORM_FLIP_V: + layer->transform = HISI_FB_TRANSFORM_ROT_180; + break; + case HISI_FB_TRANSFORM_ROT_90: + layer->transform = + (HISI_FB_TRANSFORM_ROT_90 | + HISI_FB_TRANSFORM_FLIP_H); + break; + case HISI_FB_TRANSFORM_ROT_180: + layer->transform = HISI_FB_TRANSFORM_FLIP_V; + break; + case HISI_FB_TRANSFORM_ROT_270: + layer->transform = + (HISI_FB_TRANSFORM_ROT_90 | + HISI_FB_TRANSFORM_FLIP_V); + break; + + case (HISI_FB_TRANSFORM_ROT_90 | HISI_FB_TRANSFORM_FLIP_H): + layer->transform = HISI_FB_TRANSFORM_ROT_90; + break; + case (HISI_FB_TRANSFORM_ROT_90 | HISI_FB_TRANSFORM_FLIP_V): + layer->transform = HISI_FB_TRANSFORM_ROT_270; + break; + + default: + HISI_FB_ERR("not support this transform(%d).\n", + layer->transform); + ret = -1; + break; + } + + if (ret == 0) { + if ((pinfo->dirty_region_updt_support == 1) && + (pov_req->dirty_rect.w > 0) && + (pov_req->dirty_rect.h > 0)) { + layer->dst_rect.x = + (pov_req->dirty_rect.w - + (layer->dst_rect.x + layer->dst_rect.w)); + } else { + layer->dst_rect.x = + (get_panel_xres(hisifd) - + (layer->dst_rect.x + layer->dst_rect.w)); + } + } + } else if (pinfo->lcd_refresh_direction_ctrl == LCD_REFRESH_LEFT_BOTTOM) { + switch (layer->transform) { + case HISI_FB_TRANSFORM_NOP: + layer->transform = HISI_FB_TRANSFORM_FLIP_V; + break; + case HISI_FB_TRANSFORM_FLIP_H: + layer->transform = HISI_FB_TRANSFORM_ROT_180; + break; + case HISI_FB_TRANSFORM_FLIP_V: + layer->transform = HISI_FB_TRANSFORM_NOP; + break; + case HISI_FB_TRANSFORM_ROT_90: + layer->transform = + (HISI_FB_TRANSFORM_ROT_90 | + HISI_FB_TRANSFORM_FLIP_V); + break; + case HISI_FB_TRANSFORM_ROT_180: + layer->transform = HISI_FB_TRANSFORM_FLIP_H; + break; + case HISI_FB_TRANSFORM_ROT_270: + layer->transform = + (HISI_FB_TRANSFORM_ROT_90 | + HISI_FB_TRANSFORM_FLIP_H); + break; + + case (HISI_FB_TRANSFORM_ROT_90 | HISI_FB_TRANSFORM_FLIP_H): + layer->transform = HISI_FB_TRANSFORM_ROT_270; + break; + case (HISI_FB_TRANSFORM_ROT_90 | HISI_FB_TRANSFORM_FLIP_V): + layer->transform = HISI_FB_TRANSFORM_ROT_90; + break; + + default: + HISI_FB_ERR("not support this transform(%d).\n", + layer->transform); + ret = -1; + break; + } + + if (ret == 0) { + if ((pinfo->dirty_region_updt_support == 1) && + (pov_req->dirty_rect.w > 0) && + (pov_req->dirty_rect.h > 0)) { + layer->dst_rect.y = + (pov_req->dirty_rect.h - + (layer->dst_rect.y + layer->dst_rect.h)); + } else { + layer->dst_rect.y = + (get_panel_yres(hisifd) - + (layer->dst_rect.y + layer->dst_rect.h)); + } + } + } else if (pinfo->lcd_refresh_direction_ctrl == + LCD_REFRESH_RIGHT_BOTTOM) { + switch (layer->transform) { + case HISI_FB_TRANSFORM_NOP: + layer->transform = HISI_FB_TRANSFORM_ROT_180; + break; + case HISI_FB_TRANSFORM_FLIP_H: + layer->transform = HISI_FB_TRANSFORM_FLIP_V; + break; + case HISI_FB_TRANSFORM_FLIP_V: + layer->transform = HISI_FB_TRANSFORM_FLIP_H; + break; + case HISI_FB_TRANSFORM_ROT_90: + layer->transform = HISI_FB_TRANSFORM_ROT_270; + break; + case HISI_FB_TRANSFORM_ROT_180: + layer->transform = HISI_FB_TRANSFORM_NOP; + break; + case HISI_FB_TRANSFORM_ROT_270: + layer->transform = HISI_FB_TRANSFORM_ROT_90; + break; + + case (HISI_FB_TRANSFORM_ROT_90 | HISI_FB_TRANSFORM_FLIP_H): + layer->transform = + (HISI_FB_TRANSFORM_ROT_90 | + HISI_FB_TRANSFORM_FLIP_V); + break; + case (HISI_FB_TRANSFORM_ROT_90 | HISI_FB_TRANSFORM_FLIP_V): + layer->transform = + (HISI_FB_TRANSFORM_ROT_90 | + HISI_FB_TRANSFORM_FLIP_H); + break; + + default: + HISI_FB_ERR("not support this transform(%d).\n", + layer->transform); + ret = -1; + break; + } + + if (ret == 0) { + if ((pinfo->dirty_region_updt_support == 1) && + (pov_req->dirty_rect.w > 0) && + (pov_req->dirty_rect.h > 0)) { + layer->dst_rect.x = + (pov_req->dirty_rect.w - + (layer->dst_rect.x + layer->dst_rect.w)); + layer->dst_rect.y = + (pov_req->dirty_rect.h - + (layer->dst_rect.y + layer->dst_rect.h)); + } else { + layer->dst_rect.x = + (get_panel_xres(hisifd) - + (layer->dst_rect.x + layer->dst_rect.w)); + layer->dst_rect.y = + (get_panel_yres(hisifd) - + (layer->dst_rect.y + layer->dst_rect.h)); + } + } + } else { + HISI_FB_ERR + ("fb%d, not support this lcd_refresh_direction_ctrl(%d)!\n", + hisifd->index, pinfo->lcd_refresh_direction_ctrl); + ret = -1; + } + + return ret; +} + +static int hisi_dss_lcd_refresh_direction_dirty_region(struct hisi_fb_data_type + *hisifd, + dss_overlay_t *pov_req) +{ + struct hisi_panel_info *pinfo = NULL; + int ret = 0; + + BUG_ON(hisifd == NULL); + BUG_ON(pov_req == NULL); + + pinfo = &(hisifd->panel_info); + if ((pov_req->ovl_idx != DSS_OVL0) && (pov_req->ovl_idx != DSS_OVL1)) + return 0; + + if (pinfo->lcd_refresh_direction_ctrl == LCD_REFRESH_LEFT_TOP) { + ; + } else if (pinfo->lcd_refresh_direction_ctrl == LCD_REFRESH_RIGHT_TOP) { + if (pinfo->dirty_region_updt_support == 1) { + pov_req->dirty_rect.x = + (get_panel_xres(hisifd) - + (pov_req->dirty_rect.x + pov_req->dirty_rect.w)); + } + } else if (pinfo->lcd_refresh_direction_ctrl == LCD_REFRESH_LEFT_BOTTOM) { + if (pinfo->dirty_region_updt_support == 1) { + pov_req->dirty_rect.y = + (get_panel_yres(hisifd) - + (pov_req->dirty_rect.y + pov_req->dirty_rect.h)); + } + } else if (pinfo->lcd_refresh_direction_ctrl == + LCD_REFRESH_RIGHT_BOTTOM) { + if (pinfo->dirty_region_updt_support == 1) { + pov_req->dirty_rect.x = + (get_panel_xres(hisifd) - + (pov_req->dirty_rect.x + pov_req->dirty_rect.w)); + pov_req->dirty_rect.y = + (get_panel_yres(hisifd) - + (pov_req->dirty_rect.y + pov_req->dirty_rect.h)); + } + } else { + HISI_FB_ERR + ("fb%d, not support this lcd_refresh_direction_ctrl(%d)!\n", + hisifd->index, pinfo->lcd_refresh_direction_ctrl); + ret = -1; + } + + return ret; +} + +int hisi_dss_handle_cur_ovl_req(struct hisi_fb_data_type *hisifd, + dss_overlay_t *pov_req) +{ + struct hisi_panel_info *pinfo = NULL; + dss_overlay_block_t *pov_h_block_infos = NULL; + dss_overlay_block_t *pov_h_block = NULL; + dss_layer_t *layer = NULL; + int i = 0; + int m = 0; + + BUG_ON(hisifd == NULL); + BUG_ON(pov_req == NULL); + pinfo = &(hisifd->panel_info); + + hisifd->resolution_rect = pov_req->res_updt_rect; + + pov_h_block_infos = + (dss_overlay_block_t *) (pov_req->ov_block_infos_ptr); + for (m = 0; m < pov_req->ov_block_nums; m++) { + pov_h_block = &(pov_h_block_infos[m]); + + for (i = 0; i < pov_h_block->layer_nums; i++) { + layer = &(pov_h_block->layer_infos[i]); + + hisi_dss_lcd_refresh_direction_layer(hisifd, pov_req, + layer); + } + } + hisi_dss_lcd_refresh_direction_dirty_region(hisifd, pov_req); + + return 0; +} + +/******************************************************************************* + ** + */ +int hisi_get_hal_format(struct fb_info *info) +{ + struct fb_var_screeninfo *var = NULL; + int hal_format = 0; + + BUG_ON(info == NULL); + var = &info->var; + + switch (var->bits_per_pixel) { + case 16: + if (var->blue.offset == 0) { + if (var->red.offset == 8) { + hal_format = (var->transp.offset == 12) ? + HISI_FB_PIXEL_FORMAT_BGRA_4444 : + HISI_FB_PIXEL_FORMAT_BGRX_4444; + } else if (var->red.offset == 10) { + hal_format = (var->transp.offset == 12) ? + HISI_FB_PIXEL_FORMAT_BGRA_5551 : + HISI_FB_PIXEL_FORMAT_BGRX_5551; + } else if (var->red.offset == 11) { + hal_format = HISI_FB_PIXEL_FORMAT_RGB_565; + } + } + break; + + case 32: + if (var->blue.offset == 0) { + /* BUGFIX: Modified for Standard Android Format */ + /* hal_format = (var->transp.length == 8) ? + HISI_FB_PIXEL_FORMAT_BGRA_8888 : HISI_FB_PIXEL_FORMAT_BGRX_8888; */ + hal_format = (var->transp.length == 8) ? + HISI_FB_PIXEL_FORMAT_RGBA_8888 : + HISI_FB_PIXEL_FORMAT_RGBX_8888; + } else { + hal_format = (var->transp.length == 8) ? + HISI_FB_PIXEL_FORMAT_RGBA_8888 : + HISI_FB_PIXEL_FORMAT_RGBX_8888; + } + break; + + default: + goto err_return; + } + + return hal_format; + + err_return: + HISI_FB_ERR("not support this bits_per_pixel(%d)!\n", + var->bits_per_pixel); + return -1; +} + +static bool hal_format_has_alpha(uint32_t format) +{ + switch (format) { + case HISI_FB_PIXEL_FORMAT_RGBA_4444: + case HISI_FB_PIXEL_FORMAT_RGBA_5551: + case HISI_FB_PIXEL_FORMAT_RGBA_8888: + + case HISI_FB_PIXEL_FORMAT_BGRA_4444: + case HISI_FB_PIXEL_FORMAT_BGRA_5551: + case HISI_FB_PIXEL_FORMAT_BGRA_8888: + return true; + + default: + return false; + } +} + +bool isYUVPackage(uint32_t format) +{ + switch (format) { + case HISI_FB_PIXEL_FORMAT_YUV_422_I: + case HISI_FB_PIXEL_FORMAT_YUYV_422_Pkg: + case HISI_FB_PIXEL_FORMAT_YVYU_422_Pkg: + case HISI_FB_PIXEL_FORMAT_UYVY_422_Pkg: + case HISI_FB_PIXEL_FORMAT_VYUY_422_Pkg: + return true; + + default: + return false; + } +} + +bool isYUVSemiPlanar(uint32_t format) +{ + switch (format) { + case HISI_FB_PIXEL_FORMAT_YCbCr_422_SP: + case HISI_FB_PIXEL_FORMAT_YCrCb_422_SP: + case HISI_FB_PIXEL_FORMAT_YCbCr_420_SP: + case HISI_FB_PIXEL_FORMAT_YCrCb_420_SP: + return true; + + default: + return false; + } +} + +bool isYUVPlanar(uint32_t format) +{ + switch (format) { + case HISI_FB_PIXEL_FORMAT_YCbCr_422_P: + case HISI_FB_PIXEL_FORMAT_YCrCb_422_P: + case HISI_FB_PIXEL_FORMAT_YCbCr_420_P: + case HISI_FB_PIXEL_FORMAT_YCrCb_420_P: + return true; + + default: + return false; + } +} + +bool isYUV(uint32_t format) +{ + return isYUVPackage(format) || + isYUVSemiPlanar(format) || isYUVPlanar(format); +} + +bool is_YUV_SP_420(uint32_t format) +{ + switch (format) { + case HISI_FB_PIXEL_FORMAT_YCbCr_420_SP: + case HISI_FB_PIXEL_FORMAT_YCrCb_420_SP: + return true; + + default: + return false; + } +} + +bool is_YUV_SP_422(uint32_t format) +{ + switch (format) { + case HISI_FB_PIXEL_FORMAT_YCbCr_422_SP: + case HISI_FB_PIXEL_FORMAT_YCrCb_422_SP: + return true; + + default: + return false; + } +} + +bool is_YUV_P_420(uint32_t format) +{ + switch (format) { + case HISI_FB_PIXEL_FORMAT_YCbCr_420_P: + case HISI_FB_PIXEL_FORMAT_YCrCb_420_P: + return true; + + default: + return false; + } +} + +bool is_YUV_P_422(uint32_t format) +{ + switch (format) { + case HISI_FB_PIXEL_FORMAT_YCbCr_422_P: + case HISI_FB_PIXEL_FORMAT_YCrCb_422_P: + return true; + + default: + return false; + } +} + +bool is_RGBX(uint32_t format) +{ + switch (format) { + case HISI_FB_PIXEL_FORMAT_RGBX_4444: + case HISI_FB_PIXEL_FORMAT_BGRX_4444: + case HISI_FB_PIXEL_FORMAT_RGBX_5551: + case HISI_FB_PIXEL_FORMAT_BGRX_5551: + case HISI_FB_PIXEL_FORMAT_RGBX_8888: + case HISI_FB_PIXEL_FORMAT_BGRX_8888: + return true; + + default: + return false; + } +} + +bool isNeedDither(int fmt) +{ + return (fmt == DFC_PIXEL_FORMAT_RGB_565) || + (fmt == DFC_PIXEL_FORMAT_BGR_565); +} + +static bool isNeedRectClip(dss_rect_ltrb_t clip_rect) +{ + return ((clip_rect.left > 0) || (clip_rect.top > 0) || + (clip_rect.right > 0) || (clip_rect.bottom > 0)); +} + +static bool isSrcRectMasked(dss_layer_t *layer, int aligned_pixel) +{ + BUG_ON(layer == NULL); + + return ((layer->src_rect_mask.w != 0) && + (layer->src_rect_mask.h != 0) && + (ALIGN_DOWN + (layer->src_rect_mask.x + layer->src_rect_mask.w, + aligned_pixel) > 1)); +} + +static uint32_t isNeedRdmaStretchBlt(struct hisi_fb_data_type *hisifd, + dss_layer_t *layer) +{ + uint32_t v_stretch_ratio_threshold = 0; + uint32_t v_stretch_ratio = 0; + + BUG_ON(layer == NULL); + + if (layer->need_cap & CAP_AFBCD) { +#if 0 + v_stretch_ratio = layer->src_rect.h / layer->dst_rect.h; + if (v_stretch_ratio < 2) + v_stretch_ratio = 0; +#else + v_stretch_ratio = 0; +#endif + } else { + if (is_YUV_SP_420(layer->img.format) + || is_YUV_P_420(layer->img.format)) { + v_stretch_ratio_threshold = + ((layer->src_rect.h + layer->dst_rect.h - + 1) / layer->dst_rect.h); + v_stretch_ratio = + ((layer->src_rect.h / layer->dst_rect.h) / 2) * 2; + } else { + v_stretch_ratio_threshold = + ((layer->src_rect.h + layer->dst_rect.h - + 1) / layer->dst_rect.h); + v_stretch_ratio = + (layer->src_rect.h / layer->dst_rect.h); + } + + if (v_stretch_ratio_threshold <= g_rdma_stretch_threshold) + v_stretch_ratio = 0; + } + + return v_stretch_ratio; +} + +static int hisi_adjust_clip_rect(dss_layer_t *layer, + dss_rect_ltrb_t *clip_rect) +{ + int ret = 0; + uint32_t temp = 0; + + BUG_ON(layer == NULL); + BUG_ON(clip_rect == NULL); + + if ((clip_rect->left < 0 || clip_rect->left > DFC_MAX_CLIP_NUM) || + (clip_rect->right < 0 || clip_rect->right > DFC_MAX_CLIP_NUM) || + (clip_rect->top < 0 || clip_rect->top > DFC_MAX_CLIP_NUM) || + (clip_rect->bottom < 0 || clip_rect->bottom > DFC_MAX_CLIP_NUM)) { + return -EINVAL; + } + + switch (layer->transform) { + case HISI_FB_TRANSFORM_NOP: + + break; + case HISI_FB_TRANSFORM_FLIP_H: + { + temp = clip_rect->left; + clip_rect->left = clip_rect->right; + clip_rect->right = temp; + } + break; + case HISI_FB_TRANSFORM_FLIP_V: + { + temp = clip_rect->top; + clip_rect->top = clip_rect->bottom; + clip_rect->bottom = temp; + } + break; + case HISI_FB_TRANSFORM_ROT_180: + { + temp = clip_rect->left; + clip_rect->left = clip_rect->right; + clip_rect->right = temp; + + temp = clip_rect->top; + clip_rect->top = clip_rect->bottom; + clip_rect->bottom = temp; + } + break; + default: + HISI_FB_ERR("not supported this transform(%d)!", + layer->transform); + break; + } + + return ret; +} + +static int hisi_pixel_format_hal2dma(int format) +{ + int ret = 0; + + switch (format) { + case HISI_FB_PIXEL_FORMAT_RGB_565: + case HISI_FB_PIXEL_FORMAT_BGR_565: + ret = DMA_PIXEL_FORMAT_RGB_565; + break; + case HISI_FB_PIXEL_FORMAT_RGBX_4444: + case HISI_FB_PIXEL_FORMAT_BGRX_4444: + ret = DMA_PIXEL_FORMAT_XRGB_4444; + break; + case HISI_FB_PIXEL_FORMAT_RGBA_4444: + case HISI_FB_PIXEL_FORMAT_BGRA_4444: + ret = DMA_PIXEL_FORMAT_ARGB_4444; + break; + case HISI_FB_PIXEL_FORMAT_RGBX_5551: + case HISI_FB_PIXEL_FORMAT_BGRX_5551: + ret = DMA_PIXEL_FORMAT_XRGB_5551; + break; + case HISI_FB_PIXEL_FORMAT_RGBA_5551: + case HISI_FB_PIXEL_FORMAT_BGRA_5551: + ret = DMA_PIXEL_FORMAT_ARGB_5551; + break; + + case HISI_FB_PIXEL_FORMAT_RGBX_8888: + case HISI_FB_PIXEL_FORMAT_BGRX_8888: + ret = DMA_PIXEL_FORMAT_XRGB_8888; + break; + case HISI_FB_PIXEL_FORMAT_RGBA_8888: + case HISI_FB_PIXEL_FORMAT_BGRA_8888: + ret = DMA_PIXEL_FORMAT_ARGB_8888; + break; + + case HISI_FB_PIXEL_FORMAT_YUV_422_I: + case HISI_FB_PIXEL_FORMAT_YUYV_422_Pkg: + case HISI_FB_PIXEL_FORMAT_YVYU_422_Pkg: + case HISI_FB_PIXEL_FORMAT_UYVY_422_Pkg: + case HISI_FB_PIXEL_FORMAT_VYUY_422_Pkg: + ret = DMA_PIXEL_FORMAT_YUYV_422_Pkg; + break; + + case HISI_FB_PIXEL_FORMAT_YCbCr_422_P: + case HISI_FB_PIXEL_FORMAT_YCrCb_422_P: + ret = DMA_PIXEL_FORMAT_YUV_422_P_HP; + break; + case HISI_FB_PIXEL_FORMAT_YCbCr_420_P: + case HISI_FB_PIXEL_FORMAT_YCrCb_420_P: + ret = DMA_PIXEL_FORMAT_YUV_420_P_HP; + break; + + case HISI_FB_PIXEL_FORMAT_YCbCr_422_SP: + case HISI_FB_PIXEL_FORMAT_YCrCb_422_SP: + ret = DMA_PIXEL_FORMAT_YUV_422_SP_HP; + break; + case HISI_FB_PIXEL_FORMAT_YCbCr_420_SP: + case HISI_FB_PIXEL_FORMAT_YCrCb_420_SP: + ret = DMA_PIXEL_FORMAT_YUV_420_SP_HP; + break; + + default: + HISI_FB_ERR("not support format(%d)!\n", format); + ret = -1; + break; + } + + return ret; +} + +static int hisi_transform_hal2dma(int transform, int chn_idx) +{ + int ret = 0; + + if (chn_idx < DSS_WCHN_W0 || chn_idx == DSS_RCHN_V2) { + switch (transform) { + case HISI_FB_TRANSFORM_NOP: + ret = DSS_TRANSFORM_NOP; + break; + case HISI_FB_TRANSFORM_FLIP_H: + ret = DSS_TRANSFORM_FLIP_H; + break; + case HISI_FB_TRANSFORM_FLIP_V: + ret = DSS_TRANSFORM_FLIP_V; + break; + case HISI_FB_TRANSFORM_ROT_180: + ret = DSS_TRANSFORM_FLIP_V | DSS_TRANSFORM_FLIP_H; + break; + default: + ret = -1; + HISI_FB_ERR("Transform %d is not supported", transform); + break; + } + } else { + if (transform == HISI_FB_TRANSFORM_NOP) { + ret = DSS_TRANSFORM_NOP; + } else if (transform == + (HISI_FB_TRANSFORM_ROT_90 | + HISI_FB_TRANSFORM_FLIP_V)) { + ret = DSS_TRANSFORM_ROT; + } else { + ret = -1; + HISI_FB_ERR("Transform %d is not supported", transform); + } + } + + return ret; +} + +static int hisi_pixel_format_hal2dfc(int format) +{ + int ret = 0; + + switch (format) { + case HISI_FB_PIXEL_FORMAT_RGB_565: + ret = DFC_PIXEL_FORMAT_RGB_565; + break; + case HISI_FB_PIXEL_FORMAT_RGBX_4444: + ret = DFC_PIXEL_FORMAT_XBGR_4444; + break; + case HISI_FB_PIXEL_FORMAT_RGBA_4444: + ret = DFC_PIXEL_FORMAT_ABGR_4444; + break; + case HISI_FB_PIXEL_FORMAT_RGBX_5551: + ret = DFC_PIXEL_FORMAT_XBGR_5551; + break; + case HISI_FB_PIXEL_FORMAT_RGBA_5551: + ret = DFC_PIXEL_FORMAT_ABGR_5551; + break; + case HISI_FB_PIXEL_FORMAT_RGBX_8888: + ret = DFC_PIXEL_FORMAT_XBGR_8888; + break; + case HISI_FB_PIXEL_FORMAT_RGBA_8888: + ret = DFC_PIXEL_FORMAT_ABGR_8888; + break; + + case HISI_FB_PIXEL_FORMAT_BGR_565: + ret = DFC_PIXEL_FORMAT_BGR_565; + break; + case HISI_FB_PIXEL_FORMAT_BGRX_4444: + ret = DFC_PIXEL_FORMAT_XRGB_4444; + break; + case HISI_FB_PIXEL_FORMAT_BGRA_4444: + ret = DFC_PIXEL_FORMAT_ARGB_4444; + break; + case HISI_FB_PIXEL_FORMAT_BGRX_5551: + ret = DFC_PIXEL_FORMAT_XRGB_5551; + break; + case HISI_FB_PIXEL_FORMAT_BGRA_5551: + ret = DFC_PIXEL_FORMAT_ARGB_5551; + break; + case HISI_FB_PIXEL_FORMAT_BGRX_8888: + ret = DFC_PIXEL_FORMAT_XRGB_8888; + break; + case HISI_FB_PIXEL_FORMAT_BGRA_8888: + ret = DFC_PIXEL_FORMAT_ARGB_8888; + break; + + case HISI_FB_PIXEL_FORMAT_YUV_422_I: + case HISI_FB_PIXEL_FORMAT_YUYV_422_Pkg: + ret = DFC_PIXEL_FORMAT_YUYV422; + break; + case HISI_FB_PIXEL_FORMAT_YVYU_422_Pkg: + ret = DFC_PIXEL_FORMAT_YVYU422; + break; + case HISI_FB_PIXEL_FORMAT_UYVY_422_Pkg: + ret = DFC_PIXEL_FORMAT_UYVY422; + break; + case HISI_FB_PIXEL_FORMAT_VYUY_422_Pkg: + ret = DFC_PIXEL_FORMAT_VYUY422; + break; + + case HISI_FB_PIXEL_FORMAT_YCbCr_422_SP: + ret = DFC_PIXEL_FORMAT_YUYV422; + break; + case HISI_FB_PIXEL_FORMAT_YCrCb_422_SP: + ret = DFC_PIXEL_FORMAT_YVYU422; + break; + case HISI_FB_PIXEL_FORMAT_YCbCr_420_SP: + ret = DFC_PIXEL_FORMAT_YUYV422; + break; + case HISI_FB_PIXEL_FORMAT_YCrCb_420_SP: + ret = DFC_PIXEL_FORMAT_YVYU422; + break; + + case HISI_FB_PIXEL_FORMAT_YCbCr_422_P: + case HISI_FB_PIXEL_FORMAT_YCbCr_420_P: + ret = DFC_PIXEL_FORMAT_YUYV422; + break; + case HISI_FB_PIXEL_FORMAT_YCrCb_422_P: + case HISI_FB_PIXEL_FORMAT_YCrCb_420_P: + ret = DFC_PIXEL_FORMAT_YVYU422; + break; + + default: + HISI_FB_ERR("not support format(%d)!\n", format); + ret = -1; + break; + } + + return ret; +} + +static int hisi_rb_swap(int format) +{ + switch (format) { + case HISI_FB_PIXEL_FORMAT_BGR_565: + case HISI_FB_PIXEL_FORMAT_BGRX_4444: + case HISI_FB_PIXEL_FORMAT_BGRA_4444: + case HISI_FB_PIXEL_FORMAT_BGRX_5551: + case HISI_FB_PIXEL_FORMAT_BGRA_5551: + case HISI_FB_PIXEL_FORMAT_BGRX_8888: + case HISI_FB_PIXEL_FORMAT_BGRA_8888: + return 1; + default: + return 0; + } +} + +static int hisi_uv_swap(int format) +{ + switch (format) { + case HISI_FB_PIXEL_FORMAT_YCrCb_422_SP: + case HISI_FB_PIXEL_FORMAT_YCrCb_420_SP: + case HISI_FB_PIXEL_FORMAT_YCrCb_422_P: + case HISI_FB_PIXEL_FORMAT_YCrCb_420_P: + return 1; + + default: + return 0; + } +} + +static int hisi_dfc_get_bpp(int dfc_format) +{ + int ret = 0; + + switch (dfc_format) { + case DFC_PIXEL_FORMAT_RGB_565: + case DFC_PIXEL_FORMAT_XRGB_4444: + case DFC_PIXEL_FORMAT_ARGB_4444: + case DFC_PIXEL_FORMAT_XRGB_5551: + case DFC_PIXEL_FORMAT_ARGB_5551: + + case DFC_PIXEL_FORMAT_BGR_565: + case DFC_PIXEL_FORMAT_XBGR_4444: + case DFC_PIXEL_FORMAT_ABGR_4444: + case DFC_PIXEL_FORMAT_XBGR_5551: + case DFC_PIXEL_FORMAT_ABGR_5551: + ret = 2; + break; + + case DFC_PIXEL_FORMAT_XRGB_8888: + case DFC_PIXEL_FORMAT_ARGB_8888: + case DFC_PIXEL_FORMAT_XBGR_8888: + case DFC_PIXEL_FORMAT_ABGR_8888: + ret = 4; + break; + + case DFC_PIXEL_FORMAT_YUV444: + case DFC_PIXEL_FORMAT_YVU444: + ret = 3; + break; + + case DFC_PIXEL_FORMAT_YUYV422: + case DFC_PIXEL_FORMAT_YVYU422: + case DFC_PIXEL_FORMAT_VYUY422: + case DFC_PIXEL_FORMAT_UYVY422: + ret = 2; + break; + + default: + HISI_FB_ERR("not support format(%d)!\n", dfc_format); + ret = -1; + break; + } + + return ret; +} + +static uint32_t hisi_calculate_display_addr(bool mmu_enable, + dss_layer_t *layer, + dss_rect_ltrb_t *aligned_rect, + int add_type) +{ + uint32_t addr = 0; + uint32_t src_addr = 0; + uint32_t stride = 0; + uint32_t offset = 0; + int bpp = 0; + int left = 0; + int right = 0; + int top = 0; + int bottom = 0; + + left = aligned_rect->left; + right = aligned_rect->right; + top = aligned_rect->top; + bottom = aligned_rect->bottom; + + if (add_type == DSS_ADDR_PLANE0) { + stride = layer->img.stride; + offset = 0; + src_addr = + mmu_enable ? layer->img.vir_addr : layer->img.phy_addr; + bpp = layer->img.bpp; + } else if (add_type == DSS_ADDR_PLANE1) { + stride = layer->img.stride_plane1; + offset = layer->img.offset_plane1; + src_addr = mmu_enable ? (layer->img.vir_addr + offset) : + (layer->img.phy_addr + offset); + bpp = 1; + + if (is_YUV_P_420(layer->img.format) + || is_YUV_P_422(layer->img.format)) { + left /= 2; + right /= 2; + } + + if (is_YUV_SP_420(layer->img.format) + || is_YUV_P_420(layer->img.format)) { + top /= 2; + bottom /= 2; + } + } else if (add_type == DSS_ADDR_PLANE2) { + stride = layer->img.stride_plane2; + offset = layer->img.offset_plane2; + src_addr = mmu_enable ? (layer->img.vir_addr + offset) : + (layer->img.phy_addr + offset); + bpp = 1; + + if (is_YUV_P_420(layer->img.format) + || is_YUV_P_422(layer->img.format)) { + left /= 2; + right /= 2; + } + + if (is_YUV_SP_420(layer->img.format) + || is_YUV_P_420(layer->img.format)) { + top /= 2; + bottom /= 2; + } + } else { + HISI_FB_ERR("NOT SUPPORT this add_type(%d).\n", add_type); + BUG_ON(1); + } + + switch (layer->transform) { + case HISI_FB_TRANSFORM_NOP: + addr = src_addr + top * stride + left * bpp; + break; + case HISI_FB_TRANSFORM_FLIP_H: + addr = src_addr + top * stride + right * bpp; + break; + case HISI_FB_TRANSFORM_FLIP_V: + addr = src_addr + bottom * stride + left * bpp; + break; + case HISI_FB_TRANSFORM_ROT_180: + addr = src_addr + bottom * stride + right * bpp; + break; + default: + HISI_FB_ERR("not supported this transform(%d)!", + layer->transform); + break; + } + + return addr; +} + +/******************************************************************************* + ** DSS MIF + */ +static void hisi_dss_mif_init(char __iomem *mif_ch_base, + dss_mif_t *s_mif, int chn_idx) +{ + uint32_t rw_type = 0; + + BUG_ON(mif_ch_base == NULL); + BUG_ON(s_mif == NULL); + + memset(s_mif, 0, sizeof(dss_mif_t)); + + s_mif->mif_ctrl1 = 0x00000020; + s_mif->mif_ctrl2 = 0x0; + s_mif->mif_ctrl3 = 0x0; + s_mif->mif_ctrl4 = 0x0; + s_mif->mif_ctrl5 = 0x0; + rw_type = (chn_idx < DSS_WCHN_W0 || chn_idx == DSS_RCHN_V2) ? 0x0 : 0x1; + + s_mif->mif_ctrl1 = set_bits32(s_mif->mif_ctrl1, 0x0, 1, 5); + s_mif->mif_ctrl1 = set_bits32(s_mif->mif_ctrl1, rw_type, 1, 17); +} + +static void hisi_dss_mif_set_reg(struct hisi_fb_data_type *hisifd, + char __iomem *mif_ch_base, dss_mif_t *s_mif, + int chn_idx) +{ + BUG_ON(hisifd == NULL); + BUG_ON(mif_ch_base == NULL); + BUG_ON(s_mif == NULL); + + hisifd->set_reg(hisifd, mif_ch_base + MIF_CTRL1, + s_mif->mif_ctrl1, 32, 0); + hisifd->set_reg(hisifd, mif_ch_base + MIF_CTRL2, + s_mif->mif_ctrl2, 32, 0); + hisifd->set_reg(hisifd, mif_ch_base + MIF_CTRL3, + s_mif->mif_ctrl3, 32, 0); + hisifd->set_reg(hisifd, mif_ch_base + MIF_CTRL4, + s_mif->mif_ctrl4, 32, 0); + hisifd->set_reg(hisifd, mif_ch_base + MIF_CTRL5, + s_mif->mif_ctrl5, 32, 0); +} + +void hisi_dss_mif_on(struct hisi_fb_data_type *hisifd) +{ + char __iomem *mif_base = NULL; + + BUG_ON(hisifd == NULL); + + mif_base = hisifd->dss_base + DSS_MIF_OFFSET; + + set_reg(mif_base + MIF_ENABLE, 0x1, 1, 0); + set_reg(hisifd->dss_base + MIF_CH0_OFFSET + MIF_CTRL0, 0x1, 1, 0); + set_reg(hisifd->dss_base + MIF_CH1_OFFSET + MIF_CTRL0, 0x1, 1, 0); + set_reg(hisifd->dss_base + MIF_CH2_OFFSET + MIF_CTRL0, 0x1, 1, 0); + set_reg(hisifd->dss_base + MIF_CH3_OFFSET + MIF_CTRL0, 0x1, 1, 0); + set_reg(hisifd->dss_base + MIF_CH4_OFFSET + MIF_CTRL0, 0x1, 1, 0); + set_reg(hisifd->dss_base + MIF_CH5_OFFSET + MIF_CTRL0, 0x1, 1, 0); + set_reg(hisifd->dss_base + MIF_CH6_OFFSET + MIF_CTRL0, 0x1, 1, 0); + set_reg(hisifd->dss_base + MIF_CH7_OFFSET + MIF_CTRL0, 0x1, 1, 0); + set_reg(hisifd->dss_base + MIF_CH8_OFFSET + MIF_CTRL0, 0x1, 1, 0); + set_reg(hisifd->dss_base + MIF_CH9_OFFSET + MIF_CTRL0, 0x1, 1, 0); + + set_reg(hisifd->dss_base + MIF_CH10_OFFSET + MIF_CTRL0, 0x1, 1, 0); + set_reg(hisifd->dss_base + MIF_CH11_OFFSET + MIF_CTRL0, 0x1, 1, 0); +} + +int hisi_dss_mif_config(struct hisi_fb_data_type *hisifd, + dss_layer_t *layer, dss_wb_layer_t *wb_layer, + bool rdma_stretch_enable) +{ + dss_mif_t *mif = NULL; + int chn_idx = 0; + dss_img_t *img = NULL; + uint32_t transform = 0; + uint32_t invalid_sel = 0; + uint32_t need_cap = 0; + uint32_t *semi_plane1 = NULL; + int v_scaling_factor = 0; + + BUG_ON(hisifd == NULL); + BUG_ON((layer == NULL) && (wb_layer == NULL)); + + if (wb_layer) { + img = &(wb_layer->dst); + chn_idx = wb_layer->chn_idx; + transform = wb_layer->transform; + need_cap = wb_layer->need_cap; + v_scaling_factor = 1; + } else { + img = &(layer->img); + chn_idx = layer->chn_idx; + transform = layer->transform; + need_cap = layer->need_cap; + v_scaling_factor = + layer->src_rect.h / layer->dst_rect.h + + ((layer->src_rect.h % layer->dst_rect.h) > 0 ? 1 : 0); + } + + mif = &(hisifd->dss_module.mif[chn_idx]); + hisifd->dss_module.mif_used[chn_idx] = 1; + + semi_plane1 = &mif->mif_ctrl4; + + if (img->mmu_enable == 0) { + mif->mif_ctrl1 = set_bits32(mif->mif_ctrl1, 0x1, 1, 5); + } else { + if (need_cap & (CAP_AFBCD | CAP_AFBCE)) { + invalid_sel = 0; + } else { + invalid_sel = + hisi_dss_mif_get_invalid_sel(img, transform, + v_scaling_factor, + ((need_cap & CAP_TILE) + ? 1 : 0), + rdma_stretch_enable); + } + + mif->mif_ctrl1 = set_bits32(mif->mif_ctrl1, 0x0, 1, 5); + mif->mif_ctrl1 = set_bits32(mif->mif_ctrl1, invalid_sel, 2, 10); + mif->mif_ctrl1 = + set_bits32(mif->mif_ctrl1, ((invalid_sel == 0) ? 0x1 : 0x0), + 1, 19); + + if (invalid_sel == 0) { + mif->mif_ctrl2 = set_bits32(mif->mif_ctrl2, 0x0, 20, 0); + mif->mif_ctrl3 = set_bits32(mif->mif_ctrl3, 0x0, 20, 0); + mif->mif_ctrl4 = set_bits32(mif->mif_ctrl4, 0x0, 20, 0); + mif->mif_ctrl5 = set_bits32(mif->mif_ctrl5, 0x0, 20, 0); + } else if ((invalid_sel == 1) || (invalid_sel == 2)) { + if (img->stride > 0) { + mif->mif_ctrl5 = set_bits32(mif->mif_ctrl5, + ((img->stride /MIF_STRIDE_UNIT) + + (((img->stride % MIF_STRIDE_UNIT) > 0) ? + 1 : 0)), 20, 0); + } + + if (isYUVSemiPlanar(img->format)) { + if (img->stride_plane1 > 0) { + *semi_plane1 = set_bits32(*semi_plane1, + ((img->stride_plane1 / MIF_STRIDE_UNIT) + + (((img->stride_plane1 % MIF_STRIDE_UNIT) >0) ? + 1 : 0)), 20, 0); + } + } else if (isYUVPlanar(img->format)) { + if (img->stride_plane1 > 0) { + mif->mif_ctrl4 = + set_bits32(mif->mif_ctrl4, + ((img->stride_plane1 / + MIF_STRIDE_UNIT) + + (((img->stride_plane1 % + MIF_STRIDE_UNIT) > + 0) ? 1 : 0)), 20, 0); + } + + if (img->stride_plane2 > 0) { + mif->mif_ctrl3 = + set_bits32(mif->mif_ctrl3, + ((img->stride_plane2 / + MIF_STRIDE_UNIT) + + (((img->stride_plane2 % + MIF_STRIDE_UNIT) > + 0) ? 1 : 0)), 20, 0); + } + } else { + ; + } + } else if (invalid_sel == 3) { + if (img->stride > 0) { + mif->mif_ctrl5 = + set_bits32(mif->mif_ctrl5, + DSS_MIF_CTRL2_INVAL_SEL3_STRIDE_MASK, 4, 16); + } + if (isYUVSemiPlanar(img->format)) { + if (img->stride_plane1 > 0) + *semi_plane1 = + set_bits32(*semi_plane1, 0xE, 4, 16); + + } else if (isYUVPlanar(img->format)) { + if (img->stride_plane1 > 0) + mif->mif_ctrl3 = + set_bits32(mif->mif_ctrl3, 0xE, 4, 16); + + if (img->stride_plane2 > 0) + mif->mif_ctrl4 = + set_bits32(mif->mif_ctrl4, 0xE, 4, 16); + } else { + ; + } + } else { + HISI_FB_ERR("fb%d, invalid_sel(%d) not support!\n", + hisifd->index, invalid_sel); + } + } + + return 0; +} + +/******************************************************************************* + ** DSS RDMA + */ +static void hisi_dss_rdma_init(char __iomem *dma_base, dss_rdma_t *s_dma) +{ + BUG_ON(dma_base == NULL); + BUG_ON(s_dma == NULL); + + memset(s_dma, 0, sizeof(dss_rdma_t)); + + s_dma->oft_x0 = inp32(dma_base + DMA_OFT_X0); + s_dma->oft_y0 = inp32(dma_base + DMA_OFT_Y0); + s_dma->oft_x1 = inp32(dma_base + DMA_OFT_X1); + s_dma->oft_y1 = inp32(dma_base + DMA_OFT_Y1); + s_dma->mask0 = inp32(dma_base + DMA_MASK0); + s_dma->mask1 = inp32(dma_base + DMA_MASK1); + s_dma->stretch_size_vrt = inp32(dma_base + DMA_STRETCH_SIZE_VRT); + s_dma->ctrl = inp32(dma_base + DMA_CTRL); + s_dma->tile_scram = inp32(dma_base + DMA_TILE_SCRAM); + + s_dma->ch_rd_shadow = inp32(dma_base + CH_RD_SHADOW); + s_dma->ch_ctl = inp32(dma_base + CH_CTL); + + s_dma->data_addr0 = inp32(dma_base + DMA_DATA_ADDR0); + s_dma->stride0 = inp32(dma_base + DMA_STRIDE0); + s_dma->stretch_stride0 = inp32(dma_base + DMA_STRETCH_STRIDE0); + s_dma->data_num0 = inp32(dma_base + DMA_DATA_NUM0); + + s_dma->vpp_ctrl = inp32(dma_base + VPP_CTRL); + s_dma->vpp_mem_ctrl = inp32(dma_base + VPP_MEM_CTRL); + + s_dma->dma_buf_ctrl = inp32(dma_base + DMA_BUF_CTRL); + + s_dma->afbcd_hreg_hdr_ptr_lo = inp32(dma_base + AFBCD_HREG_HDR_PTR_LO); + s_dma->afbcd_hreg_pic_width = inp32(dma_base + AFBCD_HREG_PIC_WIDTH); + s_dma->afbcd_hreg_pic_height = inp32(dma_base + AFBCD_HREG_PIC_HEIGHT); + s_dma->afbcd_hreg_format = inp32(dma_base + AFBCD_HREG_FORMAT); + s_dma->afbcd_ctl = inp32(dma_base + AFBCD_CTL); + s_dma->afbcd_str = inp32(dma_base + AFBCD_STR); + s_dma->afbcd_line_crop = inp32(dma_base + AFBCD_LINE_CROP); + s_dma->afbcd_input_header_stride = + inp32(dma_base + AFBCD_INPUT_HEADER_STRIDE); + s_dma->afbcd_payload_stride = inp32(dma_base + AFBCD_PAYLOAD_STRIDE); + s_dma->afbcd_mm_base_0 = inp32(dma_base + AFBCD_MM_BASE_0); + s_dma->afbcd_afbcd_payload_pointer = + inp32(dma_base + AFBCD_AFBCD_PAYLOAD_POINTER); + s_dma->afbcd_height_bf_str = inp32(dma_base + AFBCD_HEIGHT_BF_STR); + s_dma->afbcd_os_cfg = inp32(dma_base + AFBCD_OS_CFG); + s_dma->afbcd_mem_ctrl = inp32(dma_base + AFBCD_MEM_CTRL); +} + +static void hisi_dss_rdma_u_init(char __iomem *dma_base, dss_rdma_t *s_dma) +{ + BUG_ON(dma_base == NULL); + BUG_ON(s_dma == NULL); + + s_dma->data_addr1 = inp32(dma_base + DMA_DATA_ADDR1); + s_dma->stride1 = inp32(dma_base + DMA_STRIDE1); + s_dma->stretch_stride1 = inp32(dma_base + DMA_STRETCH_STRIDE1); + s_dma->data_num1 = inp32(dma_base + DMA_DATA_NUM1); +} + +static void hisi_dss_rdma_v_init(char __iomem *dma_base, dss_rdma_t *s_dma) +{ + BUG_ON(dma_base == NULL); + BUG_ON(s_dma == NULL); + + s_dma->data_addr2 = inp32(dma_base + DMA_DATA_ADDR2); + s_dma->stride2 = inp32(dma_base + DMA_STRIDE2); + s_dma->stretch_stride2 = inp32(dma_base + DMA_STRETCH_STRIDE2); + s_dma->data_num2 = inp32(dma_base + DMA_DATA_NUM2); +} + +void hisi_dss_chn_set_reg_default_value(struct hisi_fb_data_type *hisifd, + char __iomem *dma_base) +{ + BUG_ON(hisifd == NULL); + BUG_ON(dma_base == NULL); + + hisifd->set_reg(hisifd, dma_base + CH_REG_DEFAULT, 0x1, 32, 0); + hisifd->set_reg(hisifd, dma_base + CH_REG_DEFAULT, 0x0, 32, 0); +} + +static void hisi_dss_rdma_set_reg(struct hisi_fb_data_type *hisifd, + char __iomem *dma_base, dss_rdma_t *s_dma) +{ + BUG_ON(hisifd == NULL); + BUG_ON(dma_base == NULL); + BUG_ON(s_dma == NULL); + + hisifd->set_reg(hisifd, dma_base + CH_REG_DEFAULT, 0x1, 32, 0); + hisifd->set_reg(hisifd, dma_base + CH_REG_DEFAULT, 0x0, 32, 0); + + hisifd->set_reg(hisifd, dma_base + DMA_OFT_X0, s_dma->oft_x0, 32, 0); + hisifd->set_reg(hisifd, dma_base + DMA_OFT_Y0, s_dma->oft_y0, 32, 0); + hisifd->set_reg(hisifd, dma_base + DMA_OFT_X1, s_dma->oft_x1, 32, 0); + hisifd->set_reg(hisifd, dma_base + DMA_OFT_Y1, s_dma->oft_y1, 32, 0); + hisifd->set_reg(hisifd, dma_base + DMA_MASK0, s_dma->mask0, 32, 0); + hisifd->set_reg(hisifd, dma_base + DMA_MASK1, s_dma->mask1, 32, 0); + hisifd->set_reg(hisifd, dma_base + DMA_STRETCH_SIZE_VRT, + s_dma->stretch_size_vrt, 32, 0); + hisifd->set_reg(hisifd, dma_base + DMA_CTRL, s_dma->ctrl, 32, 0); + hisifd->set_reg(hisifd, dma_base + DMA_TILE_SCRAM, s_dma->tile_scram, + 32, 0); + hisifd->set_reg(hisifd, dma_base + DMA_DATA_ADDR0, s_dma->data_addr0, + 32, 0); + hisifd->set_reg(hisifd, dma_base + DMA_STRIDE0, s_dma->stride0, 32, 0); + hisifd->set_reg(hisifd, dma_base + DMA_STRETCH_STRIDE0, + s_dma->stretch_stride0, 32, 0); + + hisifd->set_reg(hisifd, dma_base + CH_RD_SHADOW, s_dma->ch_rd_shadow, + 32, 0); + hisifd->set_reg(hisifd, dma_base + CH_CTL, s_dma->ch_ctl, 32, 0); + + if (s_dma->vpp_used) { + hisifd->set_reg(hisifd, dma_base + VPP_CTRL, s_dma->vpp_ctrl, + 32, 0); + } + + hisifd->set_reg(hisifd, dma_base + DMA_BUF_CTRL, s_dma->dma_buf_ctrl, + 32, 0); + + if (s_dma->afbc_used) { + hisifd->set_reg(hisifd, dma_base + AFBCD_HREG_HDR_PTR_LO, + s_dma->afbcd_hreg_hdr_ptr_lo, 32, 0); + hisifd->set_reg(hisifd, dma_base + AFBCD_HREG_PIC_WIDTH, + s_dma->afbcd_hreg_pic_width, 32, 0); + hisifd->set_reg(hisifd, dma_base + AFBCD_HREG_PIC_HEIGHT, + s_dma->afbcd_hreg_pic_height, 32, 0); + hisifd->set_reg(hisifd, dma_base + AFBCD_HREG_FORMAT, + s_dma->afbcd_hreg_format, 32, 0); + hisifd->set_reg(hisifd, dma_base + AFBCD_CTL, s_dma->afbcd_ctl, + 32, 0); + hisifd->set_reg(hisifd, dma_base + AFBCD_STR, s_dma->afbcd_str, + 32, 0); + hisifd->set_reg(hisifd, dma_base + AFBCD_LINE_CROP, + s_dma->afbcd_line_crop, 32, 0); + hisifd->set_reg(hisifd, dma_base + AFBCD_INPUT_HEADER_STRIDE, + s_dma->afbcd_input_header_stride, 32, 0); + hisifd->set_reg(hisifd, dma_base + AFBCD_PAYLOAD_STRIDE, + s_dma->afbcd_payload_stride, 32, 0); + hisifd->set_reg(hisifd, dma_base + AFBCD_MM_BASE_0, + s_dma->afbcd_mm_base_0, 32, 0); + hisifd->set_reg(hisifd, dma_base + AFBCD_AFBCD_PAYLOAD_POINTER, + s_dma->afbcd_afbcd_payload_pointer, 32, 0); + hisifd->set_reg(hisifd, dma_base + AFBCD_HEIGHT_BF_STR, + s_dma->afbcd_height_bf_str, 32, 0); + hisifd->set_reg(hisifd, dma_base + AFBCD_OS_CFG, + s_dma->afbcd_os_cfg, 32, 0); + hisifd->set_reg(hisifd, dma_base + AFBCD_SCRAMBLE_MODE, + s_dma->afbcd_scramble_mode, 32, 0); + hisifd->set_reg(hisifd, dma_base + AFBCD_HEADER_POINTER_OFFSET, + s_dma->afbcd_header_pointer_offset, 32, 0); + } +} + +static void hisi_dss_rdma_u_set_reg(struct hisi_fb_data_type *hisifd, + char __iomem *dma_base, dss_rdma_t *s_dma) +{ + BUG_ON(hisifd == NULL); + BUG_ON(dma_base == NULL); + BUG_ON(s_dma == NULL); + + hisifd->set_reg(hisifd, dma_base + DMA_DATA_ADDR1, s_dma->data_addr1, + 32, 0); + hisifd->set_reg(hisifd, dma_base + DMA_STRIDE1, s_dma->stride1, 32, 0); + hisifd->set_reg(hisifd, dma_base + DMA_STRETCH_STRIDE1, + s_dma->stretch_stride1, 32, 0); +} + +static void hisi_dss_rdma_v_set_reg(struct hisi_fb_data_type *hisifd, + char __iomem *dma_base, dss_rdma_t *s_dma) +{ + BUG_ON(hisifd == NULL); + BUG_ON(dma_base == NULL); + BUG_ON(s_dma == NULL); + + hisifd->set_reg(hisifd, dma_base + DMA_DATA_ADDR2, s_dma->data_addr2, + 32, 0); + hisifd->set_reg(hisifd, dma_base + DMA_STRIDE2, s_dma->stride2, 32, 0); + hisifd->set_reg(hisifd, dma_base + DMA_STRETCH_STRIDE2, + s_dma->stretch_stride2, 32, 0); +} + +static int hisi_get_rdma_tile_interleave(uint32_t stride) +{ + int i = 0; + uint32_t interleave[MAX_TILE_SURPORT_NUM] = { + 256, 512, 1024, 2048, 4096, 8192, + }; + + for (i = 0; i < MAX_TILE_SURPORT_NUM; i++) { + if (interleave[i] == stride) + return MIN_INTERLEAVE + i; + } + + return 0; +} + +int hisi_dss_rdma_config(struct hisi_fb_data_type *hisifd, int ovl_idx, + dss_layer_t *layer, dss_rect_ltrb_t *clip_rect, + dss_rect_t *out_aligned_rect, + bool *rdma_stretch_enable) +{ + dss_rdma_t *dma = NULL; + + bool mmu_enable = false; + bool is_yuv_semi_planar = false; + bool is_yuv_planar = false; + bool src_rect_mask_enable = false; + + uint32_t rdma_addr = 0; + uint32_t rdma_stride = 0; + int rdma_format = 0; + int rdma_transform = 0; + int rdma_data_num = 0; + uint32_t stretch_size_vrt = 0; + uint32_t stretched_line_num = 0; + uint32_t stretched_stride = 0; + + int bpp = 0; + int aligned_pixel = 0; + int rdma_oft_x0 = 0; + int rdma_oft_y0 = 0; + int rdma_oft_x1 = 0; + int rdma_oft_y1 = 0; + int rdma_mask_x0 = 0; + int rdma_mask_y0 = 0; + int rdma_mask_x1 = 0; + int rdma_mask_y1 = 0; + + int chn_idx = 0; + uint32_t l2t_interleave_n = 0; + dss_rect_ltrb_t aligned_rect = { 0, 0, 0, 0 }; + dss_rect_ltrb_t aligned_mask_rect = { 0, 0, 0, 0 }; + dss_rect_t new_src_rect; + + uint32_t afbcd_half_block_mode = 0; + uint32_t afbcd_stretch_acc = 0; + uint32_t afbcd_stretch_inc = 0; + uint32_t afbcd_height_bf_str = 0; + uint32_t afbcd_top_crop_num = 0; + uint32_t afbcd_bottom_crop_num = 0; + uint32_t afbc_header_addr = 0; + uint32_t afbc_header_stride = 0; + uint32_t afbc_payload_addr = 0; + uint32_t afbc_payload_stride = 0; + uint32_t afbc_header_start_pos = 0; + uint32_t afbc_header_pointer_offset = 0; + uint32_t stride_align = 0; + uint32_t addr_align = 0; + dss_rect_ltrb_t afbc_rect; + uint32_t mm_base_0 = 0; + uint32_t mm_base_1 = 0; + bool mm_alloc_needed = false; + + BUG_ON(hisifd == NULL); + BUG_ON(layer == NULL); + BUG_ON((ovl_idx < DSS_OVL0) || (ovl_idx >= DSS_OVL_IDX_MAX)); + + chn_idx = layer->chn_idx; + new_src_rect = layer->src_rect; + + stretched_line_num = isNeedRdmaStretchBlt(hisifd, layer); + *rdma_stretch_enable = (stretched_line_num > 0) ? true : false; + + mmu_enable = (layer->img.mmu_enable == 1) ? true : false; + is_yuv_semi_planar = isYUVSemiPlanar(layer->img.format); + is_yuv_planar = isYUVPlanar(layer->img.format); + + rdma_format = hisi_pixel_format_hal2dma(layer->img.format); + if (rdma_format < 0) { + HISI_FB_ERR("layer format(%d) not support !\n", + layer->img.format); + return -EINVAL; + } + + rdma_transform = hisi_transform_hal2dma(layer->transform, chn_idx); + if (rdma_transform < 0) { + HISI_FB_ERR("layer transform(%d) not support!\n", + layer->transform); + return -EINVAL; + } + + bpp = (is_yuv_semi_planar || is_yuv_planar) ? 1 : layer->img.bpp; + aligned_pixel = DMA_ALIGN_BYTES / bpp; + + src_rect_mask_enable = isSrcRectMasked(layer, aligned_pixel); + + dma = &(hisifd->dss_module.rdma[chn_idx]); + hisifd->dss_module.dma_used[chn_idx] = 1; + + if (layer->need_cap & CAP_YUV_DEINTERLACE) { + dma->vpp_used = 1; + + if (layer->transform & HISI_FB_TRANSFORM_ROT_90) { + dma->vpp_ctrl = set_bits32(dma->vpp_ctrl, 0x2, 2, 0); + } else { + dma->vpp_ctrl = set_bits32(dma->vpp_ctrl, 0x3, 2, 0); + } + } + + if (layer->need_cap & CAP_AFBCD) { + if ((layer->img.mmbuf_base > 0) && (layer->img.mmbuf_size > 0)) { + mm_base_0 = layer->img.mmbuf_base; + mm_base_1 = + layer->img.mmbuf_base + layer->img.mmbuf_size / 2; + } else { + BUG_ON(hisifd->mmbuf_info == NULL); + + if (ovl_idx <= DSS_OVL1) { + mm_alloc_needed = true; + } else { + if (hisifd->mmbuf_info->mm_used[chn_idx] == 1) + mm_alloc_needed = false; + else + mm_alloc_needed = true; + } + + if (mm_alloc_needed) { + afbc_rect.left = + ALIGN_DOWN(new_src_rect.x, + MMBUF_ADDR_ALIGN); + afbc_rect.right = + ALIGN_UP(new_src_rect.x - afbc_rect.left + + new_src_rect.w, MMBUF_ADDR_ALIGN); + hisifd->mmbuf_info->mm_size[chn_idx] = + afbc_rect.right * layer->img.bpp * + MMBUF_LINE_NUM; + hisifd->mmbuf_info->mm_base[chn_idx] = + hisi_dss_mmbuf_alloc(g_mmbuf_gen_pool, + hisifd->mmbuf_info->mm_size[chn_idx]); + if (hisifd->mmbuf_info->mm_base[chn_idx] < + MMBUF_BASE) { + HISI_FB_ERR + ("fb%d, chn%d failed to alloc mmbuf, mm_base=0x%x.\n", + hisifd->index, chn_idx, + hisifd->mmbuf_info->mm_base[chn_idx]); + return -EINVAL; + } + } + + mm_base_0 = hisifd->mmbuf_info->mm_base[chn_idx]; + mm_base_1 = hisifd->mmbuf_info->mm_base[chn_idx] + + hisifd->mmbuf_info->mm_size[chn_idx] / 2; + hisifd->mmbuf_info->mm_used[chn_idx] = 1; + } + + mm_base_0 -= MMBUF_BASE; + mm_base_1 -= MMBUF_BASE; + + if ((layer->img.width & (AFBC_HEADER_ADDR_ALIGN - 1)) || + (layer->img.height & (AFBC_BLOCK_ALIGN - 1))) { + HISI_FB_ERR + ("layer%d img width(%d) is not %d bytes aligned, or " + "img heigh(%d) is not %d bytes aligned!\n", + layer->layer_idx, layer->img.width, + AFBC_HEADER_ADDR_ALIGN, layer->img.height, + AFBC_BLOCK_ALIGN); + return -EINVAL; + } + + if ((mm_base_0 & (MMBUF_ADDR_ALIGN - 1)) || + (mm_base_1 & (MMBUF_ADDR_ALIGN - 1)) || + (layer->img.mmbuf_size & (MMBUF_ADDR_ALIGN - 1))) { + HISI_FB_ERR + ("layer%d mm_base_0(0x%x) is not %d bytes aligned, or " + "mm_base_1(0x%x) is not %d bytes aligned, or mmbuf_size(0x%x) is " + "not %d bytes aligned!\n", layer->layer_idx, + mm_base_0, MMBUF_ADDR_ALIGN, mm_base_1, + MMBUF_ADDR_ALIGN, layer->img.mmbuf_size, + MMBUF_ADDR_ALIGN); + return -EINVAL; + } + + dma->afbc_used = 1; + + aligned_rect.left = + ALIGN_DOWN(new_src_rect.x, AFBC_BLOCK_ALIGN); + aligned_rect.right = + ALIGN_UP(new_src_rect.x + new_src_rect.w, + AFBC_BLOCK_ALIGN) - 1; + aligned_rect.top = ALIGN_DOWN(new_src_rect.y, AFBC_BLOCK_ALIGN); + aligned_rect.bottom = + ALIGN_UP(new_src_rect.y + new_src_rect.h, + AFBC_BLOCK_ALIGN) - 1; + + out_aligned_rect->x = 0; + out_aligned_rect->y = 0; + out_aligned_rect->w = + aligned_rect.right - aligned_rect.left + 1; + out_aligned_rect->h = + aligned_rect.bottom - aligned_rect.top + 1; + + afbcd_height_bf_str = + aligned_rect.bottom - aligned_rect.top + 1; + + if (*rdma_stretch_enable) { + afbcd_stretch_inc = 0; + afbcd_stretch_acc = 0; + + out_aligned_rect->h /= 2; + if (layer->transform & HISI_FB_TRANSFORM_FLIP_V) { + afbcd_half_block_mode = + AFBC_HALF_BLOCK_LOWER_ONLY; + } else { + afbcd_half_block_mode = + AFBC_HALF_BLOCK_UPPER_ONLY; + } + } else { + if (layer->transform & HISI_FB_TRANSFORM_FLIP_V) { + afbcd_half_block_mode = + AFBC_HALF_BLOCK_LOWER_UPPER_ALL; + } else { + afbcd_half_block_mode = + AFBC_HALF_BLOCK_UPPER_LOWER_ALL; + } + } + + if (layer->img. + afbc_header_addr & (AFBC_SUPER_GRAPH_HEADER_ADDR_ALIGN - + 1)) { + HISI_FB_ERR + ("layer%d super graph afbc_header_addr(0x%x) " + "is not %d bytes aligned!\n", + layer->layer_idx, afbc_header_addr, + AFBC_SUPER_GRAPH_HEADER_ADDR_ALIGN); + return -EINVAL; + } + + clip_rect->left = new_src_rect.x - aligned_rect.left; + clip_rect->right = + aligned_rect.right - DSS_WIDTH(new_src_rect.x + + new_src_rect.w); + clip_rect->top = new_src_rect.y - aligned_rect.top; + clip_rect->bottom = + aligned_rect.bottom - DSS_HEIGHT(new_src_rect.y + + new_src_rect.h); + if (hisi_adjust_clip_rect(layer, clip_rect) < 0) { + HISI_FB_ERR + ("clip rect invalid => layer_idx=%d, chn_idx=%d, " + "clip_rect(%d, %d, %d, %d).\n", + layer->layer_idx, chn_idx, clip_rect->left, + clip_rect->right, clip_rect->top, + clip_rect->bottom); + return -EINVAL; + } + + afbcd_top_crop_num = (clip_rect->top > AFBCD_TOP_CROP_MAX) ? + AFBCD_TOP_CROP_MAX : clip_rect->top; + afbcd_bottom_crop_num = + (clip_rect->bottom > + AFBCD_BOTTOM_CROP_MAX) ? AFBCD_BOTTOM_CROP_MAX : + clip_rect->bottom; + + clip_rect->top -= afbcd_top_crop_num; + BUG_ON(clip_rect->top < 0); + clip_rect->bottom -= afbcd_bottom_crop_num; + BUG_ON(clip_rect->bottom < 0); + + out_aligned_rect->h -= + (afbcd_top_crop_num + afbcd_bottom_crop_num); + + rdma_oft_x0 = aligned_rect.left / aligned_pixel; + rdma_oft_x1 = aligned_rect.right / aligned_pixel; + stretch_size_vrt = DSS_HEIGHT(out_aligned_rect->h); + stretched_line_num = 0; + + afbc_rect = aligned_rect; + afbc_rect.left = + ALIGN_DOWN(new_src_rect.x, AFBC_HEADER_ADDR_ALIGN); + afbc_rect.right = + ALIGN_UP(new_src_rect.x + new_src_rect.w, + AFBC_HEADER_ADDR_ALIGN) - 1; + + afbc_header_stride = + (layer->img.width / AFBC_BLOCK_ALIGN) * + AFBC_HEADER_STRIDE_BLOCK; + afbc_header_pointer_offset = + (afbc_rect.top / AFBC_BLOCK_ALIGN) * afbc_header_stride + + (afbc_rect.left / AFBC_BLOCK_ALIGN) * + AFBC_HEADER_STRIDE_BLOCK; + afbc_header_addr = + layer->img.afbc_header_addr + afbc_header_pointer_offset; + + if ((afbc_header_addr & (AFBC_HEADER_ADDR_ALIGN - 1)) || + (afbc_header_stride & (AFBC_HEADER_STRIDE_ALIGN - 1))) { + HISI_FB_ERR + ("layer%d afbc_header_addr(0x%x) is not %d bytes aligned, or " + "afbc_header_stride(0x%x) is not %d bytes aligned!\n", + layer->layer_idx, afbc_header_addr, + AFBC_HEADER_ADDR_ALIGN, afbc_header_stride, + AFBC_HEADER_STRIDE_ALIGN); + return -EINVAL; + } + + BUG_ON((aligned_rect.left - afbc_rect.left) < 0); + afbc_header_start_pos = + (aligned_rect.left - afbc_rect.left) / AFBC_BLOCK_ALIGN; + + if (layer->img.bpp == 4) { + stride_align = AFBC_PAYLOAD_STRIDE_ALIGN_32; + addr_align = AFBC_PAYLOAD_ADDR_ALIGN_32; + } else if (layer->img.bpp == 2) { + stride_align = AFBC_PAYLOAD_STRIDE_ALIGN_16; + addr_align = AFBC_PAYLOAD_ADDR_ALIGN_16; + } else { + HISI_FB_ERR("bpp(%d) not supported!\n", layer->img.bpp); + return -EINVAL; + } + + afbc_payload_stride = layer->img.afbc_payload_stride; + if (layer->img.afbc_scramble_mode != DSS_AFBC_SCRAMBLE_MODE2) { + afbc_payload_stride = + (layer->img.width / AFBC_BLOCK_ALIGN) * + stride_align; + } + afbc_payload_addr = layer->img.afbc_payload_addr + + (aligned_rect.top / AFBC_BLOCK_ALIGN) * + afbc_payload_stride + + (aligned_rect.left / AFBC_BLOCK_ALIGN) * stride_align; + + if ((afbc_payload_addr & (addr_align - 1)) || + (afbc_payload_stride & (stride_align - 1))) { + HISI_FB_ERR + ("layer%d afbc_payload_addr(0x%x) is not %d bytes aligned, or " + "afbc_payload_stride(0x%x) is not %d bytes aligned!\n", + layer->layer_idx, afbc_payload_addr, addr_align, + afbc_payload_stride, stride_align); + return -EINVAL; + } + + if (g_debug_ovl_online_composer) { + HISI_FB_INFO + ("fb%d, mm_base_0=0x%x, mm_base_1=0x%x, mmbuf_size=%d, " + "aligned_rect(%d,%d,%d,%d), afbc_rect(%d,%d,%d,%d)!\n", + hisifd->index, mm_base_0, mm_base_1, + layer->img.mmbuf_size, aligned_rect.left, + aligned_rect.top, aligned_rect.right, + aligned_rect.bottom, afbc_rect.left, afbc_rect.top, + afbc_rect.right, afbc_rect.bottom); + } + + dma->oft_x0 = set_bits32(dma->oft_x0, rdma_oft_x0, 16, 0); + dma->oft_x1 = set_bits32(dma->oft_x1, rdma_oft_x1, 16, 0); + dma->stretch_size_vrt = set_bits32(dma->stretch_size_vrt, + (stretch_size_vrt | + (stretched_line_num << 13)), + 19, 0); + dma->ctrl = set_bits32(dma->ctrl, rdma_format, 5, 3); + dma->ctrl = + set_bits32(dma->ctrl, (mmu_enable ? 0x1 : 0x0), 1, 8); + dma->ctrl = set_bits32(dma->ctrl, rdma_transform, 3, 9); + dma->ctrl = + set_bits32(dma->ctrl, (*rdma_stretch_enable ? 1 : 0), 1, + 12); + dma->ch_ctl = set_bits32(dma->ch_ctl, 0x1, 1, 0); + dma->ch_ctl = set_bits32(dma->ch_ctl, 0x1, 1, 2); + + dma->afbcd_hreg_pic_width = + set_bits32(dma->afbcd_hreg_pic_width, + (aligned_rect.right - aligned_rect.left), 16, 0); + dma->afbcd_hreg_pic_height = + set_bits32(dma->afbcd_hreg_pic_height, + (aligned_rect.bottom - aligned_rect.top), 16, 0); + dma->afbcd_hreg_format = + set_bits32(dma->afbcd_hreg_format, 0x1, 1, 0); + dma->afbcd_hreg_format = + set_bits32(dma->afbcd_hreg_format, + (isYUVPackage(layer->img.format) ? 0x0 : 0x1), 1, + 21); + dma->afbcd_ctl = + set_bits32(dma->afbcd_ctl, afbcd_half_block_mode, 2, 6); + dma->afbcd_str = + set_bits32(dma->afbcd_str, + (afbcd_stretch_acc << 8 | afbcd_stretch_inc), 12, + 0); + dma->afbcd_line_crop = + set_bits32(dma->afbcd_line_crop, + (afbcd_top_crop_num << 4 | + afbcd_bottom_crop_num), 8, 0); + dma->afbcd_hreg_hdr_ptr_lo = + set_bits32(dma->afbcd_hreg_hdr_ptr_lo, afbc_header_addr, 32, + 0); + dma->afbcd_input_header_stride = + set_bits32(dma->afbcd_input_header_stride, + (afbc_header_start_pos << 14) | + afbc_header_stride, 16, 0); + dma->afbcd_payload_stride = + set_bits32(dma->afbcd_payload_stride, afbc_payload_stride, + 20, 0); + dma->afbcd_mm_base_0 = + set_bits32(dma->afbcd_mm_base_0, mm_base_0, 32, 0); + dma->afbcd_afbcd_payload_pointer = + set_bits32(dma->afbcd_afbcd_payload_pointer, + afbc_payload_addr, 32, 0); + dma->afbcd_height_bf_str = + set_bits32(dma->afbcd_height_bf_str, + DSS_HEIGHT(afbcd_height_bf_str), 16, 0); + dma->afbcd_header_pointer_offset = + set_bits32(dma->afbcd_header_pointer_offset, + afbc_header_pointer_offset, 32, 0); + dma->afbcd_scramble_mode = + set_bits32(dma->afbcd_scramble_mode, + layer->img.afbc_scramble_mode, 2, 0); + + return 0; + } + + rdma_addr = mmu_enable ? layer->img.vir_addr : layer->img.phy_addr; + if (rdma_addr & (DMA_ADDR_ALIGN - 1)) { + HISI_FB_ERR + ("layer%d rdma_addr(0x%x) is not %d bytes aligned.\n", + layer->layer_idx, rdma_addr, DMA_ADDR_ALIGN); + return -EINVAL; + } + + if (layer->img.stride & (DMA_STRIDE_ALIGN - 1)) { + HISI_FB_ERR("layer%d stride(0x%x) is not %d bytes aligned.\n", + layer->layer_idx, layer->img.stride, + DMA_STRIDE_ALIGN); + return -EINVAL; + } + + if (layer->need_cap & CAP_TILE) { + l2t_interleave_n = + hisi_get_rdma_tile_interleave(layer->img.stride); + if (l2t_interleave_n < MIN_INTERLEAVE) { + HISI_FB_ERR + ("tile stride should be 256*2^n, error stride:%d!\n", + layer->img.stride); + return -EINVAL; + } + + if (rdma_addr & (TILE_DMA_ADDR_ALIGN - 1)) { + HISI_FB_ERR + ("layer%d tile rdma_addr(0x%x) is not %d bytes aligned.\n", + layer->layer_idx, rdma_addr, TILE_DMA_ADDR_ALIGN); + return -EINVAL; + } + } + + if (is_YUV_P_420(layer->img.format) || is_YUV_P_422(layer->img.format)) { + aligned_rect.left = + ALIGN_DOWN(new_src_rect.x, 2 * aligned_pixel); + aligned_rect.right = + ALIGN_UP(new_src_rect.x + new_src_rect.w, + 2 * aligned_pixel) - 1; + } else { + aligned_rect.left = ALIGN_DOWN(new_src_rect.x, aligned_pixel); + aligned_rect.right = + ALIGN_UP(new_src_rect.x + new_src_rect.w, + aligned_pixel) - 1; + } + + if (is_YUV_SP_420(layer->img.format) || is_YUV_P_420(layer->img.format)) { + aligned_rect.top = ALIGN_DOWN(new_src_rect.y, 2); + aligned_rect.bottom = + ALIGN_UP(new_src_rect.y + new_src_rect.h, 2) - 1; + } else { + aligned_rect.top = new_src_rect.y; + aligned_rect.bottom = + DSS_HEIGHT(new_src_rect.y + new_src_rect.h); + } + + if (src_rect_mask_enable) { + if (is_YUV_P_420(layer->img.format) + || is_YUV_P_422(layer->img.format)) { + aligned_mask_rect.left = + ALIGN_UP(layer->src_rect_mask.x, 2 * aligned_pixel); + aligned_mask_rect.right = + ALIGN_DOWN(layer->src_rect_mask.x + + layer->src_rect_mask.w, + 2 * aligned_pixel) - 1; + } else { + aligned_mask_rect.left = + ALIGN_UP(layer->src_rect_mask.x, aligned_pixel); + aligned_mask_rect.right = + ALIGN_DOWN(layer->src_rect_mask.x + + layer->src_rect_mask.w, + aligned_pixel) - 1; + } + + if (is_YUV_SP_420(layer->img.format) + || is_YUV_P_420(layer->img.format)) { + aligned_mask_rect.top = + ALIGN_UP(layer->src_rect_mask.y, 2); + aligned_mask_rect.bottom = + ALIGN_DOWN(layer->src_rect_mask.y + + layer->src_rect_mask.h, 2) - 1; + } else { + aligned_mask_rect.top = layer->src_rect_mask.y; + aligned_mask_rect.bottom = + DSS_HEIGHT(layer->src_rect_mask.y + + layer->src_rect_mask.h); + } + } + + out_aligned_rect->x = 0; + out_aligned_rect->y = 0; + out_aligned_rect->w = aligned_rect.right - aligned_rect.left + 1; + out_aligned_rect->h = aligned_rect.bottom - aligned_rect.top + 1; + if (stretched_line_num > 0) { + stretch_size_vrt = (out_aligned_rect->h / stretched_line_num) + + ((out_aligned_rect->h % stretched_line_num) ? 1 : 0) - 1; + + out_aligned_rect->h = stretch_size_vrt + 1; + } else { + stretch_size_vrt = 0x0; + } + + clip_rect->left = new_src_rect.x - aligned_rect.left; + clip_rect->right = + aligned_rect.right - DSS_WIDTH(new_src_rect.x + new_src_rect.w); + clip_rect->top = new_src_rect.y - aligned_rect.top; + clip_rect->bottom = + aligned_rect.bottom - DSS_HEIGHT(new_src_rect.y + new_src_rect.h); + + if (hisi_adjust_clip_rect(layer, clip_rect) < 0) { + HISI_FB_ERR + ("clip rect invalid => layer_idx=%d, chn_idx=%d, " + "clip_rect(%d, %d, %d, %d).\n", + layer->layer_idx, chn_idx, clip_rect->left, + clip_rect->right, clip_rect->top, clip_rect->bottom); + return -EINVAL; + } + + rdma_oft_y0 = aligned_rect.top; + rdma_oft_y1 = aligned_rect.bottom; + rdma_oft_x0 = aligned_rect.left / aligned_pixel; + rdma_oft_x1 = aligned_rect.right / aligned_pixel; + + if ((rdma_oft_x1 - rdma_oft_x0) < 0 || + (rdma_oft_x1 - rdma_oft_x0 + 1) > DMA_IN_WIDTH_MAX) { + HISI_FB_ERR + ("out of range, rdma_oft_x0 = %d, rdma_oft_x1 = %d!\n", + rdma_oft_x0, rdma_oft_x1); + return -EINVAL; + } + + if ((rdma_oft_y1 - rdma_oft_y0) < 0 || + (rdma_oft_y1 - rdma_oft_y0 + 1) > DMA_IN_HEIGHT_MAX) { + HISI_FB_ERR + ("out of range, rdma_oft_y0 = %d, rdma_oft_y1 = %d\n", + rdma_oft_y0, rdma_oft_y1); + return -EINVAL; + } + + rdma_addr = + hisi_calculate_display_addr(mmu_enable, layer, &aligned_rect, + DSS_ADDR_PLANE0); + rdma_stride = layer->img.stride; + rdma_data_num = + (rdma_oft_x1 - rdma_oft_x0 + 1) * (rdma_oft_y1 - rdma_oft_y0 + 1); + + if (src_rect_mask_enable) { + rdma_mask_y0 = aligned_mask_rect.top; + rdma_mask_y1 = aligned_mask_rect.bottom; + rdma_mask_x0 = aligned_mask_rect.left / aligned_pixel; + rdma_mask_x1 = aligned_mask_rect.right / aligned_pixel; + + if ((rdma_mask_x1 - rdma_mask_x0) > 2) + rdma_mask_x0 += 2; + + if ((rdma_mask_x0 <= rdma_oft_x0) + || (rdma_mask_x1 >= rdma_oft_x1) + || (rdma_mask_y0 <= rdma_oft_y0) + || (rdma_mask_y1 >= rdma_oft_y1)) { + src_rect_mask_enable = false; + rdma_mask_x0 = 0; + rdma_mask_y0 = 0; + rdma_mask_x1 = 0; + rdma_mask_y1 = 0; + } + } + + if (stretched_line_num > 0) { + stretched_stride = + stretched_line_num * rdma_stride / DMA_ALIGN_BYTES; + rdma_data_num = + (stretch_size_vrt + 1) * (rdma_oft_x1 - rdma_oft_x0 + 1); + } else { + stretch_size_vrt = rdma_oft_y1 - rdma_oft_y0; + stretched_line_num = 0x0; + stretched_stride = 0x0; + } + + dma->oft_x0 = set_bits32(dma->oft_x0, rdma_oft_x0, 16, 0); + dma->oft_y0 = set_bits32(dma->oft_y0, rdma_oft_y0, 16, 0); + dma->oft_x1 = set_bits32(dma->oft_x1, rdma_oft_x1, 16, 0); + dma->oft_y1 = set_bits32(dma->oft_y1, rdma_oft_y1, 16, 0); + dma->mask0 = set_bits32(dma->mask0, + (rdma_mask_y0 | (rdma_mask_x0 << 16)), 32, 0); + dma->mask1 = set_bits32(dma->mask1, + (rdma_mask_y1 | (rdma_mask_x1 << 16)), 32, 0); + dma->stretch_size_vrt = set_bits32(dma->stretch_size_vrt, + (stretch_size_vrt | + (stretched_line_num << 13)), 19, 0); + dma->ctrl = + set_bits32(dma->ctrl, ((layer->need_cap & CAP_TILE) ? 0x1 : 0x0), 1, + 1); + dma->ctrl = set_bits32(dma->ctrl, rdma_format, 5, 3); + dma->ctrl = set_bits32(dma->ctrl, (mmu_enable ? 0x1 : 0x0), 1, 8); + dma->ctrl = set_bits32(dma->ctrl, rdma_transform, 3, 9); + dma->ctrl = + set_bits32(dma->ctrl, ((stretched_line_num > 0) ? 0x1 : 0x0), 1, + 12); + dma->ctrl = + set_bits32(dma->ctrl, (src_rect_mask_enable ? 0x1 : 0x0), 1, 17); + dma->tile_scram = + set_bits32(dma->tile_scram, + ((layer->need_cap & CAP_TILE) ? 0x1 : 0x0), 1, 0); + dma->ch_ctl = set_bits32(dma->ch_ctl, 0x1, 1, 0); + + dma->data_addr0 = set_bits32(dma->data_addr0, rdma_addr, 32, 0); + dma->stride0 = set_bits32(dma->stride0, + ((rdma_stride / + DMA_ALIGN_BYTES) | (l2t_interleave_n << + 16)), 20, 0); + dma->stretch_stride0 = + set_bits32(dma->stretch_stride0, stretched_stride, 19, 0); + dma->data_num0 = set_bits32(dma->data_num0, rdma_data_num, 30, 0); + + if (is_yuv_semi_planar || is_yuv_planar) { + if (is_YUV_P_420(layer->img.format) + || is_YUV_P_422(layer->img.format)) { + rdma_oft_x0 /= 2; + rdma_oft_x1 = (rdma_oft_x1 + 1) / 2 - 1; + } + + if (is_YUV_SP_420(layer->img.format) + || is_YUV_P_420(layer->img.format)) { + rdma_oft_y0 /= 2; + rdma_oft_y1 = (rdma_oft_y1 + 1) / 2 - 1; + + stretched_line_num /= 2; + } + + rdma_addr = + hisi_calculate_display_addr(mmu_enable, layer, + &aligned_rect, DSS_ADDR_PLANE1); + rdma_stride = layer->img.stride_plane1; + rdma_data_num = + (rdma_oft_x1 - rdma_oft_x0 + 1) * (rdma_oft_y1 - + rdma_oft_y0 + 1) * 2; + + if (*rdma_stretch_enable) { + stretched_stride = + stretched_line_num * rdma_stride / DMA_ALIGN_BYTES; + rdma_data_num = + (stretch_size_vrt + 1) * (rdma_oft_x1 - + rdma_oft_x0 + 1) * 2; + } else { + stretch_size_vrt = 0; + stretched_line_num = 0; + stretched_stride = 0; + } + + dma->data_addr1 = set_bits32(dma->data_addr1, rdma_addr, 32, 0); + dma->stride1 = set_bits32(dma->stride1, + ((rdma_stride / + DMA_ALIGN_BYTES) | (l2t_interleave_n << 16)), 20, 0); + dma->stretch_stride1 = + set_bits32(dma->stretch_stride1, stretched_stride, 19, 0); + dma->data_num1 = + set_bits32(dma->data_num1, rdma_data_num, 30, 0); + + if (is_yuv_planar) { + rdma_addr = + hisi_calculate_display_addr(mmu_enable, layer, + &aligned_rect, + DSS_ADDR_PLANE2); + rdma_stride = layer->img.stride_plane2; + + dma->data_addr2 = + set_bits32(dma->data_addr2, rdma_addr, 32, 0); + dma->stride2 = + set_bits32(dma->stride2, + ((rdma_stride / + DMA_ALIGN_BYTES) | (l2t_interleave_n << 16)), 20, 0); + dma->stretch_stride2 = + set_bits32(dma->stretch_stride1, stretched_stride, + 19, 0); + dma->data_num2 = + set_bits32(dma->data_num1, rdma_data_num, 30, 0); + } + } + + return 0; +} + +/******************************************************************************* + ** DSS DFC + */ +static void hisi_dss_dfc_init(char __iomem *dfc_base, dss_dfc_t *s_dfc) +{ + BUG_ON(dfc_base == NULL); + BUG_ON(s_dfc == NULL); + + memset(s_dfc, 0, sizeof(dss_dfc_t)); + + s_dfc->disp_size = inp32(dfc_base + DFC_DISP_SIZE); + s_dfc->pix_in_num = inp32(dfc_base + DFC_PIX_IN_NUM); + s_dfc->disp_fmt = inp32(dfc_base + DFC_DISP_FMT); + s_dfc->clip_ctl_hrz = inp32(dfc_base + DFC_CLIP_CTL_HRZ); + s_dfc->clip_ctl_vrz = inp32(dfc_base + DFC_CLIP_CTL_VRZ); + s_dfc->ctl_clip_en = inp32(dfc_base + DFC_CTL_CLIP_EN); + s_dfc->icg_module = inp32(dfc_base + DFC_ICG_MODULE); + s_dfc->dither_enable = inp32(dfc_base + DFC_DITHER_ENABLE); + s_dfc->padding_ctl = inp32(dfc_base + DFC_PADDING_CTL); +} + +static void hisi_dss_dfc_set_reg(struct hisi_fb_data_type *hisifd, + char __iomem *dfc_base, dss_dfc_t *s_dfc) +{ + BUG_ON(hisifd == NULL); + BUG_ON(dfc_base == NULL); + BUG_ON(s_dfc == NULL); + + hisifd->set_reg(hisifd, dfc_base + DFC_DISP_SIZE, s_dfc->disp_size, 32, + 0); + hisifd->set_reg(hisifd, dfc_base + DFC_PIX_IN_NUM, s_dfc->pix_in_num, + 32, 0); + hisifd->set_reg(hisifd, dfc_base + DFC_DISP_FMT, s_dfc->disp_fmt, 32, + 0); + hisifd->set_reg(hisifd, dfc_base + DFC_CLIP_CTL_HRZ, + s_dfc->clip_ctl_hrz, 32, 0); + hisifd->set_reg(hisifd, dfc_base + DFC_CLIP_CTL_VRZ, + s_dfc->clip_ctl_vrz, 32, 0); + hisifd->set_reg(hisifd, dfc_base + DFC_CTL_CLIP_EN, s_dfc->ctl_clip_en, + 32, 0); + hisifd->set_reg(hisifd, dfc_base + DFC_ICG_MODULE, s_dfc->icg_module, + 32, 0); + hisifd->set_reg(hisifd, dfc_base + DFC_DITHER_ENABLE, + s_dfc->dither_enable, 32, 0); + hisifd->set_reg(hisifd, dfc_base + DFC_PADDING_CTL, s_dfc->padding_ctl, + 32, 0); +} + +int hisi_dss_rdfc_config(struct hisi_fb_data_type *hisifd, dss_layer_t *layer, + dss_rect_t *aligned_rect, dss_rect_ltrb_t clip_rect) +{ + dss_dfc_t *dfc = NULL; + int chn_idx = 0; + int dfc_fmt = 0; + int dfc_bpp = 0; + int dfc_pix_in_num = 0; + int dfc_aligned = 0; + int size_hrz = 0; + int size_vrt = 0; + int dfc_hrz_clip = 0; + bool need_clip = false; + + BUG_ON(hisifd == NULL); + BUG_ON(layer == NULL); + + chn_idx = layer->chn_idx; + + dfc = &(hisifd->dss_module.dfc[chn_idx]); + hisifd->dss_module.dfc_used[chn_idx] = 1; + + dfc_fmt = hisi_pixel_format_hal2dfc(layer->img.format); + if (dfc_fmt < 0) { + HISI_FB_ERR("layer format (%d) not support !\n", + layer->img.format); + return -EINVAL; + } + + dfc_bpp = hisi_dfc_get_bpp(dfc_fmt); + if (dfc_bpp <= 0) { + HISI_FB_ERR("dfc_bpp(%d) not support !\n", dfc_bpp); + return -EINVAL; + } + + dfc_pix_in_num = (dfc_bpp <= 2) ? 0x1 : 0x0; + dfc_aligned = (dfc_bpp <= 2) ? 4 : 2; + + need_clip = isNeedRectClip(clip_rect); + + size_hrz = DSS_WIDTH(aligned_rect->w); + size_vrt = DSS_HEIGHT(aligned_rect->h); + + if (((size_hrz + 1) % dfc_aligned) != 0) { + size_hrz -= 1; + HISI_FB_ERR("SIZE_HRT=%d mismatch!bpp=%d\n", size_hrz, + layer->img.bpp); + + HISI_FB_ERR("layer_idx%d, format=%d, transform=%d, " + "original_src_rect(%d,%d,%d,%d), rdma_out_rect(%d,%d,%d,%d), " + "dst_rect(%d,%d,%d,%d)!\n", + layer->layer_idx, layer->img.format, + layer->transform, layer->src_rect.x, + layer->src_rect.y, layer->src_rect.w, + layer->src_rect.h, aligned_rect->x, aligned_rect->y, + aligned_rect->w, aligned_rect->h, layer->dst_rect.x, + layer->dst_rect.y, layer->dst_rect.w, + layer->dst_rect.h); + } + + dfc_hrz_clip = (size_hrz + 1) % dfc_aligned; + if (dfc_hrz_clip) { + clip_rect.right += dfc_hrz_clip; + size_hrz += dfc_hrz_clip; + need_clip = true; + } + + dfc->disp_size = + set_bits32(dfc->disp_size, (size_vrt | (size_hrz << 16)), 29, 0); + dfc->pix_in_num = set_bits32(dfc->pix_in_num, dfc_pix_in_num, 1, 0); + dfc->disp_fmt = set_bits32(dfc->disp_fmt, + ((dfc_fmt << 1) | + (hisi_uv_swap(layer->img.format) << 6) | + (hisi_rb_swap(layer->img.format) << 7)), 8, 0); + + if (need_clip) { + dfc->clip_ctl_hrz = set_bits32(dfc->clip_ctl_hrz, + (clip_rect.right | (clip_rect.left << 16)), + 32, 0); + dfc->clip_ctl_vrz = + set_bits32(dfc->clip_ctl_vrz, + (clip_rect.bottom | (clip_rect.top << 16)), 32, 0); + dfc->ctl_clip_en = set_bits32(dfc->ctl_clip_en, 0x1, 1, 0); + } else { + dfc->clip_ctl_hrz = set_bits32(dfc->clip_ctl_hrz, 0x0, 32, 0); + dfc->clip_ctl_vrz = set_bits32(dfc->clip_ctl_vrz, 0x0, 32, 0); + dfc->ctl_clip_en = set_bits32(dfc->ctl_clip_en, 0x1, 1, 0); + } + dfc->icg_module = set_bits32(dfc->icg_module, 0x1, 1, 0); + dfc->dither_enable = set_bits32(dfc->dither_enable, 0x0, 1, 0); + dfc->padding_ctl = set_bits32(dfc->padding_ctl, 0x0, 17, 0); + + if (need_clip) { + aligned_rect->w -= (clip_rect.left + clip_rect.right); + aligned_rect->h -= (clip_rect.top + clip_rect.bottom); + } + + return 0; +} + +/******************************************************************************* + ** DSS SCF + */ + +/* Filter coefficients for SCF */ +#define PHASE_NUM (66) +#define TAP4 (4) +#define TAP5 (5) +#define TAP6 (6) +#define COEF_LUT_NUM (2) + +static const int COEF_LUT_TAP4[SCL_COEF_IDX_MAX][PHASE_NUM][TAP4] = { + /* YUV_COEF_IDX */ + { + {214, 599, 214, -3}, + {207, 597, 223, -3}, + {200, 596, 231, -3}, + {193, 596, 238, -3}, + {186, 595, 246, -3}, + {178, 594, 255, -3}, + {171, 593, 263, -3}, + {165, 591, 271, -3}, + {158, 589, 279, -2}, + {151, 587, 288, -2}, + {145, 584, 296, -1}, + {139, 582, 304, -1}, + {133, 578, 312, 1}, + {127, 575, 321, 1}, + {121, 572, 329, 2}, + {115, 568, 337, 4}, + {109, 564, 346, 5}, + {104, 560, 354, 6}, + {98, 555, 362, 9}, + {94, 550, 370, 10}, + {88, 546, 379, 11}, + {84, 540, 387, 13}, + {79, 535, 395, 15}, + {74, 530, 403, 17}, + {70, 524, 411, 19}, + {66, 518, 419, 21}, + {62, 512, 427, 23}, + {57, 506, 435, 26}, + {54, 499, 443, 28}, + {50, 492, 451, 31}, + {47, 486, 457, 34}, + {43, 479, 465, 37}, + {40, 472, 472, 40}, + {214, 599, 214, -3}, + {207, 597, 223, -3}, + {200, 596, 231, -3}, + {193, 596, 238, -3}, + {186, 595, 246, -3}, + {178, 594, 255, -3}, + {171, 593, 263, -3}, + {165, 591, 271, -3}, + {158, 589, 279, -2}, + {151, 587, 288, -2}, + {145, 584, 296, -1}, + {139, 582, 304, -1}, + {133, 578, 312, 1}, + {127, 575, 321, 1}, + {121, 572, 329, 2}, + {115, 568, 337, 4}, + {109, 564, 346, 5}, + {104, 560, 354, 6}, + {98, 555, 362, 9}, + {94, 550, 370, 10}, + {88, 546, 379, 11}, + {84, 540, 387, 13}, + {79, 535, 395, 15}, + {74, 530, 403, 17}, + {70, 524, 411, 19}, + {66, 518, 419, 21}, + {62, 512, 427, 23}, + {57, 506, 435, 26}, + {54, 499, 443, 28}, + {50, 492, 451, 31}, + {47, 486, 457, 34}, + {43, 479, 465, 37}, + {40, 472, 472, 40} + }, + + /* RGB_COEF_IDX */ + { + {0, 1024, 0, 0}, + {0, 1008, 16, 0}, + {0, 992, 32, 0}, + {0, 976, 48, 0}, + {0, 960, 64, 0}, + {0, 944, 80, 0}, + {0, 928, 96, 0}, + {0, 912, 112, 0}, + {0, 896, 128, 0}, + {0, 880, 144, 0}, + {0, 864, 160, 0}, + {0, 848, 176, 0}, + {0, 832, 192, 0}, + {0, 816, 208, 0}, + {0, 800, 224, 0}, + {0, 784, 240, 0}, + {0, 768, 256, 0}, + {0, 752, 272, 0}, + {0, 736, 288, 0}, + {0, 720, 304, 0}, + {0, 704, 320, 0}, + {0, 688, 336, 0}, + {0, 672, 352, 0}, + {0, 656, 368, 0}, + {0, 640, 384, 0}, + {0, 624, 400, 0}, + {0, 608, 416, 0}, + {0, 592, 432, 0}, + {0, 576, 448, 0}, + {0, 560, 464, 0}, + {0, 544, 480, 0}, + {0, 528, 496, 0}, + {0, 512, 512, 0}, + {0, 1024, 0, 0}, + {0, 1008, 16, 0}, + {0, 992, 32, 0}, + {0, 976, 48, 0}, + {0, 960, 64, 0}, + {0, 944, 80, 0}, + {0, 928, 96, 0}, + {0, 912, 112, 0}, + {0, 896, 128, 0}, + {0, 880, 144, 0}, + {0, 864, 160, 0}, + {0, 848, 176, 0}, + {0, 832, 192, 0}, + {0, 816, 208, 0}, + {0, 800, 224, 0}, + {0, 784, 240, 0}, + {0, 768, 256, 0}, + {0, 752, 272, 0}, + {0, 736, 288, 0}, + {0, 720, 304, 0}, + {0, 704, 320, 0}, + {0, 688, 336, 0}, + {0, 672, 352, 0}, + {0, 656, 368, 0}, + {0, 640, 384, 0}, + {0, 624, 400, 0}, + {0, 608, 416, 0}, + {0, 592, 432, 0}, + {0, 576, 448, 0}, + {0, 560, 464, 0}, + {0, 544, 480, 0}, + {0, 528, 496, 0}, + {0, 512, 512, 0} + } +}; + +static const int COEF_LUT_TAP5[SCL_COEF_IDX_MAX][PHASE_NUM][TAP5] = { + /* YUV_COEF_IDX */ + { + {98, 415, 415, 98, -2}, + {95, 412, 418, 103, -4}, + {91, 408, 422, 107, -4}, + {87, 404, 426, 111, -4}, + {84, 399, 430, 115, -4}, + {80, 395, 434, 119, -4}, + {76, 390, 438, 124, -4}, + {73, 386, 440, 128, -3}, + {70, 381, 444, 132, -3}, + {66, 376, 448, 137, -3}, + {63, 371, 451, 142, -3}, + {60, 366, 455, 146, -3}, + {57, 361, 457, 151, -2}, + {54, 356, 460, 156, -2}, + {51, 351, 463, 161, -2}, + {49, 346, 465, 165, -1}, + {46, 341, 468, 170, -1}, + {43, 336, 470, 175, 0}, + {41, 331, 472, 180, 0}, + {38, 325, 474, 186, 1}, + {36, 320, 476, 191, 1}, + {34, 315, 477, 196, 2}, + {32, 309, 479, 201, 3}, + {29, 304, 481, 206, 4}, + {27, 299, 481, 212, 5}, + {26, 293, 482, 217, 6}, + {24, 288, 484, 222, 6}, + {22, 282, 484, 228, 8}, + {20, 277, 485, 233, 9}, + {19, 271, 485, 238, 11}, + {17, 266, 485, 244, 12}, + {16, 260, 485, 250, 13}, + {14, 255, 486, 255, 14}, + {-94, 608, 608, -94, -4}, + {-94, 594, 619, -91, -4}, + {-96, 579, 635, -89, -5}, + {-96, 563, 650, -87, -6}, + {-97, 548, 665, -85, -7}, + {-97, 532, 678, -82, -7}, + {-98, 516, 693, -79, -8}, + {-97, 500, 705, -75, -9}, + {-97, 484, 720, -72, -11}, + {-97, 468, 733, -68, -12}, + {-96, 452, 744, -63, -13}, + {-95, 436, 755, -58, -14}, + {-94, 419, 768, -53, -16}, + {-93, 403, 779, -48, -17}, + {-92, 387, 789, -42, -18}, + {-90, 371, 799, -36, -20}, + {-89, 355, 809, -29, -22}, + {-87, 339, 817, -22, -23}, + {-86, 324, 826, -15, -25}, + {-84, 308, 835, -8, -27}, + {-82, 293, 842, 0, -29}, + {-80, 277, 849, 9, -31}, + {-78, 262, 855, 18, -33}, + {-75, 247, 860, 27, -35}, + {-73, 233, 865, 36, -37}, + {-71, 218, 870, 46, -39}, + {-69, 204, 874, 56, -41}, + {-66, 190, 876, 67, -43}, + {-64, 176, 879, 78, -45}, + {-62, 163, 882, 89, -48}, + {-59, 150, 883, 100, -50}, + {-57, 137, 883, 112, -51}, + {-55, 125, 884, 125, -55} + }, + + /* RGB_COEF_IDX */ + { + {0, 512, 512, 0, 0}, + {0, 496, 528, 0, 0}, + {0, 480, 544, 0, 0}, + {0, 464, 560, 0, 0}, + {0, 448, 576, 0, 0}, + {0, 432, 592, 0, 0}, + {0, 416, 608, 0, 0}, + {0, 400, 624, 0, 0}, + {0, 384, 640, 0, 0}, + {0, 368, 656, 0, 0}, + {0, 352, 672, 0, 0}, + {0, 336, 688, 0, 0}, + {0, 320, 704, 0, 0}, + {0, 304, 720, 0, 0}, + {0, 288, 736, 0, 0}, + {0, 272, 752, 0, 0}, + {0, 256, 768, 0, 0}, + {0, 240, 784, 0, 0}, + {0, 224, 800, 0, 0}, + {0, 208, 816, 0, 0}, + {0, 192, 832, 0, 0}, + {0, 176, 848, 0, 0}, + {0, 160, 864, 0, 0}, + {0, 144, 880, 0, 0}, + {0, 128, 896, 0, 0}, + {0, 112, 912, 0, 0}, + {0, 96, 928, 0, 0}, + {0, 80, 944, 0, 0}, + {0, 64, 960, 0, 0}, + {0, 48, 976, 0, 0}, + {0, 32, 992, 0, 0}, + {0, 16, 1008, 0, 0}, + {0, 0, 1024, 0, 0}, + {0, 512, 512, 0, 0}, + {0, 496, 528, 0, 0}, + {0, 480, 544, 0, 0}, + {0, 464, 560, 0, 0}, + {0, 448, 576, 0, 0}, + {0, 432, 592, 0, 0}, + {0, 416, 608, 0, 0}, + {0, 400, 624, 0, 0}, + {0, 384, 640, 0, 0}, + {0, 368, 656, 0, 0}, + {0, 352, 672, 0, 0}, + {0, 336, 688, 0, 0}, + {0, 320, 704, 0, 0}, + {0, 304, 720, 0, 0}, + {0, 288, 736, 0, 0}, + {0, 272, 752, 0, 0}, + {0, 256, 768, 0, 0}, + {0, 240, 784, 0, 0}, + {0, 224, 800, 0, 0}, + {0, 208, 816, 0, 0}, + {0, 192, 832, 0, 0}, + {0, 176, 848, 0, 0}, + {0, 160, 864, 0, 0}, + {0, 144, 880, 0, 0}, + {0, 128, 896, 0, 0}, + {0, 112, 912, 0, 0}, + {0, 96, 928, 0, 0}, + {0, 80, 944, 0, 0}, + {0, 64, 960, 0, 0}, + {0, 48, 976, 0, 0}, + {0, 32, 992, 0, 0}, + {0, 16, 1008, 0, 0}, + {0, 0, 1024, 0, 0} + } +}; + +static const int COEF_LUT_TAP6[SCL_COEF_IDX_MAX][PHASE_NUM][TAP6] = { + /* YUV_COEF_IDX */ + { + {2, 264, 500, 264, 2, -8}, + {2, 257, 499, 268, 6, -8}, + {1, 252, 498, 274, 8, -9}, + {-1, 246, 498, 281, 9, -9}, + {-2, 241, 497, 286, 12, -10}, + {-3, 235, 497, 292, 13, -10}, + {-5, 230, 496, 298, 15, -10}, + {-6, 225, 495, 303, 18, -11}, + {-7, 219, 494, 309, 20, -11}, + {-7, 213, 493, 314, 23, -12}, + {-9, 208, 491, 320, 26, -12}, + {-10, 203, 490, 325, 28, -12}, + {-10, 197, 488, 331, 31, -13}, + {-10, 192, 486, 336, 33, -13}, + {-12, 186, 485, 342, 36, -13}, + {-12, 181, 482, 347, 39, -13}, + {-13, 176, 480, 352, 42, -13}, + {-14, 171, 478, 358, 45, -14}, + {-14, 166, 476, 363, 48, -15}, + {-14, 160, 473, 368, 52, -15}, + {-14, 155, 470, 373, 55, -15}, + {-15, 150, 467, 378, 59, -15}, + {-15, 145, 464, 383, 62, -15}, + {-16, 141, 461, 388, 65, -15}, + {-16, 136, 458, 393, 68, -15}, + {-16, 131, 455, 398, 72, -16}, + {-16, 126, 451, 402, 77, -16}, + {-16, 122, 448, 407, 79, -16}, + {-16, 117, 444, 411, 84, -16}, + {-17, 113, 441, 416, 87, -16}, + {-17, 108, 437, 420, 92, -16}, + {-17, 104, 433, 424, 96, -16}, + {-17, 100, 429, 429, 100, -17}, + {-187, 105, 1186, 105, -187, 2}, + {-182, 86, 1186, 124, -192, 2}, + {-176, 67, 1185, 143, -197, 2}, + {-170, 49, 1182, 163, -202, 2}, + {-166, 32, 1180, 184, -207, 1}, + {-160, 15, 1176, 204, -212, 1}, + {-155, -2, 1171, 225, -216, 1}, + {-149, -18, 1166, 246, -221, 0}, + {-145, -34, 1160, 268, -225, 0}, + {-139, -49, 1153, 290, -230, -1}, + {-134, -63, 1145, 312, -234, -2}, + {-129, -78, 1137, 334, -238, -2}, + {-124, -91, 1128, 357, -241, -5}, + {-119, -104, 1118, 379, -245, -5}, + {-114, -117, 1107, 402, -248, -6}, + {-109, -129, 1096, 425, -251, -8}, + {-104, -141, 1083, 448, -254, -8}, + {-100, -152, 1071, 471, -257, -9}, + {-95, -162, 1057, 494, -259, -11}, + {-90, -172, 1043, 517, -261, -13}, + {-86, -181, 1028, 540, -263, -14}, + {-82, -190, 1013, 563, -264, -16}, + {-77, -199, 997, 586, -265, -18}, + {-73, -207, 980, 609, -266, -19}, + {-69, -214, 963, 632, -266, -22}, + {-65, -221, 945, 655, -266, -24}, + {-62, -227, 927, 678, -266, -26}, + {-58, -233, 908, 700, -265, -28}, + {-54, -238, 889, 722, -264, -31}, + {-51, -243, 870, 744, -262, -34}, + {-48, -247, 850, 766, -260, -37}, + {-45, -251, 829, 787, -257, -39}, + {-42, -255, 809, 809, -255, -42} + }, + + /* RGB_COEF_IDX */ + { + {0, 0, 1024, 0, 0, 0}, + {0, 0, 1008, 16, 0, 0}, + {0, 0, 992, 32, 0, 0}, + {0, 0, 976, 48, 0, 0}, + {0, 0, 960, 64, 0, 0}, + {0, 0, 944, 80, 0, 0}, + {0, 0, 928, 96, 0, 0}, + {0, 0, 912, 112, 0, 0}, + {0, 0, 896, 128, 0, 0}, + {0, 0, 880, 144, 0, 0}, + {0, 0, 864, 160, 0, 0}, + {0, 0, 848, 176, 0, 0}, + {0, 0, 832, 192, 0, 0}, + {0, 0, 816, 208, 0, 0}, + {0, 0, 800, 224, 0, 0}, + {0, 0, 784, 240, 0, 0}, + {0, 0, 768, 256, 0, 0}, + {0, 0, 752, 272, 0, 0}, + {0, 0, 736, 288, 0, 0}, + {0, 0, 720, 304, 0, 0}, + {0, 0, 704, 320, 0, 0}, + {0, 0, 688, 336, 0, 0}, + {0, 0, 672, 352, 0, 0}, + {0, 0, 656, 368, 0, 0}, + {0, 0, 640, 384, 0, 0}, + {0, 0, 624, 400, 0, 0}, + {0, 0, 608, 416, 0, 0}, + {0, 0, 592, 432, 0, 0}, + {0, 0, 576, 448, 0, 0}, + {0, 0, 560, 464, 0, 0}, + {0, 0, 544, 480, 0, 0}, + {0, 0, 528, 496, 0, 0}, + {0, 0, 512, 512, 0, 0}, + {0, 0, 1024, 0, 0, 0}, + {0, 0, 1008, 16, 0, 0}, + {0, 0, 992, 32, 0, 0}, + {0, 0, 976, 48, 0, 0}, + {0, 0, 960, 64, 0, 0}, + {0, 0, 944, 80, 0, 0}, + {0, 0, 928, 96, 0, 0}, + {0, 0, 912, 112, 0, 0}, + {0, 0, 896, 128, 0, 0}, + {0, 0, 880, 144, 0, 0}, + {0, 0, 864, 160, 0, 0}, + {0, 0, 848, 176, 0, 0}, + {0, 0, 832, 192, 0, 0}, + {0, 0, 816, 208, 0, 0}, + {0, 0, 800, 224, 0, 0}, + {0, 0, 784, 240, 0, 0}, + {0, 0, 768, 256, 0, 0}, + {0, 0, 752, 272, 0, 0}, + {0, 0, 736, 288, 0, 0}, + {0, 0, 720, 304, 0, 0}, + {0, 0, 704, 320, 0, 0}, + {0, 0, 688, 336, 0, 0}, + {0, 0, 672, 352, 0, 0}, + {0, 0, 656, 368, 0, 0}, + {0, 0, 640, 384, 0, 0}, + {0, 0, 624, 400, 0, 0}, + {0, 0, 608, 416, 0, 0}, + {0, 0, 592, 432, 0, 0}, + {0, 0, 576, 448, 0, 0}, + {0, 0, 560, 464, 0, 0}, + {0, 0, 544, 480, 0, 0}, + {0, 0, 528, 496, 0, 0}, + {0, 0, 512, 512, 0, 0} + } +}; + +static void hisi_dss_scl_init(char __iomem *scl_base, dss_scl_t *s_scl) +{ + BUG_ON(scl_base == NULL); + BUG_ON(s_scl == NULL); + + memset(s_scl, 0, sizeof(dss_scl_t)); + + s_scl->en_hscl_str = inp32(scl_base + SCF_EN_HSCL_STR); + s_scl->en_vscl_str = inp32(scl_base + SCF_EN_VSCL_STR); + s_scl->h_v_order = inp32(scl_base + SCF_H_V_ORDER); + s_scl->input_width_height = inp32(scl_base + SCF_INPUT_WIDTH_HEIGHT); + s_scl->output_width_height = inp32(scl_base + SCF_OUTPUT_WIDTH_HEIGHT); + s_scl->en_hscl = inp32(scl_base + SCF_EN_HSCL); + s_scl->en_vscl = inp32(scl_base + SCF_EN_VSCL); + s_scl->acc_hscl = inp32(scl_base + SCF_ACC_HSCL); + s_scl->inc_hscl = inp32(scl_base + SCF_INC_HSCL); + s_scl->inc_vscl = inp32(scl_base + SCF_INC_VSCL); + s_scl->en_mmp = inp32(scl_base + SCF_EN_MMP); +} + +void hisi_dss_scl_set_reg(struct hisi_fb_data_type *hisifd, + char __iomem *scl_base, dss_scl_t *s_scl) +{ + BUG_ON(scl_base == NULL); + BUG_ON(s_scl == NULL); + + if (hisifd) { + hisifd->set_reg(hisifd, scl_base + SCF_EN_HSCL_STR, + s_scl->en_hscl_str, 32, 0); + hisifd->set_reg(hisifd, scl_base + SCF_EN_VSCL_STR, + s_scl->en_vscl_str, 32, 0); + hisifd->set_reg(hisifd, scl_base + SCF_H_V_ORDER, + s_scl->h_v_order, 32, 0); + hisifd->set_reg(hisifd, scl_base + SCF_INPUT_WIDTH_HEIGHT, + s_scl->input_width_height, 32, 0); + hisifd->set_reg(hisifd, scl_base + SCF_OUTPUT_WIDTH_HEIGHT, + s_scl->output_width_height, 32, 0); + hisifd->set_reg(hisifd, scl_base + SCF_EN_HSCL, + s_scl->en_hscl, 32, 0); + hisifd->set_reg(hisifd, scl_base + SCF_EN_VSCL, + s_scl->en_vscl, 32, 0); + hisifd->set_reg(hisifd, scl_base + SCF_ACC_HSCL, + s_scl->acc_hscl, 32, 0); + hisifd->set_reg(hisifd, scl_base + SCF_INC_HSCL, + s_scl->inc_hscl, 32, 0); + hisifd->set_reg(hisifd, scl_base + SCF_INC_VSCL, + s_scl->inc_vscl, 32, 0); + hisifd->set_reg(hisifd, scl_base + SCF_EN_MMP, + s_scl->en_mmp, 32, 0); + } else { + set_reg(scl_base + SCF_EN_HSCL_STR, s_scl->en_hscl_str, 32, 0); + set_reg(scl_base + SCF_EN_VSCL_STR, s_scl->en_vscl_str, 32, 0); + set_reg(scl_base + SCF_H_V_ORDER, s_scl->h_v_order, 32, 0); + set_reg(scl_base + SCF_INPUT_WIDTH_HEIGHT, + s_scl->input_width_height, 32, 0); + set_reg(scl_base + SCF_OUTPUT_WIDTH_HEIGHT, + s_scl->output_width_height, 32, 0); + set_reg(scl_base + SCF_EN_HSCL, s_scl->en_hscl, 32, 0); + set_reg(scl_base + SCF_EN_VSCL, s_scl->en_vscl, 32, 0); + set_reg(scl_base + SCF_ACC_HSCL, s_scl->acc_hscl, 32, 0); + set_reg(scl_base + SCF_INC_HSCL, s_scl->inc_hscl, 32, 0); + set_reg(scl_base + SCF_INC_VSCL, s_scl->inc_vscl, 32, 0); + set_reg(scl_base + SCF_EN_MMP, s_scl->en_mmp, 32, 0); + } +} + +int hisi_dss_scl_write_coefs(struct hisi_fb_data_type *hisifd, + bool enable_cmdlist, char __iomem *addr, + const int **p, int row, int col) +{ + int groups[3] = { 0 }; + int offset = 0; + int valid_num = 0; + int i = 0; + int j = 0; + int k = 0; + + BUG_ON(hisifd == NULL); + BUG_ON(addr == NULL); + + if ((row != PHASE_NUM) || (col < TAP4 || col > TAP6)) { + HISI_FB_ERR + ("SCF filter coefficients is err, phase_num = %d, tap_num = %d\n", + row, col); + return -EINVAL; + } + + /*byte */ + offset = (col == TAP4) ? 8 : 16; + valid_num = (offset == 16) ? 3 : 2; + + for (i = 0; i < row; i++) { + for (j = 0; j < col; j += 2) { + if ((col % 2) && (j == col - 1)) { + groups[j / 2] = + (*((int *)p + i * col + j) & 0xFFF) | (0 << + 16); + } else { + groups[j / 2] = + (*((int *)p + i * col + j) & 0xFFF) | + (*((int *)p + i * col + j + 1) << 16); + } + } + + for (k = 0; k < valid_num; k++) { + if (enable_cmdlist) { + hisifd->set_reg(hisifd, + addr + offset * i + + k * sizeof(int), groups[k], 32, + 0); + } else { + set_reg(addr + offset * i + k * sizeof(int), + groups[k], 32, 0); + } + groups[k] = 0; + } + } + + return 0; +} + +int hisi_dss_chn_scl_load_filter_coef_set_reg(struct hisi_fb_data_type *hisifd, + bool enable_cmdlist, int chn_idx, + uint32_t format) +{ + uint32_t module_base = 0; + char __iomem *h0_y_addr = NULL; + char __iomem *y_addr = NULL; + char __iomem *uv_addr = NULL; + int ret = 0; + int chn_coef_idx = SCL_COEF_YUV_IDX; + + BUG_ON(hisifd == NULL); + if ((chn_idx != DSS_RCHN_V0) && (chn_idx != DSS_RCHN_V1) + && (chn_idx != DSS_RCHN_V2)) + return 0; + + if (isYUV(format)) { + chn_coef_idx = SCL_COEF_YUV_IDX; + } else { + chn_coef_idx = SCL_COEF_RGB_IDX; + } + + if (g_scf_lut_chn_coef_idx[chn_idx] == chn_coef_idx) + return 0; + + g_scf_lut_chn_coef_idx[chn_idx] = chn_coef_idx; + + module_base = g_dss_module_base[chn_idx][MODULE_SCL_LUT]; + BUG_ON(module_base == 0); + + h0_y_addr = hisifd->dss_base + module_base + DSS_SCF_H0_Y_COEF_OFFSET; + y_addr = hisifd->dss_base + module_base + DSS_SCF_Y_COEF_OFFSET; + uv_addr = hisifd->dss_base + module_base + DSS_SCF_UV_COEF_OFFSET; + + ret = + hisi_dss_scl_write_coefs(hisifd, enable_cmdlist, h0_y_addr, + (const int **)COEF_LUT_TAP6[chn_coef_idx], + PHASE_NUM, TAP6); + if (ret < 0) { + HISI_FB_ERR("Error to write H0_Y_COEF coefficients.\n"); + } + + ret = + hisi_dss_scl_write_coefs(hisifd, enable_cmdlist, y_addr, + (const int **)COEF_LUT_TAP5[chn_coef_idx], + PHASE_NUM, TAP5); + if (ret < 0) { + HISI_FB_ERR("Error to write Y_COEF coefficients.\n"); + } + + ret = + hisi_dss_scl_write_coefs(hisifd, enable_cmdlist, uv_addr, + (const int **)COEF_LUT_TAP4[chn_coef_idx], + PHASE_NUM, TAP4); + if (ret < 0) { + HISI_FB_ERR("Error to write UV_COEF coefficients.\n"); + } + + return ret; +} + +int hisi_dss_scl_coef_on(struct hisi_fb_data_type *hisifd, bool enable_cmdlist, + int coef_lut_idx) +{ + int i = 0; + uint32_t module_base = 0; + char __iomem *h0_y_addr = NULL; + char __iomem *y_addr = NULL; + char __iomem *uv_addr = NULL; + int ret = 0; + + BUG_ON(hisifd == NULL); + + for (i = 0; i < DSS_CHN_MAX_DEFINE; i++) { + module_base = g_dss_module_base[i][MODULE_SCL_LUT]; + if (module_base != 0) { + h0_y_addr = + hisifd->dss_base + module_base + + DSS_SCF_H0_Y_COEF_OFFSET; + y_addr = + hisifd->dss_base + module_base + + DSS_SCF_Y_COEF_OFFSET; + uv_addr = + hisifd->dss_base + module_base + + DSS_SCF_UV_COEF_OFFSET; + + g_scf_lut_chn_coef_idx[i] = coef_lut_idx; + + ret = + hisi_dss_scl_write_coefs(hisifd, enable_cmdlist, + h0_y_addr, + (const int **) + COEF_LUT_TAP6 + [coef_lut_idx], PHASE_NUM, + TAP6); + if (ret < 0) { + HISI_FB_ERR + ("Error to write H0_Y_COEF coefficients.\n"); + } + + if (i == DSS_RCHN_V0) { + hisi_dss_arsr2p_coef_on(hisifd, enable_cmdlist); + continue; + } + + ret = + hisi_dss_scl_write_coefs(hisifd, enable_cmdlist, y_addr, + (const int **)COEF_LUT_TAP5[coef_lut_idx], + PHASE_NUM, TAP5); + if (ret < 0) { + HISI_FB_ERR + ("Error to write Y_COEF coefficients.\n"); + } + + ret = + hisi_dss_scl_write_coefs(hisifd, enable_cmdlist, uv_addr, + (const int **)COEF_LUT_TAP4[coef_lut_idx], + PHASE_NUM, TAP4); + if (ret < 0) { + HISI_FB_ERR + ("Error to write UV_COEF coefficients.\n"); + } + } + } + + return 0; +} + +int hisi_dss_scl_config(struct hisi_fb_data_type *hisifd, + dss_layer_t *layer, dss_rect_t *aligned_rect, + bool rdma_stretch_enable) +{ + dss_scl_t *scl = NULL; + dss_rect_t src_rect; + dss_rect_t dst_rect; + uint32_t need_cap = 0; + int chn_idx = 0; + uint32_t transform = 0; + dss_block_info_t *pblock_info = NULL; + + bool has_pixel_alpha = false; + bool en_hscl = false; + bool en_vscl = false; + bool en_mmp = false; + uint32_t h_ratio = 0; + uint32_t v_ratio = 0; + uint32_t h_v_order = 0; + uint32_t acc_hscl = 0; + uint32_t acc_vscl = 0; + uint32_t scf_en_vscl = 0; + + BUG_ON(hisifd == NULL); + BUG_ON(layer == NULL); + + need_cap = layer->need_cap; + chn_idx = layer->chn_idx; + transform = layer->transform; + if (aligned_rect) + src_rect = *aligned_rect; + else + src_rect = layer->src_rect; + dst_rect = layer->dst_rect; + pblock_info = &(layer->block_info); + + if (pblock_info && pblock_info->both_vscfh_arsr2p_used) { + dst_rect = pblock_info->arsr2p_in_rect; + } + + if (chn_idx == DSS_RCHN_V0) { + dst_rect.h = src_rect.h; + } + + do { + if (chn_idx == DSS_RCHN_V0 && pblock_info->h_ratio_arsr2p + && pblock_info->h_ratio) { + h_ratio = pblock_info->h_ratio; + en_hscl = true; + break; + } else if (chn_idx == DSS_RCHN_V0 && !pblock_info->h_ratio + && pblock_info->h_ratio_arsr2p) { + break; + } + + if (pblock_info && (pblock_info->h_ratio != 0) + && (pblock_info->h_ratio != SCF_INC_FACTOR)) { + h_ratio = pblock_info->h_ratio; + en_hscl = true; + break; + } + + if (chn_idx == DSS_RCHN_V0) { + dst_rect.w = + (src_rect.w > dst_rect.w ? dst_rect.w : src_rect.w); + } + + if (src_rect.w == dst_rect.w) + break; + + en_hscl = true; + + if ((src_rect.w < SCF_MIN_INPUT) + || (dst_rect.w < SCF_MIN_OUTPUT)) { + HISI_FB_ERR + ("src_rect.w(%d) small than 16, " + "or dst_rect.w(%d) small than 16\n", + src_rect.w, dst_rect.w); + return -EINVAL; + } + + h_ratio = + (DSS_HEIGHT(src_rect.w) * SCF_INC_FACTOR + + SCF_INC_FACTOR / 2 - acc_hscl) / DSS_HEIGHT(dst_rect.w); + + if ((dst_rect.w > (src_rect.w * SCF_UPSCALE_MAX)) + || (src_rect.w > (dst_rect.w * SCF_DOWNSCALE_MAX))) { + HISI_FB_ERR + ("width out of range, original_src_rec(%d, %d, %d, %d) " + "new_src_rect(%d, %d, %d, %d), " + "dst_rect(%d, %d, %d, %d), rdma_stretch_enable=%d\n", + layer->src_rect.x, layer->src_rect.y, + layer->src_rect.w, layer->src_rect.h, src_rect.x, + src_rect.y, src_rect.w, src_rect.h, dst_rect.x, + dst_rect.y, dst_rect.w, dst_rect.h, + rdma_stretch_enable); + + return -EINVAL; + } + } while (0); + + do { + if (src_rect.h == dst_rect.h) + break; + + en_vscl = true; + scf_en_vscl = 1; + + v_ratio = + (DSS_HEIGHT(src_rect.h) * SCF_INC_FACTOR + + SCF_INC_FACTOR / 2 - acc_vscl) / DSS_HEIGHT(dst_rect.h); + + if ((dst_rect.h > (src_rect.h * SCF_UPSCALE_MAX)) + || (src_rect.h > (dst_rect.h * SCF_DOWNSCALE_MAX))) { + HISI_FB_ERR + ("height out of range, original_src_rec(%d, %d, %d, %d) " + "new_src_rect(%d, %d, %d, %d), " + "dst_rect(%d, %d, %d, %d), rdma_stretch_enable=%d.\n", + layer->src_rect.x, layer->src_rect.y, + layer->src_rect.w, layer->src_rect.h, src_rect.x, + src_rect.y, src_rect.w, src_rect.h, dst_rect.x, + dst_rect.y, dst_rect.w, dst_rect.h, + rdma_stretch_enable); + return -EINVAL; + } + } while (0); + + if (!en_hscl && !en_vscl) { + return 0; + } + + /* scale down, do hscl first; scale up, do vscl first */ + h_v_order = (src_rect.w > dst_rect.w) ? 0 : 1; + + if (pblock_info && (pblock_info->acc_hscl != 0)) { + acc_hscl = pblock_info->acc_hscl; + } + + scl = &(hisifd->dss_module.scl[chn_idx]); + hisifd->dss_module.scl_used[chn_idx] = 1; + + has_pixel_alpha = hal_format_has_alpha(layer->img.format); + + scl->en_hscl_str = set_bits32(scl->en_hscl_str, 0x0, 1, 0); + + if (v_ratio >= 2 * SCF_INC_FACTOR) { + if (has_pixel_alpha) + scl->en_vscl_str = + set_bits32(scl->en_vscl_str, 0x3, 2, 0); + else + scl->en_vscl_str = + set_bits32(scl->en_vscl_str, 0x1, 2, 0); + } else { + scl->en_vscl_str = set_bits32(scl->en_vscl_str, 0x0, 1, 0); + } + + if (src_rect.h > dst_rect.h) { + scf_en_vscl = 0x3; + } + en_mmp = 0x1; + + scl->h_v_order = set_bits32(scl->h_v_order, h_v_order, 1, 0); + scl->input_width_height = set_bits32(scl->input_width_height, + DSS_HEIGHT(src_rect.h), 13, 0); + scl->input_width_height = set_bits32(scl->input_width_height, + DSS_WIDTH(src_rect.w), 13, 16); + scl->output_width_height = set_bits32(scl->output_width_height, + DSS_HEIGHT(dst_rect.h), 13, 0); + scl->output_width_height = set_bits32(scl->output_width_height, + DSS_WIDTH(dst_rect.w), 13, 16); + scl->en_hscl = set_bits32(scl->en_hscl, (en_hscl ? 0x1 : 0x0), 1, 0); + scl->en_vscl = set_bits32(scl->en_vscl, scf_en_vscl, 2, 0); + scl->acc_hscl = set_bits32(scl->acc_hscl, acc_hscl, 31, 0); + scl->inc_hscl = set_bits32(scl->inc_hscl, h_ratio, 24, 0); + scl->inc_vscl = set_bits32(scl->inc_vscl, v_ratio, 24, 0); + scl->en_mmp = set_bits32(scl->en_mmp, en_mmp, 1, 0); + scl->fmt = layer->img.format; + + return 0; +} + +static void hisi_dss_post_scf_init(char __iomem *post_scf_base, + dss_arsr1p_t *s_post_scf) +{ + BUG_ON(post_scf_base == NULL); + BUG_ON(s_post_scf == NULL); + + memset(s_post_scf, 0, sizeof(dss_arsr1p_t)); + + s_post_scf->ihleft = inp32(post_scf_base + ARSR1P_IHLEFT); + s_post_scf->ihright = inp32(post_scf_base + ARSR1P_IHRIGHT); + s_post_scf->ihleft1 = inp32(post_scf_base + ARSR1P_IHLEFT1); + s_post_scf->ihright1 = inp32(post_scf_base + ARSR1P_IHRIGHT1); + s_post_scf->ivtop = inp32(post_scf_base + ARSR1P_IVTOP); + s_post_scf->ivbottom = inp32(post_scf_base + ARSR1P_IVBOTTOM); + s_post_scf->uv_offset = inp32(post_scf_base + ARSR1P_UV_OFFSET); + s_post_scf->ihinc = inp32(post_scf_base + ARSR1P_IHINC); + s_post_scf->ivinc = inp32(post_scf_base + ARSR1P_IVINC); + s_post_scf->mode = inp32(post_scf_base + ARSR1P_MODE); + s_post_scf->format = inp32(post_scf_base + ARSR1P_FORMAT); + + s_post_scf->skin_thres_y = inp32(post_scf_base + ARSR1P_SKIN_THRES_Y); + s_post_scf->skin_thres_u = inp32(post_scf_base + ARSR1P_SKIN_THRES_U); + s_post_scf->skin_thres_v = inp32(post_scf_base + ARSR1P_SKIN_THRES_V); + s_post_scf->skin_expected = inp32(post_scf_base + ARSR1P_SKIN_EXPECTED); + s_post_scf->skin_cfg = inp32(post_scf_base + ARSR1P_SKIN_CFG); + s_post_scf->shoot_cfg1 = inp32(post_scf_base + ARSR1P_SHOOT_CFG1); + s_post_scf->shoot_cfg2 = inp32(post_scf_base + ARSR1P_SHOOT_CFG2); + s_post_scf->sharp_cfg1 = inp32(post_scf_base + ARSR1P_SHARP_CFG1); + s_post_scf->sharp_cfg2 = inp32(post_scf_base + ARSR1P_SHARP_CFG2); + s_post_scf->sharp_cfg3 = inp32(post_scf_base + ARSR1P_SHARP_CFG3); + s_post_scf->sharp_cfg4 = inp32(post_scf_base + ARSR1P_SHARP_CFG4); + s_post_scf->sharp_cfg5 = inp32(post_scf_base + ARSR1P_SHARP_CFG5); + s_post_scf->sharp_cfg6 = inp32(post_scf_base + ARSR1P_SHARP_CFG6); + s_post_scf->sharp_cfg7 = inp32(post_scf_base + ARSR1P_SHARP_CFG7); + s_post_scf->sharp_cfg8 = inp32(post_scf_base + ARSR1P_SHARP_CFG8); + s_post_scf->sharp_cfg9 = inp32(post_scf_base + ARSR1P_SHARP_CFG9); + s_post_scf->sharp_cfg10 = inp32(post_scf_base + ARSR1P_SHARP_CFG10); + s_post_scf->sharp_cfg11 = inp32(post_scf_base + ARSR1P_SHARP_CFG11); + s_post_scf->diff_ctrl = inp32(post_scf_base + ARSR1P_DIFF_CTRL); + s_post_scf->lsc_cfg1 = inp32(post_scf_base + ARSR1P_LSC_CFG1); + s_post_scf->lsc_cfg2 = inp32(post_scf_base + ARSR1P_LSC_CFG2); + s_post_scf->lsc_cfg3 = inp32(post_scf_base + ARSR1P_LSC_CFG3); + s_post_scf->force_clk_on_cfg = + inp32(post_scf_base + ARSR1P_FORCE_CLK_ON_CFG); +} + +static void hisi_dss_post_scf_set_reg(struct hisi_fb_data_type *hisifd, + char __iomem *post_scf_base, + dss_arsr1p_t *s_post_scf) +{ + BUG_ON(hisifd == NULL); + BUG_ON(post_scf_base == NULL); + BUG_ON(s_post_scf == NULL); + + hisifd->set_reg(hisifd, + hisifd->dss_base + DSS_DPP_OFFSET + DPP_IMG_SIZE_BEF_SR, + ((DSS_HEIGHT(s_post_scf->dpp_img_vrt_bef_sr) << 16) | + (DSS_WIDTH(s_post_scf->dpp_img_hrz_bef_sr))), 32, 0); + hisifd->set_reg(hisifd, + hisifd->dss_base + DSS_DPP_OFFSET + DPP_IMG_SIZE_AFT_SR, + ((DSS_HEIGHT(s_post_scf->dpp_img_vrt_aft_sr) << 16) | + (DSS_WIDTH(s_post_scf->dpp_img_hrz_aft_sr))), 32, 0); + + outp32(post_scf_base + ARSR1P_IHLEFT, s_post_scf->ihleft); + outp32(post_scf_base + ARSR1P_IHRIGHT, s_post_scf->ihright); + outp32(post_scf_base + ARSR1P_IHLEFT1, s_post_scf->ihleft1); + outp32(post_scf_base + ARSR1P_IHRIGHT1, s_post_scf->ihright1); + outp32(post_scf_base + ARSR1P_IVTOP, s_post_scf->ivtop); + outp32(post_scf_base + ARSR1P_IVBOTTOM, s_post_scf->ivbottom); + outp32(post_scf_base + ARSR1P_UV_OFFSET, s_post_scf->uv_offset); + outp32(post_scf_base + ARSR1P_IHINC, s_post_scf->ihinc); + outp32(post_scf_base + ARSR1P_IVINC, s_post_scf->ivinc); + outp32(post_scf_base + ARSR1P_MODE, s_post_scf->mode); + outp32(post_scf_base + ARSR1P_FORMAT, s_post_scf->format); + + outp32(post_scf_base + ARSR1P_SKIN_THRES_Y, s_post_scf->skin_thres_y); + outp32(post_scf_base + ARSR1P_SKIN_THRES_U, s_post_scf->skin_thres_u); + outp32(post_scf_base + ARSR1P_SKIN_THRES_V, s_post_scf->skin_thres_v); + outp32(post_scf_base + ARSR1P_SKIN_EXPECTED, s_post_scf->skin_expected); + outp32(post_scf_base + ARSR1P_SKIN_CFG, s_post_scf->skin_cfg); + outp32(post_scf_base + ARSR1P_SHOOT_CFG1, s_post_scf->shoot_cfg1); + outp32(post_scf_base + ARSR1P_SHOOT_CFG2, s_post_scf->shoot_cfg2); + outp32(post_scf_base + ARSR1P_SHARP_CFG1, s_post_scf->sharp_cfg1); + outp32(post_scf_base + ARSR1P_SHARP_CFG2, s_post_scf->sharp_cfg2); + outp32(post_scf_base + ARSR1P_SHARP_CFG3, s_post_scf->sharp_cfg3); + outp32(post_scf_base + ARSR1P_SHARP_CFG4, s_post_scf->sharp_cfg4); + outp32(post_scf_base + ARSR1P_SHARP_CFG5, s_post_scf->sharp_cfg5); + outp32(post_scf_base + ARSR1P_SHARP_CFG6, s_post_scf->sharp_cfg6); + outp32(post_scf_base + ARSR1P_SHARP_CFG7, s_post_scf->sharp_cfg7); + outp32(post_scf_base + ARSR1P_SHARP_CFG8, s_post_scf->sharp_cfg8); + outp32(post_scf_base + ARSR1P_SHARP_CFG9, s_post_scf->sharp_cfg9); + outp32(post_scf_base + ARSR1P_SHARP_CFG10, s_post_scf->sharp_cfg10); + outp32(post_scf_base + ARSR1P_SHARP_CFG11, s_post_scf->sharp_cfg11); + outp32(post_scf_base + ARSR1P_DIFF_CTRL, s_post_scf->diff_ctrl); + outp32(post_scf_base + ARSR1P_LSC_CFG1, s_post_scf->lsc_cfg1); + outp32(post_scf_base + ARSR1P_LSC_CFG2, s_post_scf->lsc_cfg2); + outp32(post_scf_base + ARSR1P_LSC_CFG3, s_post_scf->lsc_cfg3); + outp32(post_scf_base + ARSR1P_FORCE_CLK_ON_CFG, + s_post_scf->force_clk_on_cfg); +} + +int hisi_dss_post_scf_config(struct hisi_fb_data_type *hisifd, + dss_overlay_t *pov_req) +{ + struct hisi_panel_info *pinfo = NULL; + dss_rect_t src_rect = { 0 }; + dss_rect_t dst_rect = { 0 }; + dss_arsr1p_t *post_scf = NULL; + + int32_t ihinc = 0; + int32_t ivinc = 0; + int32_t ihleft = 0; + int32_t ihright = 0; + int32_t ihleft1 = 0; + int32_t ihright1 = 0; + int32_t ivtop = 0; + int32_t ivbottom = 0; + int32_t extraw = 0; + int32_t extraw_left = 0; + int32_t extraw_right = 0; + + BUG_ON(hisifd == NULL); + BUG_ON(pov_req == NULL); + pinfo = &(hisifd->panel_info); + + if (!HISI_DSS_SUPPORT_DPP_MODULE_BIT(DPP_MODULE_POST_SCF)) { + return 0; + } + + if ((pov_req->res_updt_rect.w == 0) && (pov_req->res_updt_rect.h == 0)) { + return 0; + } + + if ((pov_req->res_updt_rect.w < 0) || (pov_req->res_updt_rect.h < 0)) { + HISI_FB_ERR("fb%d, res_updt_rect[%d,%d, %d,%d] is invalid!\n", + hisifd->index, pov_req->res_updt_rect.x, + pov_req->res_updt_rect.y, pov_req->res_updt_rect.w, + pov_req->res_updt_rect.h); + return 0; + } + + if ((pov_req->res_updt_rect.w == hisifd->res_updt_rect.w) + && (pov_req->res_updt_rect.h == hisifd->res_updt_rect.h)) { + + return 0; + } + + HISI_FB_DEBUG + ("fb%d, post scf res_updt_rect[%d, %d]->lcd_rect[%d, %d]\n", + hisifd->index, pov_req->res_updt_rect.w, pov_req->res_updt_rect.h, + pinfo->xres, pinfo->yres); + + hisifd->res_updt_rect = pov_req->res_updt_rect; + + src_rect = pov_req->res_updt_rect; + dst_rect.x = 0; + dst_rect.y = 0; + dst_rect.w = pinfo->xres; + dst_rect.h = pinfo->yres; + + post_scf = &(hisifd->dss_module.post_scf); + hisifd->dss_module.post_scf_used = 1; + + if ((src_rect.w < 16) || (src_rect.h < 16) + || (src_rect.w > 3840) || (src_rect.h > 8192) + || (dst_rect.w > 8192) || (dst_rect.h > 8192)) { + HISI_FB_ERR + ("invalid input size: src_rect(%d,%d,%d,%d) " + "should be larger than 16*16, less than 3840*8192!\n" + "invalid output size: dst_rect(%d,%d,%d,%d) " + "should be less than 8192*8192!\n", + src_rect.x, src_rect.y, src_rect.w, src_rect.h, dst_rect.x, + dst_rect.y, dst_rect.w, dst_rect.h); + post_scf->mode = 0x1; + return 0; + } + + ihinc = ARSR1P_INC_FACTOR * src_rect.w / dst_rect.w; + ivinc = ARSR1P_INC_FACTOR * src_rect.h / dst_rect.h; + + if ((ihinc == ARSR1P_INC_FACTOR) + && (ivinc == ARSR1P_INC_FACTOR) + && (pinfo->arsr1p_sharpness_support != 1)) { + post_scf->mode = 0x1; + return 0; + } + + /* 0x2000<=ihinc<=0x80000; 0x2000<=ivinc<=0x80000; */ + if ((ihinc < 0x2000) || (ihinc > ARSR1P_INC_FACTOR) + || (ivinc < 0x2000) || (ivinc > ARSR1P_INC_FACTOR)) { + HISI_FB_ERR("invalid ihinc(0x%x), ivinc(0x%x)!\n", ihinc, + ivinc); + post_scf->mode = 0x1; + return -1; + } + + if ((ihinc > ARSR1P_INC_FACTOR) || (ivinc > ARSR1P_INC_FACTOR)) { + HISI_FB_ERR + ("scaling down is not supported by ARSR1P, " + "ihinc = 0x%x, ivinc = 0x%x\n", + ihinc, ivinc); + post_scf->mode = 0x1; + return -1; + } + + post_scf->mode = 0x0; + if (pinfo->arsr1p_sharpness_support) { + post_scf->mode |= 0xe; + } + + post_scf->mode |= 0x20; + if ((ihinc < ARSR1P_INC_FACTOR) || (ivinc < ARSR1P_INC_FACTOR)) { + post_scf->mode |= 0x10; + } else { + post_scf->mode |= 0x40; + } + + post_scf->dpp_img_hrz_bef_sr = src_rect.w; + post_scf->dpp_img_vrt_bef_sr = src_rect.h; + post_scf->dpp_img_hrz_aft_sr = dst_rect.w; + post_scf->dpp_img_vrt_aft_sr = dst_rect.h; + + extraw = (8 * ARSR1P_INC_FACTOR) / ihinc; + extraw_left = (extraw % 2) ? (extraw + 1) : (extraw); + extraw = (2 * ARSR1P_INC_FACTOR) / ihinc; + extraw_right = (extraw % 2) ? (extraw + 1) : (extraw); + + ihleft1 = dst_rect.x * ihinc - src_rect.x * ARSR1P_INC_FACTOR; + if (ihleft1 < 0) + ihleft1 = 0; + ihleft = ihleft1 - extraw_left * ihinc; + if (ihleft < 0) + ihleft = 0; + + ihright1 = ihleft1 + (dst_rect.w - 1) * ihinc; + ihright = ihright1 + extraw_right * ihinc; + if (ihright >= src_rect.w * ARSR1P_INC_FACTOR) + ihright = src_rect.w * ARSR1P_INC_FACTOR - 1; + + ivtop = dst_rect.y * ivinc - src_rect.y * ARSR1P_INC_FACTOR; + if (ivtop < 0) + ivtop = 0; + ivbottom = ivtop + (dst_rect.h - 1) * ivinc; + if (ivbottom >= src_rect.h * ARSR1P_INC_FACTOR) + ivbottom = src_rect.h * ARSR1P_INC_FACTOR - 1; + + if ((ihleft1 - ihleft) % (ihinc)) { + HISI_FB_ERR + ("(ihleft1(%d)-ihleft(%d)) ihinc(%d) != 0, invalid!\n", + ihleft1, ihleft, ihinc); + post_scf->mode = 0x1; + return -1; + } + + if ((ihright1 - ihleft1) % ihinc) { + HISI_FB_ERR + ("(ihright1(%d)-ihleft1(%d)) ihinc(%d) != 0, invalid!\n", + ihright1, ihleft1, ihinc); + post_scf->mode = 0x1; + return -1; + } + + post_scf->ihleft = set_bits32(post_scf->ihleft, ihleft, 32, 0); + post_scf->ihright = set_bits32(post_scf->ihright, ihright, 32, 0); + post_scf->ihleft1 = set_bits32(post_scf->ihleft1, ihleft1, 32, 0); + post_scf->ihright1 = set_bits32(post_scf->ihright1, ihright1, 32, 0); + post_scf->ivtop = set_bits32(post_scf->ivtop, ivtop, 32, 0); + post_scf->ivbottom = set_bits32(post_scf->ivbottom, ivbottom, 32, 0); + post_scf->ihinc = set_bits32(post_scf->ihinc, ihinc, 32, 0); + post_scf->ivinc = set_bits32(post_scf->ivinc, ivinc, 32, 0); + + post_scf->skin_thres_y = + set_bits32(post_scf->skin_thres_y, 0x534b, 32, 0); + post_scf->skin_thres_u = + set_bits32(post_scf->skin_thres_u, 0x330a05, 32, 0); + post_scf->skin_thres_v = + set_bits32(post_scf->skin_thres_v, 0xaa0c06, 32, 0); + post_scf->skin_expected = + set_bits32(post_scf->skin_expected, 0x917198, 32, 0); + post_scf->skin_cfg = set_bits32(post_scf->skin_cfg, 0x30a06, 32, 0); + post_scf->shoot_cfg1 = set_bits32(post_scf->shoot_cfg1, 0x14, 32, 0); + post_scf->shoot_cfg2 = set_bits32(post_scf->shoot_cfg2, 0x1f0, 32, 0); + post_scf->sharp_cfg1 = + set_bits32(post_scf->sharp_cfg1, 0x40300602, 32, 0); + post_scf->sharp_cfg2 = + set_bits32(post_scf->sharp_cfg2, 0x40300602, 32, 0); + post_scf->sharp_cfg3 = + set_bits32(post_scf->sharp_cfg3, 0x12c0000, 32, 0); + post_scf->sharp_cfg4 = set_bits32(post_scf->sharp_cfg4, 0x0, 32, 0); + post_scf->sharp_cfg5 = + set_bits32(post_scf->sharp_cfg5, 0x1900000, 32, 0); + post_scf->sharp_cfg6 = + set_bits32(post_scf->sharp_cfg6, 0xffff641e, 32, 0); + post_scf->sharp_cfg7 = + set_bits32(post_scf->sharp_cfg7, 0x1a00018, 32, 0); + post_scf->sharp_cfg8 = + set_bits32(post_scf->sharp_cfg8, 0x200640, 32, 0); + post_scf->sharp_cfg9 = + set_bits32(post_scf->sharp_cfg9, 0x2006400, 32, 0); + post_scf->sharp_cfg10 = set_bits32(post_scf->sharp_cfg10, 0x0, 32, 0); + post_scf->sharp_cfg11 = set_bits32(post_scf->sharp_cfg11, 0x0, 32, 0); + + post_scf->diff_ctrl = set_bits32(post_scf->diff_ctrl, 0x1410, 32, 0); + post_scf->lsc_cfg1 = set_bits32(post_scf->lsc_cfg1, 0x3c618410, 32, 0); + post_scf->lsc_cfg2 = set_bits32(post_scf->lsc_cfg2, 0x0, 32, 0); + post_scf->lsc_cfg3 = set_bits32(post_scf->lsc_cfg3, 0x800600, 32, 0); + + return 0; +} + +/******************************************************************************* + ** DSS POST_CLIP + */ +static void hisi_dss_post_clip_init(char __iomem *post_clip_base, + dss_post_clip_t *s_post_clip) +{ + BUG_ON(post_clip_base == NULL); + BUG_ON(s_post_clip == NULL); + + memset(s_post_clip, 0, sizeof(dss_post_clip_t)); +} + +int hisi_dss_post_clip_config(struct hisi_fb_data_type *hisifd, + dss_layer_t *layer) +{ + dss_post_clip_t *post_clip = NULL; + int chn_idx = 0; + dss_rect_t post_clip_rect; + + chn_idx = layer->chn_idx; + post_clip_rect = layer->dst_rect; + + if (((chn_idx >= DSS_RCHN_V0) && (chn_idx <= DSS_RCHN_G1)) + || (chn_idx == DSS_RCHN_V2)) { + post_clip = &(hisifd->dss_module.post_clip[chn_idx]); + hisifd->dss_module.post_cilp_used[chn_idx] = 1; + + post_clip->disp_size = + set_bits32(post_clip->disp_size, + DSS_HEIGHT(post_clip_rect.h), 13, 0); + post_clip->disp_size = + set_bits32(post_clip->disp_size, + DSS_WIDTH(post_clip_rect.w), 13, 16); + + if ((chn_idx == DSS_RCHN_V0) + && layer->block_info.arsr2p_left_clip) { + post_clip->clip_ctl_hrz = + set_bits32(post_clip->clip_ctl_hrz, + layer->block_info.arsr2p_left_clip, 6, 16); + post_clip->clip_ctl_hrz = + set_bits32(post_clip->clip_ctl_hrz, 0x0, 6, 0); + } else { + post_clip->clip_ctl_hrz = + set_bits32(post_clip->clip_ctl_hrz, 0x0, 32, 0); + } + + post_clip->clip_ctl_vrz = + set_bits32(post_clip->clip_ctl_vrz, 0x0, 32, 0); + post_clip->ctl_clip_en = + set_bits32(post_clip->ctl_clip_en, 0x1, 32, 0); + } + + return 0; +} + +void hisi_dss_post_clip_set_reg(struct hisi_fb_data_type *hisifd, + char __iomem *post_clip_base, + dss_post_clip_t *s_post_clip) +{ + BUG_ON(hisifd == NULL); + BUG_ON(post_clip_base == NULL); + BUG_ON(s_post_clip == NULL); + + hisifd->set_reg(hisifd, post_clip_base + POST_CLIP_DISP_SIZE, + s_post_clip->disp_size, 32, 0); + hisifd->set_reg(hisifd, post_clip_base + POST_CLIP_CTL_HRZ, + s_post_clip->clip_ctl_hrz, 32, 0); + hisifd->set_reg(hisifd, post_clip_base + POST_CLIP_CTL_VRZ, + s_post_clip->clip_ctl_vrz, 32, 0); + hisifd->set_reg(hisifd, post_clip_base + POST_CLIP_EN, + s_post_clip->ctl_clip_en, 32, 0); +} + +/******************************************************************************* + ** DSS MCTL + */ +static void hisi_dss_mctl_init(char __iomem *mctl_base, dss_mctl_t *s_mctl) +{ + BUG_ON(mctl_base == NULL); + BUG_ON(s_mctl == NULL); + + memset(s_mctl, 0, sizeof(dss_mctl_t)); +} + +static void hisi_dss_mctl_ch_starty_init(char __iomem *mctl_ch_starty_base, + dss_mctl_ch_t *s_mctl_ch) +{ + BUG_ON(mctl_ch_starty_base == NULL); + BUG_ON(s_mctl_ch == NULL); + + memset(s_mctl_ch, 0, sizeof(dss_mctl_ch_t)); + + s_mctl_ch->chn_starty = inp32(mctl_ch_starty_base); +} + +static void hisi_dss_mctl_ch_mod_dbg_init(char __iomem *mctl_ch_dbg_base, + dss_mctl_ch_t *s_mctl_ch) +{ + BUG_ON(mctl_ch_dbg_base == NULL); + BUG_ON(s_mctl_ch == NULL); + + s_mctl_ch->chn_mod_dbg = inp32(mctl_ch_dbg_base); +} + +static void hisi_dss_mctl_sys_init(char __iomem *mctl_sys_base, + dss_mctl_sys_t *s_mctl_sys) +{ + int i = 0; + + BUG_ON(mctl_sys_base == NULL); + BUG_ON(s_mctl_sys == NULL); + + memset(s_mctl_sys, 0, sizeof(dss_mctl_sys_t)); + + for (i = 0; i < DSS_OVL_IDX_MAX; i++) { + s_mctl_sys->chn_ov_sel[i] = 0xFFFFFFFF; + } + + for (i = 0; i < DSS_WCH_MAX; i++) { + s_mctl_sys->wchn_ov_sel[i] = 0x0; + } +} + +static void hisi_dss_mctl_sys_set_reg(struct hisi_fb_data_type *hisifd, + char __iomem *mctl_sys_base, + dss_mctl_sys_t *s_mctl_sys, int ovl_idx) +{ + int k = 0; + + BUG_ON(hisifd == NULL); + BUG_ON(mctl_sys_base == NULL); + BUG_ON(s_mctl_sys == NULL); + BUG_ON((ovl_idx < DSS_OVL0) || (ovl_idx >= DSS_OVL_IDX_MAX)); + + if (s_mctl_sys->chn_ov_sel_used[ovl_idx]) { + hisifd->set_reg(hisifd, + mctl_sys_base + MCTL_RCH_OV0_SEL + ovl_idx * 0x4, + s_mctl_sys->chn_ov_sel[ovl_idx], 32, 0); + } + + for (k = 0; k < DSS_WCH_MAX; k++) { + if (s_mctl_sys->wch_ov_sel_used[k]) { + hisifd->set_reg(hisifd, + mctl_sys_base + MCTL_WCH_OV2_SEL + k * 0x4, + s_mctl_sys->wchn_ov_sel[k], 32, 0); + } + } + + if (s_mctl_sys->ov_flush_en_used[ovl_idx]) { + hisifd->set_reg(hisifd, + mctl_sys_base + MCTL_OV0_FLUSH_EN + ovl_idx * 0x4, + s_mctl_sys->ov_flush_en[ovl_idx], 32, 0); + } +} + +static void hisi_dss_mctl_ov_set_reg(struct hisi_fb_data_type *hisifd, + char __iomem *mctl_base, + dss_mctl_t *s_mctl, int ovl_idx, + bool enable_cmdlist) +{ + BUG_ON(hisifd == NULL); + BUG_ON(mctl_base == NULL); + BUG_ON(s_mctl == NULL); + BUG_ON((ovl_idx < DSS_OVL0) || (ovl_idx >= DSS_OVL_IDX_MAX)); + + if ((ovl_idx == DSS_OVL0) || (ovl_idx == DSS_OVL1)) { + hisifd->set_reg(hisifd, mctl_base + MCTL_CTL_MUTEX_DBUF, + s_mctl->ctl_mutex_dbuf, 32, 0); + hisi_dss_mctl_ov_set_ctl_dbg_reg(hisifd, mctl_base, + enable_cmdlist); + } + + hisifd->set_reg(hisifd, mctl_base + MCTL_CTL_MUTEX_OV, + s_mctl->ctl_mutex_ov, 32, 0); +} + +static void hisi_dss_mctl_ch_set_reg(struct hisi_fb_data_type *hisifd, + dss_mctl_ch_base_t *mctl_ch_base, + dss_mctl_ch_t *s_mctl_ch, + int32_t mctl_idx) +{ + char __iomem *chn_mutex_base = NULL; + int i = 0; + + BUG_ON(hisifd == NULL); + BUG_ON(mctl_ch_base == NULL); + BUG_ON(s_mctl_ch == NULL); + BUG_ON((mctl_idx < DSS_MCTL0) || (mctl_idx >= DSS_MCTL_IDX_MAX)); + + for (i = 0; i < DSS_MCTL_IDX_MAX; i++) { + if (g_dss_module_ovl_base[i][MODULE_MCTL_BASE] == 0) + continue; + chn_mutex_base = mctl_ch_base->chn_mutex_base + + g_dss_module_ovl_base[i][MODULE_MCTL_BASE]; + + if (i != mctl_idx) { + hisifd->set_reg(hisifd, chn_mutex_base, 0, 32, 0); + } + } + + chn_mutex_base = mctl_ch_base->chn_mutex_base + + g_dss_module_ovl_base[mctl_idx][MODULE_MCTL_BASE]; + BUG_ON(chn_mutex_base == NULL); + + hisifd->set_reg(hisifd, chn_mutex_base, s_mctl_ch->chn_mutex, 32, 0); +} + +static void hisi_dss_mctl_sys_ch_set_reg(struct hisi_fb_data_type *hisifd, + dss_mctl_ch_base_t *mctl_ch_base, + dss_mctl_ch_t *s_mctl_ch, int chn_idx, + bool normal) +{ + char __iomem *mctl_sys_base = NULL; + + BUG_ON(hisifd == NULL); + BUG_ON(mctl_ch_base == NULL); + BUG_ON(s_mctl_ch == NULL); + + mctl_sys_base = hisifd->dss_base + DSS_MCTRL_SYS_OFFSET; + + if (normal == true) { + if (chn_idx == DSS_RCHN_V2) { + hisifd->set_reg(hisifd, mctl_sys_base + MCTL_MOD19_DBG, + 0xA0000, 32, 0); + } + + if (chn_idx == DSS_WCHN_W2) { + hisifd->set_reg(hisifd, mctl_sys_base + MCTL_MOD20_DBG, + 0xA0000, 32, 0); + } + } + + if (normal == false) { + if (chn_idx == DSS_RCHN_V2) { + hisifd->set_reg(hisifd, mctl_sys_base + MCTL_MOD19_DBG, + 0xA0002, 32, 0); + } + + if (chn_idx == DSS_WCHN_W2) { + hisifd->set_reg(hisifd, mctl_sys_base + MCTL_MOD20_DBG, + 0xA0002, 32, 0); + } + } + + if (mctl_ch_base->chn_ov_en_base) { + hisifd->set_reg(hisifd, mctl_ch_base->chn_ov_en_base, + s_mctl_ch->chn_ov_oen, 32, 0); + } + + hisifd->set_reg(hisifd, mctl_ch_base->chn_flush_en_base, + s_mctl_ch->chn_flush_en, 32, 0); +} + +void hisi_dss_mctl_mutex_lock(struct hisi_fb_data_type *hisifd, int ovl_idx) +{ + char __iomem *mctl_base = NULL; + + BUG_ON(hisifd == NULL); + BUG_ON((ovl_idx < DSS_OVL0) || (ovl_idx >= DSS_OVL_IDX_MAX)); + + mctl_base = hisifd->dss_module.mctl_base[ovl_idx]; + + hisifd->set_reg(hisifd, mctl_base + MCTL_CTL_MUTEX, 0x1, 1, 0); +} + +void hisi_dss_mctl_mutex_unlock(struct hisi_fb_data_type *hisifd, int ovl_idx) +{ + char __iomem *mctl_base = NULL; + + BUG_ON(hisifd == NULL); + BUG_ON((ovl_idx < DSS_OVL0) || (ovl_idx >= DSS_OVL_IDX_MAX)); + + mctl_base = hisifd->dss_module.mctl_base[ovl_idx]; + + hisifd->set_reg(hisifd, mctl_base + MCTL_CTL_MUTEX, 0x0, 1, 0); +} + +void hisi_dss_mctl_on(struct hisi_fb_data_type *hisifd, int mctl_idx, + bool enable_cmdlist, bool fastboot_enable) +{ + char __iomem *mctl_base = NULL; + char __iomem *mctl_sys_base = NULL; + int i = 0; + int tmp = 0; + + BUG_ON(hisifd == NULL); + BUG_ON((mctl_idx < DSS_MCTL0) || (mctl_idx >= DSS_MCTL_IDX_MAX)); + + mctl_base = hisifd->dss_base + + g_dss_module_ovl_base[mctl_idx][MODULE_MCTL_BASE]; + mctl_sys_base = hisifd->dss_base + DSS_MCTRL_SYS_OFFSET; + + set_reg(mctl_base + MCTL_CTL_EN, 0x1, 32, 0); + + if ((mctl_idx == DSS_MCTL0) || (mctl_idx == DSS_MCTL1)) { + set_reg(mctl_base + MCTL_CTL_MUTEX_ITF, mctl_idx + 1, 32, 0); + } + + if (enable_cmdlist) { + tmp = MCTL_MOD_DBG_CH_NUM + MCTL_MOD_DBG_OV_NUM + + MCTL_MOD_DBG_DBUF_NUM + MCTL_MOD_DBG_SCF_NUM; + for (i = 0; i < tmp; i++) { + set_reg(mctl_sys_base + MCTL_MOD0_DBG + i * 0x4, + 0xA0000, 32, 0); + } + + for (i = 0; i < MCTL_MOD_DBG_ITF_NUM; i++) { + set_reg(mctl_sys_base + MCTL_MOD17_DBG + i * 0x4, + 0xA0F00, 32, 0); + } + + if (!fastboot_enable) { + set_reg(mctl_base + MCTL_CTL_TOP, 0x1, 32, 0); + } + } else { + set_reg(mctl_base + MCTL_CTL_DBG, 0xB13A00, 32, 0); + if (is_mipi_cmd_panel(hisifd)) { + set_reg(mctl_base + MCTL_CTL_TOP, 0x1, 32, 0); + } else { + if (mctl_idx == DSS_MCTL0) { + set_reg(mctl_base + MCTL_CTL_TOP, 0x2, 32, 0); + } else if (mctl_idx == DSS_MCTL1) { + set_reg(mctl_base + MCTL_CTL_TOP, 0x3, 32, 0); + } else { + set_reg(mctl_base + MCTL_CTL_TOP, 0x1, 32, 0); + } + } + } +} + +int hisi_dss_mctl_ch_config(struct hisi_fb_data_type *hisifd, + dss_overlay_t *pov_req, dss_layer_t *layer, + dss_wb_layer_t *wb_layer, int ovl_idx, + dss_rect_t *wb_ov_block_rect, bool has_base) +{ + int chn_idx = 0; + int layer_idx = 0; + dss_mctl_ch_t *mctl_ch = NULL; + dss_mctl_sys_t *mctl_sys = NULL; + + BUG_ON(hisifd == NULL); + BUG_ON(pov_req == NULL); + BUG_ON((layer == NULL) && (wb_layer == NULL)); + + if (wb_layer) { + chn_idx = wb_layer->chn_idx; + + mctl_sys = &(hisifd->dss_module.mctl_sys); + hisifd->dss_module.mctl_sys_used = 1; + + mctl_ch = &(hisifd->dss_module.mctl_ch[chn_idx]); + hisifd->dss_module.mctl_ch_used[chn_idx] = 1; + + if (chn_idx != DSS_WCHN_W2) { + mctl_ch->chn_ov_oen = set_bits32(mctl_ch->chn_ov_oen, + (ovl_idx - 1), 32, 0); + + if (pov_req->wb_layer_nums == MAX_DSS_DST_NUM) { + mctl_sys->wchn_ov_sel[0] = + set_bits32(mctl_sys->wchn_ov_sel[0], 3, 32, 0); + mctl_sys->wch_ov_sel_used[0] = 1; + mctl_sys->wchn_ov_sel[1] = + set_bits32(mctl_sys->wchn_ov_sel[1], 3, 32, 0); + mctl_sys->wch_ov_sel_used[1] = 1; + } else { + mctl_sys->wchn_ov_sel[ovl_idx - DSS_OVL2] = + set_bits32(mctl_sys->wchn_ov_sel[ovl_idx - DSS_OVL2], + (chn_idx - DSS_WCHN_W0 + 1), 32, 0); + mctl_sys->wch_ov_sel_used[ovl_idx - DSS_OVL2] = 1; + } + } + + mctl_ch->chn_mutex = set_bits32(mctl_ch->chn_mutex, 0x1, 1, 0); + mctl_ch->chn_flush_en = + set_bits32(mctl_ch->chn_flush_en, 0x1, 1, 0); + } else { + chn_idx = layer->chn_idx; + layer_idx = layer->layer_idx; + + if (layer->need_cap & CAP_BASE) + return 0; + + if (has_base) { + layer_idx -= 1; + if (layer_idx < 0) { + HISI_FB_ERR + ("fb%d, layer_idx(%d) is out of range!", + hisifd->index, layer_idx); + return -EINVAL; + } + } + + mctl_sys = &(hisifd->dss_module.mctl_sys); + hisifd->dss_module.mctl_sys_used = 1; + + if (layer->need_cap & (CAP_DIM | CAP_PURE_COLOR)) { + mctl_sys->chn_ov_sel[ovl_idx] = + set_bits32(mctl_sys->chn_ov_sel[ovl_idx], 0x8, 4, + (layer_idx + 1) * 4); + mctl_sys->chn_ov_sel_used[ovl_idx] = 1; + } else { + mctl_ch = &(hisifd->dss_module.mctl_ch[chn_idx]); + hisifd->dss_module.mctl_ch_used[chn_idx] = 1; + + mctl_ch->chn_mutex = + set_bits32(mctl_ch->chn_mutex, 0x1, 1, 0); + mctl_ch->chn_flush_en = + set_bits32(mctl_ch->chn_flush_en, 0x1, 1, 0); + + if (chn_idx != DSS_RCHN_V2) { + mctl_ch->chn_ov_oen = + set_bits32(mctl_ch->chn_ov_oen, + ((1 << (layer_idx + 1)) | + (0x100 << ovl_idx)), 32, 0); + + if (wb_ov_block_rect) { + mctl_ch->chn_starty = + set_bits32(mctl_ch->chn_starty, + ((layer->dst_rect.y - + wb_ov_block_rect->y) | (0x8 << 16)), 32, 0); + } else { + mctl_ch->chn_starty = + set_bits32(mctl_ch->chn_starty, + (layer->dst_rect.y | (0x8 << 16)), 32, 0); + } + + mctl_sys->chn_ov_sel[ovl_idx] = + set_bits32(mctl_sys->chn_ov_sel[ovl_idx], + chn_idx, 4, (layer_idx + 1) * 4); + mctl_sys->chn_ov_sel_used[ovl_idx] = 1; + } + } + } + + return 0; +} + +int hisi_dss_mctl_ov_config(struct hisi_fb_data_type *hisifd, + dss_overlay_t *pov_req, int ovl_idx, bool has_base, + bool is_first_ov_block) +{ + dss_mctl_t *mctl = NULL; + dss_mctl_sys_t *mctl_sys = NULL; + + BUG_ON(hisifd == NULL); + BUG_ON((ovl_idx < DSS_OVL0) || (ovl_idx >= DSS_OVL_IDX_MAX)); + + if (pov_req && pov_req->wb_layer_infos[0].chn_idx == DSS_WCHN_W2) { + return 0; + } + + mctl = &(hisifd->dss_module.mctl[ovl_idx]); + hisifd->dss_module.mctl_used[ovl_idx] = 1; + + if (ovl_idx == DSS_OVL0) { + mctl->ctl_mutex_itf = + set_bits32(mctl->ctl_mutex_itf, 0x1, 2, 0); + mctl->ctl_mutex_dbuf = + set_bits32(mctl->ctl_mutex_dbuf, 0x1, 2, 0); + } else if (ovl_idx == DSS_OVL1) { + mctl->ctl_mutex_itf = + set_bits32(mctl->ctl_mutex_itf, 0x2, 2, 0); + mctl->ctl_mutex_dbuf = + set_bits32(mctl->ctl_mutex_dbuf, 0x2, 2, 0); + } else { + ; + } + + mctl->ctl_mutex_ov = set_bits32(mctl->ctl_mutex_ov, 1 << ovl_idx, 4, 0); + + mctl_sys = &(hisifd->dss_module.mctl_sys); + hisifd->dss_module.mctl_sys_used = 1; + + mctl_sys->chn_ov_sel[ovl_idx] = + set_bits32(mctl_sys->chn_ov_sel[ovl_idx], 0x8, 4, 0); + mctl_sys->chn_ov_sel_used[ovl_idx] = 1; + + if ((ovl_idx == DSS_OVL0) || (ovl_idx == DSS_OVL1)) { + if (is_first_ov_block) { + mctl_sys->ov_flush_en[ovl_idx] = + set_bits32(mctl_sys->ov_flush_en[ovl_idx], 0xd, 4, 0); + } else { + mctl_sys->ov_flush_en[ovl_idx] = + set_bits32(mctl_sys->ov_flush_en[ovl_idx], 0x1, 1, 0); + } + mctl_sys->ov_flush_en_used[ovl_idx] = 1; + } else { + mctl_sys->ov_flush_en[ovl_idx] = + set_bits32(mctl_sys->ov_flush_en[ovl_idx], 0x1, 1, 0); + mctl_sys->ov_flush_en_used[ovl_idx] = 1; + } + + return 0; +} + +/******************************************************************************* + ** DSS OVL + */ +static dss_ovl_alpha_t g_ovl_alpha[DSS_BLEND_MAX] = { + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0}, + {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {3, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0}, + {1, 0, 0, 0, 0, 0, 3, 0, 0, 1, 0}, + {0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0}, + {3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 3, 0, 0, 1, 0}, + {3, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0}, + {3, 0, 0, 0, 1, 0, 3, 0, 0, 0, 0}, + {3, 0, 0, 0, 0, 0, 3, 0, 0, 1, 0}, + {3, 0, 0, 0, 1, 0, 3, 0, 0, 1, 0}, + {1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0}, + {3, 0, 0, 0, 1, 0, 3, 0, 0, 0, 1}, + {3, 0, 0, 0, 1, 0, 3, 2, 0, 0, 0}, + {3, 0, 0, 0, 1, 1, 3, 1, 0, 0, 1}, + {2, 2, 0, 0, 0, 0, 1, 0, 0, 0, 0}, + {1, 0, 0, 0, 0, 0, 2, 2, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 3, 2, 0, 0, 0}, + {3, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 2, 2, 0, 0, 0}, + {2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {2, 2, 0, 0, 0, 0, 3, 2, 0, 0, 0}, + {3, 2, 0, 0, 0, 0, 2, 2, 0, 0, 0}, + {2, 2, 0, 0, 0, 0, 2, 2, 0, 0, 0}, + {3, 2, 0, 0, 0, 0, 3, 2, 0, 0, 0}, + {2, 1, 0, 0, 0, 0, 3, 2, 0, 0, 0}, + {2, 1, 0, 0, 0, 0, 3, 1, 0, 0, 1}, + {0, 0, 0, 0, 0, 1, 3, 0, 1, 0, 0}, + + {2, 1, 0, 0, 0, 1, 3, 2, 0, 0, 0}, + {2, 1, 0, 0, 0, 1, 3, 1, 0, 0, 1}, + {0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0}, +}; + +static uint32_t get_ovl_blending_mode(dss_overlay_t *pov_req, + dss_layer_t *layer) +{ + uint32_t blend_mode = 0; + bool has_per_pixel_alpha = false; + + BUG_ON(layer == NULL); + + has_per_pixel_alpha = hal_format_has_alpha(layer->img.format); + + /* delete it for DTS2015061204735 and DTS2015060408590 */ + /* + if (layer->layer_idx == 0) { + if (has_per_pixel_alpha) { + blend_mode = DSS_BLEND_SRC; + } else { + blend_mode= DSS_BLEND_FIX_PER17; + } + } else + */ + { + if (layer->blending == HISI_FB_BLENDING_PREMULT) { + if (has_per_pixel_alpha) { + blend_mode = + (layer->glb_alpha < + 0xFF) ? DSS_BLEND_FIX_PER12 : + DSS_BLEND_SRC_OVER_DST; + } else { + blend_mode = + (layer->glb_alpha < + 0xFF) ? DSS_BLEND_FIX_PER8 : DSS_BLEND_SRC; + } + } else if (layer->blending == HISI_FB_BLENDING_COVERAGE) { + if (has_per_pixel_alpha) { + blend_mode = + (layer->glb_alpha < + 0xFF) ? DSS_BLEND_FIX_PER13 : + DSS_BLEND_FIX_OVER; + } else { + blend_mode = + (layer->glb_alpha < + 0xFF) ? DSS_BLEND_FIX_PER8 : DSS_BLEND_SRC; + } + } else { + if (has_per_pixel_alpha) { + blend_mode = DSS_BLEND_SRC; + } else { + blend_mode = DSS_BLEND_FIX_PER17; + } + } + } + + if (g_debug_ovl_online_composer) { + HISI_FB_INFO + ("layer_idx(%d), blending=%d, fomat=%d, " + "has_per_pixel_alpha=%d, blend_mode=%d.\n", + layer->layer_idx, layer->blending, layer->img.format, + has_per_pixel_alpha, blend_mode); + } + + return blend_mode; +} + +static void hisi_dss_ovl_init(char __iomem *ovl_base, dss_ovl_t *s_ovl, + int ovl_idx) +{ + int i = 0; + + BUG_ON(ovl_base == NULL); + BUG_ON(s_ovl == NULL); + + memset(s_ovl, 0, sizeof(dss_ovl_t)); + + s_ovl->ovl_size = inp32(ovl_base + OVL_SIZE); + s_ovl->ovl_bg_color = inp32(ovl_base + OVL_BG_COLOR); + s_ovl->ovl_dst_startpos = inp32(ovl_base + OVL_DST_STARTPOS); + s_ovl->ovl_dst_endpos = inp32(ovl_base + OVL_DST_ENDPOS); + s_ovl->ovl_gcfg = inp32(ovl_base + OVL_GCFG); + + if ((ovl_idx == DSS_OVL1) || (ovl_idx == DSS_OVL3)) { + for (i = 0; i < OVL_2LAYER_NUM; i++) { + s_ovl->ovl_layer[i].layer_pos = + inp32(ovl_base + OVL_LAYER0_POS + i * 0x3C); + s_ovl->ovl_layer[i].layer_size = + inp32(ovl_base + OVL_LAYER0_SIZE + i * 0x3C); + s_ovl->ovl_layer[i].layer_pattern = + inp32(ovl_base + OVL_LAYER0_PATTERN + i * 0x3C); + s_ovl->ovl_layer[i].layer_alpha = + inp32(ovl_base + OVL_LAYER0_ALPHA + i * 0x3C); + s_ovl->ovl_layer[i].layer_cfg = + inp32(ovl_base + OVL_LAYER0_CFG + i * 0x3C); + + s_ovl->ovl_layer_pos[i].layer_pspos = + inp32(ovl_base + OVL_LAYER0_PSPOS + i * 0x3C); + s_ovl->ovl_layer_pos[i].layer_pepos = + inp32(ovl_base + OVL_LAYER0_PEPOS + i * 0x3C); + } + + s_ovl->ovl_block_size = inp32(ovl_base + OVL2_BLOCK_SIZE); + } else { + for (i = 0; i < OVL_6LAYER_NUM; i++) { + s_ovl->ovl_layer[i].layer_pos = + inp32(ovl_base + OVL_LAYER0_POS + i * 0x3C); + s_ovl->ovl_layer[i].layer_size = + inp32(ovl_base + OVL_LAYER0_SIZE + i * 0x3C); + s_ovl->ovl_layer[i].layer_pattern = + inp32(ovl_base + OVL_LAYER0_PATTERN + i * 0x3C); + s_ovl->ovl_layer[i].layer_alpha = + inp32(ovl_base + OVL_LAYER0_ALPHA + i * 0x3C); + s_ovl->ovl_layer[i].layer_cfg = + inp32(ovl_base + OVL_LAYER0_CFG + i * 0x3C); + + s_ovl->ovl_layer_pos[i].layer_pspos = + inp32(ovl_base + OVL_LAYER0_PSPOS + i * 0x3C); + s_ovl->ovl_layer_pos[i].layer_pepos = + inp32(ovl_base + OVL_LAYER0_PEPOS + i * 0x3C); + } + + s_ovl->ovl_block_size = inp32(ovl_base + OVL6_BLOCK_SIZE); + } +} + +static void hisi_dss_ovl_set_reg(struct hisi_fb_data_type *hisifd, + char __iomem *ovl_base, dss_ovl_t *s_ovl, + int ovl_idx) +{ + int i = 0; + + BUG_ON(hisifd == NULL); + BUG_ON(ovl_base == NULL); + BUG_ON(s_ovl == NULL); + + if ((ovl_idx == DSS_OVL1) || (ovl_idx == DSS_OVL3)) { + hisifd->set_reg(hisifd, ovl_base + OVL2_REG_DEFAULT, 0x1, 32, 0); + hisifd->set_reg(hisifd, ovl_base + OVL2_REG_DEFAULT, 0x0, 32, 0); + } else { + hisifd->set_reg(hisifd, ovl_base + OVL6_REG_DEFAULT, 0x1, 32, 0); + hisifd->set_reg(hisifd, ovl_base + OVL6_REG_DEFAULT, 0x0, 32, 0); + } + + hisifd->set_reg(hisifd, ovl_base + OVL_SIZE, s_ovl->ovl_size, 32, 0); + hisifd->set_reg(hisifd, ovl_base + OVL_BG_COLOR, + s_ovl->ovl_bg_color, 32, 0); + hisifd->set_reg(hisifd, ovl_base + OVL_DST_STARTPOS, + s_ovl->ovl_dst_startpos, 32, 0); + hisifd->set_reg(hisifd, ovl_base + OVL_DST_ENDPOS, + s_ovl->ovl_dst_endpos, 32, 0); + hisifd->set_reg(hisifd, ovl_base + OVL_GCFG, s_ovl->ovl_gcfg, 32, 0); + + if ((ovl_idx == DSS_OVL1) || (ovl_idx == DSS_OVL3)) { + for (i = 0; i < OVL_2LAYER_NUM; i++) { + if (s_ovl->ovl_layer_used[i] == 1) { + hisifd->set_reg(hisifd, + ovl_base + OVL_LAYER0_POS + i * 0x3C, + s_ovl->ovl_layer[i].layer_pos, 32, 0); + hisifd->set_reg(hisifd, + ovl_base + OVL_LAYER0_SIZE + i * 0x3C, + s_ovl->ovl_layer[i].layer_size, 32, 0); + hisifd->set_reg(hisifd, + ovl_base + OVL_LAYER0_PATTERN + i * 0x3C, + s_ovl->ovl_layer[i].layer_pattern, 32, 0); + hisifd->set_reg(hisifd, + ovl_base + OVL_LAYER0_ALPHA + i * 0x3C, + s_ovl->ovl_layer[i].layer_alpha, 32, 0); + hisifd->set_reg(hisifd, + ovl_base + OVL_LAYER0_CFG + i * 0x3C, + s_ovl->ovl_layer[i].layer_cfg, 32, 0); + + hisifd->set_reg(hisifd, + ovl_base + OVL_LAYER0_PSPOS + i * 0x3C, + s_ovl->ovl_layer_pos[i].layer_pspos, 32, 0); + hisifd->set_reg(hisifd, + ovl_base + OVL_LAYER0_PEPOS + i * 0x3C, + s_ovl->ovl_layer_pos[i].layer_pepos, 32, 0); + } else { + hisifd->set_reg(hisifd, + ovl_base + OVL_LAYER0_POS + i * 0x3C, + s_ovl->ovl_layer[i].layer_pos, 32, 0); + hisifd->set_reg(hisifd, + ovl_base + OVL_LAYER0_SIZE + i * 0x3C, + s_ovl->ovl_layer[i].layer_size, 32, 0); + hisifd->set_reg(hisifd, + ovl_base + OVL_LAYER0_CFG + i * 0x3C, + s_ovl->ovl_layer[i].layer_cfg, 32, 0); + } + } + + hisifd->set_reg(hisifd, ovl_base + OVL2_BLOCK_SIZE, + s_ovl->ovl_block_size, 32, 0); + } else { + for (i = 0; i < OVL_6LAYER_NUM; i++) { + if (s_ovl->ovl_layer_used[i] == 1) { + hisifd->set_reg(hisifd, + ovl_base + OVL_LAYER0_POS + i * 0x3C, + s_ovl->ovl_layer[i].layer_pos, 32, 0); + hisifd->set_reg(hisifd, + ovl_base + OVL_LAYER0_SIZE + i * 0x3C, + s_ovl->ovl_layer[i].layer_size, 32, 0); + hisifd->set_reg(hisifd, + ovl_base + OVL_LAYER0_PATTERN + i * 0x3C, + s_ovl->ovl_layer[i].layer_pattern, 32, 0); + hisifd->set_reg(hisifd, + ovl_base + OVL_LAYER0_ALPHA + i * 0x3C, + s_ovl->ovl_layer[i].layer_alpha, 32, 0); + hisifd->set_reg(hisifd, + ovl_base + OVL_LAYER0_CFG + i * 0x3C, + s_ovl->ovl_layer[i].layer_cfg, 32, 0); + + hisifd->set_reg(hisifd, + ovl_base + OVL_LAYER0_PSPOS + i * 0x3C, + s_ovl->ovl_layer_pos[i].layer_pspos, 32, 0); + hisifd->set_reg(hisifd, + ovl_base + OVL_LAYER0_PEPOS +i * 0x3C, + s_ovl->ovl_layer_pos[i].layer_pepos, 32, 0); + } else { + hisifd->set_reg(hisifd, + ovl_base + OVL_LAYER0_POS +i * 0x3C, + s_ovl->ovl_layer[i].layer_pos, 32, 0); + hisifd->set_reg(hisifd, + ovl_base + OVL_LAYER0_SIZE + i * 0x3C, + s_ovl->ovl_layer[i].layer_size, 32, 0); + hisifd->set_reg(hisifd, + ovl_base + OVL_LAYER0_CFG + i * 0x3C, + s_ovl->ovl_layer[i].layer_cfg, 32, 0); + } + } + + hisifd->set_reg(hisifd, ovl_base + OVL6_BLOCK_SIZE, + s_ovl->ovl_block_size, 32, 0); + } +} + +void hisi_dss_ov_set_reg_default_value(struct hisi_fb_data_type *hisifd, + char __iomem *ovl_base, int ovl_idx) +{ + BUG_ON(hisifd == NULL); + BUG_ON(ovl_base == NULL); + + if ((ovl_idx == DSS_OVL1) || (ovl_idx == DSS_OVL3)) { + hisifd->set_reg(hisifd, ovl_base + OVL2_REG_DEFAULT, 0x1, 32, + 0); + hisifd->set_reg(hisifd, ovl_base + OVL2_REG_DEFAULT, 0x0, 32, + 0); + } else { + hisifd->set_reg(hisifd, ovl_base + OVL6_REG_DEFAULT, 0x1, 32, + 0); + hisifd->set_reg(hisifd, ovl_base + OVL6_REG_DEFAULT, 0x0, 32, + 0); + } +} + +int hisi_dss_ovl_base_config(struct hisi_fb_data_type *hisifd, + dss_overlay_t *pov_req, + dss_overlay_block_t *pov_h_block, + dss_rect_t *wb_ov_block_rect, int ovl_idx, + int ov_h_block_idx) +{ + dss_ovl_t *ovl = NULL; + int img_width = 0; + int img_height = 0; + int block_size = 0x7FFF; + int temp = 0; + int i = 0; + int m = 0; + + dss_overlay_block_t *pov_h_block_infos_tmp = NULL; + dss_overlay_block_t *pov_h_block_tmp = NULL; + dss_layer_t *layer = NULL; + int pov_h_block_idx = 0; + int layer_idx = 0; + bool has_base = false; + + BUG_ON(hisifd == NULL); + BUG_ON((ovl_idx < DSS_OVL0) || (ovl_idx >= DSS_OVL_IDX_MAX)); + + if (pov_req && pov_req->wb_layer_infos[0].chn_idx == DSS_WCHN_W2) { + return 0; + } + + ovl = &(hisifd->dss_module.ov[ovl_idx]); + hisifd->dss_module.ov_used[ovl_idx] = 1; + + if (wb_ov_block_rect) { + img_width = wb_ov_block_rect->w; + img_height = wb_ov_block_rect->h; + } else { + if ((!pov_req) + || (pov_req->dirty_rect.x == 0 && pov_req->dirty_rect.y == 0 + && pov_req->dirty_rect.w == 0 + && pov_req->dirty_rect.h == 0)) { + img_width = get_panel_xres(hisifd); + img_height = get_panel_yres(hisifd); + } else { + img_width = pov_req->dirty_rect.w; + img_height = pov_req->dirty_rect.h; + } + } + + if (pov_h_block && (pov_req->ov_block_nums != 0)) { + if (pov_req->ov_block_nums > 1) { + pov_h_block_infos_tmp = + (dss_overlay_block_t *) (pov_req->ov_block_infos_ptr); + for (m = ov_h_block_idx; m < pov_req->ov_block_nums; + m++) { + pov_h_block_tmp = &(pov_h_block_infos_tmp[m]); + has_base = false; + + for (i = 0; i < pov_h_block_tmp->layer_nums; + i++) { + layer = + &(pov_h_block_tmp->layer_infos[i]); + if (layer->need_cap & CAP_BASE) { + HISI_FB_INFO + ("layer%d is base, i=%d!\n", + layer->layer_idx, i); + has_base = true; + continue; + } + + layer_idx = i; + if (has_base) { + layer_idx = i - 1; + } + + if (layer_idx >= pov_h_block_idx) { + ovl->ovl_layer[layer_idx].layer_pos = + set_bits32(ovl->ovl_layer + [layer_idx].layer_pos, 0, 15, 0); + ovl->ovl_layer[layer_idx].layer_pos = + set_bits32(ovl->ovl_layer + [layer_idx].layer_pos, + img_height, 15, 16); + + ovl->ovl_layer[layer_idx].layer_size = + set_bits32(ovl->ovl_layer + [layer_idx].layer_size, + img_width, 15, 0); + ovl->ovl_layer[layer_idx].layer_size = + set_bits32(ovl->ovl_layer + [layer_idx].layer_size, + img_height + 1, 15, 16); + ovl->ovl_layer[layer_idx].layer_cfg = + set_bits32(ovl->ovl_layer + [layer_idx].layer_cfg, + 0x1, 1, 0); + + if (layer->need_cap & (CAP_DIM | + CAP_PURE_COLOR)) { + + ovl->ovl_layer[layer_idx].layer_pattern = + set_bits32(ovl->ovl_layer + [layer_idx].layer_pattern, + layer->color, 32, 0); + ovl->ovl_layer[layer_idx].layer_cfg = + set_bits32(ovl->ovl_layer + [layer_idx].layer_cfg, + 0x1, 1, 0); + ovl->ovl_layer[layer_idx].layer_cfg = + set_bits32(ovl->ovl_layer + [layer_idx].layer_cfg, + 0x1, 1, 8); + } else { + ovl->ovl_layer[layer_idx].layer_pattern = + set_bits32(ovl->ovl_layer + [layer_idx].layer_pattern, + 0x0, 32, 0); + ovl->ovl_layer[layer_idx].layer_cfg = + set_bits32(ovl->ovl_layer + [layer_idx].layer_cfg, + 0x1, 1, 0); + ovl->ovl_layer[layer_idx].layer_cfg = + set_bits32(ovl->ovl_layer + [layer_idx].layer_cfg, + 0x0, 1, 8); + } + + ovl->ovl_layer_used[layer_idx] = 1; + pov_h_block_idx = layer_idx + 1; + } + } + } + } + + if (wb_ov_block_rect) { + if ((pov_req->wb_layer_infos[0].transform & + HISI_FB_TRANSFORM_ROT_90) + || (pov_req->wb_layer_infos[1].transform & + HISI_FB_TRANSFORM_ROT_90)) { + block_size = DSS_HEIGHT(wb_ov_block_rect->h); + } else { + temp = + pov_h_block->ov_block_rect.y + + DSS_HEIGHT(pov_h_block->ov_block_rect.h) - + wb_ov_block_rect->y; + if (temp >= wb_ov_block_rect->h) { + block_size = + DSS_HEIGHT(wb_ov_block_rect->h); + } else { + block_size = temp; + } + } + } else { + block_size = + pov_h_block->ov_block_rect.y + + DSS_HEIGHT(pov_h_block->ov_block_rect.h); + } + } + + ovl->ovl_size = set_bits32(ovl->ovl_size, DSS_WIDTH(img_width), 15, 0); + ovl->ovl_size = + set_bits32(ovl->ovl_size, DSS_HEIGHT(img_height), 15, 16); +#ifdef CONFIG_HISI_FB_OV_BASE_USED + ovl->ovl_bg_color = set_bits32(ovl->ovl_bg_color, 0xFFFF0000, 32, 0); +#else + ovl->ovl_bg_color = set_bits32(ovl->ovl_bg_color, 0xFF000000, 32, 0); +#endif + ovl->ovl_dst_startpos = set_bits32(ovl->ovl_dst_startpos, 0x0, 32, 0); + ovl->ovl_dst_endpos = + set_bits32(ovl->ovl_dst_endpos, DSS_WIDTH(img_width), 15, 0); + ovl->ovl_dst_endpos = + set_bits32(ovl->ovl_dst_endpos, DSS_HEIGHT(img_height), 15, 16); + ovl->ovl_gcfg = set_bits32(ovl->ovl_gcfg, 0x1, 1, 0); + ovl->ovl_gcfg = set_bits32(ovl->ovl_gcfg, 0x1, 1, 16); + ovl->ovl_block_size = + set_bits32(ovl->ovl_block_size, block_size, 15, 16); + + return 0; +} + +int hisi_dss_ovl_layer_config(struct hisi_fb_data_type *hisifd, + dss_overlay_t *pov_req, dss_layer_t *layer, + dss_rect_t *wb_ov_block_rect, bool has_base) +{ + dss_ovl_t *ovl = NULL; + int ovl_idx = 0; + int layer_idx = 0; + int blend_mode = 0; + dss_rect_t wb_ov_rect; + dss_rect_t dst_rect; + + BUG_ON(hisifd == NULL); + BUG_ON(layer == NULL); + + ovl_idx = hisifd->ov_req.ovl_idx; + layer_idx = layer->layer_idx; + + if (layer->chn_idx == DSS_RCHN_V2) { + return 0; + } + + BUG_ON((ovl_idx < DSS_OVL0) || (ovl_idx >= DSS_OVL_IDX_MAX)); + ovl = &(hisifd->dss_module.ov[ovl_idx]); + hisifd->dss_module.ov_used[ovl_idx] = 1; + + if (layer->need_cap & CAP_BASE) { + ovl->ovl_bg_color = + set_bits32(ovl->ovl_bg_color, layer->color, 32, 0); + ovl->ovl_gcfg = set_bits32(ovl->ovl_gcfg, 0x1, 1, 16); + return 0; + } + + if (layer->glb_alpha < 0) { + layer->glb_alpha = 0; + HISI_FB_ERR("layer's glb_alpha(0x%x) is out of range!", + layer->glb_alpha); + } else if (layer->glb_alpha > 0xFF) { + layer->glb_alpha = 0xFF; + HISI_FB_ERR("layer's glb_alpha(0x%x) is out of range!", + layer->glb_alpha); + } + + blend_mode = get_ovl_blending_mode(pov_req, layer); + BUG_ON((blend_mode < 0) || (blend_mode >= DSS_BLEND_MAX)); + + if (has_base) { + layer_idx -= 1; + if (layer_idx < 0) { + HISI_FB_ERR("layer_idx(%d) is out of range!\n", + layer_idx); + return -EINVAL; + } + } + + ovl->ovl_layer_used[layer_idx] = 1; + + if ((layer->chn_idx == DSS_RCHN_V0) + && layer->block_info.arsr2p_left_clip) { + dst_rect.x = + layer->dst_rect.x + layer->block_info.arsr2p_left_clip; + dst_rect.y = layer->dst_rect.y; + dst_rect.w = + layer->dst_rect.w - layer->block_info.arsr2p_left_clip; + dst_rect.h = layer->dst_rect.h; + } else { + dst_rect = layer->dst_rect; + } + + if (wb_ov_block_rect) { + wb_ov_rect.x = pov_req->wb_ov_rect.x + wb_ov_block_rect->x; + wb_ov_rect.y = pov_req->wb_ov_rect.y; + + ovl->ovl_layer[layer_idx].layer_pos = + set_bits32(ovl->ovl_layer[layer_idx].layer_pos, + (dst_rect.x - wb_ov_rect.x), 15, 0); + ovl->ovl_layer[layer_idx].layer_pos = + set_bits32(ovl->ovl_layer[layer_idx].layer_pos, + (dst_rect.y - wb_ov_rect.y), 15, 16); + + ovl->ovl_layer[layer_idx].layer_size = + set_bits32(ovl->ovl_layer[layer_idx].layer_size, + (dst_rect.x - wb_ov_rect.x + + DSS_WIDTH(dst_rect.w)), 15, 0); + ovl->ovl_layer[layer_idx].layer_size = + set_bits32(ovl->ovl_layer[layer_idx].layer_size, + (dst_rect.y - wb_ov_rect.y + + DSS_HEIGHT(dst_rect.h)), 15, 16); + } else { + ovl->ovl_layer[layer_idx].layer_pos = + set_bits32(ovl->ovl_layer[layer_idx].layer_pos, dst_rect.x, + 15, 0); + ovl->ovl_layer[layer_idx].layer_pos = + set_bits32(ovl->ovl_layer[layer_idx].layer_pos, dst_rect.y, + 15, 16); + + ovl->ovl_layer[layer_idx].layer_size = + set_bits32(ovl->ovl_layer[layer_idx].layer_size, + DSS_WIDTH(dst_rect.x + dst_rect.w), 15, 0); + ovl->ovl_layer[layer_idx].layer_size = + set_bits32(ovl->ovl_layer[layer_idx].layer_size, + DSS_HEIGHT(dst_rect.y + dst_rect.h), 15, 16); + } + + ovl->ovl_layer[layer_idx].layer_alpha = + set_bits32(ovl->ovl_layer[layer_idx].layer_alpha, + ((layer->glb_alpha << 0) | + (g_ovl_alpha[blend_mode].fix_mode << 8) | + (g_ovl_alpha[blend_mode].dst_pmode << 9) | + (g_ovl_alpha[blend_mode].alpha_offdst << 10) | + (g_ovl_alpha[blend_mode].dst_gmode << 12) | + (g_ovl_alpha[blend_mode].dst_amode << 14) | + (layer->glb_alpha <<16) | + (g_ovl_alpha[blend_mode].alpha_smode << 24) | + (g_ovl_alpha[blend_mode].src_pmode << 25) | + (g_ovl_alpha[blend_mode].src_lmode << 26) | + (g_ovl_alpha[blend_mode].alpha_offdst << 27) | + (g_ovl_alpha[blend_mode].src_gmode << 28) | + (g_ovl_alpha[blend_mode].src_amode << 30)), 32, 0); + + if (layer->need_cap & (CAP_DIM | CAP_PURE_COLOR)) { + ovl->ovl_layer[layer_idx].layer_pattern = + set_bits32(ovl->ovl_layer[layer_idx].layer_pattern, + layer->color, 32, 0); + ovl->ovl_layer[layer_idx].layer_cfg = + set_bits32(ovl->ovl_layer[layer_idx].layer_cfg, 0x1, 1, 0); + ovl->ovl_layer[layer_idx].layer_cfg = + set_bits32(ovl->ovl_layer[layer_idx].layer_cfg, 0x1, 1, 8); + } else { + ovl->ovl_layer[layer_idx].layer_pattern = + set_bits32(ovl->ovl_layer[layer_idx].layer_pattern, 0x0, 32, + 0); + ovl->ovl_layer[layer_idx].layer_cfg = + set_bits32(ovl->ovl_layer[layer_idx].layer_cfg, 0x1, 1, 0); + ovl->ovl_layer[layer_idx].layer_cfg = + set_bits32(ovl->ovl_layer[layer_idx].layer_cfg, 0x0, 1, 8); + } + + ovl->ovl_layer_pos[layer_idx].layer_pspos = + set_bits32(ovl->ovl_layer_pos[layer_idx].layer_pspos, dst_rect.x, + 15, 0); + ovl->ovl_layer_pos[layer_idx].layer_pspos = + set_bits32(ovl->ovl_layer_pos[layer_idx].layer_pspos, dst_rect.y, + 15, 16); + ovl->ovl_layer_pos[layer_idx].layer_pepos = + set_bits32(ovl->ovl_layer_pos[layer_idx].layer_pepos, + DSS_WIDTH(dst_rect.x + dst_rect.w), 15, 0); + ovl->ovl_layer_pos[layer_idx].layer_pepos = + set_bits32(ovl->ovl_layer_pos[layer_idx].layer_pepos, + DSS_HEIGHT(dst_rect.y + dst_rect.h), 15, 16); + + return 0; +} + +/******************************************************************************* + ** dirty_region_updt + */ +static void hisi_dss_dirty_region_dbuf_set_reg(struct hisi_fb_data_type *hisifd, + char __iomem *dss_base, + dirty_region_updt_t * + s_dirty_region_updt) +{ + BUG_ON(hisifd == NULL); + BUG_ON(dss_base == NULL); + BUG_ON(s_dirty_region_updt == NULL); + + hisifd->set_reg(hisifd, dss_base + DSS_DBUF0_OFFSET + DBUF_FRM_SIZE, + s_dirty_region_updt->dbuf_frm_size, 32, 0); + hisifd->set_reg(hisifd, dss_base + DSS_DBUF0_OFFSET + DBUF_FRM_HSIZE, + s_dirty_region_updt->dbuf_frm_hsize, 32, 0); + hisifd->set_reg(hisifd, dss_base + DSS_DPP_OFFSET + DPP_IMG_SIZE_BEF_SR, + ((s_dirty_region_updt->dpp_img_vrt_bef_sr << 16) | + s_dirty_region_updt->dpp_img_hrz_bef_sr), 32, 0); + hisifd->set_reg(hisifd, dss_base + DSS_DPP_OFFSET + DPP_IMG_SIZE_AFT_SR, + ((s_dirty_region_updt->dpp_img_vrt_aft_sr << 16) | + s_dirty_region_updt->dpp_img_hrz_aft_sr), 32, 0); +} + +static void hisi_dss_dirty_region_updt_set_reg(struct hisi_fb_data_type *hisifd, + char __iomem *dss_base, + dirty_region_updt_t * + s_dirty_region_updt) +{ + BUG_ON(hisifd == NULL); + BUG_ON(dss_base == NULL); + BUG_ON(s_dirty_region_updt == NULL); + + set_reg(dss_base + DSS_MIPI_DSI0_OFFSET + MIPIDSI_EDPI_CMD_SIZE_OFFSET, + s_dirty_region_updt->edpi_cmd_size, 32, 0); + if (is_dual_mipi_panel(hisifd)) { + set_reg(dss_base + DSS_MIPI_DSI1_OFFSET + + MIPIDSI_EDPI_CMD_SIZE_OFFSET, + s_dirty_region_updt->edpi_cmd_size, 32, 0); + } + + set_reg(dss_base + DSS_LDI0_OFFSET + LDI_DPI0_HRZ_CTRL0, + s_dirty_region_updt->ldi_dpi0_hrz_ctrl0, 29, 0); + set_reg(dss_base + DSS_LDI0_OFFSET + LDI_DPI0_HRZ_CTRL1, + s_dirty_region_updt->ldi_dpi0_hrz_ctrl1, 13, 0); + set_reg(dss_base + DSS_LDI0_OFFSET + LDI_DPI0_HRZ_CTRL2, + s_dirty_region_updt->ldi_dpi0_hrz_ctrl2, 13, 0); + set_reg(dss_base + DSS_LDI0_OFFSET + LDI_VRT_CTRL0, + s_dirty_region_updt->ldi_vrt_ctrl0, 29, 0); + set_reg(dss_base + DSS_LDI0_OFFSET + LDI_VRT_CTRL1, + s_dirty_region_updt->ldi_vrt_ctrl1, 13, 0); + set_reg(dss_base + DSS_LDI0_OFFSET + LDI_VRT_CTRL2, + s_dirty_region_updt->ldi_vrt_ctrl2, 13, 0); + + if (is_dual_mipi_panel(hisifd)) { + set_reg(dss_base + DSS_LDI0_OFFSET + LDI_DPI1_HRZ_CTRL0, + s_dirty_region_updt->ldi_dpi1_hrz_ctrl0, 29, 0); + set_reg(dss_base + DSS_LDI0_OFFSET + LDI_DPI1_HRZ_CTRL1, + s_dirty_region_updt->ldi_dpi1_hrz_ctrl1, 13, 0); + set_reg(dss_base + DSS_LDI0_OFFSET + LDI_DPI1_HRZ_CTRL2, + s_dirty_region_updt->ldi_dpi1_hrz_ctrl2, 13, 0); + } + + if (hisifd->panel_info.ifbc_type != IFBC_TYPE_NONE) { + if (!is_ifbc_vesa_panel(hisifd)) { + set_reg(dss_base + DSS_IFBC_OFFSET + IFBC_SIZE, + s_dirty_region_updt->ifbc_size, 32, 0); + } else { + set_reg(dss_base + DSS_DSC_OFFSET + DSC_PIC_SIZE, + s_dirty_region_updt->ifbc_size, 32, 0); + } + } +} + +int hisi_dss_dirty_region_dbuf_config(struct hisi_fb_data_type *hisifd, + dss_overlay_t *pov_req) +{ + struct hisi_panel_info *pinfo = NULL; + dirty_region_updt_t *dirty_region_updt = NULL; + struct dss_rect dirty = { 0 }; + + BUG_ON(hisifd == NULL); + pinfo = &(hisifd->panel_info); + + if ((hisifd->index != PRIMARY_PANEL_IDX) || + !pinfo->dirty_region_updt_support) + return 0; + + if ((!pov_req) + || (pov_req->dirty_rect.x == 0 && pov_req->dirty_rect.y == 0 + && pov_req->dirty_rect.w == 0 && pov_req->dirty_rect.h == 0)) { + dirty.x = 0; + dirty.y = 0; + dirty.w = hisifd->panel_info.xres; + dirty.h = hisifd->panel_info.yres; + } else { + dirty = pov_req->dirty_rect; + } + + if ((dirty.x == hisifd->dirty_region_updt.x) + && (dirty.y == hisifd->dirty_region_updt.y) + && (dirty.w == hisifd->dirty_region_updt.w) + && (dirty.h == hisifd->dirty_region_updt.h)) { + return 0; + } + + dirty_region_updt = &(hisifd->dss_module.dirty_region_updt); + hisifd->dss_module.dirty_region_updt_used = 1; + dirty_region_updt->dpp_img_hrz_bef_sr = + set_bits32(dirty_region_updt->dpp_img_hrz_bef_sr, + DSS_WIDTH(dirty.w), 13, 0); + dirty_region_updt->dpp_img_vrt_bef_sr = + set_bits32(dirty_region_updt->dpp_img_vrt_bef_sr, + DSS_WIDTH(dirty.h), 13, 0); + dirty_region_updt->dpp_img_hrz_aft_sr = + set_bits32(dirty_region_updt->dpp_img_hrz_aft_sr, + DSS_WIDTH(dirty.w), 13, 0); + dirty_region_updt->dpp_img_vrt_aft_sr = + set_bits32(dirty_region_updt->dpp_img_vrt_aft_sr, + DSS_WIDTH(dirty.h), 13, 0); + + dirty_region_updt->dbuf_frm_size = + set_bits32(dirty_region_updt->dbuf_frm_size, dirty.w * dirty.h, 27, + 0); + dirty_region_updt->dbuf_frm_hsize = + set_bits32(dirty_region_updt->dbuf_frm_hsize, DSS_WIDTH(dirty.w), + 13, 0); + + return 0; +} + +void hisi_dss_dirty_region_updt_config(struct hisi_fb_data_type *hisifd, + dss_overlay_t *pov_req) +{ + struct hisi_fb_panel_data *pdata = NULL; + struct hisi_panel_info *pinfo = NULL; + dirty_region_updt_t *dirty_region_updt = NULL; + struct dss_rect dirty = { 0 }; + uint32_t h_porch_pading = 0; + uint32_t v_porch_pading = 0; + dss_rect_t rect = { 0 }; + uint32_t max_latency = 0; + uint32_t bits_per_pixel = 0; + uint32_t h_front_porch_max = 0; + uint32_t h_front_porch = 0; + uint32_t h_back_porch = 0; + + BUG_ON(hisifd == NULL); + pdata = dev_get_platdata(&hisifd->pdev->dev); + BUG_ON(pdata == NULL); + pinfo = &(hisifd->panel_info); + + if ((hisifd->index != PRIMARY_PANEL_IDX) || + !pinfo->dirty_region_updt_support) + return; + + if ((!pov_req) || (pov_req->dirty_rect.w == 0) + || (pov_req->dirty_rect.h == 0)) { + dirty.x = 0; + dirty.y = 0; + dirty.w = hisifd->panel_info.xres; + dirty.h = hisifd->panel_info.yres; + } else { + dirty = pov_req->dirty_rect; + } + + if (hisifd->panel_info.xres >= dirty.w) { + h_porch_pading = hisifd->panel_info.xres - dirty.w; + } + + if (hisifd->panel_info.yres >= dirty.h) { + v_porch_pading = hisifd->panel_info.yres - dirty.h; + } + + if ((dirty.x == hisifd->dirty_region_updt.x) + && (dirty.y == hisifd->dirty_region_updt.y) + && (dirty.w == hisifd->dirty_region_updt.w) + && (dirty.h == hisifd->dirty_region_updt.h)) { + return; + } + + rect.x = 0; + rect.y = 0; + rect.w = dirty.w; + rect.h = dirty.h; + mipi_ifbc_get_rect(hisifd, &rect); + + h_front_porch = pinfo->ldi.h_front_porch; + h_back_porch = pinfo->ldi.h_back_porch; + + h_porch_pading = h_porch_pading * rect.w / dirty.w; + v_porch_pading = v_porch_pading * rect.h / dirty.h; + + if (pinfo->bpp == LCD_RGB888) + bits_per_pixel = 24; + else if (pinfo->bpp == LCD_RGB565) + bits_per_pixel = 16; + else + bits_per_pixel = 24; + + if (pinfo->pxl_clk_rate_div == 0) + pinfo->pxl_clk_rate_div = 1; + max_latency = + (rect.w * bits_per_pixel / 8 + 1 + 6) / (pinfo->mipi.lane_nums + 1); + + h_front_porch_max = + max_latency * (pinfo->pxl_clk_rate / pinfo->pxl_clk_rate_div) / + pinfo->dsi_phy_ctrl.lane_byte_clk; + HISI_FB_DEBUG("bits_per_pixel = %d\n" "data_lane_lp2hs_time = %d\n" + "max_latency = %d\n" "pxl_clk_rate = %lld\n" + "pxl_clk_rate_div = %d\n" + "dsi_phy_ctrl.lane_byte_clk = %lld\n" + "h_front_porch_max = %d\n", bits_per_pixel, + pinfo->dsi_phy_ctrl.data_lane_lp2hs_time, max_latency, + pinfo->pxl_clk_rate, pinfo->pxl_clk_rate_div, + pinfo->dsi_phy_ctrl.lane_byte_clk, h_front_porch_max); + + if (h_front_porch > h_front_porch_max) { + h_back_porch += (h_front_porch - h_front_porch_max); + h_front_porch = h_front_porch_max; + } + + dirty_region_updt = &(hisifd->dss_module.dirty_region_updt); + + dirty_region_updt->ldi_dpi0_hrz_ctrl0 = + set_bits32(dirty_region_updt->ldi_dpi0_hrz_ctrl0, + (h_front_porch) | ((h_back_porch + h_porch_pading) << + 16), 29, 0); + dirty_region_updt->ldi_dpi0_hrz_ctrl1 = + set_bits32(dirty_region_updt->ldi_dpi0_hrz_ctrl1, + DSS_WIDTH(pinfo->ldi.h_pulse_width), 13, 0); + dirty_region_updt->ldi_dpi0_hrz_ctrl2 = + set_bits32(dirty_region_updt->ldi_dpi0_hrz_ctrl2, DSS_WIDTH(rect.w), + 13, 0); + + if (is_dual_mipi_panel(hisifd)) { + dirty_region_updt->ldi_dpi1_hrz_ctrl0 = + set_bits32(dirty_region_updt->ldi_dpi1_hrz_ctrl0, + (h_back_porch + h_porch_pading) << 16, 29, 0); + dirty_region_updt->ldi_dpi1_hrz_ctrl1 = + set_bits32(dirty_region_updt->ldi_dpi1_hrz_ctrl1, + DSS_WIDTH(pinfo->ldi.h_pulse_width), 13, 0); + dirty_region_updt->ldi_dpi1_hrz_ctrl2 = + set_bits32(dirty_region_updt->ldi_dpi1_hrz_ctrl2, + DSS_WIDTH(rect.w), 13, 0); + } + + dirty_region_updt->ldi_vrt_ctrl0 = + set_bits32(dirty_region_updt->ldi_vrt_ctrl0, + (pinfo->ldi.v_front_porch + + v_porch_pading) | ((pinfo->ldi.v_back_porch) << 16), 29, + 0); + dirty_region_updt->ldi_vrt_ctrl1 = + set_bits32(dirty_region_updt->ldi_vrt_ctrl1, + DSS_HEIGHT(pinfo->ldi.v_pulse_width), 13, 0); + dirty_region_updt->ldi_vrt_ctrl2 = + set_bits32(dirty_region_updt->ldi_vrt_ctrl2, DSS_HEIGHT(rect.h), 13, + 0); + + dirty_region_updt->edpi_cmd_size = + set_bits32(dirty_region_updt->edpi_cmd_size, rect.w, 16, 0); + + if (pinfo->ifbc_type != IFBC_TYPE_NONE) { + if ((pinfo->ifbc_type == IFBC_TYPE_VESA2X_DUAL) || + (pinfo->ifbc_type == IFBC_TYPE_VESA3X_DUAL)) { + dirty_region_updt->ifbc_size = + set_bits32(dirty_region_updt->ifbc_size, + ((DSS_WIDTH(dirty.w / 2) << 16) | + DSS_HEIGHT(dirty.h)), 32, 0); + } else { + dirty_region_updt->ifbc_size = + set_bits32(dirty_region_updt->ifbc_size, + ((DSS_WIDTH(dirty.w) << 16) | + DSS_HEIGHT(dirty.h)), 32, 0); + } + } + + /*if (pdata && pdata->set_display_region) { + pdata->set_display_region(hisifd->pdev, &dirty); + } */ + + hisifd->dirty_region_updt = dirty; + + hisi_dss_dirty_region_updt_set_reg(hisifd, hisifd->dss_base, + &(hisifd->dss_module. + dirty_region_updt)); + + if (g_debug_dirty_region_updt) { + HISI_FB_INFO + ("dirty_region(%d,%d, %d,%d), h_porch_pading=%d, v_porch_pading=%d.\n", + dirty.x, dirty.y, dirty.w, dirty.h, h_porch_pading, + v_porch_pading); + } +} + +/******************************************************************************* + ** WCHN + */ +static uint32_t hisi_calculate_display_addr_wb(bool mmu_enable, + dss_wb_layer_t *wb_layer, + dss_rect_t aligned_rect, + dss_rect_t *ov_block_rect, + int add_type) +{ + uint32_t addr = 0; + uint32_t dst_addr = 0; + uint32_t stride = 0; + uint32_t offset = 0; + int left = 0, top = 0; + int bpp = 0; + + if (wb_layer->transform & HISI_FB_TRANSFORM_ROT_90) { + left = wb_layer->dst_rect.x; + top = + ov_block_rect->x - wb_layer->dst_rect.x + + wb_layer->dst_rect.y; + } else { + left = aligned_rect.x; + top = aligned_rect.y; + } + + if (add_type == DSS_ADDR_PLANE0) { + stride = wb_layer->dst.stride; + dst_addr = + mmu_enable ? wb_layer->dst.vir_addr : wb_layer->dst. + phy_addr; + } else if (add_type == DSS_ADDR_PLANE1) { + stride = wb_layer->dst.stride_plane1; + offset = wb_layer->dst.offset_plane1; + dst_addr = + mmu_enable ? (wb_layer->dst.vir_addr + + offset) : (wb_layer->dst.phy_addr + offset); + top /= 2; + } else { + HISI_FB_ERR("NOT SUPPORT this add_type(%d).\n", add_type); + BUG_ON(1); + } + + bpp = wb_layer->dst.bpp; + addr = dst_addr + left * bpp + top * stride; + + return addr; +} + +int hisi_dss_wdfc_config(struct hisi_fb_data_type *hisifd, + dss_wb_layer_t *layer, dss_rect_t *aligned_rect, + dss_rect_t *ov_block_rect) +{ + dss_dfc_t *dfc = NULL; + int chn_idx = 0; + dss_rect_t in_rect; + bool need_dither = false; + + int size_hrz = 0; + int size_vrt = 0; + int dfc_fmt = 0; + int dfc_pix_in_num = 0; + int aligned_line = 0; + uint32_t dfc_w = 0; + int aligned_pixel = 0; + + uint32_t left_pad = 0; + uint32_t right_pad = 0; + uint32_t top_pad = 0; + uint32_t bottom_pad = 0; + + uint32_t addr = 0; + uint32_t dst_addr = 0; + uint32_t bpp = 0; + bool mmu_enable = false; + + BUG_ON(hisifd == NULL); + BUG_ON(layer == NULL); + BUG_ON(aligned_rect == NULL); + + chn_idx = layer->chn_idx; + + dfc = &(hisifd->dss_module.dfc[chn_idx]); + hisifd->dss_module.dfc_used[chn_idx] = 1; + + dfc_fmt = hisi_pixel_format_hal2dfc(layer->dst.format); + if (dfc_fmt < 0) { + HISI_FB_ERR("layer format (%d) not support !\n", + layer->dst.format); + return -EINVAL; + } + + if (layer->need_cap & CAP_AFBCE) { + aligned_pixel = AFBC_BLOCK_ALIGN; + } else { + aligned_pixel = DMA_ALIGN_BYTES / layer->dst.bpp; + } + + need_dither = isNeedDither(dfc_fmt); + if (ov_block_rect) { + memcpy(&in_rect, ov_block_rect, sizeof(dss_rect_t)); + } else { + in_rect = layer->src_rect; + } + + size_hrz = DSS_WIDTH(in_rect.w); + size_vrt = DSS_HEIGHT(in_rect.h); + + if ((size_hrz + 1) % 2 == 1) { + size_hrz += 1; + dfc_w = 1; + } + + dfc_pix_in_num = (layer->dst.bpp <= 2) ? 0x1 : 0x0; + + if (layer->need_cap & CAP_AFBCE) { + aligned_rect->x = ALIGN_DOWN(in_rect.x, aligned_pixel); + aligned_rect->w = + ALIGN_UP(in_rect.x - aligned_rect->x + in_rect.w + dfc_w, + aligned_pixel); + aligned_rect->y = ALIGN_DOWN(in_rect.y, aligned_pixel); + aligned_rect->h = + ALIGN_UP(in_rect.y - aligned_rect->y + in_rect.h, + aligned_pixel); + + left_pad = in_rect.x - aligned_rect->x; + right_pad = + aligned_rect->w - (in_rect.x - aligned_rect->x + in_rect.w + + dfc_w); + top_pad = in_rect.y - aligned_rect->y; + bottom_pad = + aligned_rect->h - (in_rect.y - aligned_rect->y + in_rect.h); + } else if (layer->transform & HISI_FB_TRANSFORM_ROT_90) { + aligned_line = (layer->dst.bpp <= 2) ? 32 : 16; + mmu_enable = (layer->dst.mmu_enable == 1) ? true : false; + dst_addr = + mmu_enable ? layer->dst.vir_addr : layer->dst.phy_addr; + bpp = layer->dst.bpp; + addr = + dst_addr + layer->dst_rect.x * bpp + + (in_rect.x - layer->dst_rect.x + layer->dst_rect.y) * + layer->dst.stride; + + if (is_YUV_SP_420(layer->dst.format)) { + top_pad = (addr & 0x1F) / bpp; + } else { + top_pad = (addr & 0x3F) / bpp; + } + + aligned_rect->x = in_rect.x; + aligned_rect->y = in_rect.y; + aligned_rect->w = size_hrz + 1; + aligned_rect->h = ALIGN_UP(in_rect.h + top_pad, aligned_line); + + left_pad = 0; + right_pad = 0; + bottom_pad = aligned_rect->h - in_rect.h - top_pad; + } else { + aligned_rect->x = ALIGN_DOWN(in_rect.x, aligned_pixel); + aligned_rect->w = + ALIGN_UP(in_rect.x - aligned_rect->x + in_rect.w + dfc_w, + aligned_pixel); + aligned_rect->y = in_rect.y; + + if (is_YUV_SP_420(layer->dst.format)) { + aligned_rect->h = ALIGN_UP(in_rect.h, 2); + } else { + aligned_rect->h = in_rect.h; + } + + left_pad = in_rect.x - aligned_rect->x; + right_pad = aligned_rect->w - (left_pad + in_rect.w + dfc_w); + top_pad = 0; + bottom_pad = aligned_rect->h - in_rect.h; + } + + dfc->disp_size = + set_bits32(dfc->disp_size, (size_vrt | (size_hrz << 16)), 32, 0); + dfc->pix_in_num = set_bits32(dfc->pix_in_num, dfc_pix_in_num, 1, 0); + dfc->disp_fmt = set_bits32(dfc->disp_fmt, dfc_fmt, 5, 1); + dfc->clip_ctl_hrz = set_bits32(dfc->clip_ctl_hrz, 0x0, 12, 0); + dfc->clip_ctl_vrz = set_bits32(dfc->clip_ctl_vrz, 0x0, 12, 0); + dfc->ctl_clip_en = set_bits32(dfc->ctl_clip_en, 0x0, 1, 0); + dfc->icg_module = set_bits32(dfc->icg_module, 0x1, 1, 0); + if (need_dither) { + dfc->dither_enable = set_bits32(dfc->dither_enable, 0x1, 1, 0); + } else { + dfc->dither_enable = set_bits32(dfc->dither_enable, 0x0, 1, 0); + } + + if (left_pad || right_pad || top_pad || bottom_pad) { + dfc->padding_ctl = set_bits32(dfc->padding_ctl, (left_pad | + (right_pad << 8) | (top_pad << 16) | + (bottom_pad << 24) | (0x1 << 31)), 32, 0); + } else { + dfc->padding_ctl = set_bits32(dfc->padding_ctl, 0x0, 32, 0); + } + + return 0; +} + +static void hisi_dss_wdma_init(char __iomem *wdma_base, dss_wdma_t *s_wdma) +{ + BUG_ON(wdma_base == NULL); + BUG_ON(s_wdma == NULL); + + memset(s_wdma, 0, sizeof(dss_wdma_t)); + + s_wdma->oft_x0 = inp32(wdma_base + DMA_OFT_X0); + s_wdma->oft_y0 = inp32(wdma_base + DMA_OFT_Y0); + s_wdma->oft_x1 = inp32(wdma_base + DMA_OFT_X1); + s_wdma->oft_y1 = inp32(wdma_base + DMA_OFT_Y1); + s_wdma->mask0 = inp32(wdma_base + DMA_MASK0); + s_wdma->mask1 = inp32(wdma_base + DMA_MASK1); + s_wdma->stretch_size_vrt = inp32(wdma_base + DMA_STRETCH_SIZE_VRT); + s_wdma->ctrl = inp32(wdma_base + DMA_CTRL); + s_wdma->tile_scram = inp32(wdma_base + DMA_TILE_SCRAM); + s_wdma->sw_mask_en = inp32(wdma_base + WDMA_DMA_SW_MASK_EN); + s_wdma->start_mask0 = inp32(wdma_base + WDMA_DMA_START_MASK0); + s_wdma->end_mask0 = inp32(wdma_base + WDMA_DMA_END_MASK1); + s_wdma->start_mask1 = inp32(wdma_base + WDMA_DMA_START_MASK1); + s_wdma->end_mask1 = inp32(wdma_base + WDMA_DMA_END_MASK1); + s_wdma->data_addr = inp32(wdma_base + DMA_DATA_ADDR0); + s_wdma->stride0 = inp32(wdma_base + DMA_STRIDE0); + s_wdma->data1_addr = inp32(wdma_base + DMA_DATA_ADDR1); + s_wdma->stride1 = inp32(wdma_base + DMA_STRIDE1); + s_wdma->stretch_stride = inp32(wdma_base + DMA_STRETCH_STRIDE0); + s_wdma->data_num = inp32(wdma_base + DMA_DATA_NUM0); + + s_wdma->ch_rd_shadow = inp32(wdma_base + CH_RD_SHADOW); + s_wdma->ch_ctl = inp32(wdma_base + CH_CTL); + s_wdma->ch_secu_en = inp32(wdma_base + CH_SECU_EN); + s_wdma->ch_sw_end_req = inp32(wdma_base + CH_SW_END_REQ); + + s_wdma->afbce_hreg_pic_blks = inp32(wdma_base + AFBCE_HREG_PIC_BLKS); + s_wdma->afbce_hreg_format = inp32(wdma_base + AFBCE_HREG_FORMAT); + s_wdma->afbce_hreg_hdr_ptr_lo = + inp32(wdma_base + AFBCE_HREG_HDR_PTR_LO); + s_wdma->afbce_hreg_pld_ptr_lo = + inp32(wdma_base + AFBCE_HREG_PLD_PTR_LO); + s_wdma->afbce_picture_size = inp32(wdma_base + AFBCE_PICTURE_SIZE); + s_wdma->afbce_ctl = inp32(wdma_base + AFBCE_CTL); + s_wdma->afbce_header_srtide = inp32(wdma_base + AFBCE_HEADER_SRTIDE); + s_wdma->afbce_payload_stride = inp32(wdma_base + AFBCE_PAYLOAD_STRIDE); + s_wdma->afbce_enc_os_cfg = inp32(wdma_base + AFBCE_ENC_OS_CFG); + s_wdma->afbce_mem_ctrl = inp32(wdma_base + AFBCE_MEM_CTRL); +} + +static void hisi_dss_wdma_set_reg(struct hisi_fb_data_type *hisifd, + char __iomem *wdma_base, dss_wdma_t *s_wdma) +{ + BUG_ON(hisifd == NULL); + BUG_ON(wdma_base == NULL); + BUG_ON(s_wdma == NULL); + + hisifd->set_reg(hisifd, wdma_base + CH_REG_DEFAULT, 0x1, 32, 0); + hisifd->set_reg(hisifd, wdma_base + CH_REG_DEFAULT, 0x0, 32, 0); + + hisifd->set_reg(hisifd, wdma_base + DMA_OFT_X0, s_wdma->oft_x0, 32, 0); + hisifd->set_reg(hisifd, wdma_base + DMA_OFT_Y0, s_wdma->oft_y0, 32, 0); + hisifd->set_reg(hisifd, wdma_base + DMA_OFT_X1, s_wdma->oft_x1, 32, 0); + hisifd->set_reg(hisifd, wdma_base + DMA_OFT_Y1, s_wdma->oft_y1, 32, 0); + hisifd->set_reg(hisifd, wdma_base + DMA_CTRL, s_wdma->ctrl, 32, 0); + hisifd->set_reg(hisifd, wdma_base + DMA_TILE_SCRAM, + s_wdma->tile_scram, 32, 0); + hisifd->set_reg(hisifd, wdma_base + WDMA_DMA_SW_MASK_EN, + s_wdma->sw_mask_en, 32, 0); + hisifd->set_reg(hisifd, wdma_base + WDMA_DMA_START_MASK0, + s_wdma->start_mask0, 32, 0); + hisifd->set_reg(hisifd, wdma_base + WDMA_DMA_END_MASK0, + s_wdma->end_mask0, 32, 0); + hisifd->set_reg(hisifd, wdma_base + DMA_DATA_ADDR0, + s_wdma->data_addr, 32, 0); + hisifd->set_reg(hisifd, wdma_base + DMA_STRIDE0, + s_wdma->stride0, 32, 0); + hisifd->set_reg(hisifd, wdma_base + DMA_DATA_ADDR1, + s_wdma->data1_addr, 32, 0); + hisifd->set_reg(hisifd, wdma_base + DMA_STRIDE1, + s_wdma->stride1, 32, 0); + + hisifd->set_reg(hisifd, wdma_base + CH_CTL, s_wdma->ch_ctl, 32, 0); + hisifd->set_reg(hisifd, wdma_base + ROT_SIZE, s_wdma->rot_size, 32, 0); + hisifd->set_reg(hisifd, wdma_base + DMA_BUF_SIZE, + s_wdma->dma_buf_size, 32, 0); + + if (s_wdma->afbc_used == 1) { + hisifd->set_reg(hisifd, wdma_base + AFBCE_HREG_PIC_BLKS, + s_wdma->afbce_hreg_pic_blks, 32, 0); + hisifd->set_reg(hisifd, wdma_base + AFBCE_HREG_FORMAT, + s_wdma->afbce_hreg_format, 32, 0); + hisifd->set_reg(hisifd, wdma_base + AFBCE_HREG_HDR_PTR_LO, + s_wdma->afbce_hreg_hdr_ptr_lo, 32, 0); + hisifd->set_reg(hisifd, wdma_base + AFBCE_HREG_PLD_PTR_LO, + s_wdma->afbce_hreg_pld_ptr_lo, 32, 0); + hisifd->set_reg(hisifd, wdma_base + AFBCE_PICTURE_SIZE, + s_wdma->afbce_picture_size, 32, 0); + hisifd->set_reg(hisifd, wdma_base + AFBCE_HEADER_SRTIDE, + s_wdma->afbce_header_srtide, 32, 0); + hisifd->set_reg(hisifd, wdma_base + AFBCE_PAYLOAD_STRIDE, + s_wdma->afbce_payload_stride, 32, 0); + hisifd->set_reg(hisifd, wdma_base + AFBCE_ENC_OS_CFG, + s_wdma->afbce_enc_os_cfg, 32, 0); + hisifd->set_reg(hisifd, wdma_base + AFBCE_THRESHOLD, + s_wdma->afbce_threshold, 32, 0); + hisifd->set_reg(hisifd, wdma_base + AFBCE_SCRAMBLE_MODE, + s_wdma->afbce_scramble_mode, 32, 0); + hisifd->set_reg(hisifd, wdma_base + AFBCE_HEADER_POINTER_OFFSET, + s_wdma->afbce_header_pointer_offset, 32, 0); + } +} + +int hisi_dss_wdma_config(struct hisi_fb_data_type *hisifd, + dss_overlay_t *pov_req, dss_wb_layer_t *layer, + dss_rect_t aligned_rect, dss_rect_t *ov_block_rect, + bool last_block) +{ + dss_wdma_t *wdma = NULL; + int chn_idx = 0; + int wdma_format = 0; + int wdma_transform = 0; + uint32_t oft_x0 = 0; + uint32_t oft_x1 = 0; + uint32_t oft_y0 = 0; + uint32_t oft_y1 = 0; + uint32_t data_num = 0; + uint32_t wdma_addr = 0; + uint32_t wdma_stride = 0; + + uint32_t wdma_buf_width = 0; + uint32_t wdma_buf_height = 0; + + dss_rect_t in_rect; + int temp = 0; + int aligned_pixel = 0; + int l2t_interleave_n = 0; + bool mmu_enable = false; + + dss_rect_ltrb_t afbc_header_rect = { 0 }; + dss_rect_ltrb_t afbc_payload_rect = { 0 }; + uint32_t afbce_hreg_pic_blks; + uint32_t afbc_header_addr = 0; + uint32_t afbc_header_stride = 0; + uint32_t afbc_payload_addr = 0; + uint32_t afbc_payload_stride = 0; + int32_t afbc_header_start_pos = 0; + uint32_t afbc_header_pointer_offset = 0; + uint32_t stride_align = 0; + uint32_t addr_align = 0; + + BUG_ON(hisifd == NULL); + BUG_ON(pov_req == NULL); + BUG_ON(layer == NULL); + + chn_idx = layer->chn_idx; + + wdma = &(hisifd->dss_module.wdma[chn_idx]); + hisifd->dss_module.dma_used[chn_idx] = 1; + + wdma_format = hisi_pixel_format_hal2dma(layer->dst.format); + if (wdma_format < 0) { + HISI_FB_ERR("hisi_pixel_format_hal2dma failed!\n"); + return -EINVAL; + } + + in_rect = aligned_rect; + aligned_pixel = DMA_ALIGN_BYTES / layer->dst.bpp; + + wdma_transform = hisi_transform_hal2dma(layer->transform, chn_idx); + if (wdma_transform < 0) { + HISI_FB_ERR("hisi_transform_hal2dma failed!\n"); + return -EINVAL; + } + + mmu_enable = (layer->dst.mmu_enable == 1) ? true : false; + wdma_addr = mmu_enable ? layer->dst.vir_addr : layer->dst.phy_addr; + + if (layer->need_cap & CAP_AFBCE) { + wdma->afbc_used = 1; + if ((layer->dst.width & (AFBC_HEADER_ADDR_ALIGN - 1)) || + (layer->dst.height & (AFBC_BLOCK_ALIGN - 1))) { + HISI_FB_ERR + ("wb_layer img width(%d) is not %d bytes aligned, or " + "img heigh(%d) is not %d bytes aligned!\n", + layer->dst.width, AFBC_HEADER_ADDR_ALIGN, + layer->dst.height, AFBC_BLOCK_ALIGN); + return -EINVAL; + } + + if ((in_rect.w < AFBC_PIC_WIDTH_MIN) + || (in_rect.w > AFBCE_IN_WIDTH_MAX) + || (in_rect.h < AFBC_PIC_HEIGHT_MIN) + || (in_rect.h > AFBC_PIC_HEIGHT_MAX) + || (in_rect.w & (AFBC_BLOCK_ALIGN - 1)) + || (in_rect.h & (AFBC_BLOCK_ALIGN - 1))) { + HISI_FB_ERR + ("afbce in_rect(%d,%d, %d,%d) is out of range!", + in_rect.x, in_rect.y, in_rect.w, in_rect.h); + return -EINVAL; + } + + afbc_header_rect.right = + ALIGN_UP(in_rect.x + in_rect.w, AFBC_HEADER_ADDR_ALIGN) - 1; + afbc_header_rect.bottom = + ALIGN_UP(in_rect.y + in_rect.h, AFBC_BLOCK_ALIGN) - 1; + if (layer->transform & HISI_FB_TRANSFORM_ROT_90) { + afbc_header_rect.left = + ALIGN_DOWN(layer->dst_rect.x, + AFBC_HEADER_ADDR_ALIGN); + afbc_header_rect.top = + ALIGN_DOWN(layer->dst_rect.y + + (ov_block_rect->x - layer->dst_rect.x), + AFBC_BLOCK_ALIGN); + + afbc_payload_rect.left = + ALIGN_DOWN(layer->dst_rect.x, AFBC_BLOCK_ALIGN); + afbc_payload_rect.top = afbc_header_rect.top; + + afbc_header_start_pos = + (layer->dst_rect.x - + afbc_header_rect.left) / AFBC_BLOCK_ALIGN; + } else { + afbc_header_rect.left = + ALIGN_DOWN(in_rect.x, AFBC_HEADER_ADDR_ALIGN); + afbc_header_rect.top = + ALIGN_DOWN(in_rect.y, AFBC_BLOCK_ALIGN); + + afbc_payload_rect.left = + ALIGN_DOWN(in_rect.x, AFBC_BLOCK_ALIGN); + afbc_payload_rect.top = afbc_header_rect.top; + + afbc_header_start_pos = + (in_rect.x - + afbc_header_rect.left) / AFBC_BLOCK_ALIGN; + } + + if (afbc_header_start_pos < 0) { + HISI_FB_ERR("afbc_header_start_pos(%d) is invalid!\n", + afbc_header_start_pos); + return -EINVAL; + } + + afbce_hreg_pic_blks = + (in_rect.w / AFBC_BLOCK_ALIGN) * (in_rect.h / + AFBC_BLOCK_ALIGN) - 1; + + afbc_header_stride = + (layer->dst.width / AFBC_BLOCK_ALIGN) * + AFBC_HEADER_STRIDE_BLOCK; + + afbc_header_pointer_offset = + (afbc_header_rect.top / AFBC_BLOCK_ALIGN) * + afbc_header_stride + + (afbc_header_rect.left / AFBC_BLOCK_ALIGN) * + AFBC_HEADER_STRIDE_BLOCK; + + afbc_header_addr = + layer->dst.afbc_header_addr + afbc_header_pointer_offset; + + if ((afbc_header_addr & (AFBC_HEADER_ADDR_ALIGN - 1)) || + (afbc_header_stride & (AFBC_HEADER_STRIDE_ALIGN - 1))) { + HISI_FB_ERR + ("wb_layer afbc_header_addr(0x%x) is not %d bytes aligned, or " + "afbc_header_stride(0x%x) is not %d bytes aligned!\n", + afbc_header_addr, AFBC_HEADER_ADDR_ALIGN, + afbc_header_stride, AFBC_HEADER_STRIDE_ALIGN); + return -EINVAL; + } + + if (layer->dst.bpp == 4) { + stride_align = AFBC_PAYLOAD_STRIDE_ALIGN_32; + addr_align = AFBC_PAYLOAD_ADDR_ALIGN_32; + } else if (layer->dst.bpp == 2) { + stride_align = AFBC_PAYLOAD_STRIDE_ALIGN_16; + addr_align = AFBC_PAYLOAD_ADDR_ALIGN_16; + } else { + HISI_FB_ERR("bpp(%d) not supported!\n", layer->dst.bpp); + return -EINVAL; + } + + afbc_payload_stride = layer->dst.afbc_payload_stride; + if (layer->dst.afbc_scramble_mode != DSS_AFBC_SCRAMBLE_MODE2) { + afbc_payload_stride = + (layer->dst.width / AFBC_BLOCK_ALIGN) * + stride_align; + } + afbc_payload_addr = layer->dst.afbc_payload_addr + + (afbc_payload_rect.top / AFBC_BLOCK_ALIGN) * + afbc_payload_stride + + (afbc_payload_rect.left / AFBC_BLOCK_ALIGN) * stride_align; + + if ((afbc_payload_addr & (addr_align - 1)) || + (afbc_payload_stride & (stride_align - 1))) { + HISI_FB_ERR + ("afbc_payload_addr(0x%x) is not %d bytes aligned, or " + "afbc_payload_stride(0x%x) is not %d bytes aligned!\n", + afbc_payload_addr, addr_align, afbc_payload_stride, + stride_align); + return -EINVAL; + } + + if (g_debug_ovl_online_composer) { + HISI_FB_INFO + ("aligned_rect(%d,%d,%d,%d), afbc_rect(%d,%d,%d,%d)!\n", + in_rect.x, in_rect.y, + DSS_WIDTH(in_rect.x + in_rect.w), + DSS_WIDTH(in_rect.y + in_rect.h), + afbc_payload_rect.left, afbc_payload_rect.top, + afbc_payload_rect.right, afbc_payload_rect.bottom); + } + + wdma->ctrl = set_bits32(wdma->ctrl, wdma_format, 5, 3); + wdma->ctrl = + set_bits32(wdma->ctrl, (mmu_enable ? 0x1 : 0x0), 1, 8); + wdma->ctrl = set_bits32(wdma->ctrl, wdma_transform, 3, 9); + if (last_block) { + wdma->ch_ctl = set_bits32(wdma->ch_ctl, 0x1d, 5, 0); + } else { + wdma->ch_ctl = set_bits32(wdma->ch_ctl, 0xd, 5, 0); + } + + wdma->rot_size = set_bits32(wdma->rot_size, + (DSS_WIDTH(in_rect.w) | + (DSS_HEIGHT(in_rect.h) << 16)), 32, 0); + + wdma->afbce_hreg_pic_blks = + set_bits32(wdma->afbce_hreg_pic_blks, + afbce_hreg_pic_blks, 24, 0); + + wdma->afbce_hreg_format = + set_bits32(wdma->afbce_hreg_format, + (isYUVPackage(layer->dst.format) ? 0x0 : 0x1), 1, 21); + + wdma->afbce_hreg_hdr_ptr_lo = + set_bits32(wdma->afbce_hreg_hdr_ptr_lo, + afbc_header_addr, 32, 0); + + wdma->afbce_hreg_pld_ptr_lo = + set_bits32(wdma->afbce_hreg_pld_ptr_lo, + afbc_payload_addr, 32, 0); + + wdma->afbce_picture_size = + set_bits32(wdma->afbce_picture_size, + ((DSS_WIDTH(in_rect.w) << 16) | + DSS_HEIGHT(in_rect.h)), 32, 0); + + wdma->afbce_header_srtide = + set_bits32(wdma->afbce_header_srtide, + ((afbc_header_start_pos << 14) | + afbc_header_stride), 16, 0); + + wdma->afbce_payload_stride = + set_bits32(wdma->afbce_payload_stride, afbc_payload_stride, 20, 0); + + wdma->afbce_enc_os_cfg = + set_bits32(wdma->afbce_enc_os_cfg, + DSS_AFBCE_ENC_OS_CFG_DEFAULT_VAL, 3, 0); + + wdma->afbce_mem_ctrl = + set_bits32(wdma->afbce_mem_ctrl, 0x0, 12, 0); + wdma->afbce_threshold = + set_bits32(wdma->afbce_threshold, 0x2, 32, 0); + wdma->afbce_header_pointer_offset = + set_bits32(wdma->afbce_header_pointer_offset, + afbc_header_pointer_offset, 32, 0); + wdma->afbce_scramble_mode = + set_bits32(wdma->afbce_scramble_mode, + layer->dst.afbc_scramble_mode, 2, 0); + + return 0; + } + + if (layer->need_cap & CAP_TILE) { + l2t_interleave_n = + hisi_get_rdma_tile_interleave(layer->dst.stride); + if (l2t_interleave_n < MIN_INTERLEAVE) { + HISI_FB_ERR + ("tile stride should be 256*2^n, error stride:%d!\n", + layer->dst.stride); + return -EINVAL; + } + + if (wdma_addr & (TILE_DMA_ADDR_ALIGN - 1)) { + HISI_FB_ERR + ("tile wdma_addr(0x%x) is not %d bytes aligned.\n", + wdma_addr, TILE_DMA_ADDR_ALIGN); + return -EINVAL; + } + } + + if (layer->transform & HISI_FB_TRANSFORM_ROT_90) { + temp = in_rect.w; + in_rect.w = in_rect.h; + in_rect.h = temp; + + oft_x0 = 0; + oft_x1 = DSS_WIDTH(in_rect.w) / aligned_pixel; + oft_y0 = 0; + oft_y1 = DSS_HEIGHT(ov_block_rect->w); + } else { + oft_x0 = in_rect.x / aligned_pixel; + oft_x1 = DSS_WIDTH(in_rect.x + in_rect.w) / aligned_pixel; + oft_y0 = in_rect.y; + oft_y1 = DSS_HEIGHT(in_rect.y + in_rect.h); + } + + wdma_addr = + hisi_calculate_display_addr_wb(mmu_enable, layer, in_rect, + ov_block_rect, DSS_ADDR_PLANE0); + wdma_stride = layer->dst.stride / DMA_ALIGN_BYTES; + + data_num = (oft_x1 - oft_x0 + 1) * (oft_y1 - oft_y0 + 1); + if (layer->transform & HISI_FB_TRANSFORM_ROT_90) { + wdma->rot_size = set_bits32(wdma->rot_size, + (DSS_WIDTH(ov_block_rect->w) | + (DSS_HEIGHT(aligned_rect.h) << 16)), 32, 0); + + if (ov_block_rect) { + wdma_buf_width = DSS_HEIGHT(ov_block_rect->h); + wdma_buf_height = DSS_WIDTH(ov_block_rect->w); + } else { + wdma_buf_width = DSS_HEIGHT(layer->src_rect.h); + wdma_buf_height = DSS_WIDTH(layer->src_rect.w); + } + } else { + if (ov_block_rect) { + wdma_buf_width = DSS_WIDTH(ov_block_rect->w); + wdma_buf_height = DSS_HEIGHT(ov_block_rect->h); + } else { + wdma_buf_width = DSS_WIDTH(layer->src_rect.w); + wdma_buf_height = DSS_HEIGHT(layer->src_rect.h); + } + } + + wdma->oft_x0 = set_bits32(wdma->oft_x0, oft_x0, 12, 0); + wdma->oft_y0 = set_bits32(wdma->oft_y0, oft_y0, 16, 0); + wdma->oft_x1 = set_bits32(wdma->oft_x1, oft_x1, 12, 0); + wdma->oft_y1 = set_bits32(wdma->oft_y1, oft_y1, 16, 0); + + wdma->ctrl = set_bits32(wdma->ctrl, wdma_format, 5, 3); + wdma->ctrl = set_bits32(wdma->ctrl, wdma_transform, 3, 9); + wdma->ctrl = set_bits32(wdma->ctrl, (mmu_enable ? 0x1 : 0x0), 1, 8); + wdma->data_num = set_bits32(wdma->data_num, data_num, 30, 0); + + wdma->ctrl = + set_bits32(wdma->ctrl, ((layer->need_cap & CAP_TILE) ? 0x1 : 0x0), + 1, 1); + wdma->tile_scram = + set_bits32(wdma->tile_scram, + ((layer->need_cap & CAP_TILE) ? 0x1 : 0x0), 1, 0); + + wdma->data_addr = set_bits32(wdma->data_addr, wdma_addr, 32, 0); + wdma->stride0 = + set_bits32(wdma->stride0, wdma_stride | (l2t_interleave_n << 16), + 20, 0); + + if (is_YUV_SP_420(layer->dst.format)) { + wdma_addr = + hisi_calculate_display_addr_wb(mmu_enable, layer, in_rect, + ov_block_rect, DSS_ADDR_PLANE1); + + wdma_stride = layer->dst.stride_plane1 / DMA_ALIGN_BYTES; + wdma->data1_addr = + set_bits32(wdma->data1_addr, wdma_addr, 32, 0); + wdma->stride1 = set_bits32(wdma->stride1, wdma_stride, 13, 0); + } + + if (last_block) { + wdma->ch_ctl = set_bits32(wdma->ch_ctl, 1, 1, 4); + } else { + wdma->ch_ctl = set_bits32(wdma->ch_ctl, 0, 1, 4); + } + wdma->ch_ctl = set_bits32(wdma->ch_ctl, 1, 1, 3); + wdma->ch_ctl = set_bits32(wdma->ch_ctl, 1, 1, 0); + + wdma->dma_buf_size = set_bits32(wdma->dma_buf_size, + wdma_buf_width | (wdma_buf_height << 16), 32, 0); + + return 0; +} + +/******************************************************************************* + ** DSS GLOBAL + */ +int hisi_dss_module_init(struct hisi_fb_data_type *hisifd) +{ + BUG_ON(hisifd == NULL); + + memcpy(&(hisifd->dss_module), &(hisifd->dss_module_default), + sizeof(dss_module_reg_t)); + + return 0; +} + +int hisi_dss_module_default(struct hisi_fb_data_type *hisifd) +{ + dss_module_reg_t *dss_module = NULL; + uint32_t module_base = 0; + char __iomem *dss_base = NULL; + int i = 0; + + BUG_ON(hisifd == NULL); + dss_base = hisifd->dss_base; + BUG_ON(dss_base == NULL); + + dss_module = &(hisifd->dss_module_default); + memset(dss_module, 0, sizeof(dss_module_reg_t)); + + for (i = 0; i < DSS_MCTL_IDX_MAX; i++) { + module_base = g_dss_module_ovl_base[i][MODULE_MCTL_BASE]; + if (module_base != 0) { + dss_module->mctl_base[i] = dss_base + module_base; + hisi_dss_mctl_init(dss_module->mctl_base[i], + &(dss_module->mctl[i])); + } + } + + for (i = 0; i < DSS_OVL_IDX_MAX; i++) { + module_base = g_dss_module_ovl_base[i][MODULE_OVL_BASE]; + if (module_base != 0) { + dss_module->ov_base[i] = dss_base + module_base; + hisi_dss_ovl_init(dss_module->ov_base[i], + &(dss_module->ov[i]), i); + } + } + + for (i = 0; i < DSS_CHN_MAX_DEFINE; i++) { + module_base = g_dss_module_base[i][MODULE_AIF0_CHN]; + if (module_base != 0) { + dss_module->aif_ch_base[i] = dss_base + module_base; + hisi_dss_aif_init(dss_module->aif_ch_base[i], + &(dss_module->aif[i])); + } + + module_base = g_dss_module_base[i][MODULE_AIF1_CHN]; + if (module_base != 0) { + dss_module->aif1_ch_base[i] = dss_base + module_base; + hisi_dss_aif_init(dss_module->aif1_ch_base[i], + &(dss_module->aif1[i])); + } + + module_base = g_dss_module_base[i][MODULE_MIF_CHN]; + if (module_base != 0) { + dss_module->mif_ch_base[i] = dss_base + module_base; + hisi_dss_mif_init(dss_module->mif_ch_base[i], + &(dss_module->mif[i]), i); + } + + module_base = g_dss_module_base[i][MODULE_MCTL_CHN_MUTEX]; + if (module_base != 0) { + dss_module->mctl_ch_base[i].chn_mutex_base = + dss_base + module_base; + } + + module_base = g_dss_module_base[i][MODULE_MCTL_CHN_FLUSH_EN]; + if (module_base != 0) { + dss_module->mctl_ch_base[i].chn_flush_en_base = + dss_base + module_base; + } + + module_base = g_dss_module_base[i][MODULE_MCTL_CHN_OV_OEN]; + if (module_base != 0) { + dss_module->mctl_ch_base[i].chn_ov_en_base = + dss_base + module_base; + } + + module_base = g_dss_module_base[i][MODULE_MCTL_CHN_STARTY]; + if (module_base != 0) { + dss_module->mctl_ch_base[i].chn_starty_base = + dss_base + module_base; + hisi_dss_mctl_ch_starty_init( + dss_module->mctl_ch_base[i].chn_starty_base, + &(dss_module->mctl_ch[i])); + } + + module_base = g_dss_module_base[i][MODULE_MCTL_CHN_MOD_DBG]; + if (module_base != 0) { + dss_module->mctl_ch_base[i].chn_mod_dbg_base = + dss_base + module_base; + hisi_dss_mctl_ch_mod_dbg_init( + dss_module->mctl_ch_base[i].chn_mod_dbg_base, + &(dss_module->mctl_ch[i])); + } + + module_base = g_dss_module_base[i][MODULE_DMA]; + if (module_base != 0) { + dss_module->dma_base[i] = dss_base + module_base; + if (i < DSS_WCHN_W0 || i == DSS_RCHN_V2) { + hisi_dss_rdma_init(dss_module->dma_base[i], + &(dss_module->rdma[i])); + } else { + hisi_dss_wdma_init(dss_module->dma_base[i], + &(dss_module->wdma[i])); + } + + if ((i == DSS_RCHN_V0) || (i == DSS_RCHN_V1) + || (i == DSS_RCHN_V2)) { + hisi_dss_rdma_u_init(dss_module->dma_base[i], + &(dss_module->rdma[i])); + hisi_dss_rdma_v_init(dss_module->dma_base[i], + &(dss_module->rdma[i])); + } + } + + module_base = g_dss_module_base[i][MODULE_DFC]; + if (module_base != 0) { + dss_module->dfc_base[i] = dss_base + module_base; + hisi_dss_dfc_init(dss_module->dfc_base[i], + &(dss_module->dfc[i])); + } + + module_base = g_dss_module_base[i][MODULE_SCL]; + if (module_base != 0) { + dss_module->scl_base[i] = dss_base + module_base; + hisi_dss_scl_init(dss_module->scl_base[i], + &(dss_module->scl[i])); + } + + module_base = DSS_POST_SCF_OFFSET; + if (module_base != 0) { + dss_module->post_scf_base = dss_base + module_base; + hisi_dss_post_scf_init(dss_module->post_scf_base, + &(dss_module->post_scf)); + } + module_base = g_dss_module_base[i][MODULE_PCSC]; + if (module_base != 0) { + dss_module->pcsc_base[i] = dss_base + module_base; + hisi_dss_csc_init(dss_module->pcsc_base[i], + &(dss_module->pcsc[i])); + } + + module_base = g_dss_module_base[i][MODULE_ARSR2P]; + if (module_base != 0) { + dss_module->arsr2p_base[i] = dss_base + module_base; + hisi_dss_arsr2p_init(dss_module->arsr2p_base[i], + &(dss_module->arsr2p[i])); + } + module_base = g_dss_module_base[i][MODULE_POST_CLIP]; + if (module_base != 0) { + dss_module->post_clip_base[i] = dss_base + module_base; + hisi_dss_post_clip_init(dss_module->post_clip_base[i], + &(dss_module->post_clip[i])); + } + + module_base = g_dss_module_base[i][MODULE_CSC]; + if (module_base != 0) { + dss_module->csc_base[i] = dss_base + module_base; + hisi_dss_csc_init(dss_module->csc_base[i], + &(dss_module->csc[i])); + } + } + + module_base = DSS_MCTRL_SYS_OFFSET; + if (module_base != 0) { + dss_module->mctl_sys_base = dss_base + module_base; + hisi_dss_mctl_sys_init(dss_module->mctl_sys_base, + &(dss_module->mctl_sys)); + } + + module_base = DSS_SMMU_OFFSET; + if (module_base != 0) { + dss_module->smmu_base = dss_base + module_base; + hisi_dss_smmu_init(dss_module->smmu_base, &(dss_module->smmu)); + } + + return 0; +} + +int hisi_dss_ch_module_set_regs(struct hisi_fb_data_type *hisifd, + int32_t mctl_idx, int chn_idx, uint32_t wb_type, + bool enable_cmdlist) +{ + dss_module_reg_t *dss_module = NULL; + int i = 0; + int ret = 0; + uint32_t tmp = 0; + + BUG_ON(hisifd == NULL); + BUG_ON((chn_idx < 0) || (chn_idx >= DSS_CHN_MAX_DEFINE)); + + dss_module = &(hisifd->dss_module); + i = chn_idx; + + if (enable_cmdlist) { + if (chn_idx == DSS_RCHN_V2) { + tmp = (0x1 << DSS_CMDLIST_V2); + hisifd->cmdlist_idx = DSS_CMDLIST_V2; + } else if (chn_idx == DSS_WCHN_W2) { + tmp = (0x1 << DSS_CMDLIST_W2); + hisifd->cmdlist_idx = DSS_CMDLIST_W2; + } else { + tmp = (0x1 << chn_idx); + hisifd->cmdlist_idx = chn_idx; + } + + ret = + hisi_cmdlist_add_new_node(hisifd, tmp, 0, 0, 0, 0, wb_type); + if (ret != 0) { + HISI_FB_ERR("fb%d, hisi_cmdlist_add_new_node err:%d \n", + hisifd->index, ret); + goto err_return; + } + } + + if (dss_module->mctl_ch_used[i] == 1) { + hisi_dss_mctl_ch_set_reg(hisifd, + &(dss_module->mctl_ch_base[i]), + &(dss_module->mctl_ch[i]), mctl_idx); + } + + if (dss_module->smmu_used == 1) { + hisi_dss_smmu_ch_set_reg(hisifd, dss_module->smmu_base, + &(dss_module->smmu), i); + } + + if (dss_module->dma_used[i] == 1) { + if (i < DSS_WCHN_W0 || i == DSS_RCHN_V2) { + hisi_dss_rdma_set_reg(hisifd, dss_module->dma_base[i], + &(dss_module->rdma[i])); + } else { + hisi_dss_wdma_set_reg(hisifd, dss_module->dma_base[i], + &(dss_module->wdma[i])); + } + + if ((i == DSS_RCHN_V0) || (i == DSS_RCHN_V1) + || (i == DSS_RCHN_V2)) { + hisi_dss_rdma_u_set_reg(hisifd, dss_module->dma_base[i], + &(dss_module->rdma[i])); + hisi_dss_rdma_v_set_reg(hisifd, dss_module->dma_base[i], + &(dss_module->rdma[i])); + } + } + + if (dss_module->aif_ch_used[i] == 1) { + hisi_dss_aif_ch_set_reg(hisifd, dss_module->aif_ch_base[i], + &(dss_module->aif[i])); + } + + if (dss_module->aif1_ch_used[i] == 1) { + hisi_dss_aif_ch_set_reg(hisifd, dss_module->aif1_ch_base[i], + &(dss_module->aif1[i])); + } + + if (dss_module->mif_used[i] == 1) { + hisi_dss_mif_set_reg(hisifd, dss_module->mif_ch_base[i], + &(dss_module->mif[i]), i); + } + + if (dss_module->dfc_used[i] == 1) { + hisi_dss_dfc_set_reg(hisifd, dss_module->dfc_base[i], + &(dss_module->dfc[i])); + } + + if (dss_module->scl_used[i] == 1) { + hisi_dss_chn_scl_load_filter_coef_set_reg(hisifd, false, + chn_idx, + dss_module->scl[i].fmt); + hisi_dss_scl_set_reg(hisifd, dss_module->scl_base[i], + &(dss_module->scl[i])); + } + if (hisifd->dss_module.post_cilp_used[i]) { + hisi_dss_post_clip_set_reg(hisifd, + dss_module->post_clip_base[i], + &(dss_module->post_clip[i])); + } + if (dss_module->pcsc_used[i] == 1) { + hisi_dss_csc_set_reg(hisifd, dss_module->pcsc_base[i], + &(dss_module->pcsc[i])); + } + + if (dss_module->arsr2p_used[i] == 1) { + hisi_dss_arsr2p_set_reg(hisifd, dss_module->arsr2p_base[i], + &(dss_module->arsr2p[i])); + } + + if (dss_module->csc_used[i] == 1) { + hisi_dss_csc_set_reg(hisifd, dss_module->csc_base[i], + &(dss_module->csc[i])); + } + + if (dss_module->mctl_ch_used[i] == 1) { + hisi_dss_mctl_sys_ch_set_reg(hisifd, + &(dss_module->mctl_ch_base[i]), + &(dss_module->mctl_ch[i]), i, true); + } + + return 0; + + err_return: + return ret; +} + +int hisi_dss_ov_module_set_regs(struct hisi_fb_data_type *hisifd, + dss_overlay_t *pov_req, int ovl_idx, + bool enable_cmdlist, int task_end, int last, + bool is_first_ov_block) +{ + dss_module_reg_t *dss_module = NULL; + int i = 0; + int ret = 0; + uint32_t tmp = 0; + + BUG_ON(hisifd == NULL); + + if (pov_req && pov_req->wb_layer_infos[0].chn_idx == DSS_WCHN_W2) { + return 0; + } + + dss_module = &(hisifd->dss_module); + i = ovl_idx; + + if (enable_cmdlist) { + tmp = (0x1 << (DSS_CMDLIST_OV0 + ovl_idx)); + hisifd->cmdlist_idx = DSS_CMDLIST_OV0 + ovl_idx; + + ret = + hisi_cmdlist_add_new_node(hisifd, tmp, 0, task_end, 0, last, + 0); + if (ret != 0) { + HISI_FB_ERR("fb%d, hisi_cmdlist_add_new_node err:%d \n", + hisifd->index, ret); + goto err_return; + } + } + + if (dss_module->mctl_used[i] == 1) { + hisi_dss_mctl_ov_set_reg(hisifd, dss_module->mctl_base[i], + &(dss_module->mctl[i]), ovl_idx, + enable_cmdlist); + } + + if (is_first_ov_block) { + if (dss_module->dirty_region_updt_used == 1) + hisi_dss_dirty_region_dbuf_set_reg(hisifd, + hisifd->dss_base, + &(dss_module-> + dirty_region_updt)); + } + + if (dss_module->ov_used[i] == 1) { + hisi_dss_ovl_set_reg(hisifd, dss_module->ov_base[i], + &(dss_module->ov[i]), ovl_idx); + } + + if (hisifd->dss_module.post_scf_used == 1) { + hisi_dss_post_scf_set_reg(hisifd, + hisifd->dss_module.post_scf_base, + &(hisifd->dss_module.post_scf)); + } + + if (dss_module->mctl_sys_used == 1) { + hisi_dss_mctl_sys_set_reg(hisifd, dss_module->mctl_sys_base, + &(dss_module->mctl_sys), ovl_idx); + } + + return 0; + + err_return: + return ret; +} + +int hisi_dss_prev_module_set_regs(struct hisi_fb_data_type *hisifd, + dss_overlay_t *pov_req, + uint32_t cmdlist_pre_idxs, + bool enable_cmdlist, bool *use_comm_mmbuf) +{ + dss_module_reg_t *dss_module = NULL; + dss_layer_t *layer = NULL; + dss_wb_layer_t *wb_layer = NULL; + int32_t ovl_idx = 0; + int32_t layer_idx = 0; + int32_t mctl_idx = 0; + int chn_idx = 0; + int i = 0; + int j = 0; + int k = 0; + int m = 0; + bool has_base = false; + int ret = 0; + uint32_t tmp = 0; + uint32_t cmdlist_idxs_temp = 0; + dss_overlay_block_t *pov_h_block_infos = NULL; + dss_overlay_block_t *pov_h_block = NULL; + dss_mmbuf_t offline_mmbuf[DSS_CHN_MAX_DEFINE]; + bool has_rot = false; + + BUG_ON(hisifd == NULL); + BUG_ON(pov_req == NULL); + + ovl_idx = pov_req->ovl_idx; + dss_module = &(hisifd->dss_module); + + if (enable_cmdlist) { + if (pov_req->wb_enable) { + ret = + hisi_cmdlist_add_new_node(hisifd, cmdlist_pre_idxs, + 0, 1, 1, 1, 0); + } else { + ret = + hisi_cmdlist_add_new_node(hisifd, cmdlist_pre_idxs, + 0, 0, 0, 0, 0); + } + if (ret != 0) { + HISI_FB_ERR("fb%d, hisi_cmdlist_add_new_node err:%d \n", + hisifd->index, ret); + goto err_return; + } + } + + memset(offline_mmbuf, 0x0, sizeof(offline_mmbuf)); + cmdlist_idxs_temp = cmdlist_pre_idxs; + pov_h_block_infos = (dss_overlay_block_t *) pov_req->ov_block_infos_ptr; + for (m = 0; m < pov_req->ov_block_nums; m++) { + pov_h_block = &(pov_h_block_infos[m]); + + for (i = 0; i < pov_h_block->layer_nums; i++) { + layer = &(pov_h_block->layer_infos[i]); + chn_idx = layer->chn_idx; + layer_idx = layer->layer_idx; + + if (chn_idx == DSS_RCHN_V2) { + mctl_idx = DSS_MCTL5; + } else { + mctl_idx = ovl_idx; + } + + if (layer->need_cap & (CAP_BASE | CAP_DIM | CAP_PURE_COLOR)) { + if (layer->need_cap & CAP_BASE) + has_base = true; + + continue; + } + + if (ovl_idx == DSS_OVL0) { + if ((layer->need_cap & CAP_AFBCD) + && (layer->dst_rect.y >= + pov_h_block->ov_block_rect.y)) { + if (j < DSS_CHN_MAX_DEFINE) { + g_pre_online_mmbuf[j].addr = + layer->img.mmbuf_base; + g_pre_online_mmbuf[j].size = + layer->img.mmbuf_size; + j++; + } + } + } + + if (ovl_idx == DSS_OVL2) { + if (layer->need_cap & CAP_AFBCD) { + if (j < DSS_CHN_MAX_DEFINE) { + offline_mmbuf[j].addr = + layer->img.mmbuf_base; + offline_mmbuf[j].size = + layer->img.mmbuf_size; + j++; + } + } + } + + if (chn_idx == DSS_RCHN_V2) { + tmp = (0x1 << DSS_CMDLIST_V2); + hisifd->cmdlist_idx = DSS_CMDLIST_V2; + } else { + tmp = (0x1 << chn_idx); + hisifd->cmdlist_idx = chn_idx; + } + + if ((cmdlist_idxs_temp & tmp) != tmp) { + continue; + } else { + cmdlist_idxs_temp &= (~tmp); + } + + hisi_dss_chn_set_reg_default_value(hisifd, + dss_module->dma_base[chn_idx]); + hisi_dss_smmu_ch_set_reg(hisifd, dss_module->smmu_base, + &(dss_module->smmu), chn_idx); + hisi_dss_mif_set_reg(hisifd, + dss_module->mif_ch_base[chn_idx], + &(dss_module->mif[chn_idx]), chn_idx); + hisi_dss_aif_ch_set_reg(hisifd, + dss_module->aif_ch_base[chn_idx], + &(dss_module->aif[chn_idx])); + + dss_module->mctl_ch[chn_idx].chn_mutex = + set_bits32(dss_module->mctl_ch[chn_idx].chn_mutex, + 0x1, 1, 0); + dss_module->mctl_ch[chn_idx].chn_flush_en = + set_bits32(dss_module->mctl_ch[chn_idx].chn_flush_en, + 0x1, 1, 0); + dss_module->mctl_ch[chn_idx].chn_ov_oen = + set_bits32(dss_module->mctl_ch[chn_idx].chn_ov_oen, + 0x0, 32, 0); + dss_module->mctl_ch_used[chn_idx] = 1; + + hisi_dss_mctl_sys_ch_set_reg(hisifd, + &(dss_module->mctl_ch_base[chn_idx]), + &(dss_module->mctl_ch[chn_idx]), + chn_idx, false); + } + } + + if (g_debug_dump_mmbuf) { + if (ovl_idx == DSS_OVL0) { + for (i = 0; i < DSS_CHN_MAX_DEFINE; i++) { + HISI_FB_INFO + ("g_pre_online_mmbuf[%d].addr=%d, size=%d, j=%d\n", + i, g_pre_online_mmbuf[i].addr, + g_pre_online_mmbuf[i].size, j); + } + } + } + + if (pov_req->wb_enable + && ((ovl_idx > DSS_OVL1) || (mctl_idx == DSS_MCTL5))) { + if (mctl_idx != DSS_MCTL5) { + hisifd->cmdlist_idx = DSS_CMDLIST_OV0 + ovl_idx; + + + hisi_dss_ov_set_reg_default_value(hisifd, + dss_module->ov_base[ovl_idx], + ovl_idx); + } + + for (k = 0; k < pov_req->wb_layer_nums; k++) { + wb_layer = &(pov_req->wb_layer_infos[k]); + chn_idx = wb_layer->chn_idx; + if (wb_layer->transform & HISI_FB_TRANSFORM_ROT_90) + has_rot = true; + + if (chn_idx == DSS_WCHN_W2) { + hisifd->cmdlist_idx = DSS_CMDLIST_W2; + } else { + hisifd->cmdlist_idx = chn_idx; + } + + hisi_dss_chn_set_reg_default_value(hisifd, + dss_module->dma_base[chn_idx]); + hisi_dss_mif_set_reg(hisifd, + dss_module->mif_ch_base[chn_idx], + &(dss_module->mif[chn_idx]), chn_idx); + hisi_dss_aif_ch_set_reg(hisifd, + dss_module->aif_ch_base[chn_idx], + &(dss_module->aif[chn_idx])); + + dss_module->mctl_ch[chn_idx].chn_mutex = + set_bits32(dss_module->mctl_ch[chn_idx].chn_mutex, + 0x1, 1, 0); + dss_module->mctl_ch[chn_idx].chn_flush_en = + set_bits32(dss_module->mctl_ch[chn_idx].chn_flush_en, + 0x1, 1, 0); + dss_module->mctl_ch[chn_idx].chn_ov_oen = + set_bits32(dss_module->mctl_ch[chn_idx].chn_ov_oen, + 0x0, 32, 0); + dss_module->mctl_ch_used[chn_idx] = 1; + + hisi_dss_mctl_sys_ch_set_reg(hisifd, + &(dss_module->mctl_ch_base[chn_idx]), + &(dss_module->mctl_ch[chn_idx]), + chn_idx, false); + } + + if (mctl_idx != DSS_MCTL5) { + hisifd->cmdlist_idx = DSS_CMDLIST_OV0 + ovl_idx; + + dss_module->mctl_sys.chn_ov_sel_used[ovl_idx] = 1; + dss_module->mctl_sys.wch_ov_sel_used[ovl_idx - + DSS_OVL2] = 1; + dss_module->mctl_sys.ov_flush_en_used[ovl_idx] = 1; + dss_module->mctl_sys.ov_flush_en[ovl_idx] = + set_bits32(dss_module->mctl_sys.ov_flush_en[ovl_idx], + 0x1, 1, 0); + hisi_dss_mctl_sys_set_reg(hisifd, + dss_module->mctl_sys_base, + &(dss_module->mctl_sys), ovl_idx); + } + + for (i = 0; i < DSS_CHN_MAX_DEFINE; i++) { + for (k = 0; k < DSS_CHN_MAX_DEFINE; k++) { + if ((((offline_mmbuf[i].addr < + g_pre_online_mmbuf[k].addr + g_pre_online_mmbuf[k].size) + && (offline_mmbuf[i].addr >= + g_pre_online_mmbuf[k].addr)) + || + ((g_pre_online_mmbuf[k].addr < + offline_mmbuf[i].addr + offline_mmbuf[i].size) + && (g_pre_online_mmbuf[k].addr >= + offline_mmbuf[i].addr))) + && offline_mmbuf[i].size) { + if (use_comm_mmbuf) { + *use_comm_mmbuf = true; + break; + } + } + } + } + + if (g_debug_dump_mmbuf) { + for (i = 0; i < DSS_CHN_MAX_DEFINE; i++) { + HISI_FB_INFO + ("offline_mmbuf[%d].addr=%d, size=%d, use_comm_mmbuf=%d, j=%d\n", + i, offline_mmbuf[i].addr, + offline_mmbuf[i].size, *use_comm_mmbuf, j); + } + } + + if (!has_rot) { + memset(g_pre_online_mmbuf, 0x0, + sizeof(g_pre_online_mmbuf)); + } + } + + return 0; + + err_return: + return ret; +} + +void hisi_dss_unflow_handler(struct hisi_fb_data_type *hisifd, + dss_overlay_t *pov_req, bool unmask) +{ + uint32_t tmp = 0; + + BUG_ON(hisifd == NULL); + if (pov_req->ovl_idx == DSS_OVL0) { + tmp = + inp32(hisifd->dss_base + DSS_LDI0_OFFSET + + LDI_CPU_ITF_INT_MSK); + if (unmask) { + tmp &= ~BIT_LDI_UNFLOW; + } else { + tmp |= BIT_LDI_UNFLOW; + } + outp32(hisifd->dss_base + DSS_LDI0_OFFSET + LDI_CPU_ITF_INT_MSK, + tmp); + + } else if (pov_req->ovl_idx == DSS_OVL1) { + tmp = + inp32(hisifd->dss_base + DSS_LDI1_OFFSET + + LDI_CPU_ITF_INT_MSK); + if (unmask) { + tmp &= ~BIT_LDI_UNFLOW; + } else { + tmp |= BIT_LDI_UNFLOW; + } + outp32(hisifd->dss_base + DSS_LDI1_OFFSET + LDI_CPU_ITF_INT_MSK, + tmp); + } else { + ; + } +} + +/******************************************************************************* + ** compose handler + */ +int hisi_ov_compose_handler(struct hisi_fb_data_type *hisifd, + dss_overlay_t *pov_req, + dss_overlay_block_t *pov_h_block, + dss_layer_t *layer, + dss_rect_t *wb_dst_rect, + dss_rect_t *wb_ov_block_rect, + dss_rect_ltrb_t *clip_rect, + dss_rect_t *aligned_rect, + bool *rdma_stretch_enable, + bool *has_base, + bool csc_needed, bool enable_cmdlist) +{ + int ret = 0; + int32_t mctl_idx = 0; + + BUG_ON(hisifd == NULL); + BUG_ON(pov_h_block == NULL); + BUG_ON(layer == NULL); + BUG_ON(clip_rect == NULL); + BUG_ON(aligned_rect == NULL); + BUG_ON(rdma_stretch_enable == NULL); + + ret = hisi_dss_check_layer_par(hisifd, layer); + if (ret != 0) { + HISI_FB_ERR("hisi_dss_check_layer_par failed! ret = %d\n", ret); + goto err_return; + } + + if (layer->need_cap & (CAP_BASE | CAP_DIM | CAP_PURE_COLOR)) { + if (layer->need_cap & CAP_BASE) + *has_base = true; + + ret = + hisi_dss_ovl_layer_config(hisifd, pov_req, layer, + wb_ov_block_rect, *has_base); + if (ret != 0) { + HISI_FB_ERR + ("hisi_dss_ovl_config failed! need_cap=0x%x, ret=%d\n", + layer->need_cap, ret); + goto err_return; + } + + ret = + hisi_dss_mctl_ch_config(hisifd, pov_req, layer, NULL, + pov_req->ovl_idx, wb_ov_block_rect, + *has_base); + if (ret != 0) { + HISI_FB_ERR + ("hisi_dss_mctl_ch_config failed! ret = %d\n", ret); + goto err_return; + } + + return ret; + } + + if (g_debug_ovl_block_composer) { + HISI_FB_INFO + ("layer->dst_rect.y=%d, pov_h_block->ov_block_rect.y=%d," + "layer->chn_idx=%d, layer->layer_idx=%d\n", + layer->dst_rect.y, pov_h_block->ov_block_rect.y, + layer->chn_idx, layer->layer_idx); + } + + if (layer->dst_rect.y < pov_h_block->ov_block_rect.y) { + if (g_debug_ovl_block_composer) { + HISI_FB_INFO + ("layer->dst_rect.y=%d, pov_h_block->ov_block_rect.y=%d," + "layer->chn_idx=%d, layer->layer_idx=%d!!!!\n", + layer->dst_rect.y, pov_h_block->ov_block_rect.y, + layer->chn_idx, layer->layer_idx); + } + + ret = + hisi_dss_ovl_layer_config(hisifd, pov_req, layer, + wb_ov_block_rect, *has_base); + if (ret != 0) { + HISI_FB_ERR("hisi_dss_ovl_config failed, ret = %d\n", + ret); + goto err_return; + } + + ret = + hisi_dss_mctl_ch_config(hisifd, pov_req, layer, NULL, + pov_req->ovl_idx, wb_ov_block_rect, + *has_base); + if (ret != 0) { + HISI_FB_ERR + ("hisi_dss_mctl_ch_config failed! ret = %d\n", ret); + goto err_return; + } + + return ret; + } + + ret = hisi_dss_smmu_ch_config(hisifd, layer, NULL); + if (ret != 0) { + HISI_FB_ERR("hisi_dss_smmu_ch_config failed! ret = %d\n", ret); + goto err_return; + } + + if (g_debug_ovl_online_composer) { + HISI_FB_INFO + ("fb%d, rdma input, src_rect(%d,%d,%d,%d), " + "src_rect_mask(%d,%d,%d,%d), dst_rect(%d,%d,%d,%d).\n", + hisifd->index, layer->src_rect.x, layer->src_rect.y, + layer->src_rect.w, layer->src_rect.h, + layer->src_rect_mask.x, layer->src_rect_mask.y, + layer->src_rect_mask.w, layer->src_rect_mask.h, + layer->dst_rect.x, layer->dst_rect.y, layer->dst_rect.w, + layer->dst_rect.h); + } + + ret = hisi_dss_rdma_config(hisifd, pov_req->ovl_idx, layer, + clip_rect, aligned_rect, + rdma_stretch_enable); + if (ret != 0) { + HISI_FB_ERR("hisi_dss_rdma_config failed! ret = %d\n", ret); + goto err_return; + } + + if (g_debug_ovl_online_composer) { + HISI_FB_INFO + ("fb%d, rdma output, clip_rect(%d,%d,%d,%d), " + "aligned_rect(%d,%d,%d,%d), dst_rect(%d,%d,%d,%d).\n", + hisifd->index, clip_rect->left, clip_rect->right, + clip_rect->top, clip_rect->bottom, aligned_rect->x, + aligned_rect->y, aligned_rect->w, aligned_rect->h, + layer->dst_rect.x, layer->dst_rect.y, layer->dst_rect.w, + layer->dst_rect.h); + } + + ret = + hisi_dss_aif_ch_config(hisifd, pov_req, layer, wb_dst_rect, NULL, + pov_req->ovl_idx); + if (ret != 0) { + HISI_FB_ERR("hisi_dss_aif_ch_config failed! ret = %d\n", ret); + goto err_return; + } + + ret = + hisi_dss_aif1_ch_config(hisifd, pov_req, layer, NULL, + pov_req->ovl_idx); + if (ret != 0) { + HISI_FB_ERR("hisi_dss_aif1_ch_config failed! ret = %d\n", ret); + goto err_return; + } + + ret = hisi_dss_mif_config(hisifd, layer, NULL, *rdma_stretch_enable); + if (ret != 0) { + HISI_FB_ERR("hisi_dss_mif_config failed! ret = %d\n", ret); + goto err_return; + } + + ret = hisi_dss_rdfc_config(hisifd, layer, aligned_rect, *clip_rect); + if (ret != 0) { + HISI_FB_ERR("hisi_dss_rdfc_config failed! ret = %d\n", ret); + goto err_return; + } + + if (g_debug_ovl_online_composer) { + HISI_FB_INFO + ("fb%d, rdfc output, clip_rect(%d,%d,%d,%d), " + "aligned_rect(%d,%d,%d,%d), dst_rect(%d,%d,%d,%d).\n", + hisifd->index, clip_rect->left, clip_rect->right, + clip_rect->top, clip_rect->bottom, aligned_rect->x, + aligned_rect->y, aligned_rect->w, aligned_rect->h, + layer->dst_rect.x, layer->dst_rect.y, layer->dst_rect.w, + layer->dst_rect.h); + } + + ret = + hisi_dss_scl_config(hisifd, layer, aligned_rect, + *rdma_stretch_enable); + if (ret != 0) { + HISI_FB_ERR("hisi_dss_scl_config failed! ret = %d\n", ret); + goto err_return; + } + ret = + hisi_dss_arsr2p_config(hisifd, layer, aligned_rect, + *rdma_stretch_enable); + if (ret != 0) { + HISI_FB_ERR("hisi_dss_arsr2p_config failed! ret = %d\n", ret); + goto err_return; + } + + ret = hisi_dss_post_clip_config(hisifd, layer); + if (ret != 0) { + HISI_FB_ERR("hisi_dss_post_clip_config failed! ret = %d\n", + ret); + goto err_return; + } + + if (g_debug_ovl_online_composer) { + HISI_FB_INFO + ("fb%d, scf output, clip_rect(%d,%d,%d,%d), " + "aligned_rect(%d,%d,%d,%d), dst_rect(%d,%d,%d,%d).\n", + hisifd->index, clip_rect->left, clip_rect->right, + clip_rect->top, clip_rect->bottom, aligned_rect->x, + aligned_rect->y, aligned_rect->w, aligned_rect->h, + layer->dst_rect.x, layer->dst_rect.y, layer->dst_rect.w, + layer->dst_rect.h); + } + + if (csc_needed) { + ret = hisi_dss_csc_config(hisifd, layer, NULL); + if (ret != 0) { + HISI_FB_ERR("hisi_dss_csc_config failed! ret = %d\n", + ret); + goto err_return; + } + } + + ret = + hisi_dss_ovl_layer_config(hisifd, pov_req, layer, wb_ov_block_rect, + *has_base); + if (ret != 0) { + HISI_FB_ERR("hisi_dss_ovl_config failed, ret = %d\n", ret); + goto err_return; + } + + ret = + hisi_dss_mctl_ch_config(hisifd, pov_req, layer, NULL, + pov_req->ovl_idx, wb_ov_block_rect, + *has_base); + if (ret != 0) { + HISI_FB_ERR("hisi_dss_mctl_ch_config failed! ret = %d\n", ret); + goto err_return; + } + + if (layer->chn_idx == DSS_RCHN_V2) { + mctl_idx = DSS_MCTL5; + } else { + mctl_idx = pov_req->ovl_idx; + } + + ret = + hisi_dss_ch_module_set_regs(hisifd, mctl_idx, layer->chn_idx, 0, + enable_cmdlist); + if (ret != 0) { + HISI_FB_ERR + ("fb%d, hisi_dss_ch_module_set_regs failed! ret = %d\n", + hisifd->index, ret); + goto err_return; + } + + return 0; + + err_return: + return ret; +} + +/******************************************************************************* + ** + */ +DEFINE_SEMAPHORE(hisi_dss_mmbuf_sem); +static int mmbuf_refcount = 0; +static int dss_sr_refcount = 0; + +struct hisifb_mmbuf { + struct list_head list_node; + uint32_t addr; + uint32_t size; +}; + +static struct list_head *g_mmbuf_list = NULL; + +static void hisifb_dss_on(struct hisi_fb_data_type *hisifd, int enable_cmdlist) +{ + int prev_refcount = 0; + + BUG_ON(hisifd == NULL); + + HISI_FB_DEBUG("fb%d, +.\n", hisifd->index); + + down(&hisi_dss_mmbuf_sem); + + prev_refcount = dss_sr_refcount++; + if (!prev_refcount) { + hisi_dss_qos_on(hisifd); + hisi_dss_mmbuf_on(hisifd); + hisi_dss_mif_on(hisifd); + hisi_dss_smmu_on(hisifd); + hisi_dss_scl_coef_on(hisifd, false, SCL_COEF_YUV_IDX); + + if (enable_cmdlist) { + hisi_dss_cmdlist_qos_on(hisifd); + } + } + + up(&hisi_dss_mmbuf_sem); + + HISI_FB_DEBUG("fb%d, -, dss_sr_refcount=%d.\n", hisifd->index, + dss_sr_refcount); +} + +static void hisifb_dss_off(struct hisi_fb_data_type *hisifd, bool is_lp) +{ + struct hisifb_mmbuf *node, *_node_; + int new_refcount = 0; + + BUG_ON(hisifd == NULL); + + HISI_FB_DEBUG("fb%d, +.\n", hisifd->index); + + down(&hisi_dss_mmbuf_sem); + new_refcount = --dss_sr_refcount; + WARN_ON(new_refcount < 0); + + if (is_lp) { + if (!new_refcount) { + hisifd->ldi_data_gate_en = 0; + + memset(&(hisifd->ov_block_infos_prev_prev), 0, + HISI_DSS_OV_BLOCK_NUMS * + sizeof(dss_overlay_block_t)); + memset(&hisifd->ov_req_prev_prev, 0, + sizeof(dss_overlay_t)); + memset(&(hisifd->ov_block_infos_prev), 0, + HISI_DSS_OV_BLOCK_NUMS * + sizeof(dss_overlay_block_t)); + memset(&hisifd->ov_req_prev, 0, sizeof(dss_overlay_t)); + memset(&(hisifd->ov_block_infos), 0, + HISI_DSS_OV_BLOCK_NUMS * + sizeof(dss_overlay_block_t)); + memset(&hisifd->ov_req, 0, sizeof(dss_overlay_t)); + } + } + + if (!g_mmbuf_list || is_lp) { + up(&hisi_dss_mmbuf_sem); + return; + } + + if (!new_refcount) { + list_for_each_entry_safe(node, _node_, g_mmbuf_list, list_node) { + if ((node->addr > 0) && (node->size > 0)) { + gen_pool_free(hisifd->mmbuf_gen_pool, + node->addr, node->size); + HISI_FB_DEBUG + ("hisi_dss_mmbuf_free, addr=0x%x, size=%d.\n", + node->addr, node->size); + } + + list_del(&node->list_node); + kfree(node); + } + } + up(&hisi_dss_mmbuf_sem); + + HISI_FB_DEBUG("fb%d, -, dss_sr_refcount=%d.\n", hisifd->index, + dss_sr_refcount); +} + +void *hisi_dss_mmbuf_init(struct hisi_fb_data_type *hisifd) +{ + struct gen_pool *pool = NULL; + int order = 3; + size_t size = MMBUF_SIZE_MAX; + uint32_t addr = MMBUF_BASE; + int prev_refcount = 0; + + BUG_ON(hisifd == NULL); + + HISI_FB_DEBUG("fb%d, +.\n", hisifd->index); + + down(&hisi_dss_mmbuf_sem); + + prev_refcount = mmbuf_refcount++; + if (!prev_refcount) { + pool = gen_pool_create(order, 0); + if (pool == NULL) { + HISI_FB_ERR("fb%d, gen_pool_create failed!", + hisifd->index); + goto err_out; + } + + if (gen_pool_add(pool, addr, size, 0) != 0) { + gen_pool_destroy(pool); + HISI_FB_ERR("fb%d, gen_pool_add failed!", + hisifd->index); + goto err_out; + } + + g_mmbuf_gen_pool = pool; + + if (!g_mmbuf_list) { + g_mmbuf_list = + kzalloc(sizeof(struct list_head), GFP_KERNEL); + BUG_ON(g_mmbuf_list == NULL); + INIT_LIST_HEAD(g_mmbuf_list); + } +#ifdef CONFIG_SMMU_RWERRADDR_USED + if (!g_smmu_rwerraddr_virt) { + g_smmu_rwerraddr_virt = + kmalloc(SMMU_RW_ERR_ADDR_SIZE, + GFP_KERNEL | __GFP_DMA); + if (g_smmu_rwerraddr_virt) { + memset(g_smmu_rwerraddr_virt, 0, + SMMU_RW_ERR_ADDR_SIZE); + } else { + HISI_FB_ERR + ("kmalloc g_smmu_rwerraddr_virt fail.\n"); + } + } +#endif + } + + hisifd->mmbuf_gen_pool = g_mmbuf_gen_pool; + hisifd->mmbuf_list = g_mmbuf_list; + + err_out: + up(&hisi_dss_mmbuf_sem); + + HISI_FB_DEBUG("fb%d, -, mmbuf_refcount=%d.\n", hisifd->index, + mmbuf_refcount); + + return pool; +} + +void hisi_dss_mmbuf_deinit(struct hisi_fb_data_type *hisifd) +{ + int new_refcount = 0; + + BUG_ON(hisifd == NULL); + + HISI_FB_DEBUG("fb%d, +.\n", hisifd->index); + + hisifb_dss_off(hisifd, false); + + down(&hisi_dss_mmbuf_sem); + new_refcount = --mmbuf_refcount; + WARN_ON(new_refcount < 0); + + if (!new_refcount) { + if (g_mmbuf_gen_pool) { + gen_pool_destroy(g_mmbuf_gen_pool); + g_mmbuf_gen_pool = NULL; + } + + if (g_mmbuf_list) { + kfree(g_mmbuf_list); + g_mmbuf_list = NULL; + } +#ifdef CONFIG_SMMU_RWERRADDR_USED + if (g_smmu_rwerraddr_virt) { + kfree(g_smmu_rwerraddr_virt); + g_smmu_rwerraddr_virt = NULL; + } +#endif + } + + hisifd->mmbuf_gen_pool = NULL; + hisifd->mmbuf_list = NULL; + up(&hisi_dss_mmbuf_sem); + + HISI_FB_DEBUG("fb%d, -, mmbuf_refcount=%d.\n", hisifd->index, + mmbuf_refcount); +} + +uint32_t hisi_dss_mmbuf_alloc(void *handle, uint32_t size) +{ + uint32_t addr = 0; + struct hisifb_mmbuf *node = NULL; + struct hisifb_mmbuf *mmbuf_node, *_node_; + + if (NULL == handle) { + HISI_FB_ERR("handle is NULL!\n"); + return addr; + } + + if (NULL == g_mmbuf_list) { + HISI_FB_ERR("g_mmbuf_list is NULL!\n"); + return addr; + } + + if (size <= 0 || size > MMBUF_SIZE_MAX) { + HISI_FB_ERR("mmbuf size is invalid, size=%d!\n", size); + return addr; + } + + down(&hisi_dss_mmbuf_sem); + + addr = gen_pool_alloc(handle, size); + if (addr <= 0) { + HISI_FB_INFO("note: mmbuf not enough,addr=0x%x\n", addr); + } else { + node = kzalloc(sizeof(struct hisifb_mmbuf), GFP_KERNEL); + if (node) { + node->addr = addr; + node->size = size; + list_add_tail(&node->list_node, g_mmbuf_list); + } else { + HISI_FB_ERR("kzalloc struct hisifb_mmbuf fail!\n"); + } + + if ((addr & (MMBUF_ADDR_ALIGN - 1)) + || (size & (MMBUF_ADDR_ALIGN - 1))) { + HISI_FB_ERR + ("addr(0x%x) is not %d bytes aligned, " + "or size(0x%x) is not %d bytes" + "aligned!\n", addr, MMBUF_ADDR_ALIGN, size, + MMBUF_ADDR_ALIGN); + + list_for_each_entry_safe(mmbuf_node, _node_, + g_mmbuf_list, list_node) { + HISI_FB_ERR + ("mmbuf_node_addr(0x%x), mmbuf_node_size(0x%x)!\n", + mmbuf_node->addr, mmbuf_node->size); + } + } + } + + up(&hisi_dss_mmbuf_sem); + + HISI_FB_DEBUG("addr=0x%x, size=%d.\n", addr, size); + + return addr; +} + +void hisi_dss_mmbuf_free(void *handle, uint32_t addr, uint32_t size) +{ + struct hisifb_mmbuf *node, *_node_; + + if (NULL == handle) { + HISI_FB_ERR("handle is NULL!\n"); + return; + } + + if (NULL == g_mmbuf_list) { + HISI_FB_ERR("g_mmbuf_list is NULL!\n"); + return; + } + + down(&hisi_dss_mmbuf_sem); + + list_for_each_entry_safe(node, _node_, g_mmbuf_list, list_node) { + if ((node->addr == addr) && (node->size == size)) { + gen_pool_free(handle, addr, size); + list_del(&node->list_node); + kfree(node); + } + } + + up(&hisi_dss_mmbuf_sem); + + HISI_FB_DEBUG("addr=0x%x, size=%d.\n", addr, size); +} + +void hisi_dss_mmbuf_info_clear(struct hisi_fb_data_type *hisifd, int idx) +{ + int i = 0; + dss_mmbuf_info_t *mmbuf_info = NULL; + + BUG_ON(hisifd == NULL); + BUG_ON((idx < 0) || (idx >= HISI_DSS_CMDLIST_DATA_MAX)); + + mmbuf_info = &(hisifd->mmbuf_infos[idx]); + for (i = 0; i < DSS_CHN_MAX_DEFINE; i++) { + if (mmbuf_info->mm_used[i] == 1) { + hisi_dss_mmbuf_free(g_mmbuf_gen_pool, + mmbuf_info->mm_base[i], + mmbuf_info->mm_size[i]); + + if (g_debug_ovl_online_composer) { + HISI_FB_INFO("fb%d, mm_base(0x%x, %d).\n", + hisifd->index, + mmbuf_info->mm_base[i], + mmbuf_info->mm_size[i]); + } + + mmbuf_info->mm_base[i] = 0; + mmbuf_info->mm_size[i] = 0; + mmbuf_info->mm_used[i] = 0; + } + } +} + +void hisi_mmbuf_info_get_online(struct hisi_fb_data_type *hisifd) +{ + int tmp = 0; + + BUG_ON(hisifd == NULL); + + tmp = (hisifd->frame_count + 1) % HISI_DSS_CMDLIST_DATA_MAX; + hisi_dss_mmbuf_info_clear(hisifd, tmp); + + tmp = hisifd->frame_count % HISI_DSS_CMDLIST_DATA_MAX; + hisifd->mmbuf_info = &(hisifd->mmbuf_infos[tmp]); +} + +/******************************************************************************* + ** + */ +void hisi_dss_mmbuf_on(struct hisi_fb_data_type *hisifd) +{ + BUG_ON(hisifd == NULL); +#if 0 + outp32(hisifd->mmbuf_crg_base + SMC_LOCK, 0x5A5A5A5A); + outp32(hisifd->mmbuf_crg_base + SMC_MEM_LP, 0x00000712); +#endif +} + +static int hisi_overlay_fastboot(struct hisi_fb_data_type *hisifd) +{ + dss_overlay_t *pov_req_prev = NULL; + dss_overlay_block_t *pov_h_block_infos = NULL; + dss_overlay_block_t *pov_h_block = NULL; + dss_layer_t *layer = NULL; + + BUG_ON(hisifd == NULL); + + HISI_FB_DEBUG("fb%d, +\n", hisifd->index); + + if (hisifd->index == PRIMARY_PANEL_IDX) { + pov_req_prev = &(hisifd->ov_req_prev); + memset(pov_req_prev, 0, sizeof(dss_overlay_t)); + pov_req_prev->ov_block_infos_ptr = + (uint64_t) (&(hisifd->ov_block_infos_prev)); + pov_req_prev->ov_block_nums = 1; + pov_req_prev->ovl_idx = DSS_OVL0; + + pov_h_block_infos = + (dss_overlay_block_t *) pov_req_prev->ov_block_infos_ptr; + pov_h_block = &(pov_h_block_infos[0]); + pov_h_block->layer_nums = 1; + + layer = &(pov_h_block->layer_infos[0]); + layer->img.mmu_enable = 0; + layer->layer_idx = 0x0; + layer->chn_idx = DSS_RCHN_D0; + layer->need_cap = 0; + + memcpy(&(hisifd->dss_module_default.rdma[DSS_RCHN_D0]), + &(hisifd->dss_module_default.rdma[DSS_RCHN_D3]), + sizeof(dss_rdma_t)); + memcpy(&(hisifd->dss_module_default.dfc[DSS_RCHN_D0]), + &(hisifd->dss_module_default.dfc[DSS_RCHN_D3]), + sizeof(dss_dfc_t)); + memcpy(&(hisifd->dss_module_default.ov[DSS_OVL0].ovl_layer[0]), + &(hisifd->dss_module_default.ov[DSS_OVL0].ovl_layer[1]), + sizeof(dss_ovl_layer_t)); + + memset(&(hisifd->dss_module_default.mctl_ch[DSS_RCHN_D0]), 0, + sizeof(dss_mctl_ch_t)); + memset(&(hisifd->dss_module_default.mctl[DSS_OVL0]), 0, + sizeof(dss_mctl_t)); + + hisifd->dss_module_default.mctl_sys.chn_ov_sel[DSS_OVL0] = + 0xFFFFFFFF; + hisifd->dss_module_default.mctl_sys.ov_flush_en[DSS_OVL0] = 0x0; + + if (is_mipi_cmd_panel(hisifd)) { + if (hisifd->vactive0_start_flag == 0) { + hisifd->vactive0_start_flag = 1; + hisifd->vactive0_end_flag = 1; + } + } + } + + HISI_FB_DEBUG("fb%d, -\n", hisifd->index); + + return 0; +} + +int hisi_overlay_on(struct hisi_fb_data_type *hisifd, bool fastboot_enable) +{ + int ret = 0; + int ovl_idx = 0; + int mctl_idx = 0; + uint32_t cmdlist_idxs = 0; + int enable_cmdlist = 0; + + BUG_ON(hisifd == NULL); + + HISI_FB_DEBUG("fb%d, +\n", hisifd->index); + + memset(&(hisifd->sbl), 0, sizeof(dss_sbl_t)); + hisifd->sbl_enable = 0; + hisifd->sbl_lsensor_value = 0; + hisifd->sbl_level = 0; + + hisifd->vactive0_start_flag = 0; + hisifd->vactive0_end_flag = 0; + hisifd->crc_flag = 0; + + hisifd->dirty_region_updt.x = 0; + hisifd->dirty_region_updt.y = 0; + hisifd->dirty_region_updt.w = hisifd->panel_info.xres; + hisifd->dirty_region_updt.h = hisifd->panel_info.yres; + + hisifd->resolution_rect.x = 0; + hisifd->resolution_rect.y = 0; + hisifd->resolution_rect.w = hisifd->panel_info.xres; + hisifd->resolution_rect.h = hisifd->panel_info.yres; + + hisifd->res_updt_rect.x = 0; + hisifd->res_updt_rect.y = 0; + hisifd->res_updt_rect.w = hisifd->panel_info.xres; + hisifd->res_updt_rect.h = hisifd->panel_info.yres; + + memset(&hisifd->ov_req, 0, sizeof(dss_overlay_t)); + hisifd->ov_req.frame_no = 0xFFFFFFFF; + + g_offline_cmdlist_idxs = 0; + +#if 0 + if (g_dss_module_resource_initialized == 0) { + hisi_dss_module_default(hisifd); + g_dss_module_resource_initialized = 1; + hisifd->dss_module_resource_initialized = true; + } + + if (!hisifd->dss_module_resource_initialized) { + if (hisifd->index != PRIMARY_PANEL_IDX) { + memcpy(&(hisifd->dss_module_default), + &(hisifd_list[PRIMARY_PANEL_IDX]-> + dss_module_default), sizeof(dss_module_reg_t)); + } + hisifd->dss_module_resource_initialized = true; + } +#else + if ((hisifd->index == PRIMARY_PANEL_IDX) || + (hisifd->index == EXTERNAL_PANEL_IDX)) { + hisifb_activate_vsync(hisifd); + } + + if (g_dss_module_resource_initialized == 0) { + hisi_dss_module_default(hisifd); + g_dss_module_resource_initialized = 1; + hisifd->dss_module_resource_initialized = true; + } else { + if (!hisifd->dss_module_resource_initialized) { + if (hisifd->index != PRIMARY_PANEL_IDX) { + if (hisifd_list[PRIMARY_PANEL_IDX]) { + memcpy(&(hisifd->dss_module_default), + &(hisifd_list + [PRIMARY_PANEL_IDX]-> + dss_module_default), + sizeof(dss_module_reg_t)); + } + } + hisifd->dss_module_resource_initialized = true; + } + } +#endif + + enable_cmdlist = g_enable_ovl_cmdlist_online; + hisifb_dss_on(hisifd, enable_cmdlist); + + if ((hisifd->index == PRIMARY_PANEL_IDX) || + (hisifd->index == EXTERNAL_PANEL_IDX)) { + if (hisifd->index == PRIMARY_PANEL_IDX) { + ovl_idx = DSS_OVL0; + mctl_idx = DSS_MCTL0; + } else { + ovl_idx = DSS_OVL1; + mctl_idx = DSS_MCTL1; + } + + if ((hisifd->index == EXTERNAL_PANEL_IDX) + && hisifd->panel_info.fake_hdmi) + enable_cmdlist = 0; + + ldi_data_gate(hisifd, true); + + hisi_dss_mctl_on(hisifd, mctl_idx, enable_cmdlist, + fastboot_enable); + + if (fastboot_enable) { + hisi_overlay_fastboot(hisifd); + } else { + ret = hisi_dss_module_init(hisifd); + if (ret != 0) { + HISI_FB_ERR + ("fb%d, failed to hisi_dss_module_init! ret = %d\n", + hisifd->index, ret); + goto err_out; + } + + if (enable_cmdlist) { + hisifd->set_reg = hisi_cmdlist_set_reg; + + hisi_cmdlist_data_get_online(hisifd); + + cmdlist_idxs = + (0x1 << (ovl_idx + DSS_CMDLIST_OV0)); + hisi_cmdlist_add_nop_node(hisifd, cmdlist_idxs, + 0, 0); + } else { + hisifd->set_reg = hisifb_set_reg; + + hisi_dss_mctl_mutex_lock(hisifd, ovl_idx); + } + + hisifd->ov_req_prev.ovl_idx = ovl_idx; + + ret = + hisi_dss_ovl_base_config(hisifd, NULL, NULL, NULL, + ovl_idx, 0); + if (ret != 0) { + HISI_FB_ERR + ("fb%d, faile to hisi_dss_ovl_base_config! ret=%d\n", + hisifd->index, ret); + goto err_out; + } + + ret = + hisi_dss_mctl_ov_config(hisifd, NULL, ovl_idx, + false, true); + if (ret != 0) { + HISI_FB_ERR + ("fb%d, faile to hisi_dss_mctl_config! ret=%d\n", + hisifd->index, ret); + goto err_out; + } + + ret = + hisi_dss_ov_module_set_regs(hisifd, NULL, ovl_idx, + enable_cmdlist, 1, 0, + true); + if (ret != 0) { + HISI_FB_ERR + ("fb%d, failed to hisi_dss_module_config! ret = %d\n", + hisifd->index, ret); + goto err_out; + } + + if (enable_cmdlist) { + hisi_cmdlist_flush_cache(hisifd, + hisifd->ion_client, + cmdlist_idxs); + hisi_cmdlist_config_start(hisifd, mctl_idx, + cmdlist_idxs, 0); + } else { + hisi_dss_mctl_mutex_unlock(hisifd, ovl_idx); + } + + single_frame_update(hisifd); + enable_ldi(hisifd); + hisifb_frame_updated(hisifd); + hisifd->frame_count++; + + if (g_debug_ovl_cmdlist) { + hisi_cmdlist_dump_all_node(hisifd, NULL, + cmdlist_idxs); + } + } + err_out: + hisifb_deactivate_vsync(hisifd); + } else if (hisifd->index == AUXILIARY_PANEL_IDX) { + enable_cmdlist = g_enable_ovl_cmdlist_offline; + + hisi_dss_mctl_on(hisifd, DSS_MCTL2, enable_cmdlist, 0); + hisi_dss_mctl_on(hisifd, DSS_MCTL3, enable_cmdlist, 0); + hisi_dss_mctl_on(hisifd, DSS_MCTL5, enable_cmdlist, 0); + } else { + HISI_FB_ERR("fb%d, not supported!", hisifd->index); + } + + HISI_FB_DEBUG("fb%d, -\n", hisifd->index); + + return 0; +} + +int hisi_overlay_off(struct hisi_fb_data_type *hisifd) +{ + int ret = 0; + int ovl_idx = 0; + uint32_t cmdlist_pre_idxs = 0; + uint32_t cmdlist_idxs = 0; + int enable_cmdlist = 0; + dss_overlay_t *pov_req_prev = NULL; + + BUG_ON(hisifd == NULL); + + pov_req_prev = &(hisifd->ov_req_prev); + + HISI_FB_DEBUG("fb%d, +\n", hisifd->index); + + if ((hisifd->index == PRIMARY_PANEL_IDX) || + (hisifd->index == EXTERNAL_PANEL_IDX)) { + hisifb_activate_vsync(hisifd); + + ret = hisi_vactive0_start_config(hisifd, pov_req_prev); + if (ret != 0) { + HISI_FB_ERR + ("fb%d, hisi_vactive0_start_config failed! ret = %d\n", + hisifd->index, ret); + goto err_out; + } + + if (hisifd->aod_function == 1) { + HISI_FB_INFO("fb%d, aod mode\n", hisifd->index); + goto err_out; + } + + if (hisifd->index == PRIMARY_PANEL_IDX) { + ovl_idx = DSS_OVL0; + } else { + ovl_idx = DSS_OVL1; + } + + enable_cmdlist = g_enable_ovl_cmdlist_online; + if ((hisifd->index == EXTERNAL_PANEL_IDX) + && hisifd->panel_info.fake_hdmi) + enable_cmdlist = 0; + + ret = hisi_dss_module_init(hisifd); + if (ret != 0) { + HISI_FB_ERR + ("fb%d, failed to hisi_dss_module_init! ret = %d\n", + hisifd->index, ret); + goto err_out; + } + + if (enable_cmdlist) { + hisifd->set_reg = hisi_cmdlist_set_reg; + + hisi_cmdlist_data_get_online(hisifd); + + ret = + hisi_cmdlist_get_cmdlist_idxs(pov_req_prev, + &cmdlist_pre_idxs, + NULL); + if (ret != 0) { + HISI_FB_ERR + ("fb%d, hisi_cmdlist_get_cmdlist_idxs " + "pov_req_prev failed! ret = %d\n", + hisifd->index, ret); + goto err_out; + } + + cmdlist_idxs = (1 << (DSS_CMDLIST_OV0 + ovl_idx)); + cmdlist_pre_idxs &= (~(cmdlist_idxs)); + + hisi_cmdlist_add_nop_node(hisifd, cmdlist_pre_idxs, 0, + 0); + hisi_cmdlist_add_nop_node(hisifd, cmdlist_idxs, 0, 0); + } else { + hisifd->set_reg = hisifb_set_reg; + + hisi_dss_mctl_mutex_lock(hisifd, ovl_idx); + cmdlist_pre_idxs = ~0; + } + + hisi_dss_prev_module_set_regs(hisifd, pov_req_prev, + cmdlist_pre_idxs, enable_cmdlist, + NULL); + + ret = + hisi_dss_ovl_base_config(hisifd, NULL, NULL, NULL, ovl_idx, + 0); + if (ret != 0) { + HISI_FB_ERR + ("fb%d, faile to hisi_dss_ovl_base_config! ret=%d\n", + hisifd->index, ret); + goto err_out; + } + + ret = + hisi_dss_mctl_ov_config(hisifd, NULL, ovl_idx, false, true); + if (ret != 0) { + HISI_FB_ERR + ("fb%d, faile to hisi_dss_mctl_config! ret=%d\n", + hisifd->index, ret); + goto err_out; + } + + ret = hisi_dss_dirty_region_dbuf_config(hisifd, NULL); + if (ret != 0) { + HISI_FB_ERR + ("fb%d, hisi_dss_dirty_region_dbuf_config failed! ret = %d\n", + hisifd->index, ret); + goto err_out; + } + + ret = + hisi_dss_ov_module_set_regs(hisifd, NULL, ovl_idx, + enable_cmdlist, 1, 0, true); + if (ret != 0) { + HISI_FB_ERR + ("fb%d, failed to hisi_dss_module_config! ret = %d\n", + hisifd->index, ret); + goto err_out; + } + + if (enable_cmdlist) { + hisi_cmdlist_config_stop(hisifd, cmdlist_pre_idxs); + + cmdlist_idxs |= cmdlist_pre_idxs; + hisi_cmdlist_flush_cache(hisifd, hisifd->ion_client, + cmdlist_idxs); + + if (g_debug_ovl_cmdlist) { + hisi_cmdlist_dump_all_node(hisifd, NULL, + cmdlist_idxs); + } + + hisi_cmdlist_config_start(hisifd, ovl_idx, cmdlist_idxs, 0); + } else { + hisi_dss_mctl_mutex_unlock(hisifd, ovl_idx); + } + + if (hisifd->panel_info.dirty_region_updt_support) { + hisi_dss_dirty_region_updt_config(hisifd, NULL); + } + + ldi_data_gate(hisifd, true); + + single_frame_update(hisifd); + hisifb_frame_updated(hisifd); + + if (!hisi_dss_check_reg_reload_status(hisifd)) { + mdelay(20); + } + + ldi_data_gate(hisifd, false); + + if (is_mipi_cmd_panel(hisifd)) { + hisifd->ldi_data_gate_en = 1; + } + + hisifd->frame_count++; + err_out: + hisifb_deactivate_vsync(hisifd); + } else if (hisifd->index == AUXILIARY_PANEL_IDX) { + ; + } else { + HISI_FB_ERR("fb%d, not support !\n", hisifd->index); + BUG_ON(1); + } + + if (hisifd->index == AUXILIARY_PANEL_IDX) { + hisifb_dss_off(hisifd, true); + } else { + hisifb_dss_off(hisifd, false); + } + + hisifd->ldi_data_gate_en = 0; + + memset(&(hisifd->ov_block_infos_prev_prev), 0, + HISI_DSS_OV_BLOCK_NUMS * sizeof(dss_overlay_block_t)); + memset(&hisifd->ov_req_prev_prev, 0, sizeof(dss_overlay_t)); + memset(&(hisifd->ov_block_infos_prev), 0, + HISI_DSS_OV_BLOCK_NUMS * sizeof(dss_overlay_block_t)); + memset(&hisifd->ov_req_prev, 0, sizeof(dss_overlay_t)); + memset(&(hisifd->ov_block_infos), 0, + HISI_DSS_OV_BLOCK_NUMS * sizeof(dss_overlay_block_t)); + memset(&hisifd->ov_req, 0, sizeof(dss_overlay_t)); + + HISI_FB_DEBUG("fb%d, -\n", hisifd->index); + + return 0; +} + +bool hisi_dss_check_reg_reload_status(struct hisi_fb_data_type *hisifd) +{ + mdelay(50); + + return true; +} + +bool hisi_dss_check_crg_sctrl_status(struct hisi_fb_data_type *hisifd) +{ + uint32_t crg_state_check = 0; + uint32_t sctrl_mmbuf_dss_check = 0; + + BUG_ON(hisifd == NULL); + + crg_state_check = inp32(hisifd->peri_crg_base + PERCLKEN3); + if ((crg_state_check & 0x23000) != 0x23000) { + HISI_FB_ERR + ("dss crg_clk_enable failed, crg_state_check = 0x%x\n", + crg_state_check); + return false; + } + + crg_state_check = inp32(hisifd->peri_crg_base + PERRSTSTAT3); + if ((crg_state_check | 0xfffff3ff) != 0xfffff3ff) { + HISI_FB_ERR("dss crg_reset failed, crg_state_check = 0x%x\n", + crg_state_check); + return false; + } + + crg_state_check = inp32(hisifd->peri_crg_base + ISOSTAT); + if ((crg_state_check | 0xffffffbf) != 0xffffffbf) { + HISI_FB_ERR("dss iso_disable failed, crg_state_check = 0x%x\n", + crg_state_check); + return false; + } + + crg_state_check = inp32(hisifd->peri_crg_base + PERPWRSTAT); + if ((crg_state_check & 0x20) != 0x20) { + HISI_FB_ERR + ("dss subsys regulator_enabel failed, crg_state_check = 0x%x\n", + crg_state_check); + return false; + } + + sctrl_mmbuf_dss_check = inp32(hisifd->sctrl_base + SCPERCLKEN1); + if ((sctrl_mmbuf_dss_check & 0x1000000) != 0x1000000) { + HISI_FB_ERR + ("dss subsys mmbuf_dss_clk_enable failed, sctrl_mmbuf_dss_check = 0x%x\n", + sctrl_mmbuf_dss_check); + return false; + } + + return true; +} + +int hisi_overlay_ioctl_handler(struct hisi_fb_data_type *hisifd, + uint32_t cmd, void __user *argp) +{ + int ret = 0; + uint32_t timediff = 0; + struct timeval tv0; + struct timeval tv1; + struct hisi_panel_info *pinfo = NULL; + + if (NULL == hisifd) { + HISI_FB_ERR("NULL Pointer\n"); + return -EINVAL; + } + pinfo = &(hisifd->panel_info); + + switch (cmd) { + case HISIFB_OV_ONLINE_PLAY: + if (hisifd->ov_online_play) { + if (g_debug_ovl_online_composer_timediff & 0x1) + hisifb_get_timestamp(&tv0); + + down(&hisifd->blank_sem); + ret = hisifd->ov_online_play(hisifd, argp); + if (ret != 0) { + HISI_FB_ERR("fb%d ov_online_play failed!\n", + hisifd->index); + } + up(&hisifd->blank_sem); + + if (g_debug_ovl_online_composer_timediff & 0x1) { + hisifb_get_timestamp(&tv1); + timediff = hisifb_timestamp_diff(&tv0, &tv1); + if (timediff >= + g_debug_ovl_online_composer_time_threshold) + HISI_FB_ERR + ("ONLING_IOCTL_TIMEDIFF is %u us!\n", + timediff); + } + + if (ret == 0) { + if (hisifd->bl_update) { + hisifd->bl_update(hisifd); + } + } + } + break; + default: + break; + } + + return ret; +} + +int hisi_overlay_init(struct hisi_fb_data_type *hisifd) +{ + char wq_name[128] = { 0 }; + + BUG_ON(hisifd == NULL); + BUG_ON(hisifd->dss_base == NULL); + + hisifd->dss_module_resource_initialized = false; + + hisifd->vactive0_start_flag = 0; + hisifd->vactive0_end_flag = 0; + init_waitqueue_head(&hisifd->vactive0_start_wq); + hisifd->ldi_data_gate_en = 0; + + hisifd->crc_flag = 0; + + hisifd->frame_update_flag = 0; + + memset(&hisifd->ov_req, 0, sizeof(dss_overlay_t)); + memset(&hisifd->dss_module, 0, sizeof(dss_module_reg_t)); + memset(&hisifd->dss_module_default, 0, sizeof(dss_module_reg_t)); + + hisifd->dirty_region_updt.x = 0; + hisifd->dirty_region_updt.y = 0; + hisifd->dirty_region_updt.w = hisifd->panel_info.xres; + hisifd->dirty_region_updt.h = hisifd->panel_info.yres; + + hisifd->resolution_rect.x = 0; + hisifd->resolution_rect.y = 0; + hisifd->resolution_rect.w = hisifd->panel_info.xres; + hisifd->resolution_rect.h = hisifd->panel_info.yres; + + hisifd->res_updt_rect.x = 0; + hisifd->res_updt_rect.y = 0; + hisifd->res_updt_rect.w = hisifd->panel_info.xres; + hisifd->res_updt_rect.h = hisifd->panel_info.yres; + + hisifd->pan_display_fnc = hisi_overlay_pan_display; + hisifd->ov_ioctl_handler = hisi_overlay_ioctl_handler; + + hisifd->dss_debug_wq = NULL; + hisifd->ldi_underflow_wq = NULL; + hisifd->rch2_ce_end_wq = NULL; + hisifd->rch4_ce_end_wq = NULL; + hisifd->dpp_ce_end_wq = NULL; + hisifd->hiace_end_wq = NULL; + + if ((hisifd->index == PRIMARY_PANEL_IDX) || + (hisifd->index == EXTERNAL_PANEL_IDX + && !hisifd->panel_info.fake_hdmi)) { + snprintf(wq_name, 128, "fb%d_dss_debug", hisifd->index); + hisifd->dss_debug_wq = create_singlethread_workqueue(wq_name); + if (!hisifd->dss_debug_wq) { + HISI_FB_ERR + ("fb%d, create dss debug workqueue failed!\n", + hisifd->index); + return -EINVAL; + } + INIT_WORK(&hisifd->dss_debug_work, hisi_dss_debug_func); + + snprintf(wq_name, 128, "fb%d_ldi_underflow", hisifd->index); + hisifd->ldi_underflow_wq = + create_singlethread_workqueue(wq_name); + if (!hisifd->ldi_underflow_wq) { + HISI_FB_ERR + ("fb%d, create ldi underflow workqueue failed!\n", + hisifd->index); + return -EINVAL; + } + INIT_WORK(&hisifd->ldi_underflow_work, + hisi_ldi_underflow_handle_func); + } + + if (hisifd->index == PRIMARY_PANEL_IDX) { + hisifd->set_reg = hisi_cmdlist_set_reg; + hisifd->ov_online_play = hisi_ov_online_play; + hisifd->ov_wb_isr_handler = NULL; + hisifd->ov_vactive0_start_isr_handler = + hisi_vactive0_start_isr_handler; + + hisifd->crc_isr_handler = NULL; + + } else if (hisifd->index == EXTERNAL_PANEL_IDX) { + hisifd->set_reg = hisifb_set_reg; + hisifd->ov_online_play = hisi_ov_online_play; + hisifd->ov_wb_isr_handler = NULL; + hisifd->ov_vactive0_start_isr_handler = + hisi_vactive0_start_isr_handler; + + hisifd->crc_isr_handler = NULL; + } else if (hisifd->index == AUXILIARY_PANEL_IDX) { + hisifd->set_reg = hisi_cmdlist_set_reg; + hisifd->ov_online_play = NULL; + hisifd->ov_wb_isr_handler = NULL; + hisifd->ov_vactive0_start_isr_handler = NULL; + + hisifd->crc_isr_handler = NULL; + } else { + HISI_FB_ERR("fb%d not support this device!\n", hisifd->index); + return -EINVAL; + } + + hisi_cmdlist_init(hisifd); + + hisi_dss_mmbuf_init(hisifd); + + return 0; +} + +int hisi_overlay_deinit(struct hisi_fb_data_type *hisifd) +{ + BUG_ON(hisifd == NULL); + + if (hisifd->index == PRIMARY_PANEL_IDX) { + } + + if (hisifd->rch4_ce_end_wq) { + destroy_workqueue(hisifd->rch4_ce_end_wq); + hisifd->rch4_ce_end_wq = NULL; + } + + if (hisifd->rch2_ce_end_wq) { + destroy_workqueue(hisifd->rch2_ce_end_wq); + hisifd->rch2_ce_end_wq = NULL; + } + + if (hisifd->dpp_ce_end_wq) { + destroy_workqueue(hisifd->dpp_ce_end_wq); + hisifd->dpp_ce_end_wq = NULL; + } + + if (hisifd->hiace_end_wq) { + destroy_workqueue(hisifd->hiace_end_wq); + hisifd->hiace_end_wq = NULL; + } + + if (hisifd->dss_debug_wq) { + destroy_workqueue(hisifd->dss_debug_wq); + hisifd->dss_debug_wq = NULL; + } + + if (hisifd->ldi_underflow_wq) { + destroy_workqueue(hisifd->ldi_underflow_wq); + hisifd->ldi_underflow_wq = NULL; + } + + hisi_cmdlist_deinit(hisifd); + + hisi_dss_mmbuf_deinit(hisifd); + + return 0; +} + +void hisi_vactive0_start_isr_handler(struct hisi_fb_data_type *hisifd) +{ + BUG_ON(hisifd == NULL); + + if (is_mipi_cmd_panel(hisifd) && (hisifd->frame_update_flag == 0)) { + hisifd->vactive0_start_flag = 1; + } else { + hisifd->vactive0_start_flag++; + } + + wake_up_interruptible_all(&hisifd->vactive0_start_wq); +} + +int hisi_vactive0_start_config(struct hisi_fb_data_type *hisifd, + dss_overlay_t *pov_req) +{ + int ret = 0; + int ret1 = 0; + int times = 0; + uint32_t prev_vactive0_start = 0; + uint32_t isr_s1 = 0; + uint32_t isr_s2 = 0; + uint32_t isr_s2_mask = 0; + char __iomem *ldi_base = NULL; + struct timeval tv0; + struct timeval tv1; + dss_overlay_t *pov_req_dump = NULL; + dss_overlay_t *pov_req_prev = NULL; + dss_overlay_t *pov_req_prev_prev = NULL; + uint32_t cmdlist_idxs = 0; + uint32_t cmdlist_idxs_prev = 0; + uint32_t cmdlist_idxs_prev_prev = 0; + uint32_t read_value[4] = { 0 }; + uint32_t ldi_vstate = 0; + BUG_ON(hisifd == NULL); + BUG_ON(pov_req == NULL); + + pov_req_prev = &(hisifd->ov_req_prev); + pov_req_prev_prev = &(hisifd->ov_req_prev_prev); + if (is_mipi_cmd_panel(hisifd) && (hisifd->frame_update_flag == 0)) { + pov_req_dump = &(hisifd->ov_req_prev_prev); + if (hisifd->vactive0_start_flag == 1) { + hisifd->vactive0_start_flag = 0; + single_frame_update(hisifd); + } + + if (hisifd->vactive0_start_flag == 0) { + hisifb_get_timestamp(&tv0); + + REDO_0: + ret = + wait_event_interruptible_timeout(hisifd->vactive0_start_wq, + hisifd->vactive0_start_flag, + msecs_to_jiffies + (DSS_COMPOSER_TIMEOUT_THRESHOLD_ASIC)); + if (ret == -ERESTARTSYS) { + if (times < 50) { + times++; + mdelay(10); + goto REDO_0; + } + } + times = 0; + + if (ret <= 0) { + hisifb_get_timestamp(&tv1); + + ret1 = + hisi_cmdlist_get_cmdlist_idxs(pov_req_prev, + &cmdlist_idxs_prev, + NULL); + if (ret1 != 0) { + HISI_FB_INFO + ("fb%d, hisi_cmdlist_get_cmdlist_idxs " + "pov_req_prev failed! ret = %d\n", + hisifd->index, ret1); + } + + ret1 = + hisi_cmdlist_get_cmdlist_idxs + (pov_req_prev_prev, &cmdlist_idxs_prev_prev, + NULL); + if (ret1 != 0) { + HISI_FB_INFO + ("fb%d, hisi_cmdlist_get_cmdlist_idxs " + "pov_req_prev_prev failed! ret = %d\n", + hisifd->index, ret1); + } + + cmdlist_idxs = + cmdlist_idxs_prev | cmdlist_idxs_prev_prev; + + HISI_FB_ERR + ("fb%d, 1wait_for vactive0_start_flag timeout!ret=%d, " + "vactive0_start_flag=%d, pre_pre_frame_no=%u, " + "frame_no=%u, TIMESTAMP_DIFF is %u us, " + "cmdlist_idxs_prev=0x%x, cmdlist_idxs_prev_prev=0x%x, " + "cmdlist_idxs=0x%x, itf0_ints=0x%x\n", + hisifd->index, ret, + hisifd->vactive0_start_flag, + pov_req_dump->frame_no, pov_req->frame_no, + hisifb_timestamp_diff(&tv0, &tv1), + cmdlist_idxs_prev, cmdlist_idxs_prev_prev, + cmdlist_idxs, + inp32(hisifd->dss_base + DSS_LDI0_OFFSET + + LDI_CPU_ITF_INTS) + ); + + if (g_debug_ovl_online_composer_hold) { + dumpDssOverlay(hisifd, pov_req_dump, + (g_debug_need_save_file + == 1)); + hisi_cmdlist_dump_all_node(hisifd, NULL, + cmdlist_idxs); + mdelay(HISI_DSS_COMPOSER_HOLD_TIME); + } + + if (g_debug_ldi_underflow_clear + && g_ldi_data_gate_en) { +#if 1 + hisi_cmdlist_config_reset(hisifd, + pov_req_dump, + cmdlist_idxs); + + ldi_data_gate(hisifd, false); + mdelay(10); +#else + if (hisifd->ldi_underflow_wq) { + queue_work(hisifd-> + ldi_underflow_wq, + &hisifd-> + ldi_underflow_work); + } +#endif + + mipi_panel_check_reg(hisifd, + read_value); + ldi_vstate = + inp32(hisifd->dss_base + + DSS_LDI0_OFFSET + LDI_VSTATE); + HISI_FB_ERR("fb%d, " + "Number of the Errors on DSI : 0x05 = 0x%x\n" + "Display Power Mode : 0x0A = 0x%x\n" + "Display Signal Mode : 0x0E = 0x%x\n" + "Display Self-Diagnostic Result : 0x0F = 0x%x\n" + "LDI vstate : 0x%x, LDI dpi0_hstate : 0x%x\n", + hisifd->index, + read_value[0], + read_value[1], + read_value[2], + read_value[3], ldi_vstate, + inp32(hisifd->dss_base + + DSS_LDI0_OFFSET + + LDI_DPI0_HSTATE)); + + memset(&(hisifd->ov_block_infos_prev), 0, + HISI_DSS_OV_BLOCK_NUMS * + sizeof(dss_overlay_block_t)); + + memset(&(hisifd->ov_req_prev), 0, + sizeof(dss_overlay_t)); + + if (LDI_VSTATE_V_WAIT_TE0 == ldi_vstate) { + vactive_timeout_count++; + if ((vactive_timeout_count >= 3) + && hisifd->panel_info.esd_enable) { + hisifd->esd_recover_state = + ESD_RECOVER_STATE_START; + if (hisifd->esd_ctrl.esd_check_wq) { + queue_work(hisifd->esd_ctrl.esd_check_wq, + &(hisifd->esd_ctrl.esd_check_work)); + } + } + } + return 0; + } + + ldi_data_gate(hisifd, false); + mipi_panel_check_reg(hisifd, read_value); + ldi_vstate = + inp32(hisifd->dss_base + DSS_LDI0_OFFSET + LDI_VSTATE); + HISI_FB_ERR("fb%d, " + "Number of the Errors on DSI : 0x05 = 0x%x\n" + "Display Power Mode : 0x0A = 0x%x\n" + "Display Signal Mode : 0x0E = 0x%x\n" + "Display Self-Diagnostic Result : 0x0F = 0x%x\n" + "LDI vstate : 0x%x, LDI dpi0_hstate : 0x%x \n", + hisifd->index, read_value[0], + read_value[1], read_value[2], + read_value[3], ldi_vstate, + inp32(hisifd->dss_base + + DSS_LDI0_OFFSET + + LDI_DPI0_HSTATE)); + + REDO_1: + ret = + wait_event_interruptible_timeout(hisifd->vactive0_start_wq, + hisifd->vactive0_start_flag, + msecs_to_jiffies + (DSS_COMPOSER_TIMEOUT_THRESHOLD_ASIC)); + if (ret == -ERESTARTSYS) { + if (times < 50) { + times++; + mdelay(10); + goto REDO_1; + } + } + times = 0; + + if (ret <= 0) { + HISI_FB_ERR + ("fb%d, 2wait_for vactive0_start_flag timeout!ret=%d, " + "vactive0_start_flag=%d, frame_no=%u.\n", + hisifd->index, ret, + hisifd->vactive0_start_flag, + pov_req_dump->frame_no); + + ldi_data_gate(hisifd, false); + ret = -ETIMEDOUT; + if (LDI_VSTATE_V_WAIT_TE0 == ldi_vstate) { + vactive_timeout_count++; + if ((vactive_timeout_count >= 1) + && hisifd->panel_info.esd_enable) { + hisifd->esd_recover_state = + ESD_RECOVER_STATE_START; + if (hisifd->esd_ctrl.esd_check_wq) { + queue_work(hisifd->esd_ctrl.esd_check_wq, + &(hisifd->esd_ctrl.esd_check_work)); + } + ret = 0; + } + } + } else { + ldi_data_gate(hisifd, true); + ret = 0; + } + } else { + ldi_data_gate(hisifd, true); + ret = 0; + } + } + + ldi_data_gate(hisifd, true); + hisifd->vactive0_start_flag = 0; + hisifd->vactive0_end_flag = 0; + if (ret >= 0) { + vactive_timeout_count = 0; + } + } else { + pov_req_dump = &(hisifd->ov_req_prev); + + hisifb_get_timestamp(&tv0); + ldi_data_gate(hisifd, false); + prev_vactive0_start = hisifd->vactive0_start_flag; + + REDO_2: + ret = + wait_event_interruptible_timeout(hisifd->vactive0_start_wq, + (prev_vactive0_start != + hisifd->vactive0_start_flag), + msecs_to_jiffies + (DSS_COMPOSER_TIMEOUT_THRESHOLD_ASIC)); + if (ret == -ERESTARTSYS) { + if (times < 50) { + times++; + mdelay(10); + goto REDO_2; + } + } + + if (ret <= 0) { + hisifb_get_timestamp(&tv1); + ret = + hisi_cmdlist_get_cmdlist_idxs(pov_req_dump, + &cmdlist_idxs, NULL); + if (ret != 0) { + HISI_FB_INFO + ("fb%d, hisi_cmdlist_get_cmdlist_idxs " + "pov_req_prev failed! ret = %d\n", + hisifd->index, ret); + } + + HISI_FB_ERR + ("fb%d, 1wait_for vactive0_start_flag timeout!ret=%d, " + "vactive0_start_flag=%d, frame_no=%u, " + "TIMESTAMP_DIFF is %u us, cmdlist_idxs=0x%x!\n", + hisifd->index, ret, + hisifd->vactive0_start_flag, + pov_req_dump->frame_no, + hisifb_timestamp_diff(&tv0, &tv1), + cmdlist_idxs); + + if (g_debug_ovl_online_composer_hold) { + dumpDssOverlay(hisifd, pov_req_dump, + (g_debug_need_save_file == 1)); + hisi_cmdlist_dump_all_node(hisifd, NULL, + cmdlist_idxs); + mdelay(HISI_DSS_COMPOSER_HOLD_TIME); + } + mipi_dsi_reset(hisifd); + + ret = -ETIMEDOUT; + } else { + ret = 0; + } + } + + if (ret == -ETIMEDOUT) { + if (pov_req_dump && pov_req_dump->ovl_idx == DSS_OVL0) { + isr_s1 = inp32(hisifd->dss_base + GLB_CPU_PDP_INTS); + isr_s2_mask = + inp32(hisifd->dss_base + DSS_LDI0_OFFSET + + LDI_CPU_ITF_INT_MSK); + isr_s2 = + inp32(hisifd->dss_base + DSS_LDI0_OFFSET + + LDI_CPU_ITF_INTS); + ldi_base = hisifd->dss_base + DSS_LDI0_OFFSET; + } else if (pov_req_dump && pov_req_dump->ovl_idx == DSS_OVL1) { + isr_s1 = inp32(hisifd->dss_base + GLB_CPU_SDP_INTS); + isr_s2_mask = + inp32(hisifd->dss_base + DSS_LDI1_OFFSET + + LDI_CPU_ITF_INT_MSK); + isr_s2 = + inp32(hisifd->dss_base + DSS_LDI1_OFFSET + + LDI_CPU_ITF_INTS); + ldi_base = hisifd->dss_base + DSS_LDI1_OFFSET; + } else { + ; + } + + HISI_FB_ERR("fb%d, isr_s1=0x%x, isr_s2_mask=0x%x, isr_s2=0x%x, " + "LDI_CTRL(0x%x), LDI_FRM_MSK(0x%x).\n", + hisifd->index, isr_s1, isr_s2_mask, isr_s2, + inp32(ldi_base + LDI_CTRL), + inp32(ldi_base + LDI_FRM_MSK)); + } + + return ret; +} + +int hisi_crc_enable(struct hisi_fb_data_type *hisifd, dss_overlay_t *pov_req) +{ + uint32_t tmp = 0; + + BUG_ON(hisifd == NULL); + BUG_ON(pov_req == NULL); + + if (g_enable_crc_debug == 0) + return 0; + + if (pov_req->crc_enable_status <= 0) + return 0; + + if (hisifd->index == PRIMARY_PANEL_IDX) { + tmp = inp32(hisifd->dss_base + DSS_DPP_OFFSET + DPP_INT_MSK); + + if (pov_req->crc_enable_status == DSS_CRC_OV_EN) { + outp32(hisifd->dss_base + DSS_DBG_OFFSET + + DBG_CRC_OV0_EN, 0x1); + + tmp &= ~BIT_CRC_OV0_INT; + } else if (pov_req->crc_enable_status == DSS_CRC_LDI_EN) { + + tmp &= ~BIT_CRC_ITF0_INT; + } else if (pov_req->crc_enable_status == DSS_CRC_SUM_EN) { + outp32(hisifd->dss_base + DSS_DBG_OFFSET + + DBG_CRC_SUM_EN, 0x1); + + tmp &= ~BIT_CRC_SUM_INT; + } + outp32(hisifd->dss_base + DSS_DPP_OFFSET + DPP_INT_MSK, tmp); + } else if (hisifd->index == EXTERNAL_PANEL_IDX) { + tmp = inp32(hisifd->dss_base + DSS_DPP_OFFSET + DPP_INT_MSK); + + if (pov_req->crc_enable_status == DSS_CRC_OV_EN) { + outp32(hisifd->dss_base + DSS_DBG_OFFSET + + DBG_CRC_OV1_EN, 0x1); + + tmp &= ~BIT_CRC_OV1_INT; + } else if (pov_req->crc_enable_status == DSS_CRC_LDI_EN) { + outp32(hisifd->dss_base + GLB_CRC_LDI1_EN, 0x1); + + tmp &= ~BIT_CRC_ITF1_INT; + } else if (pov_req->crc_enable_status == DSS_CRC_SUM_EN) { + outp32(hisifd->dss_base + DSS_DBG_OFFSET + + DBG_CRC_SUM_EN, 0x1); + + tmp &= ~BIT_CRC_SUM_INT; + } + outp32(hisifd->dss_base + DSS_DPP_OFFSET + DPP_INT_MSK, tmp); + } else { + HISI_FB_ERR("fb%d, not support!", hisifd->index); + return -EINVAL; + } + + return 0; +} + +static int hisi_crc_disable(struct hisi_fb_data_type *hisifd) +{ + uint32_t tmp = 0; + + BUG_ON(hisifd == NULL); + + if (hisifd->index == PRIMARY_PANEL_IDX) { + outp32(hisifd->dss_base + DSS_DBG_OFFSET + DBG_CRC_OV0_EN, 0x0); + + outp32(hisifd->dss_base + DSS_DBG_OFFSET + DBG_CRC_SUM_EN, 0x0); + tmp = inp32(hisifd->dss_base + DSS_DPP_OFFSET + DPP_INT_MSK); + tmp |= (BIT_CRC_OV0_INT | BIT_CRC_ITF0_INT | BIT_CRC_SUM_INT); + outp32(hisifd->dss_base + DSS_DPP_OFFSET + DPP_INT_MSK, tmp); + } else if (hisifd->index == EXTERNAL_PANEL_IDX) { + outp32(hisifd->dss_base + DSS_DBG_OFFSET + DBG_CRC_OV1_EN, 0x0); + outp32(hisifd->dss_base + GLB_CRC_LDI1_EN, 0x0); + outp32(hisifd->dss_base + DSS_DBG_OFFSET + DBG_CRC_SUM_EN, 0x0); + tmp = inp32(hisifd->dss_base + DSS_DPP_OFFSET + DPP_INT_MSK); + tmp |= (BIT_CRC_OV1_INT | BIT_CRC_ITF1_INT | BIT_CRC_SUM_INT); + outp32(hisifd->dss_base + DSS_DPP_OFFSET + DPP_INT_MSK, tmp); + } else { + HISI_FB_ERR("fb%d, not support!", hisifd->index); + return -EINVAL; + } + + return 0; +} + +static int hisi_crc_get_result(struct hisi_fb_data_type *hisifd, + dss_overlay_t *pov_req) +{ + BUG_ON(hisifd == NULL); + BUG_ON(pov_req == NULL); + + if (hisifd->index == PRIMARY_PANEL_IDX) { + if (pov_req->crc_enable_status == DSS_CRC_OV_EN) { + pov_req->crc_info.crc_ov_result = + inp32(hisifd->dss_base + DSS_DBG_OFFSET + + DBG_CRC_DBG_OV0); + pov_req->crc_info.crc_ov_frm = + inp32(hisifd->dss_base + DSS_DBG_OFFSET + + DBG_CRC_OV0_FRM); + } else if (pov_req->crc_enable_status == DSS_CRC_LDI_EN) { + pov_req->crc_info.crc_ldi_result = + inp32(hisifd->dss_base + GLB_CRC_DBG_LDI0); + pov_req->crc_info.crc_ldi_frm = + inp32(hisifd->dss_base + GLB_CRC_LDI0_FRM); + } else if (pov_req->crc_enable_status == DSS_CRC_SUM_EN) { + pov_req->crc_info.crc_ldi_result = + inp32(hisifd->dss_base + DSS_DBG_OFFSET + + DBG_CRC_DBG_SUM); + pov_req->crc_info.crc_ldi_frm = + inp32(hisifd->dss_base + DSS_DBG_OFFSET + + DBG_CRC_SUM_FRM); + } + } else if (hisifd->index == EXTERNAL_PANEL_IDX) { + if (pov_req->crc_enable_status == DSS_CRC_OV_EN) { + pov_req->crc_info.crc_ov_result = + inp32(hisifd->dss_base + DSS_DBG_OFFSET + + DBG_CRC_DBG_OV1); + pov_req->crc_info.crc_ov_frm = + inp32(hisifd->dss_base + DSS_DBG_OFFSET + + DBG_CRC_OV1_FRM); + } else if (pov_req->crc_enable_status == DSS_CRC_LDI_EN) { + pov_req->crc_info.crc_ldi_result = + inp32(hisifd->dss_base + GLB_CRC_DBG_LDI1); + pov_req->crc_info.crc_ldi_frm = + inp32(hisifd->dss_base + GLB_CRC_LDI1_FRM); + } else if (pov_req->crc_enable_status == DSS_CRC_SUM_EN) { + pov_req->crc_info.crc_ldi_result = + inp32(hisifd->dss_base + DSS_DBG_OFFSET + + DBG_CRC_DBG_SUM); + pov_req->crc_info.crc_ldi_frm = + inp32(hisifd->dss_base + DSS_DBG_OFFSET + + DBG_CRC_SUM_FRM); + } + } else { + HISI_FB_ERR("fb%d, not support!", hisifd->index); + return -EINVAL; + } + + return 0; +} + +void hisi_crc_isr_handler(struct hisi_fb_data_type *hisifd) +{ + BUG_ON(hisifd == NULL); + + hisi_crc_disable(hisifd); + + hisifd->crc_flag++; + wake_up_interruptible_all(&hisifd->crc_wq); +} + +int hisi_crc_config(struct hisi_fb_data_type *hisifd, dss_overlay_t *pov_req) +{ + int ret = 0; + BUG_ON(hisifd == NULL); + BUG_ON(pov_req == NULL); + + if (g_enable_crc_debug == 0) + return 0; + + if (pov_req->crc_enable_status <= 0) + return 0; + +#if 1 + mdelay(100); + hisi_crc_get_result(hisifd, pov_req); + hisi_crc_disable(hisifd); +#else + prev_crc_flag = hisifd->crc_flag; + ret = wait_event_interruptible_timeout(hisifd->crc_wq, + (prev_crc_flag != + hisifd->crc_flag), 1 * HZ); + if (ret == -ERESTARTSYS) { + HISI_FB_DEBUG + ("fb%d, wait_for crc_flag, " + "Returns -ERESTARTSYS if interrupted by a signal!\n", + hisifd->index); + ret = + wait_event_interruptible_timeout(hisifd->crc_wq, + (prev_crc_flag != + hisifd->crc_flag), 1 * HZ); + } + + if (ret <= 0) { + HISI_FB_ERR("fb%d, wait_for crc_flag timeout!ret=%d, " + "prev_crc_flag=%d, crc_flag=%d\n", + hisifd->index, ret, prev_crc_flag, + hisifd->crc_flag); + ret = -ETIMEDOUT; + } else { + ret = 0; + + hisi_crc_get_result(hisifd, pov_req); + } +#endif + + return ret; +} + +void hisi_dss_debug_func(struct work_struct *work) +{ + struct hisi_fb_data_type *hisifd = NULL; + + hisifd = container_of(work, struct hisi_fb_data_type, dss_debug_work); + BUG_ON(hisifd == NULL); + + dumpDssOverlay(hisifd, &hisifd->ov_req, true); +} + +void hisi_ldi_underflow_handle_func(struct work_struct *work) +{ + struct hisi_fb_data_type *hisifd = NULL; + dss_overlay_t *pov_req_prev = NULL; + dss_overlay_t *pov_req_prev_prev = NULL; + uint32_t cmdlist_idxs_prev = 0; + uint32_t cmdlist_idxs_prev_prev = 0; + int ret = 0; + uint32_t tmp = 0; + uint32_t isr_s1 = 0; + uint32_t isr_s2 = 0; + + hisifd = + container_of(work, struct hisi_fb_data_type, ldi_underflow_work); + BUG_ON(hisifd == NULL); + + HISI_FB_INFO("fb%d, +.\n", hisifd->index); + + down(&hisifd->blank_sem0); + if (!hisifd->panel_power_on) { + HISI_FB_INFO("fb%d, panel is power off!", hisifd->index); + up(&hisifd->blank_sem0); + return; + } + hisifb_activate_vsync(hisifd); + + pov_req_prev = &(hisifd->ov_req_prev); + pov_req_prev_prev = &(hisifd->ov_req_prev_prev); + + ret = + hisi_cmdlist_get_cmdlist_idxs(pov_req_prev, &cmdlist_idxs_prev, NULL); + if (ret != 0) { + HISI_FB_ERR + ("fb%d, hisi_cmdlist_get_cmdlist_idxs " + "pov_req_prev failed! ret = %d\n", + hisifd->index, ret); + } + + ret = + hisi_cmdlist_get_cmdlist_idxs(pov_req_prev_prev, + &cmdlist_idxs_prev_prev, NULL); + if (ret != 0) { + HISI_FB_ERR + ("fb%d, hisi_cmdlist_get_cmdlist_idxs " + "pov_req_prev_prev failed! ret = %d\n", + hisifd->index, ret); + } + + hisi_cmdlist_config_reset(hisifd, pov_req_prev, + cmdlist_idxs_prev | cmdlist_idxs_prev_prev); + + enable_ldi(hisifd); + isr_s1 = inp32(hisifd->dss_base + GLB_CPU_PDP_INTS); + isr_s2 = inp32(hisifd->dss_base + DSS_LDI0_OFFSET + LDI_CPU_ITF_INTS); + outp32(hisifd->dss_base + DSS_LDI0_OFFSET + LDI_CPU_ITF_INTS, isr_s2); + outp32(hisifd->dss_base + GLB_CPU_PDP_INTS, isr_s1); + + tmp = inp32(hisifd->dss_base + DSS_LDI0_OFFSET + LDI_CPU_ITF_INT_MSK); + tmp &= ~BIT_LDI_UNFLOW; + outp32(hisifd->dss_base + DSS_LDI0_OFFSET + LDI_CPU_ITF_INT_MSK, tmp); + + hisifb_deactivate_vsync(hisifd); + + up(&hisifd->blank_sem0); + + HISI_FB_INFO + ("fb%d, -. cmdlist_idxs_prev = 0x%x, cmdlist_idxs_prev_prev = 0x%x\n", + hisifd->index, cmdlist_idxs_prev, cmdlist_idxs_prev_prev); +} + +/*lint +e778 +e732*/ diff --git a/drivers/video/fbdev/hisi/dss/hisi_overlay_utils.h b/drivers/video/fbdev/hisi/dss/hisi_overlay_utils.h new file mode 100755 index 000000000000..31088fbe2c73 --- /dev/null +++ b/drivers/video/fbdev/hisi/dss/hisi_overlay_utils.h @@ -0,0 +1,269 @@ +/* Copyright (c) 2013-2014, Hisilicon Tech. Co., Ltd. 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 + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ +#ifndef HISI_OVERLAY_UTILS_H +#define HISI_OVERLAY_UTILS_H + +#include "hisi_fb.h" + +/******************************************************************************* + ** + */ +extern uint32_t g_dss_module_base[DSS_CHN_MAX_DEFINE][MODULE_CHN_MAX]; +extern uint32_t g_dss_module_ovl_base[DSS_MCTL_IDX_MAX][MODULE_OVL_MAX]; +extern uint32_t g_dss_module_cap[DSS_CHN_MAX_DEFINE][MODULE_CAP_MAX]; +extern uint32_t g_dss_mif_sid_map[DSS_CHN_MAX_DEFINE]; +extern uint32_t g_dss_smmu_smrx_idx[DSS_CHN_MAX_DEFINE]; +extern int g_scf_lut_chn_coef_idx[DSS_CHN_MAX_DEFINE]; +extern unsigned int g_dss_smmu_outstanding; +extern void *g_smmu_rwerraddr_virt; + +#define DSS_COMPOSER_TIMEOUT_THRESHOLD_FPGA (10000) +#define DSS_COMPOSER_TIMEOUT_THRESHOLD_ASIC (300) + +enum ENUM_LDI_VSTATE { + LDI_VSTATE_IDLE = 0x1, + LDI_VSTATE_VSW = 0x2, + LDI_VSTATE_VBP = 0x4, + LDI_VSTATE_VACTIVE0 = 0x8, + LDI_VSTATE_VACTIVE_SPACE = 0x10, + LDI_VSTATE_VACTIVE1 = 0x20, + LDI_VSTATE_VFP = 0x40, + LDI_VSTATE_V_WAIT_TE0 = 0x80, + LDI_VSTATE_V_WAIT_TE1 = 0x100, + LDI_VSTATE_V_WAIT_TE_EN = 0x200, +}; + +void dumpDssOverlay(struct hisi_fb_data_type *hisifd, dss_overlay_t *pov_req, + bool isNeedSaveFile); + +int hisi_get_hal_format(struct fb_info *info); +int hisi_overlay_init(struct hisi_fb_data_type *hisifd); +int hisi_overlay_deinit(struct hisi_fb_data_type *hisifd); +int hisi_overlay_on(struct hisi_fb_data_type *hisifd, bool fastboot_enable); +int hisi_overlay_off(struct hisi_fb_data_type *hisifd); +bool hisi_dss_check_reg_reload_status(struct hisi_fb_data_type *hisifd); +bool hisi_dss_check_crg_sctrl_status(struct hisi_fb_data_type *hisifd); + +void hisifb_adjust_block_rect(int block_num, dss_rect_t *ov_block_rects[], + dss_wb_layer_t *wb_layer); +void hisifb_disreset_dss(struct hisi_fb_data_type *hisifd); + +void hisi_vactive0_start_isr_handler(struct hisi_fb_data_type *hisifd); +int hisi_vactive0_start_config(struct hisi_fb_data_type *hisifd, + dss_overlay_t *pov_req); + +int hisi_dss_dirty_region_dbuf_config(struct hisi_fb_data_type *hisifd, + dss_overlay_t *pov_req); +void hisi_dss_dirty_region_updt_config(struct hisi_fb_data_type *hisifd, + dss_overlay_t *pov_req); + +int hisi_dss_handle_cur_ovl_req(struct hisi_fb_data_type *hisifd, + dss_overlay_t *pov_req); + +int hisi_ov_compose_handler(struct hisi_fb_data_type *hisifd, + dss_overlay_t *pov_req, + dss_overlay_block_t *pov_h_block, + dss_layer_t *layer, + dss_rect_t *wb_dst_rect, + dss_rect_t *wb_ov_block_rect, + dss_rect_ltrb_t *clip_rect, + dss_rect_t *aligned_rect, + bool *rdma_stretch_enable, + bool *has_base, + bool csc_needed, bool enable_cmdlist); + +void hisi_dss_qos_on(struct hisi_fb_data_type *hisifd); +void hisi_dss_mmbuf_on(struct hisi_fb_data_type *hisifd); +void hisi_dss_mif_on(struct hisi_fb_data_type *hisifd); +void hisi_dss_smmu_on(struct hisi_fb_data_type *hisifd); +void hisi_dss_smmu_init(char __iomem *smmu_base, dss_smmu_t *s_smmu); +void hisi_dss_smmu_ch_set_reg(struct hisi_fb_data_type *hisifd, + char __iomem *smmu_base, dss_smmu_t *s_smmu, + int chn_idx); +void hisi_dss_smmu_ov_set_reg(struct hisi_fb_data_type *hisifd, + char __iomem *smmu_base, dss_smmu_t *s_smmu); +int hisi_dss_scl_coef_on(struct hisi_fb_data_type *hisifd, bool enable_cmdlist, + int coef_lut_idx); + +int hisi_overlay_pan_display(struct hisi_fb_data_type *hisifd); +int hisi_ov_online_play(struct hisi_fb_data_type *hisifd, void __user *argp); +int hisi_overlay_ioctl_handler(struct hisi_fb_data_type *hisifd, + uint32_t cmd, void __user *argp); + +void hisi_dss_unflow_handler(struct hisi_fb_data_type *hisifd, + dss_overlay_t *pov_req, bool unmask); + +void hisi_dss_chn_set_reg_default_value(struct hisi_fb_data_type *hisifd, + char __iomem *dma_base); +void hisi_dss_ov_set_reg_default_value(struct hisi_fb_data_type *hisifd, + char __iomem *ovl_base, int ovl_idx); +int hisi_dss_prev_module_set_regs(struct hisi_fb_data_type *hisifd, + dss_overlay_t *pov_req, + uint32_t cmdlist_pre_idxs, + bool enable_cmdlist, bool *use_comm_mmbuf); + +int hisi_dss_check_pure_layer(struct hisi_fb_data_type *hisifd, + dss_overlay_block_t *pov_h_block, + void __user *argp); + +int hisi_dss_check_userdata(struct hisi_fb_data_type *hisifd, + dss_overlay_t *pov_req, + dss_overlay_block_t *pov_h_block_infos); +int hisi_dss_check_layer_par(struct hisi_fb_data_type *hisifd, + dss_layer_t *layer); + +int hisi_dss_aif_handler(struct hisi_fb_data_type *hisifd, + dss_overlay_t *pov_req, + dss_overlay_block_t *pov_h_block); +void hisi_dss_aif_init(char __iomem *aif_ch_base, dss_aif_t *s_aif); +void hisi_dss_aif_ch_set_reg(struct hisi_fb_data_type *hisifd, + char __iomem *aif_ch_base, dss_aif_t *s_aif); +int hisi_dss_aif_ch_config(struct hisi_fb_data_type *hisifd, + dss_overlay_t *pov_req, dss_layer_t *layer, + dss_rect_t *wb_dst_rect, dss_wb_layer_t *wb_layer, + int ovl_idx); + +int hisi_dss_aif1_ch_config(struct hisi_fb_data_type *hisifd, + dss_overlay_t *pov_req, dss_layer_t *layer, + dss_wb_layer_t *wb_layer, int ovl_idx); + +int hisi_dss_mif_config(struct hisi_fb_data_type *hisifd, + dss_layer_t *layer, dss_wb_layer_t *wb_layer, + bool rdma_stretch_enable); + +int hisi_dss_smmu_ch_config(struct hisi_fb_data_type *hisifd, + dss_layer_t *layer, dss_wb_layer_t *wb_layer); + +int hisi_dss_rdma_config(struct hisi_fb_data_type *hisifd, int ovl_idx, + dss_layer_t *layer, dss_rect_ltrb_t *clip_rect, + dss_rect_t *aligned_rect, bool *rdma_stretch_enable); +int hisi_dss_wdma_config(struct hisi_fb_data_type *hisifd, + dss_overlay_t *pov_req, dss_wb_layer_t *layer, + dss_rect_t aligned_rect, dss_rect_t *ov_block_rect, + bool last_block); +int hisi_dss_rdfc_config(struct hisi_fb_data_type *hisifd, dss_layer_t *layer, + dss_rect_t *aligned_rect, dss_rect_ltrb_t clip_rect); +int hisi_dss_wdfc_config(struct hisi_fb_data_type *hisifd, + dss_wb_layer_t *layer, dss_rect_t *aligned_rect, + dss_rect_t *ov_block_rect); + +void hisi_dss_scl_set_reg(struct hisi_fb_data_type *hisifd, + char __iomem *scl_base, dss_scl_t *s_scl); +int hisi_dss_chn_scl_load_filter_coef_set_reg(struct hisi_fb_data_type *hisifd, + bool enable_cmdlist, int chn_idx, + uint32_t format); +int hisi_dss_post_scl_load_filter_coef(struct hisi_fb_data_type *hisifd, + bool enable_cmdlist, + char __iomem *scl_lut_base, + int coef_lut_idx); +int hisi_dss_scl_config(struct hisi_fb_data_type *hisifd, dss_layer_t *layer, + dss_rect_t *aligned_rect, bool rdma_stretch_enable); + +int hisi_dss_post_scf_config(struct hisi_fb_data_type *hisifd, + dss_overlay_t *pov_req); +void hisi_dss_csc_init(char __iomem *csc_base, dss_csc_t *s_csc); +void hisi_dss_csc_set_reg(struct hisi_fb_data_type *hisifd, + char __iomem *csc_base, dss_csc_t *s_csc); +int hisi_dss_csc_config(struct hisi_fb_data_type *hisifd, dss_layer_t *layer, + dss_wb_layer_t *wb_layer); + +int hisi_dss_ovl_base_config(struct hisi_fb_data_type *hisifd, + dss_overlay_t *pov_req, + dss_overlay_block_t *pov_h_block, + dss_rect_t *wb_ov_block_rect, int ovl_idx, + int ov_h_block_idx); +int hisi_dss_ovl_layer_config(struct hisi_fb_data_type *hisifd, + dss_overlay_t *pov_req, dss_layer_t *layer, + dss_rect_t *wb_ov_block_rect, bool has_base); + +void hisi_dss_mctl_mutex_lock(struct hisi_fb_data_type *hisifd, int ovl_idx); +void hisi_dss_mctl_mutex_unlock(struct hisi_fb_data_type *hisifd, int ovl_idx); +void hisi_dss_mctl_on(struct hisi_fb_data_type *hisifd, + int mctl_idx, bool enable_cmdlist, bool fastboot_enable); +int hisi_dss_mctl_ch_config(struct hisi_fb_data_type *hisifd, + dss_overlay_t *pov_req, dss_layer_t *layer, + dss_wb_layer_t *wb_layer, int ovl_idx, + dss_rect_t *wb_ov_block_rect, bool has_base); +int hisi_dss_mctl_ov_config(struct hisi_fb_data_type *hisifd, + dss_overlay_t *pov_req, int ovl_idx, bool has_base, + bool is_first_ov_block); + +int hisi_dss_sharpness_config(struct hisi_fb_data_type *hisifd, + dss_layer_t *layer); +int hisi_dss_post_clip_config(struct hisi_fb_data_type *hisifd, + dss_layer_t *layer); +int hisi_dss_ce_config(struct hisi_fb_data_type *hisifd, dss_layer_t *layer); + +int hisi_dss_module_default(struct hisi_fb_data_type *hisifd); +int hisi_dss_module_init(struct hisi_fb_data_type *hisifd); +int hisi_dss_ch_module_set_regs(struct hisi_fb_data_type *hisifd, + int32_t mctl_idx, int chn_idx, uint32_t wb_type, + bool enable_cmdlist); +int hisi_dss_ov_module_set_regs(struct hisi_fb_data_type *hisifd, + dss_overlay_t *pov_req, int ovl_idx, + bool enable_cmdlist, int task_end, int last, + bool is_first_ov_block); + +void hisi_dss_secure_layer_check_config(struct hisi_fb_data_type *hisifd, + dss_overlay_t *pov_req); +void hisi_rch2_ce_end_handle_func(struct work_struct *work); +void hisi_rch4_ce_end_handle_func(struct work_struct *work); +void hisi_dss_dpp_acm_ce_end_handle_func(struct work_struct *work); + +void hisi_crc_isr_handler(struct hisi_fb_data_type *hisifd); +int hisi_crc_enable(struct hisi_fb_data_type *hisifd, dss_overlay_t *pov_req); +int hisi_crc_config(struct hisi_fb_data_type *hisifd, dss_overlay_t *pov_req); +void hisi_dss_debug_func(struct work_struct *work); +void hisi_ldi_underflow_handle_func(struct work_struct *work); + +void *hisi_dss_mmbuf_init(struct hisi_fb_data_type *hisifd); +void hisi_dss_mmbuf_deinit(struct hisi_fb_data_type *hisifd); +uint32_t hisi_dss_mmbuf_alloc(void *handle, uint32_t size); +void hisi_dss_mmbuf_free(void *handle, uint32_t addr, uint32_t size); +void hisi_dss_mmbuf_info_clear(struct hisi_fb_data_type *hisifd, int idx); +void hisi_mmbuf_info_get_online(struct hisi_fb_data_type *hisifd); +void hisi_dss_mctl_ov_set_ctl_dbg_reg(struct hisi_fb_data_type *hisifd, + char __iomem *mctl_base, + bool enable_cmdlist); +uint32_t hisi_dss_mif_get_invalid_sel(dss_img_t *img, uint32_t transform, + int v_scaling_factor, uint8_t is_tile, + bool rdma_stretch_enable); + +bool isYUVPackage(uint32_t format); +bool isYUVSemiPlanar(uint32_t format); +bool isYUVPlanar(uint32_t format); +bool isYUV(uint32_t format); + +bool is_YUV_SP_420(uint32_t format); +bool is_YUV_SP_422(uint32_t format); +bool is_YUV_P_420(uint32_t format); +bool is_YUV_P_422(uint32_t format); +bool is_RGBX(uint32_t format); + +int hisi_dss_arsr1p_write_coefs(struct hisi_fb_data_type *hisifd, + bool enable_cmdlist, char __iomem *addr, + const int **p, int row, int col); + +/*arsr2p interface*/ +void hisi_dss_arsr2p_init(char __iomem *arsr2p_base, dss_arsr2p_t *s_arsr2p); +void hisi_dss_arsr2p_set_reg(struct hisi_fb_data_type *hisifd, + char __iomem *arsr2p_base, + dss_arsr2p_t *s_arsr2p); +void hisi_dss_arsr2p_coef_on(struct hisi_fb_data_type *hisifd, + bool enable_cmdlist); +int hisi_dss_arsr2p_config(struct hisi_fb_data_type *hisifd, + dss_layer_t *layer, dss_rect_t *aligned_rect, bool rdma_stretch_enable); +void hisi_remove_mctl_mutex(struct hisi_fb_data_type *hisifd, int mctl_idx, + uint32_t cmdlist_idxs); + +#endif /* HISI_OVERLAY_UTILS_H */ diff --git a/drivers/video/fbdev/hisi/dss/hisi_overlay_utils_hi3660.c b/drivers/video/fbdev/hisi/dss/hisi_overlay_utils_hi3660.c new file mode 100755 index 000000000000..fb7628e0aa3e --- /dev/null +++ b/drivers/video/fbdev/hisi/dss/hisi_overlay_utils_hi3660.c @@ -0,0 +1,2741 @@ +/* Copyright (c) 2013-2014, Hisilicon Tech. Co., Ltd. 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 + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include "hisi_overlay_utils.h" + +uint32_t g_dss_module_base[DSS_CHN_MAX_DEFINE][MODULE_CHN_MAX] = { + /* D0 */ + { + MIF_CH0_OFFSET, + AIF0_CH0_OFFSET, + AIF1_CH0_OFFSET, + MCTL_CTL_MUTEX_RCH0, + DSS_MCTRL_SYS_OFFSET + MCTL_RCH0_FLUSH_EN, + DSS_MCTRL_SYS_OFFSET + MCTL_RCH0_OV_OEN, + DSS_MCTRL_SYS_OFFSET + MCTL_RCH0_STARTY, + DSS_MCTRL_SYS_OFFSET + MCTL_MOD0_DBG, + DSS_RCH_D0_DMA_OFFSET, + DSS_RCH_D0_DFC_OFFSET, + 0, + 0, + 0, + 0, + 0, + 0, + DSS_RCH_D0_CSC_OFFSET, + } + , + + /* D1 */ + { + MIF_CH1_OFFSET, + AIF0_CH1_OFFSET, + AIF1_CH1_OFFSET, + MCTL_CTL_MUTEX_RCH1, + DSS_MCTRL_SYS_OFFSET + MCTL_RCH1_FLUSH_EN, + DSS_MCTRL_SYS_OFFSET + MCTL_RCH1_OV_OEN, + DSS_MCTRL_SYS_OFFSET + MCTL_RCH1_STARTY, + DSS_MCTRL_SYS_OFFSET + MCTL_MOD1_DBG, + DSS_RCH_D1_DMA_OFFSET, + DSS_RCH_D1_DFC_OFFSET, + 0, + 0, + 0, + 0, + 0, + 0, + DSS_RCH_D1_CSC_OFFSET, + } + , + + /* V0 */ + { + MIF_CH2_OFFSET, + AIF0_CH2_OFFSET, + AIF1_CH2_OFFSET, + MCTL_CTL_MUTEX_RCH2, + DSS_MCTRL_SYS_OFFSET + MCTL_RCH2_FLUSH_EN, + DSS_MCTRL_SYS_OFFSET + MCTL_RCH2_OV_OEN, + DSS_MCTRL_SYS_OFFSET + MCTL_RCH2_STARTY, + DSS_MCTRL_SYS_OFFSET + MCTL_MOD2_DBG, + DSS_RCH_VG0_DMA_OFFSET, + DSS_RCH_VG0_DFC_OFFSET, + DSS_RCH_VG0_SCL_OFFSET, + DSS_RCH_VG0_SCL_LUT_OFFSET, + DSS_RCH_VG0_ARSR_OFFSET, + DSS_RCH_VG0_ARSR_LUT_OFFSET, + DSS_RCH_VG0_POST_CLIP_OFFSET, + DSS_RCH_VG0_PCSC_OFFSET, + DSS_RCH_VG0_CSC_OFFSET, + } + , + + /* G0 */ + { + MIF_CH3_OFFSET, + AIF0_CH3_OFFSET, + AIF1_CH3_OFFSET, + MCTL_CTL_MUTEX_RCH3, + DSS_MCTRL_SYS_OFFSET + MCTL_RCH3_FLUSH_EN, + DSS_MCTRL_SYS_OFFSET + MCTL_RCH3_OV_OEN, + DSS_MCTRL_SYS_OFFSET + MCTL_RCH3_STARTY, + DSS_MCTRL_SYS_OFFSET + MCTL_MOD3_DBG, + DSS_RCH_G0_DMA_OFFSET, + DSS_RCH_G0_DFC_OFFSET, + DSS_RCH_G0_SCL_OFFSET, + 0, + 0, + 0, + DSS_RCH_G0_POST_CLIP_OFFSET, + 0, + DSS_RCH_G0_CSC_OFFSET, + } + , + + /* V1 */ + { + MIF_CH4_OFFSET, + AIF0_CH4_OFFSET, + AIF1_CH4_OFFSET, + MCTL_CTL_MUTEX_RCH4, + DSS_MCTRL_SYS_OFFSET + MCTL_RCH4_FLUSH_EN, + DSS_MCTRL_SYS_OFFSET + MCTL_RCH4_OV_OEN, + DSS_MCTRL_SYS_OFFSET + MCTL_RCH4_STARTY, + DSS_MCTRL_SYS_OFFSET + MCTL_MOD4_DBG, + DSS_RCH_VG1_DMA_OFFSET, + DSS_RCH_VG1_DFC_OFFSET, + DSS_RCH_VG1_SCL_OFFSET, + DSS_RCH_VG1_SCL_LUT_OFFSET, + 0, + 0, + DSS_RCH_VG1_POST_CLIP_OFFSET, + 0, + DSS_RCH_VG1_CSC_OFFSET, + } + , + + /* G1 */ + { + MIF_CH5_OFFSET, + AIF0_CH5_OFFSET, + AIF1_CH5_OFFSET, + MCTL_CTL_MUTEX_RCH5, + DSS_MCTRL_SYS_OFFSET + MCTL_RCH5_FLUSH_EN, + DSS_MCTRL_SYS_OFFSET + MCTL_RCH5_OV_OEN, + DSS_MCTRL_SYS_OFFSET + MCTL_RCH5_STARTY, + DSS_MCTRL_SYS_OFFSET + MCTL_MOD5_DBG, + DSS_RCH_G1_DMA_OFFSET, + DSS_RCH_G1_DFC_OFFSET, + DSS_RCH_G1_SCL_OFFSET, + 0, + 0, + 0, + DSS_RCH_G1_POST_CLIP_OFFSET, + 0, + DSS_RCH_G1_CSC_OFFSET, + } + , + + /* D2 */ + { + MIF_CH6_OFFSET, + AIF0_CH6_OFFSET, + AIF1_CH6_OFFSET, + MCTL_CTL_MUTEX_RCH6, + DSS_MCTRL_SYS_OFFSET + MCTL_RCH6_FLUSH_EN, + DSS_MCTRL_SYS_OFFSET + MCTL_RCH6_OV_OEN, + DSS_MCTRL_SYS_OFFSET + MCTL_RCH6_STARTY, + DSS_MCTRL_SYS_OFFSET + MCTL_MOD6_DBG, + DSS_RCH_D2_DMA_OFFSET, + DSS_RCH_D2_DFC_OFFSET, + 0, + 0, + 0, + 0, + 0, + 0, + DSS_RCH_D2_CSC_OFFSET, + } + , + + /* D3 */ + { + MIF_CH7_OFFSET, + AIF0_CH7_OFFSET, + AIF1_CH7_OFFSET, + MCTL_CTL_MUTEX_RCH7, + DSS_MCTRL_SYS_OFFSET + MCTL_RCH7_FLUSH_EN, + DSS_MCTRL_SYS_OFFSET + MCTL_RCH7_OV_OEN, + DSS_MCTRL_SYS_OFFSET + MCTL_RCH7_STARTY, + DSS_MCTRL_SYS_OFFSET + MCTL_MOD7_DBG, + DSS_RCH_D3_DMA_OFFSET, + DSS_RCH_D3_DFC_OFFSET, + 0, + 0, + 0, + 0, + 0, + 0, + DSS_RCH_D3_CSC_OFFSET, + } + , + + /* W0 */ + { + MIF_CH8_OFFSET, + AIF0_CH8_OFFSET, + AIF1_CH8_OFFSET, + MCTL_CTL_MUTEX_WCH0, + DSS_MCTRL_SYS_OFFSET + MCTL_WCH0_FLUSH_EN, + DSS_MCTRL_SYS_OFFSET + MCTL_WCH0_OV_IEN, + 0, + 0, + DSS_WCH0_DMA_OFFSET, + DSS_WCH0_DFC_OFFSET, + 0, + 0, + 0, + 0, + 0, + 0, + DSS_WCH0_CSC_OFFSET, + } + , + + /* W1 */ + { + MIF_CH9_OFFSET, + AIF0_CH9_OFFSET, + AIF1_CH9_OFFSET, + MCTL_CTL_MUTEX_WCH1, + DSS_MCTRL_SYS_OFFSET + MCTL_WCH1_FLUSH_EN, + DSS_MCTRL_SYS_OFFSET + MCTL_WCH1_OV_IEN, + 0, + 0, + DSS_WCH1_DMA_OFFSET, + DSS_WCH1_DFC_OFFSET, + 0, + 0, + 0, + 0, + 0, + 0, + DSS_WCH1_CSC_OFFSET, + } + , + + /* V2 */ + { + MIF_CH10_OFFSET, + AIF0_CH11_OFFSET, + AIF1_CH11_OFFSET, + MCTL_CTL_MUTEX_RCH8, + DSS_MCTRL_SYS_OFFSET + MCTL_RCH8_FLUSH_EN, + 0, + 0, + DSS_MCTRL_SYS_OFFSET + MCTL_MOD8_DBG, + DSS_RCH_VG2_DMA_OFFSET, + DSS_RCH_VG2_DFC_OFFSET, + DSS_RCH_VG2_SCL_OFFSET, + DSS_RCH_VG2_SCL_LUT_OFFSET, + 0, + 0, + DSS_RCH_VG2_POST_CLIP_OFFSET, + 0, + DSS_RCH_VG2_CSC_OFFSET, + } + , + /* W2 */ + { + MIF_CH11_OFFSET, + AIF0_CH12_OFFSET, + AIF1_CH12_OFFSET, + MCTL_CTL_MUTEX_WCH2, + DSS_MCTRL_SYS_OFFSET + MCTL_WCH2_FLUSH_EN, + 0, + 0, + 0, + DSS_WCH2_DMA_OFFSET, + DSS_WCH2_DFC_OFFSET, + 0, + 0, + 0, + 0, + 0, + 0, + DSS_WCH2_CSC_OFFSET, + } + , +}; + +uint32_t g_dss_module_ovl_base[DSS_MCTL_IDX_MAX][MODULE_OVL_MAX] = { + {DSS_OVL0_OFFSET, + DSS_MCTRL_CTL0_OFFSET} + , + + {DSS_OVL1_OFFSET, + DSS_MCTRL_CTL1_OFFSET} + , + + {DSS_OVL2_OFFSET, + DSS_MCTRL_CTL2_OFFSET} + , + + {DSS_OVL3_OFFSET, + DSS_MCTRL_CTL3_OFFSET} + , + + {0, + DSS_MCTRL_CTL4_OFFSET} + , + + {0, + DSS_MCTRL_CTL5_OFFSET} + , +}; + +int g_scf_lut_chn_coef_idx[DSS_CHN_MAX_DEFINE] = { + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, +}; + +uint32_t g_dss_module_cap[DSS_CHN_MAX_DEFINE][MODULE_CAP_MAX] = { + /* D2 */ + {0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1}, + /* D3 */ + {0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1}, + /* V0 */ + {0, 1, 1, 0, 1, 1, 1, 0, 0, 1, 1}, + /* G0 */ + {0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0}, + /* V1 */ + {0, 1, 1, 1, 0, 1, 1, 0, 1, 1, 1}, + /* G1 */ + {0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0}, + /* D0 */ + {0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1}, + /* D1 */ + {0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1}, + + /* W0 */ + {1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 1}, + /* W1 */ + {1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 1}, + + /* V2 */ + {0, 1, 1, 1, 0, 1, 1, 0, 1, 1, 1}, + /* W2 */ + {1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 1}, +}; + +/* number of smrx idx for each channel */ +uint32_t g_dss_chn_sid_num[DSS_CHN_MAX_DEFINE] = { + 4, 1, 4, 4, 4, 4, 1, 1, 3, 3, 3, 2 +}; + +/* start idx of each channel */ +/* smrx_idx = g_dss_smmu_smrx_idx[chn_idx] + (0 ~ g_dss_chn_sid_num[chn_idx]) */ +uint32_t g_dss_smmu_smrx_idx[DSS_CHN_MAX_DEFINE] = { + 0, 4, 5, 9, 13, 17, 21, 22, 26, 29, 23, 32 +}; + +void *g_smmu_rwerraddr_virt = NULL; +static void aif_bw_sort(dss_aif_bw_t a[], int n) +{ + int i = 0; + int j = 0; + dss_aif_bw_t tmp; + + for (; i < n; ++i) { + for (j = i; j < n - 1; ++j) { + if (a[j].bw > a[j + 1].bw) { + tmp = a[j]; + a[j] = a[j + 1]; + a[j + 1] = tmp; + } + } + } +} + +int hisi_dss_aif_handler(struct hisi_fb_data_type *hisifd, + dss_overlay_t *pov_req, dss_overlay_block_t *pov_h_block) +{ + int i = 0; + int k = 0; + dss_layer_t *layer = NULL; + dss_wb_layer_t *wb_layer = NULL; + int chn_idx = 0; + dss_aif_bw_t *aif_bw = NULL; + uint32_t tmp = 0; + uint32_t bw_sum = 0; + + int rch_cnt = 0; + int axi0_cnt = 0; + int axi1_cnt = 0; + dss_aif_bw_t aif_bw_tmp[DSS_CHN_MAX_DEFINE]; + + dss_aif_bw_t *aif1_bw = NULL; + + BUG_ON(hisifd == NULL); + BUG_ON(pov_req == NULL); + BUG_ON(pov_h_block == NULL); + + memset(aif_bw_tmp, 0, sizeof(aif_bw_tmp)); + + if (pov_req->wb_enable) { + for (k = 0; k < pov_req->wb_layer_nums; k++) { + wb_layer = &(pov_req->wb_layer_infos[k]); + chn_idx = wb_layer->chn_idx; + + aif_bw = &(hisifd->dss_module.aif_bw[chn_idx]); + aif_bw->bw = (uint64_t) wb_layer->dst.buf_size * + (wb_layer->src_rect.w * wb_layer->src_rect.h) / + (wb_layer->dst.width * wb_layer->dst.height); + aif_bw->chn_idx = chn_idx; + aif_bw->axi_sel = AXI_CHN1; + aif_bw->is_used = 1; + } + + if (pov_req->wb_compose_type == DSS_WB_COMPOSE_COPYBIT) { + for (i = 0; i < pov_h_block->layer_nums; i++) { + layer = &pov_h_block->layer_infos[i]; + chn_idx = layer->chn_idx; + aif_bw_tmp[i].chn_idx = chn_idx; + aif_bw_tmp[i].axi_sel = AXI_CHN0; + aif_bw_tmp[i].is_used = 1; + hisifd->dss_module.aif_bw[chn_idx] = + aif_bw_tmp[i]; + } + return 0; + } + } + + rch_cnt = 0; + for (i = 0; i < pov_h_block->layer_nums; i++) { + layer = &pov_h_block->layer_infos[i]; + chn_idx = layer->chn_idx; + + if (layer->need_cap & (CAP_BASE | CAP_DIM | CAP_PURE_COLOR)) + continue; + + if (layer->need_cap & CAP_AFBCD) { + aif1_bw = &(hisifd->dss_module.aif1_bw[chn_idx]); + aif1_bw->is_used = 1; + aif1_bw->chn_idx = chn_idx; + if ((pov_req->ovl_idx == DSS_OVL0) || + (pov_req->ovl_idx == DSS_OVL1)) { + if ((i % 2) == 0) { + aif1_bw->axi_sel = AXI_CHN0; + } else { + aif1_bw->axi_sel = AXI_CHN1; + } + } else { + if ((i % 2) == 0) { + aif1_bw->axi_sel = AXI_CHN1; + } else { + aif1_bw->axi_sel = AXI_CHN0; + } + } + + if (g_debug_ovl_online_composer) { + HISI_FB_INFO + ("fb%d, aif1, chn_idx=%d, axi_sel=%d.\n", + hisifd->index, chn_idx, aif1_bw->axi_sel); + } + } + + aif_bw_tmp[i].bw = (uint64_t) layer->img.buf_size * + (layer->src_rect.w * layer->src_rect.h) / + (layer->img.width * layer->img.height); + aif_bw_tmp[i].chn_idx = chn_idx; + aif_bw_tmp[i].axi_sel = AXI_CHN0; + aif_bw_tmp[i].is_used = 1; + + bw_sum += aif_bw_tmp[i].bw; + rch_cnt++; + } + + aif_bw_sort(aif_bw_tmp, rch_cnt); + + for (i = 0; i < DSS_CHN_MAX_DEFINE; i++) { + if (aif_bw_tmp[i].is_used != 1) + continue; + + tmp += aif_bw_tmp[i].bw; + + if ((pov_req->ovl_idx == DSS_OVL0) + || (pov_req->ovl_idx == DSS_OVL1)) { + if (tmp <= (bw_sum / 2)) { + aif_bw_tmp[i].axi_sel = AXI_CHN0; + if (axi0_cnt >= AXI0_MAX_DSS_CHN_THRESHOLD) { + aif_bw_tmp[i - + AXI0_MAX_DSS_CHN_THRESHOLD].axi_sel + = AXI_CHN1; + axi1_cnt++; + axi0_cnt--; + } + axi0_cnt++; + } else { + aif_bw_tmp[i].axi_sel = AXI_CHN1; + axi1_cnt++; + } + } else { + if (tmp <= (bw_sum / 2)) { + aif_bw_tmp[i].axi_sel = AXI_CHN1; + if (axi1_cnt >= AXI1_MAX_DSS_CHN_THRESHOLD) { + aif_bw_tmp[i - + AXI1_MAX_DSS_CHN_THRESHOLD].axi_sel + = AXI_CHN0; + axi0_cnt++; + axi1_cnt--; + } + axi1_cnt++; + } else { + aif_bw_tmp[i].axi_sel = AXI_CHN0; + axi0_cnt++; + } + } + + chn_idx = aif_bw_tmp[i].chn_idx; + hisifd->dss_module.aif_bw[chn_idx] = aif_bw_tmp[i]; + + if (g_debug_ovl_online_composer) { + HISI_FB_INFO + ("fb%d, aif0, chn_idx=%d, axi_sel=%d, bw=%llu.\n", + hisifd->index, chn_idx, aif_bw_tmp[i].axi_sel, + aif_bw_tmp[i].bw); + } + } + + return 0; +} + +void hisi_dss_qos_on(struct hisi_fb_data_type *hisifd) +{ + outp32(hisifd->noc_dss_base + 0xc, 0x2); + outp32(hisifd->noc_dss_base + 0x8c, 0x2); + outp32(hisifd->noc_dss_base + 0x10c, 0x2); + outp32(hisifd->noc_dss_base + 0x18c, 0x2); +} + +/******************************************************************************* + ** DSS AIF + */ +static int mid_array[DSS_CHN_MAX_DEFINE] = { + 0xb, 0xa, 0x9, 0x8, 0x7, 0x6, 0x5, 0x4, 0x2, 0x1, 0x3, 0x0 +}; +#define CREDIT_STEP_LOWER_ENABLE +void hisi_dss_aif_init(char __iomem *aif_ch_base, dss_aif_t *s_aif) +{ + BUG_ON(aif_ch_base == NULL); + BUG_ON(s_aif == NULL); + + memset(s_aif, 0, sizeof(dss_aif_t)); + + s_aif->aif_ch_ctl = inp32(aif_ch_base + AIF_CH_CTL); + s_aif->aif_ch_ctl_add = inp32(aif_ch_base + AIF_CH_CTL_ADD); +} + +void hisi_dss_aif_ch_set_reg(struct hisi_fb_data_type *hisifd, + char __iomem *aif_ch_base, dss_aif_t *s_aif) +{ + BUG_ON(hisifd == NULL); + BUG_ON(aif_ch_base == NULL); + BUG_ON(s_aif == NULL); + + hisifd->set_reg(hisifd, aif_ch_base + AIF_CH_CTL, s_aif->aif_ch_ctl, 32, + 0); + hisifd->set_reg(hisifd, aif_ch_base + AIF_CH_CTL_ADD, + s_aif->aif_ch_ctl_add, 32, 0); +} + +int hisi_dss_aif_ch_config(struct hisi_fb_data_type *hisifd, + dss_overlay_t *pov_req, dss_layer_t *layer, + dss_rect_t *wb_dst_rect, + dss_wb_layer_t *wb_layer, int ovl_idx) +{ + dss_aif_t *aif = NULL; + dss_aif_bw_t *aif_bw = NULL; + int chn_idx = 0; + int mid = 0; + uint32_t credit_step = 0; + uint32_t credit_step_lower = 0; + uint64_t dss_core_rate = 0; + uint32_t scfd_h = 0; + uint32_t scfd_v = 0; + uint32_t online_offline_rate = 1; + + BUG_ON(hisifd == NULL); + BUG_ON(pov_req == NULL); + BUG_ON((layer == NULL) && (wb_layer == NULL)); + BUG_ON((ovl_idx < DSS_OVL0) || (ovl_idx >= DSS_OVL_IDX_MAX)); + + if (wb_layer) { + chn_idx = wb_layer->chn_idx; + } else { + chn_idx = layer->chn_idx; + } + + aif = &(hisifd->dss_module.aif[chn_idx]); + hisifd->dss_module.aif_ch_used[chn_idx] = 1; + + aif_bw = &(hisifd->dss_module.aif_bw[chn_idx]); + BUG_ON(aif_bw->is_used != 1); + + mid = mid_array[chn_idx]; + BUG_ON(mid < 0 || mid > 0xb); + + aif->aif_ch_ctl = set_bits32(aif->aif_ch_ctl, aif_bw->axi_sel, 1, 0); + aif->aif_ch_ctl = set_bits32(aif->aif_ch_ctl, mid, 4, 4); + + if ((ovl_idx == DSS_OVL2) || (ovl_idx == DSS_OVL3) + || (layer->chn_idx == DSS_RCHN_V2)) { + if (layer && ((layer->need_cap & CAP_AFBCD) != CAP_AFBCD)) { + dss_core_rate = hisifd->dss_clk_rate.dss_pri_clk_rate; + if (dss_core_rate == 0) { + HISI_FB_ERR + ("fb%d, dss_core_rate(%llu) is invalid!", + hisifd->index, dss_core_rate); + dss_core_rate = DEFAULT_DSS_CORE_CLK_07V_RATE; + } + + credit_step_lower = + g_dss_min_bandwidth_inbusbusy * 1000000UL * 8 / + dss_core_rate; + + if ((layer->src_rect.w > layer->dst_rect.w) && + (layer->src_rect.w > get_panel_xres(hisifd))) { + scfd_h = + layer->src_rect.w * 100 / + get_panel_xres(hisifd); + } else { + scfd_h = 100; + } + + if (layer->src_rect.h > layer->dst_rect.h) { + scfd_v = + layer->src_rect.h * 100 / layer->dst_rect.h; + } else { + scfd_v = 100; + } + + if (pov_req->wb_compose_type == DSS_WB_COMPOSE_COPYBIT) { + if (wb_dst_rect) { + online_offline_rate = + wb_dst_rect->w * wb_dst_rect->h / + (hisifd->panel_info.xres * + hisifd->panel_info.yres); + } + + if (online_offline_rate == 0) + online_offline_rate = 1; + } + + credit_step = + hisifd->panel_info.pxl_clk_rate * + online_offline_rate * 32 * scfd_h * scfd_v / + dss_core_rate / (100 * 100); + + if (g_debug_ovl_online_composer + || g_debug_ovl_credit_step) { + HISI_FB_INFO + ("fb%d, layer_idx(%d), chn_idx(%d), src_rect(%d,%d,%d,%d)," + "dst_rect(%d,%d,%d,%d), scfd_h=%d, " + "scfd_v=%d, credit_step=%d.\n", + hisifd->index, layer->layer_idx, + layer->chn_idx, layer->src_rect.x, + layer->src_rect.y, layer->src_rect.w, + layer->src_rect.h, layer->dst_rect.x, + layer->dst_rect.y, layer->dst_rect.w, + layer->dst_rect.h, scfd_h, scfd_v, + credit_step); + } + + if (credit_step < 32) { + credit_step = 32; + } +#ifndef CREDIT_STEP_LOWER_ENABLE + if (credit_step > 64) { + aif->aif_ch_ctl = + set_bits32(aif->aif_ch_ctl, 0x0, 1, 11); + } else { + aif->aif_ch_ctl = + set_bits32(aif->aif_ch_ctl, 0x1, 1, 11); + aif->aif_ch_ctl = + set_bits32(aif->aif_ch_ctl, credit_step, 7, + 16); + } +#else + /* credit en lower */ + aif->aif_ch_ctl_add = + set_bits32(aif->aif_ch_ctl_add, 1, 1, 11); + aif->aif_ch_ctl_add = + set_bits32(aif->aif_ch_ctl_add, 2, 4, 12); + aif->aif_ch_ctl_add = + set_bits32(aif->aif_ch_ctl_add, credit_step_lower, + 7, 16); + aif->aif_ch_ctl = + set_bits32(aif->aif_ch_ctl, 0x2, 2, 8); + aif->aif_ch_ctl = + set_bits32(aif->aif_ch_ctl, 0x0, 1, 11); +#endif + } + + if (wb_layer) { + dss_core_rate = hisifd->dss_clk_rate.dss_pri_clk_rate; + if (dss_core_rate == 0) { + HISI_FB_ERR + ("fb%d, dss_core_rate(%llu) is invalid!", + hisifd->index, dss_core_rate); + dss_core_rate = DEFAULT_DSS_CORE_CLK_07V_RATE; + } + + credit_step_lower = + g_dss_min_bandwidth_inbusbusy * 1000000UL * 8 / + dss_core_rate; + + scfd_h = 100; + scfd_v = 100; + online_offline_rate = 1; + credit_step = + hisifd->panel_info.pxl_clk_rate * + online_offline_rate * 32 * scfd_h * scfd_v / + dss_core_rate / (100 * 100); + + if (credit_step < 32) { + credit_step = 32; + } +#ifndef CREDIT_STEP_LOWER_ENABLE + if (credit_step > 64) { + aif->aif_ch_ctl = + set_bits32(aif->aif_ch_ctl, 0x0, 1, 11); + } else { + aif->aif_ch_ctl = + set_bits32(aif->aif_ch_ctl, 0x1, 1, 11); + aif->aif_ch_ctl = + set_bits32(aif->aif_ch_ctl, credit_step, 7, + 16); + } +#else + /* credit en lower */ + aif->aif_ch_ctl_add = + set_bits32(aif->aif_ch_ctl_add, 1, 1, 11); + aif->aif_ch_ctl_add = + set_bits32(aif->aif_ch_ctl_add, 2, 4, 12); + aif->aif_ch_ctl_add = + set_bits32(aif->aif_ch_ctl_add, credit_step_lower, + 7, 16); + aif->aif_ch_ctl = + set_bits32(aif->aif_ch_ctl, 0x2, 2, 8); + aif->aif_ch_ctl = + set_bits32(aif->aif_ch_ctl, 0x0, 1, 11); +#endif + } + } + return 0; +} + +int hisi_dss_aif1_ch_config(struct hisi_fb_data_type *hisifd, + dss_overlay_t *pov_req, dss_layer_t *layer, + dss_wb_layer_t *wb_layer, int ovl_idx) +{ + dss_aif_t *aif1 = NULL; + dss_aif_bw_t *aif1_bw = NULL; + int chn_idx = 0; + uint32_t need_cap = 0; + int mid = 0; + uint32_t credit_step = 0; + uint32_t credit_step_lower = 0; + uint64_t dss_core_rate = 0; + uint32_t scfd_h = 0; + uint32_t scfd_v = 0; + + BUG_ON(hisifd == NULL); + BUG_ON(pov_req == NULL); + BUG_ON((layer == NULL) && (wb_layer == NULL)); + BUG_ON((ovl_idx < DSS_OVL0) || (ovl_idx >= DSS_OVL_IDX_MAX)); + + if (wb_layer) { + chn_idx = wb_layer->chn_idx; + need_cap = wb_layer->need_cap; + } else { + chn_idx = layer->chn_idx; + need_cap = layer->need_cap; + } + + if (!(need_cap & CAP_AFBCD)) + return 0; + + aif1 = &(hisifd->dss_module.aif1[chn_idx]); + hisifd->dss_module.aif1_ch_used[chn_idx] = 1; + + aif1_bw = &(hisifd->dss_module.aif1_bw[chn_idx]); + BUG_ON(aif1_bw->is_used != 1); + + mid = mid_array[chn_idx]; + BUG_ON(mid < 0 || mid > 0xb); + + aif1->aif_ch_ctl = set_bits32(aif1->aif_ch_ctl, aif1_bw->axi_sel, 1, 0); + aif1->aif_ch_ctl = set_bits32(aif1->aif_ch_ctl, mid, 4, 4); + + if ((ovl_idx == DSS_OVL0) || (ovl_idx == DSS_OVL1)) { + if (layer && (layer->need_cap & CAP_AFBCD)) { + dss_core_rate = hisifd->dss_clk_rate.dss_pri_clk_rate; + if (dss_core_rate == 0) { + HISI_FB_ERR + ("fb%d, dss_core_rate(%llu) is invalid!", + hisifd->index, dss_core_rate); + dss_core_rate = DEFAULT_DSS_CORE_CLK_07V_RATE; + } + + if ((layer->src_rect.w > layer->dst_rect.w) && + (layer->src_rect.w > get_panel_xres(hisifd))) { + scfd_h = + layer->src_rect.w * 100 / + get_panel_xres(hisifd); + } else { + scfd_h = 100; + } + + if (layer->src_rect.h > layer->dst_rect.h) { + scfd_v = + layer->src_rect.h * 100 / layer->dst_rect.h; + } else { + scfd_v = 100; + } + + credit_step = + hisifd->panel_info.pxl_clk_rate * 32 * 150 * + scfd_h * scfd_v / dss_core_rate / (100 * 100 * 100); + + if (g_debug_ovl_online_composer + || g_debug_ovl_credit_step) { + HISI_FB_INFO + ("fb%d, layer_idx(%d), chn_idx(%d), src_rect(%d,%d,%d,%d)," + "dst_rect(%d,%d,%d,%d), scfd_h=%d, " + "scfd_v=%d, credit_step=%d.\n", + hisifd->index, layer->layer_idx, + layer->chn_idx, layer->src_rect.x, + layer->src_rect.y, layer->src_rect.w, + layer->src_rect.h, layer->dst_rect.x, + layer->dst_rect.y, layer->dst_rect.w, + layer->dst_rect.h, scfd_h, scfd_v, + credit_step); + } + + if (credit_step < 32) { + credit_step = 32; + } + + if (credit_step > 64) { + aif1->aif_ch_ctl = + set_bits32(aif1->aif_ch_ctl, 0x0, 1, 11); + } else { + aif1->aif_ch_ctl = + set_bits32(aif1->aif_ch_ctl, 0x1, 1, 11); + aif1->aif_ch_ctl = + set_bits32(aif1->aif_ch_ctl, credit_step, 7, + 16); + } + + } + } else { + if (layer && (layer->need_cap & CAP_AFBCD)) { + dss_core_rate = hisifd->dss_clk_rate.dss_pri_clk_rate; + if (dss_core_rate == 0) { + HISI_FB_ERR + ("fb%d, dss_core_rate(%llu is invalid!", + hisifd->index, dss_core_rate); + dss_core_rate = DEFAULT_DSS_CORE_CLK_07V_RATE; + } + + credit_step_lower = + g_dss_min_bandwidth_inbusbusy * 1000000UL * 8 / + dss_core_rate; + + if ((layer->src_rect.w > layer->dst_rect.w) && + (layer->src_rect.w > get_panel_xres(hisifd))) { + scfd_h = + layer->src_rect.w * 100 / + get_panel_xres(hisifd); + } else { + scfd_h = 100; + } + + if (layer->src_rect.h > layer->dst_rect.h) { + scfd_v = + layer->src_rect.h * 100 / layer->dst_rect.h; + } else { + scfd_v = 100; + } + + credit_step = + hisifd->panel_info.pxl_clk_rate * 32 * scfd_h * + scfd_v / dss_core_rate / (100 * 100); + + if (g_debug_ovl_online_composer + || g_debug_ovl_credit_step) { + HISI_FB_INFO + ("fb%d, layer_idx(%d), chn_idx(%d), src_rect(%d,%d,%d,%d)," + "dst_rect(%d,%d,%d,%d), scfd_h=%d, " + "scfd_v=%d, credit_step=%d.\n", + hisifd->index, layer->layer_idx, + layer->chn_idx, layer->src_rect.x, + layer->src_rect.y, layer->src_rect.w, + layer->src_rect.h, layer->dst_rect.x, + layer->dst_rect.y, layer->dst_rect.w, + layer->dst_rect.h, scfd_h, scfd_v, + credit_step); + } +#ifndef CREDIT_STEP_LOWER_ENABLE + if (credit_step > 64) { + aif1->aif_ch_ctl = + set_bits32(aif1->aif_ch_ctl, 0x0, 1, 11); + } else { + aif1->aif_ch_ctl = + set_bits32(aif1->aif_ch_ctl, 0x1, 1, 11); + aif1->aif_ch_ctl = + set_bits32(aif1->aif_ch_ctl, credit_step, 7, + 16); + } +#else + /* credit en lower */ + aif1->aif_ch_ctl_add = + set_bits32(aif1->aif_ch_ctl_add, 1, 1, 11); + aif1->aif_ch_ctl_add = + set_bits32(aif1->aif_ch_ctl_add, 2, 4, 12); + aif1->aif_ch_ctl_add = + set_bits32(aif1->aif_ch_ctl_add, credit_step_lower, + 7, 16); + aif1->aif_ch_ctl = + set_bits32(aif1->aif_ch_ctl, 0x2, 2, 8); + aif1->aif_ch_ctl = + set_bits32(aif1->aif_ch_ctl, 0x0, 1, 11); +#endif + } + } + + return 0; +} + +/******************************************************************************* + ** DSS SMMU + */ +void hisi_dss_smmu_on(struct hisi_fb_data_type *hisifd) +{ + char __iomem *smmu_base = NULL; + int idx0 = 0; + int idx1 = 0; + int idx2 = 0; + uint32_t phy_pgd_base = 0; + struct iommu_domain_data *domain_data = NULL; + uint64_t smmu_rwerraddr_phys = 0; + + BUG_ON(hisifd == NULL); + + smmu_base = hisifd->dss_base + DSS_SMMU_OFFSET; + + set_reg(smmu_base + SMMU_SCR, 0x0, 1, 0); + set_reg(smmu_base + SMMU_SCR, 0x1, 8, 20); + set_reg(smmu_base + SMMU_SCR, g_dss_smmu_outstanding - 1, 4, 16); + set_reg(smmu_base + SMMU_SCR, 0x7, 3, 3); + set_reg(smmu_base + SMMU_LP_CTRL, 0x1, 1, 0); + + set_reg(smmu_base + SMMU_CB_TTBCR, 0x1, 1, 0); + + if (g_smmu_rwerraddr_virt) { + smmu_rwerraddr_phys = virt_to_phys(g_smmu_rwerraddr_virt); + set_reg(smmu_base + SMMU_ERR_RDADDR, + (uint32_t) (smmu_rwerraddr_phys & 0xFFFFFFFF), 32, 0); + set_reg(smmu_base + SMMU_ERR_WRADDR, + (uint32_t) (smmu_rwerraddr_phys & 0xFFFFFFFF), 32, 0); + } else { + set_reg(smmu_base + SMMU_ERR_RDADDR, 0x7FF00000, 32, 0); + set_reg(smmu_base + SMMU_ERR_WRADDR, 0x7FFF0000, 32, 0); + } + + set_reg(smmu_base + SMMU_RLD_EN0_NS, DSS_SMMU_RLD_EN0_DEFAULT_VAL, 32, + 0); + set_reg(smmu_base + SMMU_RLD_EN1_NS, DSS_SMMU_RLD_EN1_DEFAULT_VAL, 32, + 0); + + idx0 = 36; + idx1 = 37; + idx2 = 38; + + set_reg(smmu_base + SMMU_SMRx_NS + idx0 * 0x4, 0x1, 32, 0); + set_reg(smmu_base + SMMU_SMRx_NS + idx1 * 0x4, 0x1, 32, 0); + set_reg(smmu_base + SMMU_SMRx_NS + idx2 * 0x4, 0x1, 32, 0); + + domain_data = (struct iommu_domain_data *)(hisifd->hisi_domain->priv); + phy_pgd_base = (uint32_t) (domain_data->phy_pgd_base); + set_reg(smmu_base + SMMU_CB_TTBR0, phy_pgd_base, 32, 0); +} + +void hisi_dss_smmu_init(char __iomem *smmu_base, dss_smmu_t *s_smmu) +{ + BUG_ON(smmu_base == NULL); + BUG_ON(s_smmu == NULL); + + memset(s_smmu, 0, sizeof(dss_smmu_t)); +} + +void +hisi_dss_smmu_ch_set_reg(struct hisi_fb_data_type *hisifd, + char __iomem *smmu_base, dss_smmu_t *s_smmu, + int chn_idx) +{ + uint32_t idx = 0; + uint32_t i = 0; + + BUG_ON(hisifd == NULL); + BUG_ON(smmu_base == NULL); + BUG_ON(s_smmu == NULL); + + if (s_smmu->smmu_smrx_ns_used[chn_idx] == 0) + return; + + for (i = 0; i < g_dss_chn_sid_num[chn_idx]; i++) { + idx = g_dss_smmu_smrx_idx[chn_idx] + i; + BUG_ON((idx < 0) || (idx >= SMMU_SID_NUM)); + + hisifd->set_reg(hisifd, smmu_base + SMMU_SMRx_NS + idx * 0x4, + s_smmu->smmu_smrx_ns[idx], 32, 0); + } +} + +int +hisi_dss_smmu_ch_config(struct hisi_fb_data_type *hisifd, + dss_layer_t *layer, dss_wb_layer_t *wb_layer) +{ + dss_smmu_t *smmu = NULL; + int chn_idx = 0; + dss_img_t *img = NULL; + uint32_t idx = 0; + uint32_t i = 0; + + BUG_ON(hisifd == NULL); + BUG_ON((layer == NULL) && (wb_layer == NULL)); + + if (wb_layer) { + img = &(wb_layer->dst); + chn_idx = wb_layer->chn_idx; + } else { + img = &(layer->img); + chn_idx = layer->chn_idx; + } + + smmu = &(hisifd->dss_module.smmu); + hisifd->dss_module.smmu_used = 1; + + smmu->smmu_smrx_ns_used[chn_idx] = 1; + + for (i = 0; i < g_dss_chn_sid_num[chn_idx]; i++) { + idx = g_dss_smmu_smrx_idx[chn_idx] + i; + BUG_ON((idx < 0) || (idx >= SMMU_SID_NUM)); + + if (img->mmu_enable == 0) { + smmu->smmu_smrx_ns[idx] = + set_bits32(smmu->smmu_smrx_ns[idx], 0x1, 1, 0); + } else { + /* stream config */ + smmu->smmu_smrx_ns[idx] = + set_bits32(smmu->smmu_smrx_ns[idx], 0x0, 1, 0); + smmu->smmu_smrx_ns[idx] = + set_bits32(smmu->smmu_smrx_ns[idx], 0x1, 1, 4); + smmu->smmu_smrx_ns[idx] = + set_bits32(smmu->smmu_smrx_ns[idx], 0x3, 7, 5); + } + } + return 0; +} + +void +hisifb_adjust_block_rect(int block_num, dss_rect_t *ov_block_rects[], + dss_wb_layer_t *wb_layer) +{ + return; +} + +/******************************************************************************* + ** DSS CSC + */ +#define CSC_ROW (3) +#define CSC_COL (5) + +/* application: mode 2 is used in rgb2yuv, mode 0 is used in yuv2rgb */ +#define CSC_MPREC_MODE_0 (0) +#define CSC_MPREC_MODE_1 (1) +#define CSC_MPREC_MODE_2 (2) + +#define CSC_MPREC_MODE_RGB2YUV (CSC_MPREC_MODE_2) +#define CSC_MPREC_MODE_YUV2RGB (CSC_MPREC_MODE_0) + +/* + ** Rec.601 for Computer + ** [ p00 p01 p02 cscidc2 cscodc2 ] + ** [ p10 p11 p12 cscidc1 cscodc1 ] + ** [ p20 p21 p22 cscidc0 cscodc0 ] + */ +static int CSC_COE_YUV2RGB601_NARROW_MPREC0[CSC_ROW][CSC_COL] = { + {0x4a8, 0x000, 0x662, 0x7f0, 0x000}, + {0x4a8, 0x1e6f, 0x1cc0, 0x77f, 0x000}, + {0x4a8, 0x812, 0x000, 0x77f, 0x000} +}; + +static int CSC_COE_RGB2YUV601_NARROW_MPREC2[CSC_ROW][CSC_COL] = { + {0x41C, 0x811, 0x191, 0x000, 0x010}, + {0x1DA1, 0x1B58, 0x707, 0x000, 0x081}, + {0x707, 0x1A1E, 0x1EDB, 0x000, 0x081} +}; + +static int CSC_COE_YUV2RGB709_NARROW_MPREC0[CSC_ROW][CSC_COL] = { + {0x4a8, 0x000, 0x72c, 0x7f0, 0x000}, + {0x4a8, 0x1f26, 0x1dde, 0x77f, 0x000}, + {0x4a8, 0x873, 0x000, 0x77f, 0x000} +}; + +static int CSC_COE_RGB2YUV709_NARROW_MPREC2[CSC_ROW][CSC_COL] = { + {0x2EC, 0x9D4, 0x0FE, 0x000, 0x010}, + {0x1E64, 0x1A95, 0x707, 0x000, 0x081}, + {0x707, 0x199E, 0x1F5B, 0x000, 0x081} +}; + +static int CSC_COE_YUV2RGB601_WIDE_MPREC0[CSC_ROW][CSC_COL] = { + {0x400, 0x000, 0x59c, 0x000, 0x000}, + {0x400, 0x1ea0, 0x1d25, 0x77f, 0x000}, + {0x400, 0x717, 0x000, 0x77f, 0x000} +}; + +static int CSC_COE_RGB2YUV601_WIDE_MPREC2[CSC_ROW][CSC_COL] = { + {0x4C9, 0x964, 0x1d3, 0x000, 0x000}, + {0x1D4D, 0x1AB3, 0x800, 0x000, 0x081}, + {0x800, 0x194D, 0x1EB3, 0x000, 0x081}, +}; + +static int CSC_COE_YUV2RGB709_WIDE_MPREC0[CSC_ROW][CSC_COL] = { + {0x400, 0x000, 0x64d, 0x000, 0x000}, + {0x400, 0x1f40, 0x1e21, 0x77f, 0x000}, + {0x400, 0x76c, 0x000, 0x77f, 0x000} +}; + +static int CSC_COE_RGB2YUV709_WIDE_MPREC2[CSC_ROW][CSC_COL] = { + {0x367, 0xB71, 0x128, 0x000, 0x000}, + {0x1E2B, 0x19D5, 0x800, 0x000, 0x081}, + {0x800, 0x18BC, 0x1F44, 0x000, 0x081}, +}; + +void hisi_dss_csc_init(char __iomem *csc_base, dss_csc_t *s_csc) +{ + BUG_ON(csc_base == NULL); + BUG_ON(s_csc == NULL); + + memset(s_csc, 0, sizeof(dss_csc_t)); + + s_csc->idc0 = inp32(csc_base + CSC_IDC0); + s_csc->idc2 = inp32(csc_base + CSC_IDC2); + s_csc->odc0 = inp32(csc_base + CSC_ODC0); + s_csc->odc2 = inp32(csc_base + CSC_ODC2); + s_csc->p0 = inp32(csc_base + CSC_P0); + s_csc->p1 = inp32(csc_base + CSC_P1); + s_csc->p2 = inp32(csc_base + CSC_P2); + s_csc->p3 = inp32(csc_base + CSC_P3); + s_csc->p4 = inp32(csc_base + CSC_P4); + s_csc->icg_module = inp32(csc_base + CSC_ICG_MODULE); + s_csc->mprec = inp32(csc_base + CSC_MPREC); +} + +void +hisi_dss_csc_set_reg(struct hisi_fb_data_type *hisifd, + char __iomem *csc_base, dss_csc_t *s_csc) +{ + BUG_ON(hisifd == NULL); + BUG_ON(csc_base == NULL); + BUG_ON(s_csc == NULL); + + hisifd->set_reg(hisifd, csc_base + CSC_IDC0, s_csc->idc0, 32, 0); + hisifd->set_reg(hisifd, csc_base + CSC_IDC2, s_csc->idc2, 32, 0); + hisifd->set_reg(hisifd, csc_base + CSC_ODC0, s_csc->odc0, 32, 0); + hisifd->set_reg(hisifd, csc_base + CSC_ODC2, s_csc->odc2, 32, 0); + hisifd->set_reg(hisifd, csc_base + CSC_P0, s_csc->p0, 32, 0); + hisifd->set_reg(hisifd, csc_base + CSC_P1, s_csc->p1, 32, 0); + hisifd->set_reg(hisifd, csc_base + CSC_P2, s_csc->p2, 32, 0); + hisifd->set_reg(hisifd, csc_base + CSC_P3, s_csc->p3, 32, 0); + hisifd->set_reg(hisifd, csc_base + CSC_P4, s_csc->p4, 32, 0); + hisifd->set_reg(hisifd, csc_base + CSC_ICG_MODULE, + s_csc->icg_module, 32, 0); + hisifd->set_reg(hisifd, csc_base + CSC_MPREC, s_csc->mprec, 32, 0); +} + +bool is_pcsc_needed(dss_layer_t *layer) +{ + if (layer->chn_idx != DSS_RCHN_V0) + return false; + + if (layer->need_cap & CAP_2D_SHARPNESS) + return true; + + /* horizental shrink is not supported by arsr2p */ + if ((layer->dst_rect.h != layer->src_rect.h) + || (layer->dst_rect.w > layer->src_rect.w)) + return true; + + return false; +} + +int +hisi_dss_csc_config(struct hisi_fb_data_type *hisifd, + dss_layer_t *layer, dss_wb_layer_t *wb_layer) +{ + dss_csc_t *csc = NULL; + int chn_idx = 0; + uint32_t format = 0; + uint32_t csc_mode = 0; + int (*csc_coe_yuv2rgb)[CSC_COL]; + int (*csc_coe_rgb2yuv)[CSC_COL]; + + BUG_ON(hisifd == NULL); + + if (wb_layer) { + chn_idx = wb_layer->chn_idx; + format = wb_layer->dst.format; + csc_mode = wb_layer->dst.csc_mode; + } else { + chn_idx = layer->chn_idx; + format = layer->img.format; + csc_mode = layer->img.csc_mode; + } + + if (chn_idx != DSS_RCHN_V0) { + if (!isYUV(format)) + return 0; + hisifd->dss_module.csc_used[chn_idx] = 1; + } else if ((chn_idx == DSS_RCHN_V0) && (!isYUV(format))) { + if (!is_pcsc_needed(layer)) + return 0; + + hisifd->dss_module.csc_used[DSS_RCHN_V0] = 1; + hisifd->dss_module.pcsc_used[DSS_RCHN_V0] = 1; + } else { + hisifd->dss_module.csc_used[chn_idx] = 1; + } + + if (csc_mode == DSS_CSC_601_WIDE) { + csc_coe_yuv2rgb = CSC_COE_YUV2RGB601_WIDE_MPREC0; + csc_coe_rgb2yuv = CSC_COE_RGB2YUV601_WIDE_MPREC2; + } else if (csc_mode == DSS_CSC_601_NARROW) { + csc_coe_yuv2rgb = CSC_COE_YUV2RGB601_NARROW_MPREC0; + csc_coe_rgb2yuv = CSC_COE_RGB2YUV601_NARROW_MPREC2; + } else if (csc_mode == DSS_CSC_709_WIDE) { + csc_coe_yuv2rgb = CSC_COE_YUV2RGB709_WIDE_MPREC0; + csc_coe_rgb2yuv = CSC_COE_RGB2YUV709_WIDE_MPREC2; + } else if (csc_mode == DSS_CSC_709_NARROW) { + csc_coe_yuv2rgb = CSC_COE_YUV2RGB709_NARROW_MPREC0; + csc_coe_rgb2yuv = CSC_COE_RGB2YUV709_NARROW_MPREC2; + } else { + /* TBD add csc mprec mode 1 and mode 2 */ + HISI_FB_ERR("not support this csc_mode(%d)!\n", csc_mode); + csc_coe_yuv2rgb = CSC_COE_YUV2RGB601_WIDE_MPREC0; + csc_coe_rgb2yuv = CSC_COE_RGB2YUV601_WIDE_MPREC2; + } + + /* config rch csc */ + if (layer && hisifd->dss_module.csc_used[chn_idx]) { + csc = &(hisifd->dss_module.csc[chn_idx]); + csc->mprec = CSC_MPREC_MODE_YUV2RGB; + csc->icg_module = set_bits32(csc->icg_module, 0x1, 1, 0); + + csc->idc0 = set_bits32(csc->idc0, + (csc_coe_yuv2rgb[2][3]) | + (csc_coe_yuv2rgb[1][3] << 16), 27, 0); + csc->idc2 = + set_bits32(csc->idc2, (csc_coe_yuv2rgb[0][3]), 11, 0); + + csc->odc0 = set_bits32(csc->odc0, + (csc_coe_yuv2rgb[2][4]) | + (csc_coe_yuv2rgb[1][4] << 16), 27, 0); + csc->odc2 = + set_bits32(csc->odc2, (csc_coe_yuv2rgb[0][4]), 11, 0); + + csc->p0 = set_bits32(csc->p0, csc_coe_yuv2rgb[0][0], 13, 0); + csc->p0 = set_bits32(csc->p0, csc_coe_yuv2rgb[0][1], 13, 16); + + csc->p1 = set_bits32(csc->p1, csc_coe_yuv2rgb[0][2], 13, 0); + csc->p1 = set_bits32(csc->p1, csc_coe_yuv2rgb[1][0], 13, 16); + + csc->p2 = set_bits32(csc->p2, csc_coe_yuv2rgb[1][1], 13, 0); + csc->p2 = set_bits32(csc->p2, csc_coe_yuv2rgb[1][2], 13, 16); + + csc->p3 = set_bits32(csc->p3, csc_coe_yuv2rgb[2][0], 13, 0); + csc->p3 = set_bits32(csc->p3, csc_coe_yuv2rgb[2][1], 13, 16); + + csc->p4 = set_bits32(csc->p4, csc_coe_yuv2rgb[2][2], 13, 0); + } + + /* config rch pcsc */ + if (layer && hisifd->dss_module.pcsc_used[chn_idx]) { + csc = &(hisifd->dss_module.pcsc[chn_idx]); + csc->mprec = CSC_MPREC_MODE_RGB2YUV; + csc->icg_module = set_bits32(csc->icg_module, 0x1, 1, 0); + + csc->idc0 = set_bits32(csc->idc0, + (csc_coe_rgb2yuv[2][3]) | + (csc_coe_rgb2yuv[1][3] << 16), 27, 0); + csc->idc2 = + set_bits32(csc->idc2, (csc_coe_rgb2yuv[0][3]), 11, 0); + + csc->odc0 = set_bits32(csc->odc0, + (csc_coe_rgb2yuv[2][4]) | + (csc_coe_rgb2yuv[1][4] << 16), 27, 0); + csc->odc2 = + set_bits32(csc->odc2, (csc_coe_rgb2yuv[0][4]), 11, 0); + + csc->p0 = set_bits32(csc->p0, csc_coe_rgb2yuv[0][0], 13, 0); + csc->p0 = set_bits32(csc->p0, csc_coe_rgb2yuv[0][1], 13, 16); + + csc->p1 = set_bits32(csc->p1, csc_coe_rgb2yuv[0][2], 13, 0); + csc->p1 = set_bits32(csc->p1, csc_coe_rgb2yuv[1][0], 13, 16); + + csc->p2 = set_bits32(csc->p2, csc_coe_rgb2yuv[1][1], 13, 0); + csc->p2 = set_bits32(csc->p2, csc_coe_rgb2yuv[1][2], 13, 16); + + csc->p3 = set_bits32(csc->p3, csc_coe_rgb2yuv[2][0], 13, 0); + csc->p3 = set_bits32(csc->p3, csc_coe_rgb2yuv[2][1], 13, 16); + + csc->p4 = set_bits32(csc->p4, csc_coe_rgb2yuv[2][2], 13, 0); + } + + /* config wch csc */ + if (wb_layer) { + csc = &(hisifd->dss_module.csc[chn_idx]); + csc->mprec = CSC_MPREC_MODE_RGB2YUV; + csc->icg_module = set_bits32(csc->icg_module, 0x1, 1, 0); + + csc->idc0 = set_bits32(csc->idc0, + (csc_coe_rgb2yuv[2][3]) | + (csc_coe_rgb2yuv[1][3] << 16), 27, 0); + csc->idc2 = + set_bits32(csc->idc2, (csc_coe_rgb2yuv[0][3]), 11, 0); + + csc->odc0 = set_bits32(csc->odc0, + (csc_coe_rgb2yuv[2][4]) | + (csc_coe_rgb2yuv[1][4] << 16), 27, 0); + csc->odc2 = + set_bits32(csc->odc2, (csc_coe_rgb2yuv[0][4]), 11, 0); + + csc->p0 = set_bits32(csc->p0, csc_coe_rgb2yuv[0][0], 13, 0); + csc->p0 = set_bits32(csc->p0, csc_coe_rgb2yuv[0][1], 13, 16); + + csc->p1 = set_bits32(csc->p1, csc_coe_rgb2yuv[0][2], 13, 0); + csc->p1 = set_bits32(csc->p1, csc_coe_rgb2yuv[1][0], 13, 16); + + csc->p2 = set_bits32(csc->p2, csc_coe_rgb2yuv[1][1], 13, 0); + csc->p2 = set_bits32(csc->p2, csc_coe_rgb2yuv[1][2], 13, 16); + + csc->p3 = set_bits32(csc->p3, csc_coe_rgb2yuv[2][0], 13, 0); + csc->p3 = set_bits32(csc->p3, csc_coe_rgb2yuv[2][1], 13, 16); + + csc->p4 = set_bits32(csc->p4, csc_coe_rgb2yuv[2][2], 13, 0); + } + + return 0; +} + +uint32_t hisi_dss_mif_get_invalid_sel(dss_img_t *img, uint32_t transform, + int v_scaling_factor, uint8_t is_tile, + bool rdma_stretch_enable) +{ + uint32_t invalid_sel_val = 0; + uint32_t tlb_tag_org = 0; + + if (img == NULL) { + HISI_FB_ERR("img is null"); + return 0; + } + + if ((transform == (HISI_FB_TRANSFORM_ROT_90 | HISI_FB_TRANSFORM_FLIP_H)) + || (transform == + (HISI_FB_TRANSFORM_ROT_90 | HISI_FB_TRANSFORM_FLIP_V))) { + transform = HISI_FB_TRANSFORM_ROT_90; + } + + tlb_tag_org = (transform & 0x7) | + ((is_tile ? 1 : 0) << 3) | ((rdma_stretch_enable ? 1 : 0) << 4); + + switch (tlb_tag_org) { + case MMU_TLB_TAG_ORG_0x0: + invalid_sel_val = 1; + break; + case MMU_TLB_TAG_ORG_0x1: + invalid_sel_val = 1; + break; + case MMU_TLB_TAG_ORG_0x2: + invalid_sel_val = 2; + break; + case MMU_TLB_TAG_ORG_0x3: + invalid_sel_val = 2; + break; + case MMU_TLB_TAG_ORG_0x4: + invalid_sel_val = 0; + break; + case MMU_TLB_TAG_ORG_0x7: + invalid_sel_val = 0; + break; + + case MMU_TLB_TAG_ORG_0x8: + invalid_sel_val = 3; + break; + case MMU_TLB_TAG_ORG_0x9: + invalid_sel_val = 3; + break; + case MMU_TLB_TAG_ORG_0xA: + invalid_sel_val = 3; + break; + case MMU_TLB_TAG_ORG_0xB: + invalid_sel_val = 3; + break; + case MMU_TLB_TAG_ORG_0xC: + invalid_sel_val = 0; + break; + case MMU_TLB_TAG_ORG_0xF: + invalid_sel_val = 0; + break; + + case MMU_TLB_TAG_ORG_0x10: + invalid_sel_val = 1; + break; + case MMU_TLB_TAG_ORG_0x11: + invalid_sel_val = 1; + break; + case MMU_TLB_TAG_ORG_0x12: + invalid_sel_val = 2; + break; + case MMU_TLB_TAG_ORG_0x13: + invalid_sel_val = 2; + break; + case MMU_TLB_TAG_ORG_0x14: + invalid_sel_val = 0; + break; + case MMU_TLB_TAG_ORG_0x17: + invalid_sel_val = 0; + break; + + case MMU_TLB_TAG_ORG_0x18: + invalid_sel_val = 3; + break; + case MMU_TLB_TAG_ORG_0x19: + invalid_sel_val = 3; + break; + case MMU_TLB_TAG_ORG_0x1A: + invalid_sel_val = 3; + break; + case MMU_TLB_TAG_ORG_0x1B: + invalid_sel_val = 3; + break; + case MMU_TLB_TAG_ORG_0x1C: + invalid_sel_val = 0; + break; + case MMU_TLB_TAG_ORG_0x1F: + invalid_sel_val = 0; + break; + + default: + invalid_sel_val = 0; + HISI_FB_ERR("not support this tlb_tag_org(0x%x)!\n", + tlb_tag_org); + break; + } + + return invalid_sel_val; +} + +/******************************************************************************* + ** DSS ARSR2P + */ +#define ARSR2P_PHASE_NUM (9) +#define ARSR2P_TAP4 (4) +#define ARSR2P_TAP6 (6) +#define ARSR2P_MIN_INPUT (16) +#define ARSR2P_MAX_WIDTH (2560) +#define ARSR2P_MAX_HEIGHT (8192) +#define ARSR2P_SCALE_MAX (60) + +#define ARSR2P_SCL_UP_OFFSET (0x48) +#define ARSR2P_COEF_H0_OFFSET (0x100) +#define ARSR2P_COEF_H1_OFFSET (0x200) + +static const int COEF_AUV_SCL_UP_TAP4[ARSR2P_PHASE_NUM][ARSR2P_TAP4] = { + {-3, 254, 6, -1}, + {-9, 255, 13, -3}, + {-18, 254, 27, -7}, + {-23, 245, 44, -10}, + {-27, 233, 64, -14}, + {-29, 218, 85, -18}, + {-29, 198, 108, -21}, + {-29, 177, 132, -24}, + {-27, 155, 155, -27} +}; + +static const int COEF_AUV_SCL_DOWN_TAP4[ARSR2P_PHASE_NUM][ARSR2P_TAP4] = { + {31, 194, 31, 0}, + {23, 206, 44, -17}, + {14, 203, 57, -18}, + {6, 198, 70, -18}, + {0, 190, 85, -19}, + {-5, 180, 99, -18}, + {-10, 170, 114, -18}, + {-13, 157, 129, -17}, + {-15, 143, 143, -15} +}; + +static const int COEF_Y_SCL_UP_TAP6[ARSR2P_PHASE_NUM][ARSR2P_TAP6] = { + {0, -3, 254, 6, -1, 0}, + {4, -12, 252, 15, -5, 2}, + {7, -22, 245, 31, -9, 4}, + {10, -29, 234, 49, -14, 6}, + {12, -34, 221, 68, -19, 8}, + {13, -37, 206, 88, -24, 10}, + {14, -38, 189, 108, -29, 12}, + {14, -38, 170, 130, -33, 13}, + {14, -36, 150, 150, -36, 14} +}; + +static const int COEF_Y_SCL_DOWN_TAP6[ARSR2P_PHASE_NUM][ARSR2P_TAP6] = { + {-22, 43, 214, 43, -22, 0}, + {-18, 29, 205, 53, -23, 10}, + {-16, 18, 203, 67, -25, 9}, + {-13, 9, 198, 80, -26, 8}, + {-10, 0, 191, 95, -27, 7}, + {-7, -7, 182, 109, -27, 6}, + {-5, -14, 174, 124, -27, 4}, + {-2, -18, 162, 137, -25, 2}, + {0, -22, 150, 150, -22, 0} +}; + +/******************************************************************************* + ** DSS ARSR2P + */ +int +hisi_dss_arsr1p_write_coefs(struct hisi_fb_data_type *hisifd, + bool enable_cmdlist, char __iomem *addr, + const int **p, int row, int col) +{ + int coef_value = 0; + int coef_num = 0; + int i = 0; + int j = 0; + + BUG_ON(hisifd == NULL); + BUG_ON(addr == NULL); + + if ((row != ARSR2P_PHASE_NUM) + || ((col != ARSR2P_TAP4) && (col != ARSR2P_TAP6))) { + HISI_FB_ERR + ("arsr1p filter coefficients is err, arsr1p_phase_num = %d, arsr1p_tap_num = %d\n", + row, col); + return -EINVAL; + } + + coef_num = (col == ARSR2P_TAP4 ? 2 : 3); + + for (j = 0; j < 2; j++) { + for (i = 0; i < row; i++) { + if (coef_num == 2) { + coef_value = + (*((int *)p + i * col + j * coef_num) & + 0x1FF) | + ((*((int *)p + i * col + j * coef_num + 1) & + 0x1FF) << 9); + } else { + coef_value = + (*((int *)p + i * col + j * coef_num) & + 0x1FF) | + ((*((int *)p + i * col + j * coef_num + 1) & + 0x1FF) << 9) | ((*((int *)p + i * col + + j * coef_num + + 2) & 0x1FF) << 18); + } + + if (enable_cmdlist) { + hisifd->set_reg(hisifd, + addr + 0x8 * i + j * 0x4, + coef_value, 32, 0); + } else { + set_reg(addr + 0x8 * i + j * 0x4, coef_value, + 32, 0); + } + } + } + + return 0; +} + +int +hisi_dss_post_scl_load_filter_coef(struct hisi_fb_data_type *hisifd, + bool enable_cmdlist, + char __iomem *scl_lut_base, + int coef_lut_idx) +{ + int ret = 0; + + BUG_ON(hisifd == NULL); + + ret = + hisi_dss_arsr1p_write_coefs(hisifd, enable_cmdlist, + scl_lut_base + ARSR1P_COEFF_H_Y0, + (const int **)COEF_Y_SCL_UP_TAP6, + ARSR2P_PHASE_NUM, ARSR2P_TAP6); + if (ret < 0) { + HISI_FB_ERR("Error to write H_Y0_COEF coefficients.\n"); + } + + ret = + hisi_dss_arsr1p_write_coefs(hisifd, enable_cmdlist, + scl_lut_base + ARSR1P_COEFF_V_Y0, + (const int **)COEF_Y_SCL_UP_TAP6, + ARSR2P_PHASE_NUM, ARSR2P_TAP6); + if (ret < 0) { + HISI_FB_ERR("Error to write V_Y0_COEF coefficients.\n"); + } + + ret = + hisi_dss_arsr1p_write_coefs(hisifd, enable_cmdlist, + scl_lut_base + ARSR1P_COEFF_H_UV0, + (const int **)COEF_AUV_SCL_UP_TAP4, + ARSR2P_PHASE_NUM, ARSR2P_TAP4); + if (ret < 0) { + HISI_FB_ERR("Error to write H_UV0_COEF coefficients.\n"); + } + + ret = + hisi_dss_arsr1p_write_coefs(hisifd, enable_cmdlist, + scl_lut_base + ARSR1P_COEFF_V_UV0, + (const int **)COEF_AUV_SCL_UP_TAP4, + ARSR2P_PHASE_NUM, ARSR2P_TAP4); + if (ret < 0) { + HISI_FB_ERR("Error to write V_UV0_COEF coefficients.\n"); + } + + return ret; +} + +int +hisi_dss_arsr2p_write_coefs(struct hisi_fb_data_type *hisifd, + bool enable_cmdlist, char __iomem *addr, + const int **p, int row, int col) +{ + int coef_value = 0; + int coef_num = 0; + int i = 0; + int j = 0; + + BUG_ON(hisifd == NULL); + BUG_ON(addr == NULL); + + if ((row != ARSR2P_PHASE_NUM) + || ((col != ARSR2P_TAP4) && (col != ARSR2P_TAP6))) { + HISI_FB_ERR + ("arsr2p filter coefficients is err, arsr2p_phase_num = %d, arsr2p_tap_num = %d\n", + row, col); + return -EINVAL; + } + + coef_num = (col == ARSR2P_TAP4 ? 2 : 3); + for (i = 0; i < row; i++) { + for (j = 0; j < 2; j++) { + if (coef_num == 2) { + coef_value = + (*((int *)p + i * col + j * coef_num) & + 0x1FF) | + ((*((int *)p + i * col + j * coef_num + 1) & + 0x1FF) << 9); + } else { + coef_value = + (*((int *)p + i * col + j * coef_num) & + 0x1FF) | + ((*((int *)p + i * col + j * coef_num + 1) & + 0x1FF) << 9) | ((*((int *)p + i * col + + j * coef_num + + 2) & 0x1FF) << 18); + } + + if (enable_cmdlist) { + hisifd->set_reg(hisifd, + addr + 0x8 * i + j * 0x4, + coef_value, 32, 0); + } else { + set_reg(addr + 0x8 * i + j * 0x4, coef_value, + 32, 0); + } + } + } + + return 0; +} + +void +hisi_dss_arsr2p_write_config_coefs(struct hisi_fb_data_type *hisifd, + bool enable_cmdlist, + char __iomem *addr, + const int **scl_down, + const int **scl_up, int row, int col) +{ + int ret = 0; + + ret = + hisi_dss_arsr2p_write_coefs(hisifd, enable_cmdlist, addr, + scl_down, row, col); + if (ret < 0) { + HISI_FB_ERR("Error to write COEF_SCL_DOWN coefficients.\n"); + return; + } + + ret = + hisi_dss_arsr2p_write_coefs(hisifd, enable_cmdlist, + addr + ARSR2P_SCL_UP_OFFSET, scl_up, + row, col); + if (ret < 0) { + HISI_FB_ERR("Error to write COEF_SCL_UP coefficients.\n"); + return; + } + +} + +void hisi_dss_arsr2p_init(char __iomem *arsr2p_base, dss_arsr2p_t *s_arsr2p) +{ + BUG_ON(arsr2p_base == NULL); + BUG_ON(s_arsr2p == NULL); + + memset(s_arsr2p, 0, sizeof(dss_arsr2p_t)); + + s_arsr2p->arsr_input_width_height = + inp32(arsr2p_base + ARSR2P_INPUT_WIDTH_HEIGHT); + s_arsr2p->arsr_output_width_height = + inp32(arsr2p_base + ARSR2P_OUTPUT_WIDTH_HEIGHT); + s_arsr2p->ihleft = inp32(arsr2p_base + ARSR2P_IHLEFT); + s_arsr2p->ihright = inp32(arsr2p_base + ARSR2P_IHRIGHT); + s_arsr2p->ivtop = inp32(arsr2p_base + ARSR2P_IVTOP); + s_arsr2p->ivbottom = inp32(arsr2p_base + ARSR2P_IVBOTTOM); + s_arsr2p->ihinc = inp32(arsr2p_base + ARSR2P_IHINC); + s_arsr2p->ivinc = inp32(arsr2p_base + ARSR2P_IVINC); + s_arsr2p->offset = inp32(arsr2p_base + ARSR2P_UV_OFFSET); + s_arsr2p->mode = inp32(arsr2p_base + ARSR2P_MODE); + s_arsr2p->arsr2p_effect.skin_thres_y = + inp32(arsr2p_base + ARSR2P_SKIN_THRES_Y); + s_arsr2p->arsr2p_effect.skin_thres_u = + inp32(arsr2p_base + ARSR2P_SKIN_THRES_U); + s_arsr2p->arsr2p_effect.skin_thres_v = + inp32(arsr2p_base + ARSR2P_SKIN_THRES_V); + s_arsr2p->arsr2p_effect.skin_cfg0 = + inp32(arsr2p_base + ARSR2P_SKIN_CFG0); + s_arsr2p->arsr2p_effect.skin_cfg1 = + inp32(arsr2p_base + ARSR2P_SKIN_CFG1); + s_arsr2p->arsr2p_effect.skin_cfg2 = + inp32(arsr2p_base + ARSR2P_SKIN_CFG2); + s_arsr2p->arsr2p_effect.shoot_cfg1 = + inp32(arsr2p_base + ARSR2P_SHOOT_CFG1); + s_arsr2p->arsr2p_effect.shoot_cfg2 = + inp32(arsr2p_base + ARSR2P_SHOOT_CFG2); + s_arsr2p->arsr2p_effect.sharp_cfg1 = + inp32(arsr2p_base + ARSR2P_SHARP_CFG1); + s_arsr2p->arsr2p_effect.sharp_cfg2 = + inp32(arsr2p_base + ARSR2P_SHARP_CFG2); + s_arsr2p->arsr2p_effect.sharp_cfg3 = + inp32(arsr2p_base + ARSR2P_SHARP_CFG3); + s_arsr2p->arsr2p_effect.sharp_cfg4 = + inp32(arsr2p_base + ARSR2P_SHARP_CFG4); + s_arsr2p->arsr2p_effect.sharp_cfg5 = + inp32(arsr2p_base + ARSR2P_SHARP_CFG5); + s_arsr2p->arsr2p_effect.sharp_cfg6 = + inp32(arsr2p_base + ARSR2P_SHARP_CFG6); + s_arsr2p->arsr2p_effect.sharp_cfg7 = + inp32(arsr2p_base + ARSR2P_SHARP_CFG7); + s_arsr2p->arsr2p_effect.sharp_cfg8 = + inp32(arsr2p_base + ARSR2P_SHARP_CFG8); + s_arsr2p->arsr2p_effect.sharp_cfg9 = + inp32(arsr2p_base + ARSR2P_SHARP_CFG9); + s_arsr2p->arsr2p_effect.texturw_analysts = + inp32(arsr2p_base + ARSR2P_TEXTURW_ANALYSTS); + s_arsr2p->arsr2p_effect.intplshootctrl = + inp32(arsr2p_base + ARSR2P_INTPLSHOOTCTRL); + + s_arsr2p->ihleft1 = inp32(arsr2p_base + ARSR2P_IHLEFT1); + s_arsr2p->ihright1 = inp32(arsr2p_base + ARSR2P_IHRIGHT1); + s_arsr2p->ivbottom1 = inp32(arsr2p_base + ARSR2P_IVBOTTOM1); +} + +void +hisi_dss_arsr2p_set_reg(struct hisi_fb_data_type *hisifd, + char __iomem *arsr2p_base, dss_arsr2p_t *s_arsr2p) +{ + BUG_ON(arsr2p_base == NULL); + BUG_ON(s_arsr2p == NULL); + + hisifd->set_reg(hisifd, arsr2p_base + ARSR2P_INPUT_WIDTH_HEIGHT, + s_arsr2p->arsr_input_width_height, 32, 0); + hisifd->set_reg(hisifd, arsr2p_base + ARSR2P_OUTPUT_WIDTH_HEIGHT, + s_arsr2p->arsr_output_width_height, 32, 0); + hisifd->set_reg(hisifd, arsr2p_base + ARSR2P_IHLEFT, + s_arsr2p->ihleft, 32, 0); + hisifd->set_reg(hisifd, arsr2p_base + ARSR2P_IHRIGHT, + s_arsr2p->ihright, 32, 0); + hisifd->set_reg(hisifd, arsr2p_base + ARSR2P_IVTOP, + s_arsr2p->ivtop, 32, 0); + hisifd->set_reg(hisifd, arsr2p_base + ARSR2P_IVBOTTOM, + s_arsr2p->ivbottom, 32, 0); + hisifd->set_reg(hisifd, arsr2p_base + ARSR2P_IHINC, + s_arsr2p->ihinc, 32, 0); + hisifd->set_reg(hisifd, arsr2p_base + ARSR2P_IVINC, + s_arsr2p->ivinc, 32, 0); + hisifd->set_reg(hisifd, arsr2p_base + ARSR2P_UV_OFFSET, + s_arsr2p->offset, 32, 0); + hisifd->set_reg(hisifd, arsr2p_base + ARSR2P_MODE, + s_arsr2p->mode, 32, 0); + + if (hisifd->dss_module.arsr2p_effect_used[DSS_RCHN_V0]) { + hisifd->set_reg(hisifd, arsr2p_base + ARSR2P_SKIN_THRES_Y, + s_arsr2p->arsr2p_effect.skin_thres_y, 32, 0); + hisifd->set_reg(hisifd, arsr2p_base + ARSR2P_SKIN_THRES_U, + s_arsr2p->arsr2p_effect.skin_thres_u, 32, 0); + hisifd->set_reg(hisifd, arsr2p_base + ARSR2P_SKIN_THRES_V, + s_arsr2p->arsr2p_effect.skin_thres_v, 32, 0); + hisifd->set_reg(hisifd, arsr2p_base + ARSR2P_SKIN_CFG0, + s_arsr2p->arsr2p_effect.skin_cfg0, 32, 0); + hisifd->set_reg(hisifd, arsr2p_base + ARSR2P_SKIN_CFG1, + s_arsr2p->arsr2p_effect.skin_cfg1, 32, 0); + hisifd->set_reg(hisifd, arsr2p_base + ARSR2P_SKIN_CFG2, + s_arsr2p->arsr2p_effect.skin_cfg2, 32, 0); + hisifd->set_reg(hisifd, arsr2p_base + ARSR2P_SHOOT_CFG1, + s_arsr2p->arsr2p_effect.shoot_cfg1, 32, 0); + hisifd->set_reg(hisifd, arsr2p_base + ARSR2P_SHOOT_CFG2, + s_arsr2p->arsr2p_effect.shoot_cfg2, 32, 0); + hisifd->set_reg(hisifd, arsr2p_base + ARSR2P_SHARP_CFG1, + s_arsr2p->arsr2p_effect.sharp_cfg1, 32, 0); + hisifd->set_reg(hisifd, arsr2p_base + ARSR2P_SHARP_CFG2, + s_arsr2p->arsr2p_effect.sharp_cfg2, 32, 0); + hisifd->set_reg(hisifd, arsr2p_base + ARSR2P_SHARP_CFG3, + s_arsr2p->arsr2p_effect.sharp_cfg3, 32, 0); + hisifd->set_reg(hisifd, arsr2p_base + ARSR2P_SHARP_CFG4, + s_arsr2p->arsr2p_effect.sharp_cfg4, 32, 0); + hisifd->set_reg(hisifd, arsr2p_base + ARSR2P_SHARP_CFG5, + s_arsr2p->arsr2p_effect.sharp_cfg5, 32, 0); + hisifd->set_reg(hisifd, arsr2p_base + ARSR2P_SHARP_CFG6, + s_arsr2p->arsr2p_effect.sharp_cfg6, 32, 0); + hisifd->set_reg(hisifd, arsr2p_base + ARSR2P_SHARP_CFG7, + s_arsr2p->arsr2p_effect.sharp_cfg7, 32, 0); + hisifd->set_reg(hisifd, arsr2p_base + ARSR2P_SHARP_CFG8, + s_arsr2p->arsr2p_effect.sharp_cfg8, 32, 0); + hisifd->set_reg(hisifd, arsr2p_base + ARSR2P_SHARP_CFG9, + s_arsr2p->arsr2p_effect.sharp_cfg9, 32, 0); + hisifd->set_reg(hisifd, arsr2p_base + ARSR2P_TEXTURW_ANALYSTS, + s_arsr2p->arsr2p_effect.texturw_analysts, 32, 0); + hisifd->set_reg(hisifd, arsr2p_base + ARSR2P_INTPLSHOOTCTRL, + s_arsr2p->arsr2p_effect.intplshootctrl, 32, 0); + } + + hisifd->set_reg(hisifd, arsr2p_base + ARSR2P_IHLEFT1, + s_arsr2p->ihleft1, 32, 0); + hisifd->set_reg(hisifd, arsr2p_base + ARSR2P_IHRIGHT1, + s_arsr2p->ihright1, 32, 0); + hisifd->set_reg(hisifd, arsr2p_base + ARSR2P_IVBOTTOM1, + s_arsr2p->ivbottom1, 32, 0); +} + +void +hisi_dss_arsr2p_coef_on(struct hisi_fb_data_type *hisifd, bool enable_cmdlist) +{ + uint32_t module_base = 0; + char __iomem *arsr2p_base = 0; + char __iomem *coefy_v = NULL; + char __iomem *coefa_v = NULL; + char __iomem *coefuv_v = NULL; + + BUG_ON(hisifd == NULL); + + module_base = g_dss_module_base[DSS_RCHN_V0][MODULE_ARSR2P_LUT]; + coefy_v = hisifd->dss_base + module_base + ARSR2P_LUT_COEFY_V_OFFSET; + coefa_v = hisifd->dss_base + module_base + ARSR2P_LUT_COEFA_V_OFFSET; + coefuv_v = hisifd->dss_base + module_base + ARSR2P_LUT_COEFUV_V_OFFSET; + arsr2p_base = + hisifd->dss_base + g_dss_module_base[DSS_RCHN_V0][MODULE_ARSR2P]; + + /* COEFY_V COEFY_H */ + hisi_dss_arsr2p_write_config_coefs(hisifd, enable_cmdlist, coefy_v, + (const int **) + COEF_Y_SCL_DOWN_TAP6, + (const int **)COEF_Y_SCL_UP_TAP6, + ARSR2P_PHASE_NUM, ARSR2P_TAP6); + hisi_dss_arsr2p_write_config_coefs(hisifd, enable_cmdlist, + coefy_v + ARSR2P_COEF_H0_OFFSET, + (const int **) + COEF_Y_SCL_DOWN_TAP6, + (const int **)COEF_Y_SCL_UP_TAP6, + ARSR2P_PHASE_NUM, ARSR2P_TAP6); + hisi_dss_arsr2p_write_config_coefs(hisifd, enable_cmdlist, + coefy_v + ARSR2P_COEF_H1_OFFSET, + (const int **) + COEF_Y_SCL_DOWN_TAP6, + (const int **)COEF_Y_SCL_UP_TAP6, + ARSR2P_PHASE_NUM, ARSR2P_TAP6); + + /* COEFA_V COEFA_H */ + hisi_dss_arsr2p_write_config_coefs(hisifd, enable_cmdlist, coefa_v, + (const int **) + COEF_AUV_SCL_DOWN_TAP4, + (const int **) + COEF_AUV_SCL_UP_TAP4, + ARSR2P_PHASE_NUM, ARSR2P_TAP4); + hisi_dss_arsr2p_write_config_coefs(hisifd, enable_cmdlist, + coefa_v + ARSR2P_COEF_H0_OFFSET, + (const int **) + COEF_AUV_SCL_DOWN_TAP4, + (const int **) + COEF_AUV_SCL_UP_TAP4, + ARSR2P_PHASE_NUM, ARSR2P_TAP4); + hisi_dss_arsr2p_write_config_coefs(hisifd, enable_cmdlist, + coefa_v + ARSR2P_COEF_H1_OFFSET, + (const int **) + COEF_AUV_SCL_DOWN_TAP4, + (const int **) + COEF_AUV_SCL_UP_TAP4, + ARSR2P_PHASE_NUM, ARSR2P_TAP4); + + /* COEFUV_V COEFUV_H */ + hisi_dss_arsr2p_write_config_coefs(hisifd, enable_cmdlist, coefuv_v, + (const int **) + COEF_AUV_SCL_DOWN_TAP4, + (const int **) + COEF_AUV_SCL_UP_TAP4, + ARSR2P_PHASE_NUM, ARSR2P_TAP4); + hisi_dss_arsr2p_write_config_coefs(hisifd, enable_cmdlist, + coefuv_v + ARSR2P_COEF_H0_OFFSET, + (const int **) + COEF_AUV_SCL_DOWN_TAP4, + (const int **) + COEF_AUV_SCL_UP_TAP4, + ARSR2P_PHASE_NUM, ARSR2P_TAP4); + hisi_dss_arsr2p_write_config_coefs(hisifd, enable_cmdlist, + coefuv_v + ARSR2P_COEF_H1_OFFSET, + (const int **) + COEF_AUV_SCL_DOWN_TAP4, + (const int **) + COEF_AUV_SCL_UP_TAP4, + ARSR2P_PHASE_NUM, ARSR2P_TAP4); + + if (enable_cmdlist) { + hisifd->set_reg = hisi_cmdlist_set_reg; + } else { + hisifd->set_reg = hisifb_set_reg; + } + hisifd->set_reg(hisifd, arsr2p_base + ARSR2P_SKIN_THRES_Y, + (75 | (83 << 8) | (145 << 16)), 32, 0); + hisifd->set_reg(hisifd, arsr2p_base + ARSR2P_SKIN_THRES_U, + (5 | (10 << 8) | (113 << 16)), 32, 0); + hisifd->set_reg(hisifd, arsr2p_base + ARSR2P_SKIN_THRES_V, + (6 | (12 << 8) | (152 << 16)), 32, 0); + hisifd->set_reg(hisifd, arsr2p_base + ARSR2P_SKIN_CFG0, + (512 | (3 << 12)), 32, 0); + hisifd->set_reg(hisifd, arsr2p_base + ARSR2P_SKIN_CFG1, (819), 32, 0); + hisifd->set_reg(hisifd, arsr2p_base + ARSR2P_SKIN_CFG2, (682), 32, 0); + hisifd->set_reg(hisifd, arsr2p_base + ARSR2P_SHOOT_CFG1, + (512 | (20 << 16)), 32, 0); + hisifd->set_reg(hisifd, arsr2p_base + ARSR2P_SHOOT_CFG2, + (-16 | (0 << 16)), 32, 0); + hisifd->set_reg(hisifd, arsr2p_base + ARSR2P_SHARP_CFG1, + (2 | (6 << 8) | (48 << 16) | (64 << 24)), 32, 0); + hisifd->set_reg(hisifd, arsr2p_base + ARSR2P_SHARP_CFG2, + (8 | (24 << 8) | (24 << 16) | (40 << 24)), 32, 0); + hisifd->set_reg(hisifd, arsr2p_base + ARSR2P_SHARP_CFG3, + (1 | (1 << 8) | (2500 << 16)), 32, 0); + hisifd->set_reg(hisifd, arsr2p_base + ARSR2P_SHARP_CFG4, + (10 | (6 << 8) | (9 << 16) | (12 << 24)), 32, 0); + hisifd->set_reg(hisifd, arsr2p_base + ARSR2P_SHARP_CFG5, + (2 | (12 << 8)), 32, 0); + hisifd->set_reg(hisifd, arsr2p_base + ARSR2P_SHARP_CFG6, + (448 | (64 << 16)), 32, 0); + hisifd->set_reg(hisifd, arsr2p_base + ARSR2P_SHARP_CFG7, + (1 | (250 << 16)), 32, 0); + hisifd->set_reg(hisifd, arsr2p_base + ARSR2P_SHARP_CFG8, + (-48000), 32, 0); + hisifd->set_reg(hisifd, arsr2p_base + ARSR2P_SHARP_CFG9, + (-32000), 32, 0); + hisifd->set_reg(hisifd, arsr2p_base + ARSR2P_TEXTURW_ANALYSTS, + (15 | (20 << 16)), 32, 0); + hisifd->set_reg(hisifd, arsr2p_base + ARSR2P_INTPLSHOOTCTRL, + (4), 32, 0); + +} + +void hisi_dss_arsr2p_effect_config(dss_arsr2p_effect_t *arsr2p_effect) +{ + arsr2p_effect->skin_thres_y = 75 | (83 << 8) | (145 << 16); + arsr2p_effect->skin_thres_u = 5 | (10 << 8) | (113 << 16); + arsr2p_effect->skin_thres_v = 6 | (12 << 8) | (152 << 16); + arsr2p_effect->skin_cfg0 = 512 | (3 << 12); + arsr2p_effect->skin_cfg1 = 819; + arsr2p_effect->skin_cfg2 = 682; + arsr2p_effect->shoot_cfg1 = 512 | (20 << 16); + arsr2p_effect->shoot_cfg2 = -16 | (0 << 16); + arsr2p_effect->sharp_cfg1 = 2 | (6 << 8) | (48 << 16) | (64 << 24); + arsr2p_effect->sharp_cfg2 = 8 | (24 << 8) | (24 << 16) | (40 << 24); + arsr2p_effect->sharp_cfg3 = 1 | (1 << 8) | (2500 << 16); + arsr2p_effect->sharp_cfg4 = 10 | (6 << 8) | (9 << 16) | (12 << 24); + arsr2p_effect->sharp_cfg5 = 2 | (12 << 8); + arsr2p_effect->sharp_cfg6 = 448 | (64 << 16); + arsr2p_effect->sharp_cfg7 = 1 | (250 << 16); + arsr2p_effect->sharp_cfg8 = -48000; + arsr2p_effect->sharp_cfg9 = -32000; + arsr2p_effect->texturw_analysts = 15 | (20 << 16); + arsr2p_effect->intplshootctrl = 4; +} + +int +hisi_dss_arsr2p_config(struct hisi_fb_data_type *hisifd, + dss_layer_t *layer, dss_rect_t *aligned_rect, + bool rdma_stretch_enable) +{ + dss_arsr2p_t *arsr2p = NULL; + dss_rect_t src_rect; + dss_rect_t dst_rect; + uint32_t need_cap = 0; + int chn_idx = 0; + dss_block_info_t *pblock_info = NULL; + int extraw = 0, extraw_left = 0, extraw_right = 0; + + bool en_hscl = false; + bool en_vscl = false; + + /* arsr mode */ + bool imageintpl_dis = false; + bool hscldown_enabled = false; + bool nearest_en = false; + bool diintpl_en = false; + bool textureanalyhsisen_en = false; + bool skinctrl_en = false; + bool shootdetect_en = false; + bool sharpen_en = false; + bool arsr2p_bypass = true; + + bool hscldown_flag = false; + + int ih_inc = 0; + int iv_inc = 0; + int ih_left = 0; + int ih_right = 0; + int iv_top = 0; + int iv_bottom = 0; + int uv_offset = 0; + int src_width = 0; + int dst_whole_width = 0; + + int outph_left = 0; + int outph_right = 0; + int outpv_bottom = 0; + + BUG_ON(hisifd == NULL); + BUG_ON(layer == NULL); + + chn_idx = layer->chn_idx; + if (chn_idx != DSS_RCHN_V0) { + return 0; + } + + need_cap = layer->need_cap; + + src_rect = layer->src_rect; + dst_rect = layer->dst_rect; + pblock_info = &(layer->block_info); + + if (pblock_info && pblock_info->h_ratio_arsr2p) { + src_rect = pblock_info->arsr2p_in_rect; + } + + src_rect.h = aligned_rect->h; + + /* horizental scaler compute */ + do { + if (pblock_info && pblock_info->h_ratio_arsr2p) { + ih_inc = pblock_info->h_ratio_arsr2p; + src_width = src_rect.w; + dst_whole_width = pblock_info->arsr2p_dst_w; + src_rect.x = src_rect.x - pblock_info->arsr2p_src_x; + src_rect.y = src_rect.y - pblock_info->arsr2p_src_y; + dst_rect.x = dst_rect.x - pblock_info->arsr2p_dst_x; + dst_rect.y = dst_rect.y - pblock_info->arsr2p_dst_y; + + if (pblock_info->both_vscfh_arsr2p_used) { + hscldown_flag = true; + } + + if (rdma_stretch_enable) { + en_hscl = true; + } + + if (ih_inc && ih_inc != ARSR2P_INC_FACTOR) { + en_hscl = true; + } + } else { + /* horizental scaling down is not supported by arsr2p, set src_rect.w = dst_rect.w */ + if (src_rect.w > dst_rect.w) { + src_width = dst_rect.w; + hscldown_flag = true; + } else { + src_width = src_rect.w; + } + dst_whole_width = dst_rect.w; + + src_rect.x = 0; + src_rect.y = 0; + dst_rect.x = 0; + dst_rect.y = 0; + if (src_width != dst_rect.w) + en_hscl = true; + + ih_inc = + (DSS_WIDTH(src_width) * ARSR2P_INC_FACTOR + + ARSR2P_INC_FACTOR - ih_left) / dst_rect.w; + } + + outph_left = + dst_rect.x * ih_inc - (src_rect.x * ARSR2P_INC_FACTOR); + if (outph_left < 0) + outph_left = 0; + + extraw = (8 * ARSR2P_INC_FACTOR) / ih_inc; + extraw_left = (extraw % 2) ? (extraw + 1) : (extraw); + ih_left = outph_left - extraw_left * ih_inc; + if (ih_left < 0) + ih_left = 0; + + outph_right = + (dst_rect.x + dst_rect.w - 1) * ih_inc - + (src_rect.x * ARSR2P_INC_FACTOR); + if (dst_whole_width == dst_rect.w) { + extraw = (2 * ARSR2P_INC_FACTOR) / ih_inc; + extraw_right = (extraw % 2) ? (extraw + 1) : (extraw); + ih_right = outph_right + extraw_right * ih_inc; + + /*if(ihright+(starti << 16)) >(width - 1)* ihinc); + ihright = endo*ihinc-(starti<<16); */ + extraw = + (dst_whole_width - 1) * ih_inc - + (src_rect.x * ARSR2P_INC_FACTOR); + + if (ih_right > extraw) { + ih_right = extraw; + } + } else { + ih_right = src_width * ARSR2P_INC_FACTOR - 1; + } + } while(0); + + /* vertical scaler compute */ + do { + if (src_rect.h != dst_rect.h) + en_vscl = true; + + if (src_rect.h > dst_rect.h) { + iv_inc = + (DSS_HEIGHT(src_rect.h) * ARSR2P_INC_FACTOR + + ARSR2P_INC_FACTOR / 2 - + iv_top) / DSS_HEIGHT(dst_rect.h); + } else { + iv_inc = + (DSS_HEIGHT(src_rect.h) * ARSR2P_INC_FACTOR + + ARSR2P_INC_FACTOR - iv_top) / dst_rect.h; + } + + iv_bottom = DSS_HEIGHT(dst_rect.h) * iv_inc + iv_top; + outpv_bottom = iv_bottom; + } while(0); + + if (need_cap & CAP_2D_SHARPNESS) { + sharpen_en = true; + } + + if ((!en_hscl) && (!en_vscl)) { + if (!sharpen_en) { + /*if both scaler up and sharpness are not needed, just return */ + return 0; + } else if (!hscldown_flag) { + /*if only sharpness is needed, disable image interplo, enable textureanalyhsis */ + imageintpl_dis = true; + textureanalyhsisen_en = true; + } + } + + arsr2p = &(hisifd->dss_module.arsr2p[chn_idx]); + hisifd->dss_module.arsr2p_used[chn_idx] = 1; + + /*check arsr2p input and output width */ + if ((src_width < ARSR2P_MIN_INPUT) || (dst_rect.w < ARSR2P_MIN_INPUT) + || (src_width > ARSR2P_MAX_WIDTH) + || (dst_rect.w > ARSR2P_MAX_WIDTH)) { + HISI_FB_ERR + ("src_rect.w(%d) or dst_rect.w(%d) is smaller than 16 " + "or larger than 2560!\n", + src_width, dst_rect.w); + return -EINVAL; + } + + if ((dst_rect.w > (src_width * ARSR2P_SCALE_MAX)) + || (src_width > (dst_rect.w * ARSR2P_SCALE_MAX))) { + HISI_FB_ERR + ("width out of range, original_src_rec(%d, %d, %d, %d) " + "new_src_rect(%d, %d, %d, %d), dst_rect(%d, %d, %d, %d)\n", + layer->src_rect.x, layer->src_rect.y, src_width, + layer->src_rect.h, src_rect.x, src_rect.y, src_width, + src_rect.h, dst_rect.x, dst_rect.y, dst_rect.w, + dst_rect.h); + + return -EINVAL; + } + + /*check arsr2p input and output height */ + if ((src_rect.h > ARSR2P_MAX_HEIGHT) + || (dst_rect.h > ARSR2P_MAX_HEIGHT)) { + HISI_FB_ERR + ("src_rect.h(%d) or dst_rect.h(%d) is smaller than 16 " + "or larger than 8192!\n", + src_rect.h, dst_rect.h); + return -EINVAL; + } + + if ((dst_rect.h > (src_rect.h * ARSR2P_SCALE_MAX)) + || (src_rect.h > (dst_rect.h * ARSR2P_SCALE_MAX))) { + HISI_FB_ERR + ("height out of range, original_src_rec(%d, %d, %d, %d) " + "new_src_rect(%d, %d, %d, %d), dst_rect(%d, %d, %d, %d).\n", + layer->src_rect.x, layer->src_rect.y, layer->src_rect.w, + layer->src_rect.h, src_rect.x, src_rect.y, src_rect.w, + src_rect.h, dst_rect.x, dst_rect.y, dst_rect.w, + dst_rect.h); + return -EINVAL; + } + + /*if arsr2p is enabled, hbp+hfp+hsw > 20 */ + /*if (hisifd_primary && (hisifd_primary->panel_info.ldi.h_back_porch + hisifd_primary->panel_info.ldi.h_front_porch + + hisifd_primary->panel_info.ldi.h_pulse_width) <= 20) { + HISI_FB_ERR("ldi hbp+hfp+hsw is not larger than 20, return!\n"); + return -EINVAL; + } */ + + /*config arsr2p mode , start */ + arsr2p_bypass = false; + do { + if (hscldown_flag) { + hscldown_enabled = true; + break; + } + + if (!en_hscl && (iv_inc >= 2 * ARSR2P_INC_FACTOR) + && !pblock_info->h_ratio_arsr2p) { + nearest_en = true; + sharpen_en = false; + break; + } + + if ((!en_hscl) && (!en_vscl)) { + break; + } + + diintpl_en = true; + textureanalyhsisen_en = true; + } while(0); + + if (sharpen_en) { + skinctrl_en = true; + shootdetect_en = true; + } + /*config arsr2p mode , end */ + + /*if sharpness 2d is needed, config the arsr2p effect */ + hisi_dss_arsr2p_effect_config(&(arsr2p->arsr2p_effect)); + hisifd->dss_module.arsr2p_effect_used[chn_idx] = 1; + + arsr2p->arsr_input_width_height = + set_bits32(arsr2p->arsr_input_width_height, + DSS_HEIGHT(src_rect.h), 13, 0); + arsr2p->arsr_input_width_height = + set_bits32(arsr2p->arsr_input_width_height, DSS_WIDTH(src_width), + 13, 16); + arsr2p->arsr_output_width_height = + set_bits32(arsr2p->arsr_output_width_height, + DSS_HEIGHT(dst_rect.h), 13, 0); + arsr2p->arsr_output_width_height = + set_bits32(arsr2p->arsr_output_width_height, + DSS_WIDTH(dst_rect.w), 13, 16); + arsr2p->ihleft = set_bits32(arsr2p->ihleft, ih_left, 29, 0); + arsr2p->ihright = set_bits32(arsr2p->ihright, ih_right, 29, 0); + arsr2p->ivtop = set_bits32(arsr2p->ivtop, iv_top, 29, 0); + arsr2p->ivbottom = set_bits32(arsr2p->ivbottom, iv_bottom, 29, 0); + arsr2p->ihinc = set_bits32(arsr2p->ihinc, ih_inc, 22, 0); + arsr2p->ivinc = set_bits32(arsr2p->ivinc, iv_inc, 22, 0); + arsr2p->offset = set_bits32(arsr2p->offset, uv_offset, 22, 0); + arsr2p->mode = set_bits32(arsr2p->mode, arsr2p_bypass, 1, 0); + arsr2p->mode = set_bits32(arsr2p->mode, sharpen_en, 1, 1); + arsr2p->mode = set_bits32(arsr2p->mode, shootdetect_en, 1, 2); + arsr2p->mode = set_bits32(arsr2p->mode, skinctrl_en, 1, 3); + arsr2p->mode = set_bits32(arsr2p->mode, textureanalyhsisen_en, 1, 4); + arsr2p->mode = set_bits32(arsr2p->mode, diintpl_en, 1, 5); + arsr2p->mode = set_bits32(arsr2p->mode, nearest_en, 1, 6); + arsr2p->mode = set_bits32(arsr2p->mode, hscldown_enabled, 1, 7); + arsr2p->mode = set_bits32(arsr2p->mode, imageintpl_dis, 1, 8); + + arsr2p->ihleft1 = set_bits32(arsr2p->ihleft1, outph_left, 29, 0); + arsr2p->ihright1 = set_bits32(arsr2p->ihright1, outph_right, 29, 0); + arsr2p->ivbottom1 = set_bits32(arsr2p->ivbottom1, outpv_bottom, 29, 0); + + return 0; +} + +/******************************************************************************* + ** DSS remove mctl ch&ov mutex for offline + */ +void +hisi_remove_mctl_mutex(struct hisi_fb_data_type *hisifd, int mctl_idx, + uint32_t cmdlist_idxs) +{ + dss_module_reg_t *dss_module = NULL; + int i = 0; + char __iomem *chn_mutex_base = NULL; + char __iomem *cmdlist_base = NULL; + uint32_t offset = 0; + uint32_t cmdlist_idxs_temp = 0; + + BUG_ON(hisifd == NULL); + + dss_module = &(hisifd->dss_module); + cmdlist_base = hisifd->dss_base + DSS_CMDLIST_OFFSET; + + for (i = 0; i < DSS_CHN_MAX_DEFINE; i++) { + if (dss_module->mctl_ch_used[i] == 1) { + chn_mutex_base = + dss_module->mctl_ch_base[i].chn_mutex_base + + g_dss_module_ovl_base[mctl_idx][MODULE_MCTL_BASE]; + BUG_ON(chn_mutex_base == NULL); + + set_reg(chn_mutex_base, 0, 32, 0); + } + } + + set_reg(dss_module->mctl_base[mctl_idx] + MCTL_CTL_MUTEX_OV, 0, 32, 0); + + offset = 0x40; + cmdlist_idxs_temp = cmdlist_idxs; + + for (i = 0; i < HISI_DSS_CMDLIST_MAX; i++) { + if ((cmdlist_idxs_temp & 0x1) == 0x1) { + set_reg(cmdlist_base + CMDLIST_CH0_CTRL + i * offset, + 0x6, 3, 2); + } + cmdlist_idxs_temp = cmdlist_idxs_temp >> 1; + } + +} + +void +hisi_dss_mctl_ov_set_ctl_dbg_reg(struct hisi_fb_data_type *hisifd, + char __iomem *mctl_base, bool enable_cmdlist) +{ + if (hisifd == NULL) { + HISI_FB_ERR("hisifd is null"); + return; + } + + if (enable_cmdlist) { + set_reg(mctl_base + MCTL_CTL_DBG, 0xB03A20, 32, 0); + set_reg(mctl_base + MCTL_CTL_TOP, 0x1, 32, 0); + } else { + set_reg(mctl_base + MCTL_CTL_DBG, 0xB13A00, 32, 0); + if (hisifd->index == PRIMARY_PANEL_IDX) { + set_reg(mctl_base + MCTL_CTL_TOP, 0x2, 32, 0); + } else if (hisifd->index == EXTERNAL_PANEL_IDX) { + set_reg(mctl_base + MCTL_CTL_TOP, 0x3, 32, 0); + } else { + ; + } + } +} + +int +hisi_dss_check_userdata(struct hisi_fb_data_type *hisifd, + dss_overlay_t *pov_req, + dss_overlay_block_t *pov_h_block_infos) +{ + int i = 0; + dss_wb_layer_t *wb_layer = NULL; + + if (hisifd == NULL) { + HISI_FB_ERR("invalid hisifd!"); + return -EINVAL; + } + + if (pov_req == NULL) { + HISI_FB_ERR("fb%d, invalid pov_req!", hisifd->index); + return -EINVAL; + } + + if (pov_h_block_infos == NULL) { + HISI_FB_ERR("fb%d, invalid pov_h_block_infos!", hisifd->index); + return -EINVAL; + } + + if ((pov_req->ov_block_nums <= 0) || + (pov_req->ov_block_nums > HISI_DSS_OV_BLOCK_NUMS)) { + HISI_FB_ERR("fb%d, invalid ov_block_nums=%d!", + hisifd->index, pov_req->ov_block_nums); + return -EINVAL; + } + + if ((pov_h_block_infos->layer_nums <= 0) + || (pov_h_block_infos->layer_nums > MAX_DSS_SRC_NUM)) { + HISI_FB_ERR("fb%d, invalid layer_nums=%d!", + hisifd->index, pov_h_block_infos->layer_nums); + return -EINVAL; + } + + if ((pov_req->ovl_idx < 0) || pov_req->ovl_idx >= DSS_OVL_IDX_MAX) { + HISI_FB_ERR("fb%d, invalid ovl_idx=%d!", + hisifd->index, pov_req->ovl_idx); + return -EINVAL; + } + + if (hisifd->index == PRIMARY_PANEL_IDX) { + if (hisifd->panel_info.dirty_region_updt_support) { + if (pov_req->dirty_rect.x < 0 + || pov_req->dirty_rect.y < 0 + || pov_req->dirty_rect.w < 0 + || pov_req->dirty_rect.h < 0) { + HISI_FB_ERR + ("dirty_rect(%d, %d, %d, %d) is out of range!\n", + pov_req->dirty_rect.x, + pov_req->dirty_rect.y, + pov_req->dirty_rect.w, + pov_req->dirty_rect.h); + return -EINVAL; + } + } + } + + if (hisifd->index == AUXILIARY_PANEL_IDX) { + if (pov_req->wb_enable != 1) { + HISI_FB_ERR("pov_req->wb_enable=%u is invalid!\n", + pov_req->wb_enable); + return -EINVAL; + } + + if ((pov_req->wb_layer_nums <= 0) || + (pov_req->wb_layer_nums > MAX_DSS_DST_NUM)) { + HISI_FB_ERR("fb%d, invalid wb_layer_nums=%d!", + hisifd->index, pov_req->wb_layer_nums); + return -EINVAL; + } + + if (pov_req->wb_ov_rect.x < 0 || pov_req->wb_ov_rect.y < 0) { + HISI_FB_ERR("wb_ov_rect(%d, %d) is out of range!\n", + pov_req->wb_ov_rect.x, + pov_req->wb_ov_rect.y); + return -EINVAL; + } + + if (pov_req->wb_compose_type >= DSS_WB_COMPOSE_TYPE_MAX) { + HISI_FB_ERR("wb_compose_type=%u is invalid!\n", + pov_req->wb_compose_type); + return -EINVAL; + } + + for (i = 0; i < pov_req->wb_layer_nums; i++) { + wb_layer = &(pov_req->wb_layer_infos[i]); + + if (wb_layer->chn_idx != DSS_WCHN_W2) { + if (wb_layer->chn_idx < DSS_WCHN_W0 + || wb_layer->chn_idx > DSS_WCHN_W1) { + HISI_FB_ERR + ("fb%d, wchn_idx=%d is invalid!", + hisifd->index, wb_layer->chn_idx); + return -EINVAL; + } + } + + if (wb_layer->dst.format >= HISI_FB_PIXEL_FORMAT_MAX) { + HISI_FB_ERR("fb%d, format=%d is invalid!", + hisifd->index, + wb_layer->dst.format); + return -EINVAL; + } + + if ((wb_layer->dst.bpp == 0) + || (wb_layer->dst.width == 0) + || (wb_layer->dst.height == 0) + || (wb_layer->dst.stride == 0)) { + HISI_FB_ERR + ("fb%d, bpp=%d, width=%d, height=%d, stride=%d is invalid!", + hisifd->index, wb_layer->dst.bpp, + wb_layer->dst.width, wb_layer->dst.height, + wb_layer->dst.stride); + return -EINVAL; + } +#if 0 + if (wb_layer->dst.mmu_enable) { + if (wb_layer->dst.buf_size == 0) { + HISI_FB_ERR + ("fb%d, buf_size=%d is invalid!", + hisifd->index, + wb_layer->dst.buf_size); + return -EINVAL; + } + } + + if (isYUVSemiPlanar(wb_layer->dst.format) + || isYUVPlanar(wb_layer->dst.format)) { + if ((wb_layer->dst.stride_plane1 == 0) + || (wb_layer->dst.offset_plane1 == 0)) { + HISI_FB_ERR + ("fb%d, stride_plane1=%d, offset_plane1=%d is invalid!", + hisifd->index, + wb_layer->dst.stride_plane1, + wb_layer->dst.offset_plane1); + return -EINVAL; + } + } + + if (isYUVPlanar(wb_layer->dst.format)) { + if ((wb_layer->dst.stride_plane2 == 0) + || (wb_layer->dst.offset_plane2 == 0)) { + HISI_FB_ERR + ("fb%d, stride_plane2=%d, offset_plane2=%d is invalid!", + hisifd->index, + wb_layer->dst.stride_plane2, + wb_layer->dst.offset_plane2); + return -EINVAL; + } + } +#endif + + if (wb_layer->need_cap & CAP_AFBCE) { + if ((wb_layer->dst.afbc_header_stride == 0) + || (wb_layer->dst.afbc_payload_stride == 0)) { + HISI_FB_ERR + ("fb%d, afbc_header_stride=%d, afbc_payload_stride=%d is invalid!", + hisifd->index, + wb_layer->dst.afbc_header_stride, + wb_layer->dst.afbc_payload_stride); + return -EINVAL; + } + } + + if (wb_layer->dst.csc_mode >= DSS_CSC_MOD_MAX) { + HISI_FB_ERR("fb%d, csc_mode=%d is invalid!", + hisifd->index, + wb_layer->dst.csc_mode); + return -EINVAL; + } + + if (wb_layer->dst.afbc_scramble_mode >= + DSS_AFBC_SCRAMBLE_MODE_MAX) { + HISI_FB_ERR + ("fb%d, afbc_scramble_mode=%d is invalid!", + hisifd->index, + wb_layer->dst.afbc_scramble_mode); + return -EINVAL; + } + + if (wb_layer->src_rect.x < 0 || wb_layer->src_rect.y < 0 + || wb_layer->src_rect.w <= 0 + || wb_layer->src_rect.h <= 0) { + HISI_FB_ERR + ("src_rect(%d, %d, %d, %d) is out of range!\n", + wb_layer->src_rect.x, wb_layer->src_rect.y, + wb_layer->src_rect.w, + wb_layer->src_rect.h); + return -EINVAL; + } + + if (wb_layer->dst_rect.x < 0 || wb_layer->dst_rect.y < 0 + || wb_layer->dst_rect.w <= 0 + || wb_layer->dst_rect.h <= 0) { + HISI_FB_ERR + ("dst_rect(%d, %d, %d, %d) is out of range!\n", + wb_layer->dst_rect.x, wb_layer->dst_rect.y, + wb_layer->dst_rect.w, + wb_layer->dst_rect.h); + return -EINVAL; + } + } + } else { + ; + } + + return 0; +} + +int +hisi_dss_check_layer_par(struct hisi_fb_data_type *hisifd, dss_layer_t *layer) +{ + if (hisifd == NULL) { + HISI_FB_ERR("hisifd is NULL, return!"); + return -EINVAL; + } + + if (layer == NULL) { + HISI_FB_ERR("layer is NULL, return!"); + return -EINVAL; + } + + if (layer->layer_idx < 0 || layer->layer_idx >= MAX_DSS_SRC_NUM) { + HISI_FB_ERR("fb%d, layer_idx=%d is invalid!", hisifd->index, + layer->layer_idx); + return -EINVAL; + } + + if (layer->need_cap & (CAP_BASE | CAP_DIM | CAP_PURE_COLOR)) + return 0; + + if (hisifd->index == AUXILIARY_PANEL_IDX) { + if (layer->chn_idx != DSS_RCHN_V2) { + if (layer->chn_idx < 0 || layer->chn_idx >= DSS_WCHN_W0) { + HISI_FB_ERR("fb%d, rchn_idx=%d is invalid!", + hisifd->index, layer->chn_idx); + return -EINVAL; + } + } + + if (layer->chn_idx == DSS_RCHN_D2) { + HISI_FB_ERR + ("fb%d, chn_idx[%d] does not used by offline play!", + hisifd->index, layer->chn_idx); + return -EINVAL; + } + } else { + if (layer->chn_idx < 0 || layer->chn_idx >= DSS_WCHN_W0) { + HISI_FB_ERR("fb%d, rchn_idx=%d is invalid!", + hisifd->index, layer->chn_idx); + return -EINVAL; + } + } + + if (layer->blending < 0 || layer->blending >= HISI_FB_BLENDING_MAX) { + HISI_FB_ERR("fb%d, blending=%d is invalid!", hisifd->index, + layer->blending); + return -EINVAL; + } + + if (layer->img.format >= HISI_FB_PIXEL_FORMAT_MAX) { + HISI_FB_ERR("fb%d, format=%d is invalid!", hisifd->index, + layer->img.format); + return -EINVAL; + } + + if ((layer->img.bpp == 0) || (layer->img.width == 0) + || (layer->img.height == 0) || (layer->img.stride == 0)) { + HISI_FB_ERR + ("fb%d, bpp=%d, width=%d, height=%d, stride=%d is invalid!", + hisifd->index, layer->img.bpp, layer->img.width, + layer->img.height, layer->img.stride); + return -EINVAL; + } +#if 0 + if (layer->img.mmu_enable) { + if (layer->img.buf_size == 0) { + HISI_FB_ERR("fb%d, buf_size=%d is invalid!", + hisifd->index, layer->img.buf_size); + return -EINVAL; + } + } + + if (isYUVSemiPlanar(layer->img.format) + || isYUVPlanar(layer->img.format)) { + if ((layer->img.stride_plane1 == 0) + || (layer->img.offset_plane1 == 0)) { + HISI_FB_ERR + ("fb%d, stride_plane1=%d, offset_plane1=%d is invalid!", + hisifd->index, layer->img.stride_plane1, + layer->img.offset_plane1); + return -EINVAL; + } + } + + if (isYUVPlanar(layer->img.format)) { + if ((layer->img.stride_plane2 == 0) + || (layer->img.offset_plane2 == 0)) { + HISI_FB_ERR + ("fb%d, stride_plane2=%d, offset_plane2=%d is invalid!", + hisifd->index, layer->img.stride_plane2, + layer->img.offset_plane2); + return -EINVAL; + } + } +#endif + + if (layer->need_cap & CAP_AFBCD) { + if ((layer->img.afbc_header_stride == 0) + || (layer->img.afbc_payload_stride == 0) + || (layer->img.mmbuf_size == 0)) { + HISI_FB_ERR + ("fb%d, afbc_header_stride=%d, afbc_payload_stride=%d, " + "mmbuf_size=%d is invalid!", + hisifd->index, layer->img.afbc_header_stride, + layer->img.afbc_payload_stride, + layer->img.mmbuf_size); + return -EINVAL; + } + } + + if (layer->img.csc_mode >= DSS_CSC_MOD_MAX) { + HISI_FB_ERR("fb%d, csc_mode=%d is invalid!", hisifd->index, + layer->img.csc_mode); + return -EINVAL; + } + + if (layer->img.afbc_scramble_mode >= DSS_AFBC_SCRAMBLE_MODE_MAX) { + HISI_FB_ERR("fb%d, afbc_scramble_mode=%d is invalid!", + hisifd->index, layer->img.afbc_scramble_mode); + return -EINVAL; + } + + if ((layer->layer_idx != 0) && (layer->need_cap & CAP_BASE)) { + HISI_FB_ERR("fb%d, layer%d is not base!", hisifd->index, + layer->layer_idx); + return -EINVAL; + } + + if (layer->src_rect.x < 0 || layer->src_rect.y < 0 || + layer->src_rect.w <= 0 || layer->src_rect.h <= 0) { + HISI_FB_ERR("src_rect(%d, %d, %d, %d) is out of range!\n", + layer->src_rect.x, layer->src_rect.y, + layer->src_rect.w, layer->src_rect.h); + return -EINVAL; + } + + if (layer->src_rect_mask.x < 0 || layer->src_rect_mask.y < 0 || + layer->src_rect_mask.w < 0 || layer->src_rect_mask.h < 0) { + HISI_FB_ERR("src_rect_mask(%d, %d, %d, %d) is out of range!\n", + layer->src_rect_mask.x, layer->src_rect_mask.y, + layer->src_rect_mask.w, layer->src_rect_mask.h); + return -EINVAL; + } + + if (layer->dst_rect.x < 0 || layer->dst_rect.y < 0 || + layer->dst_rect.w <= 0 || layer->dst_rect.h <= 0) { + HISI_FB_ERR("dst_rect(%d, %d, %d, %d) is out of range!\n", + layer->dst_rect.x, layer->dst_rect.y, + layer->dst_rect.w, layer->dst_rect.h); + return -EINVAL; + } + + return 0; +} + +void hisifb_disreset_dss(struct hisi_fb_data_type *hisifd) +{ +} diff --git a/drivers/video/fbdev/hisi/dss/hisi_overlay_utils_hi3660.h b/drivers/video/fbdev/hisi/dss/hisi_overlay_utils_hi3660.h new file mode 100755 index 000000000000..1d5b1fc0cc92 --- /dev/null +++ b/drivers/video/fbdev/hisi/dss/hisi_overlay_utils_hi3660.h @@ -0,0 +1,73 @@ +/* Copyright (c) 2013-2014, Hisilicon Tech. Co., Ltd. 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 + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ +#ifndef _HISI_OVERLAY_UTILS_PLATFORM_H_ +#define _HISI_OVERLAY_UTILS_PLATFORM_H_ + +#define HISI_DSS_VERSION_V400 + +#define GPIO_LCD_POWER_1V2 (54) +#define GPIO_LCD_STANDBY (67) +#define GPIO_LCD_RESETN (65) +#define GPIO_LCD_GATING (60) +#define GPIO_LCD_PCLK_GATING (58) +#define GPIO_LCD_REFCLK_GATING (59) +#define GPIO_LCD_SPICS (168) +#define GPIO_LCD_DRV_EN (73) + +#define GPIO_PG_SEL_A (72) +#define GPIO_TX_RX_A (74) +#define GPIO_PG_SEL_B (76) +#define GPIO_TX_RX_B (78) + +/******************************************************************************* + ** + */ +#define CRGPERI_PLL0_CLK_RATE (1600000000UL) +#define CRGPERI_PLL2_CLK_RATE (960000000UL) +#define CRGPERI_PLL3_CLK_RATE (1600000000UL) + +#define DEFAULT_DSS_CORE_CLK_08V_RATE (535000000UL) +#define DEFAULT_DSS_CORE_CLK_07V_RATE (400000000UL) +#define DEFAULT_PCLK_DSS_RATE (114000000UL) +#define DEFAULT_PCLK_PCTRL_RATE (80000000UL) +#define DSS_MAX_PXL0_CLK_288M (288000000UL) + +#define MMBUF_SIZE_MAX (288 * 1024) +#define HISI_DSS_CMDLIST_MAX (16) +#define HISI_DSS_CMDLIST_IDXS_MAX (0xFFFF) +#define HISI_DSS_COPYBIT_CMDLIST_IDXS (0xC000) +#define HISI_DSS_DPP_MAX_SUPPORT_BIT (0x7ff) +#define HISIFB_DSS_PLATFORM_TYPE (FB_ACCEL_HI366x | FB_ACCEL_PLATFORM_TYPE_ASIC) + +#define DSS_MIF_SMMU_SMRX_IDX_STEP (16) +#define CRG_PERI_DIS3_DEFAULT_VAL (0x0002F000) +#define SCF_LINE_BUF (2560) +#define DSS_GLB_MODULE_CLK_SEL_DEFAULT_VAL (0xF0000008) +#define DSS_LDI_CLK_SEL_DEFAULT_VAL (0x00000004) +#define DSS_DBUF_MEM_CTRL_DEFAULT_VAL (0x00000008) +#define DSS_SMMU_RLD_EN0_DEFAULT_VAL (0xffffffff) +#define DSS_SMMU_RLD_EN1_DEFAULT_VAL (0xffffff8f) +#define DSS_SMMU_OUTSTANDING_VAL (0xf) +#define DSS_MIF_CTRL2_INVAL_SEL3_STRIDE_MASK (0xc) +#define DSS_AFBCE_ENC_OS_CFG_DEFAULT_VAL (0x7) +#define TUI_SEC_RCH (DSS_RCHN_V0) +#define DSS_CHN_MAX_DEFINE (DSS_COPYBIT_MAX) + +/* perf stat */ +#define DSS_DEVMEM_PERF_BASE (0xFDF10000) +#define CRG_PERIPH_APB_PERRSTSTAT0_REG (0x68) +#define CRG_PERIPH_APB_IP_RST_PERF_STAT_BIT (18) +#define PERF_SAMPSTOP_REG (0x10) +#define DEVMEM_PERF_SIZE (0x100) + +#endif -- 2.12.0-rc0