xref: /rockchip-linux_mpp/mpp/hal/rkenc/common/vepu541_common.c (revision 437bfbeb9567cca9cd9080e3f6954aa9d6a94f18)
1*437bfbebSnyanmisaka /*
2*437bfbebSnyanmisaka  * Copyright 2015 Rockchip Electronics Co. LTD
3*437bfbebSnyanmisaka  *
4*437bfbebSnyanmisaka  * Licensed under the Apache License, Version 2.0 (the "License");
5*437bfbebSnyanmisaka  * you may not use this file except in compliance with the License.
6*437bfbebSnyanmisaka  * You may obtain a copy of the License at
7*437bfbebSnyanmisaka  *
8*437bfbebSnyanmisaka  *      http://www.apache.org/licenses/LICENSE-2.0
9*437bfbebSnyanmisaka  *
10*437bfbebSnyanmisaka  * Unless required by applicable law or agreed to in writing, software
11*437bfbebSnyanmisaka  * distributed under the License is distributed on an "AS IS" BASIS,
12*437bfbebSnyanmisaka  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*437bfbebSnyanmisaka  * See the License for the specific language governing permissions and
14*437bfbebSnyanmisaka  * limitations under the License.
15*437bfbebSnyanmisaka  */
16*437bfbebSnyanmisaka 
17*437bfbebSnyanmisaka #define MODULE_TAG  "vepu541_common"
18*437bfbebSnyanmisaka 
19*437bfbebSnyanmisaka #include <string.h>
20*437bfbebSnyanmisaka 
21*437bfbebSnyanmisaka #include "mpp_mem.h"
22*437bfbebSnyanmisaka #include "mpp_debug.h"
23*437bfbebSnyanmisaka #include "mpp_common.h"
24*437bfbebSnyanmisaka #include "vepu5xx_common.h"
25*437bfbebSnyanmisaka #include "vepu541_common.h"
26*437bfbebSnyanmisaka 
vepu541_get_roi_buf_size(RK_S32 w,RK_S32 h)27*437bfbebSnyanmisaka RK_S32 vepu541_get_roi_buf_size(RK_S32 w, RK_S32 h)
28*437bfbebSnyanmisaka {
29*437bfbebSnyanmisaka     RK_S32 stride_h = MPP_ALIGN(w, 64) / 16;
30*437bfbebSnyanmisaka     RK_S32 stride_v = MPP_ALIGN(h, 64) / 16;
31*437bfbebSnyanmisaka     RK_S32 buf_size = stride_h * stride_v * sizeof(Vepu541RoiCfg);
32*437bfbebSnyanmisaka 
33*437bfbebSnyanmisaka     /* extra 32 byte for hardware access padding */
34*437bfbebSnyanmisaka     return buf_size + 32;
35*437bfbebSnyanmisaka }
36*437bfbebSnyanmisaka 
vepu541_set_one_roi(void * buf,MppEncROIRegion * region,RK_S32 w,RK_S32 h)37*437bfbebSnyanmisaka MPP_RET vepu541_set_one_roi(void *buf, MppEncROIRegion *region, RK_S32 w, RK_S32 h)
38*437bfbebSnyanmisaka {
39*437bfbebSnyanmisaka     Vepu541RoiCfg *ptr = (Vepu541RoiCfg *)buf;
40*437bfbebSnyanmisaka     RK_S32 mb_w = MPP_ALIGN(w, 16) / 16;
41*437bfbebSnyanmisaka     RK_S32 mb_h = MPP_ALIGN(h, 16) / 16;
42*437bfbebSnyanmisaka     RK_S32 stride_h = MPP_ALIGN(mb_w, 4);
43*437bfbebSnyanmisaka     Vepu541RoiCfg cfg;
44*437bfbebSnyanmisaka     MPP_RET ret = MPP_NOK;
45*437bfbebSnyanmisaka 
46*437bfbebSnyanmisaka     if (NULL == buf || NULL == region) {
47*437bfbebSnyanmisaka         mpp_err_f("invalid buf %p roi %p\n", buf, region);
48*437bfbebSnyanmisaka         goto DONE;
49*437bfbebSnyanmisaka     }
50*437bfbebSnyanmisaka 
51*437bfbebSnyanmisaka     RK_S32 roi_width  = (region->w + 15) / 16;
52*437bfbebSnyanmisaka     RK_S32 roi_height = (region->h + 15) / 16;
53*437bfbebSnyanmisaka     RK_S32 pos_x_init = region->x / 16;
54*437bfbebSnyanmisaka     RK_S32 pos_y_init = region->y / 16;
55*437bfbebSnyanmisaka     RK_S32 pos_x_end  = pos_x_init + roi_width;
56*437bfbebSnyanmisaka     RK_S32 pos_y_end  = pos_y_init + roi_height;
57*437bfbebSnyanmisaka     RK_S32 x, y;
58*437bfbebSnyanmisaka 
59*437bfbebSnyanmisaka     pos_x_end = MPP_MIN(pos_x_end, mb_w);
60*437bfbebSnyanmisaka     pos_y_end = MPP_MIN(pos_y_end, mb_h);
61*437bfbebSnyanmisaka     pos_x_init = MPP_MAX(pos_x_init, 0);
62*437bfbebSnyanmisaka     pos_y_init = MPP_MAX(pos_y_init, 0);
63*437bfbebSnyanmisaka 
64*437bfbebSnyanmisaka     mpp_assert(pos_x_end > pos_x_init);
65*437bfbebSnyanmisaka     mpp_assert(pos_y_end > pos_y_init);
66*437bfbebSnyanmisaka 
67*437bfbebSnyanmisaka     cfg.force_intra = region->intra;
68*437bfbebSnyanmisaka     cfg.reserved    = 0;
69*437bfbebSnyanmisaka     cfg.qp_area_idx = region->qp_area_idx;
70*437bfbebSnyanmisaka     // NOTE: When roi is enabled the qp_area_en should be one.
71*437bfbebSnyanmisaka     cfg.qp_area_en  = 1;    // region->area_map_en;
72*437bfbebSnyanmisaka     cfg.qp_adj      = region->quality;
73*437bfbebSnyanmisaka     cfg.qp_adj_mode = region->abs_qp_en;
74*437bfbebSnyanmisaka 
75*437bfbebSnyanmisaka     ptr += pos_y_init * stride_h + pos_x_init;
76*437bfbebSnyanmisaka     roi_width = pos_x_end - pos_x_init;
77*437bfbebSnyanmisaka     roi_height = pos_y_end - pos_y_init;
78*437bfbebSnyanmisaka 
79*437bfbebSnyanmisaka     for (y = 0; y < roi_height; y++) {
80*437bfbebSnyanmisaka         Vepu541RoiCfg *dst = ptr;
81*437bfbebSnyanmisaka 
82*437bfbebSnyanmisaka         for (x = 0; x < roi_width; x++, dst++)
83*437bfbebSnyanmisaka             memcpy(dst, &cfg, sizeof(cfg));
84*437bfbebSnyanmisaka 
85*437bfbebSnyanmisaka         ptr += stride_h;
86*437bfbebSnyanmisaka     }
87*437bfbebSnyanmisaka DONE:
88*437bfbebSnyanmisaka     return ret;
89*437bfbebSnyanmisaka }
90*437bfbebSnyanmisaka 
vepu541_set_roi(void * buf,MppEncROICfg * roi,RK_S32 w,RK_S32 h)91*437bfbebSnyanmisaka MPP_RET vepu541_set_roi(void *buf, MppEncROICfg *roi, RK_S32 w, RK_S32 h)
92*437bfbebSnyanmisaka {
93*437bfbebSnyanmisaka     MppEncROIRegion *region = roi->regions;
94*437bfbebSnyanmisaka     Vepu541RoiCfg *ptr = (Vepu541RoiCfg *)buf;
95*437bfbebSnyanmisaka     RK_S32 mb_w = MPP_ALIGN(w, 16) / 16;
96*437bfbebSnyanmisaka     RK_S32 mb_h = MPP_ALIGN(h, 16) / 16;
97*437bfbebSnyanmisaka     RK_S32 stride_h = MPP_ALIGN(mb_w, 4);
98*437bfbebSnyanmisaka     RK_S32 stride_v = MPP_ALIGN(mb_h, 4);
99*437bfbebSnyanmisaka     Vepu541RoiCfg cfg;
100*437bfbebSnyanmisaka     MPP_RET ret = MPP_NOK;
101*437bfbebSnyanmisaka     RK_S32 i;
102*437bfbebSnyanmisaka 
103*437bfbebSnyanmisaka     if (NULL == buf || NULL == roi) {
104*437bfbebSnyanmisaka         mpp_err_f("invalid buf %p roi %p\n", buf, roi);
105*437bfbebSnyanmisaka         goto DONE;
106*437bfbebSnyanmisaka     }
107*437bfbebSnyanmisaka 
108*437bfbebSnyanmisaka     cfg.force_intra = 0;
109*437bfbebSnyanmisaka     cfg.reserved    = 0;
110*437bfbebSnyanmisaka     cfg.qp_area_idx = 0;
111*437bfbebSnyanmisaka     cfg.qp_area_en  = 1;
112*437bfbebSnyanmisaka     cfg.qp_adj      = 0;
113*437bfbebSnyanmisaka     cfg.qp_adj_mode = 0;
114*437bfbebSnyanmisaka 
115*437bfbebSnyanmisaka     /* step 1. reset all the config */
116*437bfbebSnyanmisaka     for (i = 0; i < stride_h * stride_v; i++, ptr++)
117*437bfbebSnyanmisaka         memcpy(ptr, &cfg, sizeof(cfg));
118*437bfbebSnyanmisaka 
119*437bfbebSnyanmisaka     if (w <= 0 || h <= 0) {
120*437bfbebSnyanmisaka         mpp_err_f("invalid size [%d:%d]\n", w, h);
121*437bfbebSnyanmisaka         goto DONE;
122*437bfbebSnyanmisaka     }
123*437bfbebSnyanmisaka 
124*437bfbebSnyanmisaka     if (roi->number > VEPU541_MAX_ROI_NUM) {
125*437bfbebSnyanmisaka         mpp_err_f("invalid region number %d\n", roi->number);
126*437bfbebSnyanmisaka         goto DONE;
127*437bfbebSnyanmisaka     }
128*437bfbebSnyanmisaka 
129*437bfbebSnyanmisaka     /* check region config */
130*437bfbebSnyanmisaka     ret = MPP_OK;
131*437bfbebSnyanmisaka     for (i = 0; i < (RK_S32)roi->number; i++, region++) {
132*437bfbebSnyanmisaka         if (region->x + region->w > w || region->y + region->h > h)
133*437bfbebSnyanmisaka             ret = MPP_NOK;
134*437bfbebSnyanmisaka 
135*437bfbebSnyanmisaka         if (region->intra > 1 || region->qp_area_idx >= VEPU541_MAX_ROI_NUM ||
136*437bfbebSnyanmisaka             region->area_map_en > 1 || region->abs_qp_en > 1)
137*437bfbebSnyanmisaka             ret = MPP_NOK;
138*437bfbebSnyanmisaka 
139*437bfbebSnyanmisaka         if ((region->abs_qp_en && region->quality > 51) ||
140*437bfbebSnyanmisaka             (!region->abs_qp_en && (region->quality > 51 || region->quality < -51)))
141*437bfbebSnyanmisaka             ret = MPP_NOK;
142*437bfbebSnyanmisaka 
143*437bfbebSnyanmisaka         if (ret) {
144*437bfbebSnyanmisaka             mpp_err_f("region %d invalid param:\n", i);
145*437bfbebSnyanmisaka             mpp_err_f("position [%d:%d:%d:%d] vs [%d:%d]\n",
146*437bfbebSnyanmisaka                       region->x, region->y, region->w, region->h, w, h);
147*437bfbebSnyanmisaka             mpp_err_f("force intra %d qp area index %d\n",
148*437bfbebSnyanmisaka                       region->intra, region->qp_area_idx);
149*437bfbebSnyanmisaka             mpp_err_f("abs qp mode %d value %d\n",
150*437bfbebSnyanmisaka                       region->abs_qp_en, region->quality);
151*437bfbebSnyanmisaka             goto DONE;
152*437bfbebSnyanmisaka         }
153*437bfbebSnyanmisaka     }
154*437bfbebSnyanmisaka 
155*437bfbebSnyanmisaka     region = roi->regions;
156*437bfbebSnyanmisaka     /* step 2. setup region for top to bottom */
157*437bfbebSnyanmisaka     for (i = 0; i < (RK_S32)roi->number; i++, region++) {
158*437bfbebSnyanmisaka         vepu541_set_one_roi(buf, region, w, h);
159*437bfbebSnyanmisaka     }
160*437bfbebSnyanmisaka 
161*437bfbebSnyanmisaka DONE:
162*437bfbebSnyanmisaka     return ret;
163*437bfbebSnyanmisaka }
164*437bfbebSnyanmisaka 
165*437bfbebSnyanmisaka /*
166*437bfbebSnyanmisaka  * Invert color threshold is for the absolute difference between background
167*437bfbebSnyanmisaka  * and foregroud color.
168*437bfbebSnyanmisaka  * If background color and foregroud color are close enough then trigger the
169*437bfbebSnyanmisaka  * invert color process.
170*437bfbebSnyanmisaka  */
171*437bfbebSnyanmisaka #define ENC_DEFAULT_OSD_INV_THR         15
172*437bfbebSnyanmisaka 
173*437bfbebSnyanmisaka #define VEPU541_OSD_ADDR_IDX_BASE       124
174*437bfbebSnyanmisaka 
175*437bfbebSnyanmisaka #define VEPU541_OSD_CFG_OFFSET          0x01C0
176*437bfbebSnyanmisaka #define VEPU541_OSD_PLT_OFFSET          0x0400
177*437bfbebSnyanmisaka 
178*437bfbebSnyanmisaka typedef struct Vepu541OsdReg_t {
179*437bfbebSnyanmisaka     /*
180*437bfbebSnyanmisaka      * OSD_CFG
181*437bfbebSnyanmisaka      * Address offset: 0x01C0 Access type: read and write
182*437bfbebSnyanmisaka      * OSD configuration
183*437bfbebSnyanmisaka      */
184*437bfbebSnyanmisaka     struct {
185*437bfbebSnyanmisaka         /* OSD region enable, each bit controls corresponding OSD region. */
186*437bfbebSnyanmisaka         RK_U32  osd_e                   : 8;
187*437bfbebSnyanmisaka         /* OSD inverse color enable, each bit controls corresponding region. */
188*437bfbebSnyanmisaka         RK_U32  osd_inv_e               : 8;
189*437bfbebSnyanmisaka         /*
190*437bfbebSnyanmisaka          * OSD palette clock selection.
191*437bfbebSnyanmisaka          * 1'h0: Configure bus clock domain.
192*437bfbebSnyanmisaka          * 1'h1: Core clock domain.
193*437bfbebSnyanmisaka          */
194*437bfbebSnyanmisaka         RK_U32  osd_plt_cks             : 1;
195*437bfbebSnyanmisaka         /*
196*437bfbebSnyanmisaka          * OSD palette type.
197*437bfbebSnyanmisaka          * 1'h1: Default type.
198*437bfbebSnyanmisaka          * 1'h0: User defined type.
199*437bfbebSnyanmisaka          */
200*437bfbebSnyanmisaka         RK_U32  osd_plt_typ             : 1;
201*437bfbebSnyanmisaka         RK_U32  reserved                : 14;
202*437bfbebSnyanmisaka     } reg112;
203*437bfbebSnyanmisaka 
204*437bfbebSnyanmisaka     /*
205*437bfbebSnyanmisaka      * OSD_INV
206*437bfbebSnyanmisaka      * Address offset: 0x01C4 Access type: read and write
207*437bfbebSnyanmisaka      * OSD color inverse configuration
208*437bfbebSnyanmisaka      */
209*437bfbebSnyanmisaka     struct {
210*437bfbebSnyanmisaka         /* Color inverse theshold for OSD region0. */
211*437bfbebSnyanmisaka         RK_U32  osd_ithd_r0             : 4;
212*437bfbebSnyanmisaka         /* Color inverse theshold for OSD region1. */
213*437bfbebSnyanmisaka         RK_U32  osd_ithd_r1             : 4;
214*437bfbebSnyanmisaka         /* Color inverse theshold for OSD region2. */
215*437bfbebSnyanmisaka         RK_U32  osd_ithd_r2             : 4;
216*437bfbebSnyanmisaka         /* Color inverse theshold for OSD region3. */
217*437bfbebSnyanmisaka         RK_U32  osd_ithd_r3             : 4;
218*437bfbebSnyanmisaka         /* Color inverse theshold for OSD region4. */
219*437bfbebSnyanmisaka         RK_U32  osd_ithd_r4             : 4;
220*437bfbebSnyanmisaka         /* Color inverse theshold for OSD region5. */
221*437bfbebSnyanmisaka         RK_U32  osd_ithd_r5             : 4;
222*437bfbebSnyanmisaka         /* Color inverse theshold for OSD region6. */
223*437bfbebSnyanmisaka         RK_U32  osd_ithd_r6             : 4;
224*437bfbebSnyanmisaka         /* Color inverse theshold for OSD region7. */
225*437bfbebSnyanmisaka         RK_U32  osd_ithd_r7             : 4;
226*437bfbebSnyanmisaka     } reg113;
227*437bfbebSnyanmisaka 
228*437bfbebSnyanmisaka     RK_U32 reg114;
229*437bfbebSnyanmisaka     RK_U32 reg115;
230*437bfbebSnyanmisaka 
231*437bfbebSnyanmisaka     /*
232*437bfbebSnyanmisaka      * OSD_POS reg116_123
233*437bfbebSnyanmisaka      * Address offset: 0x01D0~0x01EC Access type: read and write
234*437bfbebSnyanmisaka      * OSD region position
235*437bfbebSnyanmisaka      */
236*437bfbebSnyanmisaka     Vepu541OsdPos  osd_pos[8];
237*437bfbebSnyanmisaka 
238*437bfbebSnyanmisaka     /*
239*437bfbebSnyanmisaka      * ADR_OSD reg124_131
240*437bfbebSnyanmisaka      * Address offset: 0x01F0~0x20C Access type: read and write
241*437bfbebSnyanmisaka      * Base address for OSD region, 16B aligned
242*437bfbebSnyanmisaka      */
243*437bfbebSnyanmisaka     RK_U32  osd_addr[8];
244*437bfbebSnyanmisaka } Vepu541OsdReg;
245*437bfbebSnyanmisaka 
vepu541_set_osd(Vepu5xxOsdCfg * cfg)246*437bfbebSnyanmisaka MPP_RET vepu541_set_osd(Vepu5xxOsdCfg *cfg)
247*437bfbebSnyanmisaka {
248*437bfbebSnyanmisaka     Vepu541OsdReg *regs = (Vepu541OsdReg *)(cfg->reg_base + (size_t)VEPU541_OSD_CFG_OFFSET);
249*437bfbebSnyanmisaka     MppDev dev = cfg->dev;
250*437bfbebSnyanmisaka     MppEncOSDPltCfg *plt_cfg = cfg->plt_cfg;
251*437bfbebSnyanmisaka     MppEncOSDData2 osd;
252*437bfbebSnyanmisaka 
253*437bfbebSnyanmisaka     if (copy2osd2(&osd, cfg->osd_data, cfg->osd_data2))
254*437bfbebSnyanmisaka         return MPP_NOK;
255*437bfbebSnyanmisaka 
256*437bfbebSnyanmisaka     if (osd.num_region == 0)
257*437bfbebSnyanmisaka         return MPP_OK;
258*437bfbebSnyanmisaka 
259*437bfbebSnyanmisaka     if (osd.num_region > 8) {
260*437bfbebSnyanmisaka         mpp_err_f("do NOT support more than 8 regions invalid num %d\n",
261*437bfbebSnyanmisaka                   osd.num_region);
262*437bfbebSnyanmisaka         mpp_assert(osd.num_region <= 8);
263*437bfbebSnyanmisaka         return MPP_NOK;
264*437bfbebSnyanmisaka     }
265*437bfbebSnyanmisaka 
266*437bfbebSnyanmisaka     if (plt_cfg->type == MPP_ENC_OSD_PLT_TYPE_USERDEF) {
267*437bfbebSnyanmisaka         MppDevRegWrCfg wr_cfg;
268*437bfbebSnyanmisaka 
269*437bfbebSnyanmisaka         wr_cfg.reg = plt_cfg->plt;
270*437bfbebSnyanmisaka         wr_cfg.size = sizeof(MppEncOSDPlt);
271*437bfbebSnyanmisaka         wr_cfg.offset = VEPU541_REG_BASE_OSD_PLT;
272*437bfbebSnyanmisaka 
273*437bfbebSnyanmisaka         mpp_dev_ioctl(dev, MPP_DEV_REG_WR, &wr_cfg);
274*437bfbebSnyanmisaka 
275*437bfbebSnyanmisaka         regs->reg112.osd_plt_cks = 1;
276*437bfbebSnyanmisaka         regs->reg112.osd_plt_typ = VEPU5xx_OSD_PLT_TYPE_USERDEF;
277*437bfbebSnyanmisaka     } else {
278*437bfbebSnyanmisaka         regs->reg112.osd_plt_cks = 0;
279*437bfbebSnyanmisaka         regs->reg112.osd_plt_typ = VEPU5xx_OSD_PLT_TYPE_DEFAULT;
280*437bfbebSnyanmisaka     }
281*437bfbebSnyanmisaka 
282*437bfbebSnyanmisaka     regs->reg112.osd_e = 0;
283*437bfbebSnyanmisaka     regs->reg112.osd_inv_e = 0;
284*437bfbebSnyanmisaka 
285*437bfbebSnyanmisaka     RK_U32 i = 0;
286*437bfbebSnyanmisaka     MppEncOSDRegion2 *region = osd.region;
287*437bfbebSnyanmisaka     MppEncOSDRegion2 *tmp = region;
288*437bfbebSnyanmisaka     RK_U32 num = osd.num_region;
289*437bfbebSnyanmisaka 
290*437bfbebSnyanmisaka     for (i = 0; i < num; i++, tmp++) {
291*437bfbebSnyanmisaka         regs->reg112.osd_e      |= tmp->enable << i;
292*437bfbebSnyanmisaka         regs->reg112.osd_inv_e  |= tmp->inverse << i;
293*437bfbebSnyanmisaka 
294*437bfbebSnyanmisaka         if (tmp->enable && tmp->num_mb_x && tmp->num_mb_y) {
295*437bfbebSnyanmisaka             Vepu541OsdPos *pos = &regs->osd_pos[i];
296*437bfbebSnyanmisaka             size_t blk_len = tmp->num_mb_x * tmp->num_mb_y * 256;
297*437bfbebSnyanmisaka             RK_S32 fd = 0;
298*437bfbebSnyanmisaka             RK_U32 buf_size = 0;
299*437bfbebSnyanmisaka 
300*437bfbebSnyanmisaka             pos->osd_lt_x = tmp->start_mb_x;
301*437bfbebSnyanmisaka             pos->osd_lt_y = tmp->start_mb_y;
302*437bfbebSnyanmisaka             pos->osd_rb_x = tmp->start_mb_x + tmp->num_mb_x - 1;
303*437bfbebSnyanmisaka             pos->osd_rb_y = tmp->start_mb_y + tmp->num_mb_y - 1;
304*437bfbebSnyanmisaka 
305*437bfbebSnyanmisaka             buf_size = mpp_buffer_get_size(tmp->buf);
306*437bfbebSnyanmisaka             fd = mpp_buffer_get_fd(tmp->buf);
307*437bfbebSnyanmisaka             if (fd < 0) {
308*437bfbebSnyanmisaka                 mpp_err_f("invalid osd buffer fd %d\n", fd);
309*437bfbebSnyanmisaka                 return MPP_NOK;
310*437bfbebSnyanmisaka             }
311*437bfbebSnyanmisaka             regs->osd_addr[i] = fd;
312*437bfbebSnyanmisaka 
313*437bfbebSnyanmisaka             if (tmp->buf_offset)
314*437bfbebSnyanmisaka                 mpp_dev_set_reg_offset(dev, VEPU541_OSD_ADDR_IDX_BASE + i, tmp->buf_offset);
315*437bfbebSnyanmisaka 
316*437bfbebSnyanmisaka             /* There should be enough buffer and offset should be 16B aligned */
317*437bfbebSnyanmisaka             if (buf_size < tmp->buf_offset + blk_len ||
318*437bfbebSnyanmisaka                 (tmp->buf_offset & 0xf)) {
319*437bfbebSnyanmisaka                 mpp_err_f("invalid osd cfg: %d x:y:w:h:off %d:%d:%d:%d:%x\n",
320*437bfbebSnyanmisaka                           i, tmp->start_mb_x, tmp->start_mb_y,
321*437bfbebSnyanmisaka                           tmp->num_mb_x, tmp->num_mb_y, tmp->buf_offset);
322*437bfbebSnyanmisaka             }
323*437bfbebSnyanmisaka         }
324*437bfbebSnyanmisaka     }
325*437bfbebSnyanmisaka 
326*437bfbebSnyanmisaka     SET_OSD_INV_THR(0, regs->reg113, region);
327*437bfbebSnyanmisaka     SET_OSD_INV_THR(1, regs->reg113, region);
328*437bfbebSnyanmisaka     SET_OSD_INV_THR(2, regs->reg113, region);
329*437bfbebSnyanmisaka     SET_OSD_INV_THR(3, regs->reg113, region);
330*437bfbebSnyanmisaka     SET_OSD_INV_THR(4, regs->reg113, region);
331*437bfbebSnyanmisaka     SET_OSD_INV_THR(5, regs->reg113, region);
332*437bfbebSnyanmisaka     SET_OSD_INV_THR(6, regs->reg113, region);
333*437bfbebSnyanmisaka     SET_OSD_INV_THR(7, regs->reg113, region);
334*437bfbebSnyanmisaka 
335*437bfbebSnyanmisaka     return MPP_OK;
336*437bfbebSnyanmisaka }
337*437bfbebSnyanmisaka 
338*437bfbebSnyanmisaka #define VEPU540_OSD_CFG_OFFSET          0x0178
339*437bfbebSnyanmisaka 
340*437bfbebSnyanmisaka typedef struct Vepu540OsdReg_t {
341*437bfbebSnyanmisaka     /*
342*437bfbebSnyanmisaka      * OSD_INV_CFG
343*437bfbebSnyanmisaka      * Address offset: 0x0178 Access type: read and write
344*437bfbebSnyanmisaka      * OSD color inverse  configuration
345*437bfbebSnyanmisaka      */
346*437bfbebSnyanmisaka     struct {
347*437bfbebSnyanmisaka         /*
348*437bfbebSnyanmisaka          * OSD color inverse enable of chroma component,
349*437bfbebSnyanmisaka          * each bit controls corresponding region.
350*437bfbebSnyanmisaka          */
351*437bfbebSnyanmisaka         RK_U32  osd_ch_inv_en           : 8;
352*437bfbebSnyanmisaka         /*
353*437bfbebSnyanmisaka          * OSD color inverse expression type
354*437bfbebSnyanmisaka          * each bit controls corresponding region.
355*437bfbebSnyanmisaka          * 1'h0: AND;
356*437bfbebSnyanmisaka          * 1'h1: OR
357*437bfbebSnyanmisaka          */
358*437bfbebSnyanmisaka         RK_U32  osd_itype               : 8;
359*437bfbebSnyanmisaka         /*
360*437bfbebSnyanmisaka          * OSD color inverse expression switch for luma component
361*437bfbebSnyanmisaka          * each bit controls corresponding region.
362*437bfbebSnyanmisaka          * 1'h0: Expression need to determine the condition;
363*437bfbebSnyanmisaka          * 1'h1: Expression don't need to determine the condition;
364*437bfbebSnyanmisaka          */
365*437bfbebSnyanmisaka         RK_U32  osd_lu_inv_msk          : 8;
366*437bfbebSnyanmisaka         /*
367*437bfbebSnyanmisaka          * OSD color inverse expression switch for chroma component
368*437bfbebSnyanmisaka          * each bit controls corresponding region.
369*437bfbebSnyanmisaka          * 1'h0: Expression need to determine the condition;
370*437bfbebSnyanmisaka          * 1'h1: Expression don't need to determine the condition;
371*437bfbebSnyanmisaka          */
372*437bfbebSnyanmisaka         RK_U32  osd_ch_inv_msk          : 8;
373*437bfbebSnyanmisaka     } reg094;
374*437bfbebSnyanmisaka 
375*437bfbebSnyanmisaka     /* reg gap 095~111 */
376*437bfbebSnyanmisaka     RK_U32 reg_095_111[17];
377*437bfbebSnyanmisaka 
378*437bfbebSnyanmisaka     /*
379*437bfbebSnyanmisaka      * OSD_CFG
380*437bfbebSnyanmisaka      * Address offset: 0x01C0 Access type: read and write
381*437bfbebSnyanmisaka      * OSD configuration
382*437bfbebSnyanmisaka      */
383*437bfbebSnyanmisaka     struct {
384*437bfbebSnyanmisaka         /* OSD region enable, each bit controls corresponding OSD region. */
385*437bfbebSnyanmisaka         RK_U32  osd_e                   : 8;
386*437bfbebSnyanmisaka         /* OSD inverse color enable, each bit controls corresponding region. */
387*437bfbebSnyanmisaka         RK_U32  osd_lu_inv_en           : 8;
388*437bfbebSnyanmisaka         /*
389*437bfbebSnyanmisaka          * OSD palette clock selection.
390*437bfbebSnyanmisaka          * 1'h0: Configure bus clock domain.
391*437bfbebSnyanmisaka          * 1'h1: Core clock domain.
392*437bfbebSnyanmisaka          */
393*437bfbebSnyanmisaka         RK_U32  osd_plt_cks             : 1;
394*437bfbebSnyanmisaka         /*
395*437bfbebSnyanmisaka          * OSD palette type.
396*437bfbebSnyanmisaka          * 1'h1: Default type.
397*437bfbebSnyanmisaka          * 1'h0: User defined type.
398*437bfbebSnyanmisaka          */
399*437bfbebSnyanmisaka         RK_U32  osd_plt_typ             : 1;
400*437bfbebSnyanmisaka         RK_U32  reserved                : 14;
401*437bfbebSnyanmisaka     } reg112;
402*437bfbebSnyanmisaka 
403*437bfbebSnyanmisaka     /*
404*437bfbebSnyanmisaka      * OSD_INV
405*437bfbebSnyanmisaka      * Address offset: 0x01C4 Access type: read and write
406*437bfbebSnyanmisaka      * OSD color inverse configuration
407*437bfbebSnyanmisaka      */
408*437bfbebSnyanmisaka     struct {
409*437bfbebSnyanmisaka         /* Color inverse theshold for OSD region0. */
410*437bfbebSnyanmisaka         RK_U32  osd_ithd_r0             : 4;
411*437bfbebSnyanmisaka         /* Color inverse theshold for OSD region1. */
412*437bfbebSnyanmisaka         RK_U32  osd_ithd_r1             : 4;
413*437bfbebSnyanmisaka         /* Color inverse theshold for OSD region2. */
414*437bfbebSnyanmisaka         RK_U32  osd_ithd_r2             : 4;
415*437bfbebSnyanmisaka         /* Color inverse theshold for OSD region3. */
416*437bfbebSnyanmisaka         RK_U32  osd_ithd_r3             : 4;
417*437bfbebSnyanmisaka         /* Color inverse theshold for OSD region4. */
418*437bfbebSnyanmisaka         RK_U32  osd_ithd_r4             : 4;
419*437bfbebSnyanmisaka         /* Color inverse theshold for OSD region5. */
420*437bfbebSnyanmisaka         RK_U32  osd_ithd_r5             : 4;
421*437bfbebSnyanmisaka         /* Color inverse theshold for OSD region6. */
422*437bfbebSnyanmisaka         RK_U32  osd_ithd_r6             : 4;
423*437bfbebSnyanmisaka         /* Color inverse theshold for OSD region7. */
424*437bfbebSnyanmisaka         RK_U32  osd_ithd_r7             : 4;
425*437bfbebSnyanmisaka     } reg113;
426*437bfbebSnyanmisaka 
427*437bfbebSnyanmisaka     RK_U32 reg114;
428*437bfbebSnyanmisaka     RK_U32 reg115;
429*437bfbebSnyanmisaka 
430*437bfbebSnyanmisaka     /*
431*437bfbebSnyanmisaka      * OSD_POS reg116_123
432*437bfbebSnyanmisaka      * Address offset: 0x01D0~0x01EC Access type: read and write
433*437bfbebSnyanmisaka      * OSD region position
434*437bfbebSnyanmisaka      */
435*437bfbebSnyanmisaka     Vepu541OsdPos  osd_pos[8];
436*437bfbebSnyanmisaka 
437*437bfbebSnyanmisaka     /*
438*437bfbebSnyanmisaka      * ADR_OSD reg124_131
439*437bfbebSnyanmisaka      * Address offset: 0x01F0~0x20C Access type: read and write
440*437bfbebSnyanmisaka      * Base address for OSD region, 16B aligned
441*437bfbebSnyanmisaka      */
442*437bfbebSnyanmisaka     RK_U32  osd_addr[8];
443*437bfbebSnyanmisaka } Vepu540OsdReg;
444*437bfbebSnyanmisaka 
vepu540_set_osd(Vepu5xxOsdCfg * cfg)445*437bfbebSnyanmisaka MPP_RET vepu540_set_osd(Vepu5xxOsdCfg *cfg)
446*437bfbebSnyanmisaka {
447*437bfbebSnyanmisaka     Vepu540OsdReg *regs = (Vepu540OsdReg *)(cfg->reg_base + (size_t)VEPU540_OSD_CFG_OFFSET);
448*437bfbebSnyanmisaka     MppDev dev = cfg->dev;
449*437bfbebSnyanmisaka     MppEncOSDPltCfg *plt_cfg = cfg->plt_cfg;
450*437bfbebSnyanmisaka     MppEncOSDData2 osd;
451*437bfbebSnyanmisaka 
452*437bfbebSnyanmisaka     if (copy2osd2(&osd, cfg->osd_data, cfg->osd_data2))
453*437bfbebSnyanmisaka         return MPP_NOK;
454*437bfbebSnyanmisaka 
455*437bfbebSnyanmisaka     if (osd.num_region == 0)
456*437bfbebSnyanmisaka         return MPP_OK;
457*437bfbebSnyanmisaka 
458*437bfbebSnyanmisaka     if (osd.num_region > 8) {
459*437bfbebSnyanmisaka         mpp_err_f("do NOT support more than 8 regions invalid num %d\n",
460*437bfbebSnyanmisaka                   osd.num_region);
461*437bfbebSnyanmisaka         mpp_assert(osd.num_region <= 8);
462*437bfbebSnyanmisaka         return MPP_NOK;
463*437bfbebSnyanmisaka     }
464*437bfbebSnyanmisaka 
465*437bfbebSnyanmisaka     if (plt_cfg->type == MPP_ENC_OSD_PLT_TYPE_USERDEF) {
466*437bfbebSnyanmisaka         MppDevRegWrCfg wr_cfg;
467*437bfbebSnyanmisaka 
468*437bfbebSnyanmisaka         wr_cfg.reg = plt_cfg->plt;
469*437bfbebSnyanmisaka         wr_cfg.size = sizeof(MppEncOSDPlt);
470*437bfbebSnyanmisaka         wr_cfg.offset = VEPU541_REG_BASE_OSD_PLT;
471*437bfbebSnyanmisaka         mpp_dev_ioctl(dev, MPP_DEV_REG_WR, &wr_cfg);
472*437bfbebSnyanmisaka 
473*437bfbebSnyanmisaka         regs->reg112.osd_plt_cks = 1;
474*437bfbebSnyanmisaka         regs->reg112.osd_plt_typ = VEPU5xx_OSD_PLT_TYPE_USERDEF;
475*437bfbebSnyanmisaka     } else {
476*437bfbebSnyanmisaka         regs->reg112.osd_plt_cks = 0;
477*437bfbebSnyanmisaka         regs->reg112.osd_plt_typ = VEPU5xx_OSD_PLT_TYPE_DEFAULT;
478*437bfbebSnyanmisaka     }
479*437bfbebSnyanmisaka 
480*437bfbebSnyanmisaka     regs->reg112.osd_e = 0;
481*437bfbebSnyanmisaka     regs->reg112.osd_lu_inv_en = 0;
482*437bfbebSnyanmisaka     regs->reg094.osd_ch_inv_en = 0;
483*437bfbebSnyanmisaka     regs->reg094.osd_lu_inv_msk = 0;
484*437bfbebSnyanmisaka 
485*437bfbebSnyanmisaka     RK_U32 num = osd.num_region;
486*437bfbebSnyanmisaka     RK_U32 k = 0;
487*437bfbebSnyanmisaka     MppEncOSDRegion2 *region = osd.region;
488*437bfbebSnyanmisaka     MppEncOSDRegion2 *tmp = region;
489*437bfbebSnyanmisaka 
490*437bfbebSnyanmisaka     for (k = 0; k < num; k++, tmp++) {
491*437bfbebSnyanmisaka         regs->reg112.osd_e          |= tmp->enable << k;
492*437bfbebSnyanmisaka         regs->reg112.osd_lu_inv_en  |= (tmp->inverse) ? (1 << k) : 0;
493*437bfbebSnyanmisaka         regs->reg094.osd_ch_inv_en  |= (tmp->inverse) ? (1 << k) : 0;
494*437bfbebSnyanmisaka 
495*437bfbebSnyanmisaka         if (tmp->enable && tmp->num_mb_x && tmp->num_mb_y) {
496*437bfbebSnyanmisaka             Vepu541OsdPos *pos = &regs->osd_pos[k];
497*437bfbebSnyanmisaka             size_t blk_len = tmp->num_mb_x * tmp->num_mb_y * 256;
498*437bfbebSnyanmisaka             RK_S32 fd = -1;
499*437bfbebSnyanmisaka             size_t buf_size = 0;
500*437bfbebSnyanmisaka 
501*437bfbebSnyanmisaka             pos->osd_lt_x = tmp->start_mb_x;
502*437bfbebSnyanmisaka             pos->osd_lt_y = tmp->start_mb_y;
503*437bfbebSnyanmisaka             pos->osd_rb_x = tmp->start_mb_x + tmp->num_mb_x - 1;
504*437bfbebSnyanmisaka             pos->osd_rb_y = tmp->start_mb_y + tmp->num_mb_y - 1;
505*437bfbebSnyanmisaka 
506*437bfbebSnyanmisaka             buf_size = mpp_buffer_get_size(tmp->buf);
507*437bfbebSnyanmisaka             fd = mpp_buffer_get_fd(tmp->buf);
508*437bfbebSnyanmisaka             if (fd < 0) {
509*437bfbebSnyanmisaka                 mpp_err_f("invalid osd buffer fd %d\n", fd);
510*437bfbebSnyanmisaka                 return MPP_NOK;
511*437bfbebSnyanmisaka             }
512*437bfbebSnyanmisaka             regs->osd_addr[k] = fd;
513*437bfbebSnyanmisaka 
514*437bfbebSnyanmisaka             if (tmp->buf_offset)
515*437bfbebSnyanmisaka                 mpp_dev_set_reg_offset(dev, VEPU541_OSD_ADDR_IDX_BASE + k, tmp->buf_offset);
516*437bfbebSnyanmisaka 
517*437bfbebSnyanmisaka             /* There should be enough buffer and offset should be 16B aligned */
518*437bfbebSnyanmisaka             if (buf_size < tmp->buf_offset + blk_len ||
519*437bfbebSnyanmisaka                 (tmp->buf_offset & 0xf)) {
520*437bfbebSnyanmisaka                 mpp_err_f("invalid osd cfg: %d x:y:w:h:off %d:%d:%d:%d:%x size %x\n",
521*437bfbebSnyanmisaka                           k, tmp->start_mb_x, tmp->start_mb_y,
522*437bfbebSnyanmisaka                           tmp->num_mb_x, tmp->num_mb_y, tmp->buf_offset, buf_size);
523*437bfbebSnyanmisaka             }
524*437bfbebSnyanmisaka         }
525*437bfbebSnyanmisaka     }
526*437bfbebSnyanmisaka 
527*437bfbebSnyanmisaka     SET_OSD_INV_THR(0, regs->reg113, region);
528*437bfbebSnyanmisaka     SET_OSD_INV_THR(1, regs->reg113, region);
529*437bfbebSnyanmisaka     SET_OSD_INV_THR(2, regs->reg113, region);
530*437bfbebSnyanmisaka     SET_OSD_INV_THR(3, regs->reg113, region);
531*437bfbebSnyanmisaka     SET_OSD_INV_THR(4, regs->reg113, region);
532*437bfbebSnyanmisaka     SET_OSD_INV_THR(5, regs->reg113, region);
533*437bfbebSnyanmisaka     SET_OSD_INV_THR(6, regs->reg113, region);
534*437bfbebSnyanmisaka     SET_OSD_INV_THR(7, regs->reg113, region);
535*437bfbebSnyanmisaka 
536*437bfbebSnyanmisaka     return MPP_OK;
537*437bfbebSnyanmisaka }
538