/*
|
* Copyright 2015 Rockchip Electronics Co. LTD
|
*
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
* you may not use this file except in compliance with the License.
|
* You may obtain a copy of the License at
|
*
|
* http://www.apache.org/licenses/LICENSE-2.0
|
*
|
* Unless required by applicable law or agreed to in writing, software
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* See the License for the specific language governing permissions and
|
* limitations under the License.
|
*/
|
|
#define MODULE_TAG "vepu541_common"
|
|
#include <string.h>
|
|
#include "mpp_mem.h"
|
#include "mpp_debug.h"
|
#include "mpp_common.h"
|
|
#include "vepu541_common.h"
|
|
static const RK_S32 zeros[9] = {0, 0, 0, 0, 0, 0, 0, 0, 0};
|
|
static VepuFmtCfg vepu541_yuv_cfg[MPP_FMT_YUV_BUTT] = {
|
{ /* MPP_FMT_YUV420SP */
|
.format = VEPU541_FMT_YUV420SP,
|
.alpha_swap = 0,
|
.rbuv_swap = 0,
|
.src_range = 0,
|
.src_endian = 0,
|
.weight = zeros,
|
.offset = zeros,
|
},
|
{ /* MPP_FMT_YUV420SP_10BIT */
|
.format = VEPU541_FMT_NONE,
|
.alpha_swap = 0,
|
.rbuv_swap = 0,
|
.src_range = 0,
|
.src_endian = 0,
|
.weight = zeros,
|
.offset = zeros,
|
},
|
{ /* MPP_FMT_YUV422SP */
|
.format = VEPU541_FMT_YUV422SP,
|
.alpha_swap = 0,
|
.rbuv_swap = 0,
|
.src_range = 0,
|
.src_endian = 0,
|
.weight = zeros,
|
.offset = zeros,
|
},
|
{ /* MPP_FMT_YUV422SP_10BIT */
|
.format = VEPU541_FMT_NONE,
|
.alpha_swap = 0,
|
.rbuv_swap = 0,
|
.src_range = 0,
|
.src_endian = 0,
|
.weight = zeros,
|
.offset = zeros,
|
},
|
{ /* MPP_FMT_YUV420P */
|
.format = VEPU541_FMT_YUV420P,
|
.alpha_swap = 0,
|
.rbuv_swap = 0,
|
.src_range = 0,
|
.src_endian = 0,
|
.weight = zeros,
|
.offset = zeros,
|
},
|
{ /* MPP_FMT_YUV420SP_VU */
|
.format = VEPU541_FMT_YUV420SP,
|
.alpha_swap = 0,
|
.rbuv_swap = 1,
|
.src_range = 0,
|
.src_endian = 0,
|
.weight = zeros,
|
.offset = zeros,
|
},
|
{ /* MPP_FMT_YUV422P */
|
.format = VEPU541_FMT_YUV422P,
|
.alpha_swap = 0,
|
.rbuv_swap = 0,
|
.src_range = 0,
|
.src_endian = 0,
|
.weight = zeros,
|
.offset = zeros,
|
},
|
{ /* MPP_FMT_YUV422SP_VU */
|
.format = VEPU541_FMT_NONE,
|
.alpha_swap = 0,
|
.rbuv_swap = 0,
|
.src_range = 0,
|
.src_endian = 0,
|
.weight = zeros,
|
.offset = zeros,
|
},
|
{ /* MPP_FMT_YUV422_YUYV */
|
.format = VEPU541_FMT_YUYV422,
|
.alpha_swap = 0,
|
.rbuv_swap = 0,
|
.src_range = 0,
|
.src_endian = 0,
|
.weight = zeros,
|
.offset = zeros,
|
},
|
{ /* MPP_FMT_YUV422_YVYU */
|
.format = VEPU541_FMT_YUYV422,
|
.alpha_swap = 0,
|
.rbuv_swap = 1,
|
.src_range = 0,
|
.src_endian = 0,
|
.weight = zeros,
|
.offset = zeros,
|
},
|
{ /* MPP_FMT_YUV422_UYVY */
|
.format = VEPU541_FMT_UYVY422,
|
.alpha_swap = 0,
|
.rbuv_swap = 0,
|
.src_range = 0,
|
.src_endian = 0,
|
.weight = zeros,
|
.offset = zeros,
|
},
|
{ /* MPP_FMT_YUV422_VYUY */
|
.format = VEPU541_FMT_UYVY422,
|
.alpha_swap = 0,
|
.rbuv_swap = 1,
|
.src_range = 0,
|
.src_endian = 0,
|
.weight = zeros,
|
.offset = zeros,
|
},
|
{ /* MPP_FMT_YUV400 */
|
.format = VEPU541_FMT_NONE,
|
.alpha_swap = 0,
|
.rbuv_swap = 0,
|
.src_range = 0,
|
.src_endian = 0,
|
.weight = zeros,
|
.offset = zeros,
|
},
|
{ /* MPP_FMT_YUV440SP */
|
.format = VEPU541_FMT_NONE,
|
.alpha_swap = 0,
|
.rbuv_swap = 0,
|
.src_range = 0,
|
.src_endian = 0,
|
.weight = zeros,
|
.offset = zeros,
|
},
|
{ /* MPP_FMT_YUV411SP */
|
.format = VEPU541_FMT_NONE,
|
.alpha_swap = 0,
|
.rbuv_swap = 0,
|
.src_range = 0,
|
.src_endian = 0,
|
.weight = zeros,
|
.offset = zeros,
|
},
|
{ /* MPP_FMT_YUV444SP */
|
.format = VEPU580_FMT_YUV444SP,
|
.alpha_swap = 0,
|
.rbuv_swap = 0,
|
.src_range = 0,
|
.src_endian = 0,
|
.weight = zeros,
|
.offset = zeros,
|
},
|
{ /* MPP_FMT_YUV444P */
|
.format = VEPU580_FMT_YUV444P,
|
.alpha_swap = 0,
|
.rbuv_swap = 1,
|
.src_range = 0,
|
.src_endian = 0,
|
.weight = zeros,
|
.offset = zeros,
|
},
|
};
|
|
static VepuFmtCfg vepu541_rgb_cfg[MPP_FMT_RGB_BUTT - MPP_FRAME_FMT_RGB] = {
|
{ /* MPP_FMT_RGB565 */
|
.format = VEPU541_FMT_BGR565,
|
.alpha_swap = 0,
|
.rbuv_swap = 1,
|
.src_range = 0,
|
.src_endian = 1,
|
.weight = zeros,
|
.offset = zeros,
|
},
|
{ /* MPP_FMT_BGR565 */
|
.format = VEPU541_FMT_BGR565,
|
.alpha_swap = 0,
|
.rbuv_swap = 0,
|
.src_range = 0,
|
.src_endian = 1,
|
.weight = zeros,
|
.offset = zeros,
|
},
|
{ /* MPP_FMT_RGB555 */
|
.format = VEPU541_FMT_NONE,
|
.alpha_swap = 0,
|
.rbuv_swap = 0,
|
.src_range = 0,
|
.src_endian = 0,
|
.weight = zeros,
|
.offset = zeros,
|
},
|
{ /* MPP_FMT_BGR555 */
|
.format = VEPU541_FMT_NONE,
|
.alpha_swap = 0,
|
.rbuv_swap = 0,
|
.src_range = 0,
|
.src_endian = 0,
|
.weight = zeros,
|
.offset = zeros,
|
},
|
{ /* MPP_FMT_RGB444 */
|
.format = VEPU541_FMT_NONE,
|
.alpha_swap = 0,
|
.rbuv_swap = 0,
|
.src_range = 0,
|
.src_endian = 0,
|
.weight = zeros,
|
.offset = zeros,
|
},
|
{ /* MPP_FMT_BGR444 */
|
.format = VEPU541_FMT_NONE,
|
.alpha_swap = 0,
|
.rbuv_swap = 0,
|
.src_range = 0,
|
.src_endian = 0,
|
.weight = zeros,
|
.offset = zeros,
|
},
|
{ /* MPP_FMT_RGB888 */
|
.format = VEPU541_FMT_BGR888,
|
.alpha_swap = 0,
|
.rbuv_swap = 0,
|
.src_range = 0,
|
.src_endian = 0,
|
.weight = zeros,
|
.offset = zeros,
|
},
|
{ /* MPP_FMT_BGR888 */
|
.format = VEPU541_FMT_BGR888,
|
.alpha_swap = 0,
|
.rbuv_swap = 1,
|
.src_range = 0,
|
.src_endian = 0,
|
.weight = zeros,
|
.offset = zeros,
|
},
|
{ /* MPP_FMT_RGB101010 */
|
.format = VEPU541_FMT_NONE,
|
.alpha_swap = 0,
|
.rbuv_swap = 0,
|
.src_range = 0,
|
.src_endian = 0,
|
.weight = zeros,
|
.offset = zeros,
|
},
|
{ /* MPP_FMT_BGR101010 */
|
.format = VEPU541_FMT_NONE,
|
.alpha_swap = 0,
|
.rbuv_swap = 0,
|
.src_range = 0,
|
.src_endian = 0,
|
.weight = zeros,
|
.offset = zeros,
|
},
|
{ /* MPP_FMT_ARGB8888 */
|
.format = VEPU541_FMT_BGRA8888,
|
.alpha_swap = 1,
|
.rbuv_swap = 1,
|
.src_range = 0,
|
.src_endian = 0,
|
.weight = zeros,
|
.offset = zeros,
|
},
|
{ /* MPP_FMT_ABGR8888 */
|
.format = VEPU541_FMT_BGRA8888,
|
.alpha_swap = 1,
|
.rbuv_swap = 0,
|
.src_range = 0,
|
.src_endian = 0,
|
.weight = zeros,
|
.offset = zeros,
|
},
|
{ /* MPP_FMT_BGRA8888 */
|
.format = VEPU541_FMT_BGRA8888,
|
.alpha_swap = 0,
|
.rbuv_swap = 0,
|
.src_range = 0,
|
.src_endian = 0,
|
.weight = zeros,
|
.offset = zeros,
|
},
|
{ /* MPP_FMT_RGBA8888 */
|
.format = VEPU541_FMT_BGRA8888,
|
.alpha_swap = 0,
|
.rbuv_swap = 1,
|
.src_endian = 0,
|
.src_range = 0,
|
.weight = zeros,
|
.offset = zeros,
|
},
|
};
|
|
MPP_RET vepu541_set_fmt(VepuFmtCfg *cfg, MppFrameFormat format)
|
{
|
VepuFmtCfg *fmt = NULL;
|
MPP_RET ret = MPP_OK;
|
|
format &= MPP_FRAME_FMT_MASK;
|
|
if (MPP_FRAME_FMT_IS_YUV(format)) {
|
fmt = &vepu541_yuv_cfg[format - MPP_FRAME_FMT_YUV];
|
} else if (MPP_FRAME_FMT_IS_RGB(format)) {
|
fmt = &vepu541_rgb_cfg[format - MPP_FRAME_FMT_RGB];
|
} else {
|
memset(cfg, 0, sizeof(*cfg));
|
cfg->format = VEPU541_FMT_NONE;
|
}
|
|
if (fmt && fmt->format != VEPU541_FMT_NONE) {
|
memcpy(cfg, fmt, sizeof(*cfg));
|
} else {
|
mpp_err_f("unsupport frame format %x\n", format);
|
cfg->format = VEPU541_FMT_NONE;
|
ret = MPP_NOK;
|
}
|
|
return ret;
|
}
|
|
RK_S32 vepu541_get_roi_buf_size(RK_S32 w, RK_S32 h)
|
{
|
RK_S32 stride_h = MPP_ALIGN(w, 64) / 16;
|
RK_S32 stride_v = MPP_ALIGN(h, 64) / 16;
|
RK_S32 buf_size = stride_h * stride_v * sizeof(Vepu541RoiCfg);
|
|
/* extra 32 byte for hardware access padding */
|
return buf_size + 32;
|
}
|
|
MPP_RET vepu541_set_roi(void *buf, MppEncROICfg *roi, RK_S32 w, RK_S32 h)
|
{
|
MppEncROIRegion *region = roi->regions;
|
Vepu541RoiCfg *ptr = (Vepu541RoiCfg *)buf;
|
RK_S32 mb_w = MPP_ALIGN(w, 16) / 16;
|
RK_S32 mb_h = MPP_ALIGN(h, 16) / 16;
|
RK_S32 stride_h = MPP_ALIGN(mb_w, 4);
|
RK_S32 stride_v = MPP_ALIGN(mb_h, 4);
|
Vepu541RoiCfg cfg;
|
MPP_RET ret = MPP_NOK;
|
RK_S32 i;
|
|
if (NULL == buf || NULL == roi) {
|
mpp_err_f("invalid buf %p roi %p\n", buf, roi);
|
goto DONE;
|
}
|
|
cfg.force_intra = 0;
|
cfg.reserved = 0;
|
cfg.qp_area_idx = 0;
|
cfg.qp_area_en = 1;
|
cfg.qp_adj = 0;
|
cfg.qp_adj_mode = 0;
|
|
/* step 1. reset all the config */
|
for (i = 0; i < stride_h * stride_v; i++, ptr++)
|
memcpy(ptr, &cfg, sizeof(cfg));
|
|
if (w <= 0 || h <= 0) {
|
mpp_err_f("invalid size [%d:%d]\n", w, h);
|
goto DONE;
|
}
|
|
if (roi->number > VEPU541_MAX_ROI_NUM) {
|
mpp_err_f("invalid region number %d\n", roi->number);
|
goto DONE;
|
}
|
|
/* check region config */
|
ret = MPP_OK;
|
for (i = 0; i < (RK_S32)roi->number; i++, region++) {
|
if (region->x + region->w > w || region->y + region->h > h)
|
ret = MPP_NOK;
|
|
if (region->intra > 1 || region->qp_area_idx >= VEPU541_MAX_ROI_NUM ||
|
region->area_map_en > 1 || region->abs_qp_en > 1)
|
ret = MPP_NOK;
|
|
if ((region->abs_qp_en && region->quality > 51) ||
|
(!region->abs_qp_en && (region->quality > 51 || region->quality < -51)))
|
ret = MPP_NOK;
|
|
if (ret) {
|
mpp_err_f("region %d invalid param:\n", i);
|
mpp_err_f("position [%d:%d:%d:%d] vs [%d:%d]\n",
|
region->x, region->y, region->w, region->h, w, h);
|
mpp_err_f("force intra %d qp area index %d\n",
|
region->intra, region->qp_area_idx);
|
mpp_err_f("abs qp mode %d value %d\n",
|
region->abs_qp_en, region->quality);
|
goto DONE;
|
}
|
}
|
|
region = roi->regions;
|
/* step 2. setup region for top to bottom */
|
for (i = 0; i < (RK_S32)roi->number; i++, region++) {
|
RK_S32 roi_width = (region->w + 15) / 16;
|
RK_S32 roi_height = (region->h + 15) / 16;
|
RK_S32 pos_x_init = (region->x + 15) / 16;
|
RK_S32 pos_y_init = (region->y + 15) / 16;
|
RK_S32 pos_x_end = pos_x_init + roi_width;
|
RK_S32 pos_y_end = pos_y_init + roi_height;
|
RK_S32 x, y;
|
|
mpp_assert(pos_x_init >= 0 && pos_x_init < mb_w);
|
mpp_assert(pos_x_end >= 0 && pos_x_end <= mb_w);
|
mpp_assert(pos_y_init >= 0 && pos_y_init < mb_h);
|
mpp_assert(pos_y_end >= 0 && pos_y_end <= mb_h);
|
|
cfg.force_intra = region->intra;
|
cfg.reserved = 0;
|
cfg.qp_area_idx = region->qp_area_idx;
|
// NOTE: When roi is enabled the qp_area_en should be one.
|
cfg.qp_area_en = 1; // region->area_map_en;
|
cfg.qp_adj = region->quality;
|
cfg.qp_adj_mode = region->abs_qp_en;
|
|
ptr = (Vepu541RoiCfg *)buf;
|
ptr += pos_y_init * stride_h + pos_x_init;
|
for (y = 0; y < roi_height; y++) {
|
Vepu541RoiCfg *dst = ptr;
|
|
for (x = 0; x < roi_width; x++, dst++)
|
memcpy(dst, &cfg, sizeof(cfg));
|
|
ptr += stride_h;
|
}
|
}
|
|
DONE:
|
return ret;
|
}
|
|
/*
|
* Invert color threshold is for the absolute difference between background
|
* and foregroud color.
|
* If background color and foregroud color are close enough then trigger the
|
* invert color process.
|
*/
|
#define ENC_DEFAULT_OSD_INV_THR 15
|
|
#define VEPU541_OSD_ADDR_IDX_BASE 124
|
#define VEPU580_OSD_ADDR_IDX_BASE 3092
|
|
#define VEPU541_OSD_CFG_OFFSET 0x01C0
|
#define VEPU541_OSD_PLT_OFFSET 0x0400
|
|
typedef enum Vepu541OsdPltType_e {
|
VEPU541_OSD_PLT_TYPE_USERDEF = 0,
|
VEPU541_OSD_PLT_TYPE_DEFAULT = 1,
|
} Vepu541OsdPltType;
|
|
typedef struct Vepu541OsdReg_t {
|
/*
|
* OSD_CFG
|
* Address offset: 0x01C0 Access type: read and write
|
* OSD configuration
|
*/
|
struct {
|
/* OSD region enable, each bit controls corresponding OSD region. */
|
RK_U32 osd_e : 8;
|
/* OSD inverse color enable, each bit controls corresponding region. */
|
RK_U32 osd_inv_e : 8;
|
/*
|
* OSD palette clock selection.
|
* 1'h0: Configure bus clock domain.
|
* 1'h1: Core clock domain.
|
*/
|
RK_U32 osd_plt_cks : 1;
|
/*
|
* OSD palette type.
|
* 1'h1: Default type.
|
* 1'h0: User defined type.
|
*/
|
RK_U32 osd_plt_typ : 1;
|
RK_U32 reserved : 14;
|
} reg112;
|
|
/*
|
* OSD_INV
|
* Address offset: 0x01C4 Access type: read and write
|
* OSD color inverse configuration
|
*/
|
struct {
|
/* Color inverse theshold for OSD region0. */
|
RK_U32 osd_ithd_r0 : 4;
|
/* Color inverse theshold for OSD region1. */
|
RK_U32 osd_ithd_r1 : 4;
|
/* Color inverse theshold for OSD region2. */
|
RK_U32 osd_ithd_r2 : 4;
|
/* Color inverse theshold for OSD region3. */
|
RK_U32 osd_ithd_r3 : 4;
|
/* Color inverse theshold for OSD region4. */
|
RK_U32 osd_ithd_r4 : 4;
|
/* Color inverse theshold for OSD region5. */
|
RK_U32 osd_ithd_r5 : 4;
|
/* Color inverse theshold for OSD region6. */
|
RK_U32 osd_ithd_r6 : 4;
|
/* Color inverse theshold for OSD region7. */
|
RK_U32 osd_ithd_r7 : 4;
|
} reg113;
|
|
RK_U32 reg114;
|
RK_U32 reg115;
|
|
/*
|
* OSD_POS reg116_123
|
* Address offset: 0x01D0~0x01EC Access type: read and write
|
* OSD region position
|
*/
|
Vepu541OsdPos osd_pos[8];
|
|
/*
|
* ADR_OSD reg124_131
|
* Address offset: 0x01F0~0x20C Access type: read and write
|
* Base address for OSD region, 16B aligned
|
*/
|
RK_U32 osd_addr[8];
|
} Vepu541OsdReg;
|
|
#define SET_OSD_INV_THR(index, reg, region)\
|
if(region[index].inverse) \
|
reg.osd_ithd_r##index = ENC_DEFAULT_OSD_INV_THR;
|
|
static MPP_RET copy2osd2(MppEncOSDData2* dst, MppEncOSDData *src1, MppEncOSDData2 *src2)
|
{
|
MPP_RET ret = MPP_OK;
|
RK_U32 i = 0;
|
|
if (src1) {
|
dst->num_region = src1->num_region;
|
for (i = 0; i < src1->num_region; i++) {
|
dst->region[i].enable = src1->region[i].enable;
|
dst->region[i].inverse = src1->region[i].inverse;
|
dst->region[i].start_mb_x = src1->region[i].start_mb_x;
|
dst->region[i].start_mb_y = src1->region[i].start_mb_y;
|
dst->region[i].num_mb_x = src1->region[i].num_mb_x;
|
dst->region[i].num_mb_y = src1->region[i].num_mb_y;
|
dst->region[i].buf_offset = src1->region[i].buf_offset;
|
dst->region[i].buf = src1->buf;
|
}
|
ret = MPP_OK;
|
} else if (src2) {
|
memcpy(dst, src2, sizeof(MppEncOSDData2));
|
ret = MPP_OK;
|
} else {
|
ret = MPP_NOK;
|
}
|
return ret;
|
}
|
|
MPP_RET vepu541_set_osd(Vepu541OsdCfg *cfg)
|
{
|
Vepu541OsdReg *regs = (Vepu541OsdReg *)(cfg->reg_base + (size_t)VEPU541_OSD_CFG_OFFSET);
|
MppDev dev = cfg->dev;
|
MppEncOSDPltCfg *plt_cfg = cfg->plt_cfg;
|
MppEncOSDData2 osd;
|
|
if (copy2osd2(&osd, cfg->osd_data, cfg->osd_data2))
|
return MPP_NOK;
|
|
if (osd.num_region == 0)
|
return MPP_OK;
|
|
if (osd.num_region > 8) {
|
mpp_err_f("do NOT support more than 8 regions invalid num %d\n",
|
osd.num_region);
|
mpp_assert(osd.num_region <= 8);
|
return MPP_NOK;
|
}
|
|
if (plt_cfg->type == MPP_ENC_OSD_PLT_TYPE_USERDEF) {
|
MppDevRegWrCfg wr_cfg;
|
|
wr_cfg.reg = plt_cfg->plt;
|
wr_cfg.size = sizeof(MppEncOSDPlt);
|
wr_cfg.offset = VEPU541_REG_BASE_OSD_PLT;
|
|
mpp_dev_ioctl(dev, MPP_DEV_REG_WR, &wr_cfg);
|
|
regs->reg112.osd_plt_cks = 1;
|
regs->reg112.osd_plt_typ = VEPU541_OSD_PLT_TYPE_USERDEF;
|
} else {
|
regs->reg112.osd_plt_cks = 0;
|
regs->reg112.osd_plt_typ = VEPU541_OSD_PLT_TYPE_DEFAULT;
|
}
|
|
regs->reg112.osd_e = 0;
|
regs->reg112.osd_inv_e = 0;
|
|
RK_U32 i = 0;
|
MppEncOSDRegion2 *region = osd.region;
|
MppEncOSDRegion2 *tmp = region;
|
RK_U32 num = osd.num_region;
|
|
for (i = 0; i < num; i++, tmp++) {
|
regs->reg112.osd_e |= tmp->enable << i;
|
regs->reg112.osd_inv_e |= tmp->inverse << i;
|
|
if (tmp->enable && tmp->num_mb_x && tmp->num_mb_y) {
|
Vepu541OsdPos *pos = ®s->osd_pos[i];
|
size_t blk_len = tmp->num_mb_x * tmp->num_mb_y * 256;
|
RK_S32 fd = 0;
|
RK_U32 buf_size = 0;
|
|
pos->osd_lt_x = tmp->start_mb_x;
|
pos->osd_lt_y = tmp->start_mb_y;
|
pos->osd_rb_x = tmp->start_mb_x + tmp->num_mb_x - 1;
|
pos->osd_rb_y = tmp->start_mb_y + tmp->num_mb_y - 1;
|
|
buf_size = mpp_buffer_get_size(tmp->buf);
|
fd = mpp_buffer_get_fd(tmp->buf);
|
if (fd < 0) {
|
mpp_err_f("invalid osd buffer fd %d\n", fd);
|
return MPP_NOK;
|
}
|
regs->osd_addr[i] = fd;
|
|
if (tmp->buf_offset) {
|
MppDevRegOffsetCfg trans_cfg;
|
|
trans_cfg.reg_idx = VEPU541_OSD_ADDR_IDX_BASE + i;
|
trans_cfg.offset = tmp->buf_offset;
|
mpp_dev_ioctl(cfg->dev, MPP_DEV_REG_OFFSET, &trans_cfg);
|
}
|
|
/* There should be enough buffer and offset should be 16B aligned */
|
if (buf_size < tmp->buf_offset + blk_len ||
|
(tmp->buf_offset & 0xf)) {
|
mpp_err_f("invalid osd cfg: %d x:y:w:h:off %d:%d:%d:%d:%x\n",
|
i, tmp->start_mb_x, tmp->start_mb_y,
|
tmp->num_mb_x, tmp->num_mb_y, tmp->buf_offset);
|
}
|
}
|
}
|
|
SET_OSD_INV_THR(0, regs->reg113, region);
|
SET_OSD_INV_THR(1, regs->reg113, region);
|
SET_OSD_INV_THR(2, regs->reg113, region);
|
SET_OSD_INV_THR(3, regs->reg113, region);
|
SET_OSD_INV_THR(4, regs->reg113, region);
|
SET_OSD_INV_THR(5, regs->reg113, region);
|
SET_OSD_INV_THR(6, regs->reg113, region);
|
SET_OSD_INV_THR(7, regs->reg113, region);
|
|
return MPP_OK;
|
}
|
|
#define VEPU540_OSD_CFG_OFFSET 0x0178
|
|
typedef struct Vepu540OsdReg_t {
|
/*
|
* OSD_INV_CFG
|
* Address offset: 0x0178 Access type: read and write
|
* OSD color inverse configuration
|
*/
|
struct {
|
/*
|
* OSD color inverse enable of chroma component,
|
* each bit controls corresponding region.
|
*/
|
RK_U32 osd_ch_inv_en : 8;
|
/*
|
* OSD color inverse expression type
|
* each bit controls corresponding region.
|
* 1'h0: AND;
|
* 1'h1: OR
|
*/
|
RK_U32 osd_itype : 8;
|
/*
|
* OSD color inverse expression switch for luma component
|
* each bit controls corresponding region.
|
* 1'h0: Expression need to determine the condition;
|
* 1'h1: Expression don't need to determine the condition;
|
*/
|
RK_U32 osd_lu_inv_msk : 8;
|
/*
|
* OSD color inverse expression switch for chroma component
|
* each bit controls corresponding region.
|
* 1'h0: Expression need to determine the condition;
|
* 1'h1: Expression don't need to determine the condition;
|
*/
|
RK_U32 osd_ch_inv_msk : 8;
|
} reg094;
|
|
/* reg gap 095~111 */
|
RK_U32 reg_095_111[17];
|
|
/*
|
* OSD_CFG
|
* Address offset: 0x01C0 Access type: read and write
|
* OSD configuration
|
*/
|
struct {
|
/* OSD region enable, each bit controls corresponding OSD region. */
|
RK_U32 osd_e : 8;
|
/* OSD inverse color enable, each bit controls corresponding region. */
|
RK_U32 osd_lu_inv_en : 8;
|
/*
|
* OSD palette clock selection.
|
* 1'h0: Configure bus clock domain.
|
* 1'h1: Core clock domain.
|
*/
|
RK_U32 osd_plt_cks : 1;
|
/*
|
* OSD palette type.
|
* 1'h1: Default type.
|
* 1'h0: User defined type.
|
*/
|
RK_U32 osd_plt_typ : 1;
|
RK_U32 reserved : 14;
|
} reg112;
|
|
/*
|
* OSD_INV
|
* Address offset: 0x01C4 Access type: read and write
|
* OSD color inverse configuration
|
*/
|
struct {
|
/* Color inverse theshold for OSD region0. */
|
RK_U32 osd_ithd_r0 : 4;
|
/* Color inverse theshold for OSD region1. */
|
RK_U32 osd_ithd_r1 : 4;
|
/* Color inverse theshold for OSD region2. */
|
RK_U32 osd_ithd_r2 : 4;
|
/* Color inverse theshold for OSD region3. */
|
RK_U32 osd_ithd_r3 : 4;
|
/* Color inverse theshold for OSD region4. */
|
RK_U32 osd_ithd_r4 : 4;
|
/* Color inverse theshold for OSD region5. */
|
RK_U32 osd_ithd_r5 : 4;
|
/* Color inverse theshold for OSD region6. */
|
RK_U32 osd_ithd_r6 : 4;
|
/* Color inverse theshold for OSD region7. */
|
RK_U32 osd_ithd_r7 : 4;
|
} reg113;
|
|
RK_U32 reg114;
|
RK_U32 reg115;
|
|
/*
|
* OSD_POS reg116_123
|
* Address offset: 0x01D0~0x01EC Access type: read and write
|
* OSD region position
|
*/
|
Vepu541OsdPos osd_pos[8];
|
|
/*
|
* ADR_OSD reg124_131
|
* Address offset: 0x01F0~0x20C Access type: read and write
|
* Base address for OSD region, 16B aligned
|
*/
|
RK_U32 osd_addr[8];
|
} Vepu540OsdReg;
|
|
MPP_RET vepu540_set_osd(Vepu541OsdCfg *cfg)
|
{
|
Vepu540OsdReg *regs = (Vepu540OsdReg *)(cfg->reg_base + (size_t)VEPU540_OSD_CFG_OFFSET);
|
MppDev dev = cfg->dev;
|
MppEncOSDPltCfg *plt_cfg = cfg->plt_cfg;
|
MppEncOSDData2 osd;
|
|
if (copy2osd2(&osd, cfg->osd_data, cfg->osd_data2))
|
return MPP_NOK;
|
|
if (osd.num_region == 0)
|
return MPP_OK;
|
|
if (osd.num_region > 8) {
|
mpp_err_f("do NOT support more than 8 regions invalid num %d\n",
|
osd.num_region);
|
mpp_assert(osd.num_region <= 8);
|
return MPP_NOK;
|
}
|
|
if (plt_cfg->type == MPP_ENC_OSD_PLT_TYPE_USERDEF) {
|
MppDevRegWrCfg wr_cfg;
|
|
wr_cfg.reg = plt_cfg->plt;
|
wr_cfg.size = sizeof(MppEncOSDPlt);
|
wr_cfg.offset = VEPU541_REG_BASE_OSD_PLT;
|
mpp_dev_ioctl(dev, MPP_DEV_REG_WR, &wr_cfg);
|
|
regs->reg112.osd_plt_cks = 1;
|
regs->reg112.osd_plt_typ = VEPU541_OSD_PLT_TYPE_USERDEF;
|
} else {
|
regs->reg112.osd_plt_cks = 0;
|
regs->reg112.osd_plt_typ = VEPU541_OSD_PLT_TYPE_DEFAULT;
|
}
|
|
regs->reg112.osd_e = 0;
|
regs->reg112.osd_lu_inv_en = 0;
|
regs->reg094.osd_ch_inv_en = 0;
|
regs->reg094.osd_lu_inv_msk = 0;
|
|
RK_U32 num = osd.num_region;
|
RK_U32 k = 0;
|
MppEncOSDRegion2 *region = osd.region;
|
MppEncOSDRegion2 *tmp = region;
|
|
for (k = 0; k < num; k++, tmp++) {
|
regs->reg112.osd_e |= tmp->enable << k;
|
regs->reg112.osd_lu_inv_en |= (tmp->inverse) ? (1 << k) : 0;
|
regs->reg094.osd_ch_inv_en |= (tmp->inverse) ? (1 << k) : 0;
|
|
if (tmp->enable && tmp->num_mb_x && tmp->num_mb_y) {
|
Vepu541OsdPos *pos = ®s->osd_pos[k];
|
size_t blk_len = tmp->num_mb_x * tmp->num_mb_y * 256;
|
RK_S32 fd = -1;
|
size_t buf_size = 0;
|
|
pos->osd_lt_x = tmp->start_mb_x;
|
pos->osd_lt_y = tmp->start_mb_y;
|
pos->osd_rb_x = tmp->start_mb_x + tmp->num_mb_x - 1;
|
pos->osd_rb_y = tmp->start_mb_y + tmp->num_mb_y - 1;
|
|
buf_size = mpp_buffer_get_size(tmp->buf);
|
fd = mpp_buffer_get_fd(tmp->buf);
|
if (fd < 0) {
|
mpp_err_f("invalid osd buffer fd %d\n", fd);
|
return MPP_NOK;
|
}
|
regs->osd_addr[k] = fd;
|
|
if (tmp->buf_offset) {
|
MppDevRegOffsetCfg trans_cfg;
|
|
trans_cfg.reg_idx = VEPU541_OSD_ADDR_IDX_BASE + k;
|
trans_cfg.offset = tmp->buf_offset;
|
mpp_dev_ioctl(dev, MPP_DEV_REG_OFFSET, &trans_cfg);
|
}
|
|
/* There should be enough buffer and offset should be 16B aligned */
|
if (buf_size < tmp->buf_offset + blk_len ||
|
(tmp->buf_offset & 0xf)) {
|
mpp_err_f("invalid osd cfg: %d x:y:w:h:off %d:%d:%d:%d:%x size %x\n",
|
k, tmp->start_mb_x, tmp->start_mb_y,
|
tmp->num_mb_x, tmp->num_mb_y, tmp->buf_offset, buf_size);
|
}
|
}
|
}
|
|
SET_OSD_INV_THR(0, regs->reg113, region);
|
SET_OSD_INV_THR(1, regs->reg113, region);
|
SET_OSD_INV_THR(2, regs->reg113, region);
|
SET_OSD_INV_THR(3, regs->reg113, region);
|
SET_OSD_INV_THR(4, regs->reg113, region);
|
SET_OSD_INV_THR(5, regs->reg113, region);
|
SET_OSD_INV_THR(6, regs->reg113, region);
|
SET_OSD_INV_THR(7, regs->reg113, region);
|
|
return MPP_OK;
|
}
|
|
typedef struct Vepu580OsdReg_t {
|
/*
|
* OSD_INV_CFG
|
* Address offset: 0x00003000 Access type: read and write
|
* OSD color inverse configuration
|
*/
|
struct {
|
/*
|
* OSD color inverse enable of luma component,
|
* each bit controls corresponding region.
|
*/
|
RK_U32 osd_lu_inv_en : 8;
|
|
/* OSD color inverse enable of chroma component,
|
* each bit controls corresponding region.
|
*/
|
RK_U32 osd_ch_inv_en : 8;
|
/*
|
* OSD color inverse expression switch for luma component
|
* each bit controls corresponding region.
|
* 1'h0: Expression need to determine the condition;
|
* 1'h1: Expression don't need to determine the condition;
|
*/
|
RK_U32 osd_lu_inv_msk : 8;
|
/*
|
* OSD color inverse expression switch for chroma component
|
* each bit controls corresponding region.
|
* 1'h0: Expression need to determine the condition;
|
* 1'h1: Expression don't need to determine the condition;
|
*/
|
RK_U32 osd_ch_inv_msk : 8;
|
} reg3072;
|
|
/*
|
* OSD_INV
|
* Address offset: 0x3004 Access type: read and write
|
* OSD color inverse configuration
|
*/
|
struct {
|
/* Color inverse theshold for OSD region0. */
|
RK_U32 osd_ithd_r0 : 4;
|
/* Color inverse theshold for OSD region1. */
|
RK_U32 osd_ithd_r1 : 4;
|
/* Color inverse theshold for OSD region2. */
|
RK_U32 osd_ithd_r2 : 4;
|
/* Color inverse theshold for OSD region3. */
|
RK_U32 osd_ithd_r3 : 4;
|
/* Color inverse theshold for OSD region4. */
|
RK_U32 osd_ithd_r4 : 4;
|
/* Color inverse theshold for OSD region5. */
|
RK_U32 osd_ithd_r5 : 4;
|
/* Color inverse theshold for OSD region6. */
|
RK_U32 osd_ithd_r6 : 4;
|
/* Color inverse theshold for OSD region7. */
|
RK_U32 osd_ithd_r7 : 4;
|
} reg3073;
|
|
/*
|
* OSD_CFG
|
* Address offset: 0x3008 Access type: read and write
|
* OSD configuration
|
*/
|
struct {
|
/* OSD region enable, each bit controls corresponding OSD region. */
|
RK_U32 osd_e : 8;
|
/*
|
* OSD color inverse expression type
|
* each bit controls corresponding region.
|
* 1'h0: AND;
|
* 1'h1: OR
|
*/
|
RK_U32 osd_itype : 8;
|
/*
|
* OSD palette clock selection.
|
* 1'h0: Configure bus clock domain.
|
* 1'h1: Core clock domain.
|
*/
|
RK_U32 osd_plt_cks : 1;
|
/*
|
* OSD palette type.
|
* 1'h1: Default type.
|
* 1'h0: User defined type.
|
*/
|
RK_U32 osd_plt_typ : 1;
|
RK_U32 reserved : 14;
|
} reg3074;
|
|
RK_U32 reserved_3075;
|
/*
|
* OSD_POS reg3076_reg3091
|
* Address offset: 0x3010~0x304c Access type: read and write
|
* OSD region position
|
*/
|
Vepu580OsdPos osd_pos[8];
|
|
/*
|
* ADR_OSD reg3092_reg3099
|
* Address offset: 0x00003050~reg306c Access type: read and write
|
* Base address for OSD region, 16B aligned
|
*/
|
RK_U32 osd_addr[8];
|
|
RK_U32 reserved3100_3103[4];
|
Vepu541OsdPltColor plt_data[256];
|
} Vepu580OsdReg;
|
|
MPP_RET vepu580_set_osd(Vepu541OsdCfg *cfg)
|
{
|
Vepu580OsdReg *regs = (Vepu580OsdReg *)cfg->reg_base;
|
MppDev dev = cfg->dev;
|
MppDevRegOffCfgs *reg_cfg = cfg->reg_cfg;
|
MppEncOSDPltCfg *plt_cfg = cfg->plt_cfg;
|
MppEncOSDData2 osd;
|
|
if (copy2osd2(&osd, cfg->osd_data, cfg->osd_data2))
|
return MPP_NOK;
|
|
if (osd.num_region == 0)
|
return MPP_OK;
|
|
if (osd.num_region > 8) {
|
mpp_err_f("do NOT support more than 8 regions invalid num %d\n",
|
osd.num_region);
|
mpp_assert(osd.num_region <= 8);
|
return MPP_NOK;
|
}
|
|
if (plt_cfg->type == MPP_ENC_OSD_PLT_TYPE_USERDEF) {
|
memcpy(regs->plt_data, plt_cfg->plt, sizeof(MppEncOSDPlt));
|
regs->reg3074.osd_plt_cks = 1;
|
regs->reg3074.osd_plt_typ = VEPU541_OSD_PLT_TYPE_USERDEF;
|
} else {
|
regs->reg3074.osd_plt_cks = 0;
|
regs->reg3074.osd_plt_typ = VEPU541_OSD_PLT_TYPE_DEFAULT;
|
}
|
|
regs->reg3074.osd_e = 0;
|
regs->reg3072.osd_lu_inv_en = 0;
|
regs->reg3072.osd_ch_inv_en = 0;
|
regs->reg3072.osd_lu_inv_msk = 0;
|
regs->reg3072.osd_ch_inv_msk = 0;
|
|
RK_U32 num = osd.num_region;
|
RK_U32 k = 0;
|
MppEncOSDRegion2 *region = osd.region;
|
MppEncOSDRegion2 *tmp = region;
|
|
for (k = 0; k < num; k++, tmp++) {
|
regs->reg3074.osd_e |= tmp->enable << k;
|
regs->reg3072.osd_lu_inv_en |= (tmp->inverse) ? (1 << k) : 0;
|
regs->reg3072.osd_ch_inv_en |= (tmp->inverse) ? (1 << k) : 0;
|
|
if (tmp->enable && tmp->num_mb_x && tmp->num_mb_y) {
|
Vepu580OsdPos *pos = ®s->osd_pos[k];
|
size_t blk_len = tmp->num_mb_x * tmp->num_mb_y * 256;
|
RK_S32 fd = -1;
|
size_t buf_size = 0;
|
|
pos->osd_lt_x = tmp->start_mb_x;
|
pos->osd_lt_y = tmp->start_mb_y;
|
pos->osd_rb_x = tmp->start_mb_x + tmp->num_mb_x - 1;
|
pos->osd_rb_y = tmp->start_mb_y + tmp->num_mb_y - 1;
|
|
buf_size = mpp_buffer_get_size(tmp->buf);
|
fd = mpp_buffer_get_fd(tmp->buf);
|
if (fd < 0) {
|
mpp_err_f("invalid osd buffer fd %d\n", fd);
|
return MPP_NOK;
|
}
|
regs->osd_addr[k] = fd;
|
|
if (tmp->buf_offset) {
|
if (reg_cfg)
|
mpp_dev_multi_offset_update(reg_cfg, VEPU580_OSD_ADDR_IDX_BASE + k, tmp->buf_offset);
|
else
|
mpp_dev_set_reg_offset(dev, VEPU580_OSD_ADDR_IDX_BASE + k, tmp->buf_offset);
|
}
|
|
/* There should be enough buffer and offset should be 16B aligned */
|
if (buf_size < tmp->buf_offset + blk_len ||
|
(tmp->buf_offset & 0xf)) {
|
mpp_err_f("invalid osd cfg: %d x:y:w:h:off %d:%d:%d:%d:%x size %x\n",
|
k, tmp->start_mb_x, tmp->start_mb_y,
|
tmp->num_mb_x, tmp->num_mb_y, tmp->buf_offset, buf_size);
|
}
|
}
|
}
|
|
SET_OSD_INV_THR(0, regs->reg3073, region);
|
SET_OSD_INV_THR(1, regs->reg3073, region);
|
SET_OSD_INV_THR(2, regs->reg3073, region);
|
SET_OSD_INV_THR(3, regs->reg3073, region);
|
SET_OSD_INV_THR(4, regs->reg3073, region);
|
SET_OSD_INV_THR(5, regs->reg3073, region);
|
SET_OSD_INV_THR(6, regs->reg3073, region);
|
SET_OSD_INV_THR(7, regs->reg3073, region);
|
|
return MPP_OK;
|
}
|