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