Quellcodebibliothek Statistik Leitseite products/sources/formale Sprachen/C/Linux/drivers/media/platform/st/sti/bdisp/   (Open Source Betriebssystem Version 6.17.9©)  Datei vom 24.10.2025 mit Größe 27 kB image not shown  

Quelle  bdisp-hw.c   Sprache: C

 
// SPDX-License-Identifier: GPL-2.0
/*
 * Copyright (C) STMicroelectronics SA 2014
 * Authors: Fabien Dessenne <fabien.dessenne@st.com> for STMicroelectronics.
 */


#include <linux/delay.h>

#include "bdisp.h"
#include "bdisp-filter.h"
#include "bdisp-reg.h"

/* Max width of the source frame in a single node */
#define MAX_SRC_WIDTH           2048

/* Reset & boot poll config */
#define POLL_RST_MAX            500
#define POLL_RST_DELAY_MS       2

enum bdisp_target_plan {
 BDISP_RGB,
 BDISP_Y,
 BDISP_CBCR
};

struct bdisp_op_cfg {
 bool cconv;          /* RGB - YUV conversion */
 bool hflip;          /* Horizontal flip */
 bool vflip;          /* Vertical flip */
 bool wide;           /* Wide (>MAX_SRC_WIDTH) */
 bool scale;          /* Scale */
 u16  h_inc;          /* Horizontal increment in 6.10 format */
 u16  v_inc;          /* Vertical increment in 6.10 format */
 bool src_interlaced; /* is the src an interlaced buffer */
 u8   src_nbp;        /* nb of planes of the src */
 bool src_yuv;        /* is the src a YUV color format */
 bool src_420;        /* is the src 4:2:0 chroma subsampled */
 u8   dst_nbp;        /* nb of planes of the dst */
 bool dst_yuv;        /* is the dst a YUV color format */
 bool dst_420;        /* is the dst 4:2:0 chroma subsampled */
};

struct bdisp_filter_addr {
 u16 min;             /* Filter min scale factor (6.10 fixed point) */
 u16 max;             /* Filter max scale factor (6.10 fixed point) */
 void *virt;          /* Virtual address for filter table */
 dma_addr_t paddr;    /* Physical address for filter table */
};

