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