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