static const struct bdisp_filter_h_spec bdisp_h_spec[] = {
 {
  .min = 0,
  .max = 921,
  .coef = {
   0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00,
   0x00, 0x00, 0xff, 0x07, 0x3d, 0xfc, 0x01, 0x00,
   0x00, 0x01, 0xfd, 0x11, 0x36, 0xf9, 0x02, 0x00,
   0x00, 0x01, 0xfb, 0x1b, 0x2e, 0xf9, 0x02, 0x00,
   0x00, 0x01, 0xf9, 0x26, 0x26, 0xf9, 0x01, 0x00,
   0x00, 0x02, 0xf9, 0x30, 0x19, 0xfb, 0x01, 0x00,
   0x00, 0x02, 0xf9, 0x39, 0x0e, 0xfd, 0x01, 0x00,
   0x00, 0x01, 0xfc, 0x3e, 0x06, 0xff, 0x00, 0x00
  }
 },
 {
  .min = 921,
  .max = 1024,
  .coef = {
   0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00,
   0xff, 0x03, 0xfd, 0x08, 0x3e, 0xf9, 0x04, 0xfe,
   0xfd, 0x06, 0xf8, 0x13, 0x3b, 0xf4, 0x07, 0xfc,
   0xfb, 0x08, 0xf5, 0x1f, 0x34, 0xf1, 0x09, 0xfb,
   0xfb, 0x09, 0xf2, 0x2b, 0x2a, 0xf1, 0x09, 0xfb,
   0xfb, 0x09, 0xf2, 0x35, 0x1e, 0xf4, 0x08, 0xfb,
   0xfc, 0x07, 0xf5, 0x3c, 0x12, 0xf7, 0x06, 0xfd,
   0xfe, 0x04, 0xfa, 0x3f, 0x07, 0xfc, 0x03, 0xff
  }
 },
 {
  .min = 1024,
  .max = 1126,
  .coef = {
   0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00,
   0xff, 0x03, 0xfd, 0x08, 0x3e, 0xf9, 0x04, 0xfe,
   0xfd, 0x06, 0xf8, 0x13, 0x3b, 0xf4, 0x07, 0xfc,
   0xfb, 0x08, 0xf5, 0x1f, 0x34, 0xf1, 0x09, 0xfb,
   0xfb, 0x09, 0xf2, 0x2b, 0x2a, 0xf1, 0x09, 0xfb,
   0xfb, 0x09, 0xf2, 0x35, 0x1e, 0xf4, 0x08, 0xfb,
   0xfc, 0x07, 0xf5, 0x3c, 0x12, 0xf7, 0x06, 0xfd,
   0xfe, 0x04, 0xfa, 0x3f, 0x07, 0xfc, 0x03, 0xff
  }
 },
 {
  .min = 1126,
  .max = 1228,
  .coef = {
   0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00,
   0xff, 0x03, 0xfd, 0x08, 0x3e, 0xf9, 0x04, 0xfe,
   0xfd, 0x06, 0xf8, 0x13, 0x3b, 0xf4, 0x07, 0xfc,
   0xfb, 0x08, 0xf5, 0x1f, 0x34, 0xf1, 0x09, 0xfb,
   0xfb, 0x09, 0xf2, 0x2b, 0x2a, 0xf1, 0x09, 0xfb,
   0xfb, 0x09, 0xf2, 0x35, 0x1e, 0xf4, 0x08, 0xfb,
   0xfc, 0x07, 0xf5, 0x3c, 0x12, 0xf7, 0x06, 0xfd,
   0xfe, 0x04, 0xfa, 0x3f, 0x07, 0xfc, 0x03, 0xff
  }
 },
 {
  .min = 1228,
  .max = 1331,
  .coef = {
   0xfd, 0x04, 0xfc, 0x05, 0x39, 0x05, 0xfc, 0x04,
   0xfc, 0x06, 0xf9, 0x0c, 0x39, 0xfe, 0x00, 0x02,
   0xfb, 0x08, 0xf6, 0x17, 0x35, 0xf9, 0x02, 0x00,
   0xfc, 0x08, 0xf4, 0x20, 0x30, 0xf4, 0x05, 0xff,
   0xfd, 0x07, 0xf4, 0x29, 0x28, 0xf3, 0x07, 0xfd,
   0xff, 0x05, 0xf5, 0x31, 0x1f, 0xf3, 0x08, 0xfc,
   0x00, 0x02, 0xf9, 0x38, 0x14, 0xf6, 0x08, 0xfb,
   0x02, 0x00, 0xff, 0x3a, 0x0b, 0xf8, 0x06, 0xfc
  }
 },
 {
  .min = 1331,
  .max = 1433,
  .coef = {
   0xfc, 0x06, 0xf9, 0x09, 0x34, 0x09, 0xf9, 0x06,
   0xfd, 0x07, 0xf7, 0x10, 0x32, 0x02, 0xfc, 0x05,
   0xfe, 0x07, 0xf6, 0x17, 0x2f, 0xfc, 0xff, 0x04,
   0xff, 0x06, 0xf5, 0x20, 0x2a, 0xf9, 0x01, 0x02,
   0x00, 0x04, 0xf6, 0x27, 0x25, 0xf6, 0x04, 0x00,
   0x02, 0x01, 0xf9, 0x2d, 0x1d, 0xf5, 0x06, 0xff,
   0x04, 0xff, 0xfd, 0x31, 0x15, 0xf5, 0x07, 0xfe,
   0x05, 0xfc, 0x02, 0x35, 0x0d, 0xf7, 0x07, 0xfd
  }
 },
 {
  .min = 1433,
  .max = 1536,
  .coef = {
   0xfe, 0x06, 0xf8, 0x0b, 0x30, 0x0b, 0xf8, 0x06,
   0xff, 0x06, 0xf7, 0x12, 0x2d, 0x05, 0xfa, 0x06,
   0x00, 0x04, 0xf6, 0x18, 0x2c, 0x00, 0xfc, 0x06,
   0x01, 0x02, 0xf7, 0x1f, 0x27, 0xfd, 0xff, 0x04,
   0x03, 0x00, 0xf9, 0x24, 0x24, 0xf9, 0x00, 0x03,
   0x04, 0xff, 0xfd, 0x29, 0x1d, 0xf7, 0x02, 0x01,
   0x06, 0xfc, 0x00, 0x2d, 0x17, 0xf6, 0x04, 0x00,
   0x06, 0xfa, 0x05, 0x30, 0x0f, 0xf7, 0x06, 0xff
  }
 },
 {
  .min = 1536,
  .max = 2048,
  .coef = {
   0x05, 0xfd, 0xfb, 0x13, 0x25, 0x13, 0xfb, 0xfd,
   0x05, 0xfc, 0xfd, 0x17, 0x24, 0x0f, 0xf9, 0xff,
   0x04, 0xfa, 0xff, 0x1b, 0x24, 0x0b, 0xf9, 0x00,
   0x03, 0xf9, 0x01, 0x1f, 0x23, 0x08, 0xf8, 0x01,
   0x02, 0xf9, 0x04, 0x22, 0x20, 0x04, 0xf9, 0x02,
   0x01, 0xf8, 0x08, 0x25, 0x1d, 0x01, 0xf9, 0x03,
   0x00, 0xf9, 0x0c, 0x25, 0x1a, 0xfe, 0xfa, 0x04,
   0xff, 0xf9, 0x10, 0x26, 0x15, 0xfc, 0xfc, 0x05
  }
 },
 {
  .min = 2048,
  .max = 3072,
  .coef = {
   0xfc, 0xfd, 0x06, 0x13, 0x18, 0x13, 0x06, 0xfd,
   0xfc, 0xfe, 0x08, 0x15, 0x17, 0x12, 0x04, 0xfc,
   0xfb, 0xfe, 0x0a, 0x16, 0x18, 0x10, 0x03, 0xfc,
   0xfb, 0x00, 0x0b, 0x18, 0x17, 0x0f, 0x01, 0xfb,
   0xfb, 0x00, 0x0d, 0x19, 0x17, 0x0d, 0x00, 0xfb,
   0xfb, 0x01, 0x0f, 0x19, 0x16, 0x0b, 0x00, 0xfb,
   0xfc, 0x03, 0x11, 0x19, 0x15, 0x09, 0xfe, 0xfb,
   0xfc, 0x04, 0x12, 0x1a, 0x12, 0x08, 0xfe, 0xfc
  }
 },
 {
  .min = 3072,
  .max = 4096,
  .coef = {
   0xfe, 0x02, 0x09, 0x0f, 0x0e, 0x0f, 0x09, 0x02,
   0xff, 0x02, 0x09, 0x0f, 0x10, 0x0e, 0x08, 0x01,
   0xff, 0x03, 0x0a, 0x10, 0x10, 0x0d, 0x07, 0x00,
   0x00, 0x04, 0x0b, 0x10, 0x0f, 0x0c, 0x06, 0x00,
   0x00, 0x05, 0x0c, 0x10, 0x0e, 0x0c, 0x05, 0x00,
   0x00, 0x06, 0x0c, 0x11, 0x0e, 0x0b, 0x04, 0x00,
   0x00, 0x07, 0x0d, 0x11, 0x0f, 0x0a, 0x03, 0xff,
   0x01, 0x08, 0x0e, 0x11, 0x0e, 0x09, 0x02, 0xff
  }
 },
 {
  .min = 4096,
  .max = 5120,
  .coef = {
   0x00, 0x04, 0x09, 0x0c, 0x0e, 0x0c, 0x09, 0x04,
   0x01, 0x05, 0x09, 0x0c, 0x0d, 0x0c, 0x08, 0x04,
   0x01, 0x05, 0x0a, 0x0c, 0x0e, 0x0b, 0x08, 0x03,
   0x02, 0x06, 0x0a, 0x0d, 0x0c, 0x0b, 0x07, 0x03,
   0x02, 0x07, 0x0a, 0x0d, 0x0d, 0x0a, 0x07, 0x02,
   0x03, 0x07, 0x0b, 0x0d, 0x0c, 0x0a, 0x06, 0x02,
   0x03, 0x08, 0x0b, 0x0d, 0x0d, 0x0a, 0x05, 0x01,
   0x04, 0x08, 0x0c, 0x0d, 0x0c, 0x09, 0x05, 0x01
  }
 },
 {
  .min = 5120,
  .max = 65535,
  .coef = {
   0x03, 0x06, 0x09, 0x0b, 0x09, 0x0b, 0x09, 0x06,
   0x03, 0x06, 0x09, 0x0b, 0x0c, 0x0a, 0x08, 0x05,
   0x03, 0x06, 0x09, 0x0b, 0x0c, 0x0a, 0x08, 0x05,
   0x04, 0x07, 0x09, 0x0b, 0x0b, 0x0a, 0x08, 0x04,
   0x04, 0x07, 0x0a, 0x0b, 0x0b, 0x0a, 0x07, 0x04,
   0x04, 0x08, 0x0a, 0x0b, 0x0b, 0x09, 0x07, 0x04,
   0x05, 0x08, 0x0a, 0x0b, 0x0c, 0x09, 0x06, 0x03,
   0x05, 0x08, 0x0a, 0x0b, 0x0c, 0x09, 0x06, 0x03
  }
 }
};

