| /* |
| * drivers/amlogic/media/vin/tvin/vdin/vdin_canvas.c |
| * |
| * Copyright (C) 2017 Amlogic, Inc. 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 as published by |
| * the Free Software Foundation; either version 2 of the License, or |
| * (at your option) any later version. |
| * |
| * 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. |
| * |
| */ |
| |
| /* Standard Linux headers */ |
| #include <linux/mm.h> |
| #include <linux/module.h> |
| #include <linux/platform_device.h> |
| #include <linux/cma.h> |
| #include <linux/amlogic/media/codec_mm/codec_mm.h> |
| #include <linux/dma-contiguous.h> |
| #include <linux/delay.h> |
| |
| /* Amlogic headers */ |
| #include <linux/amlogic/media/vfm/vframe.h> |
| #ifdef CONFIG_AMLOGIC_TEE |
| #include <linux/amlogic/tee.h> |
| #endif |
| |
| /* Local headers */ |
| #include "../tvin_format_table.h" |
| #include "vdin_drv.h" |
| #include "vdin_canvas.h" |
| #include "vdin_ctl.h" |
| /*the value depending on dts config mem limit |
| *for skip two vframe case,need +2 |
| */ |
| static unsigned int max_buf_num = VDIN_CANVAS_MAX_CNT; |
| static unsigned int min_buf_num = 4; |
| static unsigned int max_buf_width = VDIN_CANVAS_MAX_WIDTH_HD; |
| static unsigned int max_buf_height = VDIN_CANVAS_MAX_HEIGH; |
| /* one frame max metadata size:32x280 bits = 1120bytes(0x460) */ |
| unsigned int dolby_size_byte = PAGE_SIZE; |
| |
| #ifdef DEBUG_SUPPORT |
| module_param(max_buf_num, uint, 0664); |
| MODULE_PARM_DESC(max_buf_num, "vdin max buf num.\n"); |
| |
| module_param(min_buf_num, uint, 0664); |
| MODULE_PARM_DESC(min_buf_num, "vdin min buf num.\n"); |
| |
| module_param(max_buf_width, uint, 0664); |
| MODULE_PARM_DESC(max_buf_width, "vdin max buf width.\n"); |
| |
| module_param(max_buf_height, uint, 0664); |
| MODULE_PARM_DESC(max_buf_height, "vdin max buf height.\n"); |
| |
| module_param(dolby_size_byte, uint, 0664); |
| MODULE_PARM_DESC(dolby_size_byte, "dolby_size_byte.\n"); |
| #endif |
| |
| const unsigned int vdin_canvas_ids[2][VDIN_CANVAS_MAX_CNT] = { |
| { |
| 0x26, 0x27, 0x28, 0x29, 0x2a, |
| 0x2b, 0x2c, 0x2d, 0x2e, 0x2f |
| }, |
| { |
| 0x30, 0x31, 0x32, 0x33, 0x34, |
| 0x35, 0x36, 0x37, 0x38, 0x39 |
| }, |
| }; |
| |
| /*function: |
| * 1.set canvas_max_w & canvas_max_h |
| * 2.set canvas_max_size & canvas_max_num |
| * 3.set canvas_id & canvas_addr |
| */ |
| void vdin_canvas_init(struct vdin_dev_s *devp) |
| { |
| int i, canvas_id; |
| unsigned int canvas_addr; |
| int canvas_max_w = 0; |
| int canvas_max_h = VDIN_CANVAS_MAX_HEIGH; |
| |
| canvas_max_w = VDIN_CANVAS_MAX_WIDTH_HD << 1; |
| |
| devp->canvas_max_size = PAGE_ALIGN(canvas_max_w*canvas_max_h); |
| devp->canvas_max_num = devp->mem_size / devp->canvas_max_size; |
| |
| if (devp->canvas_max_num > VDIN_CANVAS_MAX_CNT) |
| devp->canvas_max_num = VDIN_CANVAS_MAX_CNT; |
| |
| devp->mem_start = roundup(devp->mem_start, devp->canvas_align); |
| pr_info("vdin.%d canvas initial table:\n", devp->index); |
| for (i = 0; i < devp->canvas_max_num; i++) { |
| canvas_id = vdin_canvas_ids[devp->index][i]; |
| canvas_addr = devp->mem_start + devp->canvas_max_size * i; |
| |
| canvas_config(canvas_id, canvas_addr, |
| canvas_max_w, canvas_max_h, |
| CANVAS_ADDR_NOWRAP, CANVAS_BLKMODE_LINEAR); |
| pr_info("\t%d: 0x%x-0x%x %dx%d (%d KB)\n", |
| canvas_id, canvas_addr, |
| (canvas_addr + devp->canvas_max_size), |
| canvas_max_w, canvas_max_h, |
| (devp->canvas_max_size >> 10)); |
| } |
| } |
| |
| /*function:canvas_config when canvas_config_mode=1 |
| * 1.set canvas_w and canvas_h |
| * 2.set canvas_max_size and canvas_max_num |
| * 3.when dest_cfmt is TVIN_NV12/TVIN_NV21, |
| * buf width add canvas_w*canvas_h |
| *based on parameters: |
| * format_convert/ source_bitdepth/ |
| * v_active color_depth_mode/ prop.dest_cfmt |
| */ |
| void vdin_canvas_start_config(struct vdin_dev_s *devp) |
| { |
| int i = 0; |
| int canvas_id; |
| unsigned long canvas_addr; |
| unsigned int chroma_size = 0; |
| unsigned int canvas_step = 1; |
| unsigned int canvas_num = VDIN_CANVAS_MAX_CNT; |
| unsigned int max_buffer_num = max_buf_num; |
| |
| switch (devp->format_convert) { |
| case VDIN_FORMAT_CONVERT_YUV_YUV444: |
| case VDIN_FORMAT_CONVERT_YUV_RGB: |
| case VDIN_FORMAT_CONVERT_RGB_YUV444: |
| case VDIN_FORMAT_CONVERT_RGB_RGB: |
| case VDIN_FORMAT_CONVERT_YUV_GBR: |
| case VDIN_FORMAT_CONVERT_YUV_BRG: |
| if (devp->source_bitdepth > VDIN_MIN_SOURCE_BITDEPTH) |
| devp->canvas_w = max_buf_width * |
| VDIN_YUV444_10BIT_PER_PIXEL_BYTE; |
| else |
| devp->canvas_w = max_buf_height * |
| VDIN_YUV444_8BIT_PER_PIXEL_BYTE; |
| break; |
| case VDIN_FORMAT_CONVERT_YUV_NV12: |
| case VDIN_FORMAT_CONVERT_YUV_NV21: |
| case VDIN_FORMAT_CONVERT_RGB_NV12: |
| case VDIN_FORMAT_CONVERT_RGB_NV21: |
| devp->canvas_w = max_buf_width; |
| canvas_num = canvas_num / 2; |
| canvas_step = 2; |
| break; |
| case VDIN_FORMAT_CONVERT_YUV_YUV422: |
| case VDIN_FORMAT_CONVERT_RGB_YUV422: |
| case VDIN_FORMAT_CONVERT_GBR_YUV422: |
| case VDIN_FORMAT_CONVERT_BRG_YUV422: |
| if ((devp->source_bitdepth > VDIN_MIN_SOURCE_BITDEPTH) && |
| (devp->full_pack == VDIN_422_FULL_PK_EN)) |
| devp->canvas_w = (max_buf_width * 5) / 2; |
| else if ((devp->source_bitdepth > VDIN_MIN_SOURCE_BITDEPTH) && |
| (devp->full_pack == VDIN_422_FULL_PK_DIS)) |
| devp->canvas_w = max_buf_width * |
| VDIN_YUV422_10BIT_PER_PIXEL_BYTE; |
| else |
| devp->canvas_w = max_buf_width * |
| VDIN_YUV422_8BIT_PER_PIXEL_BYTE; |
| break; |
| default: |
| break; |
| } |
| |
| /*backup before roundup*/ |
| devp->canvas_active_w = devp->canvas_w; |
| if (devp->force_yuv444_malloc == 1) { |
| /* 4k is not support 10 bit mode in order to save memory */ |
| if ((devp->source_bitdepth > VDIN_MIN_SOURCE_BITDEPTH) && |
| !vdin_is_4k(devp)) |
| devp->canvas_w = devp->h_active * |
| VDIN_YUV444_10BIT_PER_PIXEL_BYTE; |
| else |
| devp->canvas_w = devp->h_active * |
| VDIN_YUV444_8BIT_PER_PIXEL_BYTE; |
| } |
| /*canvas_w must ensure divided exact by 256bit(32byte)*/ |
| devp->canvas_w = roundup(devp->canvas_w, devp->canvas_align); |
| devp->canvas_h = devp->v_active; |
| |
| switch (devp->format_convert) { |
| case VDIN_FORMAT_CONVERT_YUV_NV12: |
| case VDIN_FORMAT_CONVERT_YUV_NV21: |
| case VDIN_FORMAT_CONVERT_RGB_NV12: |
| case VDIN_FORMAT_CONVERT_RGB_NV21: |
| chroma_size = devp->canvas_w * devp->canvas_h / 2; |
| break; |
| default: |
| break; |
| } |
| |
| devp->canvas_max_size = PAGE_ALIGN(devp->canvas_w* |
| devp->canvas_h+chroma_size); |
| devp->canvas_max_num = devp->mem_size / devp->canvas_max_size; |
| |
| devp->canvas_max_num = min(devp->canvas_max_num, canvas_num); |
| devp->canvas_max_num = min(devp->canvas_max_num, max_buffer_num); |
| |
| if ((devp->cma_config_en != 1) || !(devp->cma_config_flag & 0x100)) { |
| /*use_reserved_mem or alloc_from_contiguous*/ |
| devp->mem_start = roundup(devp->mem_start, devp->canvas_align); |
| #ifdef VDIN_DEBUG |
| pr_info("vdin%d cnavas start configuration table:\n", |
| devp->index); |
| #endif |
| for (i = 0; i < devp->canvas_max_num; i++) { |
| canvas_id = vdin_canvas_ids[devp->index][i*canvas_step]; |
| canvas_addr = devp->mem_start + |
| devp->canvas_max_size * i; |
| canvas_config(canvas_id, canvas_addr, |
| devp->canvas_w, devp->canvas_h, |
| CANVAS_ADDR_NOWRAP, CANVAS_BLKMODE_LINEAR); |
| if (chroma_size) |
| canvas_config(canvas_id+1, |
| canvas_addr + |
| devp->canvas_w*devp->canvas_h, |
| devp->canvas_w, |
| devp->canvas_h/2, |
| CANVAS_ADDR_NOWRAP, |
| CANVAS_BLKMODE_LINEAR); |
| #ifdef VDIN_DEBUG |
| pr_info("\t%3d: 0x%lx-0x%lx %ux%u\n", |
| canvas_id, canvas_addr, |
| canvas_addr + devp->canvas_max_size, |
| devp->canvas_w, devp->canvas_h); |
| #endif |
| } |
| } else if (devp->cma_config_flag & 0x100) { |
| #ifdef VDIN_DEBUG |
| pr_info("vdin%d cnavas start configuration table:\n", |
| devp->index); |
| #endif |
| for (i = 0; i < devp->canvas_max_num; i++) { |
| devp->vfmem_start[i] = |
| roundup(devp->vfmem_start[i], |
| devp->canvas_align); |
| canvas_id = vdin_canvas_ids[devp->index][i*canvas_step]; |
| canvas_addr = devp->vfmem_start[i]; |
| canvas_config(canvas_id, canvas_addr, |
| devp->canvas_w, devp->canvas_h, |
| CANVAS_ADDR_NOWRAP, CANVAS_BLKMODE_LINEAR); |
| if (chroma_size) |
| canvas_config(canvas_id+1, |
| canvas_addr + |
| devp->canvas_w*devp->canvas_h, |
| devp->canvas_w, |
| devp->canvas_h/2, |
| CANVAS_ADDR_NOWRAP, |
| CANVAS_BLKMODE_LINEAR); |
| #ifdef VDIN_DEBUG |
| pr_info("\t%3d: 0x%lx-0x%lx %ux%u\n", |
| canvas_id, canvas_addr, |
| canvas_addr + devp->canvas_max_size, |
| devp->canvas_w, devp->canvas_h); |
| #endif |
| } |
| } |
| } |
| |
| /* |
| *this function used for configure canvas when canvas_config_mode=2 |
| *base on the input format |
| *also used for input resalution over 1080p such as camera input 200M,500M |
| *YUV422-8BIT:1pixel = 2byte; |
| *YUV422-10BIT:1pixel = 3byte; |
| *YUV422-10BIT-FULLPACK:1pixel = 2.5byte; |
| *YUV444-8BIT:1pixel = 3byte; |
| *YUV444-10BIT:1pixel = 4byte |
| */ |
| void vdin_canvas_auto_config(struct vdin_dev_s *devp) |
| { |
| int i = 0; |
| int canvas_id; |
| unsigned long canvas_addr; |
| unsigned int chroma_size = 0; |
| unsigned int canvas_step = 1; |
| unsigned int canvas_num = VDIN_CANVAS_MAX_CNT; |
| unsigned int max_buffer_num = max_buf_num; |
| unsigned int h_active, v_active; |
| |
| if (devp->vfmem_size_small) { |
| h_active = devp->h_shrink_out; |
| v_active = devp->v_shrink_out; |
| } else { |
| h_active = devp->h_active; |
| v_active = devp->v_active; |
| } |
| |
| switch (devp->format_convert) { |
| case VDIN_FORMAT_CONVERT_YUV_YUV444: |
| case VDIN_FORMAT_CONVERT_YUV_RGB: |
| case VDIN_FORMAT_CONVERT_RGB_YUV444: |
| case VDIN_FORMAT_CONVERT_RGB_RGB: |
| case VDIN_FORMAT_CONVERT_YUV_GBR: |
| case VDIN_FORMAT_CONVERT_YUV_BRG: |
| if (devp->source_bitdepth > VDIN_MIN_SOURCE_BITDEPTH) |
| devp->canvas_w = h_active * |
| VDIN_YUV444_10BIT_PER_PIXEL_BYTE; |
| else |
| devp->canvas_w = h_active * |
| VDIN_YUV444_8BIT_PER_PIXEL_BYTE; |
| break; |
| case VDIN_FORMAT_CONVERT_YUV_NV12: |
| case VDIN_FORMAT_CONVERT_YUV_NV21: |
| case VDIN_FORMAT_CONVERT_RGB_NV12: |
| case VDIN_FORMAT_CONVERT_RGB_NV21: |
| canvas_num = canvas_num / 2; |
| canvas_step = 2; |
| devp->canvas_w = h_active; |
| break; |
| case VDIN_FORMAT_CONVERT_YUV_YUV422: |
| case VDIN_FORMAT_CONVERT_RGB_YUV422: |
| case VDIN_FORMAT_CONVERT_GBR_YUV422: |
| case VDIN_FORMAT_CONVERT_BRG_YUV422: |
| if (devp->source_bitdepth > VDIN_MIN_SOURCE_BITDEPTH) { |
| if (devp->full_pack == VDIN_422_FULL_PK_EN) |
| devp->canvas_w = (h_active * 5) / 2; |
| else if (devp->full_pack == VDIN_422_FULL_PK_DIS) |
| devp->canvas_w = h_active * |
| VDIN_YUV422_10BIT_PER_PIXEL_BYTE; |
| } else { |
| devp->canvas_w = h_active * |
| VDIN_YUV422_8BIT_PER_PIXEL_BYTE; |
| } |
| |
| /* dw only support 8bit mode */ |
| if (devp->double_wr) |
| devp->canvas_w = h_active * |
| VDIN_YUV422_8BIT_PER_PIXEL_BYTE; |
| |
| break; |
| default: |
| break; |
| } |
| |
| /*backup before roundup*/ |
| devp->canvas_active_w = devp->canvas_w; |
| |
| /* dw only supprt 8 bit mode */ |
| if ((devp->force_yuv444_malloc == 1) && !devp->double_wr) { |
| /* 4k is not support 10 bit mode in order to save memory */ |
| if ((devp->source_bitdepth > VDIN_MIN_SOURCE_BITDEPTH) && |
| !vdin_is_4k(devp)) |
| devp->canvas_w = h_active * |
| VDIN_YUV444_10BIT_PER_PIXEL_BYTE; |
| else |
| devp->canvas_w = h_active * |
| VDIN_YUV444_8BIT_PER_PIXEL_BYTE; |
| } |
| /*canvas_w must ensure divided exact by 256bit(32byte)*/ |
| devp->canvas_w = roundup(devp->canvas_w, devp->canvas_align); |
| devp->canvas_h = v_active; |
| |
| switch (devp->format_convert) { |
| case VDIN_FORMAT_CONVERT_YUV_NV12: |
| case VDIN_FORMAT_CONVERT_YUV_NV21: |
| case VDIN_FORMAT_CONVERT_RGB_NV12: |
| case VDIN_FORMAT_CONVERT_RGB_NV21: |
| chroma_size = devp->canvas_w * devp->canvas_h / 2; |
| break; |
| default: |
| break; |
| } |
| |
| devp->canvas_max_size = PAGE_ALIGN(devp->canvas_w* |
| devp->canvas_h+chroma_size); |
| /* |
| * devp->canvas_max_num = |
| * devp->mem_size / devp->canvas_max_size; |
| */ |
| |
| devp->canvas_max_num = min(devp->canvas_max_num, canvas_num); |
| devp->canvas_max_num = min(devp->canvas_max_num, max_buffer_num); |
| if (devp->canvas_max_num < devp->vfmem_max_cnt) { |
| pr_err("\nvdin%d canvas_max_num %d less than vfmem_max_cnt %d\n", |
| devp->index, devp->canvas_max_num, devp->vfmem_max_cnt); |
| } |
| devp->vfmem_max_cnt = min(devp->vfmem_max_cnt, devp->canvas_max_num); |
| |
| if (devp->set_canvas_manual == 1) { |
| for (i = 0; i < VDIN_CANVAS_MAX_CNT; i++) { |
| if (vdin_set_canvas_addr[i].dmabuff == 0) |
| break; |
| |
| canvas_id = |
| vdin_canvas_ids[devp->index][i * canvas_step]; |
| canvas_addr = vdin_set_canvas_addr[i].paddr; |
| canvas_config(canvas_id, canvas_addr, |
| devp->canvas_w, devp->canvas_h, |
| CANVAS_ADDR_NOWRAP, CANVAS_BLKMODE_LINEAR); |
| pr_info("canvas index=%d- %3d: 0x%lx-0x%lx %ux%u\n", |
| i, canvas_id, canvas_addr, |
| canvas_addr + devp->canvas_max_size, |
| devp->canvas_w, devp->canvas_h); |
| } |
| return; |
| } |
| |
| #ifdef VDIN_DEBUG |
| pr_info("vdin%d cnavas auto configuration table:\n", |
| devp->index); |
| #endif |
| for (i = 0; i < devp->canvas_max_num; i++) { |
| devp->vfmem_start[i] = |
| roundup(devp->vfmem_start[i], |
| devp->canvas_align); |
| canvas_id = vdin_canvas_ids[devp->index][i * canvas_step]; |
| canvas_addr = devp->vfmem_start[i]; |
| canvas_config(canvas_id, canvas_addr, |
| devp->canvas_w, devp->canvas_h, |
| CANVAS_ADDR_NOWRAP, CANVAS_BLKMODE_LINEAR); |
| if (chroma_size) |
| canvas_config(canvas_id + 1, |
| canvas_addr + |
| devp->canvas_w * devp->canvas_h, |
| devp->canvas_w, |
| devp->canvas_h / 2, |
| CANVAS_ADDR_NOWRAP, |
| CANVAS_BLKMODE_LINEAR); |
| #ifdef VDIN_DEBUG |
| pr_info("\t%3d: 0x%lx-0x%lx %ux%u\n", |
| canvas_id, canvas_addr, |
| canvas_addr + devp->canvas_max_size, |
| devp->canvas_w, devp->canvas_h); |
| #endif |
| } |
| } |
| |
| #ifdef CONFIG_CMA |
| /* need to be static for pointer use in codec_mm */ |
| static char vdin_name[6]; |
| /* return val:1: fail;0: ok */ |
| /* combined canvas and afbce memory */ |
| unsigned int vdin_cma_alloc(struct vdin_dev_s *devp) |
| { |
| unsigned int mem_size, h_size, v_size, frame_size; |
| int flags = CODEC_MM_FLAGS_CMA_FIRST|CODEC_MM_FLAGS_CMA_CLEAR| |
| CODEC_MM_FLAGS_DMA; |
| unsigned int max_buffer_num = min_buf_num; |
| unsigned int i, j; |
| #ifdef CONFIG_AMLOGIC_TEE |
| unsigned int res = 0; |
| #endif |
| |
| if (devp->rdma_enable) |
| max_buffer_num++; |
| /*todo: need update if vf_skip_cnt used by other port*/ |
| if (devp->vfp->skip_vf_num && |
| (IS_HDMI_SRC(devp->parm.port) || IS_TVAFE_SRC(devp->parm.port))) |
| max_buffer_num += devp->vfp->skip_vf_num; |
| |
| if (max_buffer_num > max_buf_num) |
| max_buffer_num = max_buf_num; |
| |
| /* if vfmem_cfg_num define in dts, use dts's setting */ |
| if (devp->frame_buff_num >= min_buf_num && |
| devp->frame_buff_num <= max_buf_num) |
| max_buffer_num = devp->frame_buff_num; |
| |
| devp->canvas_max_num = max_buffer_num; |
| devp->vfmem_max_cnt = max_buffer_num; |
| if ((devp->cma_config_en == 0) || |
| (devp->cma_mem_alloc == 1)) { |
| pr_info("\nvdin%d %s use_reserved mem or cma already alloced (%d,%d)!!!\n", |
| devp->index, __func__, devp->cma_config_en, |
| devp->cma_mem_alloc); |
| return 0; |
| } |
| |
| /*pixels*/ |
| h_size = devp->h_active; |
| v_size = devp->v_active; |
| |
| if (devp->canvas_config_mode == 1) { |
| h_size = max_buf_width; |
| v_size = max_buf_height; |
| } |
| |
| if ((devp->format_convert == VDIN_FORMAT_CONVERT_YUV_YUV444) || |
| (devp->format_convert == VDIN_FORMAT_CONVERT_YUV_RGB) || |
| (devp->format_convert == VDIN_FORMAT_CONVERT_RGB_YUV444) || |
| (devp->format_convert == VDIN_FORMAT_CONVERT_RGB_RGB) || |
| (devp->format_convert == VDIN_FORMAT_CONVERT_YUV_GBR) || |
| (devp->format_convert == VDIN_FORMAT_CONVERT_YUV_BRG)) { |
| /* 4k is not support 10 bit mode in order to save memory |
| * up to 4k 444 8bit mode |
| */ |
| if (/*devp->source_bitdepth > VDIN_MIN_SOURCE_BITDEPTH &&*/ |
| !vdin_is_4k(devp)) { |
| h_size = roundup(h_size * |
| VDIN_YUV444_10BIT_PER_PIXEL_BYTE, |
| devp->canvas_align); |
| devp->canvas_alin_w = h_size / |
| VDIN_YUV444_10BIT_PER_PIXEL_BYTE; |
| } else { |
| h_size = roundup(h_size * |
| VDIN_YUV444_8BIT_PER_PIXEL_BYTE, |
| devp->canvas_align); |
| devp->canvas_alin_w = h_size / |
| VDIN_YUV444_8BIT_PER_PIXEL_BYTE; |
| } |
| } else if ((devp->format_convert == VDIN_FORMAT_CONVERT_YUV_NV12) || |
| (devp->format_convert == VDIN_FORMAT_CONVERT_YUV_NV21) || |
| (devp->format_convert == VDIN_FORMAT_CONVERT_RGB_NV12) || |
| (devp->format_convert == VDIN_FORMAT_CONVERT_RGB_NV21)) { |
| h_size = roundup(h_size, devp->canvas_align); |
| devp->canvas_alin_w = h_size; |
| /*todo change with canvas alloc!!*/ |
| /* nv21/nv12 only have 8bit mode */ |
| } else { |
| /* 422 mode, 4k upto 444 8bitmode, |
| * other up to 10 bit mode |
| */ |
| if (vdin_is_4k(devp)) { |
| /*up to 444 8bit*/ |
| h_size = roundup(h_size * |
| VDIN_YUV444_8BIT_PER_PIXEL_BYTE, |
| devp->canvas_align); |
| devp->canvas_alin_w = h_size / |
| VDIN_YUV444_8BIT_PER_PIXEL_BYTE; |
| } else { |
| /*up to 444 10bit*/ |
| h_size = roundup(h_size * |
| VDIN_YUV444_10BIT_PER_PIXEL_BYTE, |
| devp->canvas_align); |
| devp->canvas_alin_w = h_size / |
| VDIN_YUV444_10BIT_PER_PIXEL_BYTE; |
| } |
| } |
| |
| /*1 frame bytes*/ |
| mem_size = h_size * v_size; |
| /*for almost uncompressed pattern,garbage at bottom |
| *1024x1658 is the worst case,each page wast 2160x3x256byte for 4096 |
| *since every block must not be separated by 2 pages |
| *screen cap & v4l2 debug doesn't use afbce,no need inc mem |
| */ |
| if (!(devp->parm.reserved & PARAM_STATE_SCREENCAP) && |
| (!(devp->flags & VDIN_FLAG_V4L2_DEBUG))) |
| mem_size += 1024 * 1658; |
| |
| if ((devp->format_convert >= VDIN_FORMAT_CONVERT_YUV_NV12) && |
| (devp->format_convert <= VDIN_FORMAT_CONVERT_RGB_NV21)) |
| mem_size = (mem_size * 3)/2; |
| devp->vfmem_size = PAGE_ALIGN(mem_size) + dolby_size_byte; |
| devp->vfmem_size = roundup(devp->vfmem_size, PAGE_SIZE); |
| |
| if (devp->double_wr || K_FORCE_HV_SHRINK) { |
| if ((devp->h_shrink_out < devp->h_active) && |
| (devp->v_shrink_out < devp->v_active)) |
| devp->vfmem_size_small = devp->vfmem_size / |
| devp->h_shrink_times / devp->v_shrink_times; |
| else if (devp->h_shrink_out < devp->h_active) |
| devp->vfmem_size_small = |
| devp->vfmem_size / devp->h_shrink_times; |
| else if (devp->v_shrink_out < devp->v_active) |
| devp->vfmem_size_small = |
| devp->vfmem_size / devp->v_shrink_times; |
| else |
| devp->vfmem_size_small = 0; |
| } else { |
| devp->vfmem_size_small = 0; |
| } |
| |
| if (devp->vfmem_size_small) |
| devp->vfmem_size_small = |
| roundup(devp->vfmem_size_small, PAGE_SIZE); |
| |
| pr_info("%s vfmem_size_small:0x%x\n", __func__, devp->vfmem_size_small); |
| /* frame is consist of the following part |
| * 1st, small frame for dw |
| * 2nd, big frame for dw, or normal frame for non-dw |
| * 3rd, header if afbce enabled |
| * 4th, table if afbece enabled |
| * --------------------- |
| * | small frame | |
| * | | |
| * |-------------------| |
| * | | |
| * | normal frame | |
| * | | |
| * |-------------------| |
| * | header | |
| * |-------------------| |
| * | table | |
| * |-------------------| |
| */ |
| if (devp->afbce_info) { |
| if (devp->afbce_valid) { |
| /*allocate mem according to resolution |
| *each block contains 32 * 4 pixels |
| *one block associated to one header(4 bytes) |
| *dolby has one page size, & each vframe |
| * aligned to page size |
| *(((h(align 32 pixel) * v(align 4 pixel)) / |
| * (32 * 4)) * 4) + dolby |
| *total max_buffer_num |
| */ |
| devp->afbce_info->frame_head_size = |
| PAGE_ALIGN((roundup(devp->h_active, 32) * |
| roundup(devp->v_active, 4)) / 32 + |
| dolby_size_byte); |
| |
| /*((h * v * byte_per_pixel + dolby) / |
| * page_size) * 4(one address size) |
| * total max_buffer_num |
| */ |
| devp->afbce_info->frame_table_size = |
| PAGE_ALIGN((devp->vfmem_size * 4) / PAGE_SIZE); |
| } else { |
| devp->afbce_info->frame_head_size = 0; |
| devp->afbce_info->frame_table_size = 0; |
| } |
| |
| frame_size = devp->vfmem_size_small + devp->vfmem_size + |
| devp->afbce_info->frame_head_size + |
| devp->afbce_info->frame_table_size; |
| |
| } else { |
| frame_size = devp->vfmem_size_small + devp->vfmem_size; |
| } |
| |
| devp->frame_size = frame_size; |
| |
| /*total frames bytes*/ |
| mem_size = PAGE_ALIGN(frame_size) * max_buffer_num; |
| mem_size = roundup(mem_size, PAGE_SIZE); |
| |
| if (devp->set_canvas_manual == 1) { |
| for (i = 0; i < VDIN_CANVAS_MAX_CNT; i++) { |
| if (vdin_set_canvas_addr[i].dmabuff == 0) |
| break; |
| |
| vdin_set_canvas_addr[i].paddr = |
| roundup(vdin_set_canvas_addr[i].paddr, |
| devp->canvas_align); |
| } |
| |
| devp->canvas_max_num = max_buffer_num = i; |
| devp->vfmem_max_cnt = max_buffer_num; |
| } |
| |
| #ifdef CONFIG_AMLOGIC_TEE |
| /* must align to 64k for secure protection |
| * always align for switch secure mode dynamically |
| */ |
| mem_size = roundup(mem_size, 64 * 1024); |
| #endif |
| |
| if (mem_size > devp->cma_mem_size) { |
| pr_err("\nvdin%d cma_mem_size (%d, %d) is not enough!!!\n", |
| devp->index, mem_size, devp->cma_mem_size); |
| mem_size = devp->cma_mem_size; |
| devp->cma_mem_alloc = 0; |
| return 1; |
| } |
| |
| if (devp->index == 0) |
| strcpy(vdin_name, "vdin0"); |
| else if (devp->index == 1) |
| strcpy(vdin_name, "vdin1"); |
| |
| if (devp->cma_config_flag & MEM_ALLOC_DISCRETE) { |
| for (i = 0; i < max_buffer_num; i++) { |
| if (devp->cma_config_flag & MEM_ALLOC_FROM_CODEC) { |
| /*add for 1g config, codec can't release |
| *mem in time |
| */ |
| for (j = 0; j < 20; j++) { |
| devp->vfmem_start[i] = |
| codec_mm_alloc_for_dma(vdin_name, |
| frame_size / |
| PAGE_SIZE, 0, |
| flags); |
| if (devp->vfmem_start[i] == 0) { |
| msleep(50); |
| pr_err("alloc mem fail:50*%dms\n", |
| j); |
| } else { |
| break; |
| } |
| } |
| |
| if (j >= 20) { |
| pr_err("\nvdin%d buf[%d]codec alloc fail!!!\n", |
| devp->index, i); |
| devp->cma_mem_alloc = 0; |
| return 1; |
| } |
| } else { |
| devp->vfvenc_pages[i] = |
| dma_alloc_from_contiguous(&devp->this_pdev->dev, |
| frame_size >> |
| PAGE_SHIFT, 0); |
| if (!devp->vfvenc_pages[i]) { |
| devp->cma_mem_alloc = 0; |
| pr_err("\nvdin%d cma mem undefined2.\n", |
| devp->index); |
| return 1; |
| } |
| devp->vfmem_start[i] = |
| page_to_phys(devp->vfvenc_pages[i]); |
| } |
| |
| if (vdin_dbg_en) |
| pr_info("vdin%d buf[%d] mem_start = 0x%lx, mem_size = 0x%x\n", |
| devp->index, i, devp->vfmem_start[i], |
| frame_size); |
| } |
| } else { |
| if (devp->cma_config_flag & MEM_ALLOC_FROM_CODEC) { |
| devp->mem_start = |
| codec_mm_alloc_for_dma(vdin_name, |
| mem_size / PAGE_SIZE, 0, flags); |
| |
| if (devp->mem_start == 0) { |
| pr_err("\nvdin%d codec alloc fail!!!\n", |
| devp->index); |
| devp->cma_mem_alloc = 0; |
| return 1; |
| } |
| } else { |
| devp->venc_pages = |
| dma_alloc_from_contiguous(&devp->this_pdev->dev, |
| mem_size >> PAGE_SHIFT, 0); |
| if (!devp->venc_pages) { |
| devp->cma_mem_alloc = 0; |
| pr_err("\nvdin%d cma mem undefined2.\n", |
| devp->index); |
| return 1; |
| } |
| devp->mem_start = page_to_phys(devp->venc_pages); |
| } |
| |
| #ifdef CONFIG_AMLOGIC_TEE |
| if (devp->secure_en) { |
| devp->secure_handle = 0; |
| res = tee_protect_mem_by_type(TEE_MEM_TYPE_VDIN, |
| devp->mem_start, |
| mem_size, |
| &devp->secure_handle); |
| if (res) |
| devp->mem_protected = 0; |
| else |
| devp->mem_protected = 1; |
| } |
| #endif |
| for (i = 0; i < max_buffer_num; i++) { |
| devp->vfmem_start[i] = devp->mem_start + frame_size * i; |
| |
| if (vdin_dbg_en) |
| pr_info("vdin%d buf[%d] mem_start = 0x%lx, mem_size = 0x%x\n", |
| devp->index, i, |
| devp->vfmem_start[i], frame_size); |
| } |
| |
| pr_info("vdin%d mem_start = 0x%lx, mem_size = 0x%x\n", |
| devp->index, devp->mem_start, mem_size); |
| } |
| |
| devp->mem_size = mem_size; |
| devp->cma_mem_alloc = 1; |
| |
| if (devp->afbce_info && devp->afbce_valid) { |
| devp->afbce_info->frame_body_size = devp->vfmem_size; |
| |
| for (i = 0; i < max_buffer_num; i++) { |
| devp->afbce_info->fm_body_paddr[i] = |
| devp->vfmem_start[i] + devp->vfmem_size_small; |
| devp->afbce_info->fm_head_paddr[i] = |
| devp->afbce_info->fm_body_paddr[i] + |
| devp->vfmem_size; |
| |
| devp->afbce_info->fm_table_paddr[i] = |
| devp->afbce_info->fm_head_paddr[i] + |
| devp->afbce_info->frame_head_size; |
| |
| if (vdin_dbg_en) { |
| pr_info("vdin%d fm_head_paddr[%d] = 0x%lx, frame_head_size = 0x%x\n", |
| devp->index, i, |
| devp->afbce_info->fm_head_paddr[i], |
| devp->afbce_info->frame_head_size); |
| pr_info("vdin%d fm_table_paddr[%d]=0x%lx, frame_table_size = 0x%x\n", |
| devp->index, i, |
| devp->afbce_info->fm_table_paddr[i], |
| devp->afbce_info->frame_table_size); |
| } |
| } |
| } |
| |
| pr_info("vdin%d cma alloc ok!\n", devp->index); |
| return 0; |
| } |
| |
| /*this function used for codec cma release |
| * 1.call codec_mm_free_for_dma() or |
| * dma_release_from_contiguous() to relase cma; |
| * 2.reset mem_start & mem_size & cma_mem_alloc to 0; |
| */ |
| void vdin_cma_release(struct vdin_dev_s *devp) |
| { |
| char vdin_name[6]; |
| unsigned int i; |
| |
| if ((devp->cma_config_en == 0) || |
| (devp->cma_mem_alloc == 0)) { |
| pr_err("\nvdin%d %s fail for (%d,%d)!!!\n", |
| devp->index, __func__, devp->cma_config_en, |
| devp->cma_mem_alloc); |
| return; |
| } |
| if (devp->index == 0) |
| strcpy(vdin_name, "vdin0"); |
| else if (devp->index == 1) |
| strcpy(vdin_name, "vdin1"); |
| |
| if (devp->cma_config_flag & MEM_ALLOC_DISCRETE) { |
| if (devp->cma_config_flag & MEM_ALLOC_FROM_CODEC) { |
| /* canvas or afbce paddr */ |
| for (i = 0; i < devp->vfmem_max_cnt; i++) |
| codec_mm_free_for_dma(vdin_name, |
| devp->vfmem_start[i]); |
| |
| pr_info("vdin%d codec cma release ok!\n", devp->index); |
| } else { |
| for (i = 0; i < devp->vfmem_max_cnt; i++) |
| dma_release_from_contiguous(&devp->this_pdev->dev, |
| devp->vfvenc_pages[i], |
| devp->frame_size >> |
| PAGE_SHIFT); |
| |
| pr_info("vdin%d cma release ok!\n", devp->index); |
| } |
| } else { |
| #ifdef CONFIG_AMLOGIC_TEE |
| if (devp->secure_en && devp->mem_protected) { |
| tee_unprotect_mem(devp->secure_handle); |
| devp->mem_protected = 0; |
| } |
| #endif |
| if (devp->cma_config_flag & MEM_ALLOC_FROM_CODEC) { |
| codec_mm_free_for_dma(vdin_name, devp->mem_start); |
| pr_info("vdin%d codec cma release ok!\n", devp->index); |
| } else { |
| if (devp->venc_pages && devp->mem_size) |
| dma_release_from_contiguous(&devp->this_pdev->dev, |
| devp->venc_pages, |
| devp->mem_size >> |
| PAGE_SHIFT); |
| |
| pr_info("vdin%d cma release ok!\n", devp->index); |
| } |
| } |
| |
| devp->mem_start = 0; |
| devp->mem_size = 0; |
| devp->cma_mem_alloc = 0; |
| } |
| /*@20170823 new add for the case of csc change after signal stable*/ |
| |
| void vdin_set_mem_protect(struct vdin_dev_s *devp, unsigned int protect) |
| { |
| #ifdef CONFIG_AMLOGIC_TEE |
| unsigned int res = 0; |
| |
| if (protect) { |
| res = tee_protect_mem_by_type(TEE_MEM_TYPE_VDIN, |
| devp->mem_start, |
| devp->mem_size, |
| &devp->secure_handle); |
| if (res) |
| devp->mem_protected = 0; |
| else |
| devp->mem_protected = 1; |
| } else { |
| tee_unprotect_mem(devp->secure_handle); |
| devp->mem_protected = 0; |
| } |
| #endif |
| } |
| |
| void vdin_cma_malloc_mode(struct vdin_dev_s *devp) |
| { |
| unsigned int h_size, v_size; |
| |
| h_size = devp->h_active; |
| v_size = devp->v_active; |
| if ((h_size <= VDIN_YUV444_MAX_CMA_WIDTH) && |
| (v_size <= VDIN_YUV444_MAX_CMA_HEIGH) && |
| (devp->cma_mem_mode == 1)) |
| devp->force_yuv444_malloc = 1; |
| else |
| devp->force_yuv444_malloc = 0; |
| |
| } |
| #endif |
| |