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
25 #include "vepu541_common.h"
26
27 static const RK_S32 zeros[9] = {0, 0, 0, 0, 0, 0, 0, 0, 0};
28
29 static VepuFmtCfg vepu541_yuv_cfg[MPP_FMT_YUV_BUTT] = {
30 { /* MPP_FMT_YUV420SP */
31 .format = VEPU541_FMT_YUV420SP,
32 .alpha_swap = 0,
33 .rbuv_swap = 0,
34 .src_range = 1,
35 .src_endian = 0,
36 .weight = zeros,
37 .offset = zeros,
38 },
39 { /* MPP_FMT_YUV420SP_10BIT */
40 .format = VEPU541_FMT_NONE,
41 .alpha_swap = 0,
42 .rbuv_swap = 0,
43 .src_range = 1,
44 .src_endian = 0,
45 .weight = zeros,
46 .offset = zeros,
47 },
48 { /* MPP_FMT_YUV422SP */
49 .format = VEPU541_FMT_YUV422SP,
50 .alpha_swap = 0,
51 .rbuv_swap = 0,
52 .src_range = 1,
53 .src_endian = 0,
54 .weight = zeros,
55 .offset = zeros,
56 },
57 { /* MPP_FMT_YUV422SP_10BIT */
58 .format = VEPU541_FMT_NONE,
59 .alpha_swap = 0,
60 .rbuv_swap = 0,
61 .src_range = 1,
62 .src_endian = 0,
63 .weight = zeros,
64 .offset = zeros,
65 },
66 { /* MPP_FMT_YUV420P */
67 .format = VEPU541_FMT_YUV420P,
68 .alpha_swap = 0,
69 .rbuv_swap = 0,
70 .src_range = 1,
71 .src_endian = 0,
72 .weight = zeros,
73 .offset = zeros,
74 },
75 { /* MPP_FMT_YUV420SP_VU */
76 .format = VEPU541_FMT_YUV420SP,
77 .alpha_swap = 0,
78 .rbuv_swap = 1,
79 .src_range = 1,
80 .src_endian = 0,
81 .weight = zeros,
82 .offset = zeros,
83 },
84 { /* MPP_FMT_YUV422P */
85 .format = VEPU541_FMT_YUV422P,
86 .alpha_swap = 0,
87 .rbuv_swap = 0,
88 .src_range = 1,
89 .src_endian = 0,
90 .weight = zeros,
91 .offset = zeros,
92 },
93 { /* MPP_FMT_YUV422SP_VU */
94 .format = VEPU541_FMT_YUV422SP,
95 .alpha_swap = 0,
96 .rbuv_swap = 1,
97 .src_range = 1,
98 .src_endian = 0,
99 .weight = zeros,
100 .offset = zeros,
101 },
102 { /* MPP_FMT_YUV422_YUYV */
103 .format = VEPU541_FMT_YUYV422,
104 .alpha_swap = 0,
105 .rbuv_swap = 0,
106 .src_range = 1,
107 .src_endian = 0,
108 .weight = zeros,
109 .offset = zeros,
110 },
111 { /* MPP_FMT_YUV422_YVYU */
112 .format = VEPU541_FMT_YUYV422,
113 .alpha_swap = 0,
114 .rbuv_swap = 1,
115 .src_range = 1,
116 .src_endian = 0,
117 .weight = zeros,
118 .offset = zeros,
119 },
120 { /* MPP_FMT_YUV422_UYVY */
121 .format = VEPU541_FMT_UYVY422,
122 .alpha_swap = 0,
123 .rbuv_swap = 0,
124 .src_range = 1,
125 .src_endian = 0,
126 .weight = zeros,
127 .offset = zeros,
128 },
129 { /* MPP_FMT_YUV422_VYUY */
130 .format = VEPU541_FMT_UYVY422,
131 .alpha_swap = 0,
132 .rbuv_swap = 1,
133 .src_range = 1,
134 .src_endian = 0,
135 .weight = zeros,
136 .offset = zeros,
137 },
138 { /* MPP_FMT_YUV400 */
139 .format = VEPU541_FMT_NONE,
140 .alpha_swap = 0,
141 .rbuv_swap = 0,
142 .src_range = 1,
143 .src_endian = 0,
144 .weight = zeros,
145 .offset = zeros,
146 },
147 { /* MPP_FMT_YUV440SP */
148 .format = VEPU541_FMT_NONE,
149 .alpha_swap = 0,
150 .rbuv_swap = 0,
151 .src_range = 1,
152 .src_endian = 0,
153 .weight = zeros,
154 .offset = zeros,
155 },
156 { /* MPP_FMT_YUV411SP */
157 .format = VEPU541_FMT_NONE,
158 .alpha_swap = 0,
159 .rbuv_swap = 0,
160 .src_range = 1,
161 .src_endian = 0,
162 .weight = zeros,
163 .offset = zeros,
164 },
165 { /* MPP_FMT_YUV444SP */
166 .format = VEPU580_FMT_YUV444SP,
167 .alpha_swap = 0,
168 .rbuv_swap = 0,
169 .src_range = 1,
170 .src_endian = 0,
171 .weight = zeros,
172 .offset = zeros,
173 },
174 { /* MPP_FMT_YUV444P */
175 .format = VEPU580_FMT_YUV444P,
176 .alpha_swap = 0,
177 .rbuv_swap = 1,
178 .src_range = 1,
179 .src_endian = 0,
180 .weight = zeros,
181 .offset = zeros,
182 },
183 };
184
185 static VepuFmtCfg vepu541_rgb_cfg[MPP_FMT_RGB_BUTT - MPP_FRAME_FMT_RGB] = {
186 { /* MPP_FMT_RGB565 */
187 .format = VEPU541_FMT_BGR565,
188 .alpha_swap = 0,
189 .rbuv_swap = 1,
190 .src_range = 1,
191 .src_endian = 1,
192 .weight = zeros,
193 .offset = zeros,
194 },
195 { /* MPP_FMT_BGR565 */
196 .format = VEPU541_FMT_BGR565,
197 .alpha_swap = 0,
198 .rbuv_swap = 0,
199 .src_range = 1,
200 .src_endian = 1,
201 .weight = zeros,
202 .offset = zeros,
203 },
204 { /* MPP_FMT_RGB555 */
205 .format = VEPU541_FMT_NONE,
206 .alpha_swap = 0,
207 .rbuv_swap = 0,
208 .src_range = 1,
209 .src_endian = 0,
210 .weight = zeros,
211 .offset = zeros,
212 },
213 { /* MPP_FMT_BGR555 */
214 .format = VEPU541_FMT_NONE,
215 .alpha_swap = 0,
216 .rbuv_swap = 0,
217 .src_range = 1,
218 .src_endian = 0,
219 .weight = zeros,
220 .offset = zeros,
221 },
222 { /* MPP_FMT_RGB444 */
223 .format = VEPU541_FMT_NONE,
224 .alpha_swap = 0,
225 .rbuv_swap = 0,
226 .src_range = 1,
227 .src_endian = 0,
228 .weight = zeros,
229 .offset = zeros,
230 },
231 { /* MPP_FMT_BGR444 */
232 .format = VEPU541_FMT_NONE,
233 .alpha_swap = 0,
234 .rbuv_swap = 0,
235 .src_range = 1,
236 .src_endian = 0,
237 .weight = zeros,
238 .offset = zeros,
239 },
240 { /* MPP_FMT_RGB888 */
241 .format = VEPU541_FMT_BGR888,
242 .alpha_swap = 0,
243 .rbuv_swap = 0,
244 .src_range = 1,
245 .src_endian = 0,
246 .weight = zeros,
247 .offset = zeros,
248 },
249 { /* MPP_FMT_BGR888 */
250 .format = VEPU541_FMT_BGR888,
251 .alpha_swap = 0,
252 .rbuv_swap = 1,
253 .src_range = 1,
254 .src_endian = 0,
255 .weight = zeros,
256 .offset = zeros,
257 },
258 { /* MPP_FMT_RGB101010 */
259 .format = VEPU541_FMT_NONE,
260 .alpha_swap = 0,
261 .rbuv_swap = 0,
262 .src_range = 1,
263 .src_endian = 0,
264 .weight = zeros,
265 .offset = zeros,
266 },
267 { /* MPP_FMT_BGR101010 */
268 .format = VEPU541_FMT_NONE,
269 .alpha_swap = 0,
270 .rbuv_swap = 0,
271 .src_range = 1,
272 .src_endian = 0,
273 .weight = zeros,
274 .offset = zeros,
275 },
276 { /* MPP_FMT_ARGB8888 */
277 .format = VEPU541_FMT_BGRA8888,
278 .alpha_swap = 1,
279 .rbuv_swap = 1,
280 .src_range = 1,
281 .src_endian = 0,
282 .weight = zeros,
283 .offset = zeros,
284 },
285 { /* MPP_FMT_ABGR8888 */
286 .format = VEPU541_FMT_BGRA8888,
287 .alpha_swap = 1,
288 .rbuv_swap = 0,
289 .src_range = 1,
290 .src_endian = 0,
291 .weight = zeros,
292 .offset = zeros,
293 },
294 { /* MPP_FMT_BGRA8888 */
295 .format = VEPU541_FMT_BGRA8888,
296 .alpha_swap = 0,
297 .rbuv_swap = 0,
298 .src_range = 1,
299 .src_endian = 0,
300 .weight = zeros,
301 .offset = zeros,
302 },
303 { /* MPP_FMT_RGBA8888 */
304 .format = VEPU541_FMT_BGRA8888,
305 .alpha_swap = 0,
306 .rbuv_swap = 1,
307 .src_endian = 0,
308 .src_range = 1,
309 .weight = zeros,
310 .offset = zeros,
311 },
312 };
313
vepu541_set_fmt(VepuFmtCfg * cfg,MppFrameFormat format)314 MPP_RET vepu541_set_fmt(VepuFmtCfg *cfg, MppFrameFormat format)
315 {
316 VepuFmtCfg *fmt = NULL;
317 MPP_RET ret = MPP_OK;
318
319 format &= MPP_FRAME_FMT_MASK;
320
321 if (MPP_FRAME_FMT_IS_YUV(format)) {
322 fmt = &vepu541_yuv_cfg[format - MPP_FRAME_FMT_YUV];
323 } else if (MPP_FRAME_FMT_IS_RGB(format)) {
324 fmt = &vepu541_rgb_cfg[format - MPP_FRAME_FMT_RGB];
325 } else {
326 memset(cfg, 0, sizeof(*cfg));
327 cfg->format = VEPU541_FMT_NONE;
328 }
329
330 if (fmt && fmt->format != VEPU541_FMT_NONE) {
331 memcpy(cfg, fmt, sizeof(*cfg));
332 } else {
333 mpp_err_f("unsupport frame format %x\n", format);
334 cfg->format = VEPU541_FMT_NONE;
335 ret = MPP_NOK;
336 }
337
338 return ret;
339 }
340
vepu541_get_roi_buf_size(RK_S32 w,RK_S32 h)341 RK_S32 vepu541_get_roi_buf_size(RK_S32 w, RK_S32 h)
342 {
343 RK_S32 stride_h = MPP_ALIGN(w, 64) / 16;
344 RK_S32 stride_v = MPP_ALIGN(h, 64) / 16;
345 RK_S32 buf_size = stride_h * stride_v * sizeof(Vepu541RoiCfg);
346
347 /* extra 32 byte for hardware access padding */
348 return buf_size + 32;
349 }
350
vepu541_set_one_roi(void * buf,MppEncROIRegion * region,RK_S32 w,RK_S32 h)351 MPP_RET vepu541_set_one_roi(void *buf, MppEncROIRegion *region, RK_S32 w, RK_S32 h)
352 {
353 Vepu541RoiCfg *ptr = (Vepu541RoiCfg *)buf;
354 RK_S32 mb_w = MPP_ALIGN(w, 16) / 16;
355 RK_S32 mb_h = MPP_ALIGN(h, 16) / 16;
356 RK_S32 stride_h = MPP_ALIGN(mb_w, 4);
357 Vepu541RoiCfg cfg;
358 MPP_RET ret = MPP_NOK;
359
360 if (NULL == buf || NULL == region) {
361 mpp_err_f("invalid buf %p roi %p\n", buf, region);
362 goto DONE;
363 }
364
365 RK_S32 roi_width = (region->w + 15) / 16;
366 RK_S32 roi_height = (region->h + 15) / 16;
367 RK_S32 pos_x_init = region->x / 16;
368 RK_S32 pos_y_init = region->y / 16;
369 RK_S32 pos_x_end = pos_x_init + roi_width;
370 RK_S32 pos_y_end = pos_y_init + roi_height;
371 RK_S32 x, y;
372
373 pos_x_end = MPP_MIN(pos_x_end, mb_w);
374 pos_y_end = MPP_MIN(pos_y_end, mb_h);
375 pos_x_init = MPP_MAX(pos_x_init, 0);
376 pos_y_init = MPP_MAX(pos_y_init, 0);
377
378 mpp_assert(pos_x_end > pos_x_init);
379 mpp_assert(pos_y_end > pos_y_init);
380
381 cfg.force_intra = region->intra;
382 cfg.reserved = 0;
383 cfg.qp_area_idx = region->qp_area_idx;
384 // NOTE: When roi is enabled the qp_area_en should be one.
385 cfg.qp_area_en = 1; // region->area_map_en;
386 cfg.qp_adj = region->quality;
387 cfg.qp_adj_mode = region->abs_qp_en;
388
389 ptr += pos_y_init * stride_h + pos_x_init;
390 roi_width = pos_x_end - pos_x_init;
391 roi_height = pos_y_end - pos_y_init;
392
393 for (y = 0; y < roi_height; y++) {
394 Vepu541RoiCfg *dst = ptr;
395
396 for (x = 0; x < roi_width; x++, dst++)
397 memcpy(dst, &cfg, sizeof(cfg));
398
399 ptr += stride_h;
400 }
401 DONE:
402 return ret;
403 }
404
vepu541_set_roi(void * buf,MppEncROICfg * roi,RK_S32 w,RK_S32 h)405 MPP_RET vepu541_set_roi(void *buf, MppEncROICfg *roi, RK_S32 w, RK_S32 h)
406 {
407 MppEncROIRegion *region = roi->regions;
408 Vepu541RoiCfg *ptr = (Vepu541RoiCfg *)buf;
409 RK_S32 mb_w = MPP_ALIGN(w, 16) / 16;
410 RK_S32 mb_h = MPP_ALIGN(h, 16) / 16;
411 RK_S32 stride_h = MPP_ALIGN(mb_w, 4);
412 RK_S32 stride_v = MPP_ALIGN(mb_h, 4);
413 Vepu541RoiCfg cfg;
414 MPP_RET ret = MPP_NOK;
415 RK_S32 i;
416
417 if (NULL == buf || NULL == roi) {
418 mpp_err_f("invalid buf %p roi %p\n", buf, roi);
419 goto DONE;
420 }
421
422 cfg.force_intra = 0;
423 cfg.reserved = 0;
424 cfg.qp_area_idx = 0;
425 cfg.qp_area_en = 1;
426 cfg.qp_adj = 0;
427 cfg.qp_adj_mode = 0;
428
429 /* step 1. reset all the config */
430 for (i = 0; i < stride_h * stride_v; i++, ptr++)
431 memcpy(ptr, &cfg, sizeof(cfg));
432
433 if (w <= 0 || h <= 0) {
434 mpp_err_f("invalid size [%d:%d]\n", w, h);
435 goto DONE;
436 }
437
438 if (roi->number > VEPU541_MAX_ROI_NUM) {
439 mpp_err_f("invalid region number %d\n", roi->number);
440 goto DONE;
441 }
442
443 /* check region config */
444 ret = MPP_OK;
445 for (i = 0; i < (RK_S32)roi->number; i++, region++) {
446 if (region->x + region->w > w || region->y + region->h > h)
447 ret = MPP_NOK;
448
449 if (region->intra > 1 || region->qp_area_idx >= VEPU541_MAX_ROI_NUM ||
450 region->area_map_en > 1 || region->abs_qp_en > 1)
451 ret = MPP_NOK;
452
453 if ((region->abs_qp_en && region->quality > 51) ||
454 (!region->abs_qp_en && (region->quality > 51 || region->quality < -51)))
455 ret = MPP_NOK;
456
457 if (ret) {
458 mpp_err_f("region %d invalid param:\n", i);
459 mpp_err_f("position [%d:%d:%d:%d] vs [%d:%d]\n",
460 region->x, region->y, region->w, region->h, w, h);
461 mpp_err_f("force intra %d qp area index %d\n",
462 region->intra, region->qp_area_idx);
463 mpp_err_f("abs qp mode %d value %d\n",
464 region->abs_qp_en, region->quality);
465 goto DONE;
466 }
467 }
468
469 region = roi->regions;
470 /* step 2. setup region for top to bottom */
471 for (i = 0; i < (RK_S32)roi->number; i++, region++) {
472 vepu541_set_one_roi(buf, region, w, h);
473 }
474
475 DONE:
476 return ret;
477 }
478
479 /*
480 * Invert color threshold is for the absolute difference between background
481 * and foregroud color.
482 * If background color and foregroud color are close enough then trigger the
483 * invert color process.
484 */
485 #define ENC_DEFAULT_OSD_INV_THR 15
486
487 #define VEPU541_OSD_ADDR_IDX_BASE 124
488 #define VEPU580_OSD_ADDR_IDX_BASE 3092
489
490 #define VEPU541_OSD_CFG_OFFSET 0x01C0
491 #define VEPU541_OSD_PLT_OFFSET 0x0400
492
493 typedef enum Vepu541OsdPltType_e {
494 VEPU541_OSD_PLT_TYPE_USERDEF = 0,
495 VEPU541_OSD_PLT_TYPE_DEFAULT = 1,
496 } Vepu541OsdPltType;
497
498 typedef struct Vepu541OsdReg_t {
499 /*
500 * OSD_CFG
501 * Address offset: 0x01C0 Access type: read and write
502 * OSD configuration
503 */
504 struct {
505 /* OSD region enable, each bit controls corresponding OSD region. */
506 RK_U32 osd_e : 8;
507 /* OSD inverse color enable, each bit controls corresponding region. */
508 RK_U32 osd_inv_e : 8;
509 /*
510 * OSD palette clock selection.
511 * 1'h0: Configure bus clock domain.
512 * 1'h1: Core clock domain.
513 */
514 RK_U32 osd_plt_cks : 1;
515 /*
516 * OSD palette type.
517 * 1'h1: Default type.
518 * 1'h0: User defined type.
519 */
520 RK_U32 osd_plt_typ : 1;
521 RK_U32 reserved : 14;
522 } reg112;
523
524 /*
525 * OSD_INV
526 * Address offset: 0x01C4 Access type: read and write
527 * OSD color inverse configuration
528 */
529 struct {
530 /* Color inverse theshold for OSD region0. */
531 RK_U32 osd_ithd_r0 : 4;
532 /* Color inverse theshold for OSD region1. */
533 RK_U32 osd_ithd_r1 : 4;
534 /* Color inverse theshold for OSD region2. */
535 RK_U32 osd_ithd_r2 : 4;
536 /* Color inverse theshold for OSD region3. */
537 RK_U32 osd_ithd_r3 : 4;
538 /* Color inverse theshold for OSD region4. */
539 RK_U32 osd_ithd_r4 : 4;
540 /* Color inverse theshold for OSD region5. */
541 RK_U32 osd_ithd_r5 : 4;
542 /* Color inverse theshold for OSD region6. */
543 RK_U32 osd_ithd_r6 : 4;
544 /* Color inverse theshold for OSD region7. */
545 RK_U32 osd_ithd_r7 : 4;
546 } reg113;
547
548 RK_U32 reg114;
549 RK_U32 reg115;
550
551 /*
552 * OSD_POS reg116_123
553 * Address offset: 0x01D0~0x01EC Access type: read and write
554 * OSD region position
555 */
556 Vepu541OsdPos osd_pos[8];
557
558 /*
559 * ADR_OSD reg124_131
560 * Address offset: 0x01F0~0x20C Access type: read and write
561 * Base address for OSD region, 16B aligned
562 */
563 RK_U32 osd_addr[8];
564 } Vepu541OsdReg;
565
566 #define SET_OSD_INV_THR(index, reg, region)\
567 if(region[index].inverse) \
568 reg.osd_ithd_r##index = ENC_DEFAULT_OSD_INV_THR;
569
copy2osd2(MppEncOSDData2 * dst,MppEncOSDData * src1,MppEncOSDData2 * src2)570 static MPP_RET copy2osd2(MppEncOSDData2* dst, MppEncOSDData *src1, MppEncOSDData2 *src2)
571 {
572 MPP_RET ret = MPP_OK;
573 RK_U32 i = 0;
574
575 if (src1) {
576 dst->num_region = src1->num_region;
577 for (i = 0; i < src1->num_region; i++) {
578 dst->region[i].enable = src1->region[i].enable;
579 dst->region[i].inverse = src1->region[i].inverse;
580 dst->region[i].start_mb_x = src1->region[i].start_mb_x;
581 dst->region[i].start_mb_y = src1->region[i].start_mb_y;
582 dst->region[i].num_mb_x = src1->region[i].num_mb_x;
583 dst->region[i].num_mb_y = src1->region[i].num_mb_y;
584 dst->region[i].buf_offset = src1->region[i].buf_offset;
585 dst->region[i].buf = src1->buf;
586 }
587 ret = MPP_OK;
588 } else if (src2) {
589 memcpy(dst, src2, sizeof(MppEncOSDData2));
590 ret = MPP_OK;
591 } else {
592 ret = MPP_NOK;
593 }
594 return ret;
595 }
596
vepu541_set_osd(Vepu541OsdCfg * cfg)597 MPP_RET vepu541_set_osd(Vepu541OsdCfg *cfg)
598 {
599 Vepu541OsdReg *regs = (Vepu541OsdReg *)(cfg->reg_base + (size_t)VEPU541_OSD_CFG_OFFSET);
600 MppDev dev = cfg->dev;
601 MppEncOSDPltCfg *plt_cfg = cfg->plt_cfg;
602 MppEncOSDData2 osd;
603
604 if (copy2osd2(&osd, cfg->osd_data, cfg->osd_data2))
605 return MPP_NOK;
606
607 if (osd.num_region == 0)
608 return MPP_OK;
609
610 if (osd.num_region > 8) {
611 mpp_err_f("do NOT support more than 8 regions invalid num %d\n",
612 osd.num_region);
613 mpp_assert(osd.num_region <= 8);
614 return MPP_NOK;
615 }
616
617 if (plt_cfg->type == MPP_ENC_OSD_PLT_TYPE_USERDEF) {
618 MppDevRegWrCfg wr_cfg;
619
620 wr_cfg.reg = plt_cfg->plt;
621 wr_cfg.size = sizeof(MppEncOSDPlt);
622 wr_cfg.offset = VEPU541_REG_BASE_OSD_PLT;
623
624 mpp_dev_ioctl(dev, MPP_DEV_REG_WR, &wr_cfg);
625
626 regs->reg112.osd_plt_cks = 1;
627 regs->reg112.osd_plt_typ = VEPU541_OSD_PLT_TYPE_USERDEF;
628 } else {
629 regs->reg112.osd_plt_cks = 0;
630 regs->reg112.osd_plt_typ = VEPU541_OSD_PLT_TYPE_DEFAULT;
631 }
632
633 regs->reg112.osd_e = 0;
634 regs->reg112.osd_inv_e = 0;
635
636 RK_U32 i = 0;
637 MppEncOSDRegion2 *region = osd.region;
638 MppEncOSDRegion2 *tmp = region;
639 RK_U32 num = osd.num_region;
640
641 for (i = 0; i < num; i++, tmp++) {
642 regs->reg112.osd_e |= tmp->enable << i;
643 regs->reg112.osd_inv_e |= tmp->inverse << i;
644
645 if (tmp->enable && tmp->num_mb_x && tmp->num_mb_y) {
646 Vepu541OsdPos *pos = ®s->osd_pos[i];
647 size_t blk_len = tmp->num_mb_x * tmp->num_mb_y * 256;
648 RK_S32 fd = 0;
649 RK_U32 buf_size = 0;
650
651 pos->osd_lt_x = tmp->start_mb_x;
652 pos->osd_lt_y = tmp->start_mb_y;
653 pos->osd_rb_x = tmp->start_mb_x + tmp->num_mb_x - 1;
654 pos->osd_rb_y = tmp->start_mb_y + tmp->num_mb_y - 1;
655
656 buf_size = mpp_buffer_get_size(tmp->buf);
657 fd = mpp_buffer_get_fd(tmp->buf);
658 if (fd < 0) {
659 mpp_err_f("invalid osd buffer fd %d\n", fd);
660 return MPP_NOK;
661 }
662 regs->osd_addr[i] = fd;
663
664 if (tmp->buf_offset) {
665 MppDevRegOffsetCfg trans_cfg;
666
667 trans_cfg.reg_idx = VEPU541_OSD_ADDR_IDX_BASE + i;
668 trans_cfg.offset = tmp->buf_offset;
669 mpp_dev_ioctl(cfg->dev, MPP_DEV_REG_OFFSET, &trans_cfg);
670 }
671
672 /* There should be enough buffer and offset should be 16B aligned */
673 if (buf_size < tmp->buf_offset + blk_len ||
674 (tmp->buf_offset & 0xf)) {
675 mpp_err_f("invalid osd cfg: %d x:y:w:h:off %d:%d:%d:%d:%x\n",
676 i, tmp->start_mb_x, tmp->start_mb_y,
677 tmp->num_mb_x, tmp->num_mb_y, tmp->buf_offset);
678 }
679 }
680 }
681
682 SET_OSD_INV_THR(0, regs->reg113, region);
683 SET_OSD_INV_THR(1, regs->reg113, region);
684 SET_OSD_INV_THR(2, regs->reg113, region);
685 SET_OSD_INV_THR(3, regs->reg113, region);
686 SET_OSD_INV_THR(4, regs->reg113, region);
687 SET_OSD_INV_THR(5, regs->reg113, region);
688 SET_OSD_INV_THR(6, regs->reg113, region);
689 SET_OSD_INV_THR(7, regs->reg113, region);
690
691 return MPP_OK;
692 }
693
694 #define VEPU540_OSD_CFG_OFFSET 0x0178
695
696 typedef struct Vepu540OsdReg_t {
697 /*
698 * OSD_INV_CFG
699 * Address offset: 0x0178 Access type: read and write
700 * OSD color inverse configuration
701 */
702 struct {
703 /*
704 * OSD color inverse enable of chroma component,
705 * each bit controls corresponding region.
706 */
707 RK_U32 osd_ch_inv_en : 8;
708 /*
709 * OSD color inverse expression type
710 * each bit controls corresponding region.
711 * 1'h0: AND;
712 * 1'h1: OR
713 */
714 RK_U32 osd_itype : 8;
715 /*
716 * OSD color inverse expression switch for luma component
717 * each bit controls corresponding region.
718 * 1'h0: Expression need to determine the condition;
719 * 1'h1: Expression don't need to determine the condition;
720 */
721 RK_U32 osd_lu_inv_msk : 8;
722 /*
723 * OSD color inverse expression switch for chroma component
724 * each bit controls corresponding region.
725 * 1'h0: Expression need to determine the condition;
726 * 1'h1: Expression don't need to determine the condition;
727 */
728 RK_U32 osd_ch_inv_msk : 8;
729 } reg094;
730
731 /* reg gap 095~111 */
732 RK_U32 reg_095_111[17];
733
734 /*
735 * OSD_CFG
736 * Address offset: 0x01C0 Access type: read and write
737 * OSD configuration
738 */
739 struct {
740 /* OSD region enable, each bit controls corresponding OSD region. */
741 RK_U32 osd_e : 8;
742 /* OSD inverse color enable, each bit controls corresponding region. */
743 RK_U32 osd_lu_inv_en : 8;
744 /*
745 * OSD palette clock selection.
746 * 1'h0: Configure bus clock domain.
747 * 1'h1: Core clock domain.
748 */
749 RK_U32 osd_plt_cks : 1;
750 /*
751 * OSD palette type.
752 * 1'h1: Default type.
753 * 1'h0: User defined type.
754 */
755 RK_U32 osd_plt_typ : 1;
756 RK_U32 reserved : 14;
757 } reg112;
758
759 /*
760 * OSD_INV
761 * Address offset: 0x01C4 Access type: read and write
762 * OSD color inverse configuration
763 */
764 struct {
765 /* Color inverse theshold for OSD region0. */
766 RK_U32 osd_ithd_r0 : 4;
767 /* Color inverse theshold for OSD region1. */
768 RK_U32 osd_ithd_r1 : 4;
769 /* Color inverse theshold for OSD region2. */
770 RK_U32 osd_ithd_r2 : 4;
771 /* Color inverse theshold for OSD region3. */
772 RK_U32 osd_ithd_r3 : 4;
773 /* Color inverse theshold for OSD region4. */
774 RK_U32 osd_ithd_r4 : 4;
775 /* Color inverse theshold for OSD region5. */
776 RK_U32 osd_ithd_r5 : 4;
777 /* Color inverse theshold for OSD region6. */
778 RK_U32 osd_ithd_r6 : 4;
779 /* Color inverse theshold for OSD region7. */
780 RK_U32 osd_ithd_r7 : 4;
781 } reg113;
782
783 RK_U32 reg114;
784 RK_U32 reg115;
785
786 /*
787 * OSD_POS reg116_123
788 * Address offset: 0x01D0~0x01EC Access type: read and write
789 * OSD region position
790 */
791 Vepu541OsdPos osd_pos[8];
792
793 /*
794 * ADR_OSD reg124_131
795 * Address offset: 0x01F0~0x20C Access type: read and write
796 * Base address for OSD region, 16B aligned
797 */
798 RK_U32 osd_addr[8];
799 } Vepu540OsdReg;
800
vepu540_set_osd(Vepu541OsdCfg * cfg)801 MPP_RET vepu540_set_osd(Vepu541OsdCfg *cfg)
802 {
803 Vepu540OsdReg *regs = (Vepu540OsdReg *)(cfg->reg_base + (size_t)VEPU540_OSD_CFG_OFFSET);
804 MppDev dev = cfg->dev;
805 MppEncOSDPltCfg *plt_cfg = cfg->plt_cfg;
806 MppEncOSDData2 osd;
807
808 if (copy2osd2(&osd, cfg->osd_data, cfg->osd_data2))
809 return MPP_NOK;
810
811 if (osd.num_region == 0)
812 return MPP_OK;
813
814 if (osd.num_region > 8) {
815 mpp_err_f("do NOT support more than 8 regions invalid num %d\n",
816 osd.num_region);
817 mpp_assert(osd.num_region <= 8);
818 return MPP_NOK;
819 }
820
821 if (plt_cfg->type == MPP_ENC_OSD_PLT_TYPE_USERDEF) {
822 MppDevRegWrCfg wr_cfg;
823
824 wr_cfg.reg = plt_cfg->plt;
825 wr_cfg.size = sizeof(MppEncOSDPlt);
826 wr_cfg.offset = VEPU541_REG_BASE_OSD_PLT;
827 mpp_dev_ioctl(dev, MPP_DEV_REG_WR, &wr_cfg);
828
829 regs->reg112.osd_plt_cks = 1;
830 regs->reg112.osd_plt_typ = VEPU541_OSD_PLT_TYPE_USERDEF;
831 } else {
832 regs->reg112.osd_plt_cks = 0;
833 regs->reg112.osd_plt_typ = VEPU541_OSD_PLT_TYPE_DEFAULT;
834 }
835
836 regs->reg112.osd_e = 0;
837 regs->reg112.osd_lu_inv_en = 0;
838 regs->reg094.osd_ch_inv_en = 0;
839 regs->reg094.osd_lu_inv_msk = 0;
840
841 RK_U32 num = osd.num_region;
842 RK_U32 k = 0;
843 MppEncOSDRegion2 *region = osd.region;
844 MppEncOSDRegion2 *tmp = region;
845
846 for (k = 0; k < num; k++, tmp++) {
847 regs->reg112.osd_e |= tmp->enable << k;
848 regs->reg112.osd_lu_inv_en |= (tmp->inverse) ? (1 << k) : 0;
849 regs->reg094.osd_ch_inv_en |= (tmp->inverse) ? (1 << k) : 0;
850
851 if (tmp->enable && tmp->num_mb_x && tmp->num_mb_y) {
852 Vepu541OsdPos *pos = ®s->osd_pos[k];
853 size_t blk_len = tmp->num_mb_x * tmp->num_mb_y * 256;
854 RK_S32 fd = -1;
855 size_t buf_size = 0;
856
857 pos->osd_lt_x = tmp->start_mb_x;
858 pos->osd_lt_y = tmp->start_mb_y;
859 pos->osd_rb_x = tmp->start_mb_x + tmp->num_mb_x - 1;
860 pos->osd_rb_y = tmp->start_mb_y + tmp->num_mb_y - 1;
861
862 buf_size = mpp_buffer_get_size(tmp->buf);
863 fd = mpp_buffer_get_fd(tmp->buf);
864 if (fd < 0) {
865 mpp_err_f("invalid osd buffer fd %d\n", fd);
866 return MPP_NOK;
867 }
868 regs->osd_addr[k] = fd;
869
870 if (tmp->buf_offset) {
871 MppDevRegOffsetCfg trans_cfg;
872
873 trans_cfg.reg_idx = VEPU541_OSD_ADDR_IDX_BASE + k;
874 trans_cfg.offset = tmp->buf_offset;
875 mpp_dev_ioctl(dev, MPP_DEV_REG_OFFSET, &trans_cfg);
876 }
877
878 /* There should be enough buffer and offset should be 16B aligned */
879 if (buf_size < tmp->buf_offset + blk_len ||
880 (tmp->buf_offset & 0xf)) {
881 mpp_err_f("invalid osd cfg: %d x:y:w:h:off %d:%d:%d:%d:%x size %x\n",
882 k, tmp->start_mb_x, tmp->start_mb_y,
883 tmp->num_mb_x, tmp->num_mb_y, tmp->buf_offset, buf_size);
884 }
885 }
886 }
887
888 SET_OSD_INV_THR(0, regs->reg113, region);
889 SET_OSD_INV_THR(1, regs->reg113, region);
890 SET_OSD_INV_THR(2, regs->reg113, region);
891 SET_OSD_INV_THR(3, regs->reg113, region);
892 SET_OSD_INV_THR(4, regs->reg113, region);
893 SET_OSD_INV_THR(5, regs->reg113, region);
894 SET_OSD_INV_THR(6, regs->reg113, region);
895 SET_OSD_INV_THR(7, regs->reg113, region);
896
897 return MPP_OK;
898 }
899
900 typedef struct Vepu580OsdReg_t {
901 /*
902 * OSD_INV_CFG
903 * Address offset: 0x00003000 Access type: read and write
904 * OSD color inverse configuration
905 */
906 struct {
907 /*
908 * OSD color inverse enable of luma component,
909 * each bit controls corresponding region.
910 */
911 RK_U32 osd_lu_inv_en : 8;
912
913 /* OSD color inverse enable of chroma component,
914 * each bit controls corresponding region.
915 */
916 RK_U32 osd_ch_inv_en : 8;
917 /*
918 * OSD color inverse expression switch for luma component
919 * each bit controls corresponding region.
920 * 1'h0: Expression need to determine the condition;
921 * 1'h1: Expression don't need to determine the condition;
922 */
923 RK_U32 osd_lu_inv_msk : 8;
924 /*
925 * OSD color inverse expression switch for chroma component
926 * each bit controls corresponding region.
927 * 1'h0: Expression need to determine the condition;
928 * 1'h1: Expression don't need to determine the condition;
929 */
930 RK_U32 osd_ch_inv_msk : 8;
931 } reg3072;
932
933 /*
934 * OSD_INV
935 * Address offset: 0x3004 Access type: read and write
936 * OSD color inverse configuration
937 */
938 struct {
939 /* Color inverse theshold for OSD region0. */
940 RK_U32 osd_ithd_r0 : 4;
941 /* Color inverse theshold for OSD region1. */
942 RK_U32 osd_ithd_r1 : 4;
943 /* Color inverse theshold for OSD region2. */
944 RK_U32 osd_ithd_r2 : 4;
945 /* Color inverse theshold for OSD region3. */
946 RK_U32 osd_ithd_r3 : 4;
947 /* Color inverse theshold for OSD region4. */
948 RK_U32 osd_ithd_r4 : 4;
949 /* Color inverse theshold for OSD region5. */
950 RK_U32 osd_ithd_r5 : 4;
951 /* Color inverse theshold for OSD region6. */
952 RK_U32 osd_ithd_r6 : 4;
953 /* Color inverse theshold for OSD region7. */
954 RK_U32 osd_ithd_r7 : 4;
955 } reg3073;
956
957 /*
958 * OSD_CFG
959 * Address offset: 0x3008 Access type: read and write
960 * OSD configuration
961 */
962 struct {
963 /* OSD region enable, each bit controls corresponding OSD region. */
964 RK_U32 osd_e : 8;
965 /*
966 * OSD color inverse expression type
967 * each bit controls corresponding region.
968 * 1'h0: AND;
969 * 1'h1: OR
970 */
971 RK_U32 osd_itype : 8;
972 /*
973 * OSD palette clock selection.
974 * 1'h0: Configure bus clock domain.
975 * 1'h1: Core clock domain.
976 */
977 RK_U32 osd_plt_cks : 1;
978 /*
979 * OSD palette type.
980 * 1'h1: Default type.
981 * 1'h0: User defined type.
982 */
983 RK_U32 osd_plt_typ : 1;
984 RK_U32 reserved : 14;
985 } reg3074;
986
987 RK_U32 reserved_3075;
988 /*
989 * OSD_POS reg3076_reg3091
990 * Address offset: 0x3010~0x304c Access type: read and write
991 * OSD region position
992 */
993 Vepu580OsdPos osd_pos[8];
994
995 /*
996 * ADR_OSD reg3092_reg3099
997 * Address offset: 0x00003050~reg306c Access type: read and write
998 * Base address for OSD region, 16B aligned
999 */
1000 RK_U32 osd_addr[8];
1001
1002 RK_U32 reserved3100_3103[4];
1003 Vepu541OsdPltColor plt_data[256];
1004 } Vepu580OsdReg;
1005
vepu580_set_osd(Vepu541OsdCfg * cfg)1006 MPP_RET vepu580_set_osd(Vepu541OsdCfg *cfg)
1007 {
1008 Vepu580OsdReg *regs = (Vepu580OsdReg *)cfg->reg_base;
1009 MppDev dev = cfg->dev;
1010 MppDevRegOffCfgs *reg_cfg = cfg->reg_cfg;
1011 MppEncOSDPltCfg *plt_cfg = cfg->plt_cfg;
1012 MppEncOSDData2 osd;
1013
1014 if (copy2osd2(&osd, cfg->osd_data, cfg->osd_data2))
1015 return MPP_NOK;
1016
1017 if (osd.num_region == 0)
1018 return MPP_OK;
1019
1020 if (osd.num_region > 8) {
1021 mpp_err_f("do NOT support more than 8 regions invalid num %d\n",
1022 osd.num_region);
1023 mpp_assert(osd.num_region <= 8);
1024 return MPP_NOK;
1025 }
1026
1027 if (plt_cfg->type == MPP_ENC_OSD_PLT_TYPE_USERDEF) {
1028 memcpy(regs->plt_data, plt_cfg->plt, sizeof(MppEncOSDPlt));
1029 regs->reg3074.osd_plt_cks = 1;
1030 regs->reg3074.osd_plt_typ = VEPU541_OSD_PLT_TYPE_USERDEF;
1031 } else {
1032 regs->reg3074.osd_plt_cks = 0;
1033 regs->reg3074.osd_plt_typ = VEPU541_OSD_PLT_TYPE_DEFAULT;
1034 }
1035
1036 regs->reg3074.osd_e = 0;
1037 regs->reg3072.osd_lu_inv_en = 0;
1038 regs->reg3072.osd_ch_inv_en = 0;
1039 regs->reg3072.osd_lu_inv_msk = 0;
1040 regs->reg3072.osd_ch_inv_msk = 0;
1041
1042 RK_U32 num = osd.num_region;
1043 RK_U32 k = 0;
1044 MppEncOSDRegion2 *region = osd.region;
1045 MppEncOSDRegion2 *tmp = region;
1046
1047 for (k = 0; k < num; k++, tmp++) {
1048 regs->reg3074.osd_e |= tmp->enable << k;
1049 regs->reg3072.osd_lu_inv_en |= (tmp->inverse) ? (1 << k) : 0;
1050 regs->reg3072.osd_ch_inv_en |= (tmp->inverse) ? (1 << k) : 0;
1051
1052 if (tmp->enable && tmp->num_mb_x && tmp->num_mb_y) {
1053 Vepu580OsdPos *pos = ®s->osd_pos[k];
1054 size_t blk_len = tmp->num_mb_x * tmp->num_mb_y * 256;
1055 RK_S32 fd = -1;
1056 size_t buf_size = 0;
1057
1058 pos->osd_lt_x = tmp->start_mb_x;
1059 pos->osd_lt_y = tmp->start_mb_y;
1060 pos->osd_rb_x = tmp->start_mb_x + tmp->num_mb_x - 1;
1061 pos->osd_rb_y = tmp->start_mb_y + tmp->num_mb_y - 1;
1062
1063 buf_size = mpp_buffer_get_size(tmp->buf);
1064 fd = mpp_buffer_get_fd(tmp->buf);
1065 if (fd < 0) {
1066 mpp_err_f("invalid osd buffer fd %d\n", fd);
1067 return MPP_NOK;
1068 }
1069 regs->osd_addr[k] = fd;
1070
1071 if (tmp->buf_offset) {
1072 if (reg_cfg)
1073 mpp_dev_multi_offset_update(reg_cfg, VEPU580_OSD_ADDR_IDX_BASE + k, tmp->buf_offset);
1074 else
1075 mpp_dev_set_reg_offset(dev, VEPU580_OSD_ADDR_IDX_BASE + k, tmp->buf_offset);
1076 }
1077
1078 /* There should be enough buffer and offset should be 16B aligned */
1079 if (buf_size < tmp->buf_offset + blk_len ||
1080 (tmp->buf_offset & 0xf)) {
1081 mpp_err_f("invalid osd cfg: %d x:y:w:h:off %d:%d:%d:%d:%x size %x\n",
1082 k, tmp->start_mb_x, tmp->start_mb_y,
1083 tmp->num_mb_x, tmp->num_mb_y, tmp->buf_offset, buf_size);
1084 }
1085 }
1086 }
1087
1088 SET_OSD_INV_THR(0, regs->reg3073, region);
1089 SET_OSD_INV_THR(1, regs->reg3073, region);
1090 SET_OSD_INV_THR(2, regs->reg3073, region);
1091 SET_OSD_INV_THR(3, regs->reg3073, region);
1092 SET_OSD_INV_THR(4, regs->reg3073, region);
1093 SET_OSD_INV_THR(5, regs->reg3073, region);
1094 SET_OSD_INV_THR(6, regs->reg3073, region);
1095 SET_OSD_INV_THR(7, regs->reg3073, region);
1096
1097 return MPP_OK;
1098 }
1099