#define NB_H_FILTER ARRAY_SIZE(bdisp_h_spec)


static const struct bdisp_filter_v_spec bdisp_v_spec[] = {
 {
  .min = 0,
  .max = 1024,
  .coef = {
   0x00, 0x00, 0x40, 0x00, 0x00,
   0x00, 0x06, 0x3d, 0xfd, 0x00,
   0xfe, 0x0f, 0x38, 0xfb, 0x00,
   0xfd, 0x19, 0x2f, 0xfb, 0x00,
   0xfc, 0x24, 0x24, 0xfc, 0x00,
   0xfb, 0x2f, 0x19, 0xfd, 0x00,
   0xfb, 0x38, 0x0f, 0xfe, 0x00,
   0xfd, 0x3d, 0x06, 0x00, 0x00
  }
 },
 {
  .min = 1024,
  .max = 1331,
  .coef = {
   0xfc, 0x05, 0x3e, 0x05, 0xfc,
   0xf8, 0x0e, 0x3b, 0xff, 0x00,
   0xf5, 0x18, 0x38, 0xf9, 0x02,
   0xf4, 0x21, 0x31, 0xf5, 0x05,
   0xf4, 0x2a, 0x27, 0xf4, 0x07,
   0xf6, 0x30, 0x1e, 0xf4, 0x08,
   0xf9, 0x35, 0x15, 0xf6, 0x07,
   0xff, 0x37, 0x0b, 0xf9, 0x06
  }
 },
 {
  .min = 1331,
  .max = 1433,
  .coef = {
   0xf8, 0x0a, 0x3c, 0x0a, 0xf8,
   0xf6, 0x12, 0x3b, 0x02, 0xfb,
   0xf4, 0x1b, 0x35, 0xfd, 0xff,
   0xf4, 0x23, 0x30, 0xf8, 0x01,
   0xf6, 0x29, 0x27, 0xf6, 0x04,
   0xf9, 0x2e, 0x1e, 0xf5, 0x06,
   0xfd, 0x31, 0x16, 0xf6, 0x06,
   0x02, 0x32, 0x0d, 0xf8, 0x07
  }
 },
 {
  .min = 1433,
  .max = 1536,
  .coef = {
   0xf6, 0x0e, 0x38, 0x0e, 0xf6,
   0xf5, 0x15, 0x38, 0x06, 0xf8,
   0xf5, 0x1d, 0x33, 0x00, 0xfb,
   0xf6, 0x23, 0x2d, 0xfc, 0xfe,
   0xf9, 0x28, 0x26, 0xf9, 0x00,
   0xfc, 0x2c, 0x1e, 0xf7, 0x03,
   0x00, 0x2e, 0x18, 0xf6, 0x04,
   0x05, 0x2e, 0x11, 0xf7, 0x05
  }
 },
 {
  .min = 1536,
  .max = 2048,
  .coef = {
   0xfb, 0x13, 0x24, 0x13, 0xfb,
   0xfd, 0x17, 0x23, 0x0f, 0xfa,
   0xff, 0x1a, 0x23, 0x0b, 0xf9,
   0x01, 0x1d, 0x22, 0x07, 0xf9,
   0x04, 0x20, 0x1f, 0x04, 0xf9,
   0x07, 0x22, 0x1c, 0x01, 0xfa,
   0x0b, 0x24, 0x17, 0xff, 0xfb,
   0x0f, 0x24, 0x14, 0xfd, 0xfc
  }
 },
 {
  .min = 2048,
  .max = 3072,
  .coef = {
   0x05, 0x10, 0x16, 0x10, 0x05,
   0x06, 0x11, 0x16, 0x0f, 0x04,
   0x08, 0x13, 0x15, 0x0e, 0x02,
   0x09, 0x14, 0x16, 0x0c, 0x01,
   0x0b, 0x15, 0x15, 0x0b, 0x00,
   0x0d, 0x16, 0x13, 0x0a, 0x00,
   0x0f, 0x17, 0x13, 0x08, 0xff,
   0x11, 0x18, 0x12, 0x07, 0xfe
  }
 },
 {
  .min = 3072,
  .max = 4096,
  .coef = {
   0x09, 0x0f, 0x10, 0x0f, 0x09,
   0x09, 0x0f, 0x12, 0x0e, 0x08,
   0x0a, 0x10, 0x11, 0x0e, 0x07,
   0x0b, 0x11, 0x11, 0x0d, 0x06,
   0x0c, 0x11, 0x12, 0x0c, 0x05,
   0x0d, 0x12, 0x11, 0x0c, 0x04,
   0x0e, 0x12, 0x11, 0x0b, 0x04,
   0x0f, 0x13, 0x11, 0x0a, 0x03
  }
 },
 {
  .min = 4096,
  .max = 5120,
  .coef = {
   0x0a, 0x0e, 0x10, 0x0e, 0x0a,
   0x0b, 0x0e, 0x0f, 0x0e, 0x0a,
   0x0b, 0x0f, 0x10, 0x0d, 0x09,
   0x0c, 0x0f, 0x10, 0x0d, 0x08,
   0x0d, 0x0f, 0x0f, 0x0d, 0x08,
   0x0d, 0x10, 0x10, 0x0c, 0x07,
   0x0e, 0x10, 0x0f, 0x0c, 0x07,
   0x0f, 0x10, 0x10, 0x0b, 0x06
  }
 },
 {
  .min = 5120,
  .max = 65535,
  .coef = {
   0x0b, 0x0e, 0x0e, 0x0e, 0x0b,
   0x0b, 0x0e, 0x0f, 0x0d, 0x0b,
   0x0c, 0x0e, 0x0f, 0x0d, 0x0a,
   0x0c, 0x0e, 0x0f, 0x0d, 0x0a,
   0x0d, 0x0f, 0x0e, 0x0d, 0x09,
   0x0d, 0x0f, 0x0f, 0x0c, 0x09,
   0x0e, 0x0f, 0x0e, 0x0c, 0x09,
   0x0e, 0x0f, 0x0f, 0x0c, 0x08
  }
 }
};

