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_nv_planes(struct ia_css_frame *frame,
52 				 unsigned int horizontal_decimation,
53 				 unsigned int vertical_decimation,
54 				 unsigned int bytes_per_element);
55 
56 static void frame_init_yuv_planes(struct ia_css_frame *frame,
57 				  unsigned int horizontal_decimation,
58 				  unsigned int vertical_decimation,
59 				  bool swap_uv,
60 				  unsigned int bytes_per_element);
61 
62 static void frame_init_rgb_planes(struct ia_css_frame *frame,
63 				  unsigned int bytes_per_element);
64 
65 static void frame_init_qplane6_planes(struct ia_css_frame *frame);
66 
67 static int frame_allocate_buffer_data(struct ia_css_frame *frame);
68 
69 static int frame_allocate_with_data(struct ia_css_frame **frame,
70 	unsigned int width,
71 	unsigned int height,
72 	enum ia_css_frame_format format,
73 	unsigned int padded_width,
74 	unsigned int raw_bit_depth);
75 
76 static struct ia_css_frame *frame_create(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 valid);
82 
83 static unsigned
84 ia_css_elems_bytes_from_info(
85     const struct ia_css_frame_info *info);
86 
87 /**************************************************************************
88 **	CSS API functions, exposed by ia_css.h
89 **************************************************************************/
90 
91 void ia_css_frame_zero(struct ia_css_frame *frame)
92 {
93 	assert(frame);
94 	hmm_set(frame->data, 0, frame->data_bytes);
95 }
96 
97 int ia_css_frame_allocate_from_info(struct ia_css_frame **frame,
98 	const struct ia_css_frame_info *info)
99 {
100 	int err = 0;
101 
102 	if (!frame || !info)
103 		return -EINVAL;
104 	ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
105 			    "ia_css_frame_allocate_from_info() enter:\n");
106 	err =
107 	    ia_css_frame_allocate(frame, info->res.width, info->res.height,
108 				  info->format, info->padded_width,
109 				  info->raw_bit_depth);
110 	ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
111 			    "ia_css_frame_allocate_from_info() leave:\n");
112 	return err;
113 }
114 
115 int ia_css_frame_allocate(struct ia_css_frame **frame,
116 				      unsigned int width,
117 				      unsigned int height,
118 				      enum ia_css_frame_format format,
119 				      unsigned int padded_width,
120 				      unsigned int raw_bit_depth)
121 {
122 	int err = 0;
123 
124 	if (!frame || width == 0 || height == 0)
125 		return -EINVAL;
126 
127 	ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
128 			    "ia_css_frame_allocate() enter: width=%d, height=%d, format=%d, padded_width=%d, raw_bit_depth=%d\n",
129 			    width, height, format, padded_width, raw_bit_depth);
130 
131 	err = frame_allocate_with_data(frame, width, height, format,
132 				       padded_width, raw_bit_depth);
133 
134 	if ((*frame) && err == 0)
135 		ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
136 				    "ia_css_frame_allocate() leave: frame=%p, data(DDR address)=0x%x\n", *frame,
137 				    (*frame)->data);
138 	else
139 		ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
140 				    "ia_css_frame_allocate() leave: frame=%p, data(DDR address)=0x%x\n",
141 				    (void *)-1, (unsigned int)-1);
142 
143 	return err;
144 }
145 
146 int ia_css_frame_map(struct ia_css_frame **frame,
147 				 const struct ia_css_frame_info *info,
148 				 const void __user *data,
149 				 unsigned int pgnr)
150 {
151 	int err = 0;
152 	struct ia_css_frame *me;
153 
154 	assert(frame);
155 
156 	/* Create the frame structure */
157 	err = ia_css_frame_create_from_info(&me, info);
158 
159 	if (err)
160 		return err;
161 
162 	if (pgnr < ((PAGE_ALIGN(me->data_bytes)) >> PAGE_SHIFT)) {
163 		dev_err(atomisp_dev,
164 			"user space memory size is less than the expected size..\n");
165 		err = -ENOMEM;
166 		goto error;
167 	} else if (pgnr > ((PAGE_ALIGN(me->data_bytes)) >> PAGE_SHIFT)) {
168 		dev_err(atomisp_dev,
169 			"user space memory size is large than the expected size..\n");
170 		err = -ENOMEM;
171 		goto error;
172 	}
173 
174 	me->data = hmm_create_from_userdata(me->data_bytes, data);
175 	if (me->data == mmgr_NULL)
176 		err = -EINVAL;
177 
178 error:
179 	if (err) {
180 		kvfree(me);
181 		me = NULL;
182 	}
183 
184 	*frame = me;
185 
186 	return err;
187 }
188 
189 int ia_css_frame_create_from_info(struct ia_css_frame **frame,
190 	const struct ia_css_frame_info *info)
191 {
192 	int err = 0;
193 	struct ia_css_frame *me;
194 
195 	ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
196 			    "ia_css_frame_create_from_info() enter:\n");
197 	if (!frame || !info) {
198 		ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
199 				    "ia_css_frame_create_from_info() leave: invalid arguments\n");
200 		return -EINVAL;
201 	}
202 
203 	me = frame_create(info->res.width,
204 			  info->res.height,
205 			  info->format,
206 			  info->padded_width,
207 			  info->raw_bit_depth,
208 			  false);
209 	if (!me) {
210 		ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
211 				    "ia_css_frame_create_from_info() leave: frame create failed\n");
212 		return -ENOMEM;
213 	}
214 
215 	err = ia_css_frame_init_planes(me);
216 
217 	if (err) {
218 		kvfree(me);
219 		me = NULL;
220 	}
221 
222 	*frame = me;
223 
224 	ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
225 			    "ia_css_frame_create_from_info() leave:\n");
226 
227 	return err;
228 }
229 
230 int ia_css_frame_set_data(struct ia_css_frame *frame,
231 				      const ia_css_ptr mapped_data,
232 				      size_t data_bytes)
233 {
234 	int err = 0;
235 
236 	ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
237 			    "ia_css_frame_set_data() enter:\n");
238 	if (!frame) {
239 		ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
240 				    "ia_css_frame_set_data() leave: NULL frame\n");
241 		return -EINVAL;
242 	}
243 
244 	/* If we are setting a valid data.
245 	 * Make sure that there is enough
246 	 * room for the expected frame format
247 	 */
248 	if ((mapped_data != mmgr_NULL) && (frame->data_bytes > data_bytes)) {
249 		ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
250 				    "ia_css_frame_set_data() leave: invalid arguments\n");
251 		return -EINVAL;
252 	}
253 
254 	frame->data = mapped_data;
255 
256 	ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "ia_css_frame_set_data() leave:\n");
257 
258 	return err;
259 }
260 
261 void ia_css_frame_free(struct ia_css_frame *frame)
262 {
263 	IA_CSS_ENTER_PRIVATE("frame = %p", frame);
264 
265 	if (frame) {
266 		hmm_free(frame->data);
267 		kvfree(frame);
268 	}
269 
270 	IA_CSS_LEAVE_PRIVATE("void");
271 }
272 
273 /**************************************************************************
274 **	Module public functions
275 **************************************************************************/
276 
277 int ia_css_frame_check_info(const struct ia_css_frame_info *info)
278 {
279 	assert(info);
280 	if (info->res.width == 0 || info->res.height == 0)
281 		return -EINVAL;
282 	return 0;
283 }
284 
285 int ia_css_frame_init_planes(struct ia_css_frame *frame)
286 {
287 	assert(frame);
288 
289 	switch (frame->info.format) {
290 	case IA_CSS_FRAME_FORMAT_MIPI:
291 		dev_err(atomisp_dev,
292 			"%s: unexpected use of IA_CSS_FRAME_FORMAT_MIPI\n", __func__);
293 		return -EINVAL;
294 	case IA_CSS_FRAME_FORMAT_RAW_PACKED:
295 		frame_init_raw_single_plane(frame, &frame->planes.raw,
296 					    frame->info.res.height,
297 					    frame->info.padded_width,
298 					    frame->info.raw_bit_depth);
299 		break;
300 	case IA_CSS_FRAME_FORMAT_RAW:
301 		frame_init_single_plane(frame, &frame->planes.raw,
302 					frame->info.res.height,
303 					frame->info.padded_width,
304 					frame->info.raw_bit_depth <= 8 ? 1 : 2);
305 		break;
306 	case IA_CSS_FRAME_FORMAT_RGB565:
307 		frame_init_single_plane(frame, &frame->planes.rgb,
308 					frame->info.res.height,
309 					frame->info.padded_width, 2);
310 		break;
311 	case IA_CSS_FRAME_FORMAT_RGBA888:
312 		frame_init_single_plane(frame, &frame->planes.rgb,
313 					frame->info.res.height,
314 					frame->info.padded_width * 4, 1);
315 		break;
316 	case IA_CSS_FRAME_FORMAT_PLANAR_RGB888:
317 		frame_init_rgb_planes(frame, 1);
318 		break;
319 	/* yuyv and uyvu have the same frame layout, only the data
320 	 * positioning differs.
321 	 */
322 	case IA_CSS_FRAME_FORMAT_YUYV:
323 	case IA_CSS_FRAME_FORMAT_UYVY:
324 	case IA_CSS_FRAME_FORMAT_CSI_MIPI_YUV420_8:
325 	case IA_CSS_FRAME_FORMAT_CSI_MIPI_LEGACY_YUV420_8:
326 		frame_init_single_plane(frame, &frame->planes.yuyv,
327 					frame->info.res.height,
328 					frame->info.padded_width * 2, 1);
329 		break;
330 	case IA_CSS_FRAME_FORMAT_YUV_LINE:
331 		/* Needs 3 extra lines to allow vf_pp prefetching */
332 		frame_init_single_plane(frame, &frame->planes.yuyv,
333 					frame->info.res.height * 3 / 2 + 3,
334 					frame->info.padded_width, 1);
335 		break;
336 	case IA_CSS_FRAME_FORMAT_NV11:
337 		frame_init_nv_planes(frame, 4, 1, 1);
338 		break;
339 	/* nv12 and nv21 have the same frame layout, only the data
340 	 * positioning differs.
341 	 */
342 	case IA_CSS_FRAME_FORMAT_NV12:
343 	case IA_CSS_FRAME_FORMAT_NV21:
344 	case IA_CSS_FRAME_FORMAT_NV12_TILEY:
345 		frame_init_nv_planes(frame, 2, 2, 1);
346 		break;
347 	case IA_CSS_FRAME_FORMAT_NV12_16:
348 		frame_init_nv_planes(frame, 2, 2, 2);
349 		break;
350 	/* nv16 and nv61 have the same frame layout, only the data
351 	 * positioning differs.
352 	 */
353 	case IA_CSS_FRAME_FORMAT_NV16:
354 	case IA_CSS_FRAME_FORMAT_NV61:
355 		frame_init_nv_planes(frame, 2, 1, 1);
356 		break;
357 	case IA_CSS_FRAME_FORMAT_YUV420:
358 		frame_init_yuv_planes(frame, 2, 2, false, 1);
359 		break;
360 	case IA_CSS_FRAME_FORMAT_YUV422:
361 		frame_init_yuv_planes(frame, 2, 1, false, 1);
362 		break;
363 	case IA_CSS_FRAME_FORMAT_YUV444:
364 		frame_init_yuv_planes(frame, 1, 1, false, 1);
365 		break;
366 	case IA_CSS_FRAME_FORMAT_YUV420_16:
367 		frame_init_yuv_planes(frame, 2, 2, false, 2);
368 		break;
369 	case IA_CSS_FRAME_FORMAT_YUV422_16:
370 		frame_init_yuv_planes(frame, 2, 1, false, 2);
371 		break;
372 	case IA_CSS_FRAME_FORMAT_YV12:
373 		frame_init_yuv_planes(frame, 2, 2, true, 1);
374 		break;
375 	case IA_CSS_FRAME_FORMAT_YV16:
376 		frame_init_yuv_planes(frame, 2, 1, true, 1);
377 		break;
378 	case IA_CSS_FRAME_FORMAT_QPLANE6:
379 		frame_init_qplane6_planes(frame);
380 		break;
381 	case IA_CSS_FRAME_FORMAT_BINARY_8:
382 		frame_init_single_plane(frame, &frame->planes.binary.data,
383 					frame->info.res.height,
384 					frame->info.padded_width, 1);
385 		frame->planes.binary.size = 0;
386 		break;
387 	default:
388 		return -EINVAL;
389 	}
390 	return 0;
391 }
392 
393 void ia_css_frame_info_set_width(struct ia_css_frame_info *info,
394 				 unsigned int width,
395 				 unsigned int min_padded_width)
396 {
397 	unsigned int align;
398 
399 	IA_CSS_ENTER_PRIVATE("info = %p,width = %d, minimum padded width = %d",
400 			     info, width, min_padded_width);
401 	if (!info) {
402 		IA_CSS_ERROR("NULL input parameter");
403 		IA_CSS_LEAVE_PRIVATE("");
404 		return;
405 	}
406 	align = max(min_padded_width, width);
407 
408 	info->res.width = width;
409 	/* frames with a U and V plane of 8 bits per pixel need to have
410 	   all planes aligned, this means double the alignment for the
411 	   Y plane if the horizontal decimation is 2. */
412 	if (info->format == IA_CSS_FRAME_FORMAT_YUV420 ||
413 	    info->format == IA_CSS_FRAME_FORMAT_YV12 ||
414 	    info->format == IA_CSS_FRAME_FORMAT_NV12 ||
415 	    info->format == IA_CSS_FRAME_FORMAT_NV21 ||
416 	    info->format == IA_CSS_FRAME_FORMAT_BINARY_8 ||
417 	    info->format == IA_CSS_FRAME_FORMAT_YUV_LINE)
418 		info->padded_width =
419 		    CEIL_MUL(align, 2 * HIVE_ISP_DDR_WORD_BYTES);
420 	else if (info->format == IA_CSS_FRAME_FORMAT_NV12_TILEY)
421 		info->padded_width = CEIL_MUL(align, NV12_TILEY_TILE_WIDTH);
422 	else if (info->format == IA_CSS_FRAME_FORMAT_RAW ||
423 		 info->format == IA_CSS_FRAME_FORMAT_RAW_PACKED)
424 		info->padded_width = CEIL_MUL(align, 2 * ISP_VEC_NELEMS);
425 	else {
426 		info->padded_width = CEIL_MUL(align, HIVE_ISP_DDR_WORD_BYTES);
427 	}
428 	IA_CSS_LEAVE_PRIVATE("");
429 }
430 
431 void ia_css_frame_info_set_format(struct ia_css_frame_info *info,
432 				  enum ia_css_frame_format format)
433 {
434 	assert(info);
435 	ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
436 			    "ia_css_frame_info_set_format() enter:\n");
437 	info->format = format;
438 }
439 
440 void ia_css_frame_info_init(struct ia_css_frame_info *info,
441 			    unsigned int width,
442 			    unsigned int height,
443 			    enum ia_css_frame_format format,
444 			    unsigned int aligned)
445 {
446 	IA_CSS_ENTER_PRIVATE("info = %p, width = %d, height = %d, format = %d, aligned = %d",
447 			     info, width, height, format, aligned);
448 	if (!info) {
449 		IA_CSS_ERROR("NULL input parameter");
450 		IA_CSS_LEAVE_PRIVATE("");
451 		return;
452 	}
453 	info->res.height = height;
454 	info->format     = format;
455 	ia_css_frame_info_set_width(info, width, aligned);
456 	IA_CSS_LEAVE_PRIVATE("");
457 }
458 
459 void ia_css_frame_free_multiple(unsigned int num_frames,
460 				struct ia_css_frame **frames_array)
461 {
462 	unsigned int i;
463 
464 	for (i = 0; i < num_frames; i++) {
465 		if (frames_array[i]) {
466 			ia_css_frame_free(frames_array[i]);
467 			frames_array[i] = NULL;
468 		}
469 	}
470 }
471 
472 int ia_css_frame_allocate_with_buffer_size(struct ia_css_frame **frame,
473 					   const unsigned int buffer_size_bytes)
474 {
475 	/* AM: Body coppied from frame_allocate_with_data(). */
476 	int err;
477 	struct ia_css_frame *me = frame_create(0, 0,
478 					       IA_CSS_FRAME_FORMAT_NUM,/* Not valid format yet */
479 					       0, 0, false);
480 
481 	if (!me)
482 		return -ENOMEM;
483 
484 	/* Get the data size */
485 	me->data_bytes = buffer_size_bytes;
486 
487 	err = frame_allocate_buffer_data(me);
488 
489 	if (err) {
490 		kvfree(me);
491 		me = NULL;
492 	}
493 
494 	*frame = me;
495 
496 	return err;
497 }
498 
499 bool ia_css_frame_info_is_same_resolution(
500     const struct ia_css_frame_info *info_a,
501     const struct ia_css_frame_info *info_b)
502 {
503 	if (!info_a || !info_b)
504 		return false;
505 	return (info_a->res.width == info_b->res.width) &&
506 	       (info_a->res.height == info_b->res.height);
507 }
508 
509 bool ia_css_frame_is_same_type(const struct ia_css_frame *frame_a,
510 			       const struct ia_css_frame *frame_b)
511 {
512 	bool is_equal = false;
513 	const struct ia_css_frame_info *info_a = &frame_a->info,
514 						*info_b = &frame_b->info;
515 
516 	ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
517 			    "ia_css_frame_is_same_type() enter:\n");
518 
519 	if (!info_a || !info_b)
520 		return false;
521 	if (info_a->format != info_b->format)
522 		return false;
523 	if (info_a->padded_width != info_b->padded_width)
524 		return false;
525 	is_equal = ia_css_frame_info_is_same_resolution(info_a, info_b);
526 
527 	ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
528 			    "ia_css_frame_is_same_type() leave:\n");
529 
530 	return is_equal;
531 }
532 
533 int ia_css_dma_configure_from_info(struct dma_port_config *config,
534 				   const struct ia_css_frame_info *info)
535 {
536 	unsigned int is_raw_packed = info->format == IA_CSS_FRAME_FORMAT_RAW_PACKED;
537 	unsigned int bits_per_pixel = is_raw_packed ? info->raw_bit_depth :
538 				      ia_css_elems_bytes_from_info(info) * 8;
539 	unsigned int pix_per_ddrword = HIVE_ISP_DDR_WORD_BITS / bits_per_pixel;
540 	unsigned int words_per_line = CEIL_DIV(info->padded_width, pix_per_ddrword);
541 	unsigned int elems_b = pix_per_ddrword;
542 
543 	config->stride = HIVE_ISP_DDR_WORD_BYTES * words_per_line;
544 	config->elems  = (uint8_t)elems_b;
545 	config->width  = (uint16_t)info->res.width;
546 	config->crop   = 0;
547 
548 	if (config->width > info->padded_width) {
549 		dev_err(atomisp_dev, "internal error: padded_width is too small!\n");
550 		return -EINVAL;
551 	}
552 
553 	return 0;
554 }
555 
556 /**************************************************************************
557 **	Static functions
558 **************************************************************************/
559 
560 static void frame_init_plane(struct ia_css_frame_plane *plane,
561 			     unsigned int width,
562 			     unsigned int stride,
563 			     unsigned int height,
564 			     unsigned int offset)
565 {
566 	plane->height = height;
567 	plane->width = width;
568 	plane->stride = stride;
569 	plane->offset = offset;
570 }
571 
572 static void frame_init_single_plane(struct ia_css_frame *frame,
573 				    struct ia_css_frame_plane *plane,
574 				    unsigned int height,
575 				    unsigned int subpixels_per_line,
576 				    unsigned int bytes_per_pixel)
577 {
578 	unsigned int stride;
579 
580 	stride = subpixels_per_line * bytes_per_pixel;
581 	/* Frame height needs to be even number - needed by hw ISYS2401
582 	   In case of odd number, round up to even.
583 	   Images won't be impacted by this round up,
584 	   only needed by jpeg/embedded data.
585 	   As long as buffer allocation and release are using data_bytes,
586 	   there won't be memory leak. */
587 	frame->data_bytes = stride * CEIL_MUL2(height, 2);
588 	frame_init_plane(plane, subpixels_per_line, stride, height, 0);
589 	return;
590 }
591 
592 static void frame_init_raw_single_plane(
593     struct ia_css_frame *frame,
594     struct ia_css_frame_plane *plane,
595     unsigned int height,
596     unsigned int subpixels_per_line,
597     unsigned int bits_per_pixel)
598 {
599 	unsigned int stride;
600 
601 	assert(frame);
602 
603 	stride = HIVE_ISP_DDR_WORD_BYTES *
604 		 CEIL_DIV(subpixels_per_line,
605 			  HIVE_ISP_DDR_WORD_BITS / bits_per_pixel);
606 	frame->data_bytes = stride * height;
607 	frame_init_plane(plane, subpixels_per_line, stride, height, 0);
608 	return;
609 }
610 
611 static void frame_init_nv_planes(struct ia_css_frame *frame,
612 				 unsigned int horizontal_decimation,
613 				 unsigned int vertical_decimation,
614 				 unsigned int bytes_per_element)
615 {
616 	unsigned int y_width = frame->info.padded_width;
617 	unsigned int y_height = frame->info.res.height;
618 	unsigned int uv_width;
619 	unsigned int uv_height;
620 	unsigned int y_bytes;
621 	unsigned int uv_bytes;
622 	unsigned int y_stride;
623 	unsigned int uv_stride;
624 
625 	assert(horizontal_decimation != 0 && vertical_decimation != 0);
626 
627 	uv_width = 2 * (y_width / horizontal_decimation);
628 	uv_height = y_height / vertical_decimation;
629 
630 	if (frame->info.format == IA_CSS_FRAME_FORMAT_NV12_TILEY) {
631 		y_width   = CEIL_MUL(y_width,   NV12_TILEY_TILE_WIDTH);
632 		uv_width  = CEIL_MUL(uv_width,  NV12_TILEY_TILE_WIDTH);
633 		y_height  = CEIL_MUL(y_height,  NV12_TILEY_TILE_HEIGHT);
634 		uv_height = CEIL_MUL(uv_height, NV12_TILEY_TILE_HEIGHT);
635 	}
636 
637 	y_stride = y_width * bytes_per_element;
638 	uv_stride = uv_width * bytes_per_element;
639 	y_bytes = y_stride * y_height;
640 	uv_bytes = uv_stride * uv_height;
641 
642 	frame->data_bytes = y_bytes + uv_bytes;
643 	frame_init_plane(&frame->planes.nv.y, y_width, y_stride, y_height, 0);
644 	frame_init_plane(&frame->planes.nv.uv, uv_width,
645 			 uv_stride, uv_height, y_bytes);
646 	return;
647 }
648 
649 static void frame_init_yuv_planes(struct ia_css_frame *frame,
650 				  unsigned int horizontal_decimation,
651 				  unsigned int vertical_decimation,
652 				  bool swap_uv,
653 				  unsigned int bytes_per_element)
654 {
655 	unsigned int y_width = frame->info.padded_width,
656 		     y_height = frame->info.res.height,
657 		     uv_width = y_width / horizontal_decimation,
658 		     uv_height = y_height / vertical_decimation,
659 		     y_stride, y_bytes, uv_bytes, uv_stride;
660 
661 	y_stride = y_width * bytes_per_element;
662 	uv_stride = uv_width * bytes_per_element;
663 	y_bytes = y_stride * y_height;
664 	uv_bytes = uv_stride * uv_height;
665 
666 	frame->data_bytes = y_bytes + 2 * uv_bytes;
667 	frame_init_plane(&frame->planes.yuv.y, y_width, y_stride, y_height, 0);
668 	if (swap_uv) {
669 		frame_init_plane(&frame->planes.yuv.v, uv_width, uv_stride,
670 				 uv_height, y_bytes);
671 		frame_init_plane(&frame->planes.yuv.u, uv_width, uv_stride,
672 				 uv_height, y_bytes + uv_bytes);
673 	} else {
674 		frame_init_plane(&frame->planes.yuv.u, uv_width, uv_stride,
675 				 uv_height, y_bytes);
676 		frame_init_plane(&frame->planes.yuv.v, uv_width, uv_stride,
677 				 uv_height, y_bytes + uv_bytes);
678 	}
679 	return;
680 }
681 
682 static void frame_init_rgb_planes(struct ia_css_frame *frame,
683 				  unsigned int bytes_per_element)
684 {
685 	unsigned int width = frame->info.res.width,
686 		     height = frame->info.res.height, stride, bytes;
687 
688 	stride = width * bytes_per_element;
689 	bytes = stride * height;
690 	frame->data_bytes = 3 * bytes;
691 	frame_init_plane(&frame->planes.planar_rgb.r, width, stride, height, 0);
692 	frame_init_plane(&frame->planes.planar_rgb.g,
693 			 width, stride, height, 1 * bytes);
694 	frame_init_plane(&frame->planes.planar_rgb.b,
695 			 width, stride, height, 2 * bytes);
696 	return;
697 }
698 
699 static void frame_init_qplane6_planes(struct ia_css_frame *frame)
700 {
701 	unsigned int width = frame->info.padded_width / 2,
702 		     height = frame->info.res.height / 2, bytes, stride;
703 
704 	stride = width * 2;
705 	bytes = stride * height;
706 
707 	frame->data_bytes = 6 * bytes;
708 	frame_init_plane(&frame->planes.plane6.r,
709 			 width, stride, height, 0 * bytes);
710 	frame_init_plane(&frame->planes.plane6.r_at_b,
711 			 width, stride, height, 1 * bytes);
712 	frame_init_plane(&frame->planes.plane6.gr,
713 			 width, stride, height, 2 * bytes);
714 	frame_init_plane(&frame->planes.plane6.gb,
715 			 width, stride, height, 3 * bytes);
716 	frame_init_plane(&frame->planes.plane6.b,
717 			 width, stride, height, 4 * bytes);
718 	frame_init_plane(&frame->planes.plane6.b_at_r,
719 			 width, stride, height, 5 * bytes);
720 	return;
721 }
722 
723 static int frame_allocate_buffer_data(struct ia_css_frame *frame)
724 {
725 #ifdef ISP2401
726 	IA_CSS_ENTER_LEAVE_PRIVATE("frame->data_bytes=%d\n", frame->data_bytes);
727 #endif
728 	frame->data = hmm_alloc(frame->data_bytes);
729 	if (frame->data == mmgr_NULL)
730 		return -ENOMEM;
731 	return 0;
732 }
733 
734 static int frame_allocate_with_data(struct ia_css_frame **frame,
735 	unsigned int width,
736 	unsigned int height,
737 	enum ia_css_frame_format format,
738 	unsigned int padded_width,
739 	unsigned int raw_bit_depth)
740 {
741 	int err;
742 	struct ia_css_frame *me = frame_create(width,
743 					       height,
744 					       format,
745 					       padded_width,
746 					       raw_bit_depth,
747 					       true);
748 
749 	if (!me)
750 		return -ENOMEM;
751 
752 	err = ia_css_frame_init_planes(me);
753 
754 	if (!err)
755 		err = frame_allocate_buffer_data(me);
756 
757 	if (err) {
758 		kvfree(me);
759 #ifndef ISP2401
760 		return err;
761 #else
762 		me = NULL;
763 #endif
764 	}
765 
766 	*frame = me;
767 
768 	return err;
769 }
770 
771 static struct ia_css_frame *frame_create(unsigned int width,
772 	unsigned int height,
773 	enum ia_css_frame_format format,
774 	unsigned int padded_width,
775 	unsigned int raw_bit_depth,
776 	bool valid)
777 {
778 	struct ia_css_frame *me = kvmalloc(sizeof(*me), GFP_KERNEL);
779 
780 	if (!me)
781 		return NULL;
782 
783 	memset(me, 0, sizeof(*me));
784 	me->info.res.width = width;
785 	me->info.res.height = height;
786 	me->info.format = format;
787 	me->info.padded_width = padded_width;
788 	me->info.raw_bit_depth = raw_bit_depth;
789 	me->valid = valid;
790 	me->data_bytes = 0;
791 	me->data = mmgr_NULL;
792 	/* To indicate it is not valid frame. */
793 	me->dynamic_queue_id = (int)SH_CSS_INVALID_QUEUE_ID;
794 	me->buf_type = IA_CSS_BUFFER_TYPE_INVALID;
795 
796 	return me;
797 }
798 
799 static unsigned
800 ia_css_elems_bytes_from_info(const struct ia_css_frame_info *info)
801 {
802 	if (info->format == IA_CSS_FRAME_FORMAT_RGB565)
803 		return 2; /* bytes per pixel */
804 	if (info->format == IA_CSS_FRAME_FORMAT_YUV420_16)
805 		return 2; /* bytes per pixel */
806 	if (info->format == IA_CSS_FRAME_FORMAT_YUV422_16)
807 		return 2; /* bytes per pixel */
808 	/* Note: Essentially NV12_16 is a 2 bytes per pixel format, this return value is used
809 	 * to configure DMA for the output buffer,
810 	 * At least in SKC this data is overwritten by isp_output_init.sp.c except for elements(elems),
811 	 * which is configured from this return value,
812 	 * NV12_16 is implemented by a double buffer of 8 bit elements hence elems should be configured as 8 */
813 	if (info->format == IA_CSS_FRAME_FORMAT_NV12_16)
814 		return 1; /* bytes per pixel */
815 
816 	if (info->format == IA_CSS_FRAME_FORMAT_RAW
817 	    || (info->format == IA_CSS_FRAME_FORMAT_RAW_PACKED)) {
818 		if (info->raw_bit_depth)
819 			return CEIL_DIV(info->raw_bit_depth, 8);
820 		else
821 			return 2; /* bytes per pixel */
822 	}
823 	if (info->format == IA_CSS_FRAME_FORMAT_PLANAR_RGB888)
824 		return 3; /* bytes per pixel */
825 	if (info->format == IA_CSS_FRAME_FORMAT_RGBA888)
826 		return 4; /* bytes per pixel */
827 	if (info->format == IA_CSS_FRAME_FORMAT_QPLANE6)
828 		return 2; /* bytes per pixel */
829 	return 1; /* Default is 1 byte per pixel */
830 }
831 
832 void ia_css_frame_info_to_frame_sp_info(
833     struct ia_css_frame_sp_info *to,
834     const struct ia_css_frame_info *from)
835 {
836 	ia_css_resolution_to_sp_resolution(&to->res, &from->res);
837 	to->padded_width = (uint16_t)from->padded_width;
838 	to->format = (uint8_t)from->format;
839 	to->raw_bit_depth = (uint8_t)from->raw_bit_depth;
840 	to->raw_bayer_order = from->raw_bayer_order;
841 }
842 
843 void ia_css_resolution_to_sp_resolution(
844     struct ia_css_sp_resolution *to,
845     const struct ia_css_resolution *from)
846 {
847 	to->width  = (uint16_t)from->width;
848 	to->height = (uint16_t)from->height;
849 }
850