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