#define NB_V_FILTER ARRAY_SIZE(bdisp_v_spec)

static struct bdisp_filter_addr bdisp_h_filter[NB_H_FILTER];
static struct bdisp_filter_addr bdisp_v_filter[NB_V_FILTER];

/**
 * bdisp_hw_reset
 * @bdisp:      bdisp entity
 *
 * Resets HW
 *
 * RETURNS:
 * 0 on success.
 */

int bdisp_hw_reset(struct bdisp_dev *bdisp)
{
 unsigned int i;

 dev_dbg(bdisp->dev, "%s\n", __func__);

 /* Mask Interrupt */
 writel(0, bdisp->regs + BLT_ITM0);

 /* Reset */
 writel(readl(bdisp->regs + BLT_CTL) | BLT_CTL_RESET,
        bdisp->regs + BLT_CTL);
 writel(0, bdisp->regs + BLT_CTL);

 /* Wait for reset done */
 for (i = 0; i < POLL_RST_MAX; i++) {
  if (readl(bdisp->regs + BLT_STA1) & BLT_STA1_IDLE)
   break;
  udelay(POLL_RST_DELAY_MS * 1000);
 }
 if (i == POLL_RST_MAX)
  dev_err(bdisp->dev, "Reset timeout\n");

 return (i == POLL_RST_MAX) ? -EAGAIN : 0;
}

/**
 * bdisp_hw_get_and_clear_irq
 * @bdisp:      bdisp entity
 *
 * Read then reset interrupt status
 *
 * RETURNS:
 * 0 if expected interrupt was raised.
 */

int bdisp_hw_get_and_clear_irq(struct bdisp_dev *bdisp)
{
 u32 its;

 its = readl(bdisp->regs + BLT_ITS);

 /* Check for the only expected IT: LastNode of AQ1 */
 if (!(its & BLT_ITS_AQ1_LNA)) {
  dev_dbg(bdisp->dev, "Unexpected IT status: 0x%08X\n", its);
  writel(its, bdisp->regs + BLT_ITS);
  return -1;
 }

 /* Clear and mask */
 writel(its, bdisp->regs + BLT_ITS);
 writel(0, bdisp->regs + BLT_ITM0);

 return 0;
}

/**
 * bdisp_hw_free_nodes
 * @ctx:        bdisp context
 *
 * Free node memory
 *
 * RETURNS:
 * None
 */

void bdisp_hw_free_nodes(struct bdisp_ctx *ctx)
{
 if (ctx && ctx->node[0])
  dma_free_attrs(ctx->bdisp_dev->dev,
          sizeof(struct bdisp_node) * MAX_NB_NODE,
          ctx->node[0], ctx->node_paddr[0],
          DMA_ATTR_WRITE_COMBINE);
}

/**
 * bdisp_hw_alloc_nodes
 * @ctx:        bdisp context
 *
 * Allocate dma memory for nodes
 *
 * RETURNS:
 * 0 on success
 */

