1 // SPDX-License-Identifier: GPL-2.0
2 /*
3 * Support for Intel Camera Imaging ISP subsystem.
4 * Copyright (c) 2015, Intel Corporation.
5 */
6
7 #include "ia_css_mipi.h"
8 #include "sh_css_mipi.h"
9 #include <type_support.h>
10 #include "system_global.h"
11 #include "ia_css_err.h"
12 #include "ia_css_pipe.h"
13 #include "ia_css_stream_format.h"
14 #include "sh_css_stream_format.h"
15 #include "ia_css_stream_public.h"
16 #include "ia_css_frame_public.h"
17 #include "ia_css_input_port.h"
18 #include "ia_css_debug.h"
19 #include "sh_css_struct.h"
20 #include "sh_css_defs.h"
21 #include "sh_css_sp.h" /* sh_css_update_host2sp_mipi_frame sh_css_update_host2sp_num_mipi_frames ... */
22 #include "sw_event_global.h" /* IA_CSS_PSYS_SW_EVENT_MIPI_BUFFERS_READY */
23
24 static u32
25 ref_count_mipi_allocation[N_CSI_PORTS]; /* Initialized in mipi_init */
26
27 /* Assumptions:
28 * - A line is multiple of 4 bytes = 1 word.
29 * - Each frame has SOF and EOF (each 1 word).
30 * - Each line has format header and optionally SOL and EOL (each 1 word).
31 * - Odd and even lines of YUV420 format are different in bites per pixel size.
32 * - Custom size of embedded data.
33 * -- Interleaved frames are not taken into account.
34 * -- Lines are multiples of 8B, and not necessary of (custom 3B, or 7B
35 * etc.).
36 * Result is given in DDR mem words, 32B or 256 bits
37 */
38 int
ia_css_mipi_frame_calculate_size(const unsigned int width,const unsigned int height,const enum atomisp_input_format format,const bool hasSOLandEOL,const unsigned int embedded_data_size_words,unsigned int * size_mem_words)39 ia_css_mipi_frame_calculate_size(const unsigned int width,
40 const unsigned int height,
41 const enum atomisp_input_format format,
42 const bool hasSOLandEOL,
43 const unsigned int embedded_data_size_words,
44 unsigned int *size_mem_words)
45 {
46 int err = 0;
47
48 unsigned int bits_per_pixel = 0;
49 unsigned int even_line_bytes = 0;
50 unsigned int odd_line_bytes = 0;
51 unsigned int words_per_odd_line = 0;
52 unsigned int words_for_first_line = 0;
53 unsigned int words_per_even_line = 0;
54 unsigned int mem_words_per_even_line = 0;
55 unsigned int mem_words_per_odd_line = 0;
56 unsigned int mem_words_for_first_line = 0;
57 unsigned int mem_words_for_EOF = 0;
58 unsigned int mem_words = 0;
59 unsigned int width_padded = width;
60
61 /* The changes will be reverted as soon as RAW
62 * Buffers are deployed by the 2401 Input System
63 * in the non-continuous use scenario.
64 */
65 if (IS_ISP2401)
66 width_padded += (2 * ISP_VEC_NELEMS);
67
68 IA_CSS_ENTER("padded_width=%d, height=%d, format=%d, hasSOLandEOL=%d, embedded_data_size_words=%d\n",
69 width_padded, height, format, hasSOLandEOL, embedded_data_size_words);
70
71 switch (format) {
72 case ATOMISP_INPUT_FORMAT_RAW_6: /* 4p, 3B, 24bits */
73 bits_per_pixel = 6;
74 break;
75 case ATOMISP_INPUT_FORMAT_RAW_7: /* 8p, 7B, 56bits */
76 bits_per_pixel = 7;
77 break;
78 case ATOMISP_INPUT_FORMAT_RAW_8: /* 1p, 1B, 8bits */
79 case ATOMISP_INPUT_FORMAT_BINARY_8: /* 8bits, TODO: check. */
80 case ATOMISP_INPUT_FORMAT_YUV420_8: /* odd 2p, 2B, 16bits, even 2p, 4B, 32bits */
81 bits_per_pixel = 8;
82 break;
83 case ATOMISP_INPUT_FORMAT_YUV420_10: /* odd 4p, 5B, 40bits, even 4p, 10B, 80bits */
84 case ATOMISP_INPUT_FORMAT_RAW_10: /* 4p, 5B, 40bits */
85 /* The changes will be reverted as soon as RAW
86 * Buffers are deployed by the 2401 Input System
87 * in the non-continuous use scenario.
88 */
89 bits_per_pixel = 10;
90 break;
91 case ATOMISP_INPUT_FORMAT_YUV420_8_LEGACY: /* 2p, 3B, 24bits */
92 case ATOMISP_INPUT_FORMAT_RAW_12: /* 2p, 3B, 24bits */
93 bits_per_pixel = 12;
94 break;
95 case ATOMISP_INPUT_FORMAT_RAW_14: /* 4p, 7B, 56bits */
96 bits_per_pixel = 14;
97 break;
98 case ATOMISP_INPUT_FORMAT_RGB_444: /* 1p, 2B, 16bits */
99 case ATOMISP_INPUT_FORMAT_RGB_555: /* 1p, 2B, 16bits */
100 case ATOMISP_INPUT_FORMAT_RGB_565: /* 1p, 2B, 16bits */
101 case ATOMISP_INPUT_FORMAT_YUV422_8: /* 2p, 4B, 32bits */
102 bits_per_pixel = 16;
103 break;
104 case ATOMISP_INPUT_FORMAT_RGB_666: /* 4p, 9B, 72bits */
105 bits_per_pixel = 18;
106 break;
107 case ATOMISP_INPUT_FORMAT_YUV422_10: /* 2p, 5B, 40bits */
108 bits_per_pixel = 20;
109 break;
110 case ATOMISP_INPUT_FORMAT_RGB_888: /* 1p, 3B, 24bits */
111 bits_per_pixel = 24;
112 break;
113
114 case ATOMISP_INPUT_FORMAT_YUV420_16: /* Not supported */
115 case ATOMISP_INPUT_FORMAT_YUV422_16: /* Not supported */
116 case ATOMISP_INPUT_FORMAT_RAW_16: /* TODO: not specified in MIPI SPEC, check */
117 default:
118 return -EINVAL;
119 }
120
121 odd_line_bytes = (width_padded * bits_per_pixel + 7) >> 3; /* ceil ( bits per line / 8) */
122
123 /* Even lines for YUV420 formats are double in bits_per_pixel. */
124 if (format == ATOMISP_INPUT_FORMAT_YUV420_8
125 || format == ATOMISP_INPUT_FORMAT_YUV420_10
126 || format == ATOMISP_INPUT_FORMAT_YUV420_16) {
127 even_line_bytes = (width_padded * 2 * bits_per_pixel + 7) >>
128 3; /* ceil ( bits per line / 8) */
129 } else {
130 even_line_bytes = odd_line_bytes;
131 }
132
133 /* a frame represented in memory: ()- optional; data - payload words.
134 * addr 0 1 2 3 4 5 6 7:
135 * first SOF (SOL) PACK_H data data data data data
136 * data data data data data data data data
137 * ...
138 * data data 0 0 0 0 0 0
139 * second (EOL) (SOL) PACK_H data data data data data
140 * data data data data data data data data
141 * ...
142 * data data 0 0 0 0 0 0
143 * ...
144 * last (EOL) EOF 0 0 0 0 0 0
145 *
146 * Embedded lines are regular lines stored before the first and after
147 * payload lines.
148 */
149
150 words_per_odd_line = (odd_line_bytes + 3) >> 2;
151 /* ceil(odd_line_bytes/4); word = 4 bytes */
152 words_per_even_line = (even_line_bytes + 3) >> 2;
153 words_for_first_line = words_per_odd_line + 2 + (hasSOLandEOL ? 1 : 0);
154 /* + SOF +packet header + optionally (SOL), but (EOL) is not in the first line */
155 words_per_odd_line += (1 + (hasSOLandEOL ? 2 : 0));
156 /* each non-first line has format header, and optionally (SOL) and (EOL). */
157 words_per_even_line += (1 + (hasSOLandEOL ? 2 : 0));
158
159 mem_words_per_odd_line = (words_per_odd_line + 7) >> 3;
160 /* ceil(words_per_odd_line/8); mem_word = 32 bytes, 8 words */
161 mem_words_for_first_line = (words_for_first_line + 7) >> 3;
162 mem_words_per_even_line = (words_per_even_line + 7) >> 3;
163 mem_words_for_EOF = 1; /* last line consist of the optional (EOL) and EOF */
164
165 mem_words = ((embedded_data_size_words + 7) >> 3) +
166 mem_words_for_first_line +
167 (((height + 1) >> 1) - 1) * mem_words_per_odd_line +
168 /* ceil (height/2) - 1 (first line is calculated separately) */
169 (height >> 1) * mem_words_per_even_line + /* floor(height/2) */
170 mem_words_for_EOF;
171
172 *size_mem_words = mem_words; /* ceil(words/8); mem word is 32B = 8words. */
173 /* Check if the above is still needed. */
174
175 IA_CSS_LEAVE_ERR(err);
176 return err;
177 }
178
179 void
mipi_init(void)180 mipi_init(void)
181 {
182 unsigned int i;
183
184 for (i = 0; i < N_CSI_PORTS; i++)
185 ref_count_mipi_allocation[i] = 0;
186 }
187
mipi_is_free(void)188 bool mipi_is_free(void)
189 {
190 unsigned int i;
191
192 for (i = 0; i < N_CSI_PORTS; i++)
193 if (ref_count_mipi_allocation[i])
194 return false;
195
196 return true;
197 }
198
199 /*
200 * @brief Calculate the required MIPI buffer sizes.
201 * Based on the stream configuration, calculate the
202 * required MIPI buffer sizes (in DDR words).
203 *
204 * @param[in] stream_cfg Point to the target stream configuration
205 * @param[out] size_mem_words MIPI buffer size in DDR words.
206 *
207 * @return
208 */
calculate_mipi_buff_size(struct ia_css_stream_config * stream_cfg,unsigned int * size_mem_words)209 static int calculate_mipi_buff_size(struct ia_css_stream_config *stream_cfg,
210 unsigned int *size_mem_words)
211 {
212 unsigned int width;
213 unsigned int height;
214 enum atomisp_input_format format;
215 bool pack_raw_pixels;
216
217 unsigned int width_padded;
218 unsigned int bits_per_pixel = 0;
219
220 unsigned int even_line_bytes = 0;
221 unsigned int odd_line_bytes = 0;
222
223 unsigned int words_per_odd_line = 0;
224 unsigned int words_per_even_line = 0;
225
226 unsigned int mem_words_per_even_line = 0;
227 unsigned int mem_words_per_odd_line = 0;
228
229 unsigned int mem_words_per_buff_line = 0;
230 unsigned int mem_words_per_buff = 0;
231 int err = 0;
232
233 /**
234 * [email protected]
235 *
236 * NOTE
237 * - In the struct "ia_css_stream_config", there
238 * are two members: "input_config" and "isys_config".
239 * Both of them provide the same information, e.g.
240 * input_res and format.
241 *
242 * Question here is that: which one shall be used?
243 */
244 width = stream_cfg->input_config.input_res.width;
245 height = stream_cfg->input_config.input_res.height;
246 format = stream_cfg->input_config.format;
247 pack_raw_pixels = stream_cfg->pack_raw_pixels;
248 /* end of NOTE */
249
250 /**
251 * [email protected]
252 *
253 * NOTE
254 * - The following code is derived from the
255 * existing code "ia_css_mipi_frame_calculate_size()".
256 *
257 * Question here is: why adding "2 * ISP_VEC_NELEMS"
258 * to "width_padded", but not making "width_padded"
259 * aligned with "2 * ISP_VEC_NELEMS"?
260 */
261 /* The changes will be reverted as soon as RAW
262 * Buffers are deployed by the 2401 Input System
263 * in the non-continuous use scenario.
264 */
265 width_padded = width + (2 * ISP_VEC_NELEMS);
266 /* end of NOTE */
267
268 IA_CSS_ENTER("padded_width=%d, height=%d, format=%d\n",
269 width_padded, height, format);
270
271 bits_per_pixel = sh_css_stream_format_2_bits_per_subpixel(format);
272 bits_per_pixel =
273 (format == ATOMISP_INPUT_FORMAT_RAW_10 && pack_raw_pixels) ? bits_per_pixel : 16;
274 if (bits_per_pixel == 0)
275 return -EINVAL;
276
277 odd_line_bytes = (width_padded * bits_per_pixel + 7) >> 3; /* ceil ( bits per line / 8) */
278
279 /* Even lines for YUV420 formats are double in bits_per_pixel. */
280 if (format == ATOMISP_INPUT_FORMAT_YUV420_8
281 || format == ATOMISP_INPUT_FORMAT_YUV420_10) {
282 even_line_bytes = (width_padded * 2 * bits_per_pixel + 7) >>
283 3; /* ceil ( bits per line / 8) */
284 } else {
285 even_line_bytes = odd_line_bytes;
286 }
287
288 words_per_odd_line = (odd_line_bytes + 3) >> 2;
289 /* ceil(odd_line_bytes/4); word = 4 bytes */
290 words_per_even_line = (even_line_bytes + 3) >> 2;
291
292 mem_words_per_odd_line = (words_per_odd_line + 7) >> 3;
293 /* ceil(words_per_odd_line/8); mem_word = 32 bytes, 8 words */
294 mem_words_per_even_line = (words_per_even_line + 7) >> 3;
295
296 mem_words_per_buff_line =
297 (mem_words_per_odd_line > mem_words_per_even_line) ? mem_words_per_odd_line : mem_words_per_even_line;
298 mem_words_per_buff = mem_words_per_buff_line * height;
299
300 *size_mem_words = mem_words_per_buff;
301
302 IA_CSS_LEAVE_ERR(err);
303 return err;
304 }
305
306 int
allocate_mipi_frames(struct ia_css_pipe * pipe,struct ia_css_stream_info * info)307 allocate_mipi_frames(struct ia_css_pipe *pipe,
308 struct ia_css_stream_info *info)
309 {
310 int err = -EINVAL;
311 unsigned int port;
312
313 ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE,
314 "allocate_mipi_frames(%p) enter:\n", pipe);
315
316 if (IS_ISP2401 && pipe->stream->config.online) {
317 ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE,
318 "allocate_mipi_frames(%p) exit: no buffers needed for 2401 pipe mode.\n",
319 pipe);
320 return 0;
321 }
322
323 if (pipe->stream->config.mode != IA_CSS_INPUT_MODE_BUFFERED_SENSOR) {
324 ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE,
325 "allocate_mipi_frames(%p) exit: no buffers needed for pipe mode.\n",
326 pipe);
327 return 0; /* AM TODO: Check */
328 }
329
330 port = (unsigned int)pipe->stream->config.source.port.port;
331 if (port >= N_CSI_PORTS) {
332 IA_CSS_ERROR("allocate_mipi_frames(%p) exit: port is not correct (port=%d).",
333 pipe, port);
334 return -EINVAL;
335 }
336
337 if (IS_ISP2401)
338 err = calculate_mipi_buff_size(&pipe->stream->config,
339 &my_css.mipi_frame_size[port]);
340
341 /*
342 * 2401 system allows multiple streams to use same physical port. This is not
343 * true for 2400 system. Currently 2401 uses MIPI buffers as a temporary solution.
344 * TODO AM: Once that is changed (removed) this code should be removed as well.
345 * In that case only 2400 related code should remain.
346 */
347 if (ref_count_mipi_allocation[port] != 0) {
348 if (IS_ISP2401)
349 ref_count_mipi_allocation[port]++;
350
351 ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE,
352 "allocate_mipi_frames(%p) leave: nothing to do, already allocated for this port (port=%d).\n",
353 pipe, port);
354 return 0;
355 }
356
357 ref_count_mipi_allocation[port]++;
358
359 /* AM TODO: mipi frames number should come from stream struct. */
360 my_css.num_mipi_frames[port] = NUM_MIPI_FRAMES_PER_STREAM;
361
362 /* Incremental allocation (per stream), not for all streams at once. */
363 { /* limit the scope of i,j */
364 unsigned int i, j;
365
366 for (i = 0; i < my_css.num_mipi_frames[port]; i++) {
367 /* free previous frame */
368 if (my_css.mipi_frames[port][i]) {
369 ia_css_frame_free(my_css.mipi_frames[port][i]);
370 my_css.mipi_frames[port][i] = NULL;
371 }
372 /* check if new frame is needed */
373 if (i < my_css.num_mipi_frames[port]) {
374 /* allocate new frame */
375 err = ia_css_frame_allocate_with_buffer_size(
376 &my_css.mipi_frames[port][i],
377 my_css.mipi_frame_size[port] * HIVE_ISP_DDR_WORD_BYTES);
378 if (err) {
379 for (j = 0; j < i; j++) {
380 if (my_css.mipi_frames[port][j]) {
381 ia_css_frame_free(my_css.mipi_frames[port][j]);
382 my_css.mipi_frames[port][j] = NULL;
383 }
384 }
385 IA_CSS_ERROR("allocate_mipi_frames(%p, %d) exit: allocation failed.",
386 pipe, port);
387 return err;
388 }
389 }
390 if (info->metadata_info.size > 0) {
391 /* free previous metadata buffer */
392 if (my_css.mipi_metadata[port][i]) {
393 ia_css_metadata_free(my_css.mipi_metadata[port][i]);
394 my_css.mipi_metadata[port][i] = NULL;
395 }
396 /* check if need to allocate a new metadata buffer */
397 if (i < my_css.num_mipi_frames[port]) {
398 /* allocate new metadata buffer */
399 my_css.mipi_metadata[port][i] = ia_css_metadata_allocate(&info->metadata_info);
400 if (!my_css.mipi_metadata[port][i]) {
401 ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE,
402 "allocate_mipi_metadata(%p, %d) failed.\n",
403 pipe, port);
404 return err;
405 }
406 }
407 }
408 }
409 }
410 ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE,
411 "allocate_mipi_frames(%p) exit:\n", pipe);
412
413 return err;
414 }
415
416 int
free_mipi_frames(struct ia_css_pipe * pipe)417 free_mipi_frames(struct ia_css_pipe *pipe)
418 {
419 int err = -EINVAL;
420 unsigned int port;
421
422 ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE,
423 "free_mipi_frames(%p) enter:\n", pipe);
424
425 /* assert(pipe != NULL); TEMP: TODO: Should be assert only. */
426 if (pipe) {
427 assert(pipe->stream);
428 if ((!pipe) || (!pipe->stream)) {
429 IA_CSS_ERROR("free_mipi_frames(%p) exit: pipe or stream is null.",
430 pipe);
431 return -EINVAL;
432 }
433
434 if (pipe->stream->config.mode != IA_CSS_INPUT_MODE_BUFFERED_SENSOR) {
435 IA_CSS_ERROR("free_mipi_frames(%p) exit: wrong mode.",
436 pipe);
437 return err;
438 }
439
440 port = (unsigned int)pipe->stream->config.source.port.port;
441
442 if (port >= N_CSI_PORTS) {
443 IA_CSS_ERROR("free_mipi_frames(%p, %d) exit: pipe port is not correct.",
444 pipe, port);
445 return err;
446 }
447
448 if (ref_count_mipi_allocation[port] > 0) {
449 if (!IS_ISP2401) {
450 assert(ref_count_mipi_allocation[port] == 1);
451 if (ref_count_mipi_allocation[port] != 1) {
452 IA_CSS_ERROR("free_mipi_frames(%p) exit: wrong ref_count (ref_count=%d).",
453 pipe, ref_count_mipi_allocation[port]);
454 return err;
455 }
456 }
457
458 ref_count_mipi_allocation[port]--;
459
460 if (ref_count_mipi_allocation[port] == 0) {
461 /* no streams are using this buffer, so free it */
462 unsigned int i;
463
464 for (i = 0; i < my_css.num_mipi_frames[port]; i++) {
465 if (my_css.mipi_frames[port][i]) {
466 ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE,
467 "free_mipi_frames(port=%d, num=%d).\n", port, i);
468 ia_css_frame_free(my_css.mipi_frames[port][i]);
469 my_css.mipi_frames[port][i] = NULL;
470 }
471 if (my_css.mipi_metadata[port][i]) {
472 ia_css_metadata_free(my_css.mipi_metadata[port][i]);
473 my_css.mipi_metadata[port][i] = NULL;
474 }
475 }
476
477 ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE,
478 "free_mipi_frames(%p) exit (deallocated).\n", pipe);
479 }
480 }
481 } else { /* pipe ==NULL */
482 /* AM TEMP: free-ing all mipi buffers just like a legacy code. */
483 for (port = 0; port < N_CSI_PORTS; port++) {
484 unsigned int i;
485
486 for (i = 0; i < my_css.num_mipi_frames[port]; i++) {
487 if (my_css.mipi_frames[port][i]) {
488 ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE,
489 "free_mipi_frames(port=%d, num=%d).\n", port, i);
490 ia_css_frame_free(my_css.mipi_frames[port][i]);
491 my_css.mipi_frames[port][i] = NULL;
492 }
493 if (my_css.mipi_metadata[port][i]) {
494 ia_css_metadata_free(my_css.mipi_metadata[port][i]);
495 my_css.mipi_metadata[port][i] = NULL;
496 }
497 }
498 ref_count_mipi_allocation[port] = 0;
499 }
500 }
501 return 0;
502 }
503
504 int
send_mipi_frames(struct ia_css_pipe * pipe)505 send_mipi_frames(struct ia_css_pipe *pipe)
506 {
507 int err = -EINVAL;
508 unsigned int i;
509 unsigned int port;
510
511 IA_CSS_ENTER_PRIVATE("pipe=%p", pipe);
512
513 /* multi stream video needs mipi buffers */
514 /* nothing to be done in other cases. */
515 if (pipe->stream->config.mode != IA_CSS_INPUT_MODE_BUFFERED_SENSOR) {
516 IA_CSS_LOG("nothing to be done for this mode");
517 return 0;
518 /* TODO: AM: maybe this should be returning an error. */
519 }
520
521 port = (unsigned int)pipe->stream->config.source.port.port;
522
523 if (port >= N_CSI_PORTS) {
524 IA_CSS_ERROR("send_mipi_frames(%p) exit: invalid port specified (port=%d).",
525 pipe, port);
526 return err;
527 }
528
529 /* Hand-over the SP-internal mipi buffers */
530 for (i = 0; i < my_css.num_mipi_frames[port]; i++) {
531 /* Need to include the offset for port. */
532 sh_css_update_host2sp_mipi_frame(port * NUM_MIPI_FRAMES_PER_STREAM + i,
533 my_css.mipi_frames[port][i]);
534 sh_css_update_host2sp_mipi_metadata(port * NUM_MIPI_FRAMES_PER_STREAM + i,
535 my_css.mipi_metadata[port][i]);
536 }
537 sh_css_update_host2sp_num_mipi_frames(my_css.num_mipi_frames[port]);
538
539 /**********************************
540 * Send an event to inform the SP
541 * that all MIPI frames are passed.
542 **********************************/
543 if (!sh_css_sp_is_running()) {
544 /* SP is not running. The queues are not valid */
545 IA_CSS_ERROR("sp is not running");
546 return err;
547 }
548
549 ia_css_bufq_enqueue_psys_event(
550 IA_CSS_PSYS_SW_EVENT_MIPI_BUFFERS_READY,
551 (uint8_t)port,
552 (uint8_t)my_css.num_mipi_frames[port],
553 0 /* not used */);
554 IA_CSS_LEAVE_ERR_PRIVATE(0);
555 return 0;
556 }
557