1 /* 2 * Support for Intel Camera Imaging ISP subsystem. 3 * Copyright (c) 2010 - 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 "platform_support.h" 16 17 #include "ia_css_inputfifo.h" 18 19 #include "device_access.h" 20 21 #define __INLINE_SP__ 22 #include "sp.h" 23 #define __INLINE_ISP__ 24 #include "isp.h" 25 #define __INLINE_IRQ__ 26 #include "irq.h" 27 #define __INLINE_FIFO_MONITOR__ 28 #include "fifo_monitor.h" 29 30 #define __INLINE_EVENT__ 31 #include "event_fifo.h" 32 #define __INLINE_SP__ 33 34 #if !defined(HAS_NO_INPUT_SYSTEM) 35 #include "input_system.h" /* MIPI_PREDICTOR_NONE,... */ 36 #endif 37 38 #include "assert_support.h" 39 40 /* System independent */ 41 #include "sh_css_internal.h" 42 #if !defined(HAS_NO_INPUT_SYSTEM) 43 #include "ia_css_isys.h" 44 #endif 45 46 #define HBLANK_CYCLES (187) 47 #define MARKER_CYCLES (6) 48 49 #if !defined(HAS_NO_INPUT_SYSTEM) 50 #include <hive_isp_css_streaming_to_mipi_types_hrt.h> 51 #endif 52 53 /* The data type is used to send special cases: 54 * yuv420: odd lines (1, 3 etc) are twice as wide as even 55 * lines (0, 2, 4 etc). 56 * rgb: for two pixels per clock, the R and B values are sent 57 * to output_0 while only G is sent to output_1. This means 58 * that output_1 only gets half the number of values of output_0. 59 * WARNING: This type should also be used for Legacy YUV420. 60 * regular: used for all other data types (RAW, YUV422, etc) 61 */ 62 enum inputfifo_mipi_data_type { 63 inputfifo_mipi_data_type_regular, 64 inputfifo_mipi_data_type_yuv420, 65 inputfifo_mipi_data_type_yuv420_legacy, 66 inputfifo_mipi_data_type_rgb, 67 }; 68 69 #if !defined(HAS_NO_INPUT_SYSTEM) 70 static unsigned int inputfifo_curr_ch_id, inputfifo_curr_fmt_type; 71 #endif 72 struct inputfifo_instance { 73 unsigned int ch_id; 74 enum atomisp_input_format input_format; 75 bool two_ppc; 76 bool streaming; 77 unsigned int hblank_cycles; 78 unsigned int marker_cycles; 79 unsigned int fmt_type; 80 enum inputfifo_mipi_data_type type; 81 }; 82 83 #if !defined(HAS_NO_INPUT_SYSTEM) 84 /* 85 * Maintain a basic streaming to Mipi administration with ch_id as index 86 * ch_id maps on the "Mipi virtual channel ID" and can have value 0..3 87 */ 88 #define INPUTFIFO_NR_OF_S2M_CHANNELS (4) 89 static struct inputfifo_instance 90 inputfifo_inst_admin[INPUTFIFO_NR_OF_S2M_CHANNELS]; 91 92 /* Streaming to MIPI */ 93 static unsigned int inputfifo_wrap_marker( 94 /* static inline unsigned inputfifo_wrap_marker( */ 95 unsigned int marker) 96 { 97 return marker | 98 (inputfifo_curr_ch_id << HIVE_STR_TO_MIPI_CH_ID_LSB) | 99 (inputfifo_curr_fmt_type << _HIVE_STR_TO_MIPI_FMT_TYPE_LSB); 100 } 101 102 static inline void 103 _sh_css_fifo_snd(unsigned int token) 104 { 105 while (!can_event_send_token(STR2MIPI_EVENT_ID)) 106 hrt_sleep(); 107 event_send_token(STR2MIPI_EVENT_ID, token); 108 return; 109 } 110 111 static void inputfifo_send_data_a( 112 /* static inline void inputfifo_send_data_a( */ 113 unsigned int data) 114 { 115 unsigned int token = (1 << HIVE_STR_TO_MIPI_VALID_A_BIT) | 116 (data << HIVE_STR_TO_MIPI_DATA_A_LSB); 117 _sh_css_fifo_snd(token); 118 return; 119 } 120 121 static void inputfifo_send_data_b( 122 /* static inline void inputfifo_send_data_b( */ 123 unsigned int data) 124 { 125 unsigned int token = (1 << HIVE_STR_TO_MIPI_VALID_B_BIT) | 126 (data << _HIVE_STR_TO_MIPI_DATA_B_LSB); 127 _sh_css_fifo_snd(token); 128 return; 129 } 130 131 static void inputfifo_send_data( 132 /* static inline void inputfifo_send_data( */ 133 unsigned int a, 134 unsigned int b) 135 { 136 unsigned int token = ((1 << HIVE_STR_TO_MIPI_VALID_A_BIT) | 137 (1 << HIVE_STR_TO_MIPI_VALID_B_BIT) | 138 (a << HIVE_STR_TO_MIPI_DATA_A_LSB) | 139 (b << _HIVE_STR_TO_MIPI_DATA_B_LSB)); 140 _sh_css_fifo_snd(token); 141 return; 142 } 143 144 static void inputfifo_send_sol(void) 145 /* static inline void inputfifo_send_sol(void) */ 146 { 147 hrt_data token = inputfifo_wrap_marker( 148 1 << HIVE_STR_TO_MIPI_SOL_BIT); 149 150 _sh_css_fifo_snd(token); 151 return; 152 } 153 154 static void inputfifo_send_eol(void) 155 /* static inline void inputfifo_send_eol(void) */ 156 { 157 hrt_data token = inputfifo_wrap_marker( 158 1 << HIVE_STR_TO_MIPI_EOL_BIT); 159 _sh_css_fifo_snd(token); 160 return; 161 } 162 163 static void inputfifo_send_sof(void) 164 /* static inline void inputfifo_send_sof(void) */ 165 { 166 hrt_data token = inputfifo_wrap_marker( 167 1 << HIVE_STR_TO_MIPI_SOF_BIT); 168 169 _sh_css_fifo_snd(token); 170 return; 171 } 172 173 static void inputfifo_send_eof(void) 174 /* static inline void inputfifo_send_eof(void) */ 175 { 176 hrt_data token = inputfifo_wrap_marker( 177 1 << HIVE_STR_TO_MIPI_EOF_BIT); 178 _sh_css_fifo_snd(token); 179 return; 180 } 181 182 static void inputfifo_send_ch_id_and_fmt_type( 183 /* static inline 184 void inputfifo_send_ch_id_and_fmt_type( */ 185 unsigned int ch_id, 186 unsigned int fmt_type) 187 { 188 hrt_data token; 189 190 inputfifo_curr_ch_id = ch_id & _HIVE_ISP_CH_ID_MASK; 191 inputfifo_curr_fmt_type = fmt_type & _HIVE_ISP_FMT_TYPE_MASK; 192 /* we send an zero marker, this will wrap the ch_id and 193 * fmt_type automatically. 194 */ 195 token = inputfifo_wrap_marker(0); 196 _sh_css_fifo_snd(token); 197 return; 198 } 199 200 static void inputfifo_send_empty_token(void) 201 /* static inline void inputfifo_send_empty_token(void) */ 202 { 203 hrt_data token = inputfifo_wrap_marker(0); 204 205 _sh_css_fifo_snd(token); 206 return; 207 } 208 209 static void inputfifo_start_frame( 210 /* static inline void inputfifo_start_frame( */ 211 unsigned int ch_id, 212 unsigned int fmt_type) 213 { 214 inputfifo_send_ch_id_and_fmt_type(ch_id, fmt_type); 215 inputfifo_send_sof(); 216 return; 217 } 218 219 static void inputfifo_end_frame( 220 unsigned int marker_cycles) 221 { 222 unsigned int i; 223 224 for (i = 0; i < marker_cycles; i++) 225 inputfifo_send_empty_token(); 226 inputfifo_send_eof(); 227 return; 228 } 229 230 static void inputfifo_send_line2( 231 const unsigned short *data, 232 unsigned int width, 233 const unsigned short *data2, 234 unsigned int width2, 235 unsigned int hblank_cycles, 236 unsigned int marker_cycles, 237 unsigned int two_ppc, 238 enum inputfifo_mipi_data_type type) 239 { 240 unsigned int i, is_rgb = 0, is_legacy = 0; 241 242 assert(data); 243 assert((data2) || (width2 == 0)); 244 if (type == inputfifo_mipi_data_type_rgb) 245 is_rgb = 1; 246 247 if (type == inputfifo_mipi_data_type_yuv420_legacy) 248 is_legacy = 1; 249 250 for (i = 0; i < hblank_cycles; i++) 251 inputfifo_send_empty_token(); 252 inputfifo_send_sol(); 253 for (i = 0; i < marker_cycles; i++) 254 inputfifo_send_empty_token(); 255 for (i = 0; i < width; i++, data++) { 256 /* for RGB in two_ppc, we only actually send 2 pixels per 257 * clock in the even pixels (0, 2 etc). In the other cycles, 258 * we only send 1 pixel, to data[0]. 259 */ 260 unsigned int send_two_pixels = two_ppc; 261 262 if ((is_rgb || is_legacy) && (i % 3 == 2)) 263 send_two_pixels = 0; 264 if (send_two_pixels) { 265 if (i + 1 == width) { 266 /* for jpg (binary) copy, this can occur 267 * if the file contains an odd number of bytes. 268 */ 269 inputfifo_send_data( 270 data[0], 0); 271 } else { 272 inputfifo_send_data( 273 data[0], data[1]); 274 } 275 /* Additional increment because we send 2 pixels */ 276 data++; 277 i++; 278 } else if (two_ppc && is_legacy) { 279 inputfifo_send_data_b(data[0]); 280 } else { 281 inputfifo_send_data_a(data[0]); 282 } 283 } 284 285 for (i = 0; i < width2; i++, data2++) { 286 /* for RGB in two_ppc, we only actually send 2 pixels per 287 * clock in the even pixels (0, 2 etc). In the other cycles, 288 * we only send 1 pixel, to data2[0]. 289 */ 290 unsigned int send_two_pixels = two_ppc; 291 292 if ((is_rgb || is_legacy) && (i % 3 == 2)) 293 send_two_pixels = 0; 294 if (send_two_pixels) { 295 if (i + 1 == width2) { 296 /* for jpg (binary) copy, this can occur 297 * if the file contains an odd number of bytes. 298 */ 299 inputfifo_send_data( 300 data2[0], 0); 301 } else { 302 inputfifo_send_data( 303 data2[0], data2[1]); 304 } 305 /* Additional increment because we send 2 pixels */ 306 data2++; 307 i++; 308 } else if (two_ppc && is_legacy) { 309 inputfifo_send_data_b(data2[0]); 310 } else { 311 inputfifo_send_data_a(data2[0]); 312 } 313 } 314 for (i = 0; i < hblank_cycles; i++) 315 inputfifo_send_empty_token(); 316 inputfifo_send_eol(); 317 return; 318 } 319 320 static void 321 inputfifo_send_line(const unsigned short *data, 322 unsigned int width, 323 unsigned int hblank_cycles, 324 unsigned int marker_cycles, 325 unsigned int two_ppc, 326 enum inputfifo_mipi_data_type type) 327 { 328 assert(data); 329 inputfifo_send_line2(data, width, NULL, 0, 330 hblank_cycles, 331 marker_cycles, 332 two_ppc, 333 type); 334 } 335 336 /* Send a frame of data into the input network via the GP FIFO. 337 * Parameters: 338 * - data: array of 16 bit values that contains all data for the frame. 339 * - width: width of a line in number of subpixels, for yuv420 it is the 340 * number of Y components per line. 341 * - height: height of the frame in number of lines. 342 * - ch_id: channel ID. 343 * - fmt_type: format type. 344 * - hblank_cycles: length of horizontal blanking in cycles. 345 * - marker_cycles: number of empty cycles after start-of-line and before 346 * end-of-frame. 347 * - two_ppc: boolean, describes whether to send one or two pixels per clock 348 * cycle. In this mode, we sent pixels N and N+1 in the same cycle, 349 * to IF_PRIM_A and IF_PRIM_B respectively. The caller must make 350 * sure the input data has been formatted correctly for this. 351 * For example, for RGB formats this means that unused values 352 * must be inserted. 353 * - yuv420: boolean, describes whether (non-legacy) yuv420 data is used. In 354 * this mode, the odd lines (1,3,5 etc) are half as long as the 355 * even lines (2,4,6 etc). 356 * Note that the first line is odd (1) and the second line is even 357 * (2). 358 * 359 * This function does not do any reordering of pixels, the caller must make 360 * sure the data is in the righ format. Please refer to the CSS receiver 361 * documentation for details on the data formats. 362 */ 363 364 static void inputfifo_send_frame( 365 const unsigned short *data, 366 unsigned int width, 367 unsigned int height, 368 unsigned int ch_id, 369 unsigned int fmt_type, 370 unsigned int hblank_cycles, 371 unsigned int marker_cycles, 372 unsigned int two_ppc, 373 enum inputfifo_mipi_data_type type) 374 { 375 unsigned int i; 376 377 assert(data); 378 inputfifo_start_frame(ch_id, fmt_type); 379 380 for (i = 0; i < height; i++) { 381 if ((type == inputfifo_mipi_data_type_yuv420) && 382 (i & 1) == 1) { 383 inputfifo_send_line(data, 2 * width, 384 hblank_cycles, 385 marker_cycles, 386 two_ppc, type); 387 data += 2 * width; 388 } else { 389 inputfifo_send_line(data, width, 390 hblank_cycles, 391 marker_cycles, 392 two_ppc, type); 393 data += width; 394 } 395 } 396 inputfifo_end_frame(marker_cycles); 397 return; 398 } 399 400 static enum inputfifo_mipi_data_type inputfifo_determine_type( 401 enum atomisp_input_format input_format) 402 { 403 enum inputfifo_mipi_data_type type; 404 405 type = inputfifo_mipi_data_type_regular; 406 if (input_format == ATOMISP_INPUT_FORMAT_YUV420_8_LEGACY) { 407 type = 408 inputfifo_mipi_data_type_yuv420_legacy; 409 } else if (input_format == ATOMISP_INPUT_FORMAT_YUV420_8 || 410 input_format == ATOMISP_INPUT_FORMAT_YUV420_10 || 411 input_format == ATOMISP_INPUT_FORMAT_YUV420_16) { 412 type = 413 inputfifo_mipi_data_type_yuv420; 414 } else if (input_format >= ATOMISP_INPUT_FORMAT_RGB_444 && 415 input_format <= ATOMISP_INPUT_FORMAT_RGB_888) { 416 type = 417 inputfifo_mipi_data_type_rgb; 418 } 419 return type; 420 } 421 422 static struct inputfifo_instance *inputfifo_get_inst( 423 unsigned int ch_id) 424 { 425 return &inputfifo_inst_admin[ch_id]; 426 } 427 428 void ia_css_inputfifo_send_input_frame( 429 const unsigned short *data, 430 unsigned int width, 431 unsigned int height, 432 unsigned int ch_id, 433 enum atomisp_input_format input_format, 434 bool two_ppc) 435 { 436 unsigned int fmt_type, hblank_cycles, marker_cycles; 437 enum inputfifo_mipi_data_type type; 438 439 assert(data); 440 hblank_cycles = HBLANK_CYCLES; 441 marker_cycles = MARKER_CYCLES; 442 ia_css_isys_convert_stream_format_to_mipi_format(input_format, 443 MIPI_PREDICTOR_NONE, 444 &fmt_type); 445 446 type = inputfifo_determine_type(input_format); 447 448 inputfifo_send_frame(data, width, height, 449 ch_id, fmt_type, hblank_cycles, marker_cycles, 450 two_ppc, type); 451 } 452 453 void ia_css_inputfifo_start_frame( 454 unsigned int ch_id, 455 enum atomisp_input_format input_format, 456 bool two_ppc) 457 { 458 struct inputfifo_instance *s2mi; 459 460 s2mi = inputfifo_get_inst(ch_id); 461 462 s2mi->ch_id = ch_id; 463 ia_css_isys_convert_stream_format_to_mipi_format(input_format, 464 MIPI_PREDICTOR_NONE, 465 &s2mi->fmt_type); 466 s2mi->two_ppc = two_ppc; 467 s2mi->type = inputfifo_determine_type(input_format); 468 s2mi->hblank_cycles = HBLANK_CYCLES; 469 s2mi->marker_cycles = MARKER_CYCLES; 470 s2mi->streaming = true; 471 472 inputfifo_start_frame(ch_id, s2mi->fmt_type); 473 return; 474 } 475 476 void ia_css_inputfifo_send_line( 477 unsigned int ch_id, 478 const unsigned short *data, 479 unsigned int width, 480 const unsigned short *data2, 481 unsigned int width2) 482 { 483 struct inputfifo_instance *s2mi; 484 485 assert(data); 486 assert((data2) || (width2 == 0)); 487 s2mi = inputfifo_get_inst(ch_id); 488 489 /* Set global variables that indicate channel_id and format_type */ 490 inputfifo_curr_ch_id = (s2mi->ch_id) & _HIVE_ISP_CH_ID_MASK; 491 inputfifo_curr_fmt_type = (s2mi->fmt_type) & _HIVE_ISP_FMT_TYPE_MASK; 492 493 inputfifo_send_line2(data, width, data2, width2, 494 s2mi->hblank_cycles, 495 s2mi->marker_cycles, 496 s2mi->two_ppc, 497 s2mi->type); 498 } 499 500 void ia_css_inputfifo_send_embedded_line( 501 unsigned int ch_id, 502 enum atomisp_input_format data_type, 503 const unsigned short *data, 504 unsigned int width) 505 { 506 struct inputfifo_instance *s2mi; 507 unsigned int fmt_type; 508 509 assert(data); 510 s2mi = inputfifo_get_inst(ch_id); 511 ia_css_isys_convert_stream_format_to_mipi_format(data_type, 512 MIPI_PREDICTOR_NONE, &fmt_type); 513 514 /* Set format_type for metadata line. */ 515 inputfifo_curr_fmt_type = fmt_type & _HIVE_ISP_FMT_TYPE_MASK; 516 517 inputfifo_send_line(data, width, s2mi->hblank_cycles, s2mi->marker_cycles, 518 s2mi->two_ppc, inputfifo_mipi_data_type_regular); 519 } 520 521 void ia_css_inputfifo_end_frame( 522 unsigned int ch_id) 523 { 524 struct inputfifo_instance *s2mi; 525 526 s2mi = inputfifo_get_inst(ch_id); 527 528 /* Set global variables that indicate channel_id and format_type */ 529 inputfifo_curr_ch_id = (s2mi->ch_id) & _HIVE_ISP_CH_ID_MASK; 530 inputfifo_curr_fmt_type = (s2mi->fmt_type) & _HIVE_ISP_FMT_TYPE_MASK; 531 532 /* Call existing HRT function */ 533 inputfifo_end_frame(s2mi->marker_cycles); 534 535 s2mi->streaming = false; 536 return; 537 } 538 #endif /* #if !defined(HAS_NO_INPUT_SYSTEM) */ 539