int bdisp_hw_alloc_nodes(struct bdisp_ctx *ctx)
{
 struct device *dev = ctx->bdisp_dev->dev;
 unsigned int i, node_size = sizeof(struct bdisp_node);
 void *base;
 dma_addr_t paddr;

 /* Allocate all the nodes within a single memory page */
 base = dma_alloc_attrs(dev, node_size * MAX_NB_NODE, &paddr,
          GFP_KERNEL, DMA_ATTR_WRITE_COMBINE);
 if (!base) {
  dev_err(dev, "%s no mem\n", __func__);
  return -ENOMEM;
 }

 memset(base, 0, node_size * MAX_NB_NODE);

 for (i = 0; i < MAX_NB_NODE; i++) {
  ctx->node[i] = base;
  ctx->node_paddr[i] = paddr;
  dev_dbg(dev, "node[%d]=0x%p (paddr=%pad)\n", i, ctx->node[i],
   &paddr);
  base += node_size;
  paddr += node_size;
 }

 return 0;
}

/**
 * bdisp_hw_free_filters
 * @dev:        device
 *
 * Free filters memory
 *
 * RETURNS:
 * None
 */

void bdisp_hw_free_filters(struct device *dev)
{
 int size = (BDISP_HF_NB * NB_H_FILTER) + (BDISP_VF_NB * NB_V_FILTER);

 if (bdisp_h_filter[0].virt)
  dma_free_attrs(dev, size, bdisp_h_filter[0].virt,
          bdisp_h_filter[0].paddr, DMA_ATTR_WRITE_COMBINE);
}

/**
 * bdisp_hw_alloc_filters
 * @dev:        device
 *
 * Allocate dma memory for filters
 *
 * RETURNS:
 * 0 on success
 */

int bdisp_hw_alloc_filters(struct device *dev)
{
 unsigned int i, size;
 void *base;
 dma_addr_t paddr;

 /* Allocate all the filters within a single memory page */
 size = (BDISP_HF_NB * NB_H_FILTER) + (BDISP_VF_NB * NB_V_FILTER);
 base = dma_alloc_attrs(dev, size, &paddr, GFP_KERNEL,
          DMA_ATTR_WRITE_COMBINE);
 if (!base)
  return -ENOMEM;

 /* Setup filter addresses */
 for (i = 0; i < NB_H_FILTER; i++) {
  bdisp_h_filter[i].min = bdisp_h_spec[i].min;
  bdisp_h_filter[i].max = bdisp_h_spec[i].max;
  memcpy(base, bdisp_h_spec[i].coef, BDISP_HF_NB);
  bdisp_h_filter[i].virt = base;
  bdisp_h_filter[i].paddr = paddr;
  base += BDISP_HF_NB;
  paddr += BDISP_HF_NB;
 }

 for (i = 0; i < NB_V_FILTER; i++) {
  bdisp_v_filter[i].min = bdisp_v_spec[i].min;
  bdisp_v_filter[i].max = bdisp_v_spec[i].max;
  memcpy(base, bdisp_v_spec[i].coef, BDISP_VF_NB);
  bdisp_v_filter[i].virt = base;
  bdisp_v_filter[i].paddr = paddr;
  base += BDISP_VF_NB;
  paddr += BDISP_VF_NB;
 }

 return 0;
}

/**
 * bdisp_hw_get_hf_addr
 * @inc:        resize increment
 *
 * Find the horizontal filter table that fits the resize increment
 *
 * RETURNS:
 * table physical address
 */

static dma_addr_t bdisp_hw_get_hf_addr(u16 inc)
{
 unsigned int i;

 for (i = NB_H_FILTER - 1; i > 0; i--)
  if ((bdisp_h_filter[i].min < inc) &&
      (inc <= bdisp_h_filter[i].max))
   break;

 return bdisp_h_filter[i].paddr;
}

/**
 * bdisp_hw_get_vf_addr
 * @inc:        resize increment
 *
 * Find the vertical filter table that fits the resize increment
 *
 * RETURNS:
 * table physical address
 */

static dma_addr_t bdisp_hw_get_vf_addr(u16 inc)
{
 unsigned int i;

 for (i = NB_V_FILTER - 1; i > 0; i--)
  if ((bdisp_v_filter[i].min < inc) &&
      (inc <= bdisp_v_filter[i].max))
   break;

 return bdisp_v_filter[i].paddr;
}

/**
 * bdisp_hw_get_inc
 * @from:       input size
 * @to:         output size
 * @inc:        resize increment in 6.10 format
 *
 * Computes the increment (inverse of scale) in 6.10 format
 *
 * RETURNS:
 * 0 on success
 */

static int bdisp_hw_get_inc(u32 from, u32 to, u16 *inc)
{
 u32 tmp;

 if (!to)
  return -EINVAL;

 if (to == from) {
  *inc = 1 << 10;
  return 0;
 }

 tmp = (from << 10) / to;
 if ((tmp > 0xFFFF) || (!tmp))
  /* overflow (downscale x 63) or too small (upscale x 1024) */
  return -EINVAL;

 *inc = (u16)tmp;

 return 0;
}

/**
 * bdisp_hw_get_hv_inc
 * @ctx:        device context
 * @h_inc:      horizontal increment
 * @v_inc:      vertical increment
 *
 * Computes the horizontal & vertical increments (inverse of scale)
 *
 * RETURNS:
 * 0 on success
 */

static int bdisp_hw_get_hv_inc(struct bdisp_ctx *ctx, u16 *h_inc, u16 *v_inc)
{
 u32 src_w, src_h, dst_w, dst_h;

 src_w = ctx->src.crop.width;
 src_h = ctx->src.crop.height;
 dst_w = ctx->dst.crop.width;
 dst_h = ctx->dst.crop.height;

 if (bdisp_hw_get_inc(src_w, dst_w, h_inc) ||
     bdisp_hw_get_inc(src_h, dst_h, v_inc)) {
  dev_err(ctx->bdisp_dev->dev,
   "scale factors failed (%dx%d)->(%dx%d)\n",
   src_w, src_h, dst_w, dst_h);
  return -EINVAL;
 }

 return 0;
}

