1 // SPDX-License-Identifier: GPL-2.0
2 /*
3 * Support for Intel Camera Imaging ISP subsystem.
4 * Copyright (c) 2015, Intel Corporation.
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms and conditions of the GNU General Public License,
8 * version 2, as published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
13 * more details.
14 */
15
16 #include "hmm.h"
17
18 #include "ia_css_frame.h"
19 #include <math_support.h>
20 #include "assert_support.h"
21 #include "ia_css_debug.h"
22 #include "isp.h"
23 #include "sh_css_internal.h"
24 #include "atomisp_internal.h"
25
26 #define NV12_TILEY_TILE_WIDTH 128
27 #define NV12_TILEY_TILE_HEIGHT 32
28
29 /**************************************************************************
30 ** Static functions declarations
31 **************************************************************************/
32 static void frame_init_plane(struct ia_css_frame_plane *plane,
33 unsigned int width,
34 unsigned int stride,
35 unsigned int height,
36 unsigned int offset);
37
38 static void frame_init_single_plane(struct ia_css_frame *frame,
39 struct ia_css_frame_plane *plane,
40 unsigned int height,
41 unsigned int subpixels_per_line,
42 unsigned int bytes_per_pixel);
43
44 static void frame_init_raw_single_plane(
45 struct ia_css_frame *frame,
46 struct ia_css_frame_plane *plane,
47 unsigned int height,
48 unsigned int subpixels_per_line,
49 unsigned int bits_per_pixel);
50
51 static void frame_init_mipi_plane(struct ia_css_frame *frame,
52 struct ia_css_frame_plane *plane,
53 unsigned int height,
54 unsigned int subpixels_per_line,
55 unsigned int bytes_per_pixel);
56
57 static void frame_init_nv_planes(struct ia_css_frame *frame,
58 unsigned int horizontal_decimation,
59 unsigned int vertical_decimation,
60 unsigned int bytes_per_element);
61
62 static void frame_init_yuv_planes(struct ia_css_frame *frame,
63 unsigned int horizontal_decimation,
64 unsigned int vertical_decimation,
65 bool swap_uv,
66 unsigned int bytes_per_element);
67
68 static void frame_init_rgb_planes(struct ia_css_frame *frame,
69 unsigned int bytes_per_element);
70
71 static void frame_init_qplane6_planes(struct ia_css_frame *frame);
72
73 static int frame_allocate_buffer_data(struct ia_css_frame *frame);
74
75 static int frame_allocate_with_data(struct ia_css_frame **frame,
76 unsigned int width,
77 unsigned int height,
78 enum ia_css_frame_format format,
79 unsigned int padded_width,
80 unsigned int raw_bit_depth,
81 bool contiguous);
82
83 static struct ia_css_frame *frame_create(unsigned int width,
84 unsigned int height,
85 enum ia_css_frame_format format,
86 unsigned int padded_width,
87 unsigned int raw_bit_depth,
88 bool contiguous,
89 bool valid);
90
91 static unsigned
92 ia_css_elems_bytes_from_info(
93 const struct ia_css_frame_info *info);
94
95 /**************************************************************************
96 ** CSS API functions, exposed by ia_css.h
97 **************************************************************************/
98
ia_css_frame_zero(struct ia_css_frame * frame)99 void ia_css_frame_zero(struct ia_css_frame *frame)
100 {
101 assert(frame);
102 hmm_set(frame->data, 0, frame->data_bytes);
103 }
104
ia_css_frame_allocate_from_info(struct ia_css_frame ** frame,const struct ia_css_frame_info * info)105 int ia_css_frame_allocate_from_info(struct ia_css_frame **frame,
106 const struct ia_css_frame_info *info)
107 {
108 int err = 0;
109
110 if (!frame || !info)
111 return -EINVAL;
112 ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
113 "ia_css_frame_allocate_from_info() enter:\n");
114 err =
115 ia_css_frame_allocate(frame, info->res.width, info->res.height,
116 info->format, info->padded_width,
117 info->raw_bit_depth);
118 ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
119 "ia_css_frame_allocate_from_info() leave:\n");
120 return err;
121 }
122
ia_css_frame_allocate(struct ia_css_frame ** frame,unsigned int width,unsigned int height,enum ia_css_frame_format format,unsigned int padded_width,unsigned int raw_bit_depth)123 int ia_css_frame_allocate(struct ia_css_frame **frame,
124 unsigned int width,
125 unsigned int height,
126 enum ia_css_frame_format format,
127 unsigned int padded_width,
128 unsigned int raw_bit_depth)
129 {
130 int err = 0;
131
132 if (!frame || width == 0 || height == 0)
133 return -EINVAL;
134
135 ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
136 "ia_css_frame_allocate() enter: width=%d, height=%d, format=%d, padded_width=%d, raw_bit_depth=%d\n",
137 width, height, format, padded_width, raw_bit_depth);
138
139 err = frame_allocate_with_data(frame, width, height, format,
140 padded_width, raw_bit_depth, false);
141
142 if ((*frame) && err == 0)
143 ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
144 "ia_css_frame_allocate() leave: frame=%p, data(DDR address)=0x%x\n", *frame,
145 (*frame)->data);
146 else
147 ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
148 "ia_css_frame_allocate() leave: frame=%p, data(DDR address)=0x%x\n",
149 (void *)-1, (unsigned int)-1);
150
151 return err;
152 }
153
ia_css_frame_map(struct ia_css_frame ** frame,const struct ia_css_frame_info * info,const void __user * data,u16 attribute,unsigned int pgnr)154 int ia_css_frame_map(struct ia_css_frame **frame,
155 const struct ia_css_frame_info *info,
156 const void __user *data,
157 u16 attribute,
158 unsigned int pgnr)
159 {
160 int err = 0;
161 struct ia_css_frame *me;
162
163 assert(frame);
164
165 /* Create the frame structure */
166 err = ia_css_frame_create_from_info(&me, info);
167
168 if (err)
169 return err;
170
171 if (!err) {
172 if (pgnr < ((PAGE_ALIGN(me->data_bytes)) >> PAGE_SHIFT)) {
173 dev_err(atomisp_dev,
174 "user space memory size is less than the expected size..\n");
175 err = -ENOMEM;
176 goto error;
177 } else if (pgnr > ((PAGE_ALIGN(me->data_bytes)) >> PAGE_SHIFT)) {
178 dev_err(atomisp_dev,
179 "user space memory size is large than the expected size..\n");
180 err = -ENOMEM;
181 goto error;
182 }
183
184 me->data = hmm_alloc(me->data_bytes, HMM_BO_USER, 0, data,
185 attribute & ATOMISP_MAP_FLAG_CACHED);
186
187 if (me->data == mmgr_NULL)
188 err = -EINVAL;
189 }
190
191 error:
192 if (err) {
193 kvfree(me);
194 me = NULL;
195 }
196
197 *frame = me;
198
199 return err;
200 }
201
ia_css_frame_create_from_info(struct ia_css_frame ** frame,const struct ia_css_frame_info * info)202 int ia_css_frame_create_from_info(struct ia_css_frame **frame,
203 const struct ia_css_frame_info *info)
204 {
205 int err = 0;
206 struct ia_css_frame *me;
207
208 ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
209 "ia_css_frame_create_from_info() enter:\n");
210 if (!frame || !info) {
211 ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
212 "ia_css_frame_create_from_info() leave: invalid arguments\n");
213 return -EINVAL;
214 }
215
216 me = frame_create(info->res.width,
217 info->res.height,
218 info->format,
219 info->padded_width,
220 info->raw_bit_depth,
221 false,
222 false);
223 if (!me) {
224 ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
225 "ia_css_frame_create_from_info() leave: frame create failed\n");
226 return -ENOMEM;
227 }
228
229 err = ia_css_frame_init_planes(me);
230
231 if (err) {
232 kvfree(me);
233 me = NULL;
234 }
235
236 *frame = me;
237
238 ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
239 "ia_css_frame_create_from_info() leave:\n");
240
241 return err;
242 }
243
ia_css_frame_set_data(struct ia_css_frame * frame,const ia_css_ptr mapped_data,size_t data_bytes)244 int ia_css_frame_set_data(struct ia_css_frame *frame,
245 const ia_css_ptr mapped_data,
246 size_t data_bytes)
247 {
248 int err = 0;
249
250 ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
251 "ia_css_frame_set_data() enter:\n");
252 if (!frame) {
253 ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
254 "ia_css_frame_set_data() leave: NULL frame\n");
255 return -EINVAL;
256 }
257
258 /* If we are setting a valid data.
259 * Make sure that there is enough
260 * room for the expected frame format
261 */
262 if ((mapped_data != mmgr_NULL) && (frame->data_bytes > data_bytes)) {
263 ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
264 "ia_css_frame_set_data() leave: invalid arguments\n");
265 return -EINVAL;
266 }
267
268 frame->data = mapped_data;
269
270 ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "ia_css_frame_set_data() leave:\n");
271
272 return err;
273 }
274
ia_css_frame_allocate_contiguous(struct ia_css_frame ** frame,unsigned int width,unsigned int height,enum ia_css_frame_format format,unsigned int padded_width,unsigned int raw_bit_depth)275 int ia_css_frame_allocate_contiguous(struct ia_css_frame **frame,
276 unsigned int width,
277 unsigned int height,
278 enum ia_css_frame_format format,
279 unsigned int padded_width,
280 unsigned int raw_bit_depth)
281 {
282 int err = 0;
283
284 ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
285 "ia_css_frame_allocate_contiguous() enter: width=%d, height=%d, format=%d, padded_width=%d, raw_bit_depth=%d\n",
286 width, height, format, padded_width, raw_bit_depth);
287
288 err = frame_allocate_with_data(frame, width, height, format,
289 padded_width, raw_bit_depth, true);
290
291 ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
292 "ia_css_frame_allocate_contiguous() leave: frame=%p\n",
293 frame ? *frame : (void *)-1);
294
295 return err;
296 }
297
ia_css_frame_allocate_contiguous_from_info(struct ia_css_frame ** frame,const struct ia_css_frame_info * info)298 int ia_css_frame_allocate_contiguous_from_info(
299 struct ia_css_frame **frame,
300 const struct ia_css_frame_info *info)
301 {
302 int err = 0;
303
304 assert(frame);
305 ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
306 "ia_css_frame_allocate_contiguous_from_info() enter:\n");
307 err = ia_css_frame_allocate_contiguous(frame,
308 info->res.width,
309 info->res.height,
310 info->format,
311 info->padded_width,
312 info->raw_bit_depth);
313 ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
314 "ia_css_frame_allocate_contiguous_from_info() leave:\n");
315 return err;
316 }
317
ia_css_frame_free(struct ia_css_frame * frame)318 void ia_css_frame_free(struct ia_css_frame *frame)
319 {
320 IA_CSS_ENTER_PRIVATE("frame = %p", frame);
321
322 if (frame) {
323 hmm_free(frame->data);
324 kvfree(frame);
325 }
326
327 IA_CSS_LEAVE_PRIVATE("void");
328 }
329
330 /**************************************************************************
331 ** Module public functions
332 **************************************************************************/
333
ia_css_frame_check_info(const struct ia_css_frame_info * info)334 int ia_css_frame_check_info(const struct ia_css_frame_info *info)
335 {
336 assert(info);
337 if (info->res.width == 0 || info->res.height == 0)
338 return -EINVAL;
339 return 0;
340 }
341
ia_css_frame_init_planes(struct ia_css_frame * frame)342 int ia_css_frame_init_planes(struct ia_css_frame *frame)
343 {
344 assert(frame);
345
346 switch (frame->info.format) {
347 case IA_CSS_FRAME_FORMAT_MIPI:
348 frame_init_mipi_plane(frame, &frame->planes.raw,
349 frame->info.res.height,
350 frame->info.padded_width,
351 frame->info.raw_bit_depth <= 8 ? 1 : 2);
352 break;
353 case IA_CSS_FRAME_FORMAT_RAW_PACKED:
354 frame_init_raw_single_plane(frame, &frame->planes.raw,
355 frame->info.res.height,
356 frame->info.padded_width,
357 frame->info.raw_bit_depth);
358 break;
359 case IA_CSS_FRAME_FORMAT_RAW:
360 frame_init_single_plane(frame, &frame->planes.raw,
361 frame->info.res.height,
362 frame->info.padded_width,
363 frame->info.raw_bit_depth <= 8 ? 1 : 2);
364 break;
365 case IA_CSS_FRAME_FORMAT_RGB565:
366 frame_init_single_plane(frame, &frame->planes.rgb,
367 frame->info.res.height,
368 frame->info.padded_width, 2);
369 break;
370 case IA_CSS_FRAME_FORMAT_RGBA888:
371 frame_init_single_plane(frame, &frame->planes.rgb,
372 frame->info.res.height,
373 frame->info.padded_width * 4, 1);
374 break;
375 case IA_CSS_FRAME_FORMAT_PLANAR_RGB888:
376 frame_init_rgb_planes(frame, 1);
377 break;
378 /* yuyv and uyvu have the same frame layout, only the data
379 * positioning differs.
380 */
381 case IA_CSS_FRAME_FORMAT_YUYV:
382 case IA_CSS_FRAME_FORMAT_UYVY:
383 case IA_CSS_FRAME_FORMAT_CSI_MIPI_YUV420_8:
384 case IA_CSS_FRAME_FORMAT_CSI_MIPI_LEGACY_YUV420_8:
385 frame_init_single_plane(frame, &frame->planes.yuyv,
386 frame->info.res.height,
387 frame->info.padded_width * 2, 1);
388 break;
389 case IA_CSS_FRAME_FORMAT_YUV_LINE:
390 /* Needs 3 extra lines to allow vf_pp prefetching */
391 frame_init_single_plane(frame, &frame->planes.yuyv,
392 frame->info.res.height * 3 / 2 + 3,
393 frame->info.padded_width, 1);
394 break;
395 case IA_CSS_FRAME_FORMAT_NV11:
396 frame_init_nv_planes(frame, 4, 1, 1);
397 break;
398 /* nv12 and nv21 have the same frame layout, only the data
399 * positioning differs.
400 */
401 case IA_CSS_FRAME_FORMAT_NV12:
402 case IA_CSS_FRAME_FORMAT_NV21:
403 case IA_CSS_FRAME_FORMAT_NV12_TILEY:
404 frame_init_nv_planes(frame, 2, 2, 1);
405 break;
406 case IA_CSS_FRAME_FORMAT_NV12_16:
407 frame_init_nv_planes(frame, 2, 2, 2);
408 break;
409 /* nv16 and nv61 have the same frame layout, only the data
410 * positioning differs.
411 */
412 case IA_CSS_FRAME_FORMAT_NV16:
413 case IA_CSS_FRAME_FORMAT_NV61:
414 frame_init_nv_planes(frame, 2, 1, 1);
415 break;
416 case IA_CSS_FRAME_FORMAT_YUV420:
417 frame_init_yuv_planes(frame, 2, 2, false, 1);
418 break;
419 case IA_CSS_FRAME_FORMAT_YUV422:
420 frame_init_yuv_planes(frame, 2, 1, false, 1);
421 break;
422 case IA_CSS_FRAME_FORMAT_YUV444:
423 frame_init_yuv_planes(frame, 1, 1, false, 1);
424 break;
425 case IA_CSS_FRAME_FORMAT_YUV420_16:
426 frame_init_yuv_planes(frame, 2, 2, false, 2);
427 break;
428 case IA_CSS_FRAME_FORMAT_YUV422_16:
429 frame_init_yuv_planes(frame, 2, 1, false, 2);
430 break;
431 case IA_CSS_FRAME_FORMAT_YV12:
432 frame_init_yuv_planes(frame, 2, 2, true, 1);
433 break;
434 case IA_CSS_FRAME_FORMAT_YV16:
435 frame_init_yuv_planes(frame, 2, 1, true, 1);
436 break;
437 case IA_CSS_FRAME_FORMAT_QPLANE6:
438 frame_init_qplane6_planes(frame);
439 break;
440 case IA_CSS_FRAME_FORMAT_BINARY_8:
441 frame_init_single_plane(frame, &frame->planes.binary.data,
442 frame->info.res.height,
443 frame->info.padded_width, 1);
444 frame->planes.binary.size = 0;
445 break;
446 default:
447 return -EINVAL;
448 }
449 return 0;
450 }
451
ia_css_frame_info_set_width(struct ia_css_frame_info * info,unsigned int width,unsigned int min_padded_width)452 void ia_css_frame_info_set_width(struct ia_css_frame_info *info,
453 unsigned int width,
454 unsigned int min_padded_width)
455 {
456 unsigned int align;
457
458 IA_CSS_ENTER_PRIVATE("info = %p,width = %d, minimum padded width = %d",
459 info, width, min_padded_width);
460 if (!info) {
461 IA_CSS_ERROR("NULL input parameter");
462 IA_CSS_LEAVE_PRIVATE("");
463 return;
464 }
465 if (min_padded_width > width)
466 align = min_padded_width;
467 else
468 align = width;
469
470 info->res.width = width;
471 /* frames with a U and V plane of 8 bits per pixel need to have
472 all planes aligned, this means double the alignment for the
473 Y plane if the horizontal decimation is 2. */
474 if (info->format == IA_CSS_FRAME_FORMAT_YUV420 ||
475 info->format == IA_CSS_FRAME_FORMAT_YV12 ||
476 info->format == IA_CSS_FRAME_FORMAT_NV12 ||
477 info->format == IA_CSS_FRAME_FORMAT_NV21 ||
478 info->format == IA_CSS_FRAME_FORMAT_BINARY_8 ||
479 info->format == IA_CSS_FRAME_FORMAT_YUV_LINE)
480 info->padded_width =
481 CEIL_MUL(align, 2 * HIVE_ISP_DDR_WORD_BYTES);
482 else if (info->format == IA_CSS_FRAME_FORMAT_NV12_TILEY)
483 info->padded_width = CEIL_MUL(align, NV12_TILEY_TILE_WIDTH);
484 else if (info->format == IA_CSS_FRAME_FORMAT_RAW ||
485 info->format == IA_CSS_FRAME_FORMAT_RAW_PACKED)
486 info->padded_width = CEIL_MUL(align, 2 * ISP_VEC_NELEMS);
487 else {
488 info->padded_width = CEIL_MUL(align, HIVE_ISP_DDR_WORD_BYTES);
489 }
490 IA_CSS_LEAVE_PRIVATE("");
491 }
492
ia_css_frame_info_set_format(struct ia_css_frame_info * info,enum ia_css_frame_format format)493 void ia_css_frame_info_set_format(struct ia_css_frame_info *info,
494 enum ia_css_frame_format format)
495 {
496 assert(info);
497 ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
498 "ia_css_frame_info_set_format() enter:\n");
499 info->format = format;
500 }
501
ia_css_frame_info_init(struct ia_css_frame_info * info,unsigned int width,unsigned int height,enum ia_css_frame_format format,unsigned int aligned)502 void ia_css_frame_info_init(struct ia_css_frame_info *info,
503 unsigned int width,
504 unsigned int height,
505 enum ia_css_frame_format format,
506 unsigned int aligned)
507 {
508 IA_CSS_ENTER_PRIVATE("info = %p, width = %d, height = %d, format = %d, aligned = %d",
509 info, width, height, format, aligned);
510 if (!info) {
511 IA_CSS_ERROR("NULL input parameter");
512 IA_CSS_LEAVE_PRIVATE("");
513 return;
514 }
515 info->res.height = height;
516 info->format = format;
517 ia_css_frame_info_set_width(info, width, aligned);
518 IA_CSS_LEAVE_PRIVATE("");
519 }
520
ia_css_frame_free_multiple(unsigned int num_frames,struct ia_css_frame ** frames_array)521 void ia_css_frame_free_multiple(unsigned int num_frames,
522 struct ia_css_frame **frames_array)
523 {
524 unsigned int i;
525
526 for (i = 0; i < num_frames; i++) {
527 if (frames_array[i]) {
528 ia_css_frame_free(frames_array[i]);
529 frames_array[i] = NULL;
530 }
531 }
532 }
533
ia_css_frame_allocate_with_buffer_size(struct ia_css_frame ** frame,const unsigned int buffer_size_bytes,const bool contiguous)534 int ia_css_frame_allocate_with_buffer_size(
535 struct ia_css_frame **frame,
536 const unsigned int buffer_size_bytes,
537 const bool contiguous)
538 {
539 /* AM: Body coppied from frame_allocate_with_data(). */
540 int err;
541 struct ia_css_frame *me = frame_create(0, 0,
542 IA_CSS_FRAME_FORMAT_NUM,/* Not valid format yet */
543 0, 0, contiguous, false);
544
545 if (!me)
546 return -ENOMEM;
547
548 /* Get the data size */
549 me->data_bytes = buffer_size_bytes;
550
551 err = frame_allocate_buffer_data(me);
552
553 if (err) {
554 kvfree(me);
555 me = NULL;
556 }
557
558 *frame = me;
559
560 return err;
561 }
562
ia_css_frame_info_is_same_resolution(const struct ia_css_frame_info * info_a,const struct ia_css_frame_info * info_b)563 bool ia_css_frame_info_is_same_resolution(
564 const struct ia_css_frame_info *info_a,
565 const struct ia_css_frame_info *info_b)
566 {
567 if (!info_a || !info_b)
568 return false;
569 return (info_a->res.width == info_b->res.width) &&
570 (info_a->res.height == info_b->res.height);
571 }
572
ia_css_frame_is_same_type(const struct ia_css_frame * frame_a,const struct ia_css_frame * frame_b)573 bool ia_css_frame_is_same_type(const struct ia_css_frame *frame_a,
574 const struct ia_css_frame *frame_b)
575 {
576 bool is_equal = false;
577 const struct ia_css_frame_info *info_a = &frame_a->info,
578 *info_b = &frame_b->info;
579
580 ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
581 "ia_css_frame_is_same_type() enter:\n");
582
583 if (!info_a || !info_b)
584 return false;
585 if (info_a->format != info_b->format)
586 return false;
587 if (info_a->padded_width != info_b->padded_width)
588 return false;
589 is_equal = ia_css_frame_info_is_same_resolution(info_a, info_b);
590
591 ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
592 "ia_css_frame_is_same_type() leave:\n");
593
594 return is_equal;
595 }
596
597 void
ia_css_dma_configure_from_info(struct dma_port_config * config,const struct ia_css_frame_info * info)598 ia_css_dma_configure_from_info(
599 struct dma_port_config *config,
600 const struct ia_css_frame_info *info)
601 {
602 unsigned int is_raw_packed = info->format == IA_CSS_FRAME_FORMAT_RAW_PACKED;
603 unsigned int bits_per_pixel = is_raw_packed ? info->raw_bit_depth :
604 ia_css_elems_bytes_from_info(info) * 8;
605 unsigned int pix_per_ddrword = HIVE_ISP_DDR_WORD_BITS / bits_per_pixel;
606 unsigned int words_per_line = CEIL_DIV(info->padded_width, pix_per_ddrword);
607 unsigned int elems_b = pix_per_ddrword;
608
609 config->stride = HIVE_ISP_DDR_WORD_BYTES * words_per_line;
610 config->elems = (uint8_t)elems_b;
611 config->width = (uint16_t)info->res.width;
612 config->crop = 0;
613 assert(config->width <= info->padded_width);
614 }
615
616 /**************************************************************************
617 ** Static functions
618 **************************************************************************/
619
frame_init_plane(struct ia_css_frame_plane * plane,unsigned int width,unsigned int stride,unsigned int height,unsigned int offset)620 static void frame_init_plane(struct ia_css_frame_plane *plane,
621 unsigned int width,
622 unsigned int stride,
623 unsigned int height,
624 unsigned int offset)
625 {
626 plane->height = height;
627 plane->width = width;
628 plane->stride = stride;
629 plane->offset = offset;
630 }
631
frame_init_single_plane(struct ia_css_frame * frame,struct ia_css_frame_plane * plane,unsigned int height,unsigned int subpixels_per_line,unsigned int bytes_per_pixel)632 static void frame_init_single_plane(struct ia_css_frame *frame,
633 struct ia_css_frame_plane *plane,
634 unsigned int height,
635 unsigned int subpixels_per_line,
636 unsigned int bytes_per_pixel)
637 {
638 unsigned int stride;
639
640 stride = subpixels_per_line * bytes_per_pixel;
641 /* Frame height needs to be even number - needed by hw ISYS2401
642 In case of odd number, round up to even.
643 Images won't be impacted by this round up,
644 only needed by jpeg/embedded data.
645 As long as buffer allocation and release are using data_bytes,
646 there won't be memory leak. */
647 frame->data_bytes = stride * CEIL_MUL2(height, 2);
648 frame_init_plane(plane, subpixels_per_line, stride, height, 0);
649 return;
650 }
651
frame_init_raw_single_plane(struct ia_css_frame * frame,struct ia_css_frame_plane * plane,unsigned int height,unsigned int subpixels_per_line,unsigned int bits_per_pixel)652 static void frame_init_raw_single_plane(
653 struct ia_css_frame *frame,
654 struct ia_css_frame_plane *plane,
655 unsigned int height,
656 unsigned int subpixels_per_line,
657 unsigned int bits_per_pixel)
658 {
659 unsigned int stride;
660
661 assert(frame);
662
663 stride = HIVE_ISP_DDR_WORD_BYTES *
664 CEIL_DIV(subpixels_per_line,
665 HIVE_ISP_DDR_WORD_BITS / bits_per_pixel);
666 frame->data_bytes = stride * height;
667 frame_init_plane(plane, subpixels_per_line, stride, height, 0);
668 return;
669 }
670
frame_init_mipi_plane(struct ia_css_frame * frame,struct ia_css_frame_plane * plane,unsigned int height,unsigned int subpixels_per_line,unsigned int bytes_per_pixel)671 static void frame_init_mipi_plane(struct ia_css_frame *frame,
672 struct ia_css_frame_plane *plane,
673 unsigned int height,
674 unsigned int subpixels_per_line,
675 unsigned int bytes_per_pixel)
676 {
677 unsigned int stride;
678
679 stride = subpixels_per_line * bytes_per_pixel;
680 frame->data_bytes = 8388608; /* 8*1024*1024 */
681 frame->valid = false;
682 frame->contiguous = true;
683 frame_init_plane(plane, subpixels_per_line, stride, height, 0);
684 return;
685 }
686
frame_init_nv_planes(struct ia_css_frame * frame,unsigned int horizontal_decimation,unsigned int vertical_decimation,unsigned int bytes_per_element)687 static void frame_init_nv_planes(struct ia_css_frame *frame,
688 unsigned int horizontal_decimation,
689 unsigned int vertical_decimation,
690 unsigned int bytes_per_element)
691 {
692 unsigned int y_width = frame->info.padded_width;
693 unsigned int y_height = frame->info.res.height;
694 unsigned int uv_width;
695 unsigned int uv_height;
696 unsigned int y_bytes;
697 unsigned int uv_bytes;
698 unsigned int y_stride;
699 unsigned int uv_stride;
700
701 assert(horizontal_decimation != 0 && vertical_decimation != 0);
702
703 uv_width = 2 * (y_width / horizontal_decimation);
704 uv_height = y_height / vertical_decimation;
705
706 if (frame->info.format == IA_CSS_FRAME_FORMAT_NV12_TILEY) {
707 y_width = CEIL_MUL(y_width, NV12_TILEY_TILE_WIDTH);
708 uv_width = CEIL_MUL(uv_width, NV12_TILEY_TILE_WIDTH);
709 y_height = CEIL_MUL(y_height, NV12_TILEY_TILE_HEIGHT);
710 uv_height = CEIL_MUL(uv_height, NV12_TILEY_TILE_HEIGHT);
711 }
712
713 y_stride = y_width * bytes_per_element;
714 uv_stride = uv_width * bytes_per_element;
715 y_bytes = y_stride * y_height;
716 uv_bytes = uv_stride * uv_height;
717
718 frame->data_bytes = y_bytes + uv_bytes;
719 frame_init_plane(&frame->planes.nv.y, y_width, y_stride, y_height, 0);
720 frame_init_plane(&frame->planes.nv.uv, uv_width,
721 uv_stride, uv_height, y_bytes);
722 return;
723 }
724
frame_init_yuv_planes(struct ia_css_frame * frame,unsigned int horizontal_decimation,unsigned int vertical_decimation,bool swap_uv,unsigned int bytes_per_element)725 static void frame_init_yuv_planes(struct ia_css_frame *frame,
726 unsigned int horizontal_decimation,
727 unsigned int vertical_decimation,
728 bool swap_uv,
729 unsigned int bytes_per_element)
730 {
731 unsigned int y_width = frame->info.padded_width,
732 y_height = frame->info.res.height,
733 uv_width = y_width / horizontal_decimation,
734 uv_height = y_height / vertical_decimation,
735 y_stride, y_bytes, uv_bytes, uv_stride;
736
737 y_stride = y_width * bytes_per_element;
738 uv_stride = uv_width * bytes_per_element;
739 y_bytes = y_stride * y_height;
740 uv_bytes = uv_stride * uv_height;
741
742 frame->data_bytes = y_bytes + 2 * uv_bytes;
743 frame_init_plane(&frame->planes.yuv.y, y_width, y_stride, y_height, 0);
744 if (swap_uv) {
745 frame_init_plane(&frame->planes.yuv.v, uv_width, uv_stride,
746 uv_height, y_bytes);
747 frame_init_plane(&frame->planes.yuv.u, uv_width, uv_stride,
748 uv_height, y_bytes + uv_bytes);
749 } else {
750 frame_init_plane(&frame->planes.yuv.u, uv_width, uv_stride,
751 uv_height, y_bytes);
752 frame_init_plane(&frame->planes.yuv.v, uv_width, uv_stride,
753 uv_height, y_bytes + uv_bytes);
754 }
755 return;
756 }
757
frame_init_rgb_planes(struct ia_css_frame * frame,unsigned int bytes_per_element)758 static void frame_init_rgb_planes(struct ia_css_frame *frame,
759 unsigned int bytes_per_element)
760 {
761 unsigned int width = frame->info.res.width,
762 height = frame->info.res.height, stride, bytes;
763
764 stride = width * bytes_per_element;
765 bytes = stride * height;
766 frame->data_bytes = 3 * bytes;
767 frame_init_plane(&frame->planes.planar_rgb.r, width, stride, height, 0);
768 frame_init_plane(&frame->planes.planar_rgb.g,
769 width, stride, height, 1 * bytes);
770 frame_init_plane(&frame->planes.planar_rgb.b,
771 width, stride, height, 2 * bytes);
772 return;
773 }
774
frame_init_qplane6_planes(struct ia_css_frame * frame)775 static void frame_init_qplane6_planes(struct ia_css_frame *frame)
776 {
777 unsigned int width = frame->info.padded_width / 2,
778 height = frame->info.res.height / 2, bytes, stride;
779
780 stride = width * 2;
781 bytes = stride * height;
782
783 frame->data_bytes = 6 * bytes;
784 frame_init_plane(&frame->planes.plane6.r,
785 width, stride, height, 0 * bytes);
786 frame_init_plane(&frame->planes.plane6.r_at_b,
787 width, stride, height, 1 * bytes);
788 frame_init_plane(&frame->planes.plane6.gr,
789 width, stride, height, 2 * bytes);
790 frame_init_plane(&frame->planes.plane6.gb,
791 width, stride, height, 3 * bytes);
792 frame_init_plane(&frame->planes.plane6.b,
793 width, stride, height, 4 * bytes);
794 frame_init_plane(&frame->planes.plane6.b_at_r,
795 width, stride, height, 5 * bytes);
796 return;
797 }
798
frame_allocate_buffer_data(struct ia_css_frame * frame)799 static int frame_allocate_buffer_data(struct ia_css_frame *frame)
800 {
801 #ifdef ISP2401
802 IA_CSS_ENTER_LEAVE_PRIVATE("frame->data_bytes=%d\n", frame->data_bytes);
803 #endif
804 frame->data = hmm_alloc(frame->data_bytes,
805 HMM_BO_PRIVATE, 0, NULL,
806 frame->contiguous ?
807 ATOMISP_MAP_FLAG_CONTIGUOUS : 0);
808
809 if (frame->data == mmgr_NULL)
810 return -ENOMEM;
811 return 0;
812 }
813
frame_allocate_with_data(struct ia_css_frame ** frame,unsigned int width,unsigned int height,enum ia_css_frame_format format,unsigned int padded_width,unsigned int raw_bit_depth,bool contiguous)814 static int frame_allocate_with_data(struct ia_css_frame **frame,
815 unsigned int width,
816 unsigned int height,
817 enum ia_css_frame_format format,
818 unsigned int padded_width,
819 unsigned int raw_bit_depth,
820 bool contiguous)
821 {
822 int err;
823 struct ia_css_frame *me = frame_create(width,
824 height,
825 format,
826 padded_width,
827 raw_bit_depth,
828 contiguous,
829 true);
830
831 if (!me)
832 return -ENOMEM;
833
834 err = ia_css_frame_init_planes(me);
835
836 if (!err)
837 err = frame_allocate_buffer_data(me);
838
839 if (err) {
840 kvfree(me);
841 #ifndef ISP2401
842 return err;
843 #else
844 me = NULL;
845 #endif
846 }
847
848 *frame = me;
849
850 return err;
851 }
852
frame_create(unsigned int width,unsigned int height,enum ia_css_frame_format format,unsigned int padded_width,unsigned int raw_bit_depth,bool contiguous,bool valid)853 static struct ia_css_frame *frame_create(unsigned int width,
854 unsigned int height,
855 enum ia_css_frame_format format,
856 unsigned int padded_width,
857 unsigned int raw_bit_depth,
858 bool contiguous,
859 bool valid)
860 {
861 struct ia_css_frame *me = kvmalloc(sizeof(*me), GFP_KERNEL);
862
863 if (!me)
864 return NULL;
865
866 memset(me, 0, sizeof(*me));
867 me->info.res.width = width;
868 me->info.res.height = height;
869 me->info.format = format;
870 me->info.padded_width = padded_width;
871 me->info.raw_bit_depth = raw_bit_depth;
872 me->contiguous = contiguous;
873 me->valid = valid;
874 me->data_bytes = 0;
875 me->data = mmgr_NULL;
876 /* To indicate it is not valid frame. */
877 me->dynamic_queue_id = (int)SH_CSS_INVALID_QUEUE_ID;
878 me->buf_type = IA_CSS_BUFFER_TYPE_INVALID;
879
880 return me;
881 }
882
883 static unsigned
ia_css_elems_bytes_from_info(const struct ia_css_frame_info * info)884 ia_css_elems_bytes_from_info(const struct ia_css_frame_info *info)
885 {
886 if (info->format == IA_CSS_FRAME_FORMAT_RGB565)
887 return 2; /* bytes per pixel */
888 if (info->format == IA_CSS_FRAME_FORMAT_YUV420_16)
889 return 2; /* bytes per pixel */
890 if (info->format == IA_CSS_FRAME_FORMAT_YUV422_16)
891 return 2; /* bytes per pixel */
892 /* Note: Essentially NV12_16 is a 2 bytes per pixel format, this return value is used
893 * to configure DMA for the output buffer,
894 * At least in SKC this data is overwritten by isp_output_init.sp.c except for elements(elems),
895 * which is configured from this return value,
896 * NV12_16 is implemented by a double buffer of 8 bit elements hence elems should be configured as 8 */
897 if (info->format == IA_CSS_FRAME_FORMAT_NV12_16)
898 return 1; /* bytes per pixel */
899
900 if (info->format == IA_CSS_FRAME_FORMAT_RAW
901 || (info->format == IA_CSS_FRAME_FORMAT_RAW_PACKED)) {
902 if (info->raw_bit_depth)
903 return CEIL_DIV(info->raw_bit_depth, 8);
904 else
905 return 2; /* bytes per pixel */
906 }
907 if (info->format == IA_CSS_FRAME_FORMAT_PLANAR_RGB888)
908 return 3; /* bytes per pixel */
909 if (info->format == IA_CSS_FRAME_FORMAT_RGBA888)
910 return 4; /* bytes per pixel */
911 if (info->format == IA_CSS_FRAME_FORMAT_QPLANE6)
912 return 2; /* bytes per pixel */
913 return 1; /* Default is 1 byte per pixel */
914 }
915
ia_css_frame_info_to_frame_sp_info(struct ia_css_frame_sp_info * to,const struct ia_css_frame_info * from)916 void ia_css_frame_info_to_frame_sp_info(
917 struct ia_css_frame_sp_info *to,
918 const struct ia_css_frame_info *from)
919 {
920 ia_css_resolution_to_sp_resolution(&to->res, &from->res);
921 to->padded_width = (uint16_t)from->padded_width;
922 to->format = (uint8_t)from->format;
923 to->raw_bit_depth = (uint8_t)from->raw_bit_depth;
924 to->raw_bayer_order = from->raw_bayer_order;
925 }
926
ia_css_resolution_to_sp_resolution(struct ia_css_sp_resolution * to,const struct ia_css_resolution * from)927 void ia_css_resolution_to_sp_resolution(
928 struct ia_css_sp_resolution *to,
929 const struct ia_css_resolution *from)
930 {
931 to->width = (uint16_t)from->width;
932 to->height = (uint16_t)from->height;
933 }
934
935 /* ISP2401 */
936 int
ia_css_frame_find_crop_resolution(const struct ia_css_resolution * in_res,const struct ia_css_resolution * out_res,struct ia_css_resolution * crop_res)937 ia_css_frame_find_crop_resolution(const struct ia_css_resolution *in_res,
938 const struct ia_css_resolution *out_res,
939 struct ia_css_resolution *crop_res) {
940 u32 wd_even_ceil, ht_even_ceil;
941 u32 in_ratio, out_ratio;
942
943 if ((!in_res) || (!out_res) || (!crop_res))
944 return -EINVAL;
945
946 IA_CSS_ENTER_PRIVATE("in(%ux%u) -> out(%ux%u)", in_res->width,
947 in_res->height, out_res->width, out_res->height);
948
949 if ((in_res->width == 0)
950 || (in_res->height == 0)
951 || (out_res->width == 0)
952 || (out_res->height == 0))
953 return -EINVAL;
954
955 if ((out_res->width > in_res->width) ||
956 (out_res->height > in_res->height))
957 return -EINVAL;
958
959 /* If aspect ratio (width/height) of out_res is higher than the aspect
960 * ratio of the in_res, then we crop vertically, otherwise we crop
961 * horizontally.
962 */
963 in_ratio = in_res->width * out_res->height;
964 out_ratio = out_res->width * in_res->height;
965
966 if (in_ratio == out_ratio)
967 {
968 crop_res->width = in_res->width;
969 crop_res->height = in_res->height;
970 } else if (out_ratio > in_ratio)
971 {
972 crop_res->width = in_res->width;
973 crop_res->height = ROUND_DIV(out_res->height * crop_res->width,
974 out_res->width);
975 } else
976 {
977 crop_res->height = in_res->height;
978 crop_res->width = ROUND_DIV(out_res->width * crop_res->height,
979 out_res->height);
980 }
981
982 /* Round new (cropped) width and height to an even number.
983 * binarydesc_calculate_bds_factor is such that we should consider as
984 * much of the input as possible. This is different only when we end up
985 * with an odd number in the last step. So, we take the next even number
986 * if it falls within the input, otherwise take the previous even no.
987 */
988 wd_even_ceil = EVEN_CEIL(crop_res->width);
989 ht_even_ceil = EVEN_CEIL(crop_res->height);
990 if ((wd_even_ceil > in_res->width) || (ht_even_ceil > in_res->height))
991 {
992 crop_res->width = EVEN_FLOOR(crop_res->width);
993 crop_res->height = EVEN_FLOOR(crop_res->height);
994 } else
995 {
996 crop_res->width = wd_even_ceil;
997 crop_res->height = ht_even_ceil;
998 }
999
1000 IA_CSS_LEAVE_PRIVATE("in(%ux%u) -> out(%ux%u)", crop_res->width,
1001 crop_res->height, out_res->width, out_res->height);
1002 return 0;
1003 }
1004