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