/**
 * bdisp_hw_get_op_cfg
 * @ctx:        device context
 * @c:          operation configuration
 *
 * Check which blitter operations are expected and sets the scaling increments
 *
 * RETURNS:
 * 0 on success
 */

static int bdisp_hw_get_op_cfg(struct bdisp_ctx *ctx, struct bdisp_op_cfg *c)
{
 struct device *dev = ctx->bdisp_dev->dev;
 struct bdisp_frame *src = &ctx->src;
 struct bdisp_frame *dst = &ctx->dst;

 if (src->width > MAX_SRC_WIDTH * MAX_VERTICAL_STRIDES) {
  dev_err(dev, "Image width out of HW caps\n");
  return -EINVAL;
 }

 c->wide = src->width > MAX_SRC_WIDTH;

 c->hflip = ctx->hflip;
 c->vflip = ctx->vflip;

 c->src_interlaced = (src->field == V4L2_FIELD_INTERLACED);

 c->src_nbp = src->fmt->nb_planes;
 c->src_yuv = (src->fmt->pixelformat == V4L2_PIX_FMT_NV12) ||
   (src->fmt->pixelformat == V4L2_PIX_FMT_YUV420);
 c->src_420 = c->src_yuv;

 c->dst_nbp = dst->fmt->nb_planes;
 c->dst_yuv = (dst->fmt->pixelformat == V4L2_PIX_FMT_NV12) ||
   (dst->fmt->pixelformat == V4L2_PIX_FMT_YUV420);
 c->dst_420 = c->dst_yuv;

 c->cconv = (c->src_yuv != c->dst_yuv);

 if (bdisp_hw_get_hv_inc(ctx, &c->h_inc, &c->v_inc)) {
  dev_err(dev, "Scale factor out of HW caps\n");
  return -EINVAL;
 }

 /* Deinterlacing adjustment : stretch a field to a frame */
 if (c->src_interlaced)
  c->v_inc /= 2;

 if ((c->h_inc != (1 << 10)) || (c->v_inc != (1 << 10)))
  c->scale = true;
 else
  c->scale = false;

 return 0;
}

/**
 * bdisp_hw_color_format
 * @pixelformat: v4l2 pixel format
 *
 * v4l2 to bdisp pixel format convert
 *
 * RETURNS:
 * bdisp pixel format
 */

static u32 bdisp_hw_color_format(u32 pixelformat)
{
 u32 ret;

 switch (pixelformat) {
 case V4L2_PIX_FMT_YUV420:
  ret = (BDISP_YUV_3B << BLT_TTY_COL_SHIFT);
  break;
 case V4L2_PIX_FMT_NV12:
  ret = (BDISP_NV12 << BLT_TTY_COL_SHIFT) | BLT_TTY_BIG_END;
  break;
 case V4L2_PIX_FMT_RGB565:
  ret = (BDISP_RGB565 << BLT_TTY_COL_SHIFT);
  break;
 case V4L2_PIX_FMT_XBGR32: /* This V4L format actually refers to xRGB */
  ret = (BDISP_XRGB8888 << BLT_TTY_COL_SHIFT);
  break;
 case V4L2_PIX_FMT_RGB24:  /* RGB888 format */
  ret = (BDISP_RGB888 << BLT_TTY_COL_SHIFT) | BLT_TTY_BIG_END;
  break;
 case V4L2_PIX_FMT_ABGR32: /* This V4L format actually refers to ARGB */

 default:
  ret = (BDISP_ARGB8888 << BLT_TTY_COL_SHIFT) | BLT_TTY_ALPHA_R;
  break;
 }

 return ret;
}

/**
 * bdisp_hw_build_node
 * @ctx:        device context
 * @cfg:        operation configuration
 * @node:       node to be set
 * @t_plan:     whether the node refers to a RGB/Y or a CbCr plane
 * @src_x_offset: x offset in the source image
 *
 * Build a node
 *
 * RETURNS:
 * None
 */

static void bdisp_hw_build_node(struct bdisp_ctx *ctx,
    struct bdisp_op_cfg *cfg,
    struct bdisp_node *node,
    enum bdisp_target_plan t_plan, int src_x_offset)
{
 struct bdisp_frame *src = &ctx->src;
 struct bdisp_frame *dst = &ctx->dst;
 u16 h_inc, v_inc, yh_inc, yv_inc;
 struct v4l2_rect src_rect = src->crop;
 struct v4l2_rect dst_rect = dst->crop;
 int dst_x_offset;
 s32 dst_width = dst->crop.width;
 u32 src_fmt, dst_fmt;
 const u32 *ivmx;

 dev_dbg(ctx->bdisp_dev->dev, "%s\n", __func__);

 memset(node, 0, sizeof(*node));

 /* Adjust src and dst areas wrt src_x_offset */
 src_rect.left += src_x_offset;
 src_rect.width -= src_x_offset;
 src_rect.width = min_t(__s32, MAX_SRC_WIDTH, src_rect.width);

 dst_x_offset = (src_x_offset * dst_width) / ctx->src.crop.width;
 dst_rect.left += dst_x_offset;
 dst_rect.width = (src_rect.width * dst_width) / ctx->src.crop.width;

 /* General */
 src_fmt = src->fmt->pixelformat;
 dst_fmt = dst->fmt->pixelformat;

 node->nip = 0;
 node->cic = BLT_CIC_ALL_GRP;
 node->ack = BLT_ACK_BYPASS_S2S3;

