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