 switch (cfg->src_nbp) {
 case 1:
  /* Src2 = RGB / Src1 = Src3 = off */
  node->ins = BLT_INS_S1_OFF | BLT_INS_S2_MEM | BLT_INS_S3_OFF;
  break;
 case 2:
  /* Src3 = Y
 * Src2 = CbCr or ColorFill if writing the Y plane
 * Src1 = off */

  node->ins = BLT_INS_S1_OFF | BLT_INS_S3_MEM;
  if (t_plan == BDISP_Y)
   node->ins |= BLT_INS_S2_CF;
  else
   node->ins |= BLT_INS_S2_MEM;
  break;
 case 3:
 default:
  /* Src3 = Y
 * Src2 = Cb or ColorFill if writing the Y plane
 * Src1 = Cr or ColorFill if writing the Y plane */

  node->ins = BLT_INS_S3_MEM;
  if (t_plan == BDISP_Y)
   node->ins |= BLT_INS_S2_CF | BLT_INS_S1_CF;
  else
   node->ins |= BLT_INS_S2_MEM | BLT_INS_S1_MEM;
  break;
 }

 /* Color convert */
 node->ins |= cfg->cconv ? BLT_INS_IVMX : 0;
 /* Scale needed if scaling OR 4:2:0 up/downsampling */
 node->ins |= (cfg->scale || cfg->src_420 || cfg->dst_420) ?
   BLT_INS_SCALE : 0;

 /* Target */
 node->tba = (t_plan == BDISP_CBCR) ? dst->paddr[1] : dst->paddr[0];

 node->tty = dst->bytesperline;
 node->tty |= bdisp_hw_color_format(dst_fmt);
 node->tty |= BLT_TTY_DITHER;
 node->tty |= (t_plan == BDISP_CBCR) ? BLT_TTY_CHROMA : 0;
 node->tty |= cfg->hflip ? BLT_TTY_HSO : 0;
 node->tty |= cfg->vflip ? BLT_TTY_VSO : 0;

 if (cfg->dst_420 && (t_plan == BDISP_CBCR)) {
  /* 420 chroma downsampling */
  dst_rect.height /= 2;
  dst_rect.width /= 2;
  dst_rect.left /= 2;
  dst_rect.top /= 2;
  dst_x_offset /= 2;
  dst_width /= 2;
 }

 node->txy = cfg->vflip ? (dst_rect.height - 1) : dst_rect.top;
 node->txy <<= 16;
 node->txy |= cfg->hflip ? (dst_width - dst_x_offset - 1) :
   dst_rect.left;

 node->tsz = dst_rect.height << 16 | dst_rect.width;

 if (cfg->src_interlaced) {
  /* handle only the top field which is half height of a frame */
  src_rect.top /= 2;
  src_rect.height /= 2;
 }

 if (cfg->src_nbp == 1) {
  /* Src 2 : RGB */
  node->s2ba = src->paddr[0];

  node->s2ty = src->bytesperline;
  if (cfg->src_interlaced)
   node->s2ty *= 2;

  node->s2ty |= bdisp_hw_color_format(src_fmt);

  node->s2xy = src_rect.top << 16 | src_rect.left;
  node->s2sz = src_rect.height << 16 | src_rect.width;
 } else {
  /* Src 2 : Cb or CbCr */
  if (cfg->src_420) {
   /* 420 chroma upsampling */
   src_rect.top /= 2;
   src_rect.left /= 2;
   src_rect.width /= 2;
   src_rect.height /= 2;
  }

  node->s2ba = src->paddr[1];

  node->s2ty = src->bytesperline;
  if (cfg->src_nbp == 3)
   node->s2ty /= 2;
  if (cfg->src_interlaced)
   node->s2ty *= 2;

  node->s2ty |= bdisp_hw_color_format(src_fmt);

  node->s2xy = src_rect.top << 16 | src_rect.left;
  node->s2sz = src_rect.height << 16 | src_rect.width;

  if (cfg->src_nbp == 3) {
   /* Src 1 : Cr */
   node->s1ba = src->paddr[2];

   node->s1ty = node->s2ty;
   node->s1xy = node->s2xy;
  }

  /* Src 3 : Y */
  node->s3ba = src->paddr[0];

  node->s3ty = src->bytesperline;
  if (cfg->src_interlaced)
   node->s3ty *= 2;
  node->s3ty |= bdisp_hw_color_format(src_fmt);

  if ((t_plan != BDISP_CBCR) && cfg->src_420) {
   /* No chroma upsampling for output RGB / Y plane */
   node->s3xy = node->s2xy * 2;
   node->s3sz = node->s2sz * 2;
  } else {
   /* No need to read Y (Src3) when writing Chroma */
   node->s3ty |= BLT_S3TY_BLANK_ACC;
   node->s3xy = node->s2xy;
   node->s3sz = node->s2sz;
  }
 }

 /* Resize (scale OR 4:2:0: chroma up/downsampling) */
 if (node->ins & BLT_INS_SCALE) {
  /* no need to compute Y when writing CbCr from RGB input */
  bool skip_y = (t_plan == BDISP_CBCR) && !cfg->src_yuv;

  /* FCTL */
  if (cfg->scale) {
   node->fctl = BLT_FCTL_HV_SCALE;
   if (!skip_y)
    node->fctl |= BLT_FCTL_Y_HV_SCALE;
  } else {
   node->fctl = BLT_FCTL_HV_SAMPLE;
   if (!skip_y)
    node->fctl |= BLT_FCTL_Y_HV_SAMPLE;
  }

  /* RSF - Chroma may need to be up/downsampled */
  h_inc = cfg->h_inc;
  v_inc = cfg->v_inc;
  if (!cfg->src_420 && cfg->dst_420 && (t_plan == BDISP_CBCR)) {
   /* RGB to 4:2:0 for Chroma: downsample */
   h_inc *= 2;
   v_inc *= 2;
  } else if (cfg->src_420 && !cfg->dst_420) {
   /* 4:2:0: to RGB: upsample*/
   h_inc /= 2;
   v_inc /= 2;
  }
  node->rsf = v_inc << 16 | h_inc;

  /* RZI */
  node->rzi = BLT_RZI_DEFAULT;

  /* Filter table physical addr */
  node->hfp = bdisp_hw_get_hf_addr(h_inc);
  node->vfp = bdisp_hw_get_vf_addr(v_inc);

  /* Y version */
  if (!skip_y) {
   yh_inc = cfg->h_inc;
   yv_inc = cfg->v_inc;

   node->y_rsf = yv_inc << 16 | yh_inc;
   node->y_rzi = BLT_RZI_DEFAULT;
   node->y_hfp = bdisp_hw_get_hf_addr(yh_inc);
   node->y_vfp = bdisp_hw_get_vf_addr(yv_inc);
  }
 }

 /* Versatile matrix for RGB / YUV conversion */
 if (cfg->cconv) {
  ivmx = cfg->src_yuv ? bdisp_yuv_to_rgb : bdisp_rgb_to_yuv;

  node->ivmx0 = ivmx[0];
  node->ivmx1 = ivmx[1];
  node->ivmx2 = ivmx[2];
  node->ivmx3 = ivmx[3];
 }
}

/**
 * bdisp_hw_build_all_nodes
 * @ctx:        device context
 *
 * Build all the nodes for the blitter operation
 *
 * RETURNS:
 * 0 on success
 */

static int bdisp_hw_build_all_nodes(struct bdisp_ctx *ctx)
{
 struct bdisp_op_cfg cfg;
 unsigned int i, nid = 0;
 int src_x_offset = 0;

 for (i = 0; i < MAX_NB_NODE; i++)
  if (!ctx->node[i]) {
   dev_err(ctx->bdisp_dev->dev, "node %d is null\n", i);
   return -EINVAL;
  }

 /* Get configuration (scale, flip, ...) */
 if (bdisp_hw_get_op_cfg(ctx, &cfg))
  return -EINVAL;

 /* Split source in vertical strides (HW constraint) */
 for (i = 0; i < MAX_VERTICAL_STRIDES; i++) {
  /* Build RGB/Y node and link it to the previous node */
  bdisp_hw_build_node(ctx, &cfg, ctx->node[nid],
        cfg.dst_nbp == 1 ? BDISP_RGB : BDISP_Y,
        src_x_offset);
  if (nid)
   ctx->node[nid - 1]->nip = ctx->node_paddr[nid];
  nid++;

  /* Build additional Cb(Cr) node, link it to the previous one */
  if (cfg.dst_nbp > 1) {
   bdisp_hw_build_node(ctx, &cfg, ctx->node[nid],
         BDISP_CBCR, src_x_offset);
   ctx->node[nid - 1]->nip = ctx->node_paddr[nid];
   nid++;
  }

  /* Next stride until full width covered */
  src_x_offset += MAX_SRC_WIDTH;
  if (src_x_offset >= ctx->src.crop.width)
   break;
 }

 /* Mark last node as the last */
 ctx->node[nid - 1]->nip = 0;

 return 0;
}

/**
 * bdisp_hw_save_request
 * @ctx:        device context
 *
 * Save a copy of the request and of the built nodes
 *
 * RETURNS:
 * None
 */

static void bdisp_hw_save_request(struct bdisp_ctx *ctx)
{
 struct bdisp_node **copy_node = ctx->bdisp_dev->dbg.copy_node;
 struct bdisp_request *request = &ctx->bdisp_dev->dbg.copy_request;
 struct bdisp_node **node = ctx->node;
 int i;

 /* Request copy */
 request->src = ctx->src;
 request->dst = ctx->dst;
 request->hflip = ctx->hflip;
 request->vflip = ctx->vflip;
 request->nb_req++;

 /* Nodes copy */
 for (i = 0; i < MAX_NB_NODE; i++) {
  /* Allocate memory if not done yet */
  if (!copy_node[i]) {
   copy_node[i] = devm_kzalloc(ctx->bdisp_dev->dev,
          sizeof(*copy_node[i]),
          GFP_ATOMIC);
   if (!copy_node[i])
    return;
  }
  *copy_node[i] = *node[i];
 }
}

/**
 * bdisp_hw_update
 * @ctx:        device context
 *
 * Send the request to the HW
 *
 * RETURNS:
 * 0 on success
 */

int bdisp_hw_update(struct bdisp_ctx *ctx)
{
 int ret;
 struct bdisp_dev *bdisp = ctx->bdisp_dev;
 struct device *dev = bdisp->dev;
 unsigned int node_id;

 dev_dbg(dev, "%s\n", __func__);

 /* build nodes */
 ret = bdisp_hw_build_all_nodes(ctx);
 if (ret) {
  dev_err(dev, "cannot build nodes (%d)\n", ret);
  return ret;
 }

 /* Save a copy of the request */
 bdisp_hw_save_request(ctx);

 /* Configure interrupt to 'Last Node Reached for AQ1' */
 writel(BLT_AQ1_CTL_CFG, bdisp->regs + BLT_AQ1_CTL);
 writel(BLT_ITS_AQ1_LNA, bdisp->regs + BLT_ITM0);

 /* Write first node addr */
 writel(ctx->node_paddr[0], bdisp->regs + BLT_AQ1_IP);

 /* Find and write last node addr : this starts the HW processing */
 for (node_id = 0; node_id < MAX_NB_NODE - 1; node_id++) {
  if (!ctx->node[node_id]->nip)
   break;
 }
 writel(ctx->node_paddr[node_id], bdisp->regs + BLT_AQ1_LNA);

 return 0;
}

Messung V0.5
C=96 H=89 G=92

¤ Dauer der Verarbeitung: 0.3 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.