From 8148baabd1c4b02c0af3002d59a1c92975d2e719 Mon Sep 17 00:00:00 2001 From: Pratyush Yadav Date: Fri, 21 Jan 2022 19:59:00 +0530 Subject: media: platform: re-structure TI drivers The ti-vpe/ sub-directory does not only contain the VPE-specific things. It also contains the CAL driver, which is a completely different subsystem. This is also not a good place to add new drivers for other TI platforms since they will all get mixed up. Separate the VPE and CAL parts into different sub-directories and rename the ti-vpe/ sub-directory to ti/. This is now the place where new TI platform drivers can be added. [mchehab: rebased to apple on the top of media/platform/Kconfig series] Signed-off-by: Pratyush Yadav Reviewed-by: Tomi Valkeinen Reviewed-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/Makefile | 6 +- drivers/media/platform/ti-vpe/Makefile | 16 - drivers/media/platform/ti-vpe/cal-camerarx.c | 915 --------- drivers/media/platform/ti-vpe/cal-video.c | 1049 ---------- drivers/media/platform/ti-vpe/cal.c | 1263 ------------ drivers/media/platform/ti-vpe/cal.h | 343 ---- drivers/media/platform/ti-vpe/cal_regs.h | 463 ----- drivers/media/platform/ti-vpe/csc.c | 279 --- drivers/media/platform/ti-vpe/csc.h | 65 - drivers/media/platform/ti-vpe/sc.c | 306 --- drivers/media/platform/ti-vpe/sc.h | 208 -- drivers/media/platform/ti-vpe/sc_coeff.h | 1339 ------------- drivers/media/platform/ti-vpe/vpdma.c | 1176 ------------ drivers/media/platform/ti-vpe/vpdma.h | 284 --- drivers/media/platform/ti-vpe/vpdma_priv.h | 639 ------ drivers/media/platform/ti-vpe/vpe.c | 2665 -------------------------- drivers/media/platform/ti-vpe/vpe_regs.h | 306 --- drivers/media/platform/ti/Makefile | 3 + drivers/media/platform/ti/cal/Makefile | 3 + drivers/media/platform/ti/cal/cal-camerarx.c | 915 +++++++++ drivers/media/platform/ti/cal/cal-video.c | 1049 ++++++++++ drivers/media/platform/ti/cal/cal.c | 1263 ++++++++++++ drivers/media/platform/ti/cal/cal.h | 343 ++++ drivers/media/platform/ti/cal/cal_regs.h | 463 +++++ drivers/media/platform/ti/vpe/Makefile | 12 + drivers/media/platform/ti/vpe/csc.c | 279 +++ drivers/media/platform/ti/vpe/csc.h | 65 + drivers/media/platform/ti/vpe/sc.c | 306 +++ drivers/media/platform/ti/vpe/sc.h | 208 ++ drivers/media/platform/ti/vpe/sc_coeff.h | 1339 +++++++++++++ drivers/media/platform/ti/vpe/vpdma.c | 1176 ++++++++++++ drivers/media/platform/ti/vpe/vpdma.h | 284 +++ drivers/media/platform/ti/vpe/vpdma_priv.h | 639 ++++++ drivers/media/platform/ti/vpe/vpe.c | 2665 ++++++++++++++++++++++++++ drivers/media/platform/ti/vpe/vpe_regs.h | 306 +++ 35 files changed, 11319 insertions(+), 11321 deletions(-) delete mode 100644 drivers/media/platform/ti-vpe/Makefile delete mode 100644 drivers/media/platform/ti-vpe/cal-camerarx.c delete mode 100644 drivers/media/platform/ti-vpe/cal-video.c delete mode 100644 drivers/media/platform/ti-vpe/cal.c delete mode 100644 drivers/media/platform/ti-vpe/cal.h delete mode 100644 drivers/media/platform/ti-vpe/cal_regs.h delete mode 100644 drivers/media/platform/ti-vpe/csc.c delete mode 100644 drivers/media/platform/ti-vpe/csc.h delete mode 100644 drivers/media/platform/ti-vpe/sc.c delete mode 100644 drivers/media/platform/ti-vpe/sc.h delete mode 100644 drivers/media/platform/ti-vpe/sc_coeff.h delete mode 100644 drivers/media/platform/ti-vpe/vpdma.c delete mode 100644 drivers/media/platform/ti-vpe/vpdma.h delete mode 100644 drivers/media/platform/ti-vpe/vpdma_priv.h delete mode 100644 drivers/media/platform/ti-vpe/vpe.c delete mode 100644 drivers/media/platform/ti-vpe/vpe_regs.h create mode 100644 drivers/media/platform/ti/Makefile create mode 100644 drivers/media/platform/ti/cal/Makefile create mode 100644 drivers/media/platform/ti/cal/cal-camerarx.c create mode 100644 drivers/media/platform/ti/cal/cal-video.c create mode 100644 drivers/media/platform/ti/cal/cal.c create mode 100644 drivers/media/platform/ti/cal/cal.h create mode 100644 drivers/media/platform/ti/cal/cal_regs.h create mode 100644 drivers/media/platform/ti/vpe/Makefile create mode 100644 drivers/media/platform/ti/vpe/csc.c create mode 100644 drivers/media/platform/ti/vpe/csc.h create mode 100644 drivers/media/platform/ti/vpe/sc.c create mode 100644 drivers/media/platform/ti/vpe/sc.h create mode 100644 drivers/media/platform/ti/vpe/sc_coeff.h create mode 100644 drivers/media/platform/ti/vpe/vpdma.c create mode 100644 drivers/media/platform/ti/vpe/vpdma.h create mode 100644 drivers/media/platform/ti/vpe/vpdma_priv.h create mode 100644 drivers/media/platform/ti/vpe/vpe.c create mode 100644 drivers/media/platform/ti/vpe/vpe_regs.h (limited to 'drivers/media') diff --git a/drivers/media/platform/Makefile b/drivers/media/platform/Makefile index 9c532bd4f96f..8d109ae9e039 100644 --- a/drivers/media/platform/Makefile +++ b/drivers/media/platform/Makefile @@ -38,11 +38,7 @@ obj-y += st/sti/c8sectpfe/ obj-y += st/sti/delta/ obj-y += st/sti/hva/ obj-y += st/stm32/ -obj-y += ti-vpe/ -obj-y += ti/am437x/ -obj-y += ti/davinci/ -obj-y += ti/omap/ -obj-y += ti/omap3isp/ +obj-y += ti/ obj-y += via/ obj-y += xilinx/ diff --git a/drivers/media/platform/ti-vpe/Makefile b/drivers/media/platform/ti-vpe/Makefile deleted file mode 100644 index ad624056e039..000000000000 --- a/drivers/media/platform/ti-vpe/Makefile +++ /dev/null @@ -1,16 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -obj-$(CONFIG_VIDEO_TI_VPE) += ti-vpe.o -obj-$(CONFIG_VIDEO_TI_VPDMA) += ti-vpdma.o -obj-$(CONFIG_VIDEO_TI_SC) += ti-sc.o -obj-$(CONFIG_VIDEO_TI_CSC) += ti-csc.o - -ti-vpe-y := vpe.o -ti-vpdma-y := vpdma.o -ti-sc-y := sc.o -ti-csc-y := csc.o - -ccflags-$(CONFIG_VIDEO_TI_VPE_DEBUG) += -DDEBUG - -obj-$(CONFIG_VIDEO_TI_CAL) += ti-cal.o - -ti-cal-y := cal.o cal-camerarx.o cal-video.o diff --git a/drivers/media/platform/ti-vpe/cal-camerarx.c b/drivers/media/platform/ti-vpe/cal-camerarx.c deleted file mode 100644 index 6b43a1525b45..000000000000 --- a/drivers/media/platform/ti-vpe/cal-camerarx.c +++ /dev/null @@ -1,915 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * TI Camera Access Layer (CAL) - CAMERARX - * - * Copyright (c) 2015-2020 Texas Instruments Inc. - * - * Authors: - * Benoit Parrot - * Laurent Pinchart - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include "cal.h" -#include "cal_regs.h" - -/* ------------------------------------------------------------------ - * I/O Register Accessors - * ------------------------------------------------------------------ - */ - -static inline u32 camerarx_read(struct cal_camerarx *phy, u32 offset) -{ - return ioread32(phy->base + offset); -} - -static inline void camerarx_write(struct cal_camerarx *phy, u32 offset, u32 val) -{ - iowrite32(val, phy->base + offset); -} - -/* ------------------------------------------------------------------ - * CAMERARX Management - * ------------------------------------------------------------------ - */ - -static s64 cal_camerarx_get_ext_link_freq(struct cal_camerarx *phy) -{ - struct v4l2_mbus_config_mipi_csi2 *mipi_csi2 = &phy->endpoint.bus.mipi_csi2; - u32 num_lanes = mipi_csi2->num_data_lanes; - const struct cal_format_info *fmtinfo; - u32 bpp; - s64 freq; - - fmtinfo = cal_format_by_code(phy->formats[CAL_CAMERARX_PAD_SINK].code); - if (!fmtinfo) - return -EINVAL; - - bpp = fmtinfo->bpp; - - freq = v4l2_get_link_freq(phy->source->ctrl_handler, bpp, 2 * num_lanes); - if (freq < 0) { - phy_err(phy, "failed to get link freq for subdev '%s'\n", - phy->source->name); - return freq; - } - - phy_dbg(3, phy, "Source Link Freq: %llu\n", freq); - - return freq; -} - -static void cal_camerarx_lane_config(struct cal_camerarx *phy) -{ - u32 val = cal_read(phy->cal, CAL_CSI2_COMPLEXIO_CFG(phy->instance)); - u32 lane_mask = CAL_CSI2_COMPLEXIO_CFG_CLOCK_POSITION_MASK; - u32 polarity_mask = CAL_CSI2_COMPLEXIO_CFG_CLOCK_POL_MASK; - struct v4l2_mbus_config_mipi_csi2 *mipi_csi2 = - &phy->endpoint.bus.mipi_csi2; - int lane; - - cal_set_field(&val, mipi_csi2->clock_lane + 1, lane_mask); - cal_set_field(&val, mipi_csi2->lane_polarities[0], polarity_mask); - for (lane = 0; lane < mipi_csi2->num_data_lanes; lane++) { - /* - * Every lane are one nibble apart starting with the - * clock followed by the data lanes so shift masks by 4. - */ - lane_mask <<= 4; - polarity_mask <<= 4; - cal_set_field(&val, mipi_csi2->data_lanes[lane] + 1, lane_mask); - cal_set_field(&val, mipi_csi2->lane_polarities[lane + 1], - polarity_mask); - } - - cal_write(phy->cal, CAL_CSI2_COMPLEXIO_CFG(phy->instance), val); - phy_dbg(3, phy, "CAL_CSI2_COMPLEXIO_CFG(%d) = 0x%08x\n", - phy->instance, val); -} - -static void cal_camerarx_enable(struct cal_camerarx *phy) -{ - u32 num_lanes = phy->cal->data->camerarx[phy->instance].num_lanes; - - regmap_field_write(phy->fields[F_CAMMODE], 0); - /* Always enable all lanes at the phy control level */ - regmap_field_write(phy->fields[F_LANEENABLE], (1 << num_lanes) - 1); - /* F_CSI_MODE is not present on every architecture */ - if (phy->fields[F_CSI_MODE]) - regmap_field_write(phy->fields[F_CSI_MODE], 1); - regmap_field_write(phy->fields[F_CTRLCLKEN], 1); -} - -void cal_camerarx_disable(struct cal_camerarx *phy) -{ - regmap_field_write(phy->fields[F_CTRLCLKEN], 0); -} - -/* - * TCLK values are OK at their reset values - */ -#define TCLK_TERM 0 -#define TCLK_MISS 1 -#define TCLK_SETTLE 14 - -static void cal_camerarx_config(struct cal_camerarx *phy, s64 link_freq) -{ - unsigned int reg0, reg1; - unsigned int ths_term, ths_settle; - - /* DPHY timing configuration */ - - /* THS_TERM: Programmed value = floor(20 ns/DDRClk period) */ - ths_term = div_s64(20 * link_freq, 1000 * 1000 * 1000); - phy_dbg(1, phy, "ths_term: %d (0x%02x)\n", ths_term, ths_term); - - /* THS_SETTLE: Programmed value = floor(105 ns/DDRClk period) + 4 */ - ths_settle = div_s64(105 * link_freq, 1000 * 1000 * 1000) + 4; - phy_dbg(1, phy, "ths_settle: %d (0x%02x)\n", ths_settle, ths_settle); - - reg0 = camerarx_read(phy, CAL_CSI2_PHY_REG0); - cal_set_field(®0, CAL_CSI2_PHY_REG0_HSCLOCKCONFIG_DISABLE, - CAL_CSI2_PHY_REG0_HSCLOCKCONFIG_MASK); - cal_set_field(®0, ths_term, CAL_CSI2_PHY_REG0_THS_TERM_MASK); - cal_set_field(®0, ths_settle, CAL_CSI2_PHY_REG0_THS_SETTLE_MASK); - - phy_dbg(1, phy, "CSI2_%d_REG0 = 0x%08x\n", phy->instance, reg0); - camerarx_write(phy, CAL_CSI2_PHY_REG0, reg0); - - reg1 = camerarx_read(phy, CAL_CSI2_PHY_REG1); - cal_set_field(®1, TCLK_TERM, CAL_CSI2_PHY_REG1_TCLK_TERM_MASK); - cal_set_field(®1, 0xb8, CAL_CSI2_PHY_REG1_DPHY_HS_SYNC_PATTERN_MASK); - cal_set_field(®1, TCLK_MISS, - CAL_CSI2_PHY_REG1_CTRLCLK_DIV_FACTOR_MASK); - cal_set_field(®1, TCLK_SETTLE, CAL_CSI2_PHY_REG1_TCLK_SETTLE_MASK); - - phy_dbg(1, phy, "CSI2_%d_REG1 = 0x%08x\n", phy->instance, reg1); - camerarx_write(phy, CAL_CSI2_PHY_REG1, reg1); -} - -static void cal_camerarx_power(struct cal_camerarx *phy, bool enable) -{ - u32 target_state; - unsigned int i; - - target_state = enable ? CAL_CSI2_COMPLEXIO_CFG_PWR_CMD_STATE_ON : - CAL_CSI2_COMPLEXIO_CFG_PWR_CMD_STATE_OFF; - - cal_write_field(phy->cal, CAL_CSI2_COMPLEXIO_CFG(phy->instance), - target_state, CAL_CSI2_COMPLEXIO_CFG_PWR_CMD_MASK); - - for (i = 0; i < 10; i++) { - u32 current_state; - - current_state = cal_read_field(phy->cal, - CAL_CSI2_COMPLEXIO_CFG(phy->instance), - CAL_CSI2_COMPLEXIO_CFG_PWR_STATUS_MASK); - - if (current_state == target_state) - break; - - usleep_range(1000, 1100); - } - - if (i == 10) - phy_err(phy, "Failed to power %s complexio\n", - enable ? "up" : "down"); -} - -static void cal_camerarx_wait_reset(struct cal_camerarx *phy) -{ - unsigned long timeout; - - timeout = jiffies + msecs_to_jiffies(750); - while (time_before(jiffies, timeout)) { - if (cal_read_field(phy->cal, - CAL_CSI2_COMPLEXIO_CFG(phy->instance), - CAL_CSI2_COMPLEXIO_CFG_RESET_DONE_MASK) == - CAL_CSI2_COMPLEXIO_CFG_RESET_DONE_RESETCOMPLETED) - break; - usleep_range(500, 5000); - } - - if (cal_read_field(phy->cal, CAL_CSI2_COMPLEXIO_CFG(phy->instance), - CAL_CSI2_COMPLEXIO_CFG_RESET_DONE_MASK) != - CAL_CSI2_COMPLEXIO_CFG_RESET_DONE_RESETCOMPLETED) - phy_err(phy, "Timeout waiting for Complex IO reset done\n"); -} - -static void cal_camerarx_wait_stop_state(struct cal_camerarx *phy) -{ - unsigned long timeout; - - timeout = jiffies + msecs_to_jiffies(750); - while (time_before(jiffies, timeout)) { - if (cal_read_field(phy->cal, - CAL_CSI2_TIMING(phy->instance), - CAL_CSI2_TIMING_FORCE_RX_MODE_IO1_MASK) == 0) - break; - usleep_range(500, 5000); - } - - if (cal_read_field(phy->cal, CAL_CSI2_TIMING(phy->instance), - CAL_CSI2_TIMING_FORCE_RX_MODE_IO1_MASK) != 0) - phy_err(phy, "Timeout waiting for stop state\n"); -} - -static void cal_camerarx_enable_irqs(struct cal_camerarx *phy) -{ - const u32 cio_err_mask = - CAL_CSI2_COMPLEXIO_IRQ_LANE_ERRORS_MASK | - CAL_CSI2_COMPLEXIO_IRQ_FIFO_OVR_MASK | - CAL_CSI2_COMPLEXIO_IRQ_SHORT_PACKET_MASK | - CAL_CSI2_COMPLEXIO_IRQ_ECC_NO_CORRECTION_MASK; - const u32 vc_err_mask = - CAL_CSI2_VC_IRQ_CS_IRQ_MASK(0) | - CAL_CSI2_VC_IRQ_CS_IRQ_MASK(1) | - CAL_CSI2_VC_IRQ_CS_IRQ_MASK(2) | - CAL_CSI2_VC_IRQ_CS_IRQ_MASK(3) | - CAL_CSI2_VC_IRQ_ECC_CORRECTION_IRQ_MASK(0) | - CAL_CSI2_VC_IRQ_ECC_CORRECTION_IRQ_MASK(1) | - CAL_CSI2_VC_IRQ_ECC_CORRECTION_IRQ_MASK(2) | - CAL_CSI2_VC_IRQ_ECC_CORRECTION_IRQ_MASK(3); - - /* Enable CIO & VC error IRQs. */ - cal_write(phy->cal, CAL_HL_IRQENABLE_SET(0), - CAL_HL_IRQ_CIO_MASK(phy->instance) | - CAL_HL_IRQ_VC_MASK(phy->instance)); - cal_write(phy->cal, CAL_CSI2_COMPLEXIO_IRQENABLE(phy->instance), - cio_err_mask); - cal_write(phy->cal, CAL_CSI2_VC_IRQENABLE(phy->instance), - vc_err_mask); -} - -static void cal_camerarx_disable_irqs(struct cal_camerarx *phy) -{ - /* Disable CIO error irqs */ - cal_write(phy->cal, CAL_HL_IRQENABLE_CLR(0), - CAL_HL_IRQ_CIO_MASK(phy->instance) | - CAL_HL_IRQ_VC_MASK(phy->instance)); - cal_write(phy->cal, CAL_CSI2_COMPLEXIO_IRQENABLE(phy->instance), 0); - cal_write(phy->cal, CAL_CSI2_VC_IRQENABLE(phy->instance), 0); -} - -static void cal_camerarx_ppi_enable(struct cal_camerarx *phy) -{ - cal_write_field(phy->cal, CAL_CSI2_PPI_CTRL(phy->instance), - 1, CAL_CSI2_PPI_CTRL_ECC_EN_MASK); - - cal_write_field(phy->cal, CAL_CSI2_PPI_CTRL(phy->instance), - 1, CAL_CSI2_PPI_CTRL_IF_EN_MASK); -} - -static void cal_camerarx_ppi_disable(struct cal_camerarx *phy) -{ - cal_write_field(phy->cal, CAL_CSI2_PPI_CTRL(phy->instance), - 0, CAL_CSI2_PPI_CTRL_IF_EN_MASK); -} - -static int cal_camerarx_start(struct cal_camerarx *phy) -{ - s64 link_freq; - u32 sscounter; - u32 val; - int ret; - - if (phy->enable_count > 0) { - phy->enable_count++; - return 0; - } - - link_freq = cal_camerarx_get_ext_link_freq(phy); - if (link_freq < 0) - return link_freq; - - ret = v4l2_subdev_call(phy->source, core, s_power, 1); - if (ret < 0 && ret != -ENOIOCTLCMD && ret != -ENODEV) { - phy_err(phy, "power on failed in subdev\n"); - return ret; - } - - cal_camerarx_enable_irqs(phy); - - /* - * CSI-2 PHY Link Initialization Sequence, according to the DRA74xP / - * DRA75xP / DRA76xP / DRA77xP TRM. The DRA71x / DRA72x and the AM65x / - * DRA80xM TRMs have a a slightly simplified sequence. - */ - - /* - * 1. Configure all CSI-2 low level protocol registers to be ready to - * receive signals/data from the CSI-2 PHY. - * - * i.-v. Configure the lanes position and polarity. - */ - cal_camerarx_lane_config(phy); - - /* - * vi.-vii. Configure D-PHY mode, enable the required lanes and - * enable the CAMERARX clock. - */ - cal_camerarx_enable(phy); - - /* - * 2. CSI PHY and link initialization sequence. - * - * a. Deassert the CSI-2 PHY reset. Do not wait for reset completion - * at this point, as it requires the external source to send the - * CSI-2 HS clock. - */ - cal_write_field(phy->cal, CAL_CSI2_COMPLEXIO_CFG(phy->instance), - CAL_CSI2_COMPLEXIO_CFG_RESET_CTRL_OPERATIONAL, - CAL_CSI2_COMPLEXIO_CFG_RESET_CTRL_MASK); - phy_dbg(3, phy, "CAL_CSI2_COMPLEXIO_CFG(%d) = 0x%08x De-assert Complex IO Reset\n", - phy->instance, - cal_read(phy->cal, CAL_CSI2_COMPLEXIO_CFG(phy->instance))); - - /* Dummy read to allow SCP reset to complete. */ - camerarx_read(phy, CAL_CSI2_PHY_REG0); - - /* Program the PHY timing parameters. */ - cal_camerarx_config(phy, link_freq); - - /* - * b. Assert the FORCERXMODE signal. - * - * The stop-state-counter is based on fclk cycles, and we always use - * the x16 and x4 settings, so stop-state-timeout = - * fclk-cycle * 16 * 4 * counter. - * - * Stop-state-timeout must be more than 100us as per CSI-2 spec, so we - * calculate a timeout that's 100us (rounding up). - */ - sscounter = DIV_ROUND_UP(clk_get_rate(phy->cal->fclk), 10000 * 16 * 4); - - val = cal_read(phy->cal, CAL_CSI2_TIMING(phy->instance)); - cal_set_field(&val, 1, CAL_CSI2_TIMING_STOP_STATE_X16_IO1_MASK); - cal_set_field(&val, 1, CAL_CSI2_TIMING_STOP_STATE_X4_IO1_MASK); - cal_set_field(&val, sscounter, - CAL_CSI2_TIMING_STOP_STATE_COUNTER_IO1_MASK); - cal_write(phy->cal, CAL_CSI2_TIMING(phy->instance), val); - phy_dbg(3, phy, "CAL_CSI2_TIMING(%d) = 0x%08x Stop States\n", - phy->instance, - cal_read(phy->cal, CAL_CSI2_TIMING(phy->instance))); - - /* Assert the FORCERXMODE signal. */ - cal_write_field(phy->cal, CAL_CSI2_TIMING(phy->instance), - 1, CAL_CSI2_TIMING_FORCE_RX_MODE_IO1_MASK); - phy_dbg(3, phy, "CAL_CSI2_TIMING(%d) = 0x%08x Force RXMODE\n", - phy->instance, - cal_read(phy->cal, CAL_CSI2_TIMING(phy->instance))); - - /* - * c. Connect pull-down on CSI-2 PHY link (using pad control). - * - * This is not required on DRA71x, DRA72x, AM65x and DRA80xM. Not - * implemented. - */ - - /* - * d. Power up the CSI-2 PHY. - * e. Check whether the state status reaches the ON state. - */ - cal_camerarx_power(phy, true); - - /* - * Start the source to enable the CSI-2 HS clock. We can now wait for - * CSI-2 PHY reset to complete. - */ - ret = v4l2_subdev_call(phy->source, video, s_stream, 1); - if (ret) { - v4l2_subdev_call(phy->source, core, s_power, 0); - cal_camerarx_disable_irqs(phy); - phy_err(phy, "stream on failed in subdev\n"); - return ret; - } - - cal_camerarx_wait_reset(phy); - - /* f. Wait for STOPSTATE=1 for all enabled lane modules. */ - cal_camerarx_wait_stop_state(phy); - - phy_dbg(1, phy, "CSI2_%u_REG1 = 0x%08x (bits 31-28 should be set)\n", - phy->instance, camerarx_read(phy, CAL_CSI2_PHY_REG1)); - - /* - * g. Disable pull-down on CSI-2 PHY link (using pad control). - * - * This is not required on DRA71x, DRA72x, AM65x and DRA80xM. Not - * implemented. - */ - - /* Finally, enable the PHY Protocol Interface (PPI). */ - cal_camerarx_ppi_enable(phy); - - phy->enable_count++; - - return 0; -} - -static void cal_camerarx_stop(struct cal_camerarx *phy) -{ - int ret; - - if (--phy->enable_count > 0) - return; - - cal_camerarx_ppi_disable(phy); - - cal_camerarx_disable_irqs(phy); - - cal_camerarx_power(phy, false); - - /* Assert Complex IO Reset */ - cal_write_field(phy->cal, CAL_CSI2_COMPLEXIO_CFG(phy->instance), - CAL_CSI2_COMPLEXIO_CFG_RESET_CTRL, - CAL_CSI2_COMPLEXIO_CFG_RESET_CTRL_MASK); - - phy_dbg(3, phy, "CAL_CSI2_COMPLEXIO_CFG(%d) = 0x%08x Complex IO in Reset\n", - phy->instance, - cal_read(phy->cal, CAL_CSI2_COMPLEXIO_CFG(phy->instance))); - - /* Disable the phy */ - cal_camerarx_disable(phy); - - if (v4l2_subdev_call(phy->source, video, s_stream, 0)) - phy_err(phy, "stream off failed in subdev\n"); - - ret = v4l2_subdev_call(phy->source, core, s_power, 0); - if (ret < 0 && ret != -ENOIOCTLCMD && ret != -ENODEV) - phy_err(phy, "power off failed in subdev\n"); -} - -/* - * Errata i913: CSI2 LDO Needs to be disabled when module is powered on - * - * Enabling CSI2 LDO shorts it to core supply. It is crucial the 2 CSI2 - * LDOs on the device are disabled if CSI-2 module is powered on - * (0x4845 B304 | 0x4845 B384 [28:27] = 0x1) or in ULPS (0x4845 B304 - * | 0x4845 B384 [28:27] = 0x2) mode. Common concerns include: high - * current draw on the module supply in active mode. - * - * Errata does not apply when CSI-2 module is powered off - * (0x4845 B304 | 0x4845 B384 [28:27] = 0x0). - * - * SW Workaround: - * Set the following register bits to disable the LDO, - * which is essentially CSI2 REG10 bit 6: - * - * Core 0: 0x4845 B828 = 0x0000 0040 - * Core 1: 0x4845 B928 = 0x0000 0040 - */ -void cal_camerarx_i913_errata(struct cal_camerarx *phy) -{ - u32 reg10 = camerarx_read(phy, CAL_CSI2_PHY_REG10); - - cal_set_field(®10, 1, CAL_CSI2_PHY_REG10_I933_LDO_DISABLE_MASK); - - phy_dbg(1, phy, "CSI2_%d_REG10 = 0x%08x\n", phy->instance, reg10); - camerarx_write(phy, CAL_CSI2_PHY_REG10, reg10); -} - -static int cal_camerarx_regmap_init(struct cal_dev *cal, - struct cal_camerarx *phy) -{ - const struct cal_camerarx_data *phy_data; - unsigned int i; - - if (!cal->data) - return -EINVAL; - - phy_data = &cal->data->camerarx[phy->instance]; - - for (i = 0; i < F_MAX_FIELDS; i++) { - struct reg_field field = { - .reg = cal->syscon_camerrx_offset, - .lsb = phy_data->fields[i].lsb, - .msb = phy_data->fields[i].msb, - }; - - /* - * Here we update the reg offset with the - * value found in DT - */ - phy->fields[i] = devm_regmap_field_alloc(cal->dev, - cal->syscon_camerrx, - field); - if (IS_ERR(phy->fields[i])) { - cal_err(cal, "Unable to allocate regmap fields\n"); - return PTR_ERR(phy->fields[i]); - } - } - - return 0; -} - -static int cal_camerarx_parse_dt(struct cal_camerarx *phy) -{ - struct v4l2_fwnode_endpoint *endpoint = &phy->endpoint; - char data_lanes[V4L2_MBUS_CSI2_MAX_DATA_LANES * 2]; - struct device_node *ep_node; - unsigned int i; - int ret; - - /* - * Find the endpoint node for the port corresponding to the PHY - * instance, and parse its CSI-2-related properties. - */ - ep_node = of_graph_get_endpoint_by_regs(phy->cal->dev->of_node, - phy->instance, 0); - if (!ep_node) { - /* - * The endpoint is not mandatory, not all PHY instances need to - * be connected in DT. - */ - phy_dbg(3, phy, "Port has no endpoint\n"); - return 0; - } - - endpoint->bus_type = V4L2_MBUS_CSI2_DPHY; - ret = v4l2_fwnode_endpoint_parse(of_fwnode_handle(ep_node), endpoint); - if (ret < 0) { - phy_err(phy, "Failed to parse endpoint\n"); - goto done; - } - - for (i = 0; i < endpoint->bus.mipi_csi2.num_data_lanes; i++) { - unsigned int lane = endpoint->bus.mipi_csi2.data_lanes[i]; - - if (lane > 4) { - phy_err(phy, "Invalid position %u for data lane %u\n", - lane, i); - ret = -EINVAL; - goto done; - } - - data_lanes[i*2] = '0' + lane; - data_lanes[i*2+1] = ' '; - } - - data_lanes[i*2-1] = '\0'; - - phy_dbg(3, phy, - "CSI-2 bus: clock lane <%u>, data lanes <%s>, flags 0x%08x\n", - endpoint->bus.mipi_csi2.clock_lane, data_lanes, - endpoint->bus.mipi_csi2.flags); - - /* Retrieve the connected device and store it for later use. */ - phy->source_ep_node = of_graph_get_remote_endpoint(ep_node); - phy->source_node = of_graph_get_port_parent(phy->source_ep_node); - if (!phy->source_node) { - phy_dbg(3, phy, "Can't get remote parent\n"); - of_node_put(phy->source_ep_node); - ret = -EINVAL; - goto done; - } - - phy_dbg(1, phy, "Found connected device %pOFn\n", phy->source_node); - -done: - of_node_put(ep_node); - return ret; -} - -/* ------------------------------------------------------------------ - * V4L2 Subdev Operations - * ------------------------------------------------------------------ - */ - -static inline struct cal_camerarx *to_cal_camerarx(struct v4l2_subdev *sd) -{ - return container_of(sd, struct cal_camerarx, subdev); -} - -static struct v4l2_mbus_framefmt * -cal_camerarx_get_pad_format(struct cal_camerarx *phy, - struct v4l2_subdev_state *sd_state, - unsigned int pad, u32 which) -{ - switch (which) { - case V4L2_SUBDEV_FORMAT_TRY: - return v4l2_subdev_get_try_format(&phy->subdev, sd_state, pad); - case V4L2_SUBDEV_FORMAT_ACTIVE: - return &phy->formats[pad]; - default: - return NULL; - } -} - -static int cal_camerarx_sd_s_stream(struct v4l2_subdev *sd, int enable) -{ - struct cal_camerarx *phy = to_cal_camerarx(sd); - int ret = 0; - - mutex_lock(&phy->mutex); - - if (enable) - ret = cal_camerarx_start(phy); - else - cal_camerarx_stop(phy); - - mutex_unlock(&phy->mutex); - - return ret; -} - -static int cal_camerarx_sd_enum_mbus_code(struct v4l2_subdev *sd, - struct v4l2_subdev_state *sd_state, - struct v4l2_subdev_mbus_code_enum *code) -{ - struct cal_camerarx *phy = to_cal_camerarx(sd); - int ret = 0; - - mutex_lock(&phy->mutex); - - /* No transcoding, source and sink codes must match. */ - if (cal_rx_pad_is_source(code->pad)) { - struct v4l2_mbus_framefmt *fmt; - - if (code->index > 0) { - ret = -EINVAL; - goto out; - } - - fmt = cal_camerarx_get_pad_format(phy, sd_state, - CAL_CAMERARX_PAD_SINK, - code->which); - code->code = fmt->code; - } else { - if (code->index >= cal_num_formats) { - ret = -EINVAL; - goto out; - } - - code->code = cal_formats[code->index].code; - } - -out: - mutex_unlock(&phy->mutex); - - return ret; -} - -static int cal_camerarx_sd_enum_frame_size(struct v4l2_subdev *sd, - struct v4l2_subdev_state *sd_state, - struct v4l2_subdev_frame_size_enum *fse) -{ - struct cal_camerarx *phy = to_cal_camerarx(sd); - const struct cal_format_info *fmtinfo; - int ret = 0; - - if (fse->index > 0) - return -EINVAL; - - mutex_lock(&phy->mutex); - - /* No transcoding, source and sink formats must match. */ - if (cal_rx_pad_is_source(fse->pad)) { - struct v4l2_mbus_framefmt *fmt; - - fmt = cal_camerarx_get_pad_format(phy, sd_state, - CAL_CAMERARX_PAD_SINK, - fse->which); - if (fse->code != fmt->code) { - ret = -EINVAL; - goto out; - } - - fse->min_width = fmt->width; - fse->max_width = fmt->width; - fse->min_height = fmt->height; - fse->max_height = fmt->height; - } else { - fmtinfo = cal_format_by_code(fse->code); - if (!fmtinfo) { - ret = -EINVAL; - goto out; - } - - fse->min_width = CAL_MIN_WIDTH_BYTES * 8 / ALIGN(fmtinfo->bpp, 8); - fse->max_width = CAL_MAX_WIDTH_BYTES * 8 / ALIGN(fmtinfo->bpp, 8); - fse->min_height = CAL_MIN_HEIGHT_LINES; - fse->max_height = CAL_MAX_HEIGHT_LINES; - } - -out: - mutex_unlock(&phy->mutex); - - return ret; -} - -static int cal_camerarx_sd_get_fmt(struct v4l2_subdev *sd, - struct v4l2_subdev_state *sd_state, - struct v4l2_subdev_format *format) -{ - struct cal_camerarx *phy = to_cal_camerarx(sd); - struct v4l2_mbus_framefmt *fmt; - - mutex_lock(&phy->mutex); - - fmt = cal_camerarx_get_pad_format(phy, sd_state, format->pad, - format->which); - format->format = *fmt; - - mutex_unlock(&phy->mutex); - - return 0; -} - -static int cal_camerarx_sd_set_fmt(struct v4l2_subdev *sd, - struct v4l2_subdev_state *sd_state, - struct v4l2_subdev_format *format) -{ - struct cal_camerarx *phy = to_cal_camerarx(sd); - const struct cal_format_info *fmtinfo; - struct v4l2_mbus_framefmt *fmt; - unsigned int bpp; - - /* No transcoding, source and sink formats must match. */ - if (cal_rx_pad_is_source(format->pad)) - return cal_camerarx_sd_get_fmt(sd, sd_state, format); - - /* - * Default to the first format if the requested media bus code isn't - * supported. - */ - fmtinfo = cal_format_by_code(format->format.code); - if (!fmtinfo) - fmtinfo = &cal_formats[0]; - - /* Clamp the size, update the code. The colorspace is accepted as-is. */ - bpp = ALIGN(fmtinfo->bpp, 8); - - format->format.width = clamp_t(unsigned int, format->format.width, - CAL_MIN_WIDTH_BYTES * 8 / bpp, - CAL_MAX_WIDTH_BYTES * 8 / bpp); - format->format.height = clamp_t(unsigned int, format->format.height, - CAL_MIN_HEIGHT_LINES, - CAL_MAX_HEIGHT_LINES); - format->format.code = fmtinfo->code; - format->format.field = V4L2_FIELD_NONE; - - /* Store the format and propagate it to the source pad. */ - - mutex_lock(&phy->mutex); - - fmt = cal_camerarx_get_pad_format(phy, sd_state, - CAL_CAMERARX_PAD_SINK, - format->which); - *fmt = format->format; - - fmt = cal_camerarx_get_pad_format(phy, sd_state, - CAL_CAMERARX_PAD_FIRST_SOURCE, - format->which); - *fmt = format->format; - - mutex_unlock(&phy->mutex); - - return 0; -} - -static int cal_camerarx_sd_init_cfg(struct v4l2_subdev *sd, - struct v4l2_subdev_state *sd_state) -{ - struct v4l2_subdev_format format = { - .which = sd_state ? V4L2_SUBDEV_FORMAT_TRY - : V4L2_SUBDEV_FORMAT_ACTIVE, - .pad = CAL_CAMERARX_PAD_SINK, - .format = { - .width = 640, - .height = 480, - .code = MEDIA_BUS_FMT_UYVY8_2X8, - .field = V4L2_FIELD_NONE, - .colorspace = V4L2_COLORSPACE_SRGB, - .ycbcr_enc = V4L2_YCBCR_ENC_601, - .quantization = V4L2_QUANTIZATION_LIM_RANGE, - .xfer_func = V4L2_XFER_FUNC_SRGB, - }, - }; - - return cal_camerarx_sd_set_fmt(sd, sd_state, &format); -} - -static const struct v4l2_subdev_video_ops cal_camerarx_video_ops = { - .s_stream = cal_camerarx_sd_s_stream, -}; - -static const struct v4l2_subdev_pad_ops cal_camerarx_pad_ops = { - .init_cfg = cal_camerarx_sd_init_cfg, - .enum_mbus_code = cal_camerarx_sd_enum_mbus_code, - .enum_frame_size = cal_camerarx_sd_enum_frame_size, - .get_fmt = cal_camerarx_sd_get_fmt, - .set_fmt = cal_camerarx_sd_set_fmt, -}; - -static const struct v4l2_subdev_ops cal_camerarx_subdev_ops = { - .video = &cal_camerarx_video_ops, - .pad = &cal_camerarx_pad_ops, -}; - -static struct media_entity_operations cal_camerarx_media_ops = { - .link_validate = v4l2_subdev_link_validate, -}; - -/* ------------------------------------------------------------------ - * Create and Destroy - * ------------------------------------------------------------------ - */ - -struct cal_camerarx *cal_camerarx_create(struct cal_dev *cal, - unsigned int instance) -{ - struct platform_device *pdev = to_platform_device(cal->dev); - struct cal_camerarx *phy; - struct v4l2_subdev *sd; - unsigned int i; - int ret; - - phy = kzalloc(sizeof(*phy), GFP_KERNEL); - if (!phy) - return ERR_PTR(-ENOMEM); - - phy->cal = cal; - phy->instance = instance; - - mutex_init(&phy->mutex); - - phy->res = platform_get_resource_byname(pdev, IORESOURCE_MEM, - (instance == 0) ? - "cal_rx_core0" : - "cal_rx_core1"); - phy->base = devm_ioremap_resource(cal->dev, phy->res); - if (IS_ERR(phy->base)) { - cal_err(cal, "failed to ioremap\n"); - ret = PTR_ERR(phy->base); - goto error; - } - - cal_dbg(1, cal, "ioresource %s at %pa - %pa\n", - phy->res->name, &phy->res->start, &phy->res->end); - - ret = cal_camerarx_regmap_init(cal, phy); - if (ret) - goto error; - - ret = cal_camerarx_parse_dt(phy); - if (ret) - goto error; - - /* Initialize the V4L2 subdev and media entity. */ - sd = &phy->subdev; - v4l2_subdev_init(sd, &cal_camerarx_subdev_ops); - sd->entity.function = MEDIA_ENT_F_VID_IF_BRIDGE; - sd->flags = V4L2_SUBDEV_FL_HAS_DEVNODE; - snprintf(sd->name, sizeof(sd->name), "CAMERARX%u", instance); - sd->dev = cal->dev; - - phy->pads[CAL_CAMERARX_PAD_SINK].flags = MEDIA_PAD_FL_SINK; - for (i = CAL_CAMERARX_PAD_FIRST_SOURCE; i < CAL_CAMERARX_NUM_PADS; ++i) - phy->pads[i].flags = MEDIA_PAD_FL_SOURCE; - sd->entity.ops = &cal_camerarx_media_ops; - ret = media_entity_pads_init(&sd->entity, ARRAY_SIZE(phy->pads), - phy->pads); - if (ret) - goto error; - - ret = cal_camerarx_sd_init_cfg(sd, NULL); - if (ret) - goto error; - - ret = v4l2_device_register_subdev(&cal->v4l2_dev, sd); - if (ret) - goto error; - - return phy; - -error: - media_entity_cleanup(&phy->subdev.entity); - kfree(phy); - return ERR_PTR(ret); -} - -void cal_camerarx_destroy(struct cal_camerarx *phy) -{ - if (!phy) - return; - - v4l2_device_unregister_subdev(&phy->subdev); - media_entity_cleanup(&phy->subdev.entity); - of_node_put(phy->source_ep_node); - of_node_put(phy->source_node); - mutex_destroy(&phy->mutex); - kfree(phy); -} diff --git a/drivers/media/platform/ti-vpe/cal-video.c b/drivers/media/platform/ti-vpe/cal-video.c deleted file mode 100644 index 3e936a2ca36c..000000000000 --- a/drivers/media/platform/ti-vpe/cal-video.c +++ /dev/null @@ -1,1049 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * TI Camera Access Layer (CAL) - Video Device - * - * Copyright (c) 2015-2020 Texas Instruments Inc. - * - * Authors: - * Benoit Parrot - * Laurent Pinchart - */ - -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "cal.h" - -/* Print Four-character-code (FOURCC) */ -static char *fourcc_to_str(u32 fmt) -{ - static char code[5]; - - code[0] = (unsigned char)(fmt & 0xff); - code[1] = (unsigned char)((fmt >> 8) & 0xff); - code[2] = (unsigned char)((fmt >> 16) & 0xff); - code[3] = (unsigned char)((fmt >> 24) & 0xff); - code[4] = '\0'; - - return code; -} - -/* ------------------------------------------------------------------ - * V4L2 Common IOCTLs - * ------------------------------------------------------------------ - */ - -static int cal_querycap(struct file *file, void *priv, - struct v4l2_capability *cap) -{ - struct cal_ctx *ctx = video_drvdata(file); - - strscpy(cap->driver, CAL_MODULE_NAME, sizeof(cap->driver)); - strscpy(cap->card, CAL_MODULE_NAME, sizeof(cap->card)); - - snprintf(cap->bus_info, sizeof(cap->bus_info), - "platform:%s", dev_name(ctx->cal->dev)); - return 0; -} - -static int cal_g_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct cal_ctx *ctx = video_drvdata(file); - - *f = ctx->v_fmt; - - return 0; -} - -/* ------------------------------------------------------------------ - * V4L2 Video Node Centric IOCTLs - * ------------------------------------------------------------------ - */ - -static const struct cal_format_info *find_format_by_pix(struct cal_ctx *ctx, - u32 pixelformat) -{ - const struct cal_format_info *fmtinfo; - unsigned int k; - - for (k = 0; k < ctx->num_active_fmt; k++) { - fmtinfo = ctx->active_fmt[k]; - if (fmtinfo->fourcc == pixelformat) - return fmtinfo; - } - - return NULL; -} - -static const struct cal_format_info *find_format_by_code(struct cal_ctx *ctx, - u32 code) -{ - const struct cal_format_info *fmtinfo; - unsigned int k; - - for (k = 0; k < ctx->num_active_fmt; k++) { - fmtinfo = ctx->active_fmt[k]; - if (fmtinfo->code == code) - return fmtinfo; - } - - return NULL; -} - -static int cal_legacy_enum_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_fmtdesc *f) -{ - struct cal_ctx *ctx = video_drvdata(file); - const struct cal_format_info *fmtinfo; - - if (f->index >= ctx->num_active_fmt) - return -EINVAL; - - fmtinfo = ctx->active_fmt[f->index]; - - f->pixelformat = fmtinfo->fourcc; - f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - return 0; -} - -static int __subdev_get_format(struct cal_ctx *ctx, - struct v4l2_mbus_framefmt *fmt) -{ - struct v4l2_subdev_format sd_fmt; - struct v4l2_mbus_framefmt *mbus_fmt = &sd_fmt.format; - int ret; - - sd_fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE; - sd_fmt.pad = 0; - - ret = v4l2_subdev_call(ctx->phy->source, pad, get_fmt, NULL, &sd_fmt); - if (ret) - return ret; - - *fmt = *mbus_fmt; - - ctx_dbg(1, ctx, "%s %dx%d code:%04X\n", __func__, - fmt->width, fmt->height, fmt->code); - - return 0; -} - -static int __subdev_set_format(struct cal_ctx *ctx, - struct v4l2_mbus_framefmt *fmt) -{ - struct v4l2_subdev_format sd_fmt; - struct v4l2_mbus_framefmt *mbus_fmt = &sd_fmt.format; - int ret; - - sd_fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE; - sd_fmt.pad = 0; - *mbus_fmt = *fmt; - - ret = v4l2_subdev_call(ctx->phy->source, pad, set_fmt, NULL, &sd_fmt); - if (ret) - return ret; - - ctx_dbg(1, ctx, "%s %dx%d code:%04X\n", __func__, - fmt->width, fmt->height, fmt->code); - - return 0; -} - -static void cal_calc_format_size(struct cal_ctx *ctx, - const struct cal_format_info *fmtinfo, - struct v4l2_format *f) -{ - u32 bpl, max_width; - - /* - * Maximum width is bound by the DMA max width in bytes. - * We need to recalculate the actual maxi width depending on the - * number of bytes per pixels required. - */ - max_width = CAL_MAX_WIDTH_BYTES / (ALIGN(fmtinfo->bpp, 8) >> 3); - v4l_bound_align_image(&f->fmt.pix.width, 48, max_width, 2, - &f->fmt.pix.height, 32, CAL_MAX_HEIGHT_LINES, - 0, 0); - - bpl = (f->fmt.pix.width * ALIGN(fmtinfo->bpp, 8)) >> 3; - f->fmt.pix.bytesperline = ALIGN(bpl, 16); - - f->fmt.pix.sizeimage = f->fmt.pix.height * - f->fmt.pix.bytesperline; - - ctx_dbg(3, ctx, "%s: fourcc: %s size: %dx%d bpl:%d img_size:%d\n", - __func__, fourcc_to_str(f->fmt.pix.pixelformat), - f->fmt.pix.width, f->fmt.pix.height, - f->fmt.pix.bytesperline, f->fmt.pix.sizeimage); -} - -static int cal_legacy_try_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct cal_ctx *ctx = video_drvdata(file); - const struct cal_format_info *fmtinfo; - struct v4l2_subdev_frame_size_enum fse; - int ret, found; - - fmtinfo = find_format_by_pix(ctx, f->fmt.pix.pixelformat); - if (!fmtinfo) { - ctx_dbg(3, ctx, "Fourcc format (0x%08x) not found.\n", - f->fmt.pix.pixelformat); - - /* Just get the first one enumerated */ - fmtinfo = ctx->active_fmt[0]; - f->fmt.pix.pixelformat = fmtinfo->fourcc; - } - - f->fmt.pix.field = ctx->v_fmt.fmt.pix.field; - - /* check for/find a valid width/height */ - ret = 0; - found = false; - fse.pad = 0; - fse.code = fmtinfo->code; - fse.which = V4L2_SUBDEV_FORMAT_ACTIVE; - for (fse.index = 0; ; fse.index++) { - ret = v4l2_subdev_call(ctx->phy->source, pad, enum_frame_size, - NULL, &fse); - if (ret) - break; - - if ((f->fmt.pix.width == fse.max_width) && - (f->fmt.pix.height == fse.max_height)) { - found = true; - break; - } else if ((f->fmt.pix.width >= fse.min_width) && - (f->fmt.pix.width <= fse.max_width) && - (f->fmt.pix.height >= fse.min_height) && - (f->fmt.pix.height <= fse.max_height)) { - found = true; - break; - } - } - - if (!found) { - /* use existing values as default */ - f->fmt.pix.width = ctx->v_fmt.fmt.pix.width; - f->fmt.pix.height = ctx->v_fmt.fmt.pix.height; - } - - /* - * Use current colorspace for now, it will get - * updated properly during s_fmt - */ - f->fmt.pix.colorspace = ctx->v_fmt.fmt.pix.colorspace; - cal_calc_format_size(ctx, fmtinfo, f); - return 0; -} - -static int cal_legacy_s_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct cal_ctx *ctx = video_drvdata(file); - struct vb2_queue *q = &ctx->vb_vidq; - struct v4l2_subdev_format sd_fmt = { - .which = V4L2_SUBDEV_FORMAT_ACTIVE, - .pad = CAL_CAMERARX_PAD_SINK, - }; - const struct cal_format_info *fmtinfo; - int ret; - - if (vb2_is_busy(q)) { - ctx_dbg(3, ctx, "%s device busy\n", __func__); - return -EBUSY; - } - - ret = cal_legacy_try_fmt_vid_cap(file, priv, f); - if (ret < 0) - return ret; - - fmtinfo = find_format_by_pix(ctx, f->fmt.pix.pixelformat); - - v4l2_fill_mbus_format(&sd_fmt.format, &f->fmt.pix, fmtinfo->code); - - ret = __subdev_set_format(ctx, &sd_fmt.format); - if (ret) - return ret; - - /* Just double check nothing has gone wrong */ - if (sd_fmt.format.code != fmtinfo->code) { - ctx_dbg(3, ctx, - "%s subdev changed format on us, this should not happen\n", - __func__); - return -EINVAL; - } - - v4l2_fill_pix_format(&ctx->v_fmt.fmt.pix, &sd_fmt.format); - ctx->v_fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - ctx->v_fmt.fmt.pix.pixelformat = fmtinfo->fourcc; - ctx->v_fmt.fmt.pix.field = sd_fmt.format.field; - cal_calc_format_size(ctx, fmtinfo, &ctx->v_fmt); - - v4l2_subdev_call(&ctx->phy->subdev, pad, set_fmt, NULL, &sd_fmt); - - ctx->fmtinfo = fmtinfo; - *f = ctx->v_fmt; - - return 0; -} - -static int cal_legacy_enum_framesizes(struct file *file, void *fh, - struct v4l2_frmsizeenum *fsize) -{ - struct cal_ctx *ctx = video_drvdata(file); - const struct cal_format_info *fmtinfo; - struct v4l2_subdev_frame_size_enum fse; - int ret; - - /* check for valid format */ - fmtinfo = find_format_by_pix(ctx, fsize->pixel_format); - if (!fmtinfo) { - ctx_dbg(3, ctx, "Invalid pixel code: %x\n", - fsize->pixel_format); - return -EINVAL; - } - - fse.index = fsize->index; - fse.pad = 0; - fse.code = fmtinfo->code; - fse.which = V4L2_SUBDEV_FORMAT_ACTIVE; - - ret = v4l2_subdev_call(ctx->phy->source, pad, enum_frame_size, NULL, - &fse); - if (ret) - return ret; - - ctx_dbg(1, ctx, "%s: index: %d code: %x W:[%d,%d] H:[%d,%d]\n", - __func__, fse.index, fse.code, fse.min_width, fse.max_width, - fse.min_height, fse.max_height); - - fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE; - fsize->discrete.width = fse.max_width; - fsize->discrete.height = fse.max_height; - - return 0; -} - -static int cal_legacy_enum_input(struct file *file, void *priv, - struct v4l2_input *inp) -{ - if (inp->index > 0) - return -EINVAL; - - inp->type = V4L2_INPUT_TYPE_CAMERA; - sprintf(inp->name, "Camera %u", inp->index); - return 0; -} - -static int cal_legacy_g_input(struct file *file, void *priv, unsigned int *i) -{ - *i = 0; - return 0; -} - -static int cal_legacy_s_input(struct file *file, void *priv, unsigned int i) -{ - return i > 0 ? -EINVAL : 0; -} - -/* timeperframe is arbitrary and continuous */ -static int cal_legacy_enum_frameintervals(struct file *file, void *priv, - struct v4l2_frmivalenum *fival) -{ - struct cal_ctx *ctx = video_drvdata(file); - const struct cal_format_info *fmtinfo; - struct v4l2_subdev_frame_interval_enum fie = { - .index = fival->index, - .width = fival->width, - .height = fival->height, - .which = V4L2_SUBDEV_FORMAT_ACTIVE, - }; - int ret; - - fmtinfo = find_format_by_pix(ctx, fival->pixel_format); - if (!fmtinfo) - return -EINVAL; - - fie.code = fmtinfo->code; - ret = v4l2_subdev_call(ctx->phy->source, pad, enum_frame_interval, - NULL, &fie); - if (ret) - return ret; - fival->type = V4L2_FRMIVAL_TYPE_DISCRETE; - fival->discrete = fie.interval; - - return 0; -} - -static int cal_legacy_g_parm(struct file *file, void *fh, struct v4l2_streamparm *a) -{ - struct cal_ctx *ctx = video_drvdata(file); - - return v4l2_g_parm_cap(video_devdata(file), ctx->phy->source, a); -} - -static int cal_legacy_s_parm(struct file *file, void *fh, struct v4l2_streamparm *a) -{ - struct cal_ctx *ctx = video_drvdata(file); - - return v4l2_s_parm_cap(video_devdata(file), ctx->phy->source, a); -} - -static const struct v4l2_ioctl_ops cal_ioctl_legacy_ops = { - .vidioc_querycap = cal_querycap, - .vidioc_enum_fmt_vid_cap = cal_legacy_enum_fmt_vid_cap, - .vidioc_g_fmt_vid_cap = cal_g_fmt_vid_cap, - .vidioc_try_fmt_vid_cap = cal_legacy_try_fmt_vid_cap, - .vidioc_s_fmt_vid_cap = cal_legacy_s_fmt_vid_cap, - .vidioc_enum_framesizes = cal_legacy_enum_framesizes, - .vidioc_reqbufs = vb2_ioctl_reqbufs, - .vidioc_create_bufs = vb2_ioctl_create_bufs, - .vidioc_prepare_buf = vb2_ioctl_prepare_buf, - .vidioc_querybuf = vb2_ioctl_querybuf, - .vidioc_qbuf = vb2_ioctl_qbuf, - .vidioc_dqbuf = vb2_ioctl_dqbuf, - .vidioc_expbuf = vb2_ioctl_expbuf, - .vidioc_enum_input = cal_legacy_enum_input, - .vidioc_g_input = cal_legacy_g_input, - .vidioc_s_input = cal_legacy_s_input, - .vidioc_enum_frameintervals = cal_legacy_enum_frameintervals, - .vidioc_streamon = vb2_ioctl_streamon, - .vidioc_streamoff = vb2_ioctl_streamoff, - .vidioc_log_status = v4l2_ctrl_log_status, - .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, - .vidioc_unsubscribe_event = v4l2_event_unsubscribe, - .vidioc_g_parm = cal_legacy_g_parm, - .vidioc_s_parm = cal_legacy_s_parm, -}; - -/* ------------------------------------------------------------------ - * V4L2 Media Controller Centric IOCTLs - * ------------------------------------------------------------------ - */ - -static int cal_mc_enum_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_fmtdesc *f) -{ - unsigned int i; - unsigned int idx; - - if (f->index >= cal_num_formats) - return -EINVAL; - - idx = 0; - - for (i = 0; i < cal_num_formats; ++i) { - if (f->mbus_code && cal_formats[i].code != f->mbus_code) - continue; - - if (idx == f->index) { - f->pixelformat = cal_formats[i].fourcc; - f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - return 0; - } - - idx++; - } - - return -EINVAL; -} - -static void cal_mc_try_fmt(struct cal_ctx *ctx, struct v4l2_format *f, - const struct cal_format_info **info) -{ - struct v4l2_pix_format *format = &f->fmt.pix; - const struct cal_format_info *fmtinfo; - unsigned int bpp; - - /* - * Default to the first format if the requested pixel format code isn't - * supported. - */ - fmtinfo = cal_format_by_fourcc(f->fmt.pix.pixelformat); - if (!fmtinfo) - fmtinfo = &cal_formats[0]; - - /* - * Clamp the size, update the pixel format. The field and colorspace are - * accepted as-is, except for V4L2_FIELD_ANY that is turned into - * V4L2_FIELD_NONE. - */ - bpp = ALIGN(fmtinfo->bpp, 8); - - format->width = clamp_t(unsigned int, format->width, - CAL_MIN_WIDTH_BYTES * 8 / bpp, - CAL_MAX_WIDTH_BYTES * 8 / bpp); - format->height = clamp_t(unsigned int, format->height, - CAL_MIN_HEIGHT_LINES, CAL_MAX_HEIGHT_LINES); - format->pixelformat = fmtinfo->fourcc; - - if (format->field == V4L2_FIELD_ANY) - format->field = V4L2_FIELD_NONE; - - /* - * Calculate the number of bytes per line and the image size. The - * hardware stores the stride as a number of 16 bytes words, in a - * signed 15-bit value. Only 14 bits are thus usable. - */ - format->bytesperline = ALIGN(clamp(format->bytesperline, - format->width * bpp / 8, - ((1U << 14) - 1) * 16), 16); - - format->sizeimage = format->height * format->bytesperline; - - format->colorspace = ctx->v_fmt.fmt.pix.colorspace; - - if (info) - *info = fmtinfo; - - ctx_dbg(3, ctx, "%s: %s %ux%u (bytesperline %u sizeimage %u)\n", - __func__, fourcc_to_str(format->pixelformat), - format->width, format->height, - format->bytesperline, format->sizeimage); -} - -static int cal_mc_try_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct cal_ctx *ctx = video_drvdata(file); - - cal_mc_try_fmt(ctx, f, NULL); - return 0; -} - -static int cal_mc_s_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct cal_ctx *ctx = video_drvdata(file); - const struct cal_format_info *fmtinfo; - - if (vb2_is_busy(&ctx->vb_vidq)) { - ctx_dbg(3, ctx, "%s device busy\n", __func__); - return -EBUSY; - } - - cal_mc_try_fmt(ctx, f, &fmtinfo); - - ctx->v_fmt = *f; - ctx->fmtinfo = fmtinfo; - - return 0; -} - -static int cal_mc_enum_framesizes(struct file *file, void *fh, - struct v4l2_frmsizeenum *fsize) -{ - struct cal_ctx *ctx = video_drvdata(file); - const struct cal_format_info *fmtinfo; - unsigned int bpp; - - if (fsize->index > 0) - return -EINVAL; - - fmtinfo = cal_format_by_fourcc(fsize->pixel_format); - if (!fmtinfo) { - ctx_dbg(3, ctx, "Invalid pixel format 0x%08x\n", - fsize->pixel_format); - return -EINVAL; - } - - bpp = ALIGN(fmtinfo->bpp, 8); - - fsize->type = V4L2_FRMSIZE_TYPE_STEPWISE; - fsize->stepwise.min_width = CAL_MIN_WIDTH_BYTES * 8 / bpp; - fsize->stepwise.max_width = CAL_MAX_WIDTH_BYTES * 8 / bpp; - fsize->stepwise.step_width = 64 / bpp; - fsize->stepwise.min_height = CAL_MIN_HEIGHT_LINES; - fsize->stepwise.max_height = CAL_MAX_HEIGHT_LINES; - fsize->stepwise.step_height = 1; - - return 0; -} - -static const struct v4l2_ioctl_ops cal_ioctl_mc_ops = { - .vidioc_querycap = cal_querycap, - .vidioc_enum_fmt_vid_cap = cal_mc_enum_fmt_vid_cap, - .vidioc_g_fmt_vid_cap = cal_g_fmt_vid_cap, - .vidioc_try_fmt_vid_cap = cal_mc_try_fmt_vid_cap, - .vidioc_s_fmt_vid_cap = cal_mc_s_fmt_vid_cap, - .vidioc_enum_framesizes = cal_mc_enum_framesizes, - .vidioc_reqbufs = vb2_ioctl_reqbufs, - .vidioc_create_bufs = vb2_ioctl_create_bufs, - .vidioc_prepare_buf = vb2_ioctl_prepare_buf, - .vidioc_querybuf = vb2_ioctl_querybuf, - .vidioc_qbuf = vb2_ioctl_qbuf, - .vidioc_dqbuf = vb2_ioctl_dqbuf, - .vidioc_expbuf = vb2_ioctl_expbuf, - .vidioc_streamon = vb2_ioctl_streamon, - .vidioc_streamoff = vb2_ioctl_streamoff, - .vidioc_log_status = v4l2_ctrl_log_status, -}; - -/* ------------------------------------------------------------------ - * videobuf2 Common Operations - * ------------------------------------------------------------------ - */ - -static int cal_queue_setup(struct vb2_queue *vq, - unsigned int *nbuffers, unsigned int *nplanes, - unsigned int sizes[], struct device *alloc_devs[]) -{ - struct cal_ctx *ctx = vb2_get_drv_priv(vq); - unsigned int size = ctx->v_fmt.fmt.pix.sizeimage; - - if (vq->num_buffers + *nbuffers < 3) - *nbuffers = 3 - vq->num_buffers; - - if (*nplanes) { - if (sizes[0] < size) - return -EINVAL; - size = sizes[0]; - } - - *nplanes = 1; - sizes[0] = size; - - ctx_dbg(3, ctx, "nbuffers=%d, size=%d\n", *nbuffers, sizes[0]); - - return 0; -} - -static int cal_buffer_prepare(struct vb2_buffer *vb) -{ - struct cal_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); - struct cal_buffer *buf = container_of(vb, struct cal_buffer, - vb.vb2_buf); - unsigned long size; - - size = ctx->v_fmt.fmt.pix.sizeimage; - if (vb2_plane_size(vb, 0) < size) { - ctx_err(ctx, - "data will not fit into plane (%lu < %lu)\n", - vb2_plane_size(vb, 0), size); - return -EINVAL; - } - - vb2_set_plane_payload(&buf->vb.vb2_buf, 0, size); - return 0; -} - -static void cal_buffer_queue(struct vb2_buffer *vb) -{ - struct cal_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); - struct cal_buffer *buf = container_of(vb, struct cal_buffer, - vb.vb2_buf); - unsigned long flags; - - /* recheck locking */ - spin_lock_irqsave(&ctx->dma.lock, flags); - list_add_tail(&buf->list, &ctx->dma.queue); - spin_unlock_irqrestore(&ctx->dma.lock, flags); -} - -static void cal_release_buffers(struct cal_ctx *ctx, - enum vb2_buffer_state state) -{ - struct cal_buffer *buf, *tmp; - - /* Release all queued buffers. */ - spin_lock_irq(&ctx->dma.lock); - - list_for_each_entry_safe(buf, tmp, &ctx->dma.queue, list) { - list_del(&buf->list); - vb2_buffer_done(&buf->vb.vb2_buf, state); - } - - if (ctx->dma.pending) { - vb2_buffer_done(&ctx->dma.pending->vb.vb2_buf, state); - ctx->dma.pending = NULL; - } - - if (ctx->dma.active) { - vb2_buffer_done(&ctx->dma.active->vb.vb2_buf, state); - ctx->dma.active = NULL; - } - - spin_unlock_irq(&ctx->dma.lock); -} - -/* ------------------------------------------------------------------ - * videobuf2 Operations - * ------------------------------------------------------------------ - */ - -static int cal_video_check_format(struct cal_ctx *ctx) -{ - const struct v4l2_mbus_framefmt *format; - struct media_pad *remote_pad; - - remote_pad = media_entity_remote_pad(&ctx->pad); - if (!remote_pad) - return -ENODEV; - - format = &ctx->phy->formats[remote_pad->index]; - - if (ctx->fmtinfo->code != format->code || - ctx->v_fmt.fmt.pix.height != format->height || - ctx->v_fmt.fmt.pix.width != format->width || - ctx->v_fmt.fmt.pix.field != format->field) - return -EPIPE; - - return 0; -} - -static int cal_start_streaming(struct vb2_queue *vq, unsigned int count) -{ - struct cal_ctx *ctx = vb2_get_drv_priv(vq); - struct cal_buffer *buf; - dma_addr_t addr; - int ret; - - ret = media_pipeline_start(&ctx->vdev.entity, &ctx->phy->pipe); - if (ret < 0) { - ctx_err(ctx, "Failed to start media pipeline: %d\n", ret); - goto error_release_buffers; - } - - /* - * Verify that the currently configured format matches the output of - * the connected CAMERARX. - */ - ret = cal_video_check_format(ctx); - if (ret < 0) { - ctx_dbg(3, ctx, - "Format mismatch between CAMERARX and video node\n"); - goto error_pipeline; - } - - ret = cal_ctx_prepare(ctx); - if (ret) { - ctx_err(ctx, "Failed to prepare context: %d\n", ret); - goto error_pipeline; - } - - spin_lock_irq(&ctx->dma.lock); - buf = list_first_entry(&ctx->dma.queue, struct cal_buffer, list); - ctx->dma.active = buf; - list_del(&buf->list); - spin_unlock_irq(&ctx->dma.lock); - - addr = vb2_dma_contig_plane_dma_addr(&buf->vb.vb2_buf, 0); - - ret = pm_runtime_resume_and_get(ctx->cal->dev); - if (ret < 0) - goto error_pipeline; - - cal_ctx_set_dma_addr(ctx, addr); - cal_ctx_start(ctx); - - ret = v4l2_subdev_call(&ctx->phy->subdev, video, s_stream, 1); - if (ret) - goto error_stop; - - if (cal_debug >= 4) - cal_quickdump_regs(ctx->cal); - - return 0; - -error_stop: - cal_ctx_stop(ctx); - pm_runtime_put_sync(ctx->cal->dev); - cal_ctx_unprepare(ctx); - -error_pipeline: - media_pipeline_stop(&ctx->vdev.entity); -error_release_buffers: - cal_release_buffers(ctx, VB2_BUF_STATE_QUEUED); - - return ret; -} - -static void cal_stop_streaming(struct vb2_queue *vq) -{ - struct cal_ctx *ctx = vb2_get_drv_priv(vq); - - cal_ctx_stop(ctx); - - v4l2_subdev_call(&ctx->phy->subdev, video, s_stream, 0); - - pm_runtime_put_sync(ctx->cal->dev); - - cal_ctx_unprepare(ctx); - - cal_release_buffers(ctx, VB2_BUF_STATE_ERROR); - - media_pipeline_stop(&ctx->vdev.entity); -} - -static const struct vb2_ops cal_video_qops = { - .queue_setup = cal_queue_setup, - .buf_prepare = cal_buffer_prepare, - .buf_queue = cal_buffer_queue, - .start_streaming = cal_start_streaming, - .stop_streaming = cal_stop_streaming, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, -}; - -/* ------------------------------------------------------------------ - * V4L2 Initialization and Registration - * ------------------------------------------------------------------ - */ - -static const struct v4l2_file_operations cal_fops = { - .owner = THIS_MODULE, - .open = v4l2_fh_open, - .release = vb2_fop_release, - .poll = vb2_fop_poll, - .unlocked_ioctl = video_ioctl2, /* V4L2 ioctl handler */ - .mmap = vb2_fop_mmap, -}; - -static int cal_ctx_v4l2_init_formats(struct cal_ctx *ctx) -{ - struct v4l2_subdev_mbus_code_enum mbus_code; - struct v4l2_mbus_framefmt mbus_fmt; - const struct cal_format_info *fmtinfo; - unsigned int i, j, k; - int ret = 0; - - /* Enumerate sub device formats and enable all matching local formats */ - ctx->active_fmt = devm_kcalloc(ctx->cal->dev, cal_num_formats, - sizeof(*ctx->active_fmt), GFP_KERNEL); - if (!ctx->active_fmt) - return -ENOMEM; - - ctx->num_active_fmt = 0; - - for (j = 0, i = 0; ; ++j) { - - memset(&mbus_code, 0, sizeof(mbus_code)); - mbus_code.index = j; - mbus_code.which = V4L2_SUBDEV_FORMAT_ACTIVE; - ret = v4l2_subdev_call(ctx->phy->source, pad, enum_mbus_code, - NULL, &mbus_code); - if (ret == -EINVAL) - break; - - if (ret) { - ctx_err(ctx, "Error enumerating mbus codes in subdev %s: %d\n", - ctx->phy->source->name, ret); - return ret; - } - - ctx_dbg(2, ctx, - "subdev %s: code: %04x idx: %u\n", - ctx->phy->source->name, mbus_code.code, j); - - for (k = 0; k < cal_num_formats; k++) { - fmtinfo = &cal_formats[k]; - - if (mbus_code.code == fmtinfo->code) { - ctx->active_fmt[i] = fmtinfo; - ctx_dbg(2, ctx, - "matched fourcc: %s: code: %04x idx: %u\n", - fourcc_to_str(fmtinfo->fourcc), - fmtinfo->code, i); - ctx->num_active_fmt = ++i; - } - } - } - - if (i == 0) { - ctx_err(ctx, "No suitable format reported by subdev %s\n", - ctx->phy->source->name); - return -EINVAL; - } - - ret = __subdev_get_format(ctx, &mbus_fmt); - if (ret) - return ret; - - fmtinfo = find_format_by_code(ctx, mbus_fmt.code); - if (!fmtinfo) { - ctx_dbg(3, ctx, "mbus code format (0x%08x) not found.\n", - mbus_fmt.code); - return -EINVAL; - } - - /* Save current format */ - v4l2_fill_pix_format(&ctx->v_fmt.fmt.pix, &mbus_fmt); - ctx->v_fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - ctx->v_fmt.fmt.pix.pixelformat = fmtinfo->fourcc; - cal_calc_format_size(ctx, fmtinfo, &ctx->v_fmt); - ctx->fmtinfo = fmtinfo; - - return 0; -} - -static int cal_ctx_v4l2_init_mc_format(struct cal_ctx *ctx) -{ - const struct cal_format_info *fmtinfo; - struct v4l2_pix_format *pix_fmt = &ctx->v_fmt.fmt.pix; - - fmtinfo = cal_format_by_code(MEDIA_BUS_FMT_UYVY8_2X8); - if (!fmtinfo) - return -EINVAL; - - pix_fmt->width = 640; - pix_fmt->height = 480; - pix_fmt->field = V4L2_FIELD_NONE; - pix_fmt->colorspace = V4L2_COLORSPACE_SRGB; - pix_fmt->ycbcr_enc = V4L2_YCBCR_ENC_601; - pix_fmt->quantization = V4L2_QUANTIZATION_LIM_RANGE; - pix_fmt->xfer_func = V4L2_XFER_FUNC_SRGB; - pix_fmt->pixelformat = fmtinfo->fourcc; - - ctx->v_fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - - /* Save current format */ - cal_calc_format_size(ctx, fmtinfo, &ctx->v_fmt); - ctx->fmtinfo = fmtinfo; - - return 0; -} - -int cal_ctx_v4l2_register(struct cal_ctx *ctx) -{ - struct video_device *vfd = &ctx->vdev; - int ret; - - if (!cal_mc_api) { - struct v4l2_ctrl_handler *hdl = &ctx->ctrl_handler; - - ret = cal_ctx_v4l2_init_formats(ctx); - if (ret) { - ctx_err(ctx, "Failed to init formats: %d\n", ret); - return ret; - } - - ret = v4l2_ctrl_add_handler(hdl, ctx->phy->source->ctrl_handler, - NULL, true); - if (ret < 0) { - ctx_err(ctx, "Failed to add source ctrl handler\n"); - return ret; - } - } else { - ret = cal_ctx_v4l2_init_mc_format(ctx); - if (ret) { - ctx_err(ctx, "Failed to init format: %d\n", ret); - return ret; - } - } - - ret = video_register_device(vfd, VFL_TYPE_VIDEO, cal_video_nr); - if (ret < 0) { - ctx_err(ctx, "Failed to register video device\n"); - return ret; - } - - ret = media_create_pad_link(&ctx->phy->subdev.entity, - CAL_CAMERARX_PAD_FIRST_SOURCE, - &vfd->entity, 0, - MEDIA_LNK_FL_IMMUTABLE | - MEDIA_LNK_FL_ENABLED); - if (ret) { - ctx_err(ctx, "Failed to create media link for context %u\n", - ctx->dma_ctx); - video_unregister_device(vfd); - return ret; - } - - ctx_info(ctx, "V4L2 device registered as %s\n", - video_device_node_name(vfd)); - - return 0; -} - -void cal_ctx_v4l2_unregister(struct cal_ctx *ctx) -{ - ctx_dbg(1, ctx, "unregistering %s\n", - video_device_node_name(&ctx->vdev)); - - video_unregister_device(&ctx->vdev); -} - -int cal_ctx_v4l2_init(struct cal_ctx *ctx) -{ - struct video_device *vfd = &ctx->vdev; - struct vb2_queue *q = &ctx->vb_vidq; - int ret; - - INIT_LIST_HEAD(&ctx->dma.queue); - spin_lock_init(&ctx->dma.lock); - mutex_init(&ctx->mutex); - init_waitqueue_head(&ctx->dma.wait); - - /* Initialize the vb2 queue. */ - q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - q->io_modes = VB2_MMAP | VB2_DMABUF; - q->drv_priv = ctx; - q->buf_struct_size = sizeof(struct cal_buffer); - q->ops = &cal_video_qops; - q->mem_ops = &vb2_dma_contig_memops; - q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; - q->lock = &ctx->mutex; - q->min_buffers_needed = 3; - q->dev = ctx->cal->dev; - - ret = vb2_queue_init(q); - if (ret) - return ret; - - /* Initialize the video device and media entity. */ - vfd->fops = &cal_fops; - vfd->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING - | (cal_mc_api ? V4L2_CAP_IO_MC : 0); - vfd->v4l2_dev = &ctx->cal->v4l2_dev; - vfd->queue = q; - snprintf(vfd->name, sizeof(vfd->name), "CAL output %u", ctx->dma_ctx); - vfd->release = video_device_release_empty; - vfd->ioctl_ops = cal_mc_api ? &cal_ioctl_mc_ops : &cal_ioctl_legacy_ops; - vfd->lock = &ctx->mutex; - video_set_drvdata(vfd, ctx); - - ctx->pad.flags = MEDIA_PAD_FL_SINK; - ret = media_entity_pads_init(&vfd->entity, 1, &ctx->pad); - if (ret < 0) - return ret; - - if (!cal_mc_api) { - /* Initialize the control handler. */ - struct v4l2_ctrl_handler *hdl = &ctx->ctrl_handler; - - ret = v4l2_ctrl_handler_init(hdl, 11); - if (ret < 0) { - ctx_err(ctx, "Failed to init ctrl handler\n"); - goto error; - } - - vfd->ctrl_handler = hdl; - } - - return 0; - -error: - media_entity_cleanup(&vfd->entity); - return ret; -} - -void cal_ctx_v4l2_cleanup(struct cal_ctx *ctx) -{ - if (!cal_mc_api) - v4l2_ctrl_handler_free(&ctx->ctrl_handler); - - media_entity_cleanup(&ctx->vdev.entity); -} diff --git a/drivers/media/platform/ti-vpe/cal.c b/drivers/media/platform/ti-vpe/cal.c deleted file mode 100644 index 4a4a6c5983f7..000000000000 --- a/drivers/media/platform/ti-vpe/cal.c +++ /dev/null @@ -1,1263 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * TI Camera Access Layer (CAL) - Driver - * - * Copyright (c) 2015-2020 Texas Instruments Inc. - * - * Authors: - * Benoit Parrot - * Laurent Pinchart - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#include "cal.h" -#include "cal_regs.h" - -MODULE_DESCRIPTION("TI CAL driver"); -MODULE_AUTHOR("Benoit Parrot, "); -MODULE_LICENSE("GPL v2"); -MODULE_VERSION("0.1.0"); - -int cal_video_nr = -1; -module_param_named(video_nr, cal_video_nr, uint, 0644); -MODULE_PARM_DESC(video_nr, "videoX start number, -1 is autodetect"); - -unsigned int cal_debug; -module_param_named(debug, cal_debug, uint, 0644); -MODULE_PARM_DESC(debug, "activates debug info"); - -#ifdef CONFIG_VIDEO_TI_CAL_MC -#define CAL_MC_API_DEFAULT 1 -#else -#define CAL_MC_API_DEFAULT 0 -#endif - -bool cal_mc_api = CAL_MC_API_DEFAULT; -module_param_named(mc_api, cal_mc_api, bool, 0444); -MODULE_PARM_DESC(mc_api, "activates the MC API"); - -/* ------------------------------------------------------------------ - * Format Handling - * ------------------------------------------------------------------ - */ - -const struct cal_format_info cal_formats[] = { - { - .fourcc = V4L2_PIX_FMT_YUYV, - .code = MEDIA_BUS_FMT_YUYV8_2X8, - .bpp = 16, - }, { - .fourcc = V4L2_PIX_FMT_UYVY, - .code = MEDIA_BUS_FMT_UYVY8_2X8, - .bpp = 16, - }, { - .fourcc = V4L2_PIX_FMT_YVYU, - .code = MEDIA_BUS_FMT_YVYU8_2X8, - .bpp = 16, - }, { - .fourcc = V4L2_PIX_FMT_VYUY, - .code = MEDIA_BUS_FMT_VYUY8_2X8, - .bpp = 16, - }, { - .fourcc = V4L2_PIX_FMT_RGB565, /* gggbbbbb rrrrrggg */ - .code = MEDIA_BUS_FMT_RGB565_2X8_LE, - .bpp = 16, - }, { - .fourcc = V4L2_PIX_FMT_RGB565X, /* rrrrrggg gggbbbbb */ - .code = MEDIA_BUS_FMT_RGB565_2X8_BE, - .bpp = 16, - }, { - .fourcc = V4L2_PIX_FMT_RGB555, /* gggbbbbb arrrrrgg */ - .code = MEDIA_BUS_FMT_RGB555_2X8_PADHI_LE, - .bpp = 16, - }, { - .fourcc = V4L2_PIX_FMT_RGB555X, /* arrrrrgg gggbbbbb */ - .code = MEDIA_BUS_FMT_RGB555_2X8_PADHI_BE, - .bpp = 16, - }, { - .fourcc = V4L2_PIX_FMT_RGB24, /* rgb */ - .code = MEDIA_BUS_FMT_RGB888_2X12_LE, - .bpp = 24, - }, { - .fourcc = V4L2_PIX_FMT_BGR24, /* bgr */ - .code = MEDIA_BUS_FMT_RGB888_2X12_BE, - .bpp = 24, - }, { - .fourcc = V4L2_PIX_FMT_RGB32, /* argb */ - .code = MEDIA_BUS_FMT_ARGB8888_1X32, - .bpp = 32, - }, { - .fourcc = V4L2_PIX_FMT_SBGGR8, - .code = MEDIA_BUS_FMT_SBGGR8_1X8, - .bpp = 8, - }, { - .fourcc = V4L2_PIX_FMT_SGBRG8, - .code = MEDIA_BUS_FMT_SGBRG8_1X8, - .bpp = 8, - }, { - .fourcc = V4L2_PIX_FMT_SGRBG8, - .code = MEDIA_BUS_FMT_SGRBG8_1X8, - .bpp = 8, - }, { - .fourcc = V4L2_PIX_FMT_SRGGB8, - .code = MEDIA_BUS_FMT_SRGGB8_1X8, - .bpp = 8, - }, { - .fourcc = V4L2_PIX_FMT_SBGGR10, - .code = MEDIA_BUS_FMT_SBGGR10_1X10, - .bpp = 10, - }, { - .fourcc = V4L2_PIX_FMT_SGBRG10, - .code = MEDIA_BUS_FMT_SGBRG10_1X10, - .bpp = 10, - }, { - .fourcc = V4L2_PIX_FMT_SGRBG10, - .code = MEDIA_BUS_FMT_SGRBG10_1X10, - .bpp = 10, - }, { - .fourcc = V4L2_PIX_FMT_SRGGB10, - .code = MEDIA_BUS_FMT_SRGGB10_1X10, - .bpp = 10, - }, { - .fourcc = V4L2_PIX_FMT_SBGGR12, - .code = MEDIA_BUS_FMT_SBGGR12_1X12, - .bpp = 12, - }, { - .fourcc = V4L2_PIX_FMT_SGBRG12, - .code = MEDIA_BUS_FMT_SGBRG12_1X12, - .bpp = 12, - }, { - .fourcc = V4L2_PIX_FMT_SGRBG12, - .code = MEDIA_BUS_FMT_SGRBG12_1X12, - .bpp = 12, - }, { - .fourcc = V4L2_PIX_FMT_SRGGB12, - .code = MEDIA_BUS_FMT_SRGGB12_1X12, - .bpp = 12, - }, -}; - -const unsigned int cal_num_formats = ARRAY_SIZE(cal_formats); - -const struct cal_format_info *cal_format_by_fourcc(u32 fourcc) -{ - unsigned int i; - - for (i = 0; i < ARRAY_SIZE(cal_formats); ++i) { - if (cal_formats[i].fourcc == fourcc) - return &cal_formats[i]; - } - - return NULL; -} - -const struct cal_format_info *cal_format_by_code(u32 code) -{ - unsigned int i; - - for (i = 0; i < ARRAY_SIZE(cal_formats); ++i) { - if (cal_formats[i].code == code) - return &cal_formats[i]; - } - - return NULL; -} - -/* ------------------------------------------------------------------ - * Platform Data - * ------------------------------------------------------------------ - */ - -static const struct cal_camerarx_data dra72x_cal_camerarx[] = { - { - .fields = { - [F_CTRLCLKEN] = { 10, 10 }, - [F_CAMMODE] = { 11, 12 }, - [F_LANEENABLE] = { 13, 16 }, - [F_CSI_MODE] = { 17, 17 }, - }, - .num_lanes = 4, - }, - { - .fields = { - [F_CTRLCLKEN] = { 0, 0 }, - [F_CAMMODE] = { 1, 2 }, - [F_LANEENABLE] = { 3, 4 }, - [F_CSI_MODE] = { 5, 5 }, - }, - .num_lanes = 2, - }, -}; - -static const struct cal_data dra72x_cal_data = { - .camerarx = dra72x_cal_camerarx, - .num_csi2_phy = ARRAY_SIZE(dra72x_cal_camerarx), -}; - -static const struct cal_data dra72x_es1_cal_data = { - .camerarx = dra72x_cal_camerarx, - .num_csi2_phy = ARRAY_SIZE(dra72x_cal_camerarx), - .flags = DRA72_CAL_PRE_ES2_LDO_DISABLE, -}; - -static const struct cal_camerarx_data dra76x_cal_csi_phy[] = { - { - .fields = { - [F_CTRLCLKEN] = { 8, 8 }, - [F_CAMMODE] = { 9, 10 }, - [F_CSI_MODE] = { 11, 11 }, - [F_LANEENABLE] = { 27, 31 }, - }, - .num_lanes = 5, - }, - { - .fields = { - [F_CTRLCLKEN] = { 0, 0 }, - [F_CAMMODE] = { 1, 2 }, - [F_CSI_MODE] = { 3, 3 }, - [F_LANEENABLE] = { 24, 26 }, - }, - .num_lanes = 3, - }, -}; - -static const struct cal_data dra76x_cal_data = { - .camerarx = dra76x_cal_csi_phy, - .num_csi2_phy = ARRAY_SIZE(dra76x_cal_csi_phy), -}; - -static const struct cal_camerarx_data am654_cal_csi_phy[] = { - { - .fields = { - [F_CTRLCLKEN] = { 15, 15 }, - [F_CAMMODE] = { 24, 25 }, - [F_LANEENABLE] = { 0, 4 }, - }, - .num_lanes = 5, - }, -}; - -static const struct cal_data am654_cal_data = { - .camerarx = am654_cal_csi_phy, - .num_csi2_phy = ARRAY_SIZE(am654_cal_csi_phy), -}; - -/* ------------------------------------------------------------------ - * I/O Register Accessors - * ------------------------------------------------------------------ - */ - -void cal_quickdump_regs(struct cal_dev *cal) -{ - unsigned int i; - - cal_info(cal, "CAL Registers @ 0x%pa:\n", &cal->res->start); - print_hex_dump(KERN_INFO, "", DUMP_PREFIX_OFFSET, 16, 4, - (__force const void *)cal->base, - resource_size(cal->res), false); - - for (i = 0; i < cal->data->num_csi2_phy; ++i) { - struct cal_camerarx *phy = cal->phy[i]; - - cal_info(cal, "CSI2 Core %u Registers @ %pa:\n", i, - &phy->res->start); - print_hex_dump(KERN_INFO, "", DUMP_PREFIX_OFFSET, 16, 4, - (__force const void *)phy->base, - resource_size(phy->res), - false); - } -} - -/* ------------------------------------------------------------------ - * Context Management - * ------------------------------------------------------------------ - */ - -#define CAL_MAX_PIX_PROC 4 - -static int cal_reserve_pix_proc(struct cal_dev *cal) -{ - unsigned long ret; - - spin_lock(&cal->v4l2_dev.lock); - - ret = find_first_zero_bit(&cal->reserved_pix_proc_mask, CAL_MAX_PIX_PROC); - - if (ret == CAL_MAX_PIX_PROC) { - spin_unlock(&cal->v4l2_dev.lock); - return -ENOSPC; - } - - cal->reserved_pix_proc_mask |= BIT(ret); - - spin_unlock(&cal->v4l2_dev.lock); - - return ret; -} - -static void cal_release_pix_proc(struct cal_dev *cal, unsigned int pix_proc_num) -{ - spin_lock(&cal->v4l2_dev.lock); - - cal->reserved_pix_proc_mask &= ~BIT(pix_proc_num); - - spin_unlock(&cal->v4l2_dev.lock); -} - -static void cal_ctx_csi2_config(struct cal_ctx *ctx) -{ - u32 val; - - val = cal_read(ctx->cal, CAL_CSI2_CTX(ctx->phy->instance, ctx->csi2_ctx)); - cal_set_field(&val, ctx->cport, CAL_CSI2_CTX_CPORT_MASK); - /* - * DT type: MIPI CSI-2 Specs - * 0x1: All - DT filter is disabled - * 0x24: RGB888 1 pixel = 3 bytes - * 0x2B: RAW10 4 pixels = 5 bytes - * 0x2A: RAW8 1 pixel = 1 byte - * 0x1E: YUV422 2 pixels = 4 bytes - */ - cal_set_field(&val, ctx->datatype, CAL_CSI2_CTX_DT_MASK); - cal_set_field(&val, ctx->vc, CAL_CSI2_CTX_VC_MASK); - cal_set_field(&val, ctx->v_fmt.fmt.pix.height, CAL_CSI2_CTX_LINES_MASK); - cal_set_field(&val, CAL_CSI2_CTX_ATT_PIX, CAL_CSI2_CTX_ATT_MASK); - cal_set_field(&val, CAL_CSI2_CTX_PACK_MODE_LINE, - CAL_CSI2_CTX_PACK_MODE_MASK); - cal_write(ctx->cal, CAL_CSI2_CTX(ctx->phy->instance, ctx->csi2_ctx), val); - ctx_dbg(3, ctx, "CAL_CSI2_CTX(%u, %u) = 0x%08x\n", - ctx->phy->instance, ctx->csi2_ctx, - cal_read(ctx->cal, CAL_CSI2_CTX(ctx->phy->instance, ctx->csi2_ctx))); -} - -static void cal_ctx_pix_proc_config(struct cal_ctx *ctx) -{ - u32 val, extract, pack; - - switch (ctx->fmtinfo->bpp) { - case 8: - extract = CAL_PIX_PROC_EXTRACT_B8; - pack = CAL_PIX_PROC_PACK_B8; - break; - case 10: - extract = CAL_PIX_PROC_EXTRACT_B10_MIPI; - pack = CAL_PIX_PROC_PACK_B16; - break; - case 12: - extract = CAL_PIX_PROC_EXTRACT_B12_MIPI; - pack = CAL_PIX_PROC_PACK_B16; - break; - case 16: - extract = CAL_PIX_PROC_EXTRACT_B16_LE; - pack = CAL_PIX_PROC_PACK_B16; - break; - default: - /* - * If you see this warning then it means that you added - * some new entry in the cal_formats[] array with a different - * bit per pixel values then the one supported below. - * Either add support for the new bpp value below or adjust - * the new entry to use one of the value below. - * - * Instead of failing here just use 8 bpp as a default. - */ - dev_warn_once(ctx->cal->dev, - "%s:%d:%s: bpp:%d unsupported! Overwritten with 8.\n", - __FILE__, __LINE__, __func__, ctx->fmtinfo->bpp); - extract = CAL_PIX_PROC_EXTRACT_B8; - pack = CAL_PIX_PROC_PACK_B8; - break; - } - - val = cal_read(ctx->cal, CAL_PIX_PROC(ctx->pix_proc)); - cal_set_field(&val, extract, CAL_PIX_PROC_EXTRACT_MASK); - cal_set_field(&val, CAL_PIX_PROC_DPCMD_BYPASS, CAL_PIX_PROC_DPCMD_MASK); - cal_set_field(&val, CAL_PIX_PROC_DPCME_BYPASS, CAL_PIX_PROC_DPCME_MASK); - cal_set_field(&val, pack, CAL_PIX_PROC_PACK_MASK); - cal_set_field(&val, ctx->cport, CAL_PIX_PROC_CPORT_MASK); - cal_set_field(&val, 1, CAL_PIX_PROC_EN_MASK); - cal_write(ctx->cal, CAL_PIX_PROC(ctx->pix_proc), val); - ctx_dbg(3, ctx, "CAL_PIX_PROC(%u) = 0x%08x\n", ctx->pix_proc, - cal_read(ctx->cal, CAL_PIX_PROC(ctx->pix_proc))); -} - -static void cal_ctx_wr_dma_config(struct cal_ctx *ctx) -{ - unsigned int stride = ctx->v_fmt.fmt.pix.bytesperline; - u32 val; - - val = cal_read(ctx->cal, CAL_WR_DMA_CTRL(ctx->dma_ctx)); - cal_set_field(&val, ctx->cport, CAL_WR_DMA_CTRL_CPORT_MASK); - cal_set_field(&val, ctx->v_fmt.fmt.pix.height, - CAL_WR_DMA_CTRL_YSIZE_MASK); - cal_set_field(&val, CAL_WR_DMA_CTRL_DTAG_PIX_DAT, - CAL_WR_DMA_CTRL_DTAG_MASK); - cal_set_field(&val, CAL_WR_DMA_CTRL_PATTERN_LINEAR, - CAL_WR_DMA_CTRL_PATTERN_MASK); - cal_set_field(&val, 1, CAL_WR_DMA_CTRL_STALL_RD_MASK); - cal_write(ctx->cal, CAL_WR_DMA_CTRL(ctx->dma_ctx), val); - ctx_dbg(3, ctx, "CAL_WR_DMA_CTRL(%d) = 0x%08x\n", ctx->dma_ctx, - cal_read(ctx->cal, CAL_WR_DMA_CTRL(ctx->dma_ctx))); - - cal_write_field(ctx->cal, CAL_WR_DMA_OFST(ctx->dma_ctx), - stride / 16, CAL_WR_DMA_OFST_MASK); - ctx_dbg(3, ctx, "CAL_WR_DMA_OFST(%d) = 0x%08x\n", ctx->dma_ctx, - cal_read(ctx->cal, CAL_WR_DMA_OFST(ctx->dma_ctx))); - - val = cal_read(ctx->cal, CAL_WR_DMA_XSIZE(ctx->dma_ctx)); - /* 64 bit word means no skipping */ - cal_set_field(&val, 0, CAL_WR_DMA_XSIZE_XSKIP_MASK); - /* - * The XSIZE field is expressed in 64-bit units and prevents overflows - * in case of synchronization issues by limiting the number of bytes - * written per line. - */ - cal_set_field(&val, stride / 8, CAL_WR_DMA_XSIZE_MASK); - cal_write(ctx->cal, CAL_WR_DMA_XSIZE(ctx->dma_ctx), val); - ctx_dbg(3, ctx, "CAL_WR_DMA_XSIZE(%d) = 0x%08x\n", ctx->dma_ctx, - cal_read(ctx->cal, CAL_WR_DMA_XSIZE(ctx->dma_ctx))); -} - -void cal_ctx_set_dma_addr(struct cal_ctx *ctx, dma_addr_t addr) -{ - cal_write(ctx->cal, CAL_WR_DMA_ADDR(ctx->dma_ctx), addr); -} - -static void cal_ctx_wr_dma_enable(struct cal_ctx *ctx) -{ - u32 val = cal_read(ctx->cal, CAL_WR_DMA_CTRL(ctx->dma_ctx)); - - cal_set_field(&val, CAL_WR_DMA_CTRL_MODE_CONST, - CAL_WR_DMA_CTRL_MODE_MASK); - cal_write(ctx->cal, CAL_WR_DMA_CTRL(ctx->dma_ctx), val); -} - -static void cal_ctx_wr_dma_disable(struct cal_ctx *ctx) -{ - u32 val = cal_read(ctx->cal, CAL_WR_DMA_CTRL(ctx->dma_ctx)); - - cal_set_field(&val, CAL_WR_DMA_CTRL_MODE_DIS, - CAL_WR_DMA_CTRL_MODE_MASK); - cal_write(ctx->cal, CAL_WR_DMA_CTRL(ctx->dma_ctx), val); -} - -static bool cal_ctx_wr_dma_stopped(struct cal_ctx *ctx) -{ - bool stopped; - - spin_lock_irq(&ctx->dma.lock); - stopped = ctx->dma.state == CAL_DMA_STOPPED; - spin_unlock_irq(&ctx->dma.lock); - - return stopped; -} - -int cal_ctx_prepare(struct cal_ctx *ctx) -{ - int ret; - - ctx->use_pix_proc = !ctx->fmtinfo->meta; - - if (ctx->use_pix_proc) { - ret = cal_reserve_pix_proc(ctx->cal); - if (ret < 0) { - ctx_err(ctx, "Failed to reserve pix proc: %d\n", ret); - return ret; - } - - ctx->pix_proc = ret; - } - - return 0; -} - -void cal_ctx_unprepare(struct cal_ctx *ctx) -{ - if (ctx->use_pix_proc) - cal_release_pix_proc(ctx->cal, ctx->pix_proc); -} - -void cal_ctx_start(struct cal_ctx *ctx) -{ - ctx->sequence = 0; - ctx->dma.state = CAL_DMA_RUNNING; - - /* Configure the CSI-2, pixel processing and write DMA contexts. */ - cal_ctx_csi2_config(ctx); - if (ctx->use_pix_proc) - cal_ctx_pix_proc_config(ctx); - cal_ctx_wr_dma_config(ctx); - - /* Enable IRQ_WDMA_END and IRQ_WDMA_START. */ - cal_write(ctx->cal, CAL_HL_IRQENABLE_SET(1), - CAL_HL_IRQ_WDMA_END_MASK(ctx->dma_ctx)); - cal_write(ctx->cal, CAL_HL_IRQENABLE_SET(2), - CAL_HL_IRQ_WDMA_START_MASK(ctx->dma_ctx)); - - cal_ctx_wr_dma_enable(ctx); -} - -void cal_ctx_stop(struct cal_ctx *ctx) -{ - long timeout; - - /* - * Request DMA stop and wait until it completes. If completion times - * out, forcefully disable the DMA. - */ - spin_lock_irq(&ctx->dma.lock); - ctx->dma.state = CAL_DMA_STOP_REQUESTED; - spin_unlock_irq(&ctx->dma.lock); - - timeout = wait_event_timeout(ctx->dma.wait, cal_ctx_wr_dma_stopped(ctx), - msecs_to_jiffies(500)); - if (!timeout) { - ctx_err(ctx, "failed to disable dma cleanly\n"); - cal_ctx_wr_dma_disable(ctx); - } - - /* Disable IRQ_WDMA_END and IRQ_WDMA_START. */ - cal_write(ctx->cal, CAL_HL_IRQENABLE_CLR(1), - CAL_HL_IRQ_WDMA_END_MASK(ctx->dma_ctx)); - cal_write(ctx->cal, CAL_HL_IRQENABLE_CLR(2), - CAL_HL_IRQ_WDMA_START_MASK(ctx->dma_ctx)); - - ctx->dma.state = CAL_DMA_STOPPED; - - /* Disable CSI2 context */ - cal_write(ctx->cal, CAL_CSI2_CTX(ctx->phy->instance, ctx->csi2_ctx), 0); - - /* Disable pix proc */ - if (ctx->use_pix_proc) - cal_write(ctx->cal, CAL_PIX_PROC(ctx->pix_proc), 0); -} - -/* ------------------------------------------------------------------ - * IRQ Handling - * ------------------------------------------------------------------ - */ - -static inline void cal_irq_wdma_start(struct cal_ctx *ctx) -{ - spin_lock(&ctx->dma.lock); - - if (ctx->dma.state == CAL_DMA_STOP_REQUESTED) { - /* - * If a stop is requested, disable the write DMA context - * immediately. The CAL_WR_DMA_CTRL_j.MODE field is shadowed, - * the current frame will complete and the DMA will then stop. - */ - cal_ctx_wr_dma_disable(ctx); - ctx->dma.state = CAL_DMA_STOP_PENDING; - } else if (!list_empty(&ctx->dma.queue) && !ctx->dma.pending) { - /* - * Otherwise, if a new buffer is available, queue it to the - * hardware. - */ - struct cal_buffer *buf; - dma_addr_t addr; - - buf = list_first_entry(&ctx->dma.queue, struct cal_buffer, - list); - addr = vb2_dma_contig_plane_dma_addr(&buf->vb.vb2_buf, 0); - cal_ctx_set_dma_addr(ctx, addr); - - ctx->dma.pending = buf; - list_del(&buf->list); - } - - spin_unlock(&ctx->dma.lock); -} - -static inline void cal_irq_wdma_end(struct cal_ctx *ctx) -{ - struct cal_buffer *buf = NULL; - - spin_lock(&ctx->dma.lock); - - /* If the DMA context was stopping, it is now stopped. */ - if (ctx->dma.state == CAL_DMA_STOP_PENDING) { - ctx->dma.state = CAL_DMA_STOPPED; - wake_up(&ctx->dma.wait); - } - - /* If a new buffer was queued, complete the current buffer. */ - if (ctx->dma.pending) { - buf = ctx->dma.active; - ctx->dma.active = ctx->dma.pending; - ctx->dma.pending = NULL; - } - - spin_unlock(&ctx->dma.lock); - - if (buf) { - buf->vb.vb2_buf.timestamp = ktime_get_ns(); - buf->vb.field = ctx->v_fmt.fmt.pix.field; - buf->vb.sequence = ctx->sequence++; - vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_DONE); - } -} - -static irqreturn_t cal_irq(int irq_cal, void *data) -{ - struct cal_dev *cal = data; - u32 status; - - status = cal_read(cal, CAL_HL_IRQSTATUS(0)); - if (status) { - unsigned int i; - - cal_write(cal, CAL_HL_IRQSTATUS(0), status); - - if (status & CAL_HL_IRQ_OCPO_ERR_MASK) - dev_err_ratelimited(cal->dev, "OCPO ERROR\n"); - - for (i = 0; i < cal->data->num_csi2_phy; ++i) { - if (status & CAL_HL_IRQ_CIO_MASK(i)) { - u32 cio_stat = cal_read(cal, - CAL_CSI2_COMPLEXIO_IRQSTATUS(i)); - - dev_err_ratelimited(cal->dev, - "CIO%u error: %#08x\n", i, cio_stat); - - cal_write(cal, CAL_CSI2_COMPLEXIO_IRQSTATUS(i), - cio_stat); - } - - if (status & CAL_HL_IRQ_VC_MASK(i)) { - u32 vc_stat = cal_read(cal, CAL_CSI2_VC_IRQSTATUS(i)); - - dev_err_ratelimited(cal->dev, - "CIO%u VC error: %#08x\n", - i, vc_stat); - - cal_write(cal, CAL_CSI2_VC_IRQSTATUS(i), vc_stat); - } - } - } - - /* Check which DMA just finished */ - status = cal_read(cal, CAL_HL_IRQSTATUS(1)); - if (status) { - unsigned int i; - - /* Clear Interrupt status */ - cal_write(cal, CAL_HL_IRQSTATUS(1), status); - - for (i = 0; i < cal->num_contexts; ++i) { - if (status & CAL_HL_IRQ_WDMA_END_MASK(i)) - cal_irq_wdma_end(cal->ctx[i]); - } - } - - /* Check which DMA just started */ - status = cal_read(cal, CAL_HL_IRQSTATUS(2)); - if (status) { - unsigned int i; - - /* Clear Interrupt status */ - cal_write(cal, CAL_HL_IRQSTATUS(2), status); - - for (i = 0; i < cal->num_contexts; ++i) { - if (status & CAL_HL_IRQ_WDMA_START_MASK(i)) - cal_irq_wdma_start(cal->ctx[i]); - } - } - - return IRQ_HANDLED; -} - -/* ------------------------------------------------------------------ - * Asynchronous V4L2 subdev binding - * ------------------------------------------------------------------ - */ - -struct cal_v4l2_async_subdev { - struct v4l2_async_subdev asd; /* Must be first */ - struct cal_camerarx *phy; -}; - -static inline struct cal_v4l2_async_subdev * -to_cal_asd(struct v4l2_async_subdev *asd) -{ - return container_of(asd, struct cal_v4l2_async_subdev, asd); -} - -static int cal_async_notifier_bound(struct v4l2_async_notifier *notifier, - struct v4l2_subdev *subdev, - struct v4l2_async_subdev *asd) -{ - struct cal_camerarx *phy = to_cal_asd(asd)->phy; - int pad; - int ret; - - if (phy->source) { - phy_info(phy, "Rejecting subdev %s (Already set!!)", - subdev->name); - return 0; - } - - phy->source = subdev; - phy_dbg(1, phy, "Using source %s for capture\n", subdev->name); - - pad = media_entity_get_fwnode_pad(&subdev->entity, - of_fwnode_handle(phy->source_ep_node), - MEDIA_PAD_FL_SOURCE); - if (pad < 0) { - phy_err(phy, "Source %s has no connected source pad\n", - subdev->name); - return pad; - } - - ret = media_create_pad_link(&subdev->entity, pad, - &phy->subdev.entity, CAL_CAMERARX_PAD_SINK, - MEDIA_LNK_FL_IMMUTABLE | - MEDIA_LNK_FL_ENABLED); - if (ret) { - phy_err(phy, "Failed to create media link for source %s\n", - subdev->name); - return ret; - } - - return 0; -} - -static int cal_async_notifier_complete(struct v4l2_async_notifier *notifier) -{ - struct cal_dev *cal = container_of(notifier, struct cal_dev, notifier); - unsigned int i; - int ret; - - for (i = 0; i < cal->num_contexts; ++i) { - ret = cal_ctx_v4l2_register(cal->ctx[i]); - if (ret) - goto err_ctx_unreg; - } - - if (!cal_mc_api) - return 0; - - ret = v4l2_device_register_subdev_nodes(&cal->v4l2_dev); - if (ret) - goto err_ctx_unreg; - - return 0; - -err_ctx_unreg: - for (; i > 0; --i) { - if (!cal->ctx[i - 1]) - continue; - - cal_ctx_v4l2_unregister(cal->ctx[i - 1]); - } - - return ret; -} - -static const struct v4l2_async_notifier_operations cal_async_notifier_ops = { - .bound = cal_async_notifier_bound, - .complete = cal_async_notifier_complete, -}; - -static int cal_async_notifier_register(struct cal_dev *cal) -{ - unsigned int i; - int ret; - - v4l2_async_nf_init(&cal->notifier); - cal->notifier.ops = &cal_async_notifier_ops; - - for (i = 0; i < cal->data->num_csi2_phy; ++i) { - struct cal_camerarx *phy = cal->phy[i]; - struct cal_v4l2_async_subdev *casd; - struct fwnode_handle *fwnode; - - if (!phy->source_node) - continue; - - fwnode = of_fwnode_handle(phy->source_node); - casd = v4l2_async_nf_add_fwnode(&cal->notifier, - fwnode, - struct cal_v4l2_async_subdev); - if (IS_ERR(casd)) { - phy_err(phy, "Failed to add subdev to notifier\n"); - ret = PTR_ERR(casd); - goto error; - } - - casd->phy = phy; - } - - ret = v4l2_async_nf_register(&cal->v4l2_dev, &cal->notifier); - if (ret) { - cal_err(cal, "Error registering async notifier\n"); - goto error; - } - - return 0; - -error: - v4l2_async_nf_cleanup(&cal->notifier); - return ret; -} - -static void cal_async_notifier_unregister(struct cal_dev *cal) -{ - v4l2_async_nf_unregister(&cal->notifier); - v4l2_async_nf_cleanup(&cal->notifier); -} - -/* ------------------------------------------------------------------ - * Media and V4L2 device handling - * ------------------------------------------------------------------ - */ - -/* - * Register user-facing devices. To be called at the end of the probe function - * when all resources are initialized and ready. - */ -static int cal_media_register(struct cal_dev *cal) -{ - int ret; - - ret = media_device_register(&cal->mdev); - if (ret) { - cal_err(cal, "Failed to register media device\n"); - return ret; - } - - /* - * Register the async notifier. This may trigger registration of the - * V4L2 video devices if all subdevs are ready. - */ - ret = cal_async_notifier_register(cal); - if (ret) { - media_device_unregister(&cal->mdev); - return ret; - } - - return 0; -} - -/* - * Unregister the user-facing devices, but don't free memory yet. To be called - * at the beginning of the remove function, to disallow access from userspace. - */ -static void cal_media_unregister(struct cal_dev *cal) -{ - unsigned int i; - - /* Unregister all the V4L2 video devices. */ - for (i = 0; i < cal->num_contexts; i++) - cal_ctx_v4l2_unregister(cal->ctx[i]); - - cal_async_notifier_unregister(cal); - media_device_unregister(&cal->mdev); -} - -/* - * Initialize the in-kernel objects. To be called at the beginning of the probe - * function, before the V4L2 device is used by the driver. - */ -static int cal_media_init(struct cal_dev *cal) -{ - struct media_device *mdev = &cal->mdev; - int ret; - - mdev->dev = cal->dev; - mdev->hw_revision = cal->revision; - strscpy(mdev->model, "CAL", sizeof(mdev->model)); - snprintf(mdev->bus_info, sizeof(mdev->bus_info), "platform:%s", - dev_name(mdev->dev)); - media_device_init(mdev); - - /* - * Initialize the V4L2 device (despite the function name, this performs - * initialization, not registration). - */ - cal->v4l2_dev.mdev = mdev; - ret = v4l2_device_register(cal->dev, &cal->v4l2_dev); - if (ret) { - cal_err(cal, "Failed to register V4L2 device\n"); - return ret; - } - - vb2_dma_contig_set_max_seg_size(cal->dev, DMA_BIT_MASK(32)); - - return 0; -} - -/* - * Cleanup the in-kernel objects, freeing memory. To be called at the very end - * of the remove sequence, when nothing (including userspace) can access the - * objects anymore. - */ -static void cal_media_cleanup(struct cal_dev *cal) -{ - v4l2_device_unregister(&cal->v4l2_dev); - media_device_cleanup(&cal->mdev); - - vb2_dma_contig_clear_max_seg_size(cal->dev); -} - -/* ------------------------------------------------------------------ - * Initialization and module stuff - * ------------------------------------------------------------------ - */ - -static struct cal_ctx *cal_ctx_create(struct cal_dev *cal, int inst) -{ - struct cal_ctx *ctx; - int ret; - - ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); - if (!ctx) - return NULL; - - ctx->cal = cal; - ctx->phy = cal->phy[inst]; - ctx->dma_ctx = inst; - ctx->csi2_ctx = inst; - ctx->cport = inst; - ctx->vc = 0; - ctx->datatype = CAL_CSI2_CTX_DT_ANY; - - ret = cal_ctx_v4l2_init(ctx); - if (ret) - return NULL; - - return ctx; -} - -static void cal_ctx_destroy(struct cal_ctx *ctx) -{ - cal_ctx_v4l2_cleanup(ctx); - - kfree(ctx); -} - -static const struct of_device_id cal_of_match[] = { - { - .compatible = "ti,dra72-cal", - .data = (void *)&dra72x_cal_data, - }, - { - .compatible = "ti,dra72-pre-es2-cal", - .data = (void *)&dra72x_es1_cal_data, - }, - { - .compatible = "ti,dra76-cal", - .data = (void *)&dra76x_cal_data, - }, - { - .compatible = "ti,am654-cal", - .data = (void *)&am654_cal_data, - }, - {}, -}; -MODULE_DEVICE_TABLE(of, cal_of_match); - -/* Get hardware revision and info. */ - -#define CAL_HL_HWINFO_VALUE 0xa3c90469 - -static void cal_get_hwinfo(struct cal_dev *cal) -{ - u32 hwinfo; - - cal->revision = cal_read(cal, CAL_HL_REVISION); - switch (FIELD_GET(CAL_HL_REVISION_SCHEME_MASK, cal->revision)) { - case CAL_HL_REVISION_SCHEME_H08: - cal_dbg(3, cal, "CAL HW revision %lu.%lu.%lu (0x%08x)\n", - FIELD_GET(CAL_HL_REVISION_MAJOR_MASK, cal->revision), - FIELD_GET(CAL_HL_REVISION_MINOR_MASK, cal->revision), - FIELD_GET(CAL_HL_REVISION_RTL_MASK, cal->revision), - cal->revision); - break; - - case CAL_HL_REVISION_SCHEME_LEGACY: - default: - cal_info(cal, "Unexpected CAL HW revision 0x%08x\n", - cal->revision); - break; - } - - hwinfo = cal_read(cal, CAL_HL_HWINFO); - if (hwinfo != CAL_HL_HWINFO_VALUE) - cal_info(cal, "CAL_HL_HWINFO = 0x%08x, expected 0x%08x\n", - hwinfo, CAL_HL_HWINFO_VALUE); -} - -static int cal_init_camerarx_regmap(struct cal_dev *cal) -{ - struct platform_device *pdev = to_platform_device(cal->dev); - struct device_node *np = cal->dev->of_node; - struct regmap_config config = { }; - struct regmap *syscon; - struct resource *res; - unsigned int offset; - void __iomem *base; - - syscon = syscon_regmap_lookup_by_phandle_args(np, "ti,camerrx-control", - 1, &offset); - if (!IS_ERR(syscon)) { - cal->syscon_camerrx = syscon; - cal->syscon_camerrx_offset = offset; - return 0; - } - - dev_warn(cal->dev, "failed to get ti,camerrx-control: %ld\n", - PTR_ERR(syscon)); - - /* - * Backward DTS compatibility. If syscon entry is not present then - * check if the camerrx_control resource is present. - */ - res = platform_get_resource_byname(pdev, IORESOURCE_MEM, - "camerrx_control"); - base = devm_ioremap_resource(cal->dev, res); - if (IS_ERR(base)) { - cal_err(cal, "failed to ioremap camerrx_control\n"); - return PTR_ERR(base); - } - - cal_dbg(1, cal, "ioresource %s at %pa - %pa\n", - res->name, &res->start, &res->end); - - config.reg_bits = 32; - config.reg_stride = 4; - config.val_bits = 32; - config.max_register = resource_size(res) - 4; - - syscon = regmap_init_mmio(NULL, base, &config); - if (IS_ERR(syscon)) { - pr_err("regmap init failed\n"); - return PTR_ERR(syscon); - } - - /* - * In this case the base already point to the direct CM register so no - * need for an offset. - */ - cal->syscon_camerrx = syscon; - cal->syscon_camerrx_offset = 0; - - return 0; -} - -static int cal_probe(struct platform_device *pdev) -{ - struct cal_dev *cal; - bool connected = false; - unsigned int i; - int ret; - int irq; - - cal = devm_kzalloc(&pdev->dev, sizeof(*cal), GFP_KERNEL); - if (!cal) - return -ENOMEM; - - cal->data = of_device_get_match_data(&pdev->dev); - if (!cal->data) { - dev_err(&pdev->dev, "Could not get feature data based on compatible version\n"); - return -ENODEV; - } - - cal->dev = &pdev->dev; - platform_set_drvdata(pdev, cal); - - /* Acquire resources: clocks, CAMERARX regmap, I/O memory and IRQ. */ - cal->fclk = devm_clk_get(&pdev->dev, "fck"); - if (IS_ERR(cal->fclk)) { - dev_err(&pdev->dev, "cannot get CAL fclk\n"); - return PTR_ERR(cal->fclk); - } - - ret = cal_init_camerarx_regmap(cal); - if (ret < 0) - return ret; - - cal->res = platform_get_resource_byname(pdev, IORESOURCE_MEM, - "cal_top"); - cal->base = devm_ioremap_resource(&pdev->dev, cal->res); - if (IS_ERR(cal->base)) - return PTR_ERR(cal->base); - - cal_dbg(1, cal, "ioresource %s at %pa - %pa\n", - cal->res->name, &cal->res->start, &cal->res->end); - - irq = platform_get_irq(pdev, 0); - cal_dbg(1, cal, "got irq# %d\n", irq); - ret = devm_request_irq(&pdev->dev, irq, cal_irq, 0, CAL_MODULE_NAME, - cal); - if (ret) - return ret; - - /* Read the revision and hardware info to verify hardware access. */ - pm_runtime_enable(&pdev->dev); - ret = pm_runtime_resume_and_get(&pdev->dev); - if (ret) - goto error_pm_runtime; - - cal_get_hwinfo(cal); - pm_runtime_put_sync(&pdev->dev); - - /* Initialize the media device. */ - ret = cal_media_init(cal); - if (ret < 0) - goto error_pm_runtime; - - /* Create CAMERARX PHYs. */ - for (i = 0; i < cal->data->num_csi2_phy; ++i) { - cal->phy[i] = cal_camerarx_create(cal, i); - if (IS_ERR(cal->phy[i])) { - ret = PTR_ERR(cal->phy[i]); - cal->phy[i] = NULL; - goto error_camerarx; - } - - if (cal->phy[i]->source_node) - connected = true; - } - - if (!connected) { - cal_err(cal, "Neither port is configured, no point in staying up\n"); - ret = -ENODEV; - goto error_camerarx; - } - - /* Create contexts. */ - for (i = 0; i < cal->data->num_csi2_phy; ++i) { - if (!cal->phy[i]->source_node) - continue; - - cal->ctx[cal->num_contexts] = cal_ctx_create(cal, i); - if (!cal->ctx[cal->num_contexts]) { - cal_err(cal, "Failed to create context %u\n", cal->num_contexts); - ret = -ENODEV; - goto error_context; - } - - cal->num_contexts++; - } - - /* Register the media device. */ - ret = cal_media_register(cal); - if (ret) - goto error_context; - - return 0; - -error_context: - for (i = 0; i < cal->num_contexts; i++) - cal_ctx_destroy(cal->ctx[i]); - -error_camerarx: - for (i = 0; i < cal->data->num_csi2_phy; i++) - cal_camerarx_destroy(cal->phy[i]); - - cal_media_cleanup(cal); - -error_pm_runtime: - pm_runtime_disable(&pdev->dev); - - return ret; -} - -static int cal_remove(struct platform_device *pdev) -{ - struct cal_dev *cal = platform_get_drvdata(pdev); - unsigned int i; - int ret; - - cal_dbg(1, cal, "Removing %s\n", CAL_MODULE_NAME); - - ret = pm_runtime_resume_and_get(&pdev->dev); - - cal_media_unregister(cal); - - for (i = 0; i < cal->data->num_csi2_phy; i++) - cal_camerarx_disable(cal->phy[i]); - - for (i = 0; i < cal->num_contexts; i++) - cal_ctx_destroy(cal->ctx[i]); - - for (i = 0; i < cal->data->num_csi2_phy; i++) - cal_camerarx_destroy(cal->phy[i]); - - cal_media_cleanup(cal); - - if (ret >= 0) - pm_runtime_put_sync(&pdev->dev); - pm_runtime_disable(&pdev->dev); - - return 0; -} - -static int cal_runtime_resume(struct device *dev) -{ - struct cal_dev *cal = dev_get_drvdata(dev); - unsigned int i; - u32 val; - - if (cal->data->flags & DRA72_CAL_PRE_ES2_LDO_DISABLE) { - /* - * Apply errata on both port everytime we (re-)enable - * the clock - */ - for (i = 0; i < cal->data->num_csi2_phy; i++) - cal_camerarx_i913_errata(cal->phy[i]); - } - - /* - * Enable global interrupts that are not related to a particular - * CAMERARAX or context. - */ - cal_write(cal, CAL_HL_IRQENABLE_SET(0), CAL_HL_IRQ_OCPO_ERR_MASK); - - val = cal_read(cal, CAL_CTRL); - cal_set_field(&val, CAL_CTRL_BURSTSIZE_BURST128, - CAL_CTRL_BURSTSIZE_MASK); - cal_set_field(&val, 0xf, CAL_CTRL_TAGCNT_MASK); - cal_set_field(&val, CAL_CTRL_POSTED_WRITES_NONPOSTED, - CAL_CTRL_POSTED_WRITES_MASK); - cal_set_field(&val, 0xff, CAL_CTRL_MFLAGL_MASK); - cal_set_field(&val, 0xff, CAL_CTRL_MFLAGH_MASK); - cal_write(cal, CAL_CTRL, val); - cal_dbg(3, cal, "CAL_CTRL = 0x%08x\n", cal_read(cal, CAL_CTRL)); - - return 0; -} - -static const struct dev_pm_ops cal_pm_ops = { - .runtime_resume = cal_runtime_resume, -}; - -static struct platform_driver cal_pdrv = { - .probe = cal_probe, - .remove = cal_remove, - .driver = { - .name = CAL_MODULE_NAME, - .pm = &cal_pm_ops, - .of_match_table = cal_of_match, - }, -}; - -module_platform_driver(cal_pdrv); diff --git a/drivers/media/platform/ti-vpe/cal.h b/drivers/media/platform/ti-vpe/cal.h deleted file mode 100644 index 527e22d022f3..000000000000 --- a/drivers/media/platform/ti-vpe/cal.h +++ /dev/null @@ -1,343 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * TI Camera Access Layer (CAL) - * - * Copyright (c) 2015-2020 Texas Instruments Inc. - * - * Authors: - * Benoit Parrot - * Laurent Pinchart - */ -#ifndef __TI_CAL_H__ -#define __TI_CAL_H__ - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#define CAL_MODULE_NAME "cal" -#define CAL_MAX_NUM_CONTEXT 8 -#define CAL_NUM_CSI2_PORTS 2 - -/* - * The width is limited by the size of the CAL_WR_DMA_XSIZE_j.XSIZE field, - * expressed in multiples of 64 bits. The height is limited by the size of the - * CAL_CSI2_CTXi_j.CTXi_LINES and CAL_WR_DMA_CTRL_j.YSIZE fields, expressed in - * lines. - */ -#define CAL_MIN_WIDTH_BYTES 16 -#define CAL_MAX_WIDTH_BYTES (8192 * 8) -#define CAL_MIN_HEIGHT_LINES 1 -#define CAL_MAX_HEIGHT_LINES 16383 - -#define CAL_CAMERARX_PAD_SINK 0 -#define CAL_CAMERARX_PAD_FIRST_SOURCE 1 -#define CAL_CAMERARX_NUM_SOURCE_PADS 1 -#define CAL_CAMERARX_NUM_PADS (1 + CAL_CAMERARX_NUM_SOURCE_PADS) - -static inline bool cal_rx_pad_is_sink(u32 pad) -{ - /* Camera RX has 1 sink pad, and N source pads */ - return pad == 0; -} - -static inline bool cal_rx_pad_is_source(u32 pad) -{ - /* Camera RX has 1 sink pad, and N source pads */ - return pad >= CAL_CAMERARX_PAD_FIRST_SOURCE && - pad <= CAL_CAMERARX_NUM_SOURCE_PADS; -} - -struct device; -struct device_node; -struct resource; -struct regmap; -struct regmap_fied; - -/* CTRL_CORE_CAMERRX_CONTROL register field id */ -enum cal_camerarx_field { - F_CTRLCLKEN, - F_CAMMODE, - F_LANEENABLE, - F_CSI_MODE, - F_MAX_FIELDS, -}; - -enum cal_dma_state { - CAL_DMA_RUNNING, - CAL_DMA_STOP_REQUESTED, - CAL_DMA_STOP_PENDING, - CAL_DMA_STOPPED, -}; - -struct cal_format_info { - u32 fourcc; - u32 code; - /* Bits per pixel */ - u8 bpp; - bool meta; -}; - -/* buffer for one video frame */ -struct cal_buffer { - /* common v4l buffer stuff -- must be first */ - struct vb2_v4l2_buffer vb; - struct list_head list; -}; - -/** - * struct cal_dmaqueue - Queue of DMA buffers - */ -struct cal_dmaqueue { - /** - * @lock: Protects all fields in the cal_dmaqueue. - */ - spinlock_t lock; - - /** - * @queue: Buffers queued to the driver and waiting for DMA processing. - * Buffers are added to the list by the vb2 .buffer_queue() operation, - * and move to @pending when they are scheduled for the next frame. - */ - struct list_head queue; - /** - * @pending: Buffer provided to the hardware to DMA the next frame. - * Will move to @active at the end of the current frame. - */ - struct cal_buffer *pending; - /** - * @active: Buffer being DMA'ed to for the current frame. Will be - * retired and given back to vb2 at the end of the current frame if - * a @pending buffer has been scheduled to replace it. - */ - struct cal_buffer *active; - - /** @state: State of the DMA engine. */ - enum cal_dma_state state; - /** @wait: Wait queue to signal a @state transition to CAL_DMA_STOPPED. */ - struct wait_queue_head wait; -}; - -struct cal_camerarx_data { - struct { - unsigned int lsb; - unsigned int msb; - } fields[F_MAX_FIELDS]; - unsigned int num_lanes; -}; - -struct cal_data { - const struct cal_camerarx_data *camerarx; - unsigned int num_csi2_phy; - unsigned int flags; -}; - -/* - * The Camera Adaptation Layer (CAL) module is paired with one or more complex - * I/O PHYs (CAMERARX). It contains multiple instances of CSI-2, processing and - * DMA contexts. - * - * The cal_dev structure represents the whole subsystem, including the CAL and - * the CAMERARX instances. Instances of struct cal_dev are named cal through the - * driver. - * - * The cal_camerarx structure represents one CAMERARX instance. Instances of - * cal_camerarx are named phy through the driver. - * - * The cal_ctx structure represents the combination of one CSI-2 context, one - * processing context and one DMA context. Instance of struct cal_ctx are named - * ctx through the driver. - */ - -struct cal_camerarx { - void __iomem *base; - struct resource *res; - struct regmap_field *fields[F_MAX_FIELDS]; - - struct cal_dev *cal; - unsigned int instance; - - struct v4l2_fwnode_endpoint endpoint; - struct device_node *source_ep_node; - struct device_node *source_node; - struct v4l2_subdev *source; - struct media_pipeline pipe; - - struct v4l2_subdev subdev; - struct media_pad pads[CAL_CAMERARX_NUM_PADS]; - struct v4l2_mbus_framefmt formats[CAL_CAMERARX_NUM_PADS]; - - /* - * Lock for camerarx ops. Protects: - * - formats - * - enable_count - */ - struct mutex mutex; - - unsigned int enable_count; -}; - -struct cal_dev { - struct clk *fclk; - int irq; - void __iomem *base; - struct resource *res; - struct device *dev; - - const struct cal_data *data; - u32 revision; - - /* Control Module handle */ - struct regmap *syscon_camerrx; - u32 syscon_camerrx_offset; - - /* Camera Core Module handle */ - struct cal_camerarx *phy[CAL_NUM_CSI2_PORTS]; - - u32 num_contexts; - struct cal_ctx *ctx[CAL_MAX_NUM_CONTEXT]; - - struct media_device mdev; - struct v4l2_device v4l2_dev; - struct v4l2_async_notifier notifier; - - unsigned long reserved_pix_proc_mask; -}; - -/* - * There is one cal_ctx structure for each camera core context. - */ -struct cal_ctx { - struct v4l2_ctrl_handler ctrl_handler; - struct video_device vdev; - struct media_pad pad; - - struct cal_dev *cal; - struct cal_camerarx *phy; - - /* v4l2_ioctl mutex */ - struct mutex mutex; - - struct cal_dmaqueue dma; - - /* video capture */ - const struct cal_format_info *fmtinfo; - /* Used to store current pixel format */ - struct v4l2_format v_fmt; - - /* Current subdev enumerated format (legacy) */ - const struct cal_format_info **active_fmt; - unsigned int num_active_fmt; - - unsigned int sequence; - struct vb2_queue vb_vidq; - u8 dma_ctx; - u8 cport; - u8 csi2_ctx; - u8 pix_proc; - u8 vc; - u8 datatype; - - bool use_pix_proc; -}; - -extern unsigned int cal_debug; -extern int cal_video_nr; -extern bool cal_mc_api; - -#define cal_dbg(level, cal, fmt, arg...) \ - do { \ - if (cal_debug >= (level)) \ - dev_printk(KERN_DEBUG, (cal)->dev, fmt, ##arg); \ - } while (0) -#define cal_info(cal, fmt, arg...) \ - dev_info((cal)->dev, fmt, ##arg) -#define cal_err(cal, fmt, arg...) \ - dev_err((cal)->dev, fmt, ##arg) - -#define ctx_dbg(level, ctx, fmt, arg...) \ - cal_dbg(level, (ctx)->cal, "ctx%u: " fmt, (ctx)->dma_ctx, ##arg) -#define ctx_info(ctx, fmt, arg...) \ - cal_info((ctx)->cal, "ctx%u: " fmt, (ctx)->dma_ctx, ##arg) -#define ctx_err(ctx, fmt, arg...) \ - cal_err((ctx)->cal, "ctx%u: " fmt, (ctx)->dma_ctx, ##arg) - -#define phy_dbg(level, phy, fmt, arg...) \ - cal_dbg(level, (phy)->cal, "phy%u: " fmt, (phy)->instance, ##arg) -#define phy_info(phy, fmt, arg...) \ - cal_info((phy)->cal, "phy%u: " fmt, (phy)->instance, ##arg) -#define phy_err(phy, fmt, arg...) \ - cal_err((phy)->cal, "phy%u: " fmt, (phy)->instance, ##arg) - -static inline u32 cal_read(struct cal_dev *cal, u32 offset) -{ - return ioread32(cal->base + offset); -} - -static inline void cal_write(struct cal_dev *cal, u32 offset, u32 val) -{ - iowrite32(val, cal->base + offset); -} - -static __always_inline u32 cal_read_field(struct cal_dev *cal, u32 offset, u32 mask) -{ - return FIELD_GET(mask, cal_read(cal, offset)); -} - -static inline void cal_write_field(struct cal_dev *cal, u32 offset, u32 value, - u32 mask) -{ - u32 val = cal_read(cal, offset); - - val &= ~mask; - val |= (value << __ffs(mask)) & mask; - cal_write(cal, offset, val); -} - -static inline void cal_set_field(u32 *valp, u32 field, u32 mask) -{ - u32 val = *valp; - - val &= ~mask; - val |= (field << __ffs(mask)) & mask; - *valp = val; -} - -extern const struct cal_format_info cal_formats[]; -extern const unsigned int cal_num_formats; -const struct cal_format_info *cal_format_by_fourcc(u32 fourcc); -const struct cal_format_info *cal_format_by_code(u32 code); - -void cal_quickdump_regs(struct cal_dev *cal); - -void cal_camerarx_disable(struct cal_camerarx *phy); -void cal_camerarx_i913_errata(struct cal_camerarx *phy); -struct cal_camerarx *cal_camerarx_create(struct cal_dev *cal, - unsigned int instance); -void cal_camerarx_destroy(struct cal_camerarx *phy); - -int cal_ctx_prepare(struct cal_ctx *ctx); -void cal_ctx_unprepare(struct cal_ctx *ctx); -void cal_ctx_set_dma_addr(struct cal_ctx *ctx, dma_addr_t addr); -void cal_ctx_start(struct cal_ctx *ctx); -void cal_ctx_stop(struct cal_ctx *ctx); - -int cal_ctx_v4l2_register(struct cal_ctx *ctx); -void cal_ctx_v4l2_unregister(struct cal_ctx *ctx); -int cal_ctx_v4l2_init(struct cal_ctx *ctx); -void cal_ctx_v4l2_cleanup(struct cal_ctx *ctx); - -#endif /* __TI_CAL_H__ */ diff --git a/drivers/media/platform/ti-vpe/cal_regs.h b/drivers/media/platform/ti-vpe/cal_regs.h deleted file mode 100644 index 40e4f972fcb7..000000000000 --- a/drivers/media/platform/ti-vpe/cal_regs.h +++ /dev/null @@ -1,463 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * TI CAL camera interface driver - * - * Copyright (c) 2015 Texas Instruments Inc. - * - * Benoit Parrot, - */ - -#ifndef __TI_CAL_REGS_H -#define __TI_CAL_REGS_H - -/* - * struct cal_dev.flags possibilities - * - * DRA72_CAL_PRE_ES2_LDO_DISABLE: - * Errata i913: CSI2 LDO Needs to be disabled when module is powered on - * - * Enabling CSI2 LDO shorts it to core supply. It is crucial the 2 CSI2 - * LDOs on the device are disabled if CSI-2 module is powered on - * (0x4845 B304 | 0x4845 B384 [28:27] = 0x1) or in ULPS (0x4845 B304 - * | 0x4845 B384 [28:27] = 0x2) mode. Common concerns include: high - * current draw on the module supply in active mode. - * - * Errata does not apply when CSI-2 module is powered off - * (0x4845 B304 | 0x4845 B384 [28:27] = 0x0). - * - * SW Workaround: - * Set the following register bits to disable the LDO, - * which is essentially CSI2 REG10 bit 6: - * - * Core 0: 0x4845 B828 = 0x0000 0040 - * Core 1: 0x4845 B928 = 0x0000 0040 - */ -#define DRA72_CAL_PRE_ES2_LDO_DISABLE BIT(0) - -/* CAL register offsets */ - -#define CAL_HL_REVISION 0x0000 -#define CAL_HL_HWINFO 0x0004 -#define CAL_HL_SYSCONFIG 0x0010 -#define CAL_HL_IRQ_EOI 0x001c -#define CAL_HL_IRQSTATUS_RAW(m) (0x20U + (m) * 0x10U) -#define CAL_HL_IRQSTATUS(m) (0x24U + (m) * 0x10U) -#define CAL_HL_IRQENABLE_SET(m) (0x28U + (m) * 0x10U) -#define CAL_HL_IRQENABLE_CLR(m) (0x2cU + (m) * 0x10U) -#define CAL_PIX_PROC(m) (0xc0U + (m) * 0x4U) -#define CAL_CTRL 0x100 -#define CAL_CTRL1 0x104 -#define CAL_LINE_NUMBER_EVT 0x108 -#define CAL_VPORT_CTRL1 0x120 -#define CAL_VPORT_CTRL2 0x124 -#define CAL_BYS_CTRL1 0x130 -#define CAL_BYS_CTRL2 0x134 -#define CAL_RD_DMA_CTRL 0x140 -#define CAL_RD_DMA_PIX_ADDR 0x144 -#define CAL_RD_DMA_PIX_OFST 0x148 -#define CAL_RD_DMA_XSIZE 0x14c -#define CAL_RD_DMA_YSIZE 0x150 -#define CAL_RD_DMA_INIT_ADDR 0x154 -#define CAL_RD_DMA_INIT_OFST 0x168 -#define CAL_RD_DMA_CTRL2 0x16c -#define CAL_WR_DMA_CTRL(m) (0x200U + (m) * 0x10U) -#define CAL_WR_DMA_ADDR(m) (0x204U + (m) * 0x10U) -#define CAL_WR_DMA_OFST(m) (0x208U + (m) * 0x10U) -#define CAL_WR_DMA_XSIZE(m) (0x20cU + (m) * 0x10U) -#define CAL_CSI2_PPI_CTRL(m) (0x300U + (m) * 0x80U) -#define CAL_CSI2_COMPLEXIO_CFG(m) (0x304U + (m) * 0x80U) -#define CAL_CSI2_COMPLEXIO_IRQSTATUS(m) (0x308U + (m) * 0x80U) -#define CAL_CSI2_SHORT_PACKET(m) (0x30cU + (m) * 0x80U) -#define CAL_CSI2_COMPLEXIO_IRQENABLE(m) (0x310U + (m) * 0x80U) -#define CAL_CSI2_TIMING(m) (0x314U + (m) * 0x80U) -#define CAL_CSI2_VC_IRQENABLE(m) (0x318U + (m) * 0x80U) -#define CAL_CSI2_VC_IRQSTATUS(m) (0x328U + (m) * 0x80U) -#define CAL_CSI2_CTX(phy, csi2_ctx) (0x330U + (phy) * 0x80U + (csi2_ctx) * 4) -#define CAL_CSI2_STATUS(phy, csi2_ctx) (0x350U + (phy) * 0x80U + (csi2_ctx) * 4) - -/* CAL CSI2 PHY register offsets */ -#define CAL_CSI2_PHY_REG0 0x000 -#define CAL_CSI2_PHY_REG1 0x004 -#define CAL_CSI2_PHY_REG2 0x008 -#define CAL_CSI2_PHY_REG10 0x028 - -/* CAL Control Module Core Camerrx Control register offsets */ -#define CM_CTRL_CORE_CAMERRX_CONTROL 0x000 - -/********************************************************************* -* Field Definition Macros -*********************************************************************/ - -#define CAL_HL_REVISION_MINOR_MASK GENMASK(5, 0) -#define CAL_HL_REVISION_CUSTOM_MASK GENMASK(7, 6) -#define CAL_HL_REVISION_MAJOR_MASK GENMASK(10, 8) -#define CAL_HL_REVISION_RTL_MASK GENMASK(15, 11) -#define CAL_HL_REVISION_FUNC_MASK GENMASK(27, 16) -#define CAL_HL_REVISION_SCHEME_MASK GENMASK(31, 30) -#define CAL_HL_REVISION_SCHEME_H08 1 -#define CAL_HL_REVISION_SCHEME_LEGACY 0 - -#define CAL_HL_HWINFO_WFIFO_MASK GENMASK(3, 0) -#define CAL_HL_HWINFO_RFIFO_MASK GENMASK(7, 4) -#define CAL_HL_HWINFO_PCTX_MASK GENMASK(12, 8) -#define CAL_HL_HWINFO_WCTX_MASK GENMASK(18, 13) -#define CAL_HL_HWINFO_VFIFO_MASK GENMASK(22, 19) -#define CAL_HL_HWINFO_NCPORT_MASK GENMASK(27, 23) -#define CAL_HL_HWINFO_NPPI_CTXS0_MASK GENMASK(29, 28) -#define CAL_HL_HWINFO_NPPI_CTXS1_MASK GENMASK(31, 30) -#define CAL_HL_HWINFO_NPPI_CONTEXTS_ZERO 0 -#define CAL_HL_HWINFO_NPPI_CONTEXTS_FOUR 1 -#define CAL_HL_HWINFO_NPPI_CONTEXTS_EIGHT 2 -#define CAL_HL_HWINFO_NPPI_CONTEXTS_RESERVED 3 - -#define CAL_HL_SYSCONFIG_SOFTRESET_MASK BIT(0) -#define CAL_HL_SYSCONFIG_SOFTRESET_DONE 0x0 -#define CAL_HL_SYSCONFIG_SOFTRESET_PENDING 0x1 -#define CAL_HL_SYSCONFIG_SOFTRESET_NOACTION 0x0 -#define CAL_HL_SYSCONFIG_SOFTRESET_RESET 0x1 -#define CAL_HL_SYSCONFIG_IDLE_MASK GENMASK(3, 2) -#define CAL_HL_SYSCONFIG_IDLEMODE_FORCE 0 -#define CAL_HL_SYSCONFIG_IDLEMODE_NO 1 -#define CAL_HL_SYSCONFIG_IDLEMODE_SMART1 2 -#define CAL_HL_SYSCONFIG_IDLEMODE_SMART2 3 - -#define CAL_HL_IRQ_EOI_LINE_NUMBER_MASK BIT(0) -#define CAL_HL_IRQ_EOI_LINE_NUMBER_READ0 0 -#define CAL_HL_IRQ_EOI_LINE_NUMBER_EOI0 0 - -#define CAL_HL_IRQ_WDMA_END_MASK(m) BIT(m) -#define CAL_HL_IRQ_WDMA_START_MASK(m) BIT(m) - -#define CAL_HL_IRQ_OCPO_ERR_MASK BIT(6) - -#define CAL_HL_IRQ_CIO_MASK(i) BIT(16 + (i) * 8) -#define CAL_HL_IRQ_VC_MASK(i) BIT(17 + (i) * 8) - -#define CAL_PIX_PROC_EN_MASK BIT(0) -#define CAL_PIX_PROC_EXTRACT_MASK GENMASK(4, 1) -#define CAL_PIX_PROC_EXTRACT_B6 0x0 -#define CAL_PIX_PROC_EXTRACT_B7 0x1 -#define CAL_PIX_PROC_EXTRACT_B8 0x2 -#define CAL_PIX_PROC_EXTRACT_B10 0x3 -#define CAL_PIX_PROC_EXTRACT_B10_MIPI 0x4 -#define CAL_PIX_PROC_EXTRACT_B12 0x5 -#define CAL_PIX_PROC_EXTRACT_B12_MIPI 0x6 -#define CAL_PIX_PROC_EXTRACT_B14 0x7 -#define CAL_PIX_PROC_EXTRACT_B14_MIPI 0x8 -#define CAL_PIX_PROC_EXTRACT_B16_BE 0x9 -#define CAL_PIX_PROC_EXTRACT_B16_LE 0xa -#define CAL_PIX_PROC_DPCMD_MASK GENMASK(9, 5) -#define CAL_PIX_PROC_DPCMD_BYPASS 0x0 -#define CAL_PIX_PROC_DPCMD_DPCM_10_8_1 0x2 -#define CAL_PIX_PROC_DPCMD_DPCM_12_8_1 0x8 -#define CAL_PIX_PROC_DPCMD_DPCM_10_7_1 0x4 -#define CAL_PIX_PROC_DPCMD_DPCM_10_7_2 0x5 -#define CAL_PIX_PROC_DPCMD_DPCM_10_6_1 0x6 -#define CAL_PIX_PROC_DPCMD_DPCM_10_6_2 0x7 -#define CAL_PIX_PROC_DPCMD_DPCM_12_7_1 0xa -#define CAL_PIX_PROC_DPCMD_DPCM_12_6_1 0xc -#define CAL_PIX_PROC_DPCMD_DPCM_14_10 0xe -#define CAL_PIX_PROC_DPCMD_DPCM_14_8_1 0x10 -#define CAL_PIX_PROC_DPCMD_DPCM_16_12_1 0x12 -#define CAL_PIX_PROC_DPCMD_DPCM_16_10_1 0x14 -#define CAL_PIX_PROC_DPCMD_DPCM_16_8_1 0x16 -#define CAL_PIX_PROC_DPCME_MASK GENMASK(15, 11) -#define CAL_PIX_PROC_DPCME_BYPASS 0x0 -#define CAL_PIX_PROC_DPCME_DPCM_10_8_1 0x2 -#define CAL_PIX_PROC_DPCME_DPCM_12_8_1 0x8 -#define CAL_PIX_PROC_DPCME_DPCM_14_10 0xe -#define CAL_PIX_PROC_DPCME_DPCM_14_8_1 0x10 -#define CAL_PIX_PROC_DPCME_DPCM_16_12_1 0x12 -#define CAL_PIX_PROC_DPCME_DPCM_16_10_1 0x14 -#define CAL_PIX_PROC_DPCME_DPCM_16_8_1 0x16 -#define CAL_PIX_PROC_PACK_MASK GENMASK(18, 16) -#define CAL_PIX_PROC_PACK_B8 0x0 -#define CAL_PIX_PROC_PACK_B10_MIPI 0x2 -#define CAL_PIX_PROC_PACK_B12 0x3 -#define CAL_PIX_PROC_PACK_B12_MIPI 0x4 -#define CAL_PIX_PROC_PACK_B16 0x5 -#define CAL_PIX_PROC_PACK_ARGB 0x6 -#define CAL_PIX_PROC_CPORT_MASK GENMASK(23, 19) - -#define CAL_CTRL_POSTED_WRITES_MASK BIT(0) -#define CAL_CTRL_POSTED_WRITES_NONPOSTED 0 -#define CAL_CTRL_POSTED_WRITES 1 -#define CAL_CTRL_TAGCNT_MASK GENMASK(4, 1) -#define CAL_CTRL_BURSTSIZE_MASK GENMASK(6, 5) -#define CAL_CTRL_BURSTSIZE_BURST16 0x0 -#define CAL_CTRL_BURSTSIZE_BURST32 0x1 -#define CAL_CTRL_BURSTSIZE_BURST64 0x2 -#define CAL_CTRL_BURSTSIZE_BURST128 0x3 -#define CAL_CTRL_LL_FORCE_STATE_MASK GENMASK(12, 7) -#define CAL_CTRL_MFLAGL_MASK GENMASK(20, 13) -#define CAL_CTRL_PWRSCPCLK_MASK BIT(21) -#define CAL_CTRL_PWRSCPCLK_AUTO 0 -#define CAL_CTRL_PWRSCPCLK_FORCE 1 -#define CAL_CTRL_RD_DMA_STALL_MASK BIT(22) -#define CAL_CTRL_MFLAGH_MASK GENMASK(31, 24) - -#define CAL_CTRL1_PPI_GROUPING_MASK GENMASK(1, 0) -#define CAL_CTRL1_PPI_GROUPING_DISABLED 0 -#define CAL_CTRL1_PPI_GROUPING_RESERVED 1 -#define CAL_CTRL1_PPI_GROUPING_0 2 -#define CAL_CTRL1_PPI_GROUPING_1 3 -#define CAL_CTRL1_INTERLEAVE01_MASK GENMASK(3, 2) -#define CAL_CTRL1_INTERLEAVE01_DISABLED 0 -#define CAL_CTRL1_INTERLEAVE01_PIX1 1 -#define CAL_CTRL1_INTERLEAVE01_PIX4 2 -#define CAL_CTRL1_INTERLEAVE01_RESERVED 3 -#define CAL_CTRL1_INTERLEAVE23_MASK GENMASK(5, 4) -#define CAL_CTRL1_INTERLEAVE23_DISABLED 0 -#define CAL_CTRL1_INTERLEAVE23_PIX1 1 -#define CAL_CTRL1_INTERLEAVE23_PIX4 2 -#define CAL_CTRL1_INTERLEAVE23_RESERVED 3 - -#define CAL_LINE_NUMBER_EVT_CPORT_MASK GENMASK(4, 0) -#define CAL_LINE_NUMBER_EVT_MASK GENMASK(29, 16) - -#define CAL_VPORT_CTRL1_PCLK_MASK GENMASK(16, 0) -#define CAL_VPORT_CTRL1_XBLK_MASK GENMASK(24, 17) -#define CAL_VPORT_CTRL1_YBLK_MASK GENMASK(30, 25) -#define CAL_VPORT_CTRL1_WIDTH_MASK BIT(31) -#define CAL_VPORT_CTRL1_WIDTH_ONE 0 -#define CAL_VPORT_CTRL1_WIDTH_TWO 1 - -#define CAL_VPORT_CTRL2_CPORT_MASK GENMASK(4, 0) -#define CAL_VPORT_CTRL2_FREERUNNING_MASK BIT(15) -#define CAL_VPORT_CTRL2_FREERUNNING_GATED 0 -#define CAL_VPORT_CTRL2_FREERUNNING_FREE 1 -#define CAL_VPORT_CTRL2_FS_RESETS_MASK BIT(16) -#define CAL_VPORT_CTRL2_FS_RESETS_NO 0 -#define CAL_VPORT_CTRL2_FS_RESETS_YES 1 -#define CAL_VPORT_CTRL2_FSM_RESET_MASK BIT(17) -#define CAL_VPORT_CTRL2_FSM_RESET_NOEFFECT 0 -#define CAL_VPORT_CTRL2_FSM_RESET 1 -#define CAL_VPORT_CTRL2_RDY_THR_MASK GENMASK(31, 18) - -#define CAL_BYS_CTRL1_PCLK_MASK GENMASK(16, 0) -#define CAL_BYS_CTRL1_XBLK_MASK GENMASK(24, 17) -#define CAL_BYS_CTRL1_YBLK_MASK GENMASK(30, 25) -#define CAL_BYS_CTRL1_BYSINEN_MASK BIT(31) - -#define CAL_BYS_CTRL2_CPORTIN_MASK GENMASK(4, 0) -#define CAL_BYS_CTRL2_CPORTOUT_MASK GENMASK(9, 5) -#define CAL_BYS_CTRL2_DUPLICATEDDATA_MASK BIT(10) -#define CAL_BYS_CTRL2_DUPLICATEDDATA_NO 0 -#define CAL_BYS_CTRL2_DUPLICATEDDATA_YES 1 -#define CAL_BYS_CTRL2_FREERUNNING_MASK BIT(11) -#define CAL_BYS_CTRL2_FREERUNNING_NO 0 -#define CAL_BYS_CTRL2_FREERUNNING_YES 1 - -#define CAL_RD_DMA_CTRL_GO_MASK BIT(0) -#define CAL_RD_DMA_CTRL_GO_DIS 0 -#define CAL_RD_DMA_CTRL_GO_EN 1 -#define CAL_RD_DMA_CTRL_GO_IDLE 0 -#define CAL_RD_DMA_CTRL_GO_BUSY 1 -#define CAL_RD_DMA_CTRL_INIT_MASK BIT(1) -#define CAL_RD_DMA_CTRL_BW_LIMITER_MASK GENMASK(10, 2) -#define CAL_RD_DMA_CTRL_OCP_TAG_CNT_MASK GENMASK(14, 11) -#define CAL_RD_DMA_CTRL_PCLK_MASK GENMASK(31, 15) - -#define CAL_RD_DMA_PIX_ADDR_MASK GENMASK(31, 3) - -#define CAL_RD_DMA_PIX_OFST_MASK GENMASK(31, 4) - -#define CAL_RD_DMA_XSIZE_MASK GENMASK(31, 19) - -#define CAL_RD_DMA_YSIZE_MASK GENMASK(29, 16) - -#define CAL_RD_DMA_INIT_ADDR_MASK GENMASK(31, 3) - -#define CAL_RD_DMA_INIT_OFST_MASK GENMASK(31, 3) - -#define CAL_RD_DMA_CTRL2_CIRC_MODE_MASK GENMASK(2, 0) -#define CAL_RD_DMA_CTRL2_CIRC_MODE_DIS 0 -#define CAL_RD_DMA_CTRL2_CIRC_MODE_ONE 1 -#define CAL_RD_DMA_CTRL2_CIRC_MODE_FOUR 2 -#define CAL_RD_DMA_CTRL2_CIRC_MODE_SIXTEEN 3 -#define CAL_RD_DMA_CTRL2_CIRC_MODE_SIXTYFOUR 4 -#define CAL_RD_DMA_CTRL2_CIRC_MODE_RESERVED 5 -#define CAL_RD_DMA_CTRL2_ICM_CSTART_MASK BIT(3) -#define CAL_RD_DMA_CTRL2_PATTERN_MASK GENMASK(5, 4) -#define CAL_RD_DMA_CTRL2_PATTERN_LINEAR 0 -#define CAL_RD_DMA_CTRL2_PATTERN_YUV420 1 -#define CAL_RD_DMA_CTRL2_PATTERN_RD2SKIP2 2 -#define CAL_RD_DMA_CTRL2_PATTERN_RD2SKIP4 3 -#define CAL_RD_DMA_CTRL2_BYSOUT_LE_WAIT_MASK BIT(6) -#define CAL_RD_DMA_CTRL2_BYSOUT_LE_WAIT_FREERUNNING 0 -#define CAL_RD_DMA_CTRL2_BYSOUT_LE_WAIT_WAITFORBYSOUT 1 -#define CAL_RD_DMA_CTRL2_CIRC_SIZE_MASK GENMASK(29, 16) - -#define CAL_WR_DMA_CTRL_MODE_MASK GENMASK(2, 0) -#define CAL_WR_DMA_CTRL_MODE_DIS 0 -#define CAL_WR_DMA_CTRL_MODE_SHD 1 -#define CAL_WR_DMA_CTRL_MODE_CNT 2 -#define CAL_WR_DMA_CTRL_MODE_CNT_INIT 3 -#define CAL_WR_DMA_CTRL_MODE_CONST 4 -#define CAL_WR_DMA_CTRL_MODE_RESERVED 5 -#define CAL_WR_DMA_CTRL_PATTERN_MASK GENMASK(4, 3) -#define CAL_WR_DMA_CTRL_PATTERN_LINEAR 0 -#define CAL_WR_DMA_CTRL_PATTERN_WR2SKIP2 2 -#define CAL_WR_DMA_CTRL_PATTERN_WR2SKIP4 3 -#define CAL_WR_DMA_CTRL_PATTERN_RESERVED 1 -#define CAL_WR_DMA_CTRL_ICM_PSTART_MASK BIT(5) -#define CAL_WR_DMA_CTRL_DTAG_MASK GENMASK(8, 6) -#define CAL_WR_DMA_CTRL_DTAG_ATT_HDR 0 -#define CAL_WR_DMA_CTRL_DTAG_ATT_DAT 1 -#define CAL_WR_DMA_CTRL_DTAG 2 -#define CAL_WR_DMA_CTRL_DTAG_PIX_HDR 3 -#define CAL_WR_DMA_CTRL_DTAG_PIX_DAT 4 -#define CAL_WR_DMA_CTRL_DTAG_D5 5 -#define CAL_WR_DMA_CTRL_DTAG_D6 6 -#define CAL_WR_DMA_CTRL_DTAG_D7 7 -#define CAL_WR_DMA_CTRL_CPORT_MASK GENMASK(13, 9) -#define CAL_WR_DMA_CTRL_STALL_RD_MASK BIT(14) -#define CAL_WR_DMA_CTRL_YSIZE_MASK GENMASK(31, 18) - -#define CAL_WR_DMA_ADDR_MASK GENMASK(31, 4) - -#define CAL_WR_DMA_OFST_MASK GENMASK(18, 4) -#define CAL_WR_DMA_OFST_CIRC_MODE_MASK GENMASK(23, 22) -#define CAL_WR_DMA_OFST_CIRC_MODE_ONE 1 -#define CAL_WR_DMA_OFST_CIRC_MODE_FOUR 2 -#define CAL_WR_DMA_OFST_CIRC_MODE_SIXTYFOUR 3 -#define CAL_WR_DMA_OFST_CIRC_MODE_DISABLED 0 -#define CAL_WR_DMA_OFST_CIRC_SIZE_MASK GENMASK(31, 24) - -#define CAL_WR_DMA_XSIZE_XSKIP_MASK GENMASK(15, 3) -#define CAL_WR_DMA_XSIZE_MASK GENMASK(31, 19) - -#define CAL_CSI2_PPI_CTRL_IF_EN_MASK BIT(0) -#define CAL_CSI2_PPI_CTRL_ECC_EN_MASK BIT(2) -#define CAL_CSI2_PPI_CTRL_FRAME_MASK BIT(3) -#define CAL_CSI2_PPI_CTRL_FRAME_IMMEDIATE 0 -#define CAL_CSI2_PPI_CTRL_FRAME 1 - -#define CAL_CSI2_COMPLEXIO_CFG_CLOCK_POSITION_MASK GENMASK(2, 0) -#define CAL_CSI2_COMPLEXIO_CFG_POSITION_5 5 -#define CAL_CSI2_COMPLEXIO_CFG_POSITION_4 4 -#define CAL_CSI2_COMPLEXIO_CFG_POSITION_3 3 -#define CAL_CSI2_COMPLEXIO_CFG_POSITION_2 2 -#define CAL_CSI2_COMPLEXIO_CFG_POSITION_1 1 -#define CAL_CSI2_COMPLEXIO_CFG_POSITION_NOT_USED 0 -#define CAL_CSI2_COMPLEXIO_CFG_CLOCK_POL_MASK BIT(3) -#define CAL_CSI2_COMPLEXIO_CFG_POL_PLUSMINUS 0 -#define CAL_CSI2_COMPLEXIO_CFG_POL_MINUSPLUS 1 -#define CAL_CSI2_COMPLEXIO_CFG_DATA1_POSITION_MASK GENMASK(6, 4) -#define CAL_CSI2_COMPLEXIO_CFG_DATA1_POL_MASK BIT(7) -#define CAL_CSI2_COMPLEXIO_CFG_DATA2_POSITION_MASK GENMASK(10, 8) -#define CAL_CSI2_COMPLEXIO_CFG_DATA2_POL_MASK BIT(11) -#define CAL_CSI2_COMPLEXIO_CFG_DATA3_POSITION_MASK GENMASK(14, 12) -#define CAL_CSI2_COMPLEXIO_CFG_DATA3_POL_MASK BIT(15) -#define CAL_CSI2_COMPLEXIO_CFG_DATA4_POSITION_MASK GENMASK(18, 16) -#define CAL_CSI2_COMPLEXIO_CFG_DATA4_POL_MASK BIT(19) -#define CAL_CSI2_COMPLEXIO_CFG_PWR_AUTO_MASK BIT(24) -#define CAL_CSI2_COMPLEXIO_CFG_PWR_STATUS_MASK GENMASK(26, 25) -#define CAL_CSI2_COMPLEXIO_CFG_PWR_STATUS_STATE_OFF 0 -#define CAL_CSI2_COMPLEXIO_CFG_PWR_STATUS_STATE_ON 1 -#define CAL_CSI2_COMPLEXIO_CFG_PWR_STATUS_STATE_ULP 2 -#define CAL_CSI2_COMPLEXIO_CFG_PWR_CMD_MASK GENMASK(28, 27) -#define CAL_CSI2_COMPLEXIO_CFG_PWR_CMD_STATE_OFF 0 -#define CAL_CSI2_COMPLEXIO_CFG_PWR_CMD_STATE_ON 1 -#define CAL_CSI2_COMPLEXIO_CFG_PWR_CMD_STATE_ULP 2 -#define CAL_CSI2_COMPLEXIO_CFG_RESET_DONE_MASK BIT(29) -#define CAL_CSI2_COMPLEXIO_CFG_RESET_DONE_RESETCOMPLETED 1 -#define CAL_CSI2_COMPLEXIO_CFG_RESET_DONE_RESETONGOING 0 -#define CAL_CSI2_COMPLEXIO_CFG_RESET_CTRL_MASK BIT(30) -#define CAL_CSI2_COMPLEXIO_CFG_RESET_CTRL 0 -#define CAL_CSI2_COMPLEXIO_CFG_RESET_CTRL_OPERATIONAL 1 - -#define CAL_CSI2_SHORT_PACKET_MASK GENMASK(23, 0) - -#define CAL_CSI2_COMPLEXIO_IRQ_ERRSOTHS1_MASK BIT(0) -#define CAL_CSI2_COMPLEXIO_IRQ_ERRSOTHS2_MASK BIT(1) -#define CAL_CSI2_COMPLEXIO_IRQ_ERRSOTHS3_MASK BIT(2) -#define CAL_CSI2_COMPLEXIO_IRQ_ERRSOTHS4_MASK BIT(3) -#define CAL_CSI2_COMPLEXIO_IRQ_ERRSOTHS5_MASK BIT(4) -#define CAL_CSI2_COMPLEXIO_IRQ_ERRSOTSYNCHS1_MASK BIT(5) -#define CAL_CSI2_COMPLEXIO_IRQ_ERRSOTSYNCHS2_MASK BIT(6) -#define CAL_CSI2_COMPLEXIO_IRQ_ERRSOTSYNCHS3_MASK BIT(7) -#define CAL_CSI2_COMPLEXIO_IRQ_ERRSOTSYNCHS4_MASK BIT(8) -#define CAL_CSI2_COMPLEXIO_IRQ_ERRSOTSYNCHS5_MASK BIT(9) -#define CAL_CSI2_COMPLEXIO_IRQ_ERRESC1_MASK BIT(10) -#define CAL_CSI2_COMPLEXIO_IRQ_ERRESC2_MASK BIT(11) -#define CAL_CSI2_COMPLEXIO_IRQ_ERRESC3_MASK BIT(12) -#define CAL_CSI2_COMPLEXIO_IRQ_ERRESC4_MASK BIT(13) -#define CAL_CSI2_COMPLEXIO_IRQ_ERRESC5_MASK BIT(14) -#define CAL_CSI2_COMPLEXIO_IRQ_ERRCONTROL1_MASK BIT(15) -#define CAL_CSI2_COMPLEXIO_IRQ_ERRCONTROL2_MASK BIT(16) -#define CAL_CSI2_COMPLEXIO_IRQ_ERRCONTROL3_MASK BIT(17) -#define CAL_CSI2_COMPLEXIO_IRQ_ERRCONTROL4_MASK BIT(18) -#define CAL_CSI2_COMPLEXIO_IRQ_ERRCONTROL5_MASK BIT(19) -#define CAL_CSI2_COMPLEXIO_IRQ_LANE_ERRORS_MASK GENMASK(19, 0) -#define CAL_CSI2_COMPLEXIO_IRQ_STATEULPM1_MASK BIT(20) -#define CAL_CSI2_COMPLEXIO_IRQ_STATEULPM2_MASK BIT(21) -#define CAL_CSI2_COMPLEXIO_IRQ_STATEULPM3_MASK BIT(22) -#define CAL_CSI2_COMPLEXIO_IRQ_STATEULPM4_MASK BIT(23) -#define CAL_CSI2_COMPLEXIO_IRQ_STATEULPM5_MASK BIT(24) -#define CAL_CSI2_COMPLEXIO_IRQ_STATEALLULPMENTER_MASK BIT(25) -#define CAL_CSI2_COMPLEXIO_IRQ_STATEALLULPMEXIT_MASK BIT(26) -#define CAL_CSI2_COMPLEXIO_IRQ_FIFO_OVR_MASK BIT(27) -#define CAL_CSI2_COMPLEXIO_IRQ_SHORT_PACKET_MASK BIT(28) -#define CAL_CSI2_COMPLEXIO_IRQ_ECC_NO_CORRECTION_MASK BIT(30) - -#define CAL_CSI2_TIMING_STOP_STATE_COUNTER_IO1_MASK GENMASK(12, 0) -#define CAL_CSI2_TIMING_STOP_STATE_X4_IO1_MASK BIT(13) -#define CAL_CSI2_TIMING_STOP_STATE_X16_IO1_MASK BIT(14) -#define CAL_CSI2_TIMING_FORCE_RX_MODE_IO1_MASK BIT(15) - -#define CAL_CSI2_VC_IRQ_FS_IRQ_MASK(n) BIT(0 + ((n) * 8)) -#define CAL_CSI2_VC_IRQ_FE_IRQ_MASK(n) BIT(1 + ((n) * 8)) -#define CAL_CSI2_VC_IRQ_LS_IRQ_MASK(n) BIT(2 + ((n) * 8)) -#define CAL_CSI2_VC_IRQ_LE_IRQ_MASK(n) BIT(3 + ((n) * 8)) -#define CAL_CSI2_VC_IRQ_CS_IRQ_MASK(n) BIT(4 + ((n) * 8)) -#define CAL_CSI2_VC_IRQ_ECC_CORRECTION_IRQ_MASK(n) BIT(5 + ((n) * 8)) - -#define CAL_CSI2_CTX_DT_MASK GENMASK(5, 0) -#define CAL_CSI2_CTX_DT_DISABLED 0 -#define CAL_CSI2_CTX_DT_ANY 1 -#define CAL_CSI2_CTX_VC_MASK GENMASK(7, 6) -#define CAL_CSI2_CTX_CPORT_MASK GENMASK(12, 8) -#define CAL_CSI2_CTX_ATT_MASK BIT(13) -#define CAL_CSI2_CTX_ATT_PIX 0 -#define CAL_CSI2_CTX_ATT 1 -#define CAL_CSI2_CTX_PACK_MODE_MASK BIT(14) -#define CAL_CSI2_CTX_PACK_MODE_LINE 0 -#define CAL_CSI2_CTX_PACK_MODE_FRAME 1 -#define CAL_CSI2_CTX_LINES_MASK GENMASK(29, 16) - -#define CAL_CSI2_STATUS_FRAME_MASK GENMASK(15, 0) - -#define CAL_CSI2_PHY_REG0_THS_SETTLE_MASK GENMASK(7, 0) -#define CAL_CSI2_PHY_REG0_THS_TERM_MASK GENMASK(15, 8) -#define CAL_CSI2_PHY_REG0_HSCLOCKCONFIG_MASK BIT(24) -#define CAL_CSI2_PHY_REG0_HSCLOCKCONFIG_DISABLE 1 -#define CAL_CSI2_PHY_REG0_HSCLOCKCONFIG_ENABLE 0 - -#define CAL_CSI2_PHY_REG1_TCLK_SETTLE_MASK GENMASK(7, 0) -#define CAL_CSI2_PHY_REG1_CTRLCLK_DIV_FACTOR_MASK GENMASK(9, 8) -#define CAL_CSI2_PHY_REG1_DPHY_HS_SYNC_PATTERN_MASK GENMASK(17, 10) -#define CAL_CSI2_PHY_REG1_TCLK_TERM_MASK GENMASK(24, 18) -#define CAL_CSI2_PHY_REG1_CLOCK_MISS_DETECTOR_STATUS_MASK BIT(25) -#define CAL_CSI2_PHY_REG1_CLOCK_MISS_DETECTOR_STATUS_ERROR 1 -#define CAL_CSI2_PHY_REG1_CLOCK_MISS_DETECTOR_STATUS_SUCCESS 0 -#define CAL_CSI2_PHY_REG1_RESET_DONE_STATUS_MASK GENMASK(29, 28) - -#define CAL_CSI2_PHY_REG10_I933_LDO_DISABLE_MASK BIT(6) - -#define CAL_CSI2_PHY_REG2_CCP2_SYNC_PATTERN_MASK GENMASK(23, 0) -#define CAL_CSI2_PHY_REG2_TRIGGER_CMD_RXTRIGESC3_MASK GENMASK(25, 24) -#define CAL_CSI2_PHY_REG2_TRIGGER_CMD_RXTRIGESC2_MASK GENMASK(27, 26) -#define CAL_CSI2_PHY_REG2_TRIGGER_CMD_RXTRIGESC1_MASK GENMASK(29, 28) -#define CAL_CSI2_PHY_REG2_TRIGGER_CMD_RXTRIGESC0_MASK GENMASK(31, 30) - -#define CM_CAMERRX_CTRL_CSI1_CTRLCLKEN_MASK BIT(0) -#define CM_CAMERRX_CTRL_CSI1_CAMMODE_MASK GENMASK(2, 1) -#define CM_CAMERRX_CTRL_CSI1_LANEENABLE_MASK GENMASK(4, 3) -#define CM_CAMERRX_CTRL_CSI1_MODE_MASK BIT(5) -#define CM_CAMERRX_CTRL_CSI0_CTRLCLKEN_MASK BIT(10) -#define CM_CAMERRX_CTRL_CSI0_CAMMODE_MASK GENMASK(12, 11) -#define CM_CAMERRX_CTRL_CSI0_LANEENABLE_MASK GENMASK(16, 13) -#define CM_CAMERRX_CTRL_CSI0_MODE_MASK BIT(17) - -#endif diff --git a/drivers/media/platform/ti-vpe/csc.c b/drivers/media/platform/ti-vpe/csc.c deleted file mode 100644 index ff15bc589f1b..000000000000 --- a/drivers/media/platform/ti-vpe/csc.c +++ /dev/null @@ -1,279 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Color space converter library - * - * Copyright (c) 2013 Texas Instruments Inc. - * - * David Griego, - * Dale Farnsworth, - * Archit Taneja, - */ - -#include -#include -#include -#include -#include -#include -#include - -#include "csc.h" - -/* - * 12 coefficients in the order: - * a0, b0, c0, a1, b1, c1, a2, b2, c2, d0, d1, d2 - */ -struct quantization { - u16 coeff[12]; -}; - -struct colorspace { - struct quantization limited; - struct quantization full; -}; - -struct encoding_direction { - struct colorspace r601; - struct colorspace r709; -}; - -struct csc_coeffs { - struct encoding_direction y2r; - struct encoding_direction r2y; -}; - -/* default colorspace coefficients */ -static struct csc_coeffs csc_coeffs = { - .y2r = { - .r601 = { - .limited = { - { /* SDTV */ - 0x0400, 0x0000, 0x057D, 0x0400, 0x1EA7, 0x1D35, - 0x0400, 0x06EF, 0x1FFE, 0x0D40, 0x0210, 0x0C88, - } - }, - .full = { - { /* SDTV */ - 0x04A8, 0x1FFE, 0x0662, 0x04A8, 0x1E6F, 0x1CBF, - 0x04A8, 0x0812, 0x1FFF, 0x0C84, 0x0220, 0x0BAC, - } - }, - }, - .r709 = { - .limited = { - { /* HDTV */ - 0x0400, 0x0000, 0x0629, 0x0400, 0x1F45, 0x1E2B, - 0x0400, 0x0742, 0x0000, 0x0CEC, 0x0148, 0x0C60, - } - }, - .full = { - { /* HDTV */ - 0x04A8, 0x0000, 0x072C, 0x04A8, 0x1F26, 0x1DDE, - 0x04A8, 0x0873, 0x0000, 0x0C20, 0x0134, 0x0B7C, - } - }, - }, - }, - .r2y = { - .r601 = { - .limited = { - { /* SDTV */ - 0x0132, 0x0259, 0x0075, 0x1F50, 0x1EA5, 0x020B, - 0x020B, 0x1E4A, 0x1FAB, 0x0000, 0x0200, 0x0200, - } - }, - .full = { - { /* SDTV */ - 0x0107, 0x0204, 0x0064, 0x1F68, 0x1ED6, 0x01C2, - 0x01C2, 0x1E87, 0x1FB7, 0x0040, 0x0200, 0x0200, - } - }, - }, - .r709 = { - .limited = { - { /* HDTV */ - 0x00DA, 0x02DC, 0x004A, 0x1F88, 0x1E6C, 0x020C, - 0x020C, 0x1E24, 0x1FD0, 0x0000, 0x0200, 0x0200, - } - }, - .full = { - { /* HDTV */ - 0x00bb, 0x0275, 0x003f, 0x1f99, 0x1ea5, 0x01c2, - 0x01c2, 0x1e67, 0x1fd7, 0x0040, 0x0200, 0x0200, - } - }, - }, - }, - -}; - -void csc_dump_regs(struct csc_data *csc) -{ - struct device *dev = &csc->pdev->dev; - -#define DUMPREG(r) dev_dbg(dev, "%-35s %08x\n", #r, \ - ioread32(csc->base + CSC_##r)) - - dev_dbg(dev, "CSC Registers @ %pa:\n", &csc->res->start); - - DUMPREG(CSC00); - DUMPREG(CSC01); - DUMPREG(CSC02); - DUMPREG(CSC03); - DUMPREG(CSC04); - DUMPREG(CSC05); - -#undef DUMPREG -} -EXPORT_SYMBOL(csc_dump_regs); - -void csc_set_coeff_bypass(struct csc_data *csc, u32 *csc_reg5) -{ - *csc_reg5 |= CSC_BYPASS; -} -EXPORT_SYMBOL(csc_set_coeff_bypass); - -/* - * set the color space converter coefficient shadow register values - */ -void csc_set_coeff(struct csc_data *csc, u32 *csc_reg0, - struct v4l2_format *src_fmt, struct v4l2_format *dst_fmt) -{ - u32 *csc_reg5 = csc_reg0 + 5; - u32 *shadow_csc = csc_reg0; - u16 *coeff, *end_coeff; - const struct v4l2_pix_format *pix; - const struct v4l2_pix_format_mplane *mp; - const struct v4l2_format_info *src_finfo, *dst_finfo; - enum v4l2_ycbcr_encoding src_ycbcr_enc, dst_ycbcr_enc; - enum v4l2_quantization src_quantization, dst_quantization; - u32 src_pixelformat, dst_pixelformat; - - if (V4L2_TYPE_IS_MULTIPLANAR(src_fmt->type)) { - mp = &src_fmt->fmt.pix_mp; - src_pixelformat = mp->pixelformat; - src_ycbcr_enc = mp->ycbcr_enc; - src_quantization = mp->quantization; - } else { - pix = &src_fmt->fmt.pix; - src_pixelformat = pix->pixelformat; - src_ycbcr_enc = pix->ycbcr_enc; - src_quantization = pix->quantization; - } - - if (V4L2_TYPE_IS_MULTIPLANAR(dst_fmt->type)) { - mp = &dst_fmt->fmt.pix_mp; - dst_pixelformat = mp->pixelformat; - dst_ycbcr_enc = mp->ycbcr_enc; - dst_quantization = mp->quantization; - } else { - pix = &dst_fmt->fmt.pix; - dst_pixelformat = pix->pixelformat; - dst_ycbcr_enc = pix->ycbcr_enc; - dst_quantization = pix->quantization; - } - - src_finfo = v4l2_format_info(src_pixelformat); - dst_finfo = v4l2_format_info(dst_pixelformat); - - if (v4l2_is_format_yuv(src_finfo) && - v4l2_is_format_rgb(dst_finfo)) { - /* Y2R */ - - /* - * These are not the standard default values but are - * set this way for historical compatibility - */ - if (src_ycbcr_enc == V4L2_YCBCR_ENC_DEFAULT) - src_ycbcr_enc = V4L2_YCBCR_ENC_601; - - if (src_quantization == V4L2_QUANTIZATION_DEFAULT) - src_quantization = V4L2_QUANTIZATION_FULL_RANGE; - - if (src_ycbcr_enc == V4L2_YCBCR_ENC_601) { - if (src_quantization == V4L2_QUANTIZATION_FULL_RANGE) - coeff = csc_coeffs.y2r.r601.full.coeff; - else - coeff = csc_coeffs.y2r.r601.limited.coeff; - } else if (src_ycbcr_enc == V4L2_YCBCR_ENC_709) { - if (src_quantization == V4L2_QUANTIZATION_FULL_RANGE) - coeff = csc_coeffs.y2r.r709.full.coeff; - else - coeff = csc_coeffs.y2r.r709.limited.coeff; - } else { - /* Should never reach this, but it keeps gcc happy */ - coeff = csc_coeffs.y2r.r601.full.coeff; - } - } else if (v4l2_is_format_rgb(src_finfo) && - v4l2_is_format_yuv(dst_finfo)) { - /* R2Y */ - - /* - * These are not the standard default values but are - * set this way for historical compatibility - */ - if (dst_ycbcr_enc == V4L2_YCBCR_ENC_DEFAULT) - dst_ycbcr_enc = V4L2_YCBCR_ENC_601; - - if (dst_quantization == V4L2_QUANTIZATION_DEFAULT) - dst_quantization = V4L2_QUANTIZATION_FULL_RANGE; - - if (dst_ycbcr_enc == V4L2_YCBCR_ENC_601) { - if (dst_quantization == V4L2_QUANTIZATION_FULL_RANGE) - coeff = csc_coeffs.r2y.r601.full.coeff; - else - coeff = csc_coeffs.r2y.r601.limited.coeff; - } else if (dst_ycbcr_enc == V4L2_YCBCR_ENC_709) { - if (dst_quantization == V4L2_QUANTIZATION_FULL_RANGE) - coeff = csc_coeffs.r2y.r709.full.coeff; - else - coeff = csc_coeffs.r2y.r709.limited.coeff; - } else { - /* Should never reach this, but it keeps gcc happy */ - coeff = csc_coeffs.r2y.r601.full.coeff; - } - } else { - *csc_reg5 |= CSC_BYPASS; - return; - } - - end_coeff = coeff + 12; - - for (; coeff < end_coeff; coeff += 2) - *shadow_csc++ = (*(coeff + 1) << 16) | *coeff; -} -EXPORT_SYMBOL(csc_set_coeff); - -struct csc_data *csc_create(struct platform_device *pdev, const char *res_name) -{ - struct csc_data *csc; - - dev_dbg(&pdev->dev, "csc_create\n"); - - csc = devm_kzalloc(&pdev->dev, sizeof(*csc), GFP_KERNEL); - if (!csc) { - dev_err(&pdev->dev, "couldn't alloc csc_data\n"); - return ERR_PTR(-ENOMEM); - } - - csc->pdev = pdev; - - csc->res = platform_get_resource_byname(pdev, IORESOURCE_MEM, - res_name); - if (csc->res == NULL) { - dev_err(&pdev->dev, "missing '%s' platform resources data\n", - res_name); - return ERR_PTR(-ENODEV); - } - - csc->base = devm_ioremap_resource(&pdev->dev, csc->res); - if (IS_ERR(csc->base)) - return ERR_CAST(csc->base); - - return csc; -} -EXPORT_SYMBOL(csc_create); - -MODULE_DESCRIPTION("TI VIP/VPE Color Space Converter"); -MODULE_AUTHOR("Texas Instruments Inc."); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/platform/ti-vpe/csc.h b/drivers/media/platform/ti-vpe/csc.h deleted file mode 100644 index af2e86bccf57..000000000000 --- a/drivers/media/platform/ti-vpe/csc.h +++ /dev/null @@ -1,65 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * Copyright (c) 2013 Texas Instruments Inc. - * - * David Griego, - * Dale Farnsworth, - * Archit Taneja, - */ -#ifndef TI_CSC_H -#define TI_CSC_H - -/* VPE color space converter regs */ -#define CSC_CSC00 0x00 -#define CSC_A0_MASK 0x1fff -#define CSC_A0_SHIFT 0 -#define CSC_B0_MASK 0x1fff -#define CSC_B0_SHIFT 16 - -#define CSC_CSC01 0x04 -#define CSC_C0_MASK 0x1fff -#define CSC_C0_SHIFT 0 -#define CSC_A1_MASK 0x1fff -#define CSC_A1_SHIFT 16 - -#define CSC_CSC02 0x08 -#define CSC_B1_MASK 0x1fff -#define CSC_B1_SHIFT 0 -#define CSC_C1_MASK 0x1fff -#define CSC_C1_SHIFT 16 - -#define CSC_CSC03 0x0c -#define CSC_A2_MASK 0x1fff -#define CSC_A2_SHIFT 0 -#define CSC_B2_MASK 0x1fff -#define CSC_B2_SHIFT 16 - -#define CSC_CSC04 0x10 -#define CSC_C2_MASK 0x1fff -#define CSC_C2_SHIFT 0 -#define CSC_D0_MASK 0x0fff -#define CSC_D0_SHIFT 16 - -#define CSC_CSC05 0x14 -#define CSC_D1_MASK 0x0fff -#define CSC_D1_SHIFT 0 -#define CSC_D2_MASK 0x0fff -#define CSC_D2_SHIFT 16 - -#define CSC_BYPASS (1 << 28) - -struct csc_data { - void __iomem *base; - struct resource *res; - - struct platform_device *pdev; -}; - -void csc_dump_regs(struct csc_data *csc); -void csc_set_coeff_bypass(struct csc_data *csc, u32 *csc_reg5); -void csc_set_coeff(struct csc_data *csc, u32 *csc_reg0, - struct v4l2_format *src_fmt, struct v4l2_format *dst_fmt); - -struct csc_data *csc_create(struct platform_device *pdev, const char *res_name); - -#endif diff --git a/drivers/media/platform/ti-vpe/sc.c b/drivers/media/platform/ti-vpe/sc.c deleted file mode 100644 index 0202d278523f..000000000000 --- a/drivers/media/platform/ti-vpe/sc.c +++ /dev/null @@ -1,306 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Scaler library - * - * Copyright (c) 2013 Texas Instruments Inc. - * - * David Griego, - * Dale Farnsworth, - * Archit Taneja, - */ - -#include -#include -#include -#include -#include - -#include "sc.h" -#include "sc_coeff.h" - -void sc_dump_regs(struct sc_data *sc) -{ - struct device *dev = &sc->pdev->dev; - -#define DUMPREG(r) dev_dbg(dev, "%-35s %08x\n", #r, \ - ioread32(sc->base + CFG_##r)) - - dev_dbg(dev, "SC Registers @ %pa:\n", &sc->res->start); - - DUMPREG(SC0); - DUMPREG(SC1); - DUMPREG(SC2); - DUMPREG(SC3); - DUMPREG(SC4); - DUMPREG(SC5); - DUMPREG(SC6); - DUMPREG(SC8); - DUMPREG(SC9); - DUMPREG(SC10); - DUMPREG(SC11); - DUMPREG(SC12); - DUMPREG(SC13); - DUMPREG(SC17); - DUMPREG(SC18); - DUMPREG(SC19); - DUMPREG(SC20); - DUMPREG(SC21); - DUMPREG(SC22); - DUMPREG(SC23); - DUMPREG(SC24); - DUMPREG(SC25); - -#undef DUMPREG -} -EXPORT_SYMBOL(sc_dump_regs); - -/* - * set the horizontal scaler coefficients according to the ratio of output to - * input widths, after accounting for up to two levels of decimation - */ -void sc_set_hs_coeffs(struct sc_data *sc, void *addr, unsigned int src_w, - unsigned int dst_w) -{ - int sixteenths; - int idx; - int i, j; - u16 *coeff_h = addr; - const u16 *cp; - - if (dst_w > src_w) { - idx = HS_UP_SCALE; - } else { - if ((dst_w << 1) < src_w) - dst_w <<= 1; /* first level decimation */ - if ((dst_w << 1) < src_w) - dst_w <<= 1; /* second level decimation */ - - if (dst_w == src_w) { - idx = HS_LE_16_16_SCALE; - } else { - sixteenths = (dst_w << 4) / src_w; - if (sixteenths < 8) - sixteenths = 8; - idx = HS_LT_9_16_SCALE + sixteenths - 8; - } - } - - cp = scaler_hs_coeffs[idx]; - - for (i = 0; i < SC_NUM_PHASES * 2; i++) { - for (j = 0; j < SC_H_NUM_TAPS; j++) - *coeff_h++ = *cp++; - /* - * for each phase, the scaler expects space for 8 coefficients - * in it's memory. For the horizontal scaler, we copy the first - * 7 coefficients and skip the last slot to move to the next - * row to hold coefficients for the next phase - */ - coeff_h += SC_NUM_TAPS_MEM_ALIGN - SC_H_NUM_TAPS; - } - - sc->load_coeff_h = true; -} -EXPORT_SYMBOL(sc_set_hs_coeffs); - -/* - * set the vertical scaler coefficients according to the ratio of output to - * input heights - */ -void sc_set_vs_coeffs(struct sc_data *sc, void *addr, unsigned int src_h, - unsigned int dst_h) -{ - int sixteenths; - int idx; - int i, j; - u16 *coeff_v = addr; - const u16 *cp; - - if (dst_h > src_h) { - idx = VS_UP_SCALE; - } else if (dst_h == src_h) { - idx = VS_1_TO_1_SCALE; - } else { - sixteenths = (dst_h << 4) / src_h; - if (sixteenths < 8) - sixteenths = 8; - idx = VS_LT_9_16_SCALE + sixteenths - 8; - } - - cp = scaler_vs_coeffs[idx]; - - for (i = 0; i < SC_NUM_PHASES * 2; i++) { - for (j = 0; j < SC_V_NUM_TAPS; j++) - *coeff_v++ = *cp++; - /* - * for the vertical scaler, we copy the first 5 coefficients and - * skip the last 3 slots to move to the next row to hold - * coefficients for the next phase - */ - coeff_v += SC_NUM_TAPS_MEM_ALIGN - SC_V_NUM_TAPS; - } - - sc->load_coeff_v = true; -} -EXPORT_SYMBOL(sc_set_vs_coeffs); - -void sc_config_scaler(struct sc_data *sc, u32 *sc_reg0, u32 *sc_reg8, - u32 *sc_reg17, unsigned int src_w, unsigned int src_h, - unsigned int dst_w, unsigned int dst_h) -{ - struct device *dev = &sc->pdev->dev; - u32 val; - int dcm_x, dcm_shift; - bool use_rav; - unsigned long lltmp; - u32 lin_acc_inc, lin_acc_inc_u; - u32 col_acc_offset; - u16 factor = 0; - int row_acc_init_rav = 0, row_acc_init_rav_b = 0; - u32 row_acc_inc = 0, row_acc_offset = 0, row_acc_offset_b = 0; - /* - * location of SC register in payload memory with respect to the first - * register in the mmr address data block - */ - u32 *sc_reg9 = sc_reg8 + 1; - u32 *sc_reg12 = sc_reg8 + 4; - u32 *sc_reg13 = sc_reg8 + 5; - u32 *sc_reg24 = sc_reg17 + 7; - - val = sc_reg0[0]; - - /* clear all the features(they may get enabled elsewhere later) */ - val &= ~(CFG_SELFGEN_FID | CFG_TRIM | CFG_ENABLE_SIN2_VER_INTP | - CFG_INTERLACE_I | CFG_DCM_4X | CFG_DCM_2X | CFG_AUTO_HS | - CFG_ENABLE_EV | CFG_USE_RAV | CFG_INVT_FID | CFG_SC_BYPASS | - CFG_INTERLACE_O | CFG_Y_PK_EN | CFG_HP_BYPASS | CFG_LINEAR); - - if (src_w == dst_w && src_h == dst_h) { - val |= CFG_SC_BYPASS; - sc_reg0[0] = val; - return; - } - - /* we only support linear scaling for now */ - val |= CFG_LINEAR; - - /* configure horizontal scaler */ - - /* enable 2X or 4X decimation */ - dcm_x = src_w / dst_w; - if (dcm_x > 4) { - val |= CFG_DCM_4X; - dcm_shift = 2; - } else if (dcm_x > 2) { - val |= CFG_DCM_2X; - dcm_shift = 1; - } else { - dcm_shift = 0; - } - - lltmp = dst_w - 1; - lin_acc_inc = div64_u64(((u64)(src_w >> dcm_shift) - 1) << 24, lltmp); - lin_acc_inc_u = 0; - col_acc_offset = 0; - - dev_dbg(dev, "hs config: src_w = %d, dst_w = %d, decimation = %s, lin_acc_inc = %08x\n", - src_w, dst_w, dcm_shift == 2 ? "4x" : - (dcm_shift == 1 ? "2x" : "none"), lin_acc_inc); - - /* configure vertical scaler */ - - /* use RAV for vertical scaler if vertical downscaling is > 4x */ - if (dst_h < (src_h >> 2)) { - use_rav = true; - val |= CFG_USE_RAV; - } else { - use_rav = false; - } - - if (use_rav) { - /* use RAV */ - factor = (u16) ((dst_h << 10) / src_h); - - row_acc_init_rav = factor + ((1 + factor) >> 1); - if (row_acc_init_rav >= 1024) - row_acc_init_rav -= 1024; - - row_acc_init_rav_b = row_acc_init_rav + - (1 + (row_acc_init_rav >> 1)) - - (1024 >> 1); - - if (row_acc_init_rav_b < 0) { - row_acc_init_rav_b += row_acc_init_rav; - row_acc_init_rav *= 2; - } - - dev_dbg(dev, "vs config(RAV): src_h = %d, dst_h = %d, factor = %d, acc_init = %08x, acc_init_b = %08x\n", - src_h, dst_h, factor, row_acc_init_rav, - row_acc_init_rav_b); - } else { - /* use polyphase */ - row_acc_inc = ((src_h - 1) << 16) / (dst_h - 1); - row_acc_offset = 0; - row_acc_offset_b = 0; - - dev_dbg(dev, "vs config(POLY): src_h = %d, dst_h = %d,row_acc_inc = %08x\n", - src_h, dst_h, row_acc_inc); - } - - - sc_reg0[0] = val; - sc_reg0[1] = row_acc_inc; - sc_reg0[2] = row_acc_offset; - sc_reg0[3] = row_acc_offset_b; - - sc_reg0[4] = ((lin_acc_inc_u & CFG_LIN_ACC_INC_U_MASK) << - CFG_LIN_ACC_INC_U_SHIFT) | (dst_w << CFG_TAR_W_SHIFT) | - (dst_h << CFG_TAR_H_SHIFT); - - sc_reg0[5] = (src_w << CFG_SRC_W_SHIFT) | (src_h << CFG_SRC_H_SHIFT); - - sc_reg0[6] = (row_acc_init_rav_b << CFG_ROW_ACC_INIT_RAV_B_SHIFT) | - (row_acc_init_rav << CFG_ROW_ACC_INIT_RAV_SHIFT); - - *sc_reg9 = lin_acc_inc; - - *sc_reg12 = col_acc_offset << CFG_COL_ACC_OFFSET_SHIFT; - - *sc_reg13 = factor; - - *sc_reg24 = (src_w << CFG_ORG_W_SHIFT) | (src_h << CFG_ORG_H_SHIFT); -} -EXPORT_SYMBOL(sc_config_scaler); - -struct sc_data *sc_create(struct platform_device *pdev, const char *res_name) -{ - struct sc_data *sc; - - dev_dbg(&pdev->dev, "sc_create\n"); - - sc = devm_kzalloc(&pdev->dev, sizeof(*sc), GFP_KERNEL); - if (!sc) { - dev_err(&pdev->dev, "couldn't alloc sc_data\n"); - return ERR_PTR(-ENOMEM); - } - - sc->pdev = pdev; - - sc->res = platform_get_resource_byname(pdev, IORESOURCE_MEM, res_name); - if (!sc->res) { - dev_err(&pdev->dev, "missing '%s' platform resources data\n", - res_name); - return ERR_PTR(-ENODEV); - } - - sc->base = devm_ioremap_resource(&pdev->dev, sc->res); - if (IS_ERR(sc->base)) - return ERR_CAST(sc->base); - - return sc; -} -EXPORT_SYMBOL(sc_create); - -MODULE_DESCRIPTION("TI VIP/VPE Scaler"); -MODULE_AUTHOR("Texas Instruments Inc."); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/platform/ti-vpe/sc.h b/drivers/media/platform/ti-vpe/sc.h deleted file mode 100644 index d55de44d5257..000000000000 --- a/drivers/media/platform/ti-vpe/sc.h +++ /dev/null @@ -1,208 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * Copyright (c) 2013 Texas Instruments Inc. - * - * David Griego, - * Dale Farnsworth, - * Archit Taneja, - */ -#ifndef TI_SC_H -#define TI_SC_H - -/* Scaler regs */ -#define CFG_SC0 0x0 -#define CFG_INTERLACE_O (1 << 0) -#define CFG_LINEAR (1 << 1) -#define CFG_SC_BYPASS (1 << 2) -#define CFG_INVT_FID (1 << 3) -#define CFG_USE_RAV (1 << 4) -#define CFG_ENABLE_EV (1 << 5) -#define CFG_AUTO_HS (1 << 6) -#define CFG_DCM_2X (1 << 7) -#define CFG_DCM_4X (1 << 8) -#define CFG_HP_BYPASS (1 << 9) -#define CFG_INTERLACE_I (1 << 10) -#define CFG_ENABLE_SIN2_VER_INTP (1 << 11) -#define CFG_Y_PK_EN (1 << 14) -#define CFG_TRIM (1 << 15) -#define CFG_SELFGEN_FID (1 << 16) - -#define CFG_SC1 0x4 -#define CFG_ROW_ACC_INC_MASK 0x07ffffff -#define CFG_ROW_ACC_INC_SHIFT 0 - -#define CFG_SC2 0x08 -#define CFG_ROW_ACC_OFFSET_MASK 0x0fffffff -#define CFG_ROW_ACC_OFFSET_SHIFT 0 - -#define CFG_SC3 0x0c -#define CFG_ROW_ACC_OFFSET_B_MASK 0x0fffffff -#define CFG_ROW_ACC_OFFSET_B_SHIFT 0 - -#define CFG_SC4 0x10 -#define CFG_TAR_H_MASK 0x07ff -#define CFG_TAR_H_SHIFT 0 -#define CFG_TAR_W_MASK 0x07ff -#define CFG_TAR_W_SHIFT 12 -#define CFG_LIN_ACC_INC_U_MASK 0x07 -#define CFG_LIN_ACC_INC_U_SHIFT 24 -#define CFG_NLIN_ACC_INIT_U_MASK 0x07 -#define CFG_NLIN_ACC_INIT_U_SHIFT 28 - -#define CFG_SC5 0x14 -#define CFG_SRC_H_MASK 0x07ff -#define CFG_SRC_H_SHIFT 0 -#define CFG_SRC_W_MASK 0x07ff -#define CFG_SRC_W_SHIFT 12 -#define CFG_NLIN_ACC_INC_U_MASK 0x07 -#define CFG_NLIN_ACC_INC_U_SHIFT 24 - -#define CFG_SC6 0x18 -#define CFG_ROW_ACC_INIT_RAV_MASK 0x03ff -#define CFG_ROW_ACC_INIT_RAV_SHIFT 0 -#define CFG_ROW_ACC_INIT_RAV_B_MASK 0x03ff -#define CFG_ROW_ACC_INIT_RAV_B_SHIFT 10 - -#define CFG_SC8 0x20 -#define CFG_NLIN_LEFT_MASK 0x07ff -#define CFG_NLIN_LEFT_SHIFT 0 -#define CFG_NLIN_RIGHT_MASK 0x07ff -#define CFG_NLIN_RIGHT_SHIFT 12 - -#define CFG_SC9 0x24 -#define CFG_LIN_ACC_INC CFG_SC9 - -#define CFG_SC10 0x28 -#define CFG_NLIN_ACC_INIT CFG_SC10 - -#define CFG_SC11 0x2c -#define CFG_NLIN_ACC_INC CFG_SC11 - -#define CFG_SC12 0x30 -#define CFG_COL_ACC_OFFSET_MASK 0x01ffffff -#define CFG_COL_ACC_OFFSET_SHIFT 0 - -#define CFG_SC13 0x34 -#define CFG_SC_FACTOR_RAV_MASK 0xff -#define CFG_SC_FACTOR_RAV_SHIFT 0 -#define CFG_CHROMA_INTP_THR_MASK 0x03ff -#define CFG_CHROMA_INTP_THR_SHIFT 12 -#define CFG_DELTA_CHROMA_THR_MASK 0x0f -#define CFG_DELTA_CHROMA_THR_SHIFT 24 - -#define CFG_SC17 0x44 -#define CFG_EV_THR_MASK 0x03ff -#define CFG_EV_THR_SHIFT 12 -#define CFG_DELTA_LUMA_THR_MASK 0x0f -#define CFG_DELTA_LUMA_THR_SHIFT 24 -#define CFG_DELTA_EV_THR_MASK 0x0f -#define CFG_DELTA_EV_THR_SHIFT 28 - -#define CFG_SC18 0x48 -#define CFG_HS_FACTOR_MASK 0x03ff -#define CFG_HS_FACTOR_SHIFT 0 -#define CFG_CONF_DEFAULT_MASK 0x01ff -#define CFG_CONF_DEFAULT_SHIFT 16 - -#define CFG_SC19 0x4c -#define CFG_HPF_COEFF0_MASK 0xff -#define CFG_HPF_COEFF0_SHIFT 0 -#define CFG_HPF_COEFF1_MASK 0xff -#define CFG_HPF_COEFF1_SHIFT 8 -#define CFG_HPF_COEFF2_MASK 0xff -#define CFG_HPF_COEFF2_SHIFT 16 -#define CFG_HPF_COEFF3_MASK 0xff -#define CFG_HPF_COEFF3_SHIFT 23 - -#define CFG_SC20 0x50 -#define CFG_HPF_COEFF4_MASK 0xff -#define CFG_HPF_COEFF4_SHIFT 0 -#define CFG_HPF_COEFF5_MASK 0xff -#define CFG_HPF_COEFF5_SHIFT 8 -#define CFG_HPF_NORM_SHIFT_MASK 0x07 -#define CFG_HPF_NORM_SHIFT_SHIFT 16 -#define CFG_NL_LIMIT_MASK 0x1ff -#define CFG_NL_LIMIT_SHIFT 20 - -#define CFG_SC21 0x54 -#define CFG_NL_LO_THR_MASK 0x01ff -#define CFG_NL_LO_THR_SHIFT 0 -#define CFG_NL_LO_SLOPE_MASK 0xff -#define CFG_NL_LO_SLOPE_SHIFT 16 - -#define CFG_SC22 0x58 -#define CFG_NL_HI_THR_MASK 0x01ff -#define CFG_NL_HI_THR_SHIFT 0 -#define CFG_NL_HI_SLOPE_SH_MASK 0x07 -#define CFG_NL_HI_SLOPE_SH_SHIFT 16 - -#define CFG_SC23 0x5c -#define CFG_GRADIENT_THR_MASK 0x07ff -#define CFG_GRADIENT_THR_SHIFT 0 -#define CFG_GRADIENT_THR_RANGE_MASK 0x0f -#define CFG_GRADIENT_THR_RANGE_SHIFT 12 -#define CFG_MIN_GY_THR_MASK 0xff -#define CFG_MIN_GY_THR_SHIFT 16 -#define CFG_MIN_GY_THR_RANGE_MASK 0x0f -#define CFG_MIN_GY_THR_RANGE_SHIFT 28 - -#define CFG_SC24 0x60 -#define CFG_ORG_H_MASK 0x07ff -#define CFG_ORG_H_SHIFT 0 -#define CFG_ORG_W_MASK 0x07ff -#define CFG_ORG_W_SHIFT 16 - -#define CFG_SC25 0x64 -#define CFG_OFF_H_MASK 0x07ff -#define CFG_OFF_H_SHIFT 0 -#define CFG_OFF_W_MASK 0x07ff -#define CFG_OFF_W_SHIFT 16 - -/* number of phases supported by the polyphase scalers */ -#define SC_NUM_PHASES 32 - -/* number of taps used by horizontal polyphase scaler */ -#define SC_H_NUM_TAPS 7 - -/* number of taps used by vertical polyphase scaler */ -#define SC_V_NUM_TAPS 5 - -/* number of taps expected by the scaler in it's coefficient memory */ -#define SC_NUM_TAPS_MEM_ALIGN 8 - -/* Maximum frame width the scaler can handle (in pixels) */ -#define SC_MAX_PIXEL_WIDTH 2047 - -/* Maximum frame height the scaler can handle (in lines) */ -#define SC_MAX_PIXEL_HEIGHT 2047 - -/* - * coefficient memory size in bytes: - * num phases x num sets(luma and chroma) x num taps(aligned) x coeff size - */ -#define SC_COEF_SRAM_SIZE (SC_NUM_PHASES * 2 * SC_NUM_TAPS_MEM_ALIGN * 2) - -struct sc_data { - void __iomem *base; - struct resource *res; - - dma_addr_t loaded_coeff_h; /* loaded h coeffs in SC */ - dma_addr_t loaded_coeff_v; /* loaded v coeffs in SC */ - - bool load_coeff_h; /* have new h SC coeffs */ - bool load_coeff_v; /* have new v SC coeffs */ - - struct platform_device *pdev; -}; - -void sc_dump_regs(struct sc_data *sc); -void sc_set_hs_coeffs(struct sc_data *sc, void *addr, unsigned int src_w, - unsigned int dst_w); -void sc_set_vs_coeffs(struct sc_data *sc, void *addr, unsigned int src_h, - unsigned int dst_h); -void sc_config_scaler(struct sc_data *sc, u32 *sc_reg0, u32 *sc_reg8, - u32 *sc_reg17, unsigned int src_w, unsigned int src_h, - unsigned int dst_w, unsigned int dst_h); -struct sc_data *sc_create(struct platform_device *pdev, const char *res_name); - -#endif diff --git a/drivers/media/platform/ti-vpe/sc_coeff.h b/drivers/media/platform/ti-vpe/sc_coeff.h deleted file mode 100644 index c525d1764099..000000000000 --- a/drivers/media/platform/ti-vpe/sc_coeff.h +++ /dev/null @@ -1,1339 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * VPE SC coefs - * - * Copyright (c) 2013 Texas Instruments Inc. - * - * David Griego, - * Dale Farnsworth, - * Archit Taneja, - */ - -#ifndef __TI_SC_COEFF_H -#define __TI_SC_COEFF_H - -/* horizontal scaler coefficients */ -enum { - HS_UP_SCALE = 0, - HS_LT_9_16_SCALE, - HS_LT_10_16_SCALE, - HS_LT_11_16_SCALE, - HS_LT_12_16_SCALE, - HS_LT_13_16_SCALE, - HS_LT_14_16_SCALE, - HS_LT_15_16_SCALE, - HS_LE_16_16_SCALE, -}; - -static const u16 scaler_hs_coeffs[13][SC_NUM_PHASES * 2 * SC_H_NUM_TAPS] = { - [HS_UP_SCALE] = { - /* Luma */ - 0x001F, 0x1F90, 0x00D2, 0x06FE, 0x00D2, 0x1F90, 0x001F, - 0x001C, 0x1F9E, 0x009F, 0x06FB, 0x0108, 0x1F82, 0x0022, - 0x0019, 0x1FAC, 0x006F, 0x06F3, 0x0140, 0x1F74, 0x0025, - 0x0016, 0x1FB9, 0x0041, 0x06E7, 0x017B, 0x1F66, 0x0028, - 0x0013, 0x1FC6, 0x0017, 0x06D6, 0x01B7, 0x1F58, 0x002B, - 0x0010, 0x1FD3, 0x1FEF, 0x06C0, 0x01F6, 0x1F4B, 0x002D, - 0x000E, 0x1FDF, 0x1FCB, 0x06A5, 0x0235, 0x1F3F, 0x002F, - 0x000B, 0x1FEA, 0x1FAA, 0x0686, 0x0277, 0x1F33, 0x0031, - 0x0009, 0x1FF5, 0x1F8C, 0x0663, 0x02B8, 0x1F28, 0x0033, - 0x0007, 0x1FFF, 0x1F72, 0x063A, 0x02FB, 0x1F1F, 0x0034, - 0x0005, 0x0008, 0x1F5A, 0x060F, 0x033E, 0x1F17, 0x0035, - 0x0003, 0x0010, 0x1F46, 0x05E0, 0x0382, 0x1F10, 0x0035, - 0x0002, 0x0017, 0x1F34, 0x05AF, 0x03C5, 0x1F0B, 0x0034, - 0x0001, 0x001E, 0x1F26, 0x0579, 0x0407, 0x1F08, 0x0033, - 0x0000, 0x0023, 0x1F1A, 0x0541, 0x0449, 0x1F07, 0x0032, - 0x1FFF, 0x0028, 0x1F12, 0x0506, 0x048A, 0x1F08, 0x002F, - 0x002C, 0x1F0C, 0x04C8, 0x04C8, 0x1F0C, 0x002C, 0x0000, - 0x002F, 0x1F08, 0x048A, 0x0506, 0x1F12, 0x0028, 0x1FFF, - 0x0032, 0x1F07, 0x0449, 0x0541, 0x1F1A, 0x0023, 0x0000, - 0x0033, 0x1F08, 0x0407, 0x0579, 0x1F26, 0x001E, 0x0001, - 0x0034, 0x1F0B, 0x03C5, 0x05AF, 0x1F34, 0x0017, 0x0002, - 0x0035, 0x1F10, 0x0382, 0x05E0, 0x1F46, 0x0010, 0x0003, - 0x0035, 0x1F17, 0x033E, 0x060F, 0x1F5A, 0x0008, 0x0005, - 0x0034, 0x1F1F, 0x02FB, 0x063A, 0x1F72, 0x1FFF, 0x0007, - 0x0033, 0x1F28, 0x02B8, 0x0663, 0x1F8C, 0x1FF5, 0x0009, - 0x0031, 0x1F33, 0x0277, 0x0686, 0x1FAA, 0x1FEA, 0x000B, - 0x002F, 0x1F3F, 0x0235, 0x06A5, 0x1FCB, 0x1FDF, 0x000E, - 0x002D, 0x1F4B, 0x01F6, 0x06C0, 0x1FEF, 0x1FD3, 0x0010, - 0x002B, 0x1F58, 0x01B7, 0x06D6, 0x0017, 0x1FC6, 0x0013, - 0x0028, 0x1F66, 0x017B, 0x06E7, 0x0041, 0x1FB9, 0x0016, - 0x0025, 0x1F74, 0x0140, 0x06F3, 0x006F, 0x1FAC, 0x0019, - 0x0022, 0x1F82, 0x0108, 0x06FB, 0x009F, 0x1F9E, 0x001C, - /* Chroma */ - 0x001F, 0x1F90, 0x00D2, 0x06FE, 0x00D2, 0x1F90, 0x001F, - 0x001C, 0x1F9E, 0x009F, 0x06FB, 0x0108, 0x1F82, 0x0022, - 0x0019, 0x1FAC, 0x006F, 0x06F3, 0x0140, 0x1F74, 0x0025, - 0x0016, 0x1FB9, 0x0041, 0x06E7, 0x017B, 0x1F66, 0x0028, - 0x0013, 0x1FC6, 0x0017, 0x06D6, 0x01B7, 0x1F58, 0x002B, - 0x0010, 0x1FD3, 0x1FEF, 0x06C0, 0x01F6, 0x1F4B, 0x002D, - 0x000E, 0x1FDF, 0x1FCB, 0x06A5, 0x0235, 0x1F3F, 0x002F, - 0x000B, 0x1FEA, 0x1FAA, 0x0686, 0x0277, 0x1F33, 0x0031, - 0x0009, 0x1FF5, 0x1F8C, 0x0663, 0x02B8, 0x1F28, 0x0033, - 0x0007, 0x1FFF, 0x1F72, 0x063A, 0x02FB, 0x1F1F, 0x0034, - 0x0005, 0x0008, 0x1F5A, 0x060F, 0x033E, 0x1F17, 0x0035, - 0x0003, 0x0010, 0x1F46, 0x05E0, 0x0382, 0x1F10, 0x0035, - 0x0002, 0x0017, 0x1F34, 0x05AF, 0x03C5, 0x1F0B, 0x0034, - 0x0001, 0x001E, 0x1F26, 0x0579, 0x0407, 0x1F08, 0x0033, - 0x0000, 0x0023, 0x1F1A, 0x0541, 0x0449, 0x1F07, 0x0032, - 0x1FFF, 0x0028, 0x1F12, 0x0506, 0x048A, 0x1F08, 0x002F, - 0x002C, 0x1F0C, 0x04C8, 0x04C8, 0x1F0C, 0x002C, 0x0000, - 0x002F, 0x1F08, 0x048A, 0x0506, 0x1F12, 0x0028, 0x1FFF, - 0x0032, 0x1F07, 0x0449, 0x0541, 0x1F1A, 0x0023, 0x0000, - 0x0033, 0x1F08, 0x0407, 0x0579, 0x1F26, 0x001E, 0x0001, - 0x0034, 0x1F0B, 0x03C5, 0x05AF, 0x1F34, 0x0017, 0x0002, - 0x0035, 0x1F10, 0x0382, 0x05E0, 0x1F46, 0x0010, 0x0003, - 0x0035, 0x1F17, 0x033E, 0x060F, 0x1F5A, 0x0008, 0x0005, - 0x0034, 0x1F1F, 0x02FB, 0x063A, 0x1F72, 0x1FFF, 0x0007, - 0x0033, 0x1F28, 0x02B8, 0x0663, 0x1F8C, 0x1FF5, 0x0009, - 0x0031, 0x1F33, 0x0277, 0x0686, 0x1FAA, 0x1FEA, 0x000B, - 0x002F, 0x1F3F, 0x0235, 0x06A5, 0x1FCB, 0x1FDF, 0x000E, - 0x002D, 0x1F4B, 0x01F6, 0x06C0, 0x1FEF, 0x1FD3, 0x0010, - 0x002B, 0x1F58, 0x01B7, 0x06D6, 0x0017, 0x1FC6, 0x0013, - 0x0028, 0x1F66, 0x017B, 0x06E7, 0x0041, 0x1FB9, 0x0016, - 0x0025, 0x1F74, 0x0140, 0x06F3, 0x006F, 0x1FAC, 0x0019, - 0x0022, 0x1F82, 0x0108, 0x06FB, 0x009F, 0x1F9E, 0x001C, - }, - [HS_LT_9_16_SCALE] = { - /* Luma */ - 0x1FA3, 0x005E, 0x024A, 0x036A, 0x024A, 0x005E, 0x1FA3, - 0x1FA3, 0x0052, 0x023A, 0x036A, 0x0259, 0x006A, 0x1FA4, - 0x1FA3, 0x0046, 0x022A, 0x036A, 0x0269, 0x0076, 0x1FA4, - 0x1FA3, 0x003B, 0x021A, 0x0368, 0x0278, 0x0083, 0x1FA5, - 0x1FA4, 0x0031, 0x020A, 0x0365, 0x0286, 0x0090, 0x1FA6, - 0x1FA5, 0x0026, 0x01F9, 0x0362, 0x0294, 0x009E, 0x1FA8, - 0x1FA6, 0x001C, 0x01E8, 0x035E, 0x02A3, 0x00AB, 0x1FAA, - 0x1FA7, 0x0013, 0x01D7, 0x035A, 0x02B0, 0x00B9, 0x1FAC, - 0x1FA9, 0x000A, 0x01C6, 0x0354, 0x02BD, 0x00C7, 0x1FAF, - 0x1FAA, 0x0001, 0x01B6, 0x034E, 0x02C9, 0x00D6, 0x1FB2, - 0x1FAC, 0x1FF9, 0x01A5, 0x0347, 0x02D5, 0x00E5, 0x1FB5, - 0x1FAE, 0x1FF1, 0x0194, 0x0340, 0x02E1, 0x00F3, 0x1FB9, - 0x1FB0, 0x1FEA, 0x0183, 0x0338, 0x02EC, 0x0102, 0x1FBD, - 0x1FB2, 0x1FE3, 0x0172, 0x0330, 0x02F6, 0x0112, 0x1FC1, - 0x1FB4, 0x1FDC, 0x0161, 0x0327, 0x0301, 0x0121, 0x1FC6, - 0x1FB7, 0x1FD6, 0x0151, 0x031D, 0x030A, 0x0130, 0x1FCB, - 0x1FD2, 0x0136, 0x02F8, 0x02F8, 0x0136, 0x1FD2, 0x0000, - 0x1FCB, 0x0130, 0x030A, 0x031D, 0x0151, 0x1FD6, 0x1FB7, - 0x1FC6, 0x0121, 0x0301, 0x0327, 0x0161, 0x1FDC, 0x1FB4, - 0x1FC1, 0x0112, 0x02F6, 0x0330, 0x0172, 0x1FE3, 0x1FB2, - 0x1FBD, 0x0102, 0x02EC, 0x0338, 0x0183, 0x1FEA, 0x1FB0, - 0x1FB9, 0x00F3, 0x02E1, 0x0340, 0x0194, 0x1FF1, 0x1FAE, - 0x1FB5, 0x00E5, 0x02D5, 0x0347, 0x01A5, 0x1FF9, 0x1FAC, - 0x1FB2, 0x00D6, 0x02C9, 0x034E, 0x01B6, 0x0001, 0x1FAA, - 0x1FAF, 0x00C7, 0x02BD, 0x0354, 0x01C6, 0x000A, 0x1FA9, - 0x1FAC, 0x00B9, 0x02B0, 0x035A, 0x01D7, 0x0013, 0x1FA7, - 0x1FAA, 0x00AB, 0x02A3, 0x035E, 0x01E8, 0x001C, 0x1FA6, - 0x1FA8, 0x009E, 0x0294, 0x0362, 0x01F9, 0x0026, 0x1FA5, - 0x1FA6, 0x0090, 0x0286, 0x0365, 0x020A, 0x0031, 0x1FA4, - 0x1FA5, 0x0083, 0x0278, 0x0368, 0x021A, 0x003B, 0x1FA3, - 0x1FA4, 0x0076, 0x0269, 0x036A, 0x022A, 0x0046, 0x1FA3, - 0x1FA4, 0x006A, 0x0259, 0x036A, 0x023A, 0x0052, 0x1FA3, - /* Chroma */ - 0x1FA3, 0x005E, 0x024A, 0x036A, 0x024A, 0x005E, 0x1FA3, - 0x1FA3, 0x0052, 0x023A, 0x036A, 0x0259, 0x006A, 0x1FA4, - 0x1FA3, 0x0046, 0x022A, 0x036A, 0x0269, 0x0076, 0x1FA4, - 0x1FA3, 0x003B, 0x021A, 0x0368, 0x0278, 0x0083, 0x1FA5, - 0x1FA4, 0x0031, 0x020A, 0x0365, 0x0286, 0x0090, 0x1FA6, - 0x1FA5, 0x0026, 0x01F9, 0x0362, 0x0294, 0x009E, 0x1FA8, - 0x1FA6, 0x001C, 0x01E8, 0x035E, 0x02A3, 0x00AB, 0x1FAA, - 0x1FA7, 0x0013, 0x01D7, 0x035A, 0x02B0, 0x00B9, 0x1FAC, - 0x1FA9, 0x000A, 0x01C6, 0x0354, 0x02BD, 0x00C7, 0x1FAF, - 0x1FAA, 0x0001, 0x01B6, 0x034E, 0x02C9, 0x00D6, 0x1FB2, - 0x1FAC, 0x1FF9, 0x01A5, 0x0347, 0x02D5, 0x00E5, 0x1FB5, - 0x1FAE, 0x1FF1, 0x0194, 0x0340, 0x02E1, 0x00F3, 0x1FB9, - 0x1FB0, 0x1FEA, 0x0183, 0x0338, 0x02EC, 0x0102, 0x1FBD, - 0x1FB2, 0x1FE3, 0x0172, 0x0330, 0x02F6, 0x0112, 0x1FC1, - 0x1FB4, 0x1FDC, 0x0161, 0x0327, 0x0301, 0x0121, 0x1FC6, - 0x1FB7, 0x1FD6, 0x0151, 0x031D, 0x030A, 0x0130, 0x1FCB, - 0x1FD2, 0x0136, 0x02F8, 0x02F8, 0x0136, 0x1FD2, 0x0000, - 0x1FCB, 0x0130, 0x030A, 0x031D, 0x0151, 0x1FD6, 0x1FB7, - 0x1FC6, 0x0121, 0x0301, 0x0327, 0x0161, 0x1FDC, 0x1FB4, - 0x1FC1, 0x0112, 0x02F6, 0x0330, 0x0172, 0x1FE3, 0x1FB2, - 0x1FBD, 0x0102, 0x02EC, 0x0338, 0x0183, 0x1FEA, 0x1FB0, - 0x1FB9, 0x00F3, 0x02E1, 0x0340, 0x0194, 0x1FF1, 0x1FAE, - 0x1FB5, 0x00E5, 0x02D5, 0x0347, 0x01A5, 0x1FF9, 0x1FAC, - 0x1FB2, 0x00D6, 0x02C9, 0x034E, 0x01B6, 0x0001, 0x1FAA, - 0x1FAF, 0x00C7, 0x02BD, 0x0354, 0x01C6, 0x000A, 0x1FA9, - 0x1FAC, 0x00B9, 0x02B0, 0x035A, 0x01D7, 0x0013, 0x1FA7, - 0x1FAA, 0x00AB, 0x02A3, 0x035E, 0x01E8, 0x001C, 0x1FA6, - 0x1FA8, 0x009E, 0x0294, 0x0362, 0x01F9, 0x0026, 0x1FA5, - 0x1FA6, 0x0090, 0x0286, 0x0365, 0x020A, 0x0031, 0x1FA4, - 0x1FA5, 0x0083, 0x0278, 0x0368, 0x021A, 0x003B, 0x1FA3, - 0x1FA4, 0x0076, 0x0269, 0x036A, 0x022A, 0x0046, 0x1FA3, - 0x1FA4, 0x006A, 0x0259, 0x036A, 0x023A, 0x0052, 0x1FA3, - }, - [HS_LT_10_16_SCALE] = { - /* Luma */ - 0x1F8D, 0x000C, 0x026A, 0x03FA, 0x026A, 0x000C, 0x1F8D, - 0x1F8F, 0x0000, 0x0255, 0x03FA, 0x027F, 0x0019, 0x1F8A, - 0x1F92, 0x1FF5, 0x023F, 0x03F8, 0x0293, 0x0027, 0x1F88, - 0x1F95, 0x1FEA, 0x022A, 0x03F6, 0x02A7, 0x0034, 0x1F86, - 0x1F99, 0x1FDF, 0x0213, 0x03F2, 0x02BB, 0x0043, 0x1F85, - 0x1F9C, 0x1FD5, 0x01FE, 0x03ED, 0x02CF, 0x0052, 0x1F83, - 0x1FA0, 0x1FCC, 0x01E8, 0x03E7, 0x02E1, 0x0061, 0x1F83, - 0x1FA4, 0x1FC3, 0x01D2, 0x03E0, 0x02F4, 0x0071, 0x1F82, - 0x1FA7, 0x1FBB, 0x01BC, 0x03D9, 0x0306, 0x0081, 0x1F82, - 0x1FAB, 0x1FB4, 0x01A6, 0x03D0, 0x0317, 0x0092, 0x1F82, - 0x1FAF, 0x1FAD, 0x0190, 0x03C7, 0x0327, 0x00A3, 0x1F83, - 0x1FB3, 0x1FA7, 0x017A, 0x03BC, 0x0337, 0x00B5, 0x1F84, - 0x1FB8, 0x1FA1, 0x0165, 0x03B0, 0x0346, 0x00C7, 0x1F85, - 0x1FBC, 0x1F9C, 0x0150, 0x03A4, 0x0354, 0x00D9, 0x1F87, - 0x1FC0, 0x1F98, 0x013A, 0x0397, 0x0361, 0x00EC, 0x1F8A, - 0x1FC4, 0x1F93, 0x0126, 0x0389, 0x036F, 0x00FE, 0x1F8D, - 0x1F93, 0x010A, 0x0363, 0x0363, 0x010A, 0x1F93, 0x0000, - 0x1F8D, 0x00FE, 0x036F, 0x0389, 0x0126, 0x1F93, 0x1FC4, - 0x1F8A, 0x00EC, 0x0361, 0x0397, 0x013A, 0x1F98, 0x1FC0, - 0x1F87, 0x00D9, 0x0354, 0x03A4, 0x0150, 0x1F9C, 0x1FBC, - 0x1F85, 0x00C7, 0x0346, 0x03B0, 0x0165, 0x1FA1, 0x1FB8, - 0x1F84, 0x00B5, 0x0337, 0x03BC, 0x017A, 0x1FA7, 0x1FB3, - 0x1F83, 0x00A3, 0x0327, 0x03C7, 0x0190, 0x1FAD, 0x1FAF, - 0x1F82, 0x0092, 0x0317, 0x03D0, 0x01A6, 0x1FB4, 0x1FAB, - 0x1F82, 0x0081, 0x0306, 0x03D9, 0x01BC, 0x1FBB, 0x1FA7, - 0x1F82, 0x0071, 0x02F4, 0x03E0, 0x01D2, 0x1FC3, 0x1FA4, - 0x1F83, 0x0061, 0x02E1, 0x03E7, 0x01E8, 0x1FCC, 0x1FA0, - 0x1F83, 0x0052, 0x02CF, 0x03ED, 0x01FE, 0x1FD5, 0x1F9C, - 0x1F85, 0x0043, 0x02BB, 0x03F2, 0x0213, 0x1FDF, 0x1F99, - 0x1F86, 0x0034, 0x02A7, 0x03F6, 0x022A, 0x1FEA, 0x1F95, - 0x1F88, 0x0027, 0x0293, 0x03F8, 0x023F, 0x1FF5, 0x1F92, - 0x1F8A, 0x0019, 0x027F, 0x03FA, 0x0255, 0x0000, 0x1F8F, - /* Chroma */ - 0x1F8D, 0x000C, 0x026A, 0x03FA, 0x026A, 0x000C, 0x1F8D, - 0x1F8F, 0x0000, 0x0255, 0x03FA, 0x027F, 0x0019, 0x1F8A, - 0x1F92, 0x1FF5, 0x023F, 0x03F8, 0x0293, 0x0027, 0x1F88, - 0x1F95, 0x1FEA, 0x022A, 0x03F6, 0x02A7, 0x0034, 0x1F86, - 0x1F99, 0x1FDF, 0x0213, 0x03F2, 0x02BB, 0x0043, 0x1F85, - 0x1F9C, 0x1FD5, 0x01FE, 0x03ED, 0x02CF, 0x0052, 0x1F83, - 0x1FA0, 0x1FCC, 0x01E8, 0x03E7, 0x02E1, 0x0061, 0x1F83, - 0x1FA4, 0x1FC3, 0x01D2, 0x03E0, 0x02F4, 0x0071, 0x1F82, - 0x1FA7, 0x1FBB, 0x01BC, 0x03D9, 0x0306, 0x0081, 0x1F82, - 0x1FAB, 0x1FB4, 0x01A6, 0x03D0, 0x0317, 0x0092, 0x1F82, - 0x1FAF, 0x1FAD, 0x0190, 0x03C7, 0x0327, 0x00A3, 0x1F83, - 0x1FB3, 0x1FA7, 0x017A, 0x03BC, 0x0337, 0x00B5, 0x1F84, - 0x1FB8, 0x1FA1, 0x0165, 0x03B0, 0x0346, 0x00C7, 0x1F85, - 0x1FBC, 0x1F9C, 0x0150, 0x03A4, 0x0354, 0x00D9, 0x1F87, - 0x1FC0, 0x1F98, 0x013A, 0x0397, 0x0361, 0x00EC, 0x1F8A, - 0x1FC4, 0x1F93, 0x0126, 0x0389, 0x036F, 0x00FE, 0x1F8D, - 0x1F93, 0x010A, 0x0363, 0x0363, 0x010A, 0x1F93, 0x0000, - 0x1F8D, 0x00FE, 0x036F, 0x0389, 0x0126, 0x1F93, 0x1FC4, - 0x1F8A, 0x00EC, 0x0361, 0x0397, 0x013A, 0x1F98, 0x1FC0, - 0x1F87, 0x00D9, 0x0354, 0x03A4, 0x0150, 0x1F9C, 0x1FBC, - 0x1F85, 0x00C7, 0x0346, 0x03B0, 0x0165, 0x1FA1, 0x1FB8, - 0x1F84, 0x00B5, 0x0337, 0x03BC, 0x017A, 0x1FA7, 0x1FB3, - 0x1F83, 0x00A3, 0x0327, 0x03C7, 0x0190, 0x1FAD, 0x1FAF, - 0x1F82, 0x0092, 0x0317, 0x03D0, 0x01A6, 0x1FB4, 0x1FAB, - 0x1F82, 0x0081, 0x0306, 0x03D9, 0x01BC, 0x1FBB, 0x1FA7, - 0x1F82, 0x0071, 0x02F4, 0x03E0, 0x01D2, 0x1FC3, 0x1FA4, - 0x1F83, 0x0061, 0x02E1, 0x03E7, 0x01E8, 0x1FCC, 0x1FA0, - 0x1F83, 0x0052, 0x02CF, 0x03ED, 0x01FE, 0x1FD5, 0x1F9C, - 0x1F85, 0x0043, 0x02BB, 0x03F2, 0x0213, 0x1FDF, 0x1F99, - 0x1F86, 0x0034, 0x02A7, 0x03F6, 0x022A, 0x1FEA, 0x1F95, - 0x1F88, 0x0027, 0x0293, 0x03F8, 0x023F, 0x1FF5, 0x1F92, - 0x1F8A, 0x0019, 0x027F, 0x03FA, 0x0255, 0x0000, 0x1F8F, - }, - [HS_LT_11_16_SCALE] = { - /* Luma */ - 0x1F95, 0x1FB5, 0x0272, 0x0488, 0x0272, 0x1FB5, 0x1F95, - 0x1F9B, 0x1FAA, 0x0257, 0x0486, 0x028D, 0x1FC1, 0x1F90, - 0x1FA0, 0x1FA0, 0x023C, 0x0485, 0x02A8, 0x1FCD, 0x1F8A, - 0x1FA6, 0x1F96, 0x0221, 0x0481, 0x02C2, 0x1FDB, 0x1F85, - 0x1FAC, 0x1F8E, 0x0205, 0x047C, 0x02DC, 0x1FE9, 0x1F80, - 0x1FB1, 0x1F86, 0x01E9, 0x0476, 0x02F6, 0x1FF8, 0x1F7C, - 0x1FB7, 0x1F7F, 0x01CE, 0x046E, 0x030F, 0x0008, 0x1F77, - 0x1FBD, 0x1F79, 0x01B3, 0x0465, 0x0326, 0x0019, 0x1F73, - 0x1FC3, 0x1F73, 0x0197, 0x045B, 0x033E, 0x002A, 0x1F70, - 0x1FC8, 0x1F6F, 0x017D, 0x044E, 0x0355, 0x003C, 0x1F6D, - 0x1FCE, 0x1F6B, 0x0162, 0x0441, 0x036B, 0x004F, 0x1F6A, - 0x1FD3, 0x1F68, 0x0148, 0x0433, 0x0380, 0x0063, 0x1F67, - 0x1FD8, 0x1F65, 0x012E, 0x0424, 0x0395, 0x0077, 0x1F65, - 0x1FDE, 0x1F63, 0x0115, 0x0413, 0x03A8, 0x008B, 0x1F64, - 0x1FE3, 0x1F62, 0x00FC, 0x0403, 0x03BA, 0x00A0, 0x1F62, - 0x1FE7, 0x1F62, 0x00E4, 0x03EF, 0x03CC, 0x00B6, 0x1F62, - 0x1F63, 0x00CA, 0x03D3, 0x03D3, 0x00CA, 0x1F63, 0x0000, - 0x1F62, 0x00B6, 0x03CC, 0x03EF, 0x00E4, 0x1F62, 0x1FE7, - 0x1F62, 0x00A0, 0x03BA, 0x0403, 0x00FC, 0x1F62, 0x1FE3, - 0x1F64, 0x008B, 0x03A8, 0x0413, 0x0115, 0x1F63, 0x1FDE, - 0x1F65, 0x0077, 0x0395, 0x0424, 0x012E, 0x1F65, 0x1FD8, - 0x1F67, 0x0063, 0x0380, 0x0433, 0x0148, 0x1F68, 0x1FD3, - 0x1F6A, 0x004F, 0x036B, 0x0441, 0x0162, 0x1F6B, 0x1FCE, - 0x1F6D, 0x003C, 0x0355, 0x044E, 0x017D, 0x1F6F, 0x1FC8, - 0x1F70, 0x002A, 0x033E, 0x045B, 0x0197, 0x1F73, 0x1FC3, - 0x1F73, 0x0019, 0x0326, 0x0465, 0x01B3, 0x1F79, 0x1FBD, - 0x1F77, 0x0008, 0x030F, 0x046E, 0x01CE, 0x1F7F, 0x1FB7, - 0x1F7C, 0x1FF8, 0x02F6, 0x0476, 0x01E9, 0x1F86, 0x1FB1, - 0x1F80, 0x1FE9, 0x02DC, 0x047C, 0x0205, 0x1F8E, 0x1FAC, - 0x1F85, 0x1FDB, 0x02C2, 0x0481, 0x0221, 0x1F96, 0x1FA6, - 0x1F8A, 0x1FCD, 0x02A8, 0x0485, 0x023C, 0x1FA0, 0x1FA0, - 0x1F90, 0x1FC1, 0x028D, 0x0486, 0x0257, 0x1FAA, 0x1F9B, - /* Chroma */ - 0x1F95, 0x1FB5, 0x0272, 0x0488, 0x0272, 0x1FB5, 0x1F95, - 0x1F9B, 0x1FAA, 0x0257, 0x0486, 0x028D, 0x1FC1, 0x1F90, - 0x1FA0, 0x1FA0, 0x023C, 0x0485, 0x02A8, 0x1FCD, 0x1F8A, - 0x1FA6, 0x1F96, 0x0221, 0x0481, 0x02C2, 0x1FDB, 0x1F85, - 0x1FAC, 0x1F8E, 0x0205, 0x047C, 0x02DC, 0x1FE9, 0x1F80, - 0x1FB1, 0x1F86, 0x01E9, 0x0476, 0x02F6, 0x1FF8, 0x1F7C, - 0x1FB7, 0x1F7F, 0x01CE, 0x046E, 0x030F, 0x0008, 0x1F77, - 0x1FBD, 0x1F79, 0x01B3, 0x0465, 0x0326, 0x0019, 0x1F73, - 0x1FC3, 0x1F73, 0x0197, 0x045B, 0x033E, 0x002A, 0x1F70, - 0x1FC8, 0x1F6F, 0x017D, 0x044E, 0x0355, 0x003C, 0x1F6D, - 0x1FCE, 0x1F6B, 0x0162, 0x0441, 0x036B, 0x004F, 0x1F6A, - 0x1FD3, 0x1F68, 0x0148, 0x0433, 0x0380, 0x0063, 0x1F67, - 0x1FD8, 0x1F65, 0x012E, 0x0424, 0x0395, 0x0077, 0x1F65, - 0x1FDE, 0x1F63, 0x0115, 0x0413, 0x03A8, 0x008B, 0x1F64, - 0x1FE3, 0x1F62, 0x00FC, 0x0403, 0x03BA, 0x00A0, 0x1F62, - 0x1FE7, 0x1F62, 0x00E4, 0x03EF, 0x03CC, 0x00B6, 0x1F62, - 0x1F63, 0x00CA, 0x03D3, 0x03D3, 0x00CA, 0x1F63, 0x0000, - 0x1F62, 0x00B6, 0x03CC, 0x03EF, 0x00E4, 0x1F62, 0x1FE7, - 0x1F62, 0x00A0, 0x03BA, 0x0403, 0x00FC, 0x1F62, 0x1FE3, - 0x1F64, 0x008B, 0x03A8, 0x0413, 0x0115, 0x1F63, 0x1FDE, - 0x1F65, 0x0077, 0x0395, 0x0424, 0x012E, 0x1F65, 0x1FD8, - 0x1F67, 0x0063, 0x0380, 0x0433, 0x0148, 0x1F68, 0x1FD3, - 0x1F6A, 0x004F, 0x036B, 0x0441, 0x0162, 0x1F6B, 0x1FCE, - 0x1F6D, 0x003C, 0x0355, 0x044E, 0x017D, 0x1F6F, 0x1FC8, - 0x1F70, 0x002A, 0x033E, 0x045B, 0x0197, 0x1F73, 0x1FC3, - 0x1F73, 0x0019, 0x0326, 0x0465, 0x01B3, 0x1F79, 0x1FBD, - 0x1F77, 0x0008, 0x030F, 0x046E, 0x01CE, 0x1F7F, 0x1FB7, - 0x1F7C, 0x1FF8, 0x02F6, 0x0476, 0x01E9, 0x1F86, 0x1FB1, - 0x1F80, 0x1FE9, 0x02DC, 0x047C, 0x0205, 0x1F8E, 0x1FAC, - 0x1F85, 0x1FDB, 0x02C2, 0x0481, 0x0221, 0x1F96, 0x1FA6, - 0x1F8A, 0x1FCD, 0x02A8, 0x0485, 0x023C, 0x1FA0, 0x1FA0, - 0x1F90, 0x1FC1, 0x028D, 0x0486, 0x0257, 0x1FAA, 0x1F9B, - }, - [HS_LT_12_16_SCALE] = { - /* Luma */ - 0x1FBB, 0x1F65, 0x025E, 0x0504, 0x025E, 0x1F65, 0x1FBB, - 0x1FC3, 0x1F5D, 0x023C, 0x0503, 0x027F, 0x1F6E, 0x1FB4, - 0x1FCA, 0x1F56, 0x021B, 0x0501, 0x02A0, 0x1F78, 0x1FAC, - 0x1FD1, 0x1F50, 0x01FA, 0x04FD, 0x02C0, 0x1F83, 0x1FA5, - 0x1FD8, 0x1F4B, 0x01D9, 0x04F6, 0x02E1, 0x1F90, 0x1F9D, - 0x1FDF, 0x1F47, 0x01B8, 0x04EF, 0x0301, 0x1F9D, 0x1F95, - 0x1FE6, 0x1F43, 0x0198, 0x04E5, 0x0321, 0x1FAB, 0x1F8E, - 0x1FEC, 0x1F41, 0x0178, 0x04DA, 0x0340, 0x1FBB, 0x1F86, - 0x1FF2, 0x1F40, 0x0159, 0x04CC, 0x035E, 0x1FCC, 0x1F7F, - 0x1FF8, 0x1F40, 0x013A, 0x04BE, 0x037B, 0x1FDD, 0x1F78, - 0x1FFE, 0x1F40, 0x011B, 0x04AD, 0x0398, 0x1FF0, 0x1F72, - 0x0003, 0x1F41, 0x00FD, 0x049C, 0x03B4, 0x0004, 0x1F6B, - 0x0008, 0x1F43, 0x00E0, 0x0489, 0x03CE, 0x0019, 0x1F65, - 0x000D, 0x1F46, 0x00C4, 0x0474, 0x03E8, 0x002E, 0x1F5F, - 0x0011, 0x1F49, 0x00A9, 0x045E, 0x0400, 0x0045, 0x1F5A, - 0x0015, 0x1F4D, 0x008E, 0x0447, 0x0418, 0x005C, 0x1F55, - 0x1F4F, 0x0076, 0x043B, 0x043B, 0x0076, 0x1F4F, 0x0000, - 0x1F55, 0x005C, 0x0418, 0x0447, 0x008E, 0x1F4D, 0x0015, - 0x1F5A, 0x0045, 0x0400, 0x045E, 0x00A9, 0x1F49, 0x0011, - 0x1F5F, 0x002E, 0x03E8, 0x0474, 0x00C4, 0x1F46, 0x000D, - 0x1F65, 0x0019, 0x03CE, 0x0489, 0x00E0, 0x1F43, 0x0008, - 0x1F6B, 0x0004, 0x03B4, 0x049C, 0x00FD, 0x1F41, 0x0003, - 0x1F72, 0x1FF0, 0x0398, 0x04AD, 0x011B, 0x1F40, 0x1FFE, - 0x1F78, 0x1FDD, 0x037B, 0x04BE, 0x013A, 0x1F40, 0x1FF8, - 0x1F7F, 0x1FCC, 0x035E, 0x04CC, 0x0159, 0x1F40, 0x1FF2, - 0x1F86, 0x1FBB, 0x0340, 0x04DA, 0x0178, 0x1F41, 0x1FEC, - 0x1F8E, 0x1FAB, 0x0321, 0x04E5, 0x0198, 0x1F43, 0x1FE6, - 0x1F95, 0x1F9D, 0x0301, 0x04EF, 0x01B8, 0x1F47, 0x1FDF, - 0x1F9D, 0x1F90, 0x02E1, 0x04F6, 0x01D9, 0x1F4B, 0x1FD8, - 0x1FA5, 0x1F83, 0x02C0, 0x04FD, 0x01FA, 0x1F50, 0x1FD1, - 0x1FAC, 0x1F78, 0x02A0, 0x0501, 0x021B, 0x1F56, 0x1FCA, - 0x1FB4, 0x1F6E, 0x027F, 0x0503, 0x023C, 0x1F5D, 0x1FC3, - /* Chroma */ - 0x1FBB, 0x1F65, 0x025E, 0x0504, 0x025E, 0x1F65, 0x1FBB, - 0x1FC3, 0x1F5D, 0x023C, 0x0503, 0x027F, 0x1F6E, 0x1FB4, - 0x1FCA, 0x1F56, 0x021B, 0x0501, 0x02A0, 0x1F78, 0x1FAC, - 0x1FD1, 0x1F50, 0x01FA, 0x04FD, 0x02C0, 0x1F83, 0x1FA5, - 0x1FD8, 0x1F4B, 0x01D9, 0x04F6, 0x02E1, 0x1F90, 0x1F9D, - 0x1FDF, 0x1F47, 0x01B8, 0x04EF, 0x0301, 0x1F9D, 0x1F95, - 0x1FE6, 0x1F43, 0x0198, 0x04E5, 0x0321, 0x1FAB, 0x1F8E, - 0x1FEC, 0x1F41, 0x0178, 0x04DA, 0x0340, 0x1FBB, 0x1F86, - 0x1FF2, 0x1F40, 0x0159, 0x04CC, 0x035E, 0x1FCC, 0x1F7F, - 0x1FF8, 0x1F40, 0x013A, 0x04BE, 0x037B, 0x1FDD, 0x1F78, - 0x1FFE, 0x1F40, 0x011B, 0x04AD, 0x0398, 0x1FF0, 0x1F72, - 0x0003, 0x1F41, 0x00FD, 0x049C, 0x03B4, 0x0004, 0x1F6B, - 0x0008, 0x1F43, 0x00E0, 0x0489, 0x03CE, 0x0019, 0x1F65, - 0x000D, 0x1F46, 0x00C4, 0x0474, 0x03E8, 0x002E, 0x1F5F, - 0x0011, 0x1F49, 0x00A9, 0x045E, 0x0400, 0x0045, 0x1F5A, - 0x0015, 0x1F4D, 0x008E, 0x0447, 0x0418, 0x005C, 0x1F55, - 0x1F4F, 0x0076, 0x043B, 0x043B, 0x0076, 0x1F4F, 0x0000, - 0x1F55, 0x005C, 0x0418, 0x0447, 0x008E, 0x1F4D, 0x0015, - 0x1F5A, 0x0045, 0x0400, 0x045E, 0x00A9, 0x1F49, 0x0011, - 0x1F5F, 0x002E, 0x03E8, 0x0474, 0x00C4, 0x1F46, 0x000D, - 0x1F65, 0x0019, 0x03CE, 0x0489, 0x00E0, 0x1F43, 0x0008, - 0x1F6B, 0x0004, 0x03B4, 0x049C, 0x00FD, 0x1F41, 0x0003, - 0x1F72, 0x1FF0, 0x0398, 0x04AD, 0x011B, 0x1F40, 0x1FFE, - 0x1F78, 0x1FDD, 0x037B, 0x04BE, 0x013A, 0x1F40, 0x1FF8, - 0x1F7F, 0x1FCC, 0x035E, 0x04CC, 0x0159, 0x1F40, 0x1FF2, - 0x1F86, 0x1FBB, 0x0340, 0x04DA, 0x0178, 0x1F41, 0x1FEC, - 0x1F8E, 0x1FAB, 0x0321, 0x04E5, 0x0198, 0x1F43, 0x1FE6, - 0x1F95, 0x1F9D, 0x0301, 0x04EF, 0x01B8, 0x1F47, 0x1FDF, - 0x1F9D, 0x1F90, 0x02E1, 0x04F6, 0x01D9, 0x1F4B, 0x1FD8, - 0x1FA5, 0x1F83, 0x02C0, 0x04FD, 0x01FA, 0x1F50, 0x1FD1, - 0x1FAC, 0x1F78, 0x02A0, 0x0501, 0x021B, 0x1F56, 0x1FCA, - 0x1FB4, 0x1F6E, 0x027F, 0x0503, 0x023C, 0x1F5D, 0x1FC3, - }, - [HS_LT_13_16_SCALE] = { - /* Luma */ - 0x1FF4, 0x1F29, 0x022D, 0x056C, 0x022D, 0x1F29, 0x1FF4, - 0x1FFC, 0x1F26, 0x0206, 0x056A, 0x0254, 0x1F2E, 0x1FEC, - 0x0003, 0x1F24, 0x01E0, 0x0567, 0x027A, 0x1F34, 0x1FE4, - 0x000A, 0x1F23, 0x01BA, 0x0561, 0x02A2, 0x1F3B, 0x1FDB, - 0x0011, 0x1F22, 0x0194, 0x055B, 0x02C9, 0x1F43, 0x1FD2, - 0x0017, 0x1F23, 0x016F, 0x0551, 0x02F0, 0x1F4D, 0x1FC9, - 0x001D, 0x1F25, 0x014B, 0x0545, 0x0316, 0x1F58, 0x1FC0, - 0x0022, 0x1F28, 0x0127, 0x0538, 0x033C, 0x1F65, 0x1FB6, - 0x0027, 0x1F2C, 0x0104, 0x0528, 0x0361, 0x1F73, 0x1FAD, - 0x002B, 0x1F30, 0x00E2, 0x0518, 0x0386, 0x1F82, 0x1FA3, - 0x002F, 0x1F36, 0x00C2, 0x0504, 0x03AA, 0x1F92, 0x1F99, - 0x0032, 0x1F3C, 0x00A2, 0x04EF, 0x03CD, 0x1FA4, 0x1F90, - 0x0035, 0x1F42, 0x0083, 0x04D9, 0x03EF, 0x1FB8, 0x1F86, - 0x0038, 0x1F49, 0x0065, 0x04C0, 0x0410, 0x1FCD, 0x1F7D, - 0x003A, 0x1F51, 0x0048, 0x04A6, 0x0431, 0x1FE3, 0x1F73, - 0x003C, 0x1F59, 0x002D, 0x048A, 0x0450, 0x1FFA, 0x1F6A, - 0x1F5D, 0x0014, 0x048F, 0x048F, 0x0014, 0x1F5D, 0x0000, - 0x1F6A, 0x1FFA, 0x0450, 0x048A, 0x002D, 0x1F59, 0x003C, - 0x1F73, 0x1FE3, 0x0431, 0x04A6, 0x0048, 0x1F51, 0x003A, - 0x1F7D, 0x1FCD, 0x0410, 0x04C0, 0x0065, 0x1F49, 0x0038, - 0x1F86, 0x1FB8, 0x03EF, 0x04D9, 0x0083, 0x1F42, 0x0035, - 0x1F90, 0x1FA4, 0x03CD, 0x04EF, 0x00A2, 0x1F3C, 0x0032, - 0x1F99, 0x1F92, 0x03AA, 0x0504, 0x00C2, 0x1F36, 0x002F, - 0x1FA3, 0x1F82, 0x0386, 0x0518, 0x00E2, 0x1F30, 0x002B, - 0x1FAD, 0x1F73, 0x0361, 0x0528, 0x0104, 0x1F2C, 0x0027, - 0x1FB6, 0x1F65, 0x033C, 0x0538, 0x0127, 0x1F28, 0x0022, - 0x1FC0, 0x1F58, 0x0316, 0x0545, 0x014B, 0x1F25, 0x001D, - 0x1FC9, 0x1F4D, 0x02F0, 0x0551, 0x016F, 0x1F23, 0x0017, - 0x1FD2, 0x1F43, 0x02C9, 0x055B, 0x0194, 0x1F22, 0x0011, - 0x1FDB, 0x1F3B, 0x02A2, 0x0561, 0x01BA, 0x1F23, 0x000A, - 0x1FE4, 0x1F34, 0x027A, 0x0567, 0x01E0, 0x1F24, 0x0003, - 0x1FEC, 0x1F2E, 0x0254, 0x056A, 0x0206, 0x1F26, 0x1FFC, - /* Chroma */ - 0x1FF4, 0x1F29, 0x022D, 0x056C, 0x022D, 0x1F29, 0x1FF4, - 0x1FFC, 0x1F26, 0x0206, 0x056A, 0x0254, 0x1F2E, 0x1FEC, - 0x0003, 0x1F24, 0x01E0, 0x0567, 0x027A, 0x1F34, 0x1FE4, - 0x000A, 0x1F23, 0x01BA, 0x0561, 0x02A2, 0x1F3B, 0x1FDB, - 0x0011, 0x1F22, 0x0194, 0x055B, 0x02C9, 0x1F43, 0x1FD2, - 0x0017, 0x1F23, 0x016F, 0x0551, 0x02F0, 0x1F4D, 0x1FC9, - 0x001D, 0x1F25, 0x014B, 0x0545, 0x0316, 0x1F58, 0x1FC0, - 0x0022, 0x1F28, 0x0127, 0x0538, 0x033C, 0x1F65, 0x1FB6, - 0x0027, 0x1F2C, 0x0104, 0x0528, 0x0361, 0x1F73, 0x1FAD, - 0x002B, 0x1F30, 0x00E2, 0x0518, 0x0386, 0x1F82, 0x1FA3, - 0x002F, 0x1F36, 0x00C2, 0x0504, 0x03AA, 0x1F92, 0x1F99, - 0x0032, 0x1F3C, 0x00A2, 0x04EF, 0x03CD, 0x1FA4, 0x1F90, - 0x0035, 0x1F42, 0x0083, 0x04D9, 0x03EF, 0x1FB8, 0x1F86, - 0x0038, 0x1F49, 0x0065, 0x04C0, 0x0410, 0x1FCD, 0x1F7D, - 0x003A, 0x1F51, 0x0048, 0x04A6, 0x0431, 0x1FE3, 0x1F73, - 0x003C, 0x1F59, 0x002D, 0x048A, 0x0450, 0x1FFA, 0x1F6A, - 0x1F5D, 0x0014, 0x048F, 0x048F, 0x0014, 0x1F5D, 0x0000, - 0x1F6A, 0x1FFA, 0x0450, 0x048A, 0x002D, 0x1F59, 0x003C, - 0x1F73, 0x1FE3, 0x0431, 0x04A6, 0x0048, 0x1F51, 0x003A, - 0x1F7D, 0x1FCD, 0x0410, 0x04C0, 0x0065, 0x1F49, 0x0038, - 0x1F86, 0x1FB8, 0x03EF, 0x04D9, 0x0083, 0x1F42, 0x0035, - 0x1F90, 0x1FA4, 0x03CD, 0x04EF, 0x00A2, 0x1F3C, 0x0032, - 0x1F99, 0x1F92, 0x03AA, 0x0504, 0x00C2, 0x1F36, 0x002F, - 0x1FA3, 0x1F82, 0x0386, 0x0518, 0x00E2, 0x1F30, 0x002B, - 0x1FAD, 0x1F73, 0x0361, 0x0528, 0x0104, 0x1F2C, 0x0027, - 0x1FB6, 0x1F65, 0x033C, 0x0538, 0x0127, 0x1F28, 0x0022, - 0x1FC0, 0x1F58, 0x0316, 0x0545, 0x014B, 0x1F25, 0x001D, - 0x1FC9, 0x1F4D, 0x02F0, 0x0551, 0x016F, 0x1F23, 0x0017, - 0x1FD2, 0x1F43, 0x02C9, 0x055B, 0x0194, 0x1F22, 0x0011, - 0x1FDB, 0x1F3B, 0x02A2, 0x0561, 0x01BA, 0x1F23, 0x000A, - 0x1FE4, 0x1F34, 0x027A, 0x0567, 0x01E0, 0x1F24, 0x0003, - 0x1FEC, 0x1F2E, 0x0254, 0x056A, 0x0206, 0x1F26, 0x1FFC, - }, - [HS_LT_14_16_SCALE] = { - /* Luma */ - 0x002F, 0x1F0B, 0x01E7, 0x05BE, 0x01E7, 0x1F0B, 0x002F, - 0x0035, 0x1F0D, 0x01BC, 0x05BD, 0x0213, 0x1F0A, 0x0028, - 0x003A, 0x1F11, 0x0191, 0x05BA, 0x023F, 0x1F0A, 0x0021, - 0x003F, 0x1F15, 0x0167, 0x05B3, 0x026C, 0x1F0C, 0x001A, - 0x0043, 0x1F1B, 0x013E, 0x05AA, 0x0299, 0x1F0F, 0x0012, - 0x0046, 0x1F21, 0x0116, 0x05A1, 0x02C6, 0x1F13, 0x0009, - 0x0049, 0x1F28, 0x00EF, 0x0593, 0x02F4, 0x1F19, 0x0000, - 0x004C, 0x1F30, 0x00C9, 0x0584, 0x0321, 0x1F20, 0x1FF6, - 0x004E, 0x1F39, 0x00A4, 0x0572, 0x034D, 0x1F2A, 0x1FEC, - 0x004F, 0x1F43, 0x0080, 0x055E, 0x037A, 0x1F34, 0x1FE2, - 0x0050, 0x1F4D, 0x005E, 0x0548, 0x03A5, 0x1F41, 0x1FD7, - 0x0050, 0x1F57, 0x003D, 0x0531, 0x03D1, 0x1F4F, 0x1FCB, - 0x0050, 0x1F62, 0x001E, 0x0516, 0x03FB, 0x1F5F, 0x1FC0, - 0x004F, 0x1F6D, 0x0000, 0x04FA, 0x0425, 0x1F71, 0x1FB4, - 0x004E, 0x1F79, 0x1FE4, 0x04DC, 0x044D, 0x1F84, 0x1FA8, - 0x004D, 0x1F84, 0x1FCA, 0x04BC, 0x0474, 0x1F99, 0x1F9C, - 0x1F8C, 0x1FAE, 0x04C6, 0x04C6, 0x1FAE, 0x1F8C, 0x0000, - 0x1F9C, 0x1F99, 0x0474, 0x04BC, 0x1FCA, 0x1F84, 0x004D, - 0x1FA8, 0x1F84, 0x044D, 0x04DC, 0x1FE4, 0x1F79, 0x004E, - 0x1FB4, 0x1F71, 0x0425, 0x04FA, 0x0000, 0x1F6D, 0x004F, - 0x1FC0, 0x1F5F, 0x03FB, 0x0516, 0x001E, 0x1F62, 0x0050, - 0x1FCB, 0x1F4F, 0x03D1, 0x0531, 0x003D, 0x1F57, 0x0050, - 0x1FD7, 0x1F41, 0x03A5, 0x0548, 0x005E, 0x1F4D, 0x0050, - 0x1FE2, 0x1F34, 0x037A, 0x055E, 0x0080, 0x1F43, 0x004F, - 0x1FEC, 0x1F2A, 0x034D, 0x0572, 0x00A4, 0x1F39, 0x004E, - 0x1FF6, 0x1F20, 0x0321, 0x0584, 0x00C9, 0x1F30, 0x004C, - 0x0000, 0x1F19, 0x02F4, 0x0593, 0x00EF, 0x1F28, 0x0049, - 0x0009, 0x1F13, 0x02C6, 0x05A1, 0x0116, 0x1F21, 0x0046, - 0x0012, 0x1F0F, 0x0299, 0x05AA, 0x013E, 0x1F1B, 0x0043, - 0x001A, 0x1F0C, 0x026C, 0x05B3, 0x0167, 0x1F15, 0x003F, - 0x0021, 0x1F0A, 0x023F, 0x05BA, 0x0191, 0x1F11, 0x003A, - 0x0028, 0x1F0A, 0x0213, 0x05BD, 0x01BC, 0x1F0D, 0x0035, - /* Chroma */ - 0x002F, 0x1F0B, 0x01E7, 0x05BE, 0x01E7, 0x1F0B, 0x002F, - 0x0035, 0x1F0D, 0x01BC, 0x05BD, 0x0213, 0x1F0A, 0x0028, - 0x003A, 0x1F11, 0x0191, 0x05BA, 0x023F, 0x1F0A, 0x0021, - 0x003F, 0x1F15, 0x0167, 0x05B3, 0x026C, 0x1F0C, 0x001A, - 0x0043, 0x1F1B, 0x013E, 0x05AA, 0x0299, 0x1F0F, 0x0012, - 0x0046, 0x1F21, 0x0116, 0x05A1, 0x02C6, 0x1F13, 0x0009, - 0x0049, 0x1F28, 0x00EF, 0x0593, 0x02F4, 0x1F19, 0x0000, - 0x004C, 0x1F30, 0x00C9, 0x0584, 0x0321, 0x1F20, 0x1FF6, - 0x004E, 0x1F39, 0x00A4, 0x0572, 0x034D, 0x1F2A, 0x1FEC, - 0x004F, 0x1F43, 0x0080, 0x055E, 0x037A, 0x1F34, 0x1FE2, - 0x0050, 0x1F4D, 0x005E, 0x0548, 0x03A5, 0x1F41, 0x1FD7, - 0x0050, 0x1F57, 0x003D, 0x0531, 0x03D1, 0x1F4F, 0x1FCB, - 0x0050, 0x1F62, 0x001E, 0x0516, 0x03FB, 0x1F5F, 0x1FC0, - 0x004F, 0x1F6D, 0x0000, 0x04FA, 0x0425, 0x1F71, 0x1FB4, - 0x004E, 0x1F79, 0x1FE4, 0x04DC, 0x044D, 0x1F84, 0x1FA8, - 0x004D, 0x1F84, 0x1FCA, 0x04BC, 0x0474, 0x1F99, 0x1F9C, - 0x1F8C, 0x1FAE, 0x04C6, 0x04C6, 0x1FAE, 0x1F8C, 0x0000, - 0x1F9C, 0x1F99, 0x0474, 0x04BC, 0x1FCA, 0x1F84, 0x004D, - 0x1FA8, 0x1F84, 0x044D, 0x04DC, 0x1FE4, 0x1F79, 0x004E, - 0x1FB4, 0x1F71, 0x0425, 0x04FA, 0x0000, 0x1F6D, 0x004F, - 0x1FC0, 0x1F5F, 0x03FB, 0x0516, 0x001E, 0x1F62, 0x0050, - 0x1FCB, 0x1F4F, 0x03D1, 0x0531, 0x003D, 0x1F57, 0x0050, - 0x1FD7, 0x1F41, 0x03A5, 0x0548, 0x005E, 0x1F4D, 0x0050, - 0x1FE2, 0x1F34, 0x037A, 0x055E, 0x0080, 0x1F43, 0x004F, - 0x1FEC, 0x1F2A, 0x034D, 0x0572, 0x00A4, 0x1F39, 0x004E, - 0x1FF6, 0x1F20, 0x0321, 0x0584, 0x00C9, 0x1F30, 0x004C, - 0x0000, 0x1F19, 0x02F4, 0x0593, 0x00EF, 0x1F28, 0x0049, - 0x0009, 0x1F13, 0x02C6, 0x05A1, 0x0116, 0x1F21, 0x0046, - 0x0012, 0x1F0F, 0x0299, 0x05AA, 0x013E, 0x1F1B, 0x0043, - 0x001A, 0x1F0C, 0x026C, 0x05B3, 0x0167, 0x1F15, 0x003F, - 0x0021, 0x1F0A, 0x023F, 0x05BA, 0x0191, 0x1F11, 0x003A, - 0x0028, 0x1F0A, 0x0213, 0x05BD, 0x01BC, 0x1F0D, 0x0035, - }, - [HS_LT_15_16_SCALE] = { - /* Luma */ - 0x005B, 0x1F0A, 0x0195, 0x060C, 0x0195, 0x1F0A, 0x005B, - 0x005D, 0x1F13, 0x0166, 0x0609, 0x01C6, 0x1F03, 0x0058, - 0x005F, 0x1F1C, 0x0138, 0x0605, 0x01F7, 0x1EFD, 0x0054, - 0x0060, 0x1F26, 0x010B, 0x05FF, 0x0229, 0x1EF8, 0x004F, - 0x0060, 0x1F31, 0x00DF, 0x05F5, 0x025C, 0x1EF5, 0x004A, - 0x0060, 0x1F3D, 0x00B5, 0x05E8, 0x028F, 0x1EF3, 0x0044, - 0x005F, 0x1F49, 0x008C, 0x05DA, 0x02C3, 0x1EF2, 0x003D, - 0x005E, 0x1F56, 0x0065, 0x05C7, 0x02F6, 0x1EF4, 0x0036, - 0x005C, 0x1F63, 0x003F, 0x05B3, 0x032B, 0x1EF7, 0x002D, - 0x0059, 0x1F71, 0x001B, 0x059D, 0x035F, 0x1EFB, 0x0024, - 0x0057, 0x1F7F, 0x1FF9, 0x0583, 0x0392, 0x1F02, 0x001A, - 0x0053, 0x1F8D, 0x1FD9, 0x0567, 0x03C5, 0x1F0B, 0x0010, - 0x0050, 0x1F9B, 0x1FBB, 0x0548, 0x03F8, 0x1F15, 0x0005, - 0x004C, 0x1FA9, 0x1F9E, 0x0528, 0x042A, 0x1F22, 0x1FF9, - 0x0048, 0x1FB7, 0x1F84, 0x0505, 0x045A, 0x1F31, 0x1FED, - 0x0043, 0x1FC5, 0x1F6C, 0x04E0, 0x048A, 0x1F42, 0x1FE0, - 0x1FD1, 0x1F50, 0x04DF, 0x04DF, 0x1F50, 0x1FD1, 0x0000, - 0x1FE0, 0x1F42, 0x048A, 0x04E0, 0x1F6C, 0x1FC5, 0x0043, - 0x1FED, 0x1F31, 0x045A, 0x0505, 0x1F84, 0x1FB7, 0x0048, - 0x1FF9, 0x1F22, 0x042A, 0x0528, 0x1F9E, 0x1FA9, 0x004C, - 0x0005, 0x1F15, 0x03F8, 0x0548, 0x1FBB, 0x1F9B, 0x0050, - 0x0010, 0x1F0B, 0x03C5, 0x0567, 0x1FD9, 0x1F8D, 0x0053, - 0x001A, 0x1F02, 0x0392, 0x0583, 0x1FF9, 0x1F7F, 0x0057, - 0x0024, 0x1EFB, 0x035F, 0x059D, 0x001B, 0x1F71, 0x0059, - 0x002D, 0x1EF7, 0x032B, 0x05B3, 0x003F, 0x1F63, 0x005C, - 0x0036, 0x1EF4, 0x02F6, 0x05C7, 0x0065, 0x1F56, 0x005E, - 0x003D, 0x1EF2, 0x02C3, 0x05DA, 0x008C, 0x1F49, 0x005F, - 0x0044, 0x1EF3, 0x028F, 0x05E8, 0x00B5, 0x1F3D, 0x0060, - 0x004A, 0x1EF5, 0x025C, 0x05F5, 0x00DF, 0x1F31, 0x0060, - 0x004F, 0x1EF8, 0x0229, 0x05FF, 0x010B, 0x1F26, 0x0060, - 0x0054, 0x1EFD, 0x01F7, 0x0605, 0x0138, 0x1F1C, 0x005F, - 0x0058, 0x1F03, 0x01C6, 0x0609, 0x0166, 0x1F13, 0x005D, - /* Chroma */ - 0x005B, 0x1F0A, 0x0195, 0x060C, 0x0195, 0x1F0A, 0x005B, - 0x005D, 0x1F13, 0x0166, 0x0609, 0x01C6, 0x1F03, 0x0058, - 0x005F, 0x1F1C, 0x0138, 0x0605, 0x01F7, 0x1EFD, 0x0054, - 0x0060, 0x1F26, 0x010B, 0x05FF, 0x0229, 0x1EF8, 0x004F, - 0x0060, 0x1F31, 0x00DF, 0x05F5, 0x025C, 0x1EF5, 0x004A, - 0x0060, 0x1F3D, 0x00B5, 0x05E8, 0x028F, 0x1EF3, 0x0044, - 0x005F, 0x1F49, 0x008C, 0x05DA, 0x02C3, 0x1EF2, 0x003D, - 0x005E, 0x1F56, 0x0065, 0x05C7, 0x02F6, 0x1EF4, 0x0036, - 0x005C, 0x1F63, 0x003F, 0x05B3, 0x032B, 0x1EF7, 0x002D, - 0x0059, 0x1F71, 0x001B, 0x059D, 0x035F, 0x1EFB, 0x0024, - 0x0057, 0x1F7F, 0x1FF9, 0x0583, 0x0392, 0x1F02, 0x001A, - 0x0053, 0x1F8D, 0x1FD9, 0x0567, 0x03C5, 0x1F0B, 0x0010, - 0x0050, 0x1F9B, 0x1FBB, 0x0548, 0x03F8, 0x1F15, 0x0005, - 0x004C, 0x1FA9, 0x1F9E, 0x0528, 0x042A, 0x1F22, 0x1FF9, - 0x0048, 0x1FB7, 0x1F84, 0x0505, 0x045A, 0x1F31, 0x1FED, - 0x0043, 0x1FC5, 0x1F6C, 0x04E0, 0x048A, 0x1F42, 0x1FE0, - 0x1FD1, 0x1F50, 0x04DF, 0x04DF, 0x1F50, 0x1FD1, 0x0000, - 0x1FE0, 0x1F42, 0x048A, 0x04E0, 0x1F6C, 0x1FC5, 0x0043, - 0x1FED, 0x1F31, 0x045A, 0x0505, 0x1F84, 0x1FB7, 0x0048, - 0x1FF9, 0x1F22, 0x042A, 0x0528, 0x1F9E, 0x1FA9, 0x004C, - 0x0005, 0x1F15, 0x03F8, 0x0548, 0x1FBB, 0x1F9B, 0x0050, - 0x0010, 0x1F0B, 0x03C5, 0x0567, 0x1FD9, 0x1F8D, 0x0053, - 0x001A, 0x1F02, 0x0392, 0x0583, 0x1FF9, 0x1F7F, 0x0057, - 0x0024, 0x1EFB, 0x035F, 0x059D, 0x001B, 0x1F71, 0x0059, - 0x002D, 0x1EF7, 0x032B, 0x05B3, 0x003F, 0x1F63, 0x005C, - 0x0036, 0x1EF4, 0x02F6, 0x05C7, 0x0065, 0x1F56, 0x005E, - 0x003D, 0x1EF2, 0x02C3, 0x05DA, 0x008C, 0x1F49, 0x005F, - 0x0044, 0x1EF3, 0x028F, 0x05E8, 0x00B5, 0x1F3D, 0x0060, - 0x004A, 0x1EF5, 0x025C, 0x05F5, 0x00DF, 0x1F31, 0x0060, - 0x004F, 0x1EF8, 0x0229, 0x05FF, 0x010B, 0x1F26, 0x0060, - 0x0054, 0x1EFD, 0x01F7, 0x0605, 0x0138, 0x1F1C, 0x005F, - 0x0058, 0x1F03, 0x01C6, 0x0609, 0x0166, 0x1F13, 0x005D, - }, - [HS_LE_16_16_SCALE] = { - /* Luma */ - 0x006E, 0x1F24, 0x013E, 0x0660, 0x013E, 0x1F24, 0x006E, - 0x006C, 0x1F33, 0x010B, 0x065D, 0x0172, 0x1F17, 0x0070, - 0x0069, 0x1F41, 0x00DA, 0x0659, 0x01A8, 0x1F0B, 0x0070, - 0x0066, 0x1F51, 0x00AA, 0x0650, 0x01DF, 0x1F00, 0x0070, - 0x0062, 0x1F61, 0x007D, 0x0644, 0x0217, 0x1EF6, 0x006F, - 0x005E, 0x1F71, 0x0051, 0x0636, 0x0250, 0x1EED, 0x006D, - 0x0059, 0x1F81, 0x0028, 0x0624, 0x028A, 0x1EE5, 0x006B, - 0x0054, 0x1F91, 0x0000, 0x060F, 0x02C5, 0x1EE0, 0x0067, - 0x004E, 0x1FA2, 0x1FDB, 0x05F6, 0x0300, 0x1EDC, 0x0063, - 0x0049, 0x1FB2, 0x1FB8, 0x05DB, 0x033B, 0x1EDA, 0x005D, - 0x0043, 0x1FC3, 0x1F98, 0x05BC, 0x0376, 0x1ED9, 0x0057, - 0x003D, 0x1FD3, 0x1F7A, 0x059B, 0x03B1, 0x1EDB, 0x004F, - 0x0036, 0x1FE2, 0x1F5E, 0x0578, 0x03EC, 0x1EDF, 0x0047, - 0x0030, 0x1FF1, 0x1F45, 0x0551, 0x0426, 0x1EE6, 0x003D, - 0x002A, 0x0000, 0x1F2E, 0x0528, 0x045F, 0x1EEE, 0x0033, - 0x0023, 0x000E, 0x1F19, 0x04FD, 0x0498, 0x1EFA, 0x0027, - 0x001B, 0x1F04, 0x04E1, 0x04E1, 0x1F04, 0x001B, 0x0000, - 0x0027, 0x1EFA, 0x0498, 0x04FD, 0x1F19, 0x000E, 0x0023, - 0x0033, 0x1EEE, 0x045F, 0x0528, 0x1F2E, 0x0000, 0x002A, - 0x003D, 0x1EE6, 0x0426, 0x0551, 0x1F45, 0x1FF1, 0x0030, - 0x0047, 0x1EDF, 0x03EC, 0x0578, 0x1F5E, 0x1FE2, 0x0036, - 0x004F, 0x1EDB, 0x03B1, 0x059B, 0x1F7A, 0x1FD3, 0x003D, - 0x0057, 0x1ED9, 0x0376, 0x05BC, 0x1F98, 0x1FC3, 0x0043, - 0x005D, 0x1EDA, 0x033B, 0x05DB, 0x1FB8, 0x1FB2, 0x0049, - 0x0063, 0x1EDC, 0x0300, 0x05F6, 0x1FDB, 0x1FA2, 0x004E, - 0x0067, 0x1EE0, 0x02C5, 0x060F, 0x0000, 0x1F91, 0x0054, - 0x006B, 0x1EE5, 0x028A, 0x0624, 0x0028, 0x1F81, 0x0059, - 0x006D, 0x1EED, 0x0250, 0x0636, 0x0051, 0x1F71, 0x005E, - 0x006F, 0x1EF6, 0x0217, 0x0644, 0x007D, 0x1F61, 0x0062, - 0x0070, 0x1F00, 0x01DF, 0x0650, 0x00AA, 0x1F51, 0x0066, - 0x0070, 0x1F0B, 0x01A8, 0x0659, 0x00DA, 0x1F41, 0x0069, - 0x0070, 0x1F17, 0x0172, 0x065D, 0x010B, 0x1F33, 0x006C, - /* Chroma */ - 0x006E, 0x1F24, 0x013E, 0x0660, 0x013E, 0x1F24, 0x006E, - 0x006C, 0x1F33, 0x010B, 0x065D, 0x0172, 0x1F17, 0x0070, - 0x0069, 0x1F41, 0x00DA, 0x0659, 0x01A8, 0x1F0B, 0x0070, - 0x0066, 0x1F51, 0x00AA, 0x0650, 0x01DF, 0x1F00, 0x0070, - 0x0062, 0x1F61, 0x007D, 0x0644, 0x0217, 0x1EF6, 0x006F, - 0x005E, 0x1F71, 0x0051, 0x0636, 0x0250, 0x1EED, 0x006D, - 0x0059, 0x1F81, 0x0028, 0x0624, 0x028A, 0x1EE5, 0x006B, - 0x0054, 0x1F91, 0x0000, 0x060F, 0x02C5, 0x1EE0, 0x0067, - 0x004E, 0x1FA2, 0x1FDB, 0x05F6, 0x0300, 0x1EDC, 0x0063, - 0x0049, 0x1FB2, 0x1FB8, 0x05DB, 0x033B, 0x1EDA, 0x005D, - 0x0043, 0x1FC3, 0x1F98, 0x05BC, 0x0376, 0x1ED9, 0x0057, - 0x003D, 0x1FD3, 0x1F7A, 0x059B, 0x03B1, 0x1EDB, 0x004F, - 0x0036, 0x1FE2, 0x1F5E, 0x0578, 0x03EC, 0x1EDF, 0x0047, - 0x0030, 0x1FF1, 0x1F45, 0x0551, 0x0426, 0x1EE6, 0x003D, - 0x002A, 0x0000, 0x1F2E, 0x0528, 0x045F, 0x1EEE, 0x0033, - 0x0023, 0x000E, 0x1F19, 0x04FD, 0x0498, 0x1EFA, 0x0027, - 0x001B, 0x1F04, 0x04E1, 0x04E1, 0x1F04, 0x001B, 0x0000, - 0x0027, 0x1EFA, 0x0498, 0x04FD, 0x1F19, 0x000E, 0x0023, - 0x0033, 0x1EEE, 0x045F, 0x0528, 0x1F2E, 0x0000, 0x002A, - 0x003D, 0x1EE6, 0x0426, 0x0551, 0x1F45, 0x1FF1, 0x0030, - 0x0047, 0x1EDF, 0x03EC, 0x0578, 0x1F5E, 0x1FE2, 0x0036, - 0x004F, 0x1EDB, 0x03B1, 0x059B, 0x1F7A, 0x1FD3, 0x003D, - 0x0057, 0x1ED9, 0x0376, 0x05BC, 0x1F98, 0x1FC3, 0x0043, - 0x005D, 0x1EDA, 0x033B, 0x05DB, 0x1FB8, 0x1FB2, 0x0049, - 0x0063, 0x1EDC, 0x0300, 0x05F6, 0x1FDB, 0x1FA2, 0x004E, - 0x0067, 0x1EE0, 0x02C5, 0x060F, 0x0000, 0x1F91, 0x0054, - 0x006B, 0x1EE5, 0x028A, 0x0624, 0x0028, 0x1F81, 0x0059, - 0x006D, 0x1EED, 0x0250, 0x0636, 0x0051, 0x1F71, 0x005E, - 0x006F, 0x1EF6, 0x0217, 0x0644, 0x007D, 0x1F61, 0x0062, - 0x0070, 0x1F00, 0x01DF, 0x0650, 0x00AA, 0x1F51, 0x0066, - 0x0070, 0x1F0B, 0x01A8, 0x0659, 0x00DA, 0x1F41, 0x0069, - 0x0070, 0x1F17, 0x0172, 0x065D, 0x010B, 0x1F33, 0x006C, - }, -}; - -/* vertical scaler coefficients */ -enum { - VS_UP_SCALE = 0, - VS_LT_9_16_SCALE, - VS_LT_10_16_SCALE, - VS_LT_11_16_SCALE, - VS_LT_12_16_SCALE, - VS_LT_13_16_SCALE, - VS_LT_14_16_SCALE, - VS_LT_15_16_SCALE, - VS_LT_16_16_SCALE, - VS_1_TO_1_SCALE, -}; - -static const u16 scaler_vs_coeffs[15][SC_NUM_PHASES * 2 * SC_V_NUM_TAPS] = { - [VS_UP_SCALE] = { - /* Luma */ - 0x1FD1, 0x00B1, 0x06FC, 0x00B1, 0x1FD1, - 0x1FD8, 0x0085, 0x06F9, 0x00E1, 0x1FC9, - 0x1FDF, 0x005B, 0x06F2, 0x0114, 0x1FC0, - 0x1FE5, 0x0035, 0x06E5, 0x014A, 0x1FB7, - 0x1FEB, 0x0012, 0x06D3, 0x0182, 0x1FAE, - 0x1FF1, 0x1FF3, 0x06BA, 0x01BD, 0x1FA5, - 0x1FF5, 0x1FD7, 0x069D, 0x01FB, 0x1F9C, - 0x1FF9, 0x1FBE, 0x067C, 0x023A, 0x1F93, - 0x1FFD, 0x1FA8, 0x0656, 0x027B, 0x1F8A, - 0x0000, 0x1F95, 0x062B, 0x02BF, 0x1F81, - 0x0002, 0x1F86, 0x05FC, 0x0303, 0x1F79, - 0x0004, 0x1F79, 0x05CA, 0x0347, 0x1F72, - 0x0005, 0x1F6F, 0x0594, 0x038D, 0x1F6B, - 0x0006, 0x1F67, 0x055B, 0x03D2, 0x1F66, - 0x0007, 0x1F62, 0x051E, 0x0417, 0x1F62, - 0x0007, 0x1F5F, 0x04DF, 0x045C, 0x1F5F, - 0x1F5E, 0x04A2, 0x04A2, 0x1F5E, 0x0000, - 0x1F5F, 0x045C, 0x04DF, 0x1F5F, 0x0007, - 0x1F62, 0x0417, 0x051E, 0x1F62, 0x0007, - 0x1F66, 0x03D2, 0x055B, 0x1F67, 0x0006, - 0x1F6B, 0x038D, 0x0594, 0x1F6F, 0x0005, - 0x1F72, 0x0347, 0x05CA, 0x1F79, 0x0004, - 0x1F79, 0x0303, 0x05FC, 0x1F86, 0x0002, - 0x1F81, 0x02BF, 0x062B, 0x1F95, 0x0000, - 0x1F8A, 0x027B, 0x0656, 0x1FA8, 0x1FFD, - 0x1F93, 0x023A, 0x067C, 0x1FBE, 0x1FF9, - 0x1F9C, 0x01FB, 0x069D, 0x1FD7, 0x1FF5, - 0x1FA5, 0x01BD, 0x06BA, 0x1FF3, 0x1FF1, - 0x1FAE, 0x0182, 0x06D3, 0x0012, 0x1FEB, - 0x1FB7, 0x014A, 0x06E5, 0x0035, 0x1FE5, - 0x1FC0, 0x0114, 0x06F2, 0x005B, 0x1FDF, - 0x1FC9, 0x00E1, 0x06F9, 0x0085, 0x1FD8, - /* Chroma */ - 0x1FD1, 0x00B1, 0x06FC, 0x00B1, 0x1FD1, - 0x1FD8, 0x0085, 0x06F9, 0x00E1, 0x1FC9, - 0x1FDF, 0x005B, 0x06F2, 0x0114, 0x1FC0, - 0x1FE5, 0x0035, 0x06E5, 0x014A, 0x1FB7, - 0x1FEB, 0x0012, 0x06D3, 0x0182, 0x1FAE, - 0x1FF1, 0x1FF3, 0x06BA, 0x01BD, 0x1FA5, - 0x1FF5, 0x1FD7, 0x069D, 0x01FB, 0x1F9C, - 0x1FF9, 0x1FBE, 0x067C, 0x023A, 0x1F93, - 0x1FFD, 0x1FA8, 0x0656, 0x027B, 0x1F8A, - 0x0000, 0x1F95, 0x062B, 0x02BF, 0x1F81, - 0x0002, 0x1F86, 0x05FC, 0x0303, 0x1F79, - 0x0004, 0x1F79, 0x05CA, 0x0347, 0x1F72, - 0x0005, 0x1F6F, 0x0594, 0x038D, 0x1F6B, - 0x0006, 0x1F67, 0x055B, 0x03D2, 0x1F66, - 0x0007, 0x1F62, 0x051E, 0x0417, 0x1F62, - 0x0007, 0x1F5F, 0x04DF, 0x045C, 0x1F5F, - 0x1F5E, 0x04A2, 0x04A2, 0x1F5E, 0x0000, - 0x1F5F, 0x045C, 0x04DF, 0x1F5F, 0x0007, - 0x1F62, 0x0417, 0x051E, 0x1F62, 0x0007, - 0x1F66, 0x03D2, 0x055B, 0x1F67, 0x0006, - 0x1F6B, 0x038D, 0x0594, 0x1F6F, 0x0005, - 0x1F72, 0x0347, 0x05CA, 0x1F79, 0x0004, - 0x1F79, 0x0303, 0x05FC, 0x1F86, 0x0002, - 0x1F81, 0x02BF, 0x062B, 0x1F95, 0x0000, - 0x1F8A, 0x027B, 0x0656, 0x1FA8, 0x1FFD, - 0x1F93, 0x023A, 0x067C, 0x1FBE, 0x1FF9, - 0x1F9C, 0x01FB, 0x069D, 0x1FD7, 0x1FF5, - 0x1FA5, 0x01BD, 0x06BA, 0x1FF3, 0x1FF1, - 0x1FAE, 0x0182, 0x06D3, 0x0012, 0x1FEB, - 0x1FB7, 0x014A, 0x06E5, 0x0035, 0x1FE5, - 0x1FC0, 0x0114, 0x06F2, 0x005B, 0x1FDF, - 0x1FC9, 0x00E1, 0x06F9, 0x0085, 0x1FD8, - }, - [VS_LT_9_16_SCALE] = { - /* Luma */ - 0x001C, 0x01F6, 0x03DC, 0x01F6, 0x001C, - 0x0018, 0x01DF, 0x03DB, 0x020C, 0x0022, - 0x0013, 0x01C9, 0x03D9, 0x0223, 0x0028, - 0x000F, 0x01B3, 0x03D6, 0x023A, 0x002E, - 0x000C, 0x019D, 0x03D2, 0x0250, 0x0035, - 0x0009, 0x0188, 0x03CC, 0x0266, 0x003D, - 0x0006, 0x0173, 0x03C5, 0x027D, 0x0045, - 0x0004, 0x015E, 0x03BD, 0x0293, 0x004E, - 0x0002, 0x014A, 0x03B4, 0x02A8, 0x0058, - 0x0000, 0x0136, 0x03AA, 0x02BE, 0x0062, - 0x1FFF, 0x0123, 0x039E, 0x02D3, 0x006D, - 0x1FFE, 0x0110, 0x0392, 0x02E8, 0x0078, - 0x1FFD, 0x00FE, 0x0384, 0x02FC, 0x0085, - 0x1FFD, 0x00ED, 0x0376, 0x030F, 0x0091, - 0x1FFC, 0x00DC, 0x0367, 0x0322, 0x009F, - 0x1FFC, 0x00CC, 0x0357, 0x0334, 0x00AD, - 0x00BC, 0x0344, 0x0344, 0x00BC, 0x0000, - 0x00AD, 0x0334, 0x0357, 0x00CC, 0x1FFC, - 0x009F, 0x0322, 0x0367, 0x00DC, 0x1FFC, - 0x0091, 0x030F, 0x0376, 0x00ED, 0x1FFD, - 0x0085, 0x02FC, 0x0384, 0x00FE, 0x1FFD, - 0x0078, 0x02E8, 0x0392, 0x0110, 0x1FFE, - 0x006D, 0x02D3, 0x039E, 0x0123, 0x1FFF, - 0x0062, 0x02BE, 0x03AA, 0x0136, 0x0000, - 0x0058, 0x02A8, 0x03B4, 0x014A, 0x0002, - 0x004E, 0x0293, 0x03BD, 0x015E, 0x0004, - 0x0045, 0x027D, 0x03C5, 0x0173, 0x0006, - 0x003D, 0x0266, 0x03CC, 0x0188, 0x0009, - 0x0035, 0x0250, 0x03D2, 0x019D, 0x000C, - 0x002E, 0x023A, 0x03D6, 0x01B3, 0x000F, - 0x0028, 0x0223, 0x03D9, 0x01C9, 0x0013, - 0x0022, 0x020C, 0x03DB, 0x01DF, 0x0018, - /* Chroma */ - 0x001C, 0x01F6, 0x03DC, 0x01F6, 0x001C, - 0x0018, 0x01DF, 0x03DB, 0x020C, 0x0022, - 0x0013, 0x01C9, 0x03D9, 0x0223, 0x0028, - 0x000F, 0x01B3, 0x03D6, 0x023A, 0x002E, - 0x000C, 0x019D, 0x03D2, 0x0250, 0x0035, - 0x0009, 0x0188, 0x03CC, 0x0266, 0x003D, - 0x0006, 0x0173, 0x03C5, 0x027D, 0x0045, - 0x0004, 0x015E, 0x03BD, 0x0293, 0x004E, - 0x0002, 0x014A, 0x03B4, 0x02A8, 0x0058, - 0x0000, 0x0136, 0x03AA, 0x02BE, 0x0062, - 0x1FFF, 0x0123, 0x039E, 0x02D3, 0x006D, - 0x1FFE, 0x0110, 0x0392, 0x02E8, 0x0078, - 0x1FFD, 0x00FE, 0x0384, 0x02FC, 0x0085, - 0x1FFD, 0x00ED, 0x0376, 0x030F, 0x0091, - 0x1FFC, 0x00DC, 0x0367, 0x0322, 0x009F, - 0x1FFC, 0x00CC, 0x0357, 0x0334, 0x00AD, - 0x00BC, 0x0344, 0x0344, 0x00BC, 0x0000, - 0x00AD, 0x0334, 0x0357, 0x00CC, 0x1FFC, - 0x009F, 0x0322, 0x0367, 0x00DC, 0x1FFC, - 0x0091, 0x030F, 0x0376, 0x00ED, 0x1FFD, - 0x0085, 0x02FC, 0x0384, 0x00FE, 0x1FFD, - 0x0078, 0x02E8, 0x0392, 0x0110, 0x1FFE, - 0x006D, 0x02D3, 0x039E, 0x0123, 0x1FFF, - 0x0062, 0x02BE, 0x03AA, 0x0136, 0x0000, - 0x0058, 0x02A8, 0x03B4, 0x014A, 0x0002, - 0x004E, 0x0293, 0x03BD, 0x015E, 0x0004, - 0x0045, 0x027D, 0x03C5, 0x0173, 0x0006, - 0x003D, 0x0266, 0x03CC, 0x0188, 0x0009, - 0x0035, 0x0250, 0x03D2, 0x019D, 0x000C, - 0x002E, 0x023A, 0x03D6, 0x01B3, 0x000F, - 0x0028, 0x0223, 0x03D9, 0x01C9, 0x0013, - 0x0022, 0x020C, 0x03DB, 0x01DF, 0x0018, - }, - [VS_LT_10_16_SCALE] = { - /* Luma */ - 0x0003, 0x01E9, 0x0428, 0x01E9, 0x0003, - 0x0000, 0x01D0, 0x0426, 0x0203, 0x0007, - 0x1FFD, 0x01B7, 0x0424, 0x021C, 0x000C, - 0x1FFB, 0x019E, 0x0420, 0x0236, 0x0011, - 0x1FF9, 0x0186, 0x041A, 0x0250, 0x0017, - 0x1FF7, 0x016E, 0x0414, 0x026A, 0x001D, - 0x1FF6, 0x0157, 0x040B, 0x0284, 0x0024, - 0x1FF5, 0x0140, 0x0401, 0x029E, 0x002C, - 0x1FF4, 0x012A, 0x03F6, 0x02B7, 0x0035, - 0x1FF4, 0x0115, 0x03E9, 0x02D0, 0x003E, - 0x1FF4, 0x0100, 0x03DB, 0x02E9, 0x0048, - 0x1FF4, 0x00EC, 0x03CC, 0x0301, 0x0053, - 0x1FF4, 0x00D9, 0x03BC, 0x0318, 0x005F, - 0x1FF5, 0x00C7, 0x03AA, 0x032F, 0x006B, - 0x1FF6, 0x00B5, 0x0398, 0x0345, 0x0078, - 0x1FF6, 0x00A5, 0x0384, 0x035B, 0x0086, - 0x0094, 0x036C, 0x036C, 0x0094, 0x0000, - 0x0086, 0x035B, 0x0384, 0x00A5, 0x1FF6, - 0x0078, 0x0345, 0x0398, 0x00B5, 0x1FF6, - 0x006B, 0x032F, 0x03AA, 0x00C7, 0x1FF5, - 0x005F, 0x0318, 0x03BC, 0x00D9, 0x1FF4, - 0x0053, 0x0301, 0x03CC, 0x00EC, 0x1FF4, - 0x0048, 0x02E9, 0x03DB, 0x0100, 0x1FF4, - 0x003E, 0x02D0, 0x03E9, 0x0115, 0x1FF4, - 0x0035, 0x02B7, 0x03F6, 0x012A, 0x1FF4, - 0x002C, 0x029E, 0x0401, 0x0140, 0x1FF5, - 0x0024, 0x0284, 0x040B, 0x0157, 0x1FF6, - 0x001D, 0x026A, 0x0414, 0x016E, 0x1FF7, - 0x0017, 0x0250, 0x041A, 0x0186, 0x1FF9, - 0x0011, 0x0236, 0x0420, 0x019E, 0x1FFB, - 0x000C, 0x021C, 0x0424, 0x01B7, 0x1FFD, - 0x0007, 0x0203, 0x0426, 0x01D0, 0x0000, - /* Chroma */ - 0x0003, 0x01E9, 0x0428, 0x01E9, 0x0003, - 0x0000, 0x01D0, 0x0426, 0x0203, 0x0007, - 0x1FFD, 0x01B7, 0x0424, 0x021C, 0x000C, - 0x1FFB, 0x019E, 0x0420, 0x0236, 0x0011, - 0x1FF9, 0x0186, 0x041A, 0x0250, 0x0017, - 0x1FF7, 0x016E, 0x0414, 0x026A, 0x001D, - 0x1FF6, 0x0157, 0x040B, 0x0284, 0x0024, - 0x1FF5, 0x0140, 0x0401, 0x029E, 0x002C, - 0x1FF4, 0x012A, 0x03F6, 0x02B7, 0x0035, - 0x1FF4, 0x0115, 0x03E9, 0x02D0, 0x003E, - 0x1FF4, 0x0100, 0x03DB, 0x02E9, 0x0048, - 0x1FF4, 0x00EC, 0x03CC, 0x0301, 0x0053, - 0x1FF4, 0x00D9, 0x03BC, 0x0318, 0x005F, - 0x1FF5, 0x00C7, 0x03AA, 0x032F, 0x006B, - 0x1FF6, 0x00B5, 0x0398, 0x0345, 0x0078, - 0x1FF6, 0x00A5, 0x0384, 0x035B, 0x0086, - 0x0094, 0x036C, 0x036C, 0x0094, 0x0000, - 0x0086, 0x035B, 0x0384, 0x00A5, 0x1FF6, - 0x0078, 0x0345, 0x0398, 0x00B5, 0x1FF6, - 0x006B, 0x032F, 0x03AA, 0x00C7, 0x1FF5, - 0x005F, 0x0318, 0x03BC, 0x00D9, 0x1FF4, - 0x0053, 0x0301, 0x03CC, 0x00EC, 0x1FF4, - 0x0048, 0x02E9, 0x03DB, 0x0100, 0x1FF4, - 0x003E, 0x02D0, 0x03E9, 0x0115, 0x1FF4, - 0x0035, 0x02B7, 0x03F6, 0x012A, 0x1FF4, - 0x002C, 0x029E, 0x0401, 0x0140, 0x1FF5, - 0x0024, 0x0284, 0x040B, 0x0157, 0x1FF6, - 0x001D, 0x026A, 0x0414, 0x016E, 0x1FF7, - 0x0017, 0x0250, 0x041A, 0x0186, 0x1FF9, - 0x0011, 0x0236, 0x0420, 0x019E, 0x1FFB, - 0x000C, 0x021C, 0x0424, 0x01B7, 0x1FFD, - 0x0007, 0x0203, 0x0426, 0x01D0, 0x0000, - }, - [VS_LT_11_16_SCALE] = { - /* Luma */ - 0x1FEC, 0x01D6, 0x047C, 0x01D6, 0x1FEC, - 0x1FEA, 0x01BA, 0x047B, 0x01F3, 0x1FEE, - 0x1FE9, 0x019D, 0x0478, 0x0211, 0x1FF1, - 0x1FE8, 0x0182, 0x0473, 0x022E, 0x1FF5, - 0x1FE8, 0x0167, 0x046C, 0x024C, 0x1FF9, - 0x1FE8, 0x014D, 0x0464, 0x026A, 0x1FFD, - 0x1FE8, 0x0134, 0x0459, 0x0288, 0x0003, - 0x1FE9, 0x011B, 0x044D, 0x02A6, 0x0009, - 0x1FE9, 0x0104, 0x0440, 0x02C3, 0x0010, - 0x1FEA, 0x00ED, 0x0430, 0x02E1, 0x0018, - 0x1FEB, 0x00D7, 0x0420, 0x02FD, 0x0021, - 0x1FED, 0x00C2, 0x040D, 0x0319, 0x002B, - 0x1FEE, 0x00AE, 0x03F9, 0x0336, 0x0035, - 0x1FF0, 0x009C, 0x03E3, 0x0350, 0x0041, - 0x1FF1, 0x008A, 0x03CD, 0x036B, 0x004D, - 0x1FF3, 0x0079, 0x03B5, 0x0384, 0x005B, - 0x0069, 0x0397, 0x0397, 0x0069, 0x0000, - 0x005B, 0x0384, 0x03B5, 0x0079, 0x1FF3, - 0x004D, 0x036B, 0x03CD, 0x008A, 0x1FF1, - 0x0041, 0x0350, 0x03E3, 0x009C, 0x1FF0, - 0x0035, 0x0336, 0x03F9, 0x00AE, 0x1FEE, - 0x002B, 0x0319, 0x040D, 0x00C2, 0x1FED, - 0x0021, 0x02FD, 0x0420, 0x00D7, 0x1FEB, - 0x0018, 0x02E1, 0x0430, 0x00ED, 0x1FEA, - 0x0010, 0x02C3, 0x0440, 0x0104, 0x1FE9, - 0x0009, 0x02A6, 0x044D, 0x011B, 0x1FE9, - 0x0003, 0x0288, 0x0459, 0x0134, 0x1FE8, - 0x1FFD, 0x026A, 0x0464, 0x014D, 0x1FE8, - 0x1FF9, 0x024C, 0x046C, 0x0167, 0x1FE8, - 0x1FF5, 0x022E, 0x0473, 0x0182, 0x1FE8, - 0x1FF1, 0x0211, 0x0478, 0x019D, 0x1FE9, - 0x1FEE, 0x01F3, 0x047B, 0x01BA, 0x1FEA, - /* Chroma */ - 0x1FEC, 0x01D6, 0x047C, 0x01D6, 0x1FEC, - 0x1FEA, 0x01BA, 0x047B, 0x01F3, 0x1FEE, - 0x1FE9, 0x019D, 0x0478, 0x0211, 0x1FF1, - 0x1FE8, 0x0182, 0x0473, 0x022E, 0x1FF5, - 0x1FE8, 0x0167, 0x046C, 0x024C, 0x1FF9, - 0x1FE8, 0x014D, 0x0464, 0x026A, 0x1FFD, - 0x1FE8, 0x0134, 0x0459, 0x0288, 0x0003, - 0x1FE9, 0x011B, 0x044D, 0x02A6, 0x0009, - 0x1FE9, 0x0104, 0x0440, 0x02C3, 0x0010, - 0x1FEA, 0x00ED, 0x0430, 0x02E1, 0x0018, - 0x1FEB, 0x00D7, 0x0420, 0x02FD, 0x0021, - 0x1FED, 0x00C2, 0x040D, 0x0319, 0x002B, - 0x1FEE, 0x00AE, 0x03F9, 0x0336, 0x0035, - 0x1FF0, 0x009C, 0x03E3, 0x0350, 0x0041, - 0x1FF1, 0x008A, 0x03CD, 0x036B, 0x004D, - 0x1FF3, 0x0079, 0x03B5, 0x0384, 0x005B, - 0x0069, 0x0397, 0x0397, 0x0069, 0x0000, - 0x005B, 0x0384, 0x03B5, 0x0079, 0x1FF3, - 0x004D, 0x036B, 0x03CD, 0x008A, 0x1FF1, - 0x0041, 0x0350, 0x03E3, 0x009C, 0x1FF0, - 0x0035, 0x0336, 0x03F9, 0x00AE, 0x1FEE, - 0x002B, 0x0319, 0x040D, 0x00C2, 0x1FED, - 0x0021, 0x02FD, 0x0420, 0x00D7, 0x1FEB, - 0x0018, 0x02E1, 0x0430, 0x00ED, 0x1FEA, - 0x0010, 0x02C3, 0x0440, 0x0104, 0x1FE9, - 0x0009, 0x02A6, 0x044D, 0x011B, 0x1FE9, - 0x0003, 0x0288, 0x0459, 0x0134, 0x1FE8, - 0x1FFD, 0x026A, 0x0464, 0x014D, 0x1FE8, - 0x1FF9, 0x024C, 0x046C, 0x0167, 0x1FE8, - 0x1FF5, 0x022E, 0x0473, 0x0182, 0x1FE8, - 0x1FF1, 0x0211, 0x0478, 0x019D, 0x1FE9, - 0x1FEE, 0x01F3, 0x047B, 0x01BA, 0x1FEA, - }, - [VS_LT_12_16_SCALE] = { - /* Luma */ - 0x1FD8, 0x01BC, 0x04D8, 0x01BC, 0x1FD8, - 0x1FD8, 0x019C, 0x04D8, 0x01DC, 0x1FD8, - 0x1FD8, 0x017D, 0x04D4, 0x01FE, 0x1FD9, - 0x1FD9, 0x015E, 0x04CF, 0x0220, 0x1FDA, - 0x1FDB, 0x0141, 0x04C7, 0x0241, 0x1FDC, - 0x1FDC, 0x0125, 0x04BC, 0x0264, 0x1FDF, - 0x1FDE, 0x0109, 0x04B0, 0x0286, 0x1FE3, - 0x1FE0, 0x00EF, 0x04A1, 0x02A9, 0x1FE7, - 0x1FE2, 0x00D6, 0x0491, 0x02CB, 0x1FEC, - 0x1FE4, 0x00BE, 0x047E, 0x02EE, 0x1FF2, - 0x1FE6, 0x00A7, 0x046A, 0x030F, 0x1FFA, - 0x1FE9, 0x0092, 0x0453, 0x0330, 0x0002, - 0x1FEB, 0x007E, 0x043B, 0x0351, 0x000B, - 0x1FED, 0x006B, 0x0421, 0x0372, 0x0015, - 0x1FEF, 0x005A, 0x0406, 0x0391, 0x0020, - 0x1FF1, 0x0049, 0x03EA, 0x03AF, 0x002D, - 0x003A, 0x03C6, 0x03C6, 0x003A, 0x0000, - 0x002D, 0x03AF, 0x03EA, 0x0049, 0x1FF1, - 0x0020, 0x0391, 0x0406, 0x005A, 0x1FEF, - 0x0015, 0x0372, 0x0421, 0x006B, 0x1FED, - 0x000B, 0x0351, 0x043B, 0x007E, 0x1FEB, - 0x0002, 0x0330, 0x0453, 0x0092, 0x1FE9, - 0x1FFA, 0x030F, 0x046A, 0x00A7, 0x1FE6, - 0x1FF2, 0x02EE, 0x047E, 0x00BE, 0x1FE4, - 0x1FEC, 0x02CB, 0x0491, 0x00D6, 0x1FE2, - 0x1FE7, 0x02A9, 0x04A1, 0x00EF, 0x1FE0, - 0x1FE3, 0x0286, 0x04B0, 0x0109, 0x1FDE, - 0x1FDF, 0x0264, 0x04BC, 0x0125, 0x1FDC, - 0x1FDC, 0x0241, 0x04C7, 0x0141, 0x1FDB, - 0x1FDA, 0x0220, 0x04CF, 0x015E, 0x1FD9, - 0x1FD9, 0x01FE, 0x04D4, 0x017D, 0x1FD8, - 0x1FD8, 0x01DC, 0x04D8, 0x019C, 0x1FD8, - /* Chroma */ - 0x1FD8, 0x01BC, 0x04D8, 0x01BC, 0x1FD8, - 0x1FD8, 0x019C, 0x04D8, 0x01DC, 0x1FD8, - 0x1FD8, 0x017D, 0x04D4, 0x01FE, 0x1FD9, - 0x1FD9, 0x015E, 0x04CF, 0x0220, 0x1FDA, - 0x1FDB, 0x0141, 0x04C7, 0x0241, 0x1FDC, - 0x1FDC, 0x0125, 0x04BC, 0x0264, 0x1FDF, - 0x1FDE, 0x0109, 0x04B0, 0x0286, 0x1FE3, - 0x1FE0, 0x00EF, 0x04A1, 0x02A9, 0x1FE7, - 0x1FE2, 0x00D6, 0x0491, 0x02CB, 0x1FEC, - 0x1FE4, 0x00BE, 0x047E, 0x02EE, 0x1FF2, - 0x1FE6, 0x00A7, 0x046A, 0x030F, 0x1FFA, - 0x1FE9, 0x0092, 0x0453, 0x0330, 0x0002, - 0x1FEB, 0x007E, 0x043B, 0x0351, 0x000B, - 0x1FED, 0x006B, 0x0421, 0x0372, 0x0015, - 0x1FEF, 0x005A, 0x0406, 0x0391, 0x0020, - 0x1FF1, 0x0049, 0x03EA, 0x03AF, 0x002D, - 0x003A, 0x03C6, 0x03C6, 0x003A, 0x0000, - 0x002D, 0x03AF, 0x03EA, 0x0049, 0x1FF1, - 0x0020, 0x0391, 0x0406, 0x005A, 0x1FEF, - 0x0015, 0x0372, 0x0421, 0x006B, 0x1FED, - 0x000B, 0x0351, 0x043B, 0x007E, 0x1FEB, - 0x0002, 0x0330, 0x0453, 0x0092, 0x1FE9, - 0x1FFA, 0x030F, 0x046A, 0x00A7, 0x1FE6, - 0x1FF2, 0x02EE, 0x047E, 0x00BE, 0x1FE4, - 0x1FEC, 0x02CB, 0x0491, 0x00D6, 0x1FE2, - 0x1FE7, 0x02A9, 0x04A1, 0x00EF, 0x1FE0, - 0x1FE3, 0x0286, 0x04B0, 0x0109, 0x1FDE, - 0x1FDF, 0x0264, 0x04BC, 0x0125, 0x1FDC, - 0x1FDC, 0x0241, 0x04C7, 0x0141, 0x1FDB, - 0x1FDA, 0x0220, 0x04CF, 0x015E, 0x1FD9, - 0x1FD9, 0x01FE, 0x04D4, 0x017D, 0x1FD8, - 0x1FD8, 0x01DC, 0x04D8, 0x019C, 0x1FD8, - }, - [VS_LT_13_16_SCALE] = { - /* Luma */ - 0x1FC8, 0x0199, 0x053E, 0x0199, 0x1FC8, - 0x1FCA, 0x0175, 0x053E, 0x01BD, 0x1FC6, - 0x1FCD, 0x0153, 0x0539, 0x01E2, 0x1FC5, - 0x1FCF, 0x0132, 0x0532, 0x0209, 0x1FC4, - 0x1FD2, 0x0112, 0x0529, 0x022F, 0x1FC4, - 0x1FD5, 0x00F4, 0x051C, 0x0256, 0x1FC5, - 0x1FD8, 0x00D7, 0x050D, 0x027E, 0x1FC6, - 0x1FDC, 0x00BB, 0x04FB, 0x02A6, 0x1FC8, - 0x1FDF, 0x00A1, 0x04E7, 0x02CE, 0x1FCB, - 0x1FE2, 0x0089, 0x04D1, 0x02F5, 0x1FCF, - 0x1FE5, 0x0072, 0x04B8, 0x031D, 0x1FD4, - 0x1FE8, 0x005D, 0x049E, 0x0344, 0x1FD9, - 0x1FEB, 0x0049, 0x0480, 0x036B, 0x1FE1, - 0x1FEE, 0x0037, 0x0462, 0x0390, 0x1FE9, - 0x1FF0, 0x0026, 0x0442, 0x03B6, 0x1FF2, - 0x1FF2, 0x0017, 0x0420, 0x03DA, 0x1FFD, - 0x0009, 0x03F7, 0x03F7, 0x0009, 0x0000, - 0x1FFD, 0x03DA, 0x0420, 0x0017, 0x1FF2, - 0x1FF2, 0x03B6, 0x0442, 0x0026, 0x1FF0, - 0x1FE9, 0x0390, 0x0462, 0x0037, 0x1FEE, - 0x1FE1, 0x036B, 0x0480, 0x0049, 0x1FEB, - 0x1FD9, 0x0344, 0x049E, 0x005D, 0x1FE8, - 0x1FD4, 0x031D, 0x04B8, 0x0072, 0x1FE5, - 0x1FCF, 0x02F5, 0x04D1, 0x0089, 0x1FE2, - 0x1FCB, 0x02CE, 0x04E7, 0x00A1, 0x1FDF, - 0x1FC8, 0x02A6, 0x04FB, 0x00BB, 0x1FDC, - 0x1FC6, 0x027E, 0x050D, 0x00D7, 0x1FD8, - 0x1FC5, 0x0256, 0x051C, 0x00F4, 0x1FD5, - 0x1FC4, 0x022F, 0x0529, 0x0112, 0x1FD2, - 0x1FC4, 0x0209, 0x0532, 0x0132, 0x1FCF, - 0x1FC5, 0x01E2, 0x0539, 0x0153, 0x1FCD, - 0x1FC6, 0x01BD, 0x053E, 0x0175, 0x1FCA, - /* Chroma */ - 0x1FC8, 0x0199, 0x053E, 0x0199, 0x1FC8, - 0x1FCA, 0x0175, 0x053E, 0x01BD, 0x1FC6, - 0x1FCD, 0x0153, 0x0539, 0x01E2, 0x1FC5, - 0x1FCF, 0x0132, 0x0532, 0x0209, 0x1FC4, - 0x1FD2, 0x0112, 0x0529, 0x022F, 0x1FC4, - 0x1FD5, 0x00F4, 0x051C, 0x0256, 0x1FC5, - 0x1FD8, 0x00D7, 0x050D, 0x027E, 0x1FC6, - 0x1FDC, 0x00BB, 0x04FB, 0x02A6, 0x1FC8, - 0x1FDF, 0x00A1, 0x04E7, 0x02CE, 0x1FCB, - 0x1FE2, 0x0089, 0x04D1, 0x02F5, 0x1FCF, - 0x1FE5, 0x0072, 0x04B8, 0x031D, 0x1FD4, - 0x1FE8, 0x005D, 0x049E, 0x0344, 0x1FD9, - 0x1FEB, 0x0049, 0x0480, 0x036B, 0x1FE1, - 0x1FEE, 0x0037, 0x0462, 0x0390, 0x1FE9, - 0x1FF0, 0x0026, 0x0442, 0x03B6, 0x1FF2, - 0x1FF2, 0x0017, 0x0420, 0x03DA, 0x1FFD, - 0x0009, 0x03F7, 0x03F7, 0x0009, 0x0000, - 0x1FFD, 0x03DA, 0x0420, 0x0017, 0x1FF2, - 0x1FF2, 0x03B6, 0x0442, 0x0026, 0x1FF0, - 0x1FE9, 0x0390, 0x0462, 0x0037, 0x1FEE, - 0x1FE1, 0x036B, 0x0480, 0x0049, 0x1FEB, - 0x1FD9, 0x0344, 0x049E, 0x005D, 0x1FE8, - 0x1FD4, 0x031D, 0x04B8, 0x0072, 0x1FE5, - 0x1FCF, 0x02F5, 0x04D1, 0x0089, 0x1FE2, - 0x1FCB, 0x02CE, 0x04E7, 0x00A1, 0x1FDF, - 0x1FC8, 0x02A6, 0x04FB, 0x00BB, 0x1FDC, - 0x1FC6, 0x027E, 0x050D, 0x00D7, 0x1FD8, - 0x1FC5, 0x0256, 0x051C, 0x00F4, 0x1FD5, - 0x1FC4, 0x022F, 0x0529, 0x0112, 0x1FD2, - 0x1FC4, 0x0209, 0x0532, 0x0132, 0x1FCF, - 0x1FC5, 0x01E2, 0x0539, 0x0153, 0x1FCD, - 0x1FC6, 0x01BD, 0x053E, 0x0175, 0x1FCA, - }, - [VS_LT_14_16_SCALE] = { - /* Luma */ - 0x1FBF, 0x016C, 0x05AA, 0x016C, 0x1FBF, - 0x1FC3, 0x0146, 0x05A8, 0x0194, 0x1FBB, - 0x1FC7, 0x0121, 0x05A3, 0x01BD, 0x1FB8, - 0x1FCB, 0x00FD, 0x059B, 0x01E8, 0x1FB5, - 0x1FD0, 0x00DC, 0x058F, 0x0213, 0x1FB2, - 0x1FD4, 0x00BC, 0x0580, 0x0240, 0x1FB0, - 0x1FD8, 0x009E, 0x056E, 0x026D, 0x1FAF, - 0x1FDC, 0x0082, 0x055A, 0x029A, 0x1FAE, - 0x1FE0, 0x0067, 0x0542, 0x02C9, 0x1FAE, - 0x1FE4, 0x004F, 0x0528, 0x02F6, 0x1FAF, - 0x1FE8, 0x0038, 0x050A, 0x0325, 0x1FB1, - 0x1FEB, 0x0024, 0x04EB, 0x0352, 0x1FB4, - 0x1FEE, 0x0011, 0x04C8, 0x0380, 0x1FB9, - 0x1FF1, 0x0000, 0x04A4, 0x03AC, 0x1FBF, - 0x1FF4, 0x1FF1, 0x047D, 0x03D8, 0x1FC6, - 0x1FF6, 0x1FE4, 0x0455, 0x0403, 0x1FCE, - 0x1FD8, 0x0428, 0x0428, 0x1FD8, 0x0000, - 0x1FCE, 0x0403, 0x0455, 0x1FE4, 0x1FF6, - 0x1FC6, 0x03D8, 0x047D, 0x1FF1, 0x1FF4, - 0x1FBF, 0x03AC, 0x04A4, 0x0000, 0x1FF1, - 0x1FB9, 0x0380, 0x04C8, 0x0011, 0x1FEE, - 0x1FB4, 0x0352, 0x04EB, 0x0024, 0x1FEB, - 0x1FB1, 0x0325, 0x050A, 0x0038, 0x1FE8, - 0x1FAF, 0x02F6, 0x0528, 0x004F, 0x1FE4, - 0x1FAE, 0x02C9, 0x0542, 0x0067, 0x1FE0, - 0x1FAE, 0x029A, 0x055A, 0x0082, 0x1FDC, - 0x1FAF, 0x026D, 0x056E, 0x009E, 0x1FD8, - 0x1FB0, 0x0240, 0x0580, 0x00BC, 0x1FD4, - 0x1FB2, 0x0213, 0x058F, 0x00DC, 0x1FD0, - 0x1FB5, 0x01E8, 0x059B, 0x00FD, 0x1FCB, - 0x1FB8, 0x01BD, 0x05A3, 0x0121, 0x1FC7, - 0x1FBB, 0x0194, 0x05A8, 0x0146, 0x1FC3, - /* Chroma */ - 0x1FBF, 0x016C, 0x05AA, 0x016C, 0x1FBF, - 0x1FC3, 0x0146, 0x05A8, 0x0194, 0x1FBB, - 0x1FC7, 0x0121, 0x05A3, 0x01BD, 0x1FB8, - 0x1FCB, 0x00FD, 0x059B, 0x01E8, 0x1FB5, - 0x1FD0, 0x00DC, 0x058F, 0x0213, 0x1FB2, - 0x1FD4, 0x00BC, 0x0580, 0x0240, 0x1FB0, - 0x1FD8, 0x009E, 0x056E, 0x026D, 0x1FAF, - 0x1FDC, 0x0082, 0x055A, 0x029A, 0x1FAE, - 0x1FE0, 0x0067, 0x0542, 0x02C9, 0x1FAE, - 0x1FE4, 0x004F, 0x0528, 0x02F6, 0x1FAF, - 0x1FE8, 0x0038, 0x050A, 0x0325, 0x1FB1, - 0x1FEB, 0x0024, 0x04EB, 0x0352, 0x1FB4, - 0x1FEE, 0x0011, 0x04C8, 0x0380, 0x1FB9, - 0x1FF1, 0x0000, 0x04A4, 0x03AC, 0x1FBF, - 0x1FF4, 0x1FF1, 0x047D, 0x03D8, 0x1FC6, - 0x1FF6, 0x1FE4, 0x0455, 0x0403, 0x1FCE, - 0x1FD8, 0x0428, 0x0428, 0x1FD8, 0x0000, - 0x1FCE, 0x0403, 0x0455, 0x1FE4, 0x1FF6, - 0x1FC6, 0x03D8, 0x047D, 0x1FF1, 0x1FF4, - 0x1FBF, 0x03AC, 0x04A4, 0x0000, 0x1FF1, - 0x1FB9, 0x0380, 0x04C8, 0x0011, 0x1FEE, - 0x1FB4, 0x0352, 0x04EB, 0x0024, 0x1FEB, - 0x1FB1, 0x0325, 0x050A, 0x0038, 0x1FE8, - 0x1FAF, 0x02F6, 0x0528, 0x004F, 0x1FE4, - 0x1FAE, 0x02C9, 0x0542, 0x0067, 0x1FE0, - 0x1FAE, 0x029A, 0x055A, 0x0082, 0x1FDC, - 0x1FAF, 0x026D, 0x056E, 0x009E, 0x1FD8, - 0x1FB0, 0x0240, 0x0580, 0x00BC, 0x1FD4, - 0x1FB2, 0x0213, 0x058F, 0x00DC, 0x1FD0, - 0x1FB5, 0x01E8, 0x059B, 0x00FD, 0x1FCB, - 0x1FB8, 0x01BD, 0x05A3, 0x0121, 0x1FC7, - 0x1FBB, 0x0194, 0x05A8, 0x0146, 0x1FC3, - }, - [VS_LT_15_16_SCALE] = { - /* Luma */ - 0x1FBD, 0x0136, 0x061A, 0x0136, 0x1FBD, - 0x1FC3, 0x010D, 0x0617, 0x0161, 0x1FB8, - 0x1FC9, 0x00E6, 0x0611, 0x018E, 0x1FB2, - 0x1FCE, 0x00C1, 0x0607, 0x01BD, 0x1FAD, - 0x1FD4, 0x009E, 0x05F9, 0x01ED, 0x1FA8, - 0x1FD9, 0x007D, 0x05E8, 0x021F, 0x1FA3, - 0x1FDE, 0x005E, 0x05D3, 0x0252, 0x1F9F, - 0x1FE2, 0x0042, 0x05BC, 0x0285, 0x1F9B, - 0x1FE7, 0x0029, 0x059F, 0x02B9, 0x1F98, - 0x1FEA, 0x0011, 0x0580, 0x02EF, 0x1F96, - 0x1FEE, 0x1FFC, 0x055D, 0x0324, 0x1F95, - 0x1FF1, 0x1FE9, 0x0538, 0x0359, 0x1F95, - 0x1FF4, 0x1FD8, 0x0510, 0x038E, 0x1F96, - 0x1FF7, 0x1FC9, 0x04E5, 0x03C2, 0x1F99, - 0x1FF9, 0x1FBD, 0x04B8, 0x03F5, 0x1F9D, - 0x1FFB, 0x1FB2, 0x0489, 0x0428, 0x1FA2, - 0x1FAA, 0x0456, 0x0456, 0x1FAA, 0x0000, - 0x1FA2, 0x0428, 0x0489, 0x1FB2, 0x1FFB, - 0x1F9D, 0x03F5, 0x04B8, 0x1FBD, 0x1FF9, - 0x1F99, 0x03C2, 0x04E5, 0x1FC9, 0x1FF7, - 0x1F96, 0x038E, 0x0510, 0x1FD8, 0x1FF4, - 0x1F95, 0x0359, 0x0538, 0x1FE9, 0x1FF1, - 0x1F95, 0x0324, 0x055D, 0x1FFC, 0x1FEE, - 0x1F96, 0x02EF, 0x0580, 0x0011, 0x1FEA, - 0x1F98, 0x02B9, 0x059F, 0x0029, 0x1FE7, - 0x1F9B, 0x0285, 0x05BC, 0x0042, 0x1FE2, - 0x1F9F, 0x0252, 0x05D3, 0x005E, 0x1FDE, - 0x1FA3, 0x021F, 0x05E8, 0x007D, 0x1FD9, - 0x1FA8, 0x01ED, 0x05F9, 0x009E, 0x1FD4, - 0x1FAD, 0x01BD, 0x0607, 0x00C1, 0x1FCE, - 0x1FB2, 0x018E, 0x0611, 0x00E6, 0x1FC9, - 0x1FB8, 0x0161, 0x0617, 0x010D, 0x1FC3, - /* Chroma */ - 0x1FBD, 0x0136, 0x061A, 0x0136, 0x1FBD, - 0x1FC3, 0x010D, 0x0617, 0x0161, 0x1FB8, - 0x1FC9, 0x00E6, 0x0611, 0x018E, 0x1FB2, - 0x1FCE, 0x00C1, 0x0607, 0x01BD, 0x1FAD, - 0x1FD4, 0x009E, 0x05F9, 0x01ED, 0x1FA8, - 0x1FD9, 0x007D, 0x05E8, 0x021F, 0x1FA3, - 0x1FDE, 0x005E, 0x05D3, 0x0252, 0x1F9F, - 0x1FE2, 0x0042, 0x05BC, 0x0285, 0x1F9B, - 0x1FE7, 0x0029, 0x059F, 0x02B9, 0x1F98, - 0x1FEA, 0x0011, 0x0580, 0x02EF, 0x1F96, - 0x1FEE, 0x1FFC, 0x055D, 0x0324, 0x1F95, - 0x1FF1, 0x1FE9, 0x0538, 0x0359, 0x1F95, - 0x1FF4, 0x1FD8, 0x0510, 0x038E, 0x1F96, - 0x1FF7, 0x1FC9, 0x04E5, 0x03C2, 0x1F99, - 0x1FF9, 0x1FBD, 0x04B8, 0x03F5, 0x1F9D, - 0x1FFB, 0x1FB2, 0x0489, 0x0428, 0x1FA2, - 0x1FAA, 0x0456, 0x0456, 0x1FAA, 0x0000, - 0x1FA2, 0x0428, 0x0489, 0x1FB2, 0x1FFB, - 0x1F9D, 0x03F5, 0x04B8, 0x1FBD, 0x1FF9, - 0x1F99, 0x03C2, 0x04E5, 0x1FC9, 0x1FF7, - 0x1F96, 0x038E, 0x0510, 0x1FD8, 0x1FF4, - 0x1F95, 0x0359, 0x0538, 0x1FE9, 0x1FF1, - 0x1F95, 0x0324, 0x055D, 0x1FFC, 0x1FEE, - 0x1F96, 0x02EF, 0x0580, 0x0011, 0x1FEA, - 0x1F98, 0x02B9, 0x059F, 0x0029, 0x1FE7, - 0x1F9B, 0x0285, 0x05BC, 0x0042, 0x1FE2, - 0x1F9F, 0x0252, 0x05D3, 0x005E, 0x1FDE, - 0x1FA3, 0x021F, 0x05E8, 0x007D, 0x1FD9, - 0x1FA8, 0x01ED, 0x05F9, 0x009E, 0x1FD4, - 0x1FAD, 0x01BD, 0x0607, 0x00C1, 0x1FCE, - 0x1FB2, 0x018E, 0x0611, 0x00E6, 0x1FC9, - 0x1FB8, 0x0161, 0x0617, 0x010D, 0x1FC3, - }, - [VS_LT_16_16_SCALE] = { - /* Luma */ - 0x1FC3, 0x00F8, 0x068A, 0x00F8, 0x1FC3, - 0x1FCA, 0x00CC, 0x0689, 0x0125, 0x1FBC, - 0x1FD1, 0x00A3, 0x0681, 0x0156, 0x1FB5, - 0x1FD7, 0x007D, 0x0676, 0x0188, 0x1FAE, - 0x1FDD, 0x005A, 0x0666, 0x01BD, 0x1FA6, - 0x1FE3, 0x0039, 0x0652, 0x01F3, 0x1F9F, - 0x1FE8, 0x001B, 0x0639, 0x022C, 0x1F98, - 0x1FEC, 0x0000, 0x061D, 0x0265, 0x1F92, - 0x1FF0, 0x1FE8, 0x05FC, 0x02A0, 0x1F8C, - 0x1FF4, 0x1FD2, 0x05D7, 0x02DC, 0x1F87, - 0x1FF7, 0x1FBF, 0x05AF, 0x0319, 0x1F82, - 0x1FFA, 0x1FAF, 0x0583, 0x0356, 0x1F7E, - 0x1FFC, 0x1FA1, 0x0554, 0x0393, 0x1F7C, - 0x1FFE, 0x1F95, 0x0523, 0x03CF, 0x1F7B, - 0x0000, 0x1F8C, 0x04EE, 0x040B, 0x1F7B, - 0x0001, 0x1F85, 0x04B8, 0x0446, 0x1F7C, - 0x1F80, 0x0480, 0x0480, 0x1F80, 0x0000, - 0x1F7C, 0x0446, 0x04B8, 0x1F85, 0x0001, - 0x1F7B, 0x040B, 0x04EE, 0x1F8C, 0x0000, - 0x1F7B, 0x03CF, 0x0523, 0x1F95, 0x1FFE, - 0x1F7C, 0x0393, 0x0554, 0x1FA1, 0x1FFC, - 0x1F7E, 0x0356, 0x0583, 0x1FAF, 0x1FFA, - 0x1F82, 0x0319, 0x05AF, 0x1FBF, 0x1FF7, - 0x1F87, 0x02DC, 0x05D7, 0x1FD2, 0x1FF4, - 0x1F8C, 0x02A0, 0x05FC, 0x1FE8, 0x1FF0, - 0x1F92, 0x0265, 0x061D, 0x0000, 0x1FEC, - 0x1F98, 0x022C, 0x0639, 0x001B, 0x1FE8, - 0x1F9F, 0x01F3, 0x0652, 0x0039, 0x1FE3, - 0x1FA6, 0x01BD, 0x0666, 0x005A, 0x1FDD, - 0x1FAE, 0x0188, 0x0676, 0x007D, 0x1FD7, - 0x1FB5, 0x0156, 0x0681, 0x00A3, 0x1FD1, - 0x1FBC, 0x0125, 0x0689, 0x00CC, 0x1FCA, - /* Chroma */ - 0x1FC3, 0x00F8, 0x068A, 0x00F8, 0x1FC3, - 0x1FCA, 0x00CC, 0x0689, 0x0125, 0x1FBC, - 0x1FD1, 0x00A3, 0x0681, 0x0156, 0x1FB5, - 0x1FD7, 0x007D, 0x0676, 0x0188, 0x1FAE, - 0x1FDD, 0x005A, 0x0666, 0x01BD, 0x1FA6, - 0x1FE3, 0x0039, 0x0652, 0x01F3, 0x1F9F, - 0x1FE8, 0x001B, 0x0639, 0x022C, 0x1F98, - 0x1FEC, 0x0000, 0x061D, 0x0265, 0x1F92, - 0x1FF0, 0x1FE8, 0x05FC, 0x02A0, 0x1F8C, - 0x1FF4, 0x1FD2, 0x05D7, 0x02DC, 0x1F87, - 0x1FF7, 0x1FBF, 0x05AF, 0x0319, 0x1F82, - 0x1FFA, 0x1FAF, 0x0583, 0x0356, 0x1F7E, - 0x1FFC, 0x1FA1, 0x0554, 0x0393, 0x1F7C, - 0x1FFE, 0x1F95, 0x0523, 0x03CF, 0x1F7B, - 0x0000, 0x1F8C, 0x04EE, 0x040B, 0x1F7B, - 0x0001, 0x1F85, 0x04B8, 0x0446, 0x1F7C, - 0x1F80, 0x0480, 0x0480, 0x1F80, 0x0000, - 0x1F7C, 0x0446, 0x04B8, 0x1F85, 0x0001, - 0x1F7B, 0x040B, 0x04EE, 0x1F8C, 0x0000, - 0x1F7B, 0x03CF, 0x0523, 0x1F95, 0x1FFE, - 0x1F7C, 0x0393, 0x0554, 0x1FA1, 0x1FFC, - 0x1F7E, 0x0356, 0x0583, 0x1FAF, 0x1FFA, - 0x1F82, 0x0319, 0x05AF, 0x1FBF, 0x1FF7, - 0x1F87, 0x02DC, 0x05D7, 0x1FD2, 0x1FF4, - 0x1F8C, 0x02A0, 0x05FC, 0x1FE8, 0x1FF0, - 0x1F92, 0x0265, 0x061D, 0x0000, 0x1FEC, - 0x1F98, 0x022C, 0x0639, 0x001B, 0x1FE8, - 0x1F9F, 0x01F3, 0x0652, 0x0039, 0x1FE3, - 0x1FA6, 0x01BD, 0x0666, 0x005A, 0x1FDD, - 0x1FAE, 0x0188, 0x0676, 0x007D, 0x1FD7, - 0x1FB5, 0x0156, 0x0681, 0x00A3, 0x1FD1, - 0x1FBC, 0x0125, 0x0689, 0x00CC, 0x1FCA, - }, - [VS_1_TO_1_SCALE] = { - /* Luma */ - 0x0000, 0x0000, 0x0800, 0x0000, 0x0000, - 0x1FD8, 0x0085, 0x06F9, 0x00E1, 0x1FC9, - 0x1FDF, 0x005B, 0x06F2, 0x0114, 0x1FC0, - 0x1FE5, 0x0035, 0x06E5, 0x014A, 0x1FB7, - 0x1FEB, 0x0012, 0x06D3, 0x0182, 0x1FAE, - 0x1FF1, 0x1FF3, 0x06BA, 0x01BD, 0x1FA5, - 0x1FF5, 0x1FD7, 0x069D, 0x01FB, 0x1F9C, - 0x1FF9, 0x1FBE, 0x067C, 0x023A, 0x1F93, - 0x1FFD, 0x1FA8, 0x0656, 0x027B, 0x1F8A, - 0x0000, 0x1F95, 0x062B, 0x02BF, 0x1F81, - 0x0002, 0x1F86, 0x05FC, 0x0303, 0x1F79, - 0x0004, 0x1F79, 0x05CA, 0x0347, 0x1F72, - 0x0005, 0x1F6F, 0x0594, 0x038D, 0x1F6B, - 0x0006, 0x1F67, 0x055B, 0x03D2, 0x1F66, - 0x0007, 0x1F62, 0x051E, 0x0417, 0x1F62, - 0x0007, 0x1F5F, 0x04DF, 0x045C, 0x1F5F, - 0x1F5E, 0x04A2, 0x04A2, 0x1F5E, 0x0000, - 0x1F5F, 0x045C, 0x04DF, 0x1F5F, 0x0007, - 0x1F62, 0x0417, 0x051E, 0x1F62, 0x0007, - 0x1F66, 0x03D2, 0x055B, 0x1F67, 0x0006, - 0x1F6B, 0x038D, 0x0594, 0x1F6F, 0x0005, - 0x1F72, 0x0347, 0x05CA, 0x1F79, 0x0004, - 0x1F79, 0x0303, 0x05FC, 0x1F86, 0x0002, - 0x1F81, 0x02BF, 0x062B, 0x1F95, 0x0000, - 0x1F8A, 0x027B, 0x0656, 0x1FA8, 0x1FFD, - 0x1F93, 0x023A, 0x067C, 0x1FBE, 0x1FF9, - 0x1F9C, 0x01FB, 0x069D, 0x1FD7, 0x1FF5, - 0x1FA5, 0x01BD, 0x06BA, 0x1FF3, 0x1FF1, - 0x1FAE, 0x0182, 0x06D3, 0x0012, 0x1FEB, - 0x1FB7, 0x014A, 0x06E5, 0x0035, 0x1FE5, - 0x1FC0, 0x0114, 0x06F2, 0x005B, 0x1FDF, - 0x1FC9, 0x00E1, 0x06F9, 0x0085, 0x1FD8, - /* Chroma */ - 0x0000, 0x0000, 0x0800, 0x0000, 0x0000, - 0x1FD8, 0x0085, 0x06F9, 0x00E1, 0x1FC9, - 0x1FDF, 0x005B, 0x06F2, 0x0114, 0x1FC0, - 0x1FE5, 0x0035, 0x06E5, 0x014A, 0x1FB7, - 0x1FEB, 0x0012, 0x06D3, 0x0182, 0x1FAE, - 0x1FF1, 0x1FF3, 0x06BA, 0x01BD, 0x1FA5, - 0x1FF5, 0x1FD7, 0x069D, 0x01FB, 0x1F9C, - 0x1FF9, 0x1FBE, 0x067C, 0x023A, 0x1F93, - 0x1FFD, 0x1FA8, 0x0656, 0x027B, 0x1F8A, - 0x0000, 0x1F95, 0x062B, 0x02BF, 0x1F81, - 0x0002, 0x1F86, 0x05FC, 0x0303, 0x1F79, - 0x0004, 0x1F79, 0x05CA, 0x0347, 0x1F72, - 0x0005, 0x1F6F, 0x0594, 0x038D, 0x1F6B, - 0x0006, 0x1F67, 0x055B, 0x03D2, 0x1F66, - 0x0007, 0x1F62, 0x051E, 0x0417, 0x1F62, - 0x0007, 0x1F5F, 0x04DF, 0x045C, 0x1F5F, - 0x1F5E, 0x04A2, 0x04A2, 0x1F5E, 0x0000, - 0x1F5F, 0x045C, 0x04DF, 0x1F5F, 0x0007, - 0x1F62, 0x0417, 0x051E, 0x1F62, 0x0007, - 0x1F66, 0x03D2, 0x055B, 0x1F67, 0x0006, - 0x1F6B, 0x038D, 0x0594, 0x1F6F, 0x0005, - 0x1F72, 0x0347, 0x05CA, 0x1F79, 0x0004, - 0x1F79, 0x0303, 0x05FC, 0x1F86, 0x0002, - 0x1F81, 0x02BF, 0x062B, 0x1F95, 0x0000, - 0x1F8A, 0x027B, 0x0656, 0x1FA8, 0x1FFD, - 0x1F93, 0x023A, 0x067C, 0x1FBE, 0x1FF9, - 0x1F9C, 0x01FB, 0x069D, 0x1FD7, 0x1FF5, - 0x1FA5, 0x01BD, 0x06BA, 0x1FF3, 0x1FF1, - 0x1FAE, 0x0182, 0x06D3, 0x0012, 0x1FEB, - 0x1FB7, 0x014A, 0x06E5, 0x0035, 0x1FE5, - 0x1FC0, 0x0114, 0x06F2, 0x005B, 0x1FDF, - 0x1FC9, 0x00E1, 0x06F9, 0x0085, 0x1FD8, - }, -}; -#endif diff --git a/drivers/media/platform/ti-vpe/vpdma.c b/drivers/media/platform/ti-vpe/vpdma.c deleted file mode 100644 index f8998a8ad371..000000000000 --- a/drivers/media/platform/ti-vpe/vpdma.c +++ /dev/null @@ -1,1176 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * VPDMA helper library - * - * Copyright (c) 2013 Texas Instruments Inc. - * - * David Griego, - * Dale Farnsworth, - * Archit Taneja, - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "vpdma.h" -#include "vpdma_priv.h" - -#define VPDMA_FIRMWARE "vpdma-1b8.bin" - -const struct vpdma_data_format vpdma_yuv_fmts[] = { - [VPDMA_DATA_FMT_Y444] = { - .type = VPDMA_DATA_FMT_TYPE_YUV, - .data_type = DATA_TYPE_Y444, - .depth = 8, - }, - [VPDMA_DATA_FMT_Y422] = { - .type = VPDMA_DATA_FMT_TYPE_YUV, - .data_type = DATA_TYPE_Y422, - .depth = 8, - }, - [VPDMA_DATA_FMT_Y420] = { - .type = VPDMA_DATA_FMT_TYPE_YUV, - .data_type = DATA_TYPE_Y420, - .depth = 8, - }, - [VPDMA_DATA_FMT_C444] = { - .type = VPDMA_DATA_FMT_TYPE_YUV, - .data_type = DATA_TYPE_C444, - .depth = 8, - }, - [VPDMA_DATA_FMT_C422] = { - .type = VPDMA_DATA_FMT_TYPE_YUV, - .data_type = DATA_TYPE_C422, - .depth = 8, - }, - [VPDMA_DATA_FMT_C420] = { - .type = VPDMA_DATA_FMT_TYPE_YUV, - .data_type = DATA_TYPE_C420, - .depth = 4, - }, - [VPDMA_DATA_FMT_CB420] = { - .type = VPDMA_DATA_FMT_TYPE_YUV, - .data_type = DATA_TYPE_CB420, - .depth = 4, - }, - [VPDMA_DATA_FMT_YCR422] = { - .type = VPDMA_DATA_FMT_TYPE_YUV, - .data_type = DATA_TYPE_YCR422, - .depth = 16, - }, - [VPDMA_DATA_FMT_YC444] = { - .type = VPDMA_DATA_FMT_TYPE_YUV, - .data_type = DATA_TYPE_YC444, - .depth = 24, - }, - [VPDMA_DATA_FMT_CRY422] = { - .type = VPDMA_DATA_FMT_TYPE_YUV, - .data_type = DATA_TYPE_CRY422, - .depth = 16, - }, - [VPDMA_DATA_FMT_CBY422] = { - .type = VPDMA_DATA_FMT_TYPE_YUV, - .data_type = DATA_TYPE_CBY422, - .depth = 16, - }, - [VPDMA_DATA_FMT_YCB422] = { - .type = VPDMA_DATA_FMT_TYPE_YUV, - .data_type = DATA_TYPE_YCB422, - .depth = 16, - }, -}; -EXPORT_SYMBOL(vpdma_yuv_fmts); - -const struct vpdma_data_format vpdma_rgb_fmts[] = { - [VPDMA_DATA_FMT_RGB565] = { - .type = VPDMA_DATA_FMT_TYPE_RGB, - .data_type = DATA_TYPE_RGB16_565, - .depth = 16, - }, - [VPDMA_DATA_FMT_ARGB16_1555] = { - .type = VPDMA_DATA_FMT_TYPE_RGB, - .data_type = DATA_TYPE_ARGB_1555, - .depth = 16, - }, - [VPDMA_DATA_FMT_ARGB16] = { - .type = VPDMA_DATA_FMT_TYPE_RGB, - .data_type = DATA_TYPE_ARGB_4444, - .depth = 16, - }, - [VPDMA_DATA_FMT_RGBA16_5551] = { - .type = VPDMA_DATA_FMT_TYPE_RGB, - .data_type = DATA_TYPE_RGBA_5551, - .depth = 16, - }, - [VPDMA_DATA_FMT_RGBA16] = { - .type = VPDMA_DATA_FMT_TYPE_RGB, - .data_type = DATA_TYPE_RGBA_4444, - .depth = 16, - }, - [VPDMA_DATA_FMT_ARGB24] = { - .type = VPDMA_DATA_FMT_TYPE_RGB, - .data_type = DATA_TYPE_ARGB24_6666, - .depth = 24, - }, - [VPDMA_DATA_FMT_RGB24] = { - .type = VPDMA_DATA_FMT_TYPE_RGB, - .data_type = DATA_TYPE_RGB24_888, - .depth = 24, - }, - [VPDMA_DATA_FMT_ARGB32] = { - .type = VPDMA_DATA_FMT_TYPE_RGB, - .data_type = DATA_TYPE_ARGB32_8888, - .depth = 32, - }, - [VPDMA_DATA_FMT_RGBA24] = { - .type = VPDMA_DATA_FMT_TYPE_RGB, - .data_type = DATA_TYPE_RGBA24_6666, - .depth = 24, - }, - [VPDMA_DATA_FMT_RGBA32] = { - .type = VPDMA_DATA_FMT_TYPE_RGB, - .data_type = DATA_TYPE_RGBA32_8888, - .depth = 32, - }, - [VPDMA_DATA_FMT_BGR565] = { - .type = VPDMA_DATA_FMT_TYPE_RGB, - .data_type = DATA_TYPE_BGR16_565, - .depth = 16, - }, - [VPDMA_DATA_FMT_ABGR16_1555] = { - .type = VPDMA_DATA_FMT_TYPE_RGB, - .data_type = DATA_TYPE_ABGR_1555, - .depth = 16, - }, - [VPDMA_DATA_FMT_ABGR16] = { - .type = VPDMA_DATA_FMT_TYPE_RGB, - .data_type = DATA_TYPE_ABGR_4444, - .depth = 16, - }, - [VPDMA_DATA_FMT_BGRA16_5551] = { - .type = VPDMA_DATA_FMT_TYPE_RGB, - .data_type = DATA_TYPE_BGRA_5551, - .depth = 16, - }, - [VPDMA_DATA_FMT_BGRA16] = { - .type = VPDMA_DATA_FMT_TYPE_RGB, - .data_type = DATA_TYPE_BGRA_4444, - .depth = 16, - }, - [VPDMA_DATA_FMT_ABGR24] = { - .type = VPDMA_DATA_FMT_TYPE_RGB, - .data_type = DATA_TYPE_ABGR24_6666, - .depth = 24, - }, - [VPDMA_DATA_FMT_BGR24] = { - .type = VPDMA_DATA_FMT_TYPE_RGB, - .data_type = DATA_TYPE_BGR24_888, - .depth = 24, - }, - [VPDMA_DATA_FMT_ABGR32] = { - .type = VPDMA_DATA_FMT_TYPE_RGB, - .data_type = DATA_TYPE_ABGR32_8888, - .depth = 32, - }, - [VPDMA_DATA_FMT_BGRA24] = { - .type = VPDMA_DATA_FMT_TYPE_RGB, - .data_type = DATA_TYPE_BGRA24_6666, - .depth = 24, - }, - [VPDMA_DATA_FMT_BGRA32] = { - .type = VPDMA_DATA_FMT_TYPE_RGB, - .data_type = DATA_TYPE_BGRA32_8888, - .depth = 32, - }, -}; -EXPORT_SYMBOL(vpdma_rgb_fmts); - -/* - * To handle RAW format we are re-using the CBY422 - * vpdma data type so that we use the vpdma to re-order - * the incoming bytes, as the parser assumes that the - * first byte presented on the bus is the MSB of a 2 - * bytes value. - * RAW8 handles from 1 to 8 bits - * RAW16 handles from 9 to 16 bits - */ -const struct vpdma_data_format vpdma_raw_fmts[] = { - [VPDMA_DATA_FMT_RAW8] = { - .type = VPDMA_DATA_FMT_TYPE_YUV, - .data_type = DATA_TYPE_CBY422, - .depth = 8, - }, - [VPDMA_DATA_FMT_RAW16] = { - .type = VPDMA_DATA_FMT_TYPE_YUV, - .data_type = DATA_TYPE_CBY422, - .depth = 16, - }, -}; -EXPORT_SYMBOL(vpdma_raw_fmts); - -const struct vpdma_data_format vpdma_misc_fmts[] = { - [VPDMA_DATA_FMT_MV] = { - .type = VPDMA_DATA_FMT_TYPE_MISC, - .data_type = DATA_TYPE_MV, - .depth = 4, - }, -}; -EXPORT_SYMBOL(vpdma_misc_fmts); - -struct vpdma_channel_info { - int num; /* VPDMA channel number */ - int cstat_offset; /* client CSTAT register offset */ -}; - -static const struct vpdma_channel_info chan_info[] = { - [VPE_CHAN_LUMA1_IN] = { - .num = VPE_CHAN_NUM_LUMA1_IN, - .cstat_offset = VPDMA_DEI_LUMA1_CSTAT, - }, - [VPE_CHAN_CHROMA1_IN] = { - .num = VPE_CHAN_NUM_CHROMA1_IN, - .cstat_offset = VPDMA_DEI_CHROMA1_CSTAT, - }, - [VPE_CHAN_LUMA2_IN] = { - .num = VPE_CHAN_NUM_LUMA2_IN, - .cstat_offset = VPDMA_DEI_LUMA2_CSTAT, - }, - [VPE_CHAN_CHROMA2_IN] = { - .num = VPE_CHAN_NUM_CHROMA2_IN, - .cstat_offset = VPDMA_DEI_CHROMA2_CSTAT, - }, - [VPE_CHAN_LUMA3_IN] = { - .num = VPE_CHAN_NUM_LUMA3_IN, - .cstat_offset = VPDMA_DEI_LUMA3_CSTAT, - }, - [VPE_CHAN_CHROMA3_IN] = { - .num = VPE_CHAN_NUM_CHROMA3_IN, - .cstat_offset = VPDMA_DEI_CHROMA3_CSTAT, - }, - [VPE_CHAN_MV_IN] = { - .num = VPE_CHAN_NUM_MV_IN, - .cstat_offset = VPDMA_DEI_MV_IN_CSTAT, - }, - [VPE_CHAN_MV_OUT] = { - .num = VPE_CHAN_NUM_MV_OUT, - .cstat_offset = VPDMA_DEI_MV_OUT_CSTAT, - }, - [VPE_CHAN_LUMA_OUT] = { - .num = VPE_CHAN_NUM_LUMA_OUT, - .cstat_offset = VPDMA_VIP_UP_Y_CSTAT, - }, - [VPE_CHAN_CHROMA_OUT] = { - .num = VPE_CHAN_NUM_CHROMA_OUT, - .cstat_offset = VPDMA_VIP_UP_UV_CSTAT, - }, - [VPE_CHAN_RGB_OUT] = { - .num = VPE_CHAN_NUM_RGB_OUT, - .cstat_offset = VPDMA_VIP_UP_Y_CSTAT, - }, -}; - -static u32 read_reg(struct vpdma_data *vpdma, int offset) -{ - return ioread32(vpdma->base + offset); -} - -static void write_reg(struct vpdma_data *vpdma, int offset, u32 value) -{ - iowrite32(value, vpdma->base + offset); -} - -static int read_field_reg(struct vpdma_data *vpdma, int offset, - u32 mask, int shift) -{ - return (read_reg(vpdma, offset) & (mask << shift)) >> shift; -} - -static void write_field_reg(struct vpdma_data *vpdma, int offset, u32 field, - u32 mask, int shift) -{ - u32 val = read_reg(vpdma, offset); - - val &= ~(mask << shift); - val |= (field & mask) << shift; - - write_reg(vpdma, offset, val); -} - -void vpdma_dump_regs(struct vpdma_data *vpdma) -{ - struct device *dev = &vpdma->pdev->dev; - -#define DUMPREG(r) dev_dbg(dev, "%-35s %08x\n", #r, read_reg(vpdma, VPDMA_##r)) - - dev_dbg(dev, "VPDMA Registers:\n"); - - DUMPREG(PID); - DUMPREG(LIST_ADDR); - DUMPREG(LIST_ATTR); - DUMPREG(LIST_STAT_SYNC); - DUMPREG(BG_RGB); - DUMPREG(BG_YUV); - DUMPREG(SETUP); - DUMPREG(MAX_SIZE1); - DUMPREG(MAX_SIZE2); - DUMPREG(MAX_SIZE3); - - /* - * dumping registers of only group0 and group3, because VPE channels - * lie within group0 and group3 registers - */ - DUMPREG(INT_CHAN_STAT(0)); - DUMPREG(INT_CHAN_MASK(0)); - DUMPREG(INT_CHAN_STAT(3)); - DUMPREG(INT_CHAN_MASK(3)); - DUMPREG(INT_CLIENT0_STAT); - DUMPREG(INT_CLIENT0_MASK); - DUMPREG(INT_CLIENT1_STAT); - DUMPREG(INT_CLIENT1_MASK); - DUMPREG(INT_LIST0_STAT); - DUMPREG(INT_LIST0_MASK); - - /* - * these are registers specific to VPE clients, we can make this - * function dump client registers specific to VPE or VIP based on - * who is using it - */ - DUMPREG(DEI_CHROMA1_CSTAT); - DUMPREG(DEI_LUMA1_CSTAT); - DUMPREG(DEI_CHROMA2_CSTAT); - DUMPREG(DEI_LUMA2_CSTAT); - DUMPREG(DEI_CHROMA3_CSTAT); - DUMPREG(DEI_LUMA3_CSTAT); - DUMPREG(DEI_MV_IN_CSTAT); - DUMPREG(DEI_MV_OUT_CSTAT); - DUMPREG(VIP_UP_Y_CSTAT); - DUMPREG(VIP_UP_UV_CSTAT); - DUMPREG(VPI_CTL_CSTAT); -} -EXPORT_SYMBOL(vpdma_dump_regs); - -/* - * Allocate a DMA buffer - */ -int vpdma_alloc_desc_buf(struct vpdma_buf *buf, size_t size) -{ - buf->size = size; - buf->mapped = false; - buf->addr = kzalloc(size, GFP_KERNEL); - if (!buf->addr) - return -ENOMEM; - - WARN_ON(((unsigned long)buf->addr & VPDMA_DESC_ALIGN) != 0); - - return 0; -} -EXPORT_SYMBOL(vpdma_alloc_desc_buf); - -void vpdma_free_desc_buf(struct vpdma_buf *buf) -{ - WARN_ON(buf->mapped); - kfree(buf->addr); - buf->addr = NULL; - buf->size = 0; -} -EXPORT_SYMBOL(vpdma_free_desc_buf); - -/* - * map descriptor/payload DMA buffer, enabling DMA access - */ -int vpdma_map_desc_buf(struct vpdma_data *vpdma, struct vpdma_buf *buf) -{ - struct device *dev = &vpdma->pdev->dev; - - WARN_ON(buf->mapped); - buf->dma_addr = dma_map_single(dev, buf->addr, buf->size, - DMA_BIDIRECTIONAL); - if (dma_mapping_error(dev, buf->dma_addr)) { - dev_err(dev, "failed to map buffer\n"); - return -EINVAL; - } - - buf->mapped = true; - - return 0; -} -EXPORT_SYMBOL(vpdma_map_desc_buf); - -/* - * unmap descriptor/payload DMA buffer, disabling DMA access and - * allowing the main processor to access the data - */ -void vpdma_unmap_desc_buf(struct vpdma_data *vpdma, struct vpdma_buf *buf) -{ - struct device *dev = &vpdma->pdev->dev; - - if (buf->mapped) - dma_unmap_single(dev, buf->dma_addr, buf->size, - DMA_BIDIRECTIONAL); - - buf->mapped = false; -} -EXPORT_SYMBOL(vpdma_unmap_desc_buf); - -/* - * Cleanup all pending descriptors of a list - * First, stop the current list being processed. - * If the VPDMA was busy, this step makes vpdma to accept post lists. - * To cleanup the internal FSM, post abort list descriptor for all the - * channels from @channels array of size @size. - */ -int vpdma_list_cleanup(struct vpdma_data *vpdma, int list_num, - int *channels, int size) -{ - struct vpdma_desc_list abort_list; - int i, ret, timeout = 500; - - write_reg(vpdma, VPDMA_LIST_ATTR, - (list_num << VPDMA_LIST_NUM_SHFT) | - (1 << VPDMA_LIST_STOP_SHFT)); - - if (size <= 0 || !channels) - return 0; - - ret = vpdma_create_desc_list(&abort_list, - size * sizeof(struct vpdma_dtd), VPDMA_LIST_TYPE_NORMAL); - if (ret) - return ret; - - for (i = 0; i < size; i++) - vpdma_add_abort_channel_ctd(&abort_list, channels[i]); - - ret = vpdma_map_desc_buf(vpdma, &abort_list.buf); - if (ret) - goto free_desc; - ret = vpdma_submit_descs(vpdma, &abort_list, list_num); - if (ret) - goto unmap_desc; - - while (vpdma_list_busy(vpdma, list_num) && --timeout) - ; - - if (timeout == 0) { - dev_err(&vpdma->pdev->dev, "Timed out cleaning up VPDMA list\n"); - ret = -EBUSY; - } - -unmap_desc: - vpdma_unmap_desc_buf(vpdma, &abort_list.buf); -free_desc: - vpdma_free_desc_buf(&abort_list.buf); - - return ret; -} -EXPORT_SYMBOL(vpdma_list_cleanup); - -/* - * create a descriptor list, the user of this list will append configuration, - * control and data descriptors to this list, this list will be submitted to - * VPDMA. VPDMA's list parser will go through each descriptor and perform the - * required DMA operations - */ -int vpdma_create_desc_list(struct vpdma_desc_list *list, size_t size, int type) -{ - int r; - - r = vpdma_alloc_desc_buf(&list->buf, size); - if (r) - return r; - - list->next = list->buf.addr; - - list->type = type; - - return 0; -} -EXPORT_SYMBOL(vpdma_create_desc_list); - -/* - * once a descriptor list is parsed by VPDMA, we reset the list by emptying it, - * to allow new descriptors to be added to the list. - */ -void vpdma_reset_desc_list(struct vpdma_desc_list *list) -{ - list->next = list->buf.addr; -} -EXPORT_SYMBOL(vpdma_reset_desc_list); - -/* - * free the buffer allocated for the VPDMA descriptor list, this should be - * called when the user doesn't want to use VPDMA any more. - */ -void vpdma_free_desc_list(struct vpdma_desc_list *list) -{ - vpdma_free_desc_buf(&list->buf); - - list->next = NULL; -} -EXPORT_SYMBOL(vpdma_free_desc_list); - -bool vpdma_list_busy(struct vpdma_data *vpdma, int list_num) -{ - return read_reg(vpdma, VPDMA_LIST_STAT_SYNC) & BIT(list_num + 16); -} -EXPORT_SYMBOL(vpdma_list_busy); - -/* - * submit a list of DMA descriptors to the VPE VPDMA, do not wait for completion - */ -int vpdma_submit_descs(struct vpdma_data *vpdma, - struct vpdma_desc_list *list, int list_num) -{ - int list_size; - unsigned long flags; - - if (vpdma_list_busy(vpdma, list_num)) - return -EBUSY; - - /* 16-byte granularity */ - list_size = (list->next - list->buf.addr) >> 4; - - spin_lock_irqsave(&vpdma->lock, flags); - write_reg(vpdma, VPDMA_LIST_ADDR, (u32) list->buf.dma_addr); - - write_reg(vpdma, VPDMA_LIST_ATTR, - (list_num << VPDMA_LIST_NUM_SHFT) | - (list->type << VPDMA_LIST_TYPE_SHFT) | - list_size); - spin_unlock_irqrestore(&vpdma->lock, flags); - - return 0; -} -EXPORT_SYMBOL(vpdma_submit_descs); - -static void dump_dtd(struct vpdma_dtd *dtd); - -void vpdma_update_dma_addr(struct vpdma_data *vpdma, - struct vpdma_desc_list *list, dma_addr_t dma_addr, - void *write_dtd, int drop, int idx) -{ - struct vpdma_dtd *dtd = list->buf.addr; - dma_addr_t write_desc_addr; - int offset; - - dtd += idx; - vpdma_unmap_desc_buf(vpdma, &list->buf); - - dtd->start_addr = dma_addr; - - /* Calculate write address from the offset of write_dtd from start - * of the list->buf - */ - offset = (void *)write_dtd - list->buf.addr; - write_desc_addr = list->buf.dma_addr + offset; - - if (drop) - dtd->desc_write_addr = dtd_desc_write_addr(write_desc_addr, - 1, 1, 0); - else - dtd->desc_write_addr = dtd_desc_write_addr(write_desc_addr, - 1, 0, 0); - - vpdma_map_desc_buf(vpdma, &list->buf); - - dump_dtd(dtd); -} -EXPORT_SYMBOL(vpdma_update_dma_addr); - -void vpdma_set_max_size(struct vpdma_data *vpdma, int reg_addr, - u32 width, u32 height) -{ - if (reg_addr != VPDMA_MAX_SIZE1 && reg_addr != VPDMA_MAX_SIZE2 && - reg_addr != VPDMA_MAX_SIZE3) - reg_addr = VPDMA_MAX_SIZE1; - - write_field_reg(vpdma, reg_addr, width - 1, - VPDMA_MAX_SIZE_WIDTH_MASK, VPDMA_MAX_SIZE_WIDTH_SHFT); - - write_field_reg(vpdma, reg_addr, height - 1, - VPDMA_MAX_SIZE_HEIGHT_MASK, VPDMA_MAX_SIZE_HEIGHT_SHFT); - -} -EXPORT_SYMBOL(vpdma_set_max_size); - -static void dump_cfd(struct vpdma_cfd *cfd) -{ - int class; - - class = cfd_get_class(cfd); - - pr_debug("config descriptor of payload class: %s\n", - class == CFD_CLS_BLOCK ? "simple block" : - "address data block"); - - if (class == CFD_CLS_BLOCK) - pr_debug("word0: dst_addr_offset = 0x%08x\n", - cfd->dest_addr_offset); - - if (class == CFD_CLS_BLOCK) - pr_debug("word1: num_data_wrds = %d\n", cfd->block_len); - - pr_debug("word2: payload_addr = 0x%08x\n", cfd->payload_addr); - - pr_debug("word3: pkt_type = %d, direct = %d, class = %d, dest = %d, payload_len = %d\n", - cfd_get_pkt_type(cfd), - cfd_get_direct(cfd), class, cfd_get_dest(cfd), - cfd_get_payload_len(cfd)); -} - -/* - * append a configuration descriptor to the given descriptor list, where the - * payload is in the form of a simple data block specified in the descriptor - * header, this is used to upload scaler coefficients to the scaler module - */ -void vpdma_add_cfd_block(struct vpdma_desc_list *list, int client, - struct vpdma_buf *blk, u32 dest_offset) -{ - struct vpdma_cfd *cfd; - int len = blk->size; - - WARN_ON(blk->dma_addr & VPDMA_DESC_ALIGN); - - cfd = list->next; - WARN_ON((void *)(cfd + 1) > (list->buf.addr + list->buf.size)); - - cfd->dest_addr_offset = dest_offset; - cfd->block_len = len; - cfd->payload_addr = (u32) blk->dma_addr; - cfd->ctl_payload_len = cfd_pkt_payload_len(CFD_INDIRECT, CFD_CLS_BLOCK, - client, len >> 4); - - list->next = cfd + 1; - - dump_cfd(cfd); -} -EXPORT_SYMBOL(vpdma_add_cfd_block); - -/* - * append a configuration descriptor to the given descriptor list, where the - * payload is in the address data block format, this is used to a configure a - * discontiguous set of MMRs - */ -void vpdma_add_cfd_adb(struct vpdma_desc_list *list, int client, - struct vpdma_buf *adb) -{ - struct vpdma_cfd *cfd; - unsigned int len = adb->size; - - WARN_ON(len & VPDMA_ADB_SIZE_ALIGN); - WARN_ON(adb->dma_addr & VPDMA_DESC_ALIGN); - - cfd = list->next; - BUG_ON((void *)(cfd + 1) > (list->buf.addr + list->buf.size)); - - cfd->w0 = 0; - cfd->w1 = 0; - cfd->payload_addr = (u32) adb->dma_addr; - cfd->ctl_payload_len = cfd_pkt_payload_len(CFD_INDIRECT, CFD_CLS_ADB, - client, len >> 4); - - list->next = cfd + 1; - - dump_cfd(cfd); -}; -EXPORT_SYMBOL(vpdma_add_cfd_adb); - -/* - * control descriptor format change based on what type of control descriptor it - * is, we only use 'sync on channel' control descriptors for now, so assume it's - * that - */ -static void dump_ctd(struct vpdma_ctd *ctd) -{ - pr_debug("control descriptor\n"); - - pr_debug("word3: pkt_type = %d, source = %d, ctl_type = %d\n", - ctd_get_pkt_type(ctd), ctd_get_source(ctd), ctd_get_ctl(ctd)); -} - -/* - * append a 'sync on channel' type control descriptor to the given descriptor - * list, this descriptor stalls the VPDMA list till the time DMA is completed - * on the specified channel - */ -void vpdma_add_sync_on_channel_ctd(struct vpdma_desc_list *list, - enum vpdma_channel chan) -{ - struct vpdma_ctd *ctd; - - ctd = list->next; - WARN_ON((void *)(ctd + 1) > (list->buf.addr + list->buf.size)); - - ctd->w0 = 0; - ctd->w1 = 0; - ctd->w2 = 0; - ctd->type_source_ctl = ctd_type_source_ctl(chan_info[chan].num, - CTD_TYPE_SYNC_ON_CHANNEL); - - list->next = ctd + 1; - - dump_ctd(ctd); -} -EXPORT_SYMBOL(vpdma_add_sync_on_channel_ctd); - -/* - * append an 'abort_channel' type control descriptor to the given descriptor - * list, this descriptor aborts any DMA transaction happening using the - * specified channel - */ -void vpdma_add_abort_channel_ctd(struct vpdma_desc_list *list, - int chan_num) -{ - struct vpdma_ctd *ctd; - - ctd = list->next; - WARN_ON((void *)(ctd + 1) > (list->buf.addr + list->buf.size)); - - ctd->w0 = 0; - ctd->w1 = 0; - ctd->w2 = 0; - ctd->type_source_ctl = ctd_type_source_ctl(chan_num, - CTD_TYPE_ABORT_CHANNEL); - - list->next = ctd + 1; - - dump_ctd(ctd); -} -EXPORT_SYMBOL(vpdma_add_abort_channel_ctd); - -static void dump_dtd(struct vpdma_dtd *dtd) -{ - int dir, chan; - - dir = dtd_get_dir(dtd); - chan = dtd_get_chan(dtd); - - pr_debug("%s data transfer descriptor for channel %d\n", - dir == DTD_DIR_OUT ? "outbound" : "inbound", chan); - - pr_debug("word0: data_type = %d, notify = %d, field = %d, 1D = %d, even_ln_skp = %d, odd_ln_skp = %d, line_stride = %d\n", - dtd_get_data_type(dtd), dtd_get_notify(dtd), dtd_get_field(dtd), - dtd_get_1d(dtd), dtd_get_even_line_skip(dtd), - dtd_get_odd_line_skip(dtd), dtd_get_line_stride(dtd)); - - if (dir == DTD_DIR_IN) - pr_debug("word1: line_length = %d, xfer_height = %d\n", - dtd_get_line_length(dtd), dtd_get_xfer_height(dtd)); - - pr_debug("word2: start_addr = %x\n", dtd->start_addr); - - pr_debug("word3: pkt_type = %d, mode = %d, dir = %d, chan = %d, pri = %d, next_chan = %d\n", - dtd_get_pkt_type(dtd), - dtd_get_mode(dtd), dir, chan, dtd_get_priority(dtd), - dtd_get_next_chan(dtd)); - - if (dir == DTD_DIR_IN) - pr_debug("word4: frame_width = %d, frame_height = %d\n", - dtd_get_frame_width(dtd), dtd_get_frame_height(dtd)); - else - pr_debug("word4: desc_write_addr = 0x%08x, write_desc = %d, drp_data = %d, use_desc_reg = %d\n", - dtd_get_desc_write_addr(dtd), dtd_get_write_desc(dtd), - dtd_get_drop_data(dtd), dtd_get_use_desc(dtd)); - - if (dir == DTD_DIR_IN) - pr_debug("word5: hor_start = %d, ver_start = %d\n", - dtd_get_h_start(dtd), dtd_get_v_start(dtd)); - else - pr_debug("word5: max_width %d, max_height %d\n", - dtd_get_max_width(dtd), dtd_get_max_height(dtd)); - - pr_debug("word6: client specific attr0 = 0x%08x\n", dtd->client_attr0); - pr_debug("word7: client specific attr1 = 0x%08x\n", dtd->client_attr1); -} - -/* - * append an outbound data transfer descriptor to the given descriptor list, - * this sets up a 'client to memory' VPDMA transfer for the given VPDMA channel - * - * @list: vpdma desc list to which we add this descriptor - * @width: width of the image in pixels in memory - * @c_rect: compose params of output image - * @fmt: vpdma data format of the buffer - * dma_addr: dma address as seen by VPDMA - * max_width: enum for maximum width of data transfer - * max_height: enum for maximum height of data transfer - * chan: VPDMA channel - * flags: VPDMA flags to configure some descriptor fields - */ -void vpdma_add_out_dtd(struct vpdma_desc_list *list, int width, - int stride, const struct v4l2_rect *c_rect, - const struct vpdma_data_format *fmt, dma_addr_t dma_addr, - int max_w, int max_h, enum vpdma_channel chan, u32 flags) -{ - vpdma_rawchan_add_out_dtd(list, width, stride, c_rect, fmt, dma_addr, - max_w, max_h, chan_info[chan].num, flags); -} -EXPORT_SYMBOL(vpdma_add_out_dtd); - -void vpdma_rawchan_add_out_dtd(struct vpdma_desc_list *list, int width, - int stride, const struct v4l2_rect *c_rect, - const struct vpdma_data_format *fmt, dma_addr_t dma_addr, - int max_w, int max_h, int raw_vpdma_chan, u32 flags) -{ - int priority = 0; - int field = 0; - int notify = 1; - int channel, next_chan; - struct v4l2_rect rect = *c_rect; - int depth = fmt->depth; - struct vpdma_dtd *dtd; - - channel = next_chan = raw_vpdma_chan; - - if (fmt->type == VPDMA_DATA_FMT_TYPE_YUV && - (fmt->data_type == DATA_TYPE_C420 || - fmt->data_type == DATA_TYPE_CB420)) { - rect.height >>= 1; - rect.top >>= 1; - depth = 8; - } - - dma_addr += rect.top * stride + (rect.left * depth >> 3); - - dtd = list->next; - WARN_ON((void *)(dtd + 1) > (list->buf.addr + list->buf.size)); - - dtd->type_ctl_stride = dtd_type_ctl_stride(fmt->data_type, - notify, - field, - !!(flags & VPDMA_DATA_FRAME_1D), - !!(flags & VPDMA_DATA_EVEN_LINE_SKIP), - !!(flags & VPDMA_DATA_ODD_LINE_SKIP), - stride); - dtd->w1 = 0; - dtd->start_addr = (u32) dma_addr; - dtd->pkt_ctl = dtd_pkt_ctl(!!(flags & VPDMA_DATA_MODE_TILED), - DTD_DIR_OUT, channel, priority, next_chan); - dtd->desc_write_addr = dtd_desc_write_addr(0, 0, 0, 0); - dtd->max_width_height = dtd_max_width_height(max_w, max_h); - dtd->client_attr0 = 0; - dtd->client_attr1 = 0; - - list->next = dtd + 1; - - dump_dtd(dtd); -} -EXPORT_SYMBOL(vpdma_rawchan_add_out_dtd); - -/* - * append an inbound data transfer descriptor to the given descriptor list, - * this sets up a 'memory to client' VPDMA transfer for the given VPDMA channel - * - * @list: vpdma desc list to which we add this descriptor - * @width: width of the image in pixels in memory(not the cropped width) - * @c_rect: crop params of input image - * @fmt: vpdma data format of the buffer - * dma_addr: dma address as seen by VPDMA - * chan: VPDMA channel - * field: top or bottom field info of the input image - * flags: VPDMA flags to configure some descriptor fields - * frame_width/height: the complete width/height of the image presented to the - * client (this makes sense when multiple channels are - * connected to the same client, forming a larger frame) - * start_h, start_v: position where the given channel starts providing pixel - * data to the client (makes sense when multiple channels - * contribute to the client) - */ -void vpdma_add_in_dtd(struct vpdma_desc_list *list, int width, - int stride, const struct v4l2_rect *c_rect, - const struct vpdma_data_format *fmt, dma_addr_t dma_addr, - enum vpdma_channel chan, int field, u32 flags, int frame_width, - int frame_height, int start_h, int start_v) -{ - int priority = 0; - int notify = 1; - int depth = fmt->depth; - int channel, next_chan; - struct v4l2_rect rect = *c_rect; - struct vpdma_dtd *dtd; - - channel = next_chan = chan_info[chan].num; - - if (fmt->type == VPDMA_DATA_FMT_TYPE_YUV && - (fmt->data_type == DATA_TYPE_C420 || - fmt->data_type == DATA_TYPE_CB420)) { - rect.height >>= 1; - rect.top >>= 1; - depth = 8; - } - - dma_addr += rect.top * stride + (rect.left * depth >> 3); - - dtd = list->next; - WARN_ON((void *)(dtd + 1) > (list->buf.addr + list->buf.size)); - - dtd->type_ctl_stride = dtd_type_ctl_stride(fmt->data_type, - notify, - field, - !!(flags & VPDMA_DATA_FRAME_1D), - !!(flags & VPDMA_DATA_EVEN_LINE_SKIP), - !!(flags & VPDMA_DATA_ODD_LINE_SKIP), - stride); - - dtd->xfer_length_height = dtd_xfer_length_height(rect.width, - rect.height); - dtd->start_addr = (u32) dma_addr; - dtd->pkt_ctl = dtd_pkt_ctl(!!(flags & VPDMA_DATA_MODE_TILED), - DTD_DIR_IN, channel, priority, next_chan); - dtd->frame_width_height = dtd_frame_width_height(frame_width, - frame_height); - dtd->start_h_v = dtd_start_h_v(start_h, start_v); - dtd->client_attr0 = 0; - dtd->client_attr1 = 0; - - list->next = dtd + 1; - - dump_dtd(dtd); -} -EXPORT_SYMBOL(vpdma_add_in_dtd); - -int vpdma_hwlist_alloc(struct vpdma_data *vpdma, void *priv) -{ - int i, list_num = -1; - unsigned long flags; - - spin_lock_irqsave(&vpdma->lock, flags); - for (i = 0; i < VPDMA_MAX_NUM_LIST && vpdma->hwlist_used[i]; i++) - ; - - if (i < VPDMA_MAX_NUM_LIST) { - list_num = i; - vpdma->hwlist_used[i] = true; - vpdma->hwlist_priv[i] = priv; - } - spin_unlock_irqrestore(&vpdma->lock, flags); - - return list_num; -} -EXPORT_SYMBOL(vpdma_hwlist_alloc); - -void *vpdma_hwlist_get_priv(struct vpdma_data *vpdma, int list_num) -{ - if (!vpdma || list_num >= VPDMA_MAX_NUM_LIST) - return NULL; - - return vpdma->hwlist_priv[list_num]; -} -EXPORT_SYMBOL(vpdma_hwlist_get_priv); - -void *vpdma_hwlist_release(struct vpdma_data *vpdma, int list_num) -{ - void *priv; - unsigned long flags; - - spin_lock_irqsave(&vpdma->lock, flags); - vpdma->hwlist_used[list_num] = false; - priv = vpdma->hwlist_priv; - spin_unlock_irqrestore(&vpdma->lock, flags); - - return priv; -} -EXPORT_SYMBOL(vpdma_hwlist_release); - -/* set or clear the mask for list complete interrupt */ -void vpdma_enable_list_complete_irq(struct vpdma_data *vpdma, int irq_num, - int list_num, bool enable) -{ - u32 reg_addr = VPDMA_INT_LIST0_MASK + VPDMA_INTX_OFFSET * irq_num; - u32 val; - - val = read_reg(vpdma, reg_addr); - if (enable) - val |= (1 << (list_num * 2)); - else - val &= ~(1 << (list_num * 2)); - write_reg(vpdma, reg_addr, val); -} -EXPORT_SYMBOL(vpdma_enable_list_complete_irq); - -/* get the LIST_STAT register */ -unsigned int vpdma_get_list_stat(struct vpdma_data *vpdma, int irq_num) -{ - u32 reg_addr = VPDMA_INT_LIST0_STAT + VPDMA_INTX_OFFSET * irq_num; - - return read_reg(vpdma, reg_addr); -} -EXPORT_SYMBOL(vpdma_get_list_stat); - -/* get the LIST_MASK register */ -unsigned int vpdma_get_list_mask(struct vpdma_data *vpdma, int irq_num) -{ - u32 reg_addr = VPDMA_INT_LIST0_MASK + VPDMA_INTX_OFFSET * irq_num; - - return read_reg(vpdma, reg_addr); -} -EXPORT_SYMBOL(vpdma_get_list_mask); - -/* clear previously occurred list interrupts in the LIST_STAT register */ -void vpdma_clear_list_stat(struct vpdma_data *vpdma, int irq_num, - int list_num) -{ - u32 reg_addr = VPDMA_INT_LIST0_STAT + VPDMA_INTX_OFFSET * irq_num; - - write_reg(vpdma, reg_addr, 3 << (list_num * 2)); -} -EXPORT_SYMBOL(vpdma_clear_list_stat); - -void vpdma_set_bg_color(struct vpdma_data *vpdma, - struct vpdma_data_format *fmt, u32 color) -{ - if (fmt->type == VPDMA_DATA_FMT_TYPE_RGB) - write_reg(vpdma, VPDMA_BG_RGB, color); - else if (fmt->type == VPDMA_DATA_FMT_TYPE_YUV) - write_reg(vpdma, VPDMA_BG_YUV, color); -} -EXPORT_SYMBOL(vpdma_set_bg_color); - -/* - * configures the output mode of the line buffer for the given client, the - * line buffer content can either be mirrored(each line repeated twice) or - * passed to the client as is - */ -void vpdma_set_line_mode(struct vpdma_data *vpdma, int line_mode, - enum vpdma_channel chan) -{ - int client_cstat = chan_info[chan].cstat_offset; - - write_field_reg(vpdma, client_cstat, line_mode, - VPDMA_CSTAT_LINE_MODE_MASK, VPDMA_CSTAT_LINE_MODE_SHIFT); -} -EXPORT_SYMBOL(vpdma_set_line_mode); - -/* - * configures the event which should trigger VPDMA transfer for the given - * client - */ -void vpdma_set_frame_start_event(struct vpdma_data *vpdma, - enum vpdma_frame_start_event fs_event, - enum vpdma_channel chan) -{ - int client_cstat = chan_info[chan].cstat_offset; - - write_field_reg(vpdma, client_cstat, fs_event, - VPDMA_CSTAT_FRAME_START_MASK, VPDMA_CSTAT_FRAME_START_SHIFT); -} -EXPORT_SYMBOL(vpdma_set_frame_start_event); - -static void vpdma_firmware_cb(const struct firmware *f, void *context) -{ - struct vpdma_data *vpdma = context; - struct vpdma_buf fw_dma_buf; - int i, r; - - dev_dbg(&vpdma->pdev->dev, "firmware callback\n"); - - if (!f || !f->data) { - dev_err(&vpdma->pdev->dev, "couldn't get firmware\n"); - return; - } - - /* already initialized */ - if (read_field_reg(vpdma, VPDMA_LIST_ATTR, VPDMA_LIST_RDY_MASK, - VPDMA_LIST_RDY_SHFT)) { - vpdma->cb(vpdma->pdev); - return; - } - - r = vpdma_alloc_desc_buf(&fw_dma_buf, f->size); - if (r) { - dev_err(&vpdma->pdev->dev, - "failed to allocate dma buffer for firmware\n"); - goto rel_fw; - } - - memcpy(fw_dma_buf.addr, f->data, f->size); - - vpdma_map_desc_buf(vpdma, &fw_dma_buf); - - write_reg(vpdma, VPDMA_LIST_ADDR, (u32) fw_dma_buf.dma_addr); - - for (i = 0; i < 100; i++) { /* max 1 second */ - msleep_interruptible(10); - - if (read_field_reg(vpdma, VPDMA_LIST_ATTR, VPDMA_LIST_RDY_MASK, - VPDMA_LIST_RDY_SHFT)) - break; - } - - if (i == 100) { - dev_err(&vpdma->pdev->dev, "firmware upload failed\n"); - goto free_buf; - } - - vpdma->cb(vpdma->pdev); - -free_buf: - vpdma_unmap_desc_buf(vpdma, &fw_dma_buf); - - vpdma_free_desc_buf(&fw_dma_buf); -rel_fw: - release_firmware(f); -} - -static int vpdma_load_firmware(struct vpdma_data *vpdma) -{ - int r; - struct device *dev = &vpdma->pdev->dev; - - r = request_firmware_nowait(THIS_MODULE, 1, - (const char *) VPDMA_FIRMWARE, dev, GFP_KERNEL, vpdma, - vpdma_firmware_cb); - if (r) { - dev_err(dev, "firmware not available %s\n", VPDMA_FIRMWARE); - return r; - } else { - dev_info(dev, "loading firmware %s\n", VPDMA_FIRMWARE); - } - - return 0; -} - -int vpdma_create(struct platform_device *pdev, struct vpdma_data *vpdma, - void (*cb)(struct platform_device *pdev)) -{ - struct resource *res; - int r; - - dev_dbg(&pdev->dev, "vpdma_create\n"); - - vpdma->pdev = pdev; - vpdma->cb = cb; - spin_lock_init(&vpdma->lock); - - res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "vpdma"); - if (res == NULL) { - dev_err(&pdev->dev, "missing platform resources data\n"); - return -ENODEV; - } - - vpdma->base = devm_ioremap(&pdev->dev, res->start, resource_size(res)); - if (!vpdma->base) { - dev_err(&pdev->dev, "failed to ioremap\n"); - return -ENOMEM; - } - - r = vpdma_load_firmware(vpdma); - if (r) { - pr_err("failed to load firmware %s\n", VPDMA_FIRMWARE); - return r; - } - - return 0; -} -EXPORT_SYMBOL(vpdma_create); - -MODULE_AUTHOR("Texas Instruments Inc."); -MODULE_FIRMWARE(VPDMA_FIRMWARE); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/platform/ti-vpe/vpdma.h b/drivers/media/platform/ti-vpe/vpdma.h deleted file mode 100644 index 393fcbb3cb40..000000000000 --- a/drivers/media/platform/ti-vpe/vpdma.h +++ /dev/null @@ -1,284 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * Copyright (c) 2013 Texas Instruments Inc. - * - * David Griego, - * Dale Farnsworth, - * Archit Taneja, - */ - -#ifndef __TI_VPDMA_H_ -#define __TI_VPDMA_H_ - -#define VPDMA_MAX_NUM_LIST 8 -/* - * A vpdma_buf tracks the size, DMA address and mapping status of each - * driver DMA area. - */ -struct vpdma_buf { - void *addr; - dma_addr_t dma_addr; - size_t size; - bool mapped; -}; - -struct vpdma_desc_list { - struct vpdma_buf buf; - void *next; - int type; -}; - -struct vpdma_data { - void __iomem *base; - - struct platform_device *pdev; - - spinlock_t lock; - bool hwlist_used[VPDMA_MAX_NUM_LIST]; - void *hwlist_priv[VPDMA_MAX_NUM_LIST]; - /* callback to VPE driver when the firmware is loaded */ - void (*cb)(struct platform_device *pdev); -}; - -enum vpdma_data_format_type { - VPDMA_DATA_FMT_TYPE_YUV, - VPDMA_DATA_FMT_TYPE_RGB, - VPDMA_DATA_FMT_TYPE_MISC, -}; - -struct vpdma_data_format { - enum vpdma_data_format_type type; - int data_type; - u8 depth; -}; - -#define VPDMA_DESC_ALIGN 16 /* 16-byte descriptor alignment */ -#define VPDMA_STRIDE_ALIGN 16 /* - * line stride of source and dest - * buffers should be 16 byte aligned - */ -#define VPDMA_MAX_STRIDE 65520 /* Max line stride 16 byte aligned */ -#define VPDMA_DTD_DESC_SIZE 32 /* 8 words */ -#define VPDMA_CFD_CTD_DESC_SIZE 16 /* 4 words */ - -#define VPDMA_LIST_TYPE_NORMAL 0 -#define VPDMA_LIST_TYPE_SELF_MODIFYING 1 -#define VPDMA_LIST_TYPE_DOORBELL 2 - -enum vpdma_yuv_formats { - VPDMA_DATA_FMT_Y444 = 0, - VPDMA_DATA_FMT_Y422, - VPDMA_DATA_FMT_Y420, - VPDMA_DATA_FMT_C444, - VPDMA_DATA_FMT_C422, - VPDMA_DATA_FMT_C420, - VPDMA_DATA_FMT_CB420, - VPDMA_DATA_FMT_YCR422, - VPDMA_DATA_FMT_YC444, - VPDMA_DATA_FMT_CRY422, - VPDMA_DATA_FMT_CBY422, - VPDMA_DATA_FMT_YCB422, -}; - -enum vpdma_rgb_formats { - VPDMA_DATA_FMT_RGB565 = 0, - VPDMA_DATA_FMT_ARGB16_1555, - VPDMA_DATA_FMT_ARGB16, - VPDMA_DATA_FMT_RGBA16_5551, - VPDMA_DATA_FMT_RGBA16, - VPDMA_DATA_FMT_ARGB24, - VPDMA_DATA_FMT_RGB24, - VPDMA_DATA_FMT_ARGB32, - VPDMA_DATA_FMT_RGBA24, - VPDMA_DATA_FMT_RGBA32, - VPDMA_DATA_FMT_BGR565, - VPDMA_DATA_FMT_ABGR16_1555, - VPDMA_DATA_FMT_ABGR16, - VPDMA_DATA_FMT_BGRA16_5551, - VPDMA_DATA_FMT_BGRA16, - VPDMA_DATA_FMT_ABGR24, - VPDMA_DATA_FMT_BGR24, - VPDMA_DATA_FMT_ABGR32, - VPDMA_DATA_FMT_BGRA24, - VPDMA_DATA_FMT_BGRA32, -}; - -enum vpdma_raw_formats { - VPDMA_DATA_FMT_RAW8 = 0, - VPDMA_DATA_FMT_RAW16, -}; - -enum vpdma_misc_formats { - VPDMA_DATA_FMT_MV = 0, -}; - -extern const struct vpdma_data_format vpdma_yuv_fmts[]; -extern const struct vpdma_data_format vpdma_rgb_fmts[]; -extern const struct vpdma_data_format vpdma_raw_fmts[]; -extern const struct vpdma_data_format vpdma_misc_fmts[]; - -enum vpdma_frame_start_event { - VPDMA_FSEVENT_HDMI_FID = 0, - VPDMA_FSEVENT_DVO2_FID, - VPDMA_FSEVENT_HDCOMP_FID, - VPDMA_FSEVENT_SD_FID, - VPDMA_FSEVENT_LM_FID0, - VPDMA_FSEVENT_LM_FID1, - VPDMA_FSEVENT_LM_FID2, - VPDMA_FSEVENT_CHANNEL_ACTIVE, -}; - -/* max width configurations */ -enum vpdma_max_width { - MAX_OUT_WIDTH_UNLIMITED = 0, - MAX_OUT_WIDTH_REG1, - MAX_OUT_WIDTH_REG2, - MAX_OUT_WIDTH_REG3, - MAX_OUT_WIDTH_352, - MAX_OUT_WIDTH_768, - MAX_OUT_WIDTH_1280, - MAX_OUT_WIDTH_1920, -}; - -/* max height configurations */ -enum vpdma_max_height { - MAX_OUT_HEIGHT_UNLIMITED = 0, - MAX_OUT_HEIGHT_REG1, - MAX_OUT_HEIGHT_REG2, - MAX_OUT_HEIGHT_REG3, - MAX_OUT_HEIGHT_288, - MAX_OUT_HEIGHT_576, - MAX_OUT_HEIGHT_720, - MAX_OUT_HEIGHT_1080, -}; - -/* - * VPDMA channel numbers - */ -enum vpdma_channel { - VPE_CHAN_LUMA1_IN, - VPE_CHAN_CHROMA1_IN, - VPE_CHAN_LUMA2_IN, - VPE_CHAN_CHROMA2_IN, - VPE_CHAN_LUMA3_IN, - VPE_CHAN_CHROMA3_IN, - VPE_CHAN_MV_IN, - VPE_CHAN_MV_OUT, - VPE_CHAN_LUMA_OUT, - VPE_CHAN_CHROMA_OUT, - VPE_CHAN_RGB_OUT, -}; - -#define VIP_CHAN_VIP2_OFFSET 70 -#define VIP_CHAN_MULT_PORTB_OFFSET 16 -#define VIP_CHAN_YUV_PORTB_OFFSET 2 -#define VIP_CHAN_RGB_PORTB_OFFSET 1 - -#define VPDMA_MAX_CHANNELS 256 - -/* flags for VPDMA data descriptors */ -#define VPDMA_DATA_ODD_LINE_SKIP (1 << 0) -#define VPDMA_DATA_EVEN_LINE_SKIP (1 << 1) -#define VPDMA_DATA_FRAME_1D (1 << 2) -#define VPDMA_DATA_MODE_TILED (1 << 3) - -/* - * client identifiers used for configuration descriptors - */ -#define CFD_MMR_CLIENT 0 -#define CFD_SC_CLIENT 4 - -/* Address data block header format */ -struct vpdma_adb_hdr { - u32 offset; - u32 nwords; - u32 reserved0; - u32 reserved1; -}; - -/* helpers for creating ADB headers for config descriptors MMRs as client */ -#define ADB_ADDR(dma_buf, str, fld) ((dma_buf)->addr + offsetof(str, fld)) -#define MMR_ADB_ADDR(buf, str, fld) ADB_ADDR(&(buf), struct str, fld) - -#define VPDMA_SET_MMR_ADB_HDR(buf, str, hdr, regs, offset_a) \ - do { \ - struct vpdma_adb_hdr *h; \ - struct str *adb = NULL; \ - h = MMR_ADB_ADDR(buf, str, hdr); \ - h->offset = (offset_a); \ - h->nwords = sizeof(adb->regs) >> 2; \ - } while (0) - -/* vpdma descriptor buffer allocation and management */ -int vpdma_alloc_desc_buf(struct vpdma_buf *buf, size_t size); -void vpdma_free_desc_buf(struct vpdma_buf *buf); -int vpdma_map_desc_buf(struct vpdma_data *vpdma, struct vpdma_buf *buf); -void vpdma_unmap_desc_buf(struct vpdma_data *vpdma, struct vpdma_buf *buf); - -/* vpdma descriptor list funcs */ -int vpdma_create_desc_list(struct vpdma_desc_list *list, size_t size, int type); -void vpdma_reset_desc_list(struct vpdma_desc_list *list); -void vpdma_free_desc_list(struct vpdma_desc_list *list); -int vpdma_submit_descs(struct vpdma_data *vpdma, struct vpdma_desc_list *list, - int list_num); -bool vpdma_list_busy(struct vpdma_data *vpdma, int list_num); -void vpdma_update_dma_addr(struct vpdma_data *vpdma, - struct vpdma_desc_list *list, dma_addr_t dma_addr, - void *write_dtd, int drop, int idx); - -/* VPDMA hardware list funcs */ -int vpdma_hwlist_alloc(struct vpdma_data *vpdma, void *priv); -void *vpdma_hwlist_get_priv(struct vpdma_data *vpdma, int list_num); -void *vpdma_hwlist_release(struct vpdma_data *vpdma, int list_num); - -/* helpers for creating vpdma descriptors */ -void vpdma_add_cfd_block(struct vpdma_desc_list *list, int client, - struct vpdma_buf *blk, u32 dest_offset); -void vpdma_add_cfd_adb(struct vpdma_desc_list *list, int client, - struct vpdma_buf *adb); -void vpdma_add_sync_on_channel_ctd(struct vpdma_desc_list *list, - enum vpdma_channel chan); -void vpdma_add_abort_channel_ctd(struct vpdma_desc_list *list, - int chan_num); -void vpdma_add_out_dtd(struct vpdma_desc_list *list, int width, - int stride, const struct v4l2_rect *c_rect, - const struct vpdma_data_format *fmt, dma_addr_t dma_addr, - int max_w, int max_h, enum vpdma_channel chan, u32 flags); -void vpdma_rawchan_add_out_dtd(struct vpdma_desc_list *list, int width, - int stride, const struct v4l2_rect *c_rect, - const struct vpdma_data_format *fmt, dma_addr_t dma_addr, - int max_w, int max_h, int raw_vpdma_chan, u32 flags); - -void vpdma_add_in_dtd(struct vpdma_desc_list *list, int width, - int stride, const struct v4l2_rect *c_rect, - const struct vpdma_data_format *fmt, dma_addr_t dma_addr, - enum vpdma_channel chan, int field, u32 flags, int frame_width, - int frame_height, int start_h, int start_v); -int vpdma_list_cleanup(struct vpdma_data *vpdma, int list_num, - int *channels, int size); - -/* vpdma list interrupt management */ -void vpdma_enable_list_complete_irq(struct vpdma_data *vpdma, int irq_num, - int list_num, bool enable); -void vpdma_clear_list_stat(struct vpdma_data *vpdma, int irq_num, - int list_num); -unsigned int vpdma_get_list_stat(struct vpdma_data *vpdma, int irq_num); -unsigned int vpdma_get_list_mask(struct vpdma_data *vpdma, int irq_num); - -/* vpdma client configuration */ -void vpdma_set_line_mode(struct vpdma_data *vpdma, int line_mode, - enum vpdma_channel chan); -void vpdma_set_frame_start_event(struct vpdma_data *vpdma, - enum vpdma_frame_start_event fs_event, enum vpdma_channel chan); -void vpdma_set_max_size(struct vpdma_data *vpdma, int reg_addr, - u32 width, u32 height); - -void vpdma_set_bg_color(struct vpdma_data *vpdma, - struct vpdma_data_format *fmt, u32 color); -void vpdma_dump_regs(struct vpdma_data *vpdma); - -/* initialize vpdma, passed with VPE's platform device pointer */ -int vpdma_create(struct platform_device *pdev, struct vpdma_data *vpdma, - void (*cb)(struct platform_device *pdev)); - -#endif diff --git a/drivers/media/platform/ti-vpe/vpdma_priv.h b/drivers/media/platform/ti-vpe/vpdma_priv.h deleted file mode 100644 index 0bbee45338bd..000000000000 --- a/drivers/media/platform/ti-vpe/vpdma_priv.h +++ /dev/null @@ -1,639 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * Copyright (c) 2013 Texas Instruments Inc. - * - * David Griego, - * Dale Farnsworth, - * Archit Taneja, - */ - -#ifndef _TI_VPDMA_PRIV_H_ -#define _TI_VPDMA_PRIV_H_ - -/* - * VPDMA Register offsets - */ - -/* Top level */ -#define VPDMA_PID 0x00 -#define VPDMA_LIST_ADDR 0x04 -#define VPDMA_LIST_ATTR 0x08 -#define VPDMA_LIST_STAT_SYNC 0x0c -#define VPDMA_BG_RGB 0x18 -#define VPDMA_BG_YUV 0x1c -#define VPDMA_SETUP 0x30 -#define VPDMA_MAX_SIZE1 0x34 -#define VPDMA_MAX_SIZE2 0x38 -#define VPDMA_MAX_SIZE3 0x3c -#define VPDMA_MAX_SIZE_WIDTH_MASK 0xffff -#define VPDMA_MAX_SIZE_WIDTH_SHFT 16 -#define VPDMA_MAX_SIZE_HEIGHT_MASK 0xffff -#define VPDMA_MAX_SIZE_HEIGHT_SHFT 0 - -/* Interrupts */ -#define VPDMA_INT_CHAN_STAT(grp) (0x40 + grp * 8) -#define VPDMA_INT_CHAN_MASK(grp) (VPDMA_INT_CHAN_STAT(grp) + 4) -#define VPDMA_INT_CLIENT0_STAT 0x78 -#define VPDMA_INT_CLIENT0_MASK 0x7c -#define VPDMA_INT_CLIENT1_STAT 0x80 -#define VPDMA_INT_CLIENT1_MASK 0x84 -#define VPDMA_INT_LIST0_STAT 0x88 -#define VPDMA_INT_LIST0_MASK 0x8c - -#define VPDMA_INTX_OFFSET 0x50 - -#define VPDMA_PERFMON(i) (0x200 + i * 4) - -/* VIP/VPE client registers */ -#define VPDMA_DEI_CHROMA1_CSTAT 0x0300 -#define VPDMA_DEI_LUMA1_CSTAT 0x0304 -#define VPDMA_DEI_LUMA2_CSTAT 0x0308 -#define VPDMA_DEI_CHROMA2_CSTAT 0x030c -#define VPDMA_DEI_LUMA3_CSTAT 0x0310 -#define VPDMA_DEI_CHROMA3_CSTAT 0x0314 -#define VPDMA_DEI_MV_IN_CSTAT 0x0330 -#define VPDMA_DEI_MV_OUT_CSTAT 0x033c -#define VPDMA_VIP_LO_Y_CSTAT 0x0388 -#define VPDMA_VIP_LO_UV_CSTAT 0x038c -#define VPDMA_VIP_UP_Y_CSTAT 0x0390 -#define VPDMA_VIP_UP_UV_CSTAT 0x0394 -#define VPDMA_VPI_CTL_CSTAT 0x03d0 - -/* Reg field info for VPDMA_CLIENT_CSTAT registers */ -#define VPDMA_CSTAT_LINE_MODE_MASK 0x03 -#define VPDMA_CSTAT_LINE_MODE_SHIFT 8 -#define VPDMA_CSTAT_FRAME_START_MASK 0xf -#define VPDMA_CSTAT_FRAME_START_SHIFT 10 - -#define VPDMA_LIST_NUM_MASK 0x07 -#define VPDMA_LIST_NUM_SHFT 24 -#define VPDMA_LIST_STOP_SHFT 20 -#define VPDMA_LIST_RDY_MASK 0x01 -#define VPDMA_LIST_RDY_SHFT 19 -#define VPDMA_LIST_TYPE_MASK 0x03 -#define VPDMA_LIST_TYPE_SHFT 16 -#define VPDMA_LIST_SIZE_MASK 0xffff - -/* - * The YUV data type definition below are taken from - * both the TRM and i839 Errata information. - * Use the correct data type considering byte - * reordering of components. - * - * Also since the single use of "C" in the 422 case - * to mean "Cr" (i.e. V component). It was decided - * to explicitly label them CR to remove any confusion. - * Bear in mind that the type label refer to the memory - * packed order (LSB - MSB). - */ -#define DATA_TYPE_Y444 0x0 -#define DATA_TYPE_Y422 0x1 -#define DATA_TYPE_Y420 0x2 -#define DATA_TYPE_C444 0x4 -#define DATA_TYPE_C422 0x5 -#define DATA_TYPE_C420 0x6 -#define DATA_TYPE_CB420 0x16 -#define DATA_TYPE_YC444 0x8 -#define DATA_TYPE_YCB422 0x7 -#define DATA_TYPE_YCR422 0x17 -#define DATA_TYPE_CBY422 0x27 -#define DATA_TYPE_CRY422 0x37 - -/* - * The RGB data type definition below are defined - * to follow Errata i819. - * The initial values were taken from: - * VPDMA_data_type_mapping_v0.2vayu_c.pdf - * But some of the ARGB definition appeared to be wrong - * in the document also. As they would yield RGBA instead. - * They have been corrected based on experimentation. - */ -#define DATA_TYPE_RGB16_565 0x10 -#define DATA_TYPE_ARGB_1555 0x13 -#define DATA_TYPE_ARGB_4444 0x14 -#define DATA_TYPE_RGBA_5551 0x11 -#define DATA_TYPE_RGBA_4444 0x12 -#define DATA_TYPE_ARGB24_6666 0x18 -#define DATA_TYPE_RGB24_888 0x16 -#define DATA_TYPE_ARGB32_8888 0x17 -#define DATA_TYPE_RGBA24_6666 0x15 -#define DATA_TYPE_RGBA32_8888 0x19 -#define DATA_TYPE_BGR16_565 0x0 -#define DATA_TYPE_ABGR_1555 0x3 -#define DATA_TYPE_ABGR_4444 0x4 -#define DATA_TYPE_BGRA_5551 0x1 -#define DATA_TYPE_BGRA_4444 0x2 -#define DATA_TYPE_ABGR24_6666 0x8 -#define DATA_TYPE_BGR24_888 0x6 -#define DATA_TYPE_ABGR32_8888 0x7 -#define DATA_TYPE_BGRA24_6666 0x5 -#define DATA_TYPE_BGRA32_8888 0x9 - -#define DATA_TYPE_MV 0x3 - -/* VPDMA channel numbers, some are common between VIP/VPE and appear twice */ -#define VPE_CHAN_NUM_LUMA1_IN 0 -#define VPE_CHAN_NUM_CHROMA1_IN 1 -#define VPE_CHAN_NUM_LUMA2_IN 2 -#define VPE_CHAN_NUM_CHROMA2_IN 3 -#define VPE_CHAN_NUM_LUMA3_IN 4 -#define VPE_CHAN_NUM_CHROMA3_IN 5 -#define VPE_CHAN_NUM_MV_IN 12 -#define VPE_CHAN_NUM_MV_OUT 15 -#define VIP1_CHAN_NUM_MULT_PORT_A_SRC0 38 -#define VIP1_CHAN_NUM_MULT_ANC_A_SRC0 70 -#define VPE_CHAN_NUM_LUMA_OUT 102 -#define VPE_CHAN_NUM_CHROMA_OUT 103 -#define VIP1_CHAN_NUM_PORT_A_LUMA 102 -#define VIP1_CHAN_NUM_PORT_A_CHROMA 103 -#define VPE_CHAN_NUM_RGB_OUT 106 -#define VIP1_CHAN_NUM_PORT_A_RGB 106 -#define VIP1_CHAN_NUM_PORT_B_RGB 107 -/* - * a VPDMA address data block payload for a configuration descriptor needs to - * have each sub block length as a multiple of 16 bytes. Therefore, the overall - * size of the payload also needs to be a multiple of 16 bytes. The sub block - * lengths should be ensured to be aligned by the VPDMA user. - */ -#define VPDMA_ADB_SIZE_ALIGN 0x0f - -/* - * data transfer descriptor - */ -struct vpdma_dtd { - u32 type_ctl_stride; - union { - u32 xfer_length_height; - u32 w1; - }; - u32 start_addr; - u32 pkt_ctl; - union { - u32 frame_width_height; /* inbound */ - u32 desc_write_addr; /* outbound */ - }; - union { - u32 start_h_v; /* inbound */ - u32 max_width_height; /* outbound */ - }; - u32 client_attr0; - u32 client_attr1; -}; - -/* Data Transfer Descriptor specifics */ -#define DTD_NO_NOTIFY 0 -#define DTD_NOTIFY 1 - -#define DTD_PKT_TYPE 0xa -#define DTD_DIR_IN 0 -#define DTD_DIR_OUT 1 - -/* type_ctl_stride */ -#define DTD_DATA_TYPE_MASK 0x3f -#define DTD_DATA_TYPE_SHFT 26 -#define DTD_NOTIFY_MASK 0x01 -#define DTD_NOTIFY_SHFT 25 -#define DTD_FIELD_MASK 0x01 -#define DTD_FIELD_SHFT 24 -#define DTD_1D_MASK 0x01 -#define DTD_1D_SHFT 23 -#define DTD_EVEN_LINE_SKIP_MASK 0x01 -#define DTD_EVEN_LINE_SKIP_SHFT 20 -#define DTD_ODD_LINE_SKIP_MASK 0x01 -#define DTD_ODD_LINE_SKIP_SHFT 16 -#define DTD_LINE_STRIDE_MASK 0xffff -#define DTD_LINE_STRIDE_SHFT 0 - -/* xfer_length_height */ -#define DTD_LINE_LENGTH_MASK 0xffff -#define DTD_LINE_LENGTH_SHFT 16 -#define DTD_XFER_HEIGHT_MASK 0xffff -#define DTD_XFER_HEIGHT_SHFT 0 - -/* pkt_ctl */ -#define DTD_PKT_TYPE_MASK 0x1f -#define DTD_PKT_TYPE_SHFT 27 -#define DTD_MODE_MASK 0x01 -#define DTD_MODE_SHFT 26 -#define DTD_DIR_MASK 0x01 -#define DTD_DIR_SHFT 25 -#define DTD_CHAN_MASK 0x01ff -#define DTD_CHAN_SHFT 16 -#define DTD_PRI_MASK 0x0f -#define DTD_PRI_SHFT 9 -#define DTD_NEXT_CHAN_MASK 0x01ff -#define DTD_NEXT_CHAN_SHFT 0 - -/* frame_width_height */ -#define DTD_FRAME_WIDTH_MASK 0xffff -#define DTD_FRAME_WIDTH_SHFT 16 -#define DTD_FRAME_HEIGHT_MASK 0xffff -#define DTD_FRAME_HEIGHT_SHFT 0 - -/* start_h_v */ -#define DTD_H_START_MASK 0xffff -#define DTD_H_START_SHFT 16 -#define DTD_V_START_MASK 0xffff -#define DTD_V_START_SHFT 0 - -#define DTD_DESC_START_MASK 0xffffffe0 -#define DTD_DESC_START_SHIFT 5 -#define DTD_WRITE_DESC_MASK 0x01 -#define DTD_WRITE_DESC_SHIFT 2 -#define DTD_DROP_DATA_MASK 0x01 -#define DTD_DROP_DATA_SHIFT 1 -#define DTD_USE_DESC_MASK 0x01 -#define DTD_USE_DESC_SHIFT 0 - -/* max_width_height */ -#define DTD_MAX_WIDTH_MASK 0x07 -#define DTD_MAX_WIDTH_SHFT 4 -#define DTD_MAX_HEIGHT_MASK 0x07 -#define DTD_MAX_HEIGHT_SHFT 0 - -static inline u32 dtd_type_ctl_stride(int type, bool notify, int field, - bool one_d, bool even_line_skip, bool odd_line_skip, - int line_stride) -{ - return (type << DTD_DATA_TYPE_SHFT) | (notify << DTD_NOTIFY_SHFT) | - (field << DTD_FIELD_SHFT) | (one_d << DTD_1D_SHFT) | - (even_line_skip << DTD_EVEN_LINE_SKIP_SHFT) | - (odd_line_skip << DTD_ODD_LINE_SKIP_SHFT) | - line_stride; -} - -static inline u32 dtd_xfer_length_height(int line_length, int xfer_height) -{ - return (line_length << DTD_LINE_LENGTH_SHFT) | xfer_height; -} - -static inline u32 dtd_pkt_ctl(bool mode, bool dir, int chan, int pri, - int next_chan) -{ - return (DTD_PKT_TYPE << DTD_PKT_TYPE_SHFT) | (mode << DTD_MODE_SHFT) | - (dir << DTD_DIR_SHFT) | (chan << DTD_CHAN_SHFT) | - (pri << DTD_PRI_SHFT) | next_chan; -} - -static inline u32 dtd_frame_width_height(int width, int height) -{ - return (width << DTD_FRAME_WIDTH_SHFT) | height; -} - -static inline u32 dtd_desc_write_addr(unsigned int addr, bool write_desc, - bool drop_data, bool use_desc) -{ - return (addr & DTD_DESC_START_MASK) | - (write_desc << DTD_WRITE_DESC_SHIFT) | - (drop_data << DTD_DROP_DATA_SHIFT) | - use_desc; -} - -static inline u32 dtd_start_h_v(int h_start, int v_start) -{ - return (h_start << DTD_H_START_SHFT) | v_start; -} - -static inline u32 dtd_max_width_height(int max_width, int max_height) -{ - return (max_width << DTD_MAX_WIDTH_SHFT) | max_height; -} - -static inline int dtd_get_data_type(struct vpdma_dtd *dtd) -{ - return dtd->type_ctl_stride >> DTD_DATA_TYPE_SHFT; -} - -static inline bool dtd_get_notify(struct vpdma_dtd *dtd) -{ - return (dtd->type_ctl_stride >> DTD_NOTIFY_SHFT) & DTD_NOTIFY_MASK; -} - -static inline int dtd_get_field(struct vpdma_dtd *dtd) -{ - return (dtd->type_ctl_stride >> DTD_FIELD_SHFT) & DTD_FIELD_MASK; -} - -static inline bool dtd_get_1d(struct vpdma_dtd *dtd) -{ - return (dtd->type_ctl_stride >> DTD_1D_SHFT) & DTD_1D_MASK; -} - -static inline bool dtd_get_even_line_skip(struct vpdma_dtd *dtd) -{ - return (dtd->type_ctl_stride >> DTD_EVEN_LINE_SKIP_SHFT) - & DTD_EVEN_LINE_SKIP_MASK; -} - -static inline bool dtd_get_odd_line_skip(struct vpdma_dtd *dtd) -{ - return (dtd->type_ctl_stride >> DTD_ODD_LINE_SKIP_SHFT) - & DTD_ODD_LINE_SKIP_MASK; -} - -static inline int dtd_get_line_stride(struct vpdma_dtd *dtd) -{ - return dtd->type_ctl_stride & DTD_LINE_STRIDE_MASK; -} - -static inline int dtd_get_line_length(struct vpdma_dtd *dtd) -{ - return dtd->xfer_length_height >> DTD_LINE_LENGTH_SHFT; -} - -static inline int dtd_get_xfer_height(struct vpdma_dtd *dtd) -{ - return dtd->xfer_length_height & DTD_XFER_HEIGHT_MASK; -} - -static inline int dtd_get_pkt_type(struct vpdma_dtd *dtd) -{ - return dtd->pkt_ctl >> DTD_PKT_TYPE_SHFT; -} - -static inline bool dtd_get_mode(struct vpdma_dtd *dtd) -{ - return (dtd->pkt_ctl >> DTD_MODE_SHFT) & DTD_MODE_MASK; -} - -static inline bool dtd_get_dir(struct vpdma_dtd *dtd) -{ - return (dtd->pkt_ctl >> DTD_DIR_SHFT) & DTD_DIR_MASK; -} - -static inline int dtd_get_chan(struct vpdma_dtd *dtd) -{ - return (dtd->pkt_ctl >> DTD_CHAN_SHFT) & DTD_CHAN_MASK; -} - -static inline int dtd_get_priority(struct vpdma_dtd *dtd) -{ - return (dtd->pkt_ctl >> DTD_PRI_SHFT) & DTD_PRI_MASK; -} - -static inline int dtd_get_next_chan(struct vpdma_dtd *dtd) -{ - return (dtd->pkt_ctl >> DTD_NEXT_CHAN_SHFT) & DTD_NEXT_CHAN_MASK; -} - -static inline int dtd_get_frame_width(struct vpdma_dtd *dtd) -{ - return dtd->frame_width_height >> DTD_FRAME_WIDTH_SHFT; -} - -static inline int dtd_get_frame_height(struct vpdma_dtd *dtd) -{ - return dtd->frame_width_height & DTD_FRAME_HEIGHT_MASK; -} - -static inline int dtd_get_desc_write_addr(struct vpdma_dtd *dtd) -{ - return dtd->desc_write_addr & DTD_DESC_START_MASK; -} - -static inline bool dtd_get_write_desc(struct vpdma_dtd *dtd) -{ - return (dtd->desc_write_addr >> DTD_WRITE_DESC_SHIFT) & - DTD_WRITE_DESC_MASK; -} - -static inline bool dtd_get_drop_data(struct vpdma_dtd *dtd) -{ - return (dtd->desc_write_addr >> DTD_DROP_DATA_SHIFT) & - DTD_DROP_DATA_MASK; -} - -static inline bool dtd_get_use_desc(struct vpdma_dtd *dtd) -{ - return dtd->desc_write_addr & DTD_USE_DESC_MASK; -} - -static inline int dtd_get_h_start(struct vpdma_dtd *dtd) -{ - return dtd->start_h_v >> DTD_H_START_SHFT; -} - -static inline int dtd_get_v_start(struct vpdma_dtd *dtd) -{ - return dtd->start_h_v & DTD_V_START_MASK; -} - -static inline int dtd_get_max_width(struct vpdma_dtd *dtd) -{ - return (dtd->max_width_height >> DTD_MAX_WIDTH_SHFT) & - DTD_MAX_WIDTH_MASK; -} - -static inline int dtd_get_max_height(struct vpdma_dtd *dtd) -{ - return (dtd->max_width_height >> DTD_MAX_HEIGHT_SHFT) & - DTD_MAX_HEIGHT_MASK; -} - -/* - * configuration descriptor - */ -struct vpdma_cfd { - union { - u32 dest_addr_offset; - u32 w0; - }; - union { - u32 block_len; /* in words */ - u32 w1; - }; - u32 payload_addr; - u32 ctl_payload_len; /* in words */ -}; - -/* Configuration descriptor specifics */ - -#define CFD_PKT_TYPE 0xb - -#define CFD_DIRECT 1 -#define CFD_INDIRECT 0 -#define CFD_CLS_ADB 0 -#define CFD_CLS_BLOCK 1 - -/* block_len */ -#define CFD__BLOCK_LEN_MASK 0xffff -#define CFD__BLOCK_LEN_SHFT 0 - -/* ctl_payload_len */ -#define CFD_PKT_TYPE_MASK 0x1f -#define CFD_PKT_TYPE_SHFT 27 -#define CFD_DIRECT_MASK 0x01 -#define CFD_DIRECT_SHFT 26 -#define CFD_CLASS_MASK 0x03 -#define CFD_CLASS_SHFT 24 -#define CFD_DEST_MASK 0xff -#define CFD_DEST_SHFT 16 -#define CFD_PAYLOAD_LEN_MASK 0xffff -#define CFD_PAYLOAD_LEN_SHFT 0 - -static inline u32 cfd_pkt_payload_len(bool direct, int cls, int dest, - int payload_len) -{ - return (CFD_PKT_TYPE << CFD_PKT_TYPE_SHFT) | - (direct << CFD_DIRECT_SHFT) | - (cls << CFD_CLASS_SHFT) | - (dest << CFD_DEST_SHFT) | - payload_len; -} - -static inline int cfd_get_pkt_type(struct vpdma_cfd *cfd) -{ - return cfd->ctl_payload_len >> CFD_PKT_TYPE_SHFT; -} - -static inline bool cfd_get_direct(struct vpdma_cfd *cfd) -{ - return (cfd->ctl_payload_len >> CFD_DIRECT_SHFT) & CFD_DIRECT_MASK; -} - -static inline bool cfd_get_class(struct vpdma_cfd *cfd) -{ - return (cfd->ctl_payload_len >> CFD_CLASS_SHFT) & CFD_CLASS_MASK; -} - -static inline int cfd_get_dest(struct vpdma_cfd *cfd) -{ - return (cfd->ctl_payload_len >> CFD_DEST_SHFT) & CFD_DEST_MASK; -} - -static inline int cfd_get_payload_len(struct vpdma_cfd *cfd) -{ - return cfd->ctl_payload_len & CFD_PAYLOAD_LEN_MASK; -} - -/* - * control descriptor - */ -struct vpdma_ctd { - union { - u32 timer_value; - u32 list_addr; - u32 w0; - }; - union { - u32 pixel_line_count; - u32 list_size; - u32 w1; - }; - union { - u32 event; - u32 fid_ctl; - u32 w2; - }; - u32 type_source_ctl; -}; - -/* control descriptor types */ -#define CTD_TYPE_SYNC_ON_CLIENT 0 -#define CTD_TYPE_SYNC_ON_LIST 1 -#define CTD_TYPE_SYNC_ON_EXT 2 -#define CTD_TYPE_SYNC_ON_LM_TIMER 3 -#define CTD_TYPE_SYNC_ON_CHANNEL 4 -#define CTD_TYPE_CHNG_CLIENT_IRQ 5 -#define CTD_TYPE_SEND_IRQ 6 -#define CTD_TYPE_RELOAD_LIST 7 -#define CTD_TYPE_ABORT_CHANNEL 8 - -#define CTD_PKT_TYPE 0xc - -/* timer_value */ -#define CTD_TIMER_VALUE_MASK 0xffff -#define CTD_TIMER_VALUE_SHFT 0 - -/* pixel_line_count */ -#define CTD_PIXEL_COUNT_MASK 0xffff -#define CTD_PIXEL_COUNT_SHFT 16 -#define CTD_LINE_COUNT_MASK 0xffff -#define CTD_LINE_COUNT_SHFT 0 - -/* list_size */ -#define CTD_LIST_SIZE_MASK 0xffff -#define CTD_LIST_SIZE_SHFT 0 - -/* event */ -#define CTD_EVENT_MASK 0x0f -#define CTD_EVENT_SHFT 0 - -/* fid_ctl */ -#define CTD_FID2_MASK 0x03 -#define CTD_FID2_SHFT 4 -#define CTD_FID1_MASK 0x03 -#define CTD_FID1_SHFT 2 -#define CTD_FID0_MASK 0x03 -#define CTD_FID0_SHFT 0 - -/* type_source_ctl */ -#define CTD_PKT_TYPE_MASK 0x1f -#define CTD_PKT_TYPE_SHFT 27 -#define CTD_SOURCE_MASK 0xff -#define CTD_SOURCE_SHFT 16 -#define CTD_CONTROL_MASK 0x0f -#define CTD_CONTROL_SHFT 0 - -static inline u32 ctd_pixel_line_count(int pixel_count, int line_count) -{ - return (pixel_count << CTD_PIXEL_COUNT_SHFT) | line_count; -} - -static inline u32 ctd_set_fid_ctl(int fid0, int fid1, int fid2) -{ - return (fid2 << CTD_FID2_SHFT) | (fid1 << CTD_FID1_SHFT) | fid0; -} - -static inline u32 ctd_type_source_ctl(int source, int control) -{ - return (CTD_PKT_TYPE << CTD_PKT_TYPE_SHFT) | - (source << CTD_SOURCE_SHFT) | control; -} - -static inline u32 ctd_get_pixel_count(struct vpdma_ctd *ctd) -{ - return ctd->pixel_line_count >> CTD_PIXEL_COUNT_SHFT; -} - -static inline int ctd_get_line_count(struct vpdma_ctd *ctd) -{ - return ctd->pixel_line_count & CTD_LINE_COUNT_MASK; -} - -static inline int ctd_get_event(struct vpdma_ctd *ctd) -{ - return ctd->event & CTD_EVENT_MASK; -} - -static inline int ctd_get_fid2_ctl(struct vpdma_ctd *ctd) -{ - return (ctd->fid_ctl >> CTD_FID2_SHFT) & CTD_FID2_MASK; -} - -static inline int ctd_get_fid1_ctl(struct vpdma_ctd *ctd) -{ - return (ctd->fid_ctl >> CTD_FID1_SHFT) & CTD_FID1_MASK; -} - -static inline int ctd_get_fid0_ctl(struct vpdma_ctd *ctd) -{ - return ctd->fid_ctl & CTD_FID2_MASK; -} - -static inline int ctd_get_pkt_type(struct vpdma_ctd *ctd) -{ - return ctd->type_source_ctl >> CTD_PKT_TYPE_SHFT; -} - -static inline int ctd_get_source(struct vpdma_ctd *ctd) -{ - return (ctd->type_source_ctl >> CTD_SOURCE_SHFT) & CTD_SOURCE_MASK; -} - -static inline int ctd_get_ctl(struct vpdma_ctd *ctd) -{ - return ctd->type_source_ctl & CTD_CONTROL_MASK; -} - -#endif diff --git a/drivers/media/platform/ti-vpe/vpe.c b/drivers/media/platform/ti-vpe/vpe.c deleted file mode 100644 index 5b1c5d96a407..000000000000 --- a/drivers/media/platform/ti-vpe/vpe.c +++ /dev/null @@ -1,2665 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * TI VPE mem2mem driver, based on the virtual v4l2-mem2mem example driver - * - * Copyright (c) 2013 Texas Instruments Inc. - * David Griego, - * Dale Farnsworth, - * Archit Taneja, - * - * Copyright (c) 2009-2010 Samsung Electronics Co., Ltd. - * Pawel Osciak, - * Marek Szyprowski, - * - * Based on the virtual v4l2-mem2mem example device - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "vpdma.h" -#include "vpdma_priv.h" -#include "vpe_regs.h" -#include "sc.h" -#include "csc.h" - -#define VPE_MODULE_NAME "vpe" - -/* minimum and maximum frame sizes */ -#define MIN_W 32 -#define MIN_H 32 -#define MAX_W 2048 -#define MAX_H 2048 - -/* required alignments */ -#define S_ALIGN 0 /* multiple of 1 */ -#define H_ALIGN 1 /* multiple of 2 */ - -/* flags that indicate a format can be used for capture/output */ -#define VPE_FMT_TYPE_CAPTURE (1 << 0) -#define VPE_FMT_TYPE_OUTPUT (1 << 1) - -/* used as plane indices */ -#define VPE_MAX_PLANES 2 -#define VPE_LUMA 0 -#define VPE_CHROMA 1 - -/* per m2m context info */ -#define VPE_MAX_SRC_BUFS 3 /* need 3 src fields to de-interlace */ - -#define VPE_DEF_BUFS_PER_JOB 1 /* default one buffer per batch job */ - -/* - * each VPE context can need up to 3 config descriptors, 7 input descriptors, - * 3 output descriptors, and 10 control descriptors - */ -#define VPE_DESC_LIST_SIZE (10 * VPDMA_DTD_DESC_SIZE + \ - 13 * VPDMA_CFD_CTD_DESC_SIZE) - -#define vpe_dbg(vpedev, fmt, arg...) \ - dev_dbg((vpedev)->v4l2_dev.dev, fmt, ##arg) -#define vpe_err(vpedev, fmt, arg...) \ - dev_err((vpedev)->v4l2_dev.dev, fmt, ##arg) - -struct vpe_us_coeffs { - unsigned short anchor_fid0_c0; - unsigned short anchor_fid0_c1; - unsigned short anchor_fid0_c2; - unsigned short anchor_fid0_c3; - unsigned short interp_fid0_c0; - unsigned short interp_fid0_c1; - unsigned short interp_fid0_c2; - unsigned short interp_fid0_c3; - unsigned short anchor_fid1_c0; - unsigned short anchor_fid1_c1; - unsigned short anchor_fid1_c2; - unsigned short anchor_fid1_c3; - unsigned short interp_fid1_c0; - unsigned short interp_fid1_c1; - unsigned short interp_fid1_c2; - unsigned short interp_fid1_c3; -}; - -/* - * Default upsampler coefficients - */ -static const struct vpe_us_coeffs us_coeffs[] = { - { - /* Coefficients for progressive input */ - 0x00C8, 0x0348, 0x0018, 0x3FD8, 0x3FB8, 0x0378, 0x00E8, 0x3FE8, - 0x00C8, 0x0348, 0x0018, 0x3FD8, 0x3FB8, 0x0378, 0x00E8, 0x3FE8, - }, - { - /* Coefficients for Top Field Interlaced input */ - 0x0051, 0x03D5, 0x3FE3, 0x3FF7, 0x3FB5, 0x02E9, 0x018F, 0x3FD3, - /* Coefficients for Bottom Field Interlaced input */ - 0x016B, 0x0247, 0x00B1, 0x3F9D, 0x3FCF, 0x03DB, 0x005D, 0x3FF9, - }, -}; - -/* - * the following registers are for configuring some of the parameters of the - * motion and edge detection blocks inside DEI, these generally remain the same, - * these could be passed later via userspace if some one needs to tweak these. - */ -struct vpe_dei_regs { - unsigned long mdt_spacial_freq_thr_reg; /* VPE_DEI_REG2 */ - unsigned long edi_config_reg; /* VPE_DEI_REG3 */ - unsigned long edi_lut_reg0; /* VPE_DEI_REG4 */ - unsigned long edi_lut_reg1; /* VPE_DEI_REG5 */ - unsigned long edi_lut_reg2; /* VPE_DEI_REG6 */ - unsigned long edi_lut_reg3; /* VPE_DEI_REG7 */ -}; - -/* - * default expert DEI register values, unlikely to be modified. - */ -static const struct vpe_dei_regs dei_regs = { - .mdt_spacial_freq_thr_reg = 0x020C0804u, - .edi_config_reg = 0x0118100Cu, - .edi_lut_reg0 = 0x08040200u, - .edi_lut_reg1 = 0x1010100Cu, - .edi_lut_reg2 = 0x10101010u, - .edi_lut_reg3 = 0x10101010u, -}; - -/* - * The port_data structure contains per-port data. - */ -struct vpe_port_data { - enum vpdma_channel channel; /* VPDMA channel */ - u8 vb_index; /* input frame f, f-1, f-2 index */ - u8 vb_part; /* plane index for co-panar formats */ -}; - -/* - * Define indices into the port_data tables - */ -#define VPE_PORT_LUMA1_IN 0 -#define VPE_PORT_CHROMA1_IN 1 -#define VPE_PORT_LUMA2_IN 2 -#define VPE_PORT_CHROMA2_IN 3 -#define VPE_PORT_LUMA3_IN 4 -#define VPE_PORT_CHROMA3_IN 5 -#define VPE_PORT_MV_IN 6 -#define VPE_PORT_MV_OUT 7 -#define VPE_PORT_LUMA_OUT 8 -#define VPE_PORT_CHROMA_OUT 9 -#define VPE_PORT_RGB_OUT 10 - -static const struct vpe_port_data port_data[11] = { - [VPE_PORT_LUMA1_IN] = { - .channel = VPE_CHAN_LUMA1_IN, - .vb_index = 0, - .vb_part = VPE_LUMA, - }, - [VPE_PORT_CHROMA1_IN] = { - .channel = VPE_CHAN_CHROMA1_IN, - .vb_index = 0, - .vb_part = VPE_CHROMA, - }, - [VPE_PORT_LUMA2_IN] = { - .channel = VPE_CHAN_LUMA2_IN, - .vb_index = 1, - .vb_part = VPE_LUMA, - }, - [VPE_PORT_CHROMA2_IN] = { - .channel = VPE_CHAN_CHROMA2_IN, - .vb_index = 1, - .vb_part = VPE_CHROMA, - }, - [VPE_PORT_LUMA3_IN] = { - .channel = VPE_CHAN_LUMA3_IN, - .vb_index = 2, - .vb_part = VPE_LUMA, - }, - [VPE_PORT_CHROMA3_IN] = { - .channel = VPE_CHAN_CHROMA3_IN, - .vb_index = 2, - .vb_part = VPE_CHROMA, - }, - [VPE_PORT_MV_IN] = { - .channel = VPE_CHAN_MV_IN, - }, - [VPE_PORT_MV_OUT] = { - .channel = VPE_CHAN_MV_OUT, - }, - [VPE_PORT_LUMA_OUT] = { - .channel = VPE_CHAN_LUMA_OUT, - .vb_part = VPE_LUMA, - }, - [VPE_PORT_CHROMA_OUT] = { - .channel = VPE_CHAN_CHROMA_OUT, - .vb_part = VPE_CHROMA, - }, - [VPE_PORT_RGB_OUT] = { - .channel = VPE_CHAN_RGB_OUT, - .vb_part = VPE_LUMA, - }, -}; - - -/* driver info for each of the supported video formats */ -struct vpe_fmt { - u32 fourcc; /* standard format identifier */ - u8 types; /* CAPTURE and/or OUTPUT */ - u8 coplanar; /* set for unpacked Luma and Chroma */ - /* vpdma format info for each plane */ - struct vpdma_data_format const *vpdma_fmt[VPE_MAX_PLANES]; -}; - -static struct vpe_fmt vpe_formats[] = { - { - .fourcc = V4L2_PIX_FMT_NV16, - .types = VPE_FMT_TYPE_CAPTURE | VPE_FMT_TYPE_OUTPUT, - .coplanar = 1, - .vpdma_fmt = { &vpdma_yuv_fmts[VPDMA_DATA_FMT_Y444], - &vpdma_yuv_fmts[VPDMA_DATA_FMT_C444], - }, - }, - { - .fourcc = V4L2_PIX_FMT_NV12, - .types = VPE_FMT_TYPE_CAPTURE | VPE_FMT_TYPE_OUTPUT, - .coplanar = 1, - .vpdma_fmt = { &vpdma_yuv_fmts[VPDMA_DATA_FMT_Y420], - &vpdma_yuv_fmts[VPDMA_DATA_FMT_C420], - }, - }, - { - .fourcc = V4L2_PIX_FMT_NV21, - .types = VPE_FMT_TYPE_CAPTURE | VPE_FMT_TYPE_OUTPUT, - .coplanar = 1, - .vpdma_fmt = { &vpdma_yuv_fmts[VPDMA_DATA_FMT_Y420], - &vpdma_yuv_fmts[VPDMA_DATA_FMT_CB420], - }, - }, - { - .fourcc = V4L2_PIX_FMT_YUYV, - .types = VPE_FMT_TYPE_CAPTURE | VPE_FMT_TYPE_OUTPUT, - .coplanar = 0, - .vpdma_fmt = { &vpdma_yuv_fmts[VPDMA_DATA_FMT_YCB422], - }, - }, - { - .fourcc = V4L2_PIX_FMT_UYVY, - .types = VPE_FMT_TYPE_CAPTURE | VPE_FMT_TYPE_OUTPUT, - .coplanar = 0, - .vpdma_fmt = { &vpdma_yuv_fmts[VPDMA_DATA_FMT_CBY422], - }, - }, - { - .fourcc = V4L2_PIX_FMT_RGB24, - .types = VPE_FMT_TYPE_CAPTURE, - .coplanar = 0, - .vpdma_fmt = { &vpdma_rgb_fmts[VPDMA_DATA_FMT_RGB24], - }, - }, - { - .fourcc = V4L2_PIX_FMT_RGB32, - .types = VPE_FMT_TYPE_CAPTURE, - .coplanar = 0, - .vpdma_fmt = { &vpdma_rgb_fmts[VPDMA_DATA_FMT_ARGB32], - }, - }, - { - .fourcc = V4L2_PIX_FMT_BGR24, - .types = VPE_FMT_TYPE_CAPTURE, - .coplanar = 0, - .vpdma_fmt = { &vpdma_rgb_fmts[VPDMA_DATA_FMT_BGR24], - }, - }, - { - .fourcc = V4L2_PIX_FMT_BGR32, - .types = VPE_FMT_TYPE_CAPTURE, - .coplanar = 0, - .vpdma_fmt = { &vpdma_rgb_fmts[VPDMA_DATA_FMT_ABGR32], - }, - }, - { - .fourcc = V4L2_PIX_FMT_RGB565, - .types = VPE_FMT_TYPE_CAPTURE, - .coplanar = 0, - .vpdma_fmt = { &vpdma_rgb_fmts[VPDMA_DATA_FMT_RGB565], - }, - }, - { - .fourcc = V4L2_PIX_FMT_RGB555, - .types = VPE_FMT_TYPE_CAPTURE, - .coplanar = 0, - .vpdma_fmt = { &vpdma_rgb_fmts[VPDMA_DATA_FMT_RGBA16_5551], - }, - }, -}; - -/* - * per-queue, driver-specific private data. - * there is one source queue and one destination queue for each m2m context. - */ -struct vpe_q_data { - /* current v4l2 format info */ - struct v4l2_format format; - unsigned int flags; - struct v4l2_rect c_rect; /* crop/compose rectangle */ - struct vpe_fmt *fmt; /* format info */ -}; - -/* vpe_q_data flag bits */ -#define Q_DATA_FRAME_1D BIT(0) -#define Q_DATA_MODE_TILED BIT(1) -#define Q_DATA_INTERLACED_ALTERNATE BIT(2) -#define Q_DATA_INTERLACED_SEQ_TB BIT(3) -#define Q_DATA_INTERLACED_SEQ_BT BIT(4) - -#define Q_IS_SEQ_XX (Q_DATA_INTERLACED_SEQ_TB | \ - Q_DATA_INTERLACED_SEQ_BT) - -#define Q_IS_INTERLACED (Q_DATA_INTERLACED_ALTERNATE | \ - Q_DATA_INTERLACED_SEQ_TB | \ - Q_DATA_INTERLACED_SEQ_BT) - -enum { - Q_DATA_SRC = 0, - Q_DATA_DST = 1, -}; - -/* find our format description corresponding to the passed v4l2_format */ -static struct vpe_fmt *__find_format(u32 fourcc) -{ - struct vpe_fmt *fmt; - unsigned int k; - - for (k = 0; k < ARRAY_SIZE(vpe_formats); k++) { - fmt = &vpe_formats[k]; - if (fmt->fourcc == fourcc) - return fmt; - } - - return NULL; -} - -static struct vpe_fmt *find_format(struct v4l2_format *f) -{ - return __find_format(f->fmt.pix.pixelformat); -} - -/* - * there is one vpe_dev structure in the driver, it is shared by - * all instances. - */ -struct vpe_dev { - struct v4l2_device v4l2_dev; - struct video_device vfd; - struct v4l2_m2m_dev *m2m_dev; - - atomic_t num_instances; /* count of driver instances */ - dma_addr_t loaded_mmrs; /* shadow mmrs in device */ - struct mutex dev_mutex; - spinlock_t lock; - - int irq; - void __iomem *base; - struct resource *res; - - struct vpdma_data vpdma_data; - struct vpdma_data *vpdma; /* vpdma data handle */ - struct sc_data *sc; /* scaler data handle */ - struct csc_data *csc; /* csc data handle */ -}; - -/* - * There is one vpe_ctx structure for each m2m context. - */ -struct vpe_ctx { - struct v4l2_fh fh; - struct vpe_dev *dev; - struct v4l2_ctrl_handler hdl; - - unsigned int field; /* current field */ - unsigned int sequence; /* current frame/field seq */ - unsigned int aborting; /* abort after next irq */ - - unsigned int bufs_per_job; /* input buffers per batch */ - unsigned int bufs_completed; /* bufs done in this batch */ - - struct vpe_q_data q_data[2]; /* src & dst queue data */ - struct vb2_v4l2_buffer *src_vbs[VPE_MAX_SRC_BUFS]; - struct vb2_v4l2_buffer *dst_vb; - - dma_addr_t mv_buf_dma[2]; /* dma addrs of motion vector in/out bufs */ - void *mv_buf[2]; /* virtual addrs of motion vector bufs */ - size_t mv_buf_size; /* current motion vector buffer size */ - struct vpdma_buf mmr_adb; /* shadow reg addr/data block */ - struct vpdma_buf sc_coeff_h; /* h coeff buffer */ - struct vpdma_buf sc_coeff_v; /* v coeff buffer */ - struct vpdma_desc_list desc_list; /* DMA descriptor list */ - - bool deinterlacing; /* using de-interlacer */ - bool load_mmrs; /* have new shadow reg values */ - - unsigned int src_mv_buf_selector; -}; - - -/* - * M2M devices get 2 queues. - * Return the queue given the type. - */ -static struct vpe_q_data *get_q_data(struct vpe_ctx *ctx, - enum v4l2_buf_type type) -{ - switch (type) { - case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: - case V4L2_BUF_TYPE_VIDEO_OUTPUT: - return &ctx->q_data[Q_DATA_SRC]; - case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: - case V4L2_BUF_TYPE_VIDEO_CAPTURE: - return &ctx->q_data[Q_DATA_DST]; - default: - return NULL; - } - return NULL; -} - -static u32 read_reg(struct vpe_dev *dev, int offset) -{ - return ioread32(dev->base + offset); -} - -static void write_reg(struct vpe_dev *dev, int offset, u32 value) -{ - iowrite32(value, dev->base + offset); -} - -/* register field read/write helpers */ -static int get_field(u32 value, u32 mask, int shift) -{ - return (value & (mask << shift)) >> shift; -} - -static int read_field_reg(struct vpe_dev *dev, int offset, u32 mask, int shift) -{ - return get_field(read_reg(dev, offset), mask, shift); -} - -static void write_field(u32 *valp, u32 field, u32 mask, int shift) -{ - u32 val = *valp; - - val &= ~(mask << shift); - val |= (field & mask) << shift; - *valp = val; -} - -static void write_field_reg(struct vpe_dev *dev, int offset, u32 field, - u32 mask, int shift) -{ - u32 val = read_reg(dev, offset); - - write_field(&val, field, mask, shift); - - write_reg(dev, offset, val); -} - -/* - * DMA address/data block for the shadow registers - */ -struct vpe_mmr_adb { - struct vpdma_adb_hdr out_fmt_hdr; - u32 out_fmt_reg[1]; - u32 out_fmt_pad[3]; - struct vpdma_adb_hdr us1_hdr; - u32 us1_regs[8]; - struct vpdma_adb_hdr us2_hdr; - u32 us2_regs[8]; - struct vpdma_adb_hdr us3_hdr; - u32 us3_regs[8]; - struct vpdma_adb_hdr dei_hdr; - u32 dei_regs[8]; - struct vpdma_adb_hdr sc_hdr0; - u32 sc_regs0[7]; - u32 sc_pad0[1]; - struct vpdma_adb_hdr sc_hdr8; - u32 sc_regs8[6]; - u32 sc_pad8[2]; - struct vpdma_adb_hdr sc_hdr17; - u32 sc_regs17[9]; - u32 sc_pad17[3]; - struct vpdma_adb_hdr csc_hdr; - u32 csc_regs[6]; - u32 csc_pad[2]; -}; - -#define GET_OFFSET_TOP(ctx, obj, reg) \ - ((obj)->res->start - ctx->dev->res->start + reg) - -#define VPE_SET_MMR_ADB_HDR(ctx, hdr, regs, offset_a) \ - VPDMA_SET_MMR_ADB_HDR(ctx->mmr_adb, vpe_mmr_adb, hdr, regs, offset_a) -/* - * Set the headers for all of the address/data block structures. - */ -static void init_adb_hdrs(struct vpe_ctx *ctx) -{ - VPE_SET_MMR_ADB_HDR(ctx, out_fmt_hdr, out_fmt_reg, VPE_CLK_FORMAT_SELECT); - VPE_SET_MMR_ADB_HDR(ctx, us1_hdr, us1_regs, VPE_US1_R0); - VPE_SET_MMR_ADB_HDR(ctx, us2_hdr, us2_regs, VPE_US2_R0); - VPE_SET_MMR_ADB_HDR(ctx, us3_hdr, us3_regs, VPE_US3_R0); - VPE_SET_MMR_ADB_HDR(ctx, dei_hdr, dei_regs, VPE_DEI_FRAME_SIZE); - VPE_SET_MMR_ADB_HDR(ctx, sc_hdr0, sc_regs0, - GET_OFFSET_TOP(ctx, ctx->dev->sc, CFG_SC0)); - VPE_SET_MMR_ADB_HDR(ctx, sc_hdr8, sc_regs8, - GET_OFFSET_TOP(ctx, ctx->dev->sc, CFG_SC8)); - VPE_SET_MMR_ADB_HDR(ctx, sc_hdr17, sc_regs17, - GET_OFFSET_TOP(ctx, ctx->dev->sc, CFG_SC17)); - VPE_SET_MMR_ADB_HDR(ctx, csc_hdr, csc_regs, - GET_OFFSET_TOP(ctx, ctx->dev->csc, CSC_CSC00)); -}; - -/* - * Allocate or re-allocate the motion vector DMA buffers - * There are two buffers, one for input and one for output. - * However, the roles are reversed after each field is processed. - * In other words, after each field is processed, the previous - * output (dst) MV buffer becomes the new input (src) MV buffer. - */ -static int realloc_mv_buffers(struct vpe_ctx *ctx, size_t size) -{ - struct device *dev = ctx->dev->v4l2_dev.dev; - - if (ctx->mv_buf_size == size) - return 0; - - if (ctx->mv_buf[0]) - dma_free_coherent(dev, ctx->mv_buf_size, ctx->mv_buf[0], - ctx->mv_buf_dma[0]); - - if (ctx->mv_buf[1]) - dma_free_coherent(dev, ctx->mv_buf_size, ctx->mv_buf[1], - ctx->mv_buf_dma[1]); - - if (size == 0) - return 0; - - ctx->mv_buf[0] = dma_alloc_coherent(dev, size, &ctx->mv_buf_dma[0], - GFP_KERNEL); - if (!ctx->mv_buf[0]) { - vpe_err(ctx->dev, "failed to allocate motion vector buffer\n"); - return -ENOMEM; - } - - ctx->mv_buf[1] = dma_alloc_coherent(dev, size, &ctx->mv_buf_dma[1], - GFP_KERNEL); - if (!ctx->mv_buf[1]) { - vpe_err(ctx->dev, "failed to allocate motion vector buffer\n"); - dma_free_coherent(dev, size, ctx->mv_buf[0], - ctx->mv_buf_dma[0]); - - return -ENOMEM; - } - - ctx->mv_buf_size = size; - ctx->src_mv_buf_selector = 0; - - return 0; -} - -static void free_mv_buffers(struct vpe_ctx *ctx) -{ - realloc_mv_buffers(ctx, 0); -} - -/* - * While de-interlacing, we keep the two most recent input buffers - * around. This function frees those two buffers when we have - * finished processing the current stream. - */ -static void free_vbs(struct vpe_ctx *ctx) -{ - struct vpe_dev *dev = ctx->dev; - unsigned long flags; - - if (ctx->src_vbs[2] == NULL) - return; - - spin_lock_irqsave(&dev->lock, flags); - if (ctx->src_vbs[2]) { - v4l2_m2m_buf_done(ctx->src_vbs[2], VB2_BUF_STATE_DONE); - if (ctx->src_vbs[1] && (ctx->src_vbs[1] != ctx->src_vbs[2])) - v4l2_m2m_buf_done(ctx->src_vbs[1], VB2_BUF_STATE_DONE); - ctx->src_vbs[2] = NULL; - ctx->src_vbs[1] = NULL; - } - spin_unlock_irqrestore(&dev->lock, flags); -} - -/* - * Enable or disable the VPE clocks - */ -static void vpe_set_clock_enable(struct vpe_dev *dev, bool on) -{ - u32 val = 0; - - if (on) - val = VPE_DATA_PATH_CLK_ENABLE | VPE_VPEDMA_CLK_ENABLE; - write_reg(dev, VPE_CLK_ENABLE, val); -} - -static void vpe_top_reset(struct vpe_dev *dev) -{ - - write_field_reg(dev, VPE_CLK_RESET, 1, VPE_DATA_PATH_CLK_RESET_MASK, - VPE_DATA_PATH_CLK_RESET_SHIFT); - - usleep_range(100, 150); - - write_field_reg(dev, VPE_CLK_RESET, 0, VPE_DATA_PATH_CLK_RESET_MASK, - VPE_DATA_PATH_CLK_RESET_SHIFT); -} - -static void vpe_top_vpdma_reset(struct vpe_dev *dev) -{ - write_field_reg(dev, VPE_CLK_RESET, 1, VPE_VPDMA_CLK_RESET_MASK, - VPE_VPDMA_CLK_RESET_SHIFT); - - usleep_range(100, 150); - - write_field_reg(dev, VPE_CLK_RESET, 0, VPE_VPDMA_CLK_RESET_MASK, - VPE_VPDMA_CLK_RESET_SHIFT); -} - -/* - * Load the correct of upsampler coefficients into the shadow MMRs - */ -static void set_us_coefficients(struct vpe_ctx *ctx) -{ - struct vpe_mmr_adb *mmr_adb = ctx->mmr_adb.addr; - struct vpe_q_data *s_q_data = &ctx->q_data[Q_DATA_SRC]; - u32 *us1_reg = &mmr_adb->us1_regs[0]; - u32 *us2_reg = &mmr_adb->us2_regs[0]; - u32 *us3_reg = &mmr_adb->us3_regs[0]; - const unsigned short *cp, *end_cp; - - cp = &us_coeffs[0].anchor_fid0_c0; - - if (s_q_data->flags & Q_IS_INTERLACED) /* interlaced */ - cp += sizeof(us_coeffs[0]) / sizeof(*cp); - - end_cp = cp + sizeof(us_coeffs[0]) / sizeof(*cp); - - while (cp < end_cp) { - write_field(us1_reg, *cp++, VPE_US_C0_MASK, VPE_US_C0_SHIFT); - write_field(us1_reg, *cp++, VPE_US_C1_MASK, VPE_US_C1_SHIFT); - *us2_reg++ = *us1_reg; - *us3_reg++ = *us1_reg++; - } - ctx->load_mmrs = true; -} - -/* - * Set the upsampler config mode and the VPDMA line mode in the shadow MMRs. - */ -static void set_cfg_modes(struct vpe_ctx *ctx) -{ - struct vpe_fmt *fmt = ctx->q_data[Q_DATA_SRC].fmt; - struct vpe_mmr_adb *mmr_adb = ctx->mmr_adb.addr; - u32 *us1_reg0 = &mmr_adb->us1_regs[0]; - u32 *us2_reg0 = &mmr_adb->us2_regs[0]; - u32 *us3_reg0 = &mmr_adb->us3_regs[0]; - int cfg_mode = 1; - - /* - * Cfg Mode 0: YUV420 source, enable upsampler, DEI is de-interlacing. - * Cfg Mode 1: YUV422 source, disable upsampler, DEI is de-interlacing. - */ - - if (fmt->fourcc == V4L2_PIX_FMT_NV12 || - fmt->fourcc == V4L2_PIX_FMT_NV21) - cfg_mode = 0; - - write_field(us1_reg0, cfg_mode, VPE_US_MODE_MASK, VPE_US_MODE_SHIFT); - write_field(us2_reg0, cfg_mode, VPE_US_MODE_MASK, VPE_US_MODE_SHIFT); - write_field(us3_reg0, cfg_mode, VPE_US_MODE_MASK, VPE_US_MODE_SHIFT); - - ctx->load_mmrs = true; -} - -static void set_line_modes(struct vpe_ctx *ctx) -{ - struct vpe_fmt *fmt = ctx->q_data[Q_DATA_SRC].fmt; - int line_mode = 1; - - if (fmt->fourcc == V4L2_PIX_FMT_NV12 || - fmt->fourcc == V4L2_PIX_FMT_NV21) - line_mode = 0; /* double lines to line buffer */ - - /* regs for now */ - vpdma_set_line_mode(ctx->dev->vpdma, line_mode, VPE_CHAN_CHROMA1_IN); - vpdma_set_line_mode(ctx->dev->vpdma, line_mode, VPE_CHAN_CHROMA2_IN); - vpdma_set_line_mode(ctx->dev->vpdma, line_mode, VPE_CHAN_CHROMA3_IN); - - /* frame start for input luma */ - vpdma_set_frame_start_event(ctx->dev->vpdma, VPDMA_FSEVENT_CHANNEL_ACTIVE, - VPE_CHAN_LUMA1_IN); - vpdma_set_frame_start_event(ctx->dev->vpdma, VPDMA_FSEVENT_CHANNEL_ACTIVE, - VPE_CHAN_LUMA2_IN); - vpdma_set_frame_start_event(ctx->dev->vpdma, VPDMA_FSEVENT_CHANNEL_ACTIVE, - VPE_CHAN_LUMA3_IN); - - /* frame start for input chroma */ - vpdma_set_frame_start_event(ctx->dev->vpdma, VPDMA_FSEVENT_CHANNEL_ACTIVE, - VPE_CHAN_CHROMA1_IN); - vpdma_set_frame_start_event(ctx->dev->vpdma, VPDMA_FSEVENT_CHANNEL_ACTIVE, - VPE_CHAN_CHROMA2_IN); - vpdma_set_frame_start_event(ctx->dev->vpdma, VPDMA_FSEVENT_CHANNEL_ACTIVE, - VPE_CHAN_CHROMA3_IN); - - /* frame start for MV in client */ - vpdma_set_frame_start_event(ctx->dev->vpdma, VPDMA_FSEVENT_CHANNEL_ACTIVE, - VPE_CHAN_MV_IN); -} - -/* - * Set the shadow registers that are modified when the source - * format changes. - */ -static void set_src_registers(struct vpe_ctx *ctx) -{ - set_us_coefficients(ctx); -} - -/* - * Set the shadow registers that are modified when the destination - * format changes. - */ -static void set_dst_registers(struct vpe_ctx *ctx) -{ - struct vpe_mmr_adb *mmr_adb = ctx->mmr_adb.addr; - struct vpe_fmt *fmt = ctx->q_data[Q_DATA_DST].fmt; - const struct v4l2_format_info *finfo; - u32 val = 0; - - finfo = v4l2_format_info(fmt->fourcc); - if (v4l2_is_format_rgb(finfo)) { - val |= VPE_RGB_OUT_SELECT; - vpdma_set_bg_color(ctx->dev->vpdma, - (struct vpdma_data_format *)fmt->vpdma_fmt[0], 0xff); - } else if (fmt->fourcc == V4L2_PIX_FMT_NV16) - val |= VPE_COLOR_SEPARATE_422; - - /* - * the source of CHR_DS and CSC is always the scaler, irrespective of - * whether it's used or not - */ - val |= VPE_DS_SRC_DEI_SCALER | VPE_CSC_SRC_DEI_SCALER; - - if (fmt->fourcc != V4L2_PIX_FMT_NV12 && - fmt->fourcc != V4L2_PIX_FMT_NV21) - val |= VPE_DS_BYPASS; - - mmr_adb->out_fmt_reg[0] = val; - - ctx->load_mmrs = true; -} - -/* - * Set the de-interlacer shadow register values - */ -static void set_dei_regs(struct vpe_ctx *ctx) -{ - struct vpe_mmr_adb *mmr_adb = ctx->mmr_adb.addr; - struct vpe_q_data *s_q_data = &ctx->q_data[Q_DATA_SRC]; - unsigned int src_h = s_q_data->c_rect.height; - unsigned int src_w = s_q_data->c_rect.width; - u32 *dei_mmr0 = &mmr_adb->dei_regs[0]; - bool deinterlace = true; - u32 val = 0; - - /* - * according to TRM, we should set DEI in progressive bypass mode when - * the input content is progressive, however, DEI is bypassed correctly - * for both progressive and interlace content in interlace bypass mode. - * It has been recommended not to use progressive bypass mode. - */ - if (!(s_q_data->flags & Q_IS_INTERLACED) || !ctx->deinterlacing) { - deinterlace = false; - val = VPE_DEI_INTERLACE_BYPASS; - } - - src_h = deinterlace ? src_h * 2 : src_h; - - val |= (src_h << VPE_DEI_HEIGHT_SHIFT) | - (src_w << VPE_DEI_WIDTH_SHIFT) | - VPE_DEI_FIELD_FLUSH; - - *dei_mmr0 = val; - - ctx->load_mmrs = true; -} - -static void set_dei_shadow_registers(struct vpe_ctx *ctx) -{ - struct vpe_mmr_adb *mmr_adb = ctx->mmr_adb.addr; - u32 *dei_mmr = &mmr_adb->dei_regs[0]; - const struct vpe_dei_regs *cur = &dei_regs; - - dei_mmr[2] = cur->mdt_spacial_freq_thr_reg; - dei_mmr[3] = cur->edi_config_reg; - dei_mmr[4] = cur->edi_lut_reg0; - dei_mmr[5] = cur->edi_lut_reg1; - dei_mmr[6] = cur->edi_lut_reg2; - dei_mmr[7] = cur->edi_lut_reg3; - - ctx->load_mmrs = true; -} - -static void config_edi_input_mode(struct vpe_ctx *ctx, int mode) -{ - struct vpe_mmr_adb *mmr_adb = ctx->mmr_adb.addr; - u32 *edi_config_reg = &mmr_adb->dei_regs[3]; - - if (mode & 0x2) - write_field(edi_config_reg, 1, 1, 2); /* EDI_ENABLE_3D */ - - if (mode & 0x3) - write_field(edi_config_reg, 1, 1, 3); /* EDI_CHROMA_3D */ - - write_field(edi_config_reg, mode, VPE_EDI_INP_MODE_MASK, - VPE_EDI_INP_MODE_SHIFT); - - ctx->load_mmrs = true; -} - -/* - * Set the shadow registers whose values are modified when either the - * source or destination format is changed. - */ -static int set_srcdst_params(struct vpe_ctx *ctx) -{ - struct vpe_q_data *s_q_data = &ctx->q_data[Q_DATA_SRC]; - struct vpe_q_data *d_q_data = &ctx->q_data[Q_DATA_DST]; - struct vpe_mmr_adb *mmr_adb = ctx->mmr_adb.addr; - unsigned int src_w = s_q_data->c_rect.width; - unsigned int src_h = s_q_data->c_rect.height; - unsigned int dst_w = d_q_data->c_rect.width; - unsigned int dst_h = d_q_data->c_rect.height; - struct v4l2_pix_format_mplane *spix; - size_t mv_buf_size; - int ret; - - ctx->sequence = 0; - ctx->field = V4L2_FIELD_TOP; - spix = &s_q_data->format.fmt.pix_mp; - - if ((s_q_data->flags & Q_IS_INTERLACED) && - !(d_q_data->flags & Q_IS_INTERLACED)) { - int bytes_per_line; - const struct vpdma_data_format *mv = - &vpdma_misc_fmts[VPDMA_DATA_FMT_MV]; - - /* - * we make sure that the source image has a 16 byte aligned - * stride, we need to do the same for the motion vector buffer - * by aligning it's stride to the next 16 byte boundary. this - * extra space will not be used by the de-interlacer, but will - * ensure that vpdma operates correctly - */ - bytes_per_line = ALIGN((spix->width * mv->depth) >> 3, - VPDMA_STRIDE_ALIGN); - mv_buf_size = bytes_per_line * spix->height; - - ctx->deinterlacing = true; - src_h <<= 1; - } else { - ctx->deinterlacing = false; - mv_buf_size = 0; - } - - free_vbs(ctx); - ctx->src_vbs[2] = ctx->src_vbs[1] = ctx->src_vbs[0] = NULL; - - ret = realloc_mv_buffers(ctx, mv_buf_size); - if (ret) - return ret; - - set_cfg_modes(ctx); - set_dei_regs(ctx); - - csc_set_coeff(ctx->dev->csc, &mmr_adb->csc_regs[0], - &s_q_data->format, &d_q_data->format); - - sc_set_hs_coeffs(ctx->dev->sc, ctx->sc_coeff_h.addr, src_w, dst_w); - sc_set_vs_coeffs(ctx->dev->sc, ctx->sc_coeff_v.addr, src_h, dst_h); - - sc_config_scaler(ctx->dev->sc, &mmr_adb->sc_regs0[0], - &mmr_adb->sc_regs8[0], &mmr_adb->sc_regs17[0], - src_w, src_h, dst_w, dst_h); - - return 0; -} - -/* - * mem2mem callbacks - */ - -/* - * job_ready() - check whether an instance is ready to be scheduled to run - */ -static int job_ready(void *priv) -{ - struct vpe_ctx *ctx = priv; - - /* - * This check is needed as this might be called directly from driver - * When called by m2m framework, this will always satisfy, but when - * called from vpe_irq, this might fail. (src stream with zero buffers) - */ - if (v4l2_m2m_num_src_bufs_ready(ctx->fh.m2m_ctx) <= 0 || - v4l2_m2m_num_dst_bufs_ready(ctx->fh.m2m_ctx) <= 0) - return 0; - - return 1; -} - -static void job_abort(void *priv) -{ - struct vpe_ctx *ctx = priv; - - /* Will cancel the transaction in the next interrupt handler */ - ctx->aborting = 1; -} - -static void vpe_dump_regs(struct vpe_dev *dev) -{ -#define DUMPREG(r) vpe_dbg(dev, "%-35s %08x\n", #r, read_reg(dev, VPE_##r)) - - vpe_dbg(dev, "VPE Registers:\n"); - - DUMPREG(PID); - DUMPREG(SYSCONFIG); - DUMPREG(INT0_STATUS0_RAW); - DUMPREG(INT0_STATUS0); - DUMPREG(INT0_ENABLE0); - DUMPREG(INT0_STATUS1_RAW); - DUMPREG(INT0_STATUS1); - DUMPREG(INT0_ENABLE1); - DUMPREG(CLK_ENABLE); - DUMPREG(CLK_RESET); - DUMPREG(CLK_FORMAT_SELECT); - DUMPREG(CLK_RANGE_MAP); - DUMPREG(US1_R0); - DUMPREG(US1_R1); - DUMPREG(US1_R2); - DUMPREG(US1_R3); - DUMPREG(US1_R4); - DUMPREG(US1_R5); - DUMPREG(US1_R6); - DUMPREG(US1_R7); - DUMPREG(US2_R0); - DUMPREG(US2_R1); - DUMPREG(US2_R2); - DUMPREG(US2_R3); - DUMPREG(US2_R4); - DUMPREG(US2_R5); - DUMPREG(US2_R6); - DUMPREG(US2_R7); - DUMPREG(US3_R0); - DUMPREG(US3_R1); - DUMPREG(US3_R2); - DUMPREG(US3_R3); - DUMPREG(US3_R4); - DUMPREG(US3_R5); - DUMPREG(US3_R6); - DUMPREG(US3_R7); - DUMPREG(DEI_FRAME_SIZE); - DUMPREG(MDT_BYPASS); - DUMPREG(MDT_SF_THRESHOLD); - DUMPREG(EDI_CONFIG); - DUMPREG(DEI_EDI_LUT_R0); - DUMPREG(DEI_EDI_LUT_R1); - DUMPREG(DEI_EDI_LUT_R2); - DUMPREG(DEI_EDI_LUT_R3); - DUMPREG(DEI_FMD_WINDOW_R0); - DUMPREG(DEI_FMD_WINDOW_R1); - DUMPREG(DEI_FMD_CONTROL_R0); - DUMPREG(DEI_FMD_CONTROL_R1); - DUMPREG(DEI_FMD_STATUS_R0); - DUMPREG(DEI_FMD_STATUS_R1); - DUMPREG(DEI_FMD_STATUS_R2); -#undef DUMPREG - - sc_dump_regs(dev->sc); - csc_dump_regs(dev->csc); -} - -static void add_out_dtd(struct vpe_ctx *ctx, int port) -{ - struct vpe_q_data *q_data = &ctx->q_data[Q_DATA_DST]; - const struct vpe_port_data *p_data = &port_data[port]; - struct vb2_buffer *vb = &ctx->dst_vb->vb2_buf; - struct vpe_fmt *fmt = q_data->fmt; - const struct vpdma_data_format *vpdma_fmt; - int mv_buf_selector = !ctx->src_mv_buf_selector; - struct v4l2_pix_format_mplane *pix; - dma_addr_t dma_addr; - u32 flags = 0; - u32 offset = 0; - u32 stride; - - if (port == VPE_PORT_MV_OUT) { - vpdma_fmt = &vpdma_misc_fmts[VPDMA_DATA_FMT_MV]; - dma_addr = ctx->mv_buf_dma[mv_buf_selector]; - q_data = &ctx->q_data[Q_DATA_SRC]; - pix = &q_data->format.fmt.pix_mp; - stride = ALIGN((pix->width * vpdma_fmt->depth) >> 3, - VPDMA_STRIDE_ALIGN); - } else { - /* to incorporate interleaved formats */ - int plane = fmt->coplanar ? p_data->vb_part : 0; - - pix = &q_data->format.fmt.pix_mp; - vpdma_fmt = fmt->vpdma_fmt[plane]; - /* - * If we are using a single plane buffer and - * we need to set a separate vpdma chroma channel. - */ - if (pix->num_planes == 1 && plane) { - dma_addr = vb2_dma_contig_plane_dma_addr(vb, 0); - /* Compute required offset */ - offset = pix->plane_fmt[0].bytesperline * pix->height; - } else { - dma_addr = vb2_dma_contig_plane_dma_addr(vb, plane); - /* Use address as is, no offset */ - offset = 0; - } - if (!dma_addr) { - vpe_err(ctx->dev, - "acquiring output buffer(%d) dma_addr failed\n", - port); - return; - } - /* Apply the offset */ - dma_addr += offset; - stride = pix->plane_fmt[VPE_LUMA].bytesperline; - } - - if (q_data->flags & Q_DATA_FRAME_1D) - flags |= VPDMA_DATA_FRAME_1D; - if (q_data->flags & Q_DATA_MODE_TILED) - flags |= VPDMA_DATA_MODE_TILED; - - vpdma_set_max_size(ctx->dev->vpdma, VPDMA_MAX_SIZE1, - MAX_W, MAX_H); - - vpdma_add_out_dtd(&ctx->desc_list, pix->width, - stride, &q_data->c_rect, - vpdma_fmt, dma_addr, MAX_OUT_WIDTH_REG1, - MAX_OUT_HEIGHT_REG1, p_data->channel, flags); -} - -static void add_in_dtd(struct vpe_ctx *ctx, int port) -{ - struct vpe_q_data *q_data = &ctx->q_data[Q_DATA_SRC]; - const struct vpe_port_data *p_data = &port_data[port]; - struct vb2_buffer *vb = &ctx->src_vbs[p_data->vb_index]->vb2_buf; - struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); - struct vpe_fmt *fmt = q_data->fmt; - struct v4l2_pix_format_mplane *pix; - const struct vpdma_data_format *vpdma_fmt; - int mv_buf_selector = ctx->src_mv_buf_selector; - int field = vbuf->field == V4L2_FIELD_BOTTOM; - int frame_width, frame_height; - dma_addr_t dma_addr; - u32 flags = 0; - u32 offset = 0; - u32 stride; - - pix = &q_data->format.fmt.pix_mp; - if (port == VPE_PORT_MV_IN) { - vpdma_fmt = &vpdma_misc_fmts[VPDMA_DATA_FMT_MV]; - dma_addr = ctx->mv_buf_dma[mv_buf_selector]; - stride = ALIGN((pix->width * vpdma_fmt->depth) >> 3, - VPDMA_STRIDE_ALIGN); - } else { - /* to incorporate interleaved formats */ - int plane = fmt->coplanar ? p_data->vb_part : 0; - - vpdma_fmt = fmt->vpdma_fmt[plane]; - /* - * If we are using a single plane buffer and - * we need to set a separate vpdma chroma channel. - */ - if (pix->num_planes == 1 && plane) { - dma_addr = vb2_dma_contig_plane_dma_addr(vb, 0); - /* Compute required offset */ - offset = pix->plane_fmt[0].bytesperline * pix->height; - } else { - dma_addr = vb2_dma_contig_plane_dma_addr(vb, plane); - /* Use address as is, no offset */ - offset = 0; - } - if (!dma_addr) { - vpe_err(ctx->dev, - "acquiring output buffer(%d) dma_addr failed\n", - port); - return; - } - /* Apply the offset */ - dma_addr += offset; - stride = pix->plane_fmt[VPE_LUMA].bytesperline; - - /* - * field used in VPDMA desc = 0 (top) / 1 (bottom) - * Use top or bottom field from same vb alternately - * For each de-interlacing operation, f,f-1,f-2 should be one - * of TBT or BTB - */ - if (q_data->flags & Q_DATA_INTERLACED_SEQ_TB || - q_data->flags & Q_DATA_INTERLACED_SEQ_BT) { - /* Select initial value based on format */ - if (q_data->flags & Q_DATA_INTERLACED_SEQ_BT) - field = 1; - else - field = 0; - - /* Toggle for each vb_index and each operation */ - field = (field + p_data->vb_index + ctx->sequence) % 2; - - if (field) { - int height = pix->height / 2; - int bpp; - - if (fmt->fourcc == V4L2_PIX_FMT_NV12 || - fmt->fourcc == V4L2_PIX_FMT_NV21) - bpp = 1; - else - bpp = vpdma_fmt->depth >> 3; - - if (plane) - height /= 2; - - dma_addr += pix->width * height * bpp; - } - } - } - - if (q_data->flags & Q_DATA_FRAME_1D) - flags |= VPDMA_DATA_FRAME_1D; - if (q_data->flags & Q_DATA_MODE_TILED) - flags |= VPDMA_DATA_MODE_TILED; - - frame_width = q_data->c_rect.width; - frame_height = q_data->c_rect.height; - - if (p_data->vb_part && (fmt->fourcc == V4L2_PIX_FMT_NV12 || - fmt->fourcc == V4L2_PIX_FMT_NV21)) - frame_height /= 2; - - vpdma_add_in_dtd(&ctx->desc_list, pix->width, stride, - &q_data->c_rect, vpdma_fmt, dma_addr, - p_data->channel, field, flags, frame_width, - frame_height, 0, 0); -} - -/* - * Enable the expected IRQ sources - */ -static void enable_irqs(struct vpe_ctx *ctx) -{ - write_reg(ctx->dev, VPE_INT0_ENABLE0_SET, VPE_INT0_LIST0_COMPLETE); - write_reg(ctx->dev, VPE_INT0_ENABLE1_SET, VPE_DEI_ERROR_INT | - VPE_DS1_UV_ERROR_INT); - - vpdma_enable_list_complete_irq(ctx->dev->vpdma, 0, 0, true); -} - -static void disable_irqs(struct vpe_ctx *ctx) -{ - write_reg(ctx->dev, VPE_INT0_ENABLE0_CLR, 0xffffffff); - write_reg(ctx->dev, VPE_INT0_ENABLE1_CLR, 0xffffffff); - - vpdma_enable_list_complete_irq(ctx->dev->vpdma, 0, 0, false); -} - -/* device_run() - prepares and starts the device - * - * This function is only called when both the source and destination - * buffers are in place. - */ -static void device_run(void *priv) -{ - struct vpe_ctx *ctx = priv; - struct sc_data *sc = ctx->dev->sc; - struct vpe_q_data *d_q_data = &ctx->q_data[Q_DATA_DST]; - struct vpe_q_data *s_q_data = &ctx->q_data[Q_DATA_SRC]; - const struct v4l2_format_info *d_finfo; - - d_finfo = v4l2_format_info(d_q_data->fmt->fourcc); - - if (ctx->deinterlacing && s_q_data->flags & Q_IS_SEQ_XX && - ctx->sequence % 2 == 0) { - /* When using SEQ_XX type buffers, each buffer has two fields - * each buffer has two fields (top & bottom) - * Removing one buffer is actually getting two fields - * Alternate between two operations:- - * Even : consume one field but DO NOT REMOVE from queue - * Odd : consume other field and REMOVE from queue - */ - ctx->src_vbs[0] = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx); - WARN_ON(ctx->src_vbs[0] == NULL); - } else { - ctx->src_vbs[0] = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx); - WARN_ON(ctx->src_vbs[0] == NULL); - } - - ctx->dst_vb = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx); - WARN_ON(ctx->dst_vb == NULL); - - if (ctx->deinterlacing) { - - if (ctx->src_vbs[2] == NULL) { - ctx->src_vbs[2] = ctx->src_vbs[0]; - WARN_ON(ctx->src_vbs[2] == NULL); - ctx->src_vbs[1] = ctx->src_vbs[0]; - WARN_ON(ctx->src_vbs[1] == NULL); - } - - /* - * we have output the first 2 frames through line average, we - * now switch to EDI de-interlacer - */ - if (ctx->sequence == 2) - config_edi_input_mode(ctx, 0x3); /* EDI (Y + UV) */ - } - - /* config descriptors */ - if (ctx->dev->loaded_mmrs != ctx->mmr_adb.dma_addr || ctx->load_mmrs) { - vpdma_map_desc_buf(ctx->dev->vpdma, &ctx->mmr_adb); - vpdma_add_cfd_adb(&ctx->desc_list, CFD_MMR_CLIENT, &ctx->mmr_adb); - - set_line_modes(ctx); - - ctx->dev->loaded_mmrs = ctx->mmr_adb.dma_addr; - ctx->load_mmrs = false; - } - - if (sc->loaded_coeff_h != ctx->sc_coeff_h.dma_addr || - sc->load_coeff_h) { - vpdma_map_desc_buf(ctx->dev->vpdma, &ctx->sc_coeff_h); - vpdma_add_cfd_block(&ctx->desc_list, CFD_SC_CLIENT, - &ctx->sc_coeff_h, 0); - - sc->loaded_coeff_h = ctx->sc_coeff_h.dma_addr; - sc->load_coeff_h = false; - } - - if (sc->loaded_coeff_v != ctx->sc_coeff_v.dma_addr || - sc->load_coeff_v) { - vpdma_map_desc_buf(ctx->dev->vpdma, &ctx->sc_coeff_v); - vpdma_add_cfd_block(&ctx->desc_list, CFD_SC_CLIENT, - &ctx->sc_coeff_v, SC_COEF_SRAM_SIZE >> 4); - - sc->loaded_coeff_v = ctx->sc_coeff_v.dma_addr; - sc->load_coeff_v = false; - } - - /* output data descriptors */ - if (ctx->deinterlacing) - add_out_dtd(ctx, VPE_PORT_MV_OUT); - - if (v4l2_is_format_rgb(d_finfo)) { - add_out_dtd(ctx, VPE_PORT_RGB_OUT); - } else { - add_out_dtd(ctx, VPE_PORT_LUMA_OUT); - if (d_q_data->fmt->coplanar) - add_out_dtd(ctx, VPE_PORT_CHROMA_OUT); - } - - /* input data descriptors */ - if (ctx->deinterlacing) { - add_in_dtd(ctx, VPE_PORT_LUMA3_IN); - add_in_dtd(ctx, VPE_PORT_CHROMA3_IN); - - add_in_dtd(ctx, VPE_PORT_LUMA2_IN); - add_in_dtd(ctx, VPE_PORT_CHROMA2_IN); - } - - add_in_dtd(ctx, VPE_PORT_LUMA1_IN); - add_in_dtd(ctx, VPE_PORT_CHROMA1_IN); - - if (ctx->deinterlacing) - add_in_dtd(ctx, VPE_PORT_MV_IN); - - /* sync on channel control descriptors for input ports */ - vpdma_add_sync_on_channel_ctd(&ctx->desc_list, VPE_CHAN_LUMA1_IN); - vpdma_add_sync_on_channel_ctd(&ctx->desc_list, VPE_CHAN_CHROMA1_IN); - - if (ctx->deinterlacing) { - vpdma_add_sync_on_channel_ctd(&ctx->desc_list, - VPE_CHAN_LUMA2_IN); - vpdma_add_sync_on_channel_ctd(&ctx->desc_list, - VPE_CHAN_CHROMA2_IN); - - vpdma_add_sync_on_channel_ctd(&ctx->desc_list, - VPE_CHAN_LUMA3_IN); - vpdma_add_sync_on_channel_ctd(&ctx->desc_list, - VPE_CHAN_CHROMA3_IN); - - vpdma_add_sync_on_channel_ctd(&ctx->desc_list, VPE_CHAN_MV_IN); - } - - /* sync on channel control descriptors for output ports */ - if (v4l2_is_format_rgb(d_finfo)) { - vpdma_add_sync_on_channel_ctd(&ctx->desc_list, - VPE_CHAN_RGB_OUT); - } else { - vpdma_add_sync_on_channel_ctd(&ctx->desc_list, - VPE_CHAN_LUMA_OUT); - if (d_q_data->fmt->coplanar) - vpdma_add_sync_on_channel_ctd(&ctx->desc_list, - VPE_CHAN_CHROMA_OUT); - } - - if (ctx->deinterlacing) - vpdma_add_sync_on_channel_ctd(&ctx->desc_list, VPE_CHAN_MV_OUT); - - enable_irqs(ctx); - - vpdma_map_desc_buf(ctx->dev->vpdma, &ctx->desc_list.buf); - vpdma_submit_descs(ctx->dev->vpdma, &ctx->desc_list, 0); -} - -static void dei_error(struct vpe_ctx *ctx) -{ - dev_warn(ctx->dev->v4l2_dev.dev, - "received DEI error interrupt\n"); -} - -static void ds1_uv_error(struct vpe_ctx *ctx) -{ - dev_warn(ctx->dev->v4l2_dev.dev, - "received downsampler error interrupt\n"); -} - -static irqreturn_t vpe_irq(int irq_vpe, void *data) -{ - struct vpe_dev *dev = (struct vpe_dev *)data; - struct vpe_ctx *ctx; - struct vpe_q_data *d_q_data; - struct vb2_v4l2_buffer *s_vb, *d_vb; - unsigned long flags; - u32 irqst0, irqst1; - bool list_complete = false; - - irqst0 = read_reg(dev, VPE_INT0_STATUS0); - if (irqst0) { - write_reg(dev, VPE_INT0_STATUS0_CLR, irqst0); - vpe_dbg(dev, "INT0_STATUS0 = 0x%08x\n", irqst0); - } - - irqst1 = read_reg(dev, VPE_INT0_STATUS1); - if (irqst1) { - write_reg(dev, VPE_INT0_STATUS1_CLR, irqst1); - vpe_dbg(dev, "INT0_STATUS1 = 0x%08x\n", irqst1); - } - - ctx = v4l2_m2m_get_curr_priv(dev->m2m_dev); - if (!ctx) { - vpe_err(dev, "instance released before end of transaction\n"); - goto handled; - } - - if (irqst1) { - if (irqst1 & VPE_DEI_ERROR_INT) { - irqst1 &= ~VPE_DEI_ERROR_INT; - dei_error(ctx); - } - if (irqst1 & VPE_DS1_UV_ERROR_INT) { - irqst1 &= ~VPE_DS1_UV_ERROR_INT; - ds1_uv_error(ctx); - } - } - - if (irqst0) { - if (irqst0 & VPE_INT0_LIST0_COMPLETE) - vpdma_clear_list_stat(ctx->dev->vpdma, 0, 0); - - irqst0 &= ~(VPE_INT0_LIST0_COMPLETE); - list_complete = true; - } - - if (irqst0 | irqst1) { - dev_warn(dev->v4l2_dev.dev, "Unexpected interrupt: INT0_STATUS0 = 0x%08x, INT0_STATUS1 = 0x%08x\n", - irqst0, irqst1); - } - - /* - * Setup next operation only when list complete IRQ occurs - * otherwise, skip the following code - */ - if (!list_complete) - goto handled; - - disable_irqs(ctx); - - vpdma_unmap_desc_buf(dev->vpdma, &ctx->desc_list.buf); - vpdma_unmap_desc_buf(dev->vpdma, &ctx->mmr_adb); - vpdma_unmap_desc_buf(dev->vpdma, &ctx->sc_coeff_h); - vpdma_unmap_desc_buf(dev->vpdma, &ctx->sc_coeff_v); - - vpdma_reset_desc_list(&ctx->desc_list); - - /* the previous dst mv buffer becomes the next src mv buffer */ - ctx->src_mv_buf_selector = !ctx->src_mv_buf_selector; - - s_vb = ctx->src_vbs[0]; - d_vb = ctx->dst_vb; - - d_vb->flags = s_vb->flags; - d_vb->vb2_buf.timestamp = s_vb->vb2_buf.timestamp; - - if (s_vb->flags & V4L2_BUF_FLAG_TIMECODE) - d_vb->timecode = s_vb->timecode; - - d_vb->sequence = ctx->sequence; - s_vb->sequence = ctx->sequence; - - d_q_data = &ctx->q_data[Q_DATA_DST]; - if (d_q_data->flags & Q_IS_INTERLACED) { - d_vb->field = ctx->field; - if (ctx->field == V4L2_FIELD_BOTTOM) { - ctx->sequence++; - ctx->field = V4L2_FIELD_TOP; - } else { - WARN_ON(ctx->field != V4L2_FIELD_TOP); - ctx->field = V4L2_FIELD_BOTTOM; - } - } else { - d_vb->field = V4L2_FIELD_NONE; - ctx->sequence++; - } - - if (ctx->deinterlacing) { - /* - * Allow source buffer to be dequeued only if it won't be used - * in the next iteration. All vbs are initialized to first - * buffer and we are shifting buffers every iteration, for the - * first two iterations, no buffer will be dequeued. - * This ensures that driver will keep (n-2)th (n-1)th and (n)th - * field when deinterlacing is enabled - */ - if (ctx->src_vbs[2] != ctx->src_vbs[1]) - s_vb = ctx->src_vbs[2]; - else - s_vb = NULL; - } - - spin_lock_irqsave(&dev->lock, flags); - - if (s_vb) - v4l2_m2m_buf_done(s_vb, VB2_BUF_STATE_DONE); - - v4l2_m2m_buf_done(d_vb, VB2_BUF_STATE_DONE); - - spin_unlock_irqrestore(&dev->lock, flags); - - if (ctx->deinterlacing) { - ctx->src_vbs[2] = ctx->src_vbs[1]; - ctx->src_vbs[1] = ctx->src_vbs[0]; - } - - /* - * Since the vb2_buf_done has already been called fir therse - * buffer we can now NULL them out so that we won't try - * to clean out stray pointer later on. - */ - ctx->src_vbs[0] = NULL; - ctx->dst_vb = NULL; - - if (ctx->aborting) - goto finished; - - ctx->bufs_completed++; - if (ctx->bufs_completed < ctx->bufs_per_job && job_ready(ctx)) { - device_run(ctx); - goto handled; - } - -finished: - vpe_dbg(ctx->dev, "finishing transaction\n"); - ctx->bufs_completed = 0; - v4l2_m2m_job_finish(dev->m2m_dev, ctx->fh.m2m_ctx); -handled: - return IRQ_HANDLED; -} - -/* - * video ioctls - */ -static int vpe_querycap(struct file *file, void *priv, - struct v4l2_capability *cap) -{ - strscpy(cap->driver, VPE_MODULE_NAME, sizeof(cap->driver)); - strscpy(cap->card, VPE_MODULE_NAME, sizeof(cap->card)); - snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s", - VPE_MODULE_NAME); - return 0; -} - -static int __enum_fmt(struct v4l2_fmtdesc *f, u32 type) -{ - int i, index; - struct vpe_fmt *fmt = NULL; - - index = 0; - for (i = 0; i < ARRAY_SIZE(vpe_formats); ++i) { - if (vpe_formats[i].types & type) { - if (index == f->index) { - fmt = &vpe_formats[i]; - break; - } - index++; - } - } - - if (!fmt) - return -EINVAL; - - f->pixelformat = fmt->fourcc; - return 0; -} - -static int vpe_enum_fmt(struct file *file, void *priv, - struct v4l2_fmtdesc *f) -{ - if (V4L2_TYPE_IS_OUTPUT(f->type)) - return __enum_fmt(f, VPE_FMT_TYPE_OUTPUT); - - return __enum_fmt(f, VPE_FMT_TYPE_CAPTURE); -} - -static int vpe_g_fmt(struct file *file, void *priv, struct v4l2_format *f) -{ - struct v4l2_pix_format_mplane *pix = &f->fmt.pix_mp; - struct vpe_ctx *ctx = file->private_data; - struct vb2_queue *vq; - struct vpe_q_data *q_data; - - vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type); - if (!vq) - return -EINVAL; - - q_data = get_q_data(ctx, f->type); - if (!q_data) - return -EINVAL; - - *f = q_data->format; - - if (V4L2_TYPE_IS_CAPTURE(f->type)) { - struct vpe_q_data *s_q_data; - struct v4l2_pix_format_mplane *spix; - - /* get colorimetry from the source queue */ - s_q_data = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE); - spix = &s_q_data->format.fmt.pix_mp; - - pix->colorspace = spix->colorspace; - pix->xfer_func = spix->xfer_func; - pix->ycbcr_enc = spix->ycbcr_enc; - pix->quantization = spix->quantization; - } - - return 0; -} - -static int __vpe_try_fmt(struct vpe_ctx *ctx, struct v4l2_format *f, - struct vpe_fmt *fmt, int type) -{ - struct v4l2_pix_format_mplane *pix = &f->fmt.pix_mp; - struct v4l2_plane_pix_format *plane_fmt; - unsigned int w_align; - int i, depth, depth_bytes, height; - unsigned int stride = 0; - const struct v4l2_format_info *finfo; - - if (!fmt || !(fmt->types & type)) { - vpe_dbg(ctx->dev, "Fourcc format (0x%08x) invalid.\n", - pix->pixelformat); - fmt = __find_format(V4L2_PIX_FMT_YUYV); - } - - if (pix->field != V4L2_FIELD_NONE && - pix->field != V4L2_FIELD_ALTERNATE && - pix->field != V4L2_FIELD_SEQ_TB && - pix->field != V4L2_FIELD_SEQ_BT) - pix->field = V4L2_FIELD_NONE; - - depth = fmt->vpdma_fmt[VPE_LUMA]->depth; - - /* - * the line stride should 16 byte aligned for VPDMA to work, based on - * the bytes per pixel, figure out how much the width should be aligned - * to make sure line stride is 16 byte aligned - */ - depth_bytes = depth >> 3; - - if (depth_bytes == 3) { - /* - * if bpp is 3(as in some RGB formats), the pixel width doesn't - * really help in ensuring line stride is 16 byte aligned - */ - w_align = 4; - } else { - /* - * for the remainder bpp(4, 2 and 1), the pixel width alignment - * can ensure a line stride alignment of 16 bytes. For example, - * if bpp is 2, then the line stride can be 16 byte aligned if - * the width is 8 byte aligned - */ - - /* - * HACK: using order_base_2() here causes lots of asm output - * errors with smatch, on i386: - * ./arch/x86/include/asm/bitops.h:457:22: - * warning: asm output is not an lvalue - * Perhaps some gcc optimization is doing the wrong thing - * there. - * Let's get rid of them by doing the calculus on two steps - */ - w_align = roundup_pow_of_two(VPDMA_DESC_ALIGN / depth_bytes); - w_align = ilog2(w_align); - } - - v4l_bound_align_image(&pix->width, MIN_W, MAX_W, w_align, - &pix->height, MIN_H, MAX_H, H_ALIGN, - S_ALIGN); - - if (!pix->num_planes || pix->num_planes > 2) - pix->num_planes = fmt->coplanar ? 2 : 1; - else if (pix->num_planes > 1 && !fmt->coplanar) - pix->num_planes = 1; - - pix->pixelformat = fmt->fourcc; - finfo = v4l2_format_info(fmt->fourcc); - - /* - * For the actual image parameters, we need to consider the field - * height of the image for SEQ_XX buffers. - */ - if (pix->field == V4L2_FIELD_SEQ_TB || pix->field == V4L2_FIELD_SEQ_BT) - height = pix->height / 2; - else - height = pix->height; - - if (!pix->colorspace) { - if (v4l2_is_format_rgb(finfo)) { - pix->colorspace = V4L2_COLORSPACE_SRGB; - } else { - if (height > 1280) /* HD */ - pix->colorspace = V4L2_COLORSPACE_REC709; - else /* SD */ - pix->colorspace = V4L2_COLORSPACE_SMPTE170M; - } - } - - for (i = 0; i < pix->num_planes; i++) { - plane_fmt = &pix->plane_fmt[i]; - depth = fmt->vpdma_fmt[i]->depth; - - stride = (pix->width * fmt->vpdma_fmt[VPE_LUMA]->depth) >> 3; - if (stride > plane_fmt->bytesperline) - plane_fmt->bytesperline = stride; - - plane_fmt->bytesperline = clamp_t(u32, plane_fmt->bytesperline, - stride, - VPDMA_MAX_STRIDE); - - plane_fmt->bytesperline = ALIGN(plane_fmt->bytesperline, - VPDMA_STRIDE_ALIGN); - - if (i == VPE_LUMA) { - plane_fmt->sizeimage = pix->height * - plane_fmt->bytesperline; - - if (pix->num_planes == 1 && fmt->coplanar) - plane_fmt->sizeimage += pix->height * - plane_fmt->bytesperline * - fmt->vpdma_fmt[VPE_CHROMA]->depth >> 3; - - } else { /* i == VIP_CHROMA */ - plane_fmt->sizeimage = (pix->height * - plane_fmt->bytesperline * - depth) >> 3; - } - } - - return 0; -} - -static int vpe_try_fmt(struct file *file, void *priv, struct v4l2_format *f) -{ - struct vpe_ctx *ctx = file->private_data; - struct vpe_fmt *fmt = find_format(f); - - if (V4L2_TYPE_IS_OUTPUT(f->type)) - return __vpe_try_fmt(ctx, f, fmt, VPE_FMT_TYPE_OUTPUT); - else - return __vpe_try_fmt(ctx, f, fmt, VPE_FMT_TYPE_CAPTURE); -} - -static int __vpe_s_fmt(struct vpe_ctx *ctx, struct v4l2_format *f) -{ - struct v4l2_pix_format_mplane *pix = &f->fmt.pix_mp; - struct v4l2_pix_format_mplane *qpix; - struct vpe_q_data *q_data; - struct vb2_queue *vq; - - vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type); - if (!vq) - return -EINVAL; - - if (vb2_is_busy(vq)) { - vpe_err(ctx->dev, "queue busy\n"); - return -EBUSY; - } - - q_data = get_q_data(ctx, f->type); - if (!q_data) - return -EINVAL; - - qpix = &q_data->format.fmt.pix_mp; - q_data->fmt = find_format(f); - q_data->format = *f; - - q_data->c_rect.left = 0; - q_data->c_rect.top = 0; - q_data->c_rect.width = pix->width; - q_data->c_rect.height = pix->height; - - if (qpix->field == V4L2_FIELD_ALTERNATE) - q_data->flags |= Q_DATA_INTERLACED_ALTERNATE; - else if (qpix->field == V4L2_FIELD_SEQ_TB) - q_data->flags |= Q_DATA_INTERLACED_SEQ_TB; - else if (qpix->field == V4L2_FIELD_SEQ_BT) - q_data->flags |= Q_DATA_INTERLACED_SEQ_BT; - else - q_data->flags &= ~Q_IS_INTERLACED; - - /* the crop height is halved for the case of SEQ_XX buffers */ - if (q_data->flags & Q_IS_SEQ_XX) - q_data->c_rect.height /= 2; - - vpe_dbg(ctx->dev, "Setting format for type %d, wxh: %dx%d, fmt: %d bpl_y %d", - f->type, pix->width, pix->height, pix->pixelformat, - pix->plane_fmt[0].bytesperline); - if (pix->num_planes == 2) - vpe_dbg(ctx->dev, " bpl_uv %d\n", - pix->plane_fmt[1].bytesperline); - - return 0; -} - -static int vpe_s_fmt(struct file *file, void *priv, struct v4l2_format *f) -{ - int ret; - struct vpe_ctx *ctx = file->private_data; - - ret = vpe_try_fmt(file, priv, f); - if (ret) - return ret; - - ret = __vpe_s_fmt(ctx, f); - if (ret) - return ret; - - if (V4L2_TYPE_IS_OUTPUT(f->type)) - set_src_registers(ctx); - else - set_dst_registers(ctx); - - return set_srcdst_params(ctx); -} - -static int __vpe_try_selection(struct vpe_ctx *ctx, struct v4l2_selection *s) -{ - struct vpe_q_data *q_data; - struct v4l2_pix_format_mplane *pix; - int height; - - if ((s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) && - (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)) - return -EINVAL; - - q_data = get_q_data(ctx, s->type); - if (!q_data) - return -EINVAL; - - pix = &q_data->format.fmt.pix_mp; - - switch (s->target) { - case V4L2_SEL_TGT_COMPOSE: - /* - * COMPOSE target is only valid for capture buffer type, return - * error for output buffer type - */ - if (s->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) - return -EINVAL; - break; - case V4L2_SEL_TGT_CROP: - /* - * CROP target is only valid for output buffer type, return - * error for capture buffer type - */ - if (s->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - break; - /* - * bound and default crop/compose targets are invalid targets to - * try/set - */ - default: - return -EINVAL; - } - - /* - * For SEQ_XX buffers, crop height should be less than the height of - * the field height, not the buffer height - */ - if (q_data->flags & Q_IS_SEQ_XX) - height = pix->height / 2; - else - height = pix->height; - - if (s->r.top < 0 || s->r.left < 0) { - vpe_err(ctx->dev, "negative values for top and left\n"); - s->r.top = s->r.left = 0; - } - - v4l_bound_align_image(&s->r.width, MIN_W, pix->width, 1, - &s->r.height, MIN_H, height, H_ALIGN, S_ALIGN); - - /* adjust left/top if cropping rectangle is out of bounds */ - if (s->r.left + s->r.width > pix->width) - s->r.left = pix->width - s->r.width; - if (s->r.top + s->r.height > pix->height) - s->r.top = pix->height - s->r.height; - - return 0; -} - -static int vpe_g_selection(struct file *file, void *fh, - struct v4l2_selection *s) -{ - struct vpe_ctx *ctx = file->private_data; - struct vpe_q_data *q_data; - struct v4l2_pix_format_mplane *pix; - bool use_c_rect = false; - - if ((s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) && - (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)) - return -EINVAL; - - q_data = get_q_data(ctx, s->type); - if (!q_data) - return -EINVAL; - - pix = &q_data->format.fmt.pix_mp; - - switch (s->target) { - case V4L2_SEL_TGT_COMPOSE_DEFAULT: - case V4L2_SEL_TGT_COMPOSE_BOUNDS: - if (s->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) - return -EINVAL; - break; - case V4L2_SEL_TGT_CROP_BOUNDS: - case V4L2_SEL_TGT_CROP_DEFAULT: - if (s->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - break; - case V4L2_SEL_TGT_COMPOSE: - if (s->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) - return -EINVAL; - use_c_rect = true; - break; - case V4L2_SEL_TGT_CROP: - if (s->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - use_c_rect = true; - break; - default: - return -EINVAL; - } - - if (use_c_rect) { - /* - * for CROP/COMPOSE target type, return c_rect params from the - * respective buffer type - */ - s->r = q_data->c_rect; - } else { - /* - * for DEFAULT/BOUNDS target type, return width and height from - * S_FMT of the respective buffer type - */ - s->r.left = 0; - s->r.top = 0; - s->r.width = pix->width; - s->r.height = pix->height; - } - - return 0; -} - - -static int vpe_s_selection(struct file *file, void *fh, - struct v4l2_selection *s) -{ - struct vpe_ctx *ctx = file->private_data; - struct vpe_q_data *q_data; - struct v4l2_selection sel = *s; - int ret; - - ret = __vpe_try_selection(ctx, &sel); - if (ret) - return ret; - - q_data = get_q_data(ctx, sel.type); - if (!q_data) - return -EINVAL; - - if ((q_data->c_rect.left == sel.r.left) && - (q_data->c_rect.top == sel.r.top) && - (q_data->c_rect.width == sel.r.width) && - (q_data->c_rect.height == sel.r.height)) { - vpe_dbg(ctx->dev, - "requested crop/compose values are already set\n"); - return 0; - } - - q_data->c_rect = sel.r; - - return set_srcdst_params(ctx); -} - -/* - * defines number of buffers/frames a context can process with VPE before - * switching to a different context. default value is 1 buffer per context - */ -#define V4L2_CID_VPE_BUFS_PER_JOB (V4L2_CID_USER_TI_VPE_BASE + 0) - -static int vpe_s_ctrl(struct v4l2_ctrl *ctrl) -{ - struct vpe_ctx *ctx = - container_of(ctrl->handler, struct vpe_ctx, hdl); - - switch (ctrl->id) { - case V4L2_CID_VPE_BUFS_PER_JOB: - ctx->bufs_per_job = ctrl->val; - break; - - default: - vpe_err(ctx->dev, "Invalid control\n"); - return -EINVAL; - } - - return 0; -} - -static const struct v4l2_ctrl_ops vpe_ctrl_ops = { - .s_ctrl = vpe_s_ctrl, -}; - -static const struct v4l2_ioctl_ops vpe_ioctl_ops = { - .vidioc_querycap = vpe_querycap, - - .vidioc_enum_fmt_vid_cap = vpe_enum_fmt, - .vidioc_g_fmt_vid_cap_mplane = vpe_g_fmt, - .vidioc_try_fmt_vid_cap_mplane = vpe_try_fmt, - .vidioc_s_fmt_vid_cap_mplane = vpe_s_fmt, - - .vidioc_enum_fmt_vid_out = vpe_enum_fmt, - .vidioc_g_fmt_vid_out_mplane = vpe_g_fmt, - .vidioc_try_fmt_vid_out_mplane = vpe_try_fmt, - .vidioc_s_fmt_vid_out_mplane = vpe_s_fmt, - - .vidioc_g_selection = vpe_g_selection, - .vidioc_s_selection = vpe_s_selection, - - .vidioc_reqbufs = v4l2_m2m_ioctl_reqbufs, - .vidioc_querybuf = v4l2_m2m_ioctl_querybuf, - .vidioc_qbuf = v4l2_m2m_ioctl_qbuf, - .vidioc_dqbuf = v4l2_m2m_ioctl_dqbuf, - .vidioc_expbuf = v4l2_m2m_ioctl_expbuf, - .vidioc_streamon = v4l2_m2m_ioctl_streamon, - .vidioc_streamoff = v4l2_m2m_ioctl_streamoff, - - .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, - .vidioc_unsubscribe_event = v4l2_event_unsubscribe, -}; - -/* - * Queue operations - */ -static int vpe_queue_setup(struct vb2_queue *vq, - unsigned int *nbuffers, unsigned int *nplanes, - unsigned int sizes[], struct device *alloc_devs[]) -{ - int i; - struct vpe_ctx *ctx = vb2_get_drv_priv(vq); - struct vpe_q_data *q_data; - struct v4l2_pix_format_mplane *pix; - - q_data = get_q_data(ctx, vq->type); - if (!q_data) - return -EINVAL; - - pix = &q_data->format.fmt.pix_mp; - *nplanes = pix->num_planes; - - for (i = 0; i < *nplanes; i++) - sizes[i] = pix->plane_fmt[i].sizeimage; - - vpe_dbg(ctx->dev, "get %d buffer(s) of size %d", *nbuffers, - sizes[VPE_LUMA]); - if (*nplanes == 2) - vpe_dbg(ctx->dev, " and %d\n", sizes[VPE_CHROMA]); - - return 0; -} - -static int vpe_buf_prepare(struct vb2_buffer *vb) -{ - struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); - struct vpe_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); - struct vpe_q_data *q_data; - struct v4l2_pix_format_mplane *pix; - int i; - - vpe_dbg(ctx->dev, "type: %d\n", vb->vb2_queue->type); - - q_data = get_q_data(ctx, vb->vb2_queue->type); - if (!q_data) - return -EINVAL; - - pix = &q_data->format.fmt.pix_mp; - - if (vb->vb2_queue->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { - if (!(q_data->flags & Q_IS_INTERLACED)) { - vbuf->field = V4L2_FIELD_NONE; - } else { - if (vbuf->field != V4L2_FIELD_TOP && - vbuf->field != V4L2_FIELD_BOTTOM && - vbuf->field != V4L2_FIELD_SEQ_TB && - vbuf->field != V4L2_FIELD_SEQ_BT) - return -EINVAL; - } - } - - for (i = 0; i < pix->num_planes; i++) { - if (vb2_plane_size(vb, i) < pix->plane_fmt[i].sizeimage) { - vpe_err(ctx->dev, - "data will not fit into plane (%lu < %lu)\n", - vb2_plane_size(vb, i), - (long)pix->plane_fmt[i].sizeimage); - return -EINVAL; - } - } - - for (i = 0; i < pix->num_planes; i++) - vb2_set_plane_payload(vb, i, pix->plane_fmt[i].sizeimage); - - return 0; -} - -static void vpe_buf_queue(struct vb2_buffer *vb) -{ - struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); - struct vpe_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); - - v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vbuf); -} - -static int check_srcdst_sizes(struct vpe_ctx *ctx) -{ - struct vpe_q_data *s_q_data = &ctx->q_data[Q_DATA_SRC]; - struct vpe_q_data *d_q_data = &ctx->q_data[Q_DATA_DST]; - unsigned int src_w = s_q_data->c_rect.width; - unsigned int src_h = s_q_data->c_rect.height; - unsigned int dst_w = d_q_data->c_rect.width; - unsigned int dst_h = d_q_data->c_rect.height; - - if (src_w == dst_w && src_h == dst_h) - return 0; - - if (src_h <= SC_MAX_PIXEL_HEIGHT && - src_w <= SC_MAX_PIXEL_WIDTH && - dst_h <= SC_MAX_PIXEL_HEIGHT && - dst_w <= SC_MAX_PIXEL_WIDTH) - return 0; - - return -1; -} - -static void vpe_return_all_buffers(struct vpe_ctx *ctx, struct vb2_queue *q, - enum vb2_buffer_state state) -{ - struct vb2_v4l2_buffer *vb; - unsigned long flags; - - for (;;) { - if (V4L2_TYPE_IS_OUTPUT(q->type)) - vb = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx); - else - vb = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx); - if (!vb) - break; - spin_lock_irqsave(&ctx->dev->lock, flags); - v4l2_m2m_buf_done(vb, state); - spin_unlock_irqrestore(&ctx->dev->lock, flags); - } - - /* - * Cleanup the in-transit vb2 buffers that have been - * removed from their respective queue already but for - * which procecessing has not been completed yet. - */ - if (V4L2_TYPE_IS_OUTPUT(q->type)) { - spin_lock_irqsave(&ctx->dev->lock, flags); - - if (ctx->src_vbs[2]) - v4l2_m2m_buf_done(ctx->src_vbs[2], state); - - if (ctx->src_vbs[1] && (ctx->src_vbs[1] != ctx->src_vbs[2])) - v4l2_m2m_buf_done(ctx->src_vbs[1], state); - - if (ctx->src_vbs[0] && - (ctx->src_vbs[0] != ctx->src_vbs[1]) && - (ctx->src_vbs[0] != ctx->src_vbs[2])) - v4l2_m2m_buf_done(ctx->src_vbs[0], state); - - ctx->src_vbs[2] = NULL; - ctx->src_vbs[1] = NULL; - ctx->src_vbs[0] = NULL; - - spin_unlock_irqrestore(&ctx->dev->lock, flags); - } else { - if (ctx->dst_vb) { - spin_lock_irqsave(&ctx->dev->lock, flags); - - v4l2_m2m_buf_done(ctx->dst_vb, state); - ctx->dst_vb = NULL; - spin_unlock_irqrestore(&ctx->dev->lock, flags); - } - } -} - -static int vpe_start_streaming(struct vb2_queue *q, unsigned int count) -{ - struct vpe_ctx *ctx = vb2_get_drv_priv(q); - - /* Check any of the size exceed maximum scaling sizes */ - if (check_srcdst_sizes(ctx)) { - vpe_err(ctx->dev, - "Conversion setup failed, check source and destination parameters\n" - ); - vpe_return_all_buffers(ctx, q, VB2_BUF_STATE_QUEUED); - return -EINVAL; - } - - if (ctx->deinterlacing) - config_edi_input_mode(ctx, 0x0); - - if (ctx->sequence != 0) - set_srcdst_params(ctx); - - return 0; -} - -static void vpe_stop_streaming(struct vb2_queue *q) -{ - struct vpe_ctx *ctx = vb2_get_drv_priv(q); - - vpe_dump_regs(ctx->dev); - vpdma_dump_regs(ctx->dev->vpdma); - - vpe_return_all_buffers(ctx, q, VB2_BUF_STATE_ERROR); -} - -static const struct vb2_ops vpe_qops = { - .queue_setup = vpe_queue_setup, - .buf_prepare = vpe_buf_prepare, - .buf_queue = vpe_buf_queue, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, - .start_streaming = vpe_start_streaming, - .stop_streaming = vpe_stop_streaming, -}; - -static int queue_init(void *priv, struct vb2_queue *src_vq, - struct vb2_queue *dst_vq) -{ - struct vpe_ctx *ctx = priv; - struct vpe_dev *dev = ctx->dev; - int ret; - - memset(src_vq, 0, sizeof(*src_vq)); - src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; - src_vq->io_modes = VB2_MMAP | VB2_DMABUF; - src_vq->drv_priv = ctx; - src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer); - src_vq->ops = &vpe_qops; - src_vq->mem_ops = &vb2_dma_contig_memops; - src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; - src_vq->lock = &dev->dev_mutex; - src_vq->dev = dev->v4l2_dev.dev; - - ret = vb2_queue_init(src_vq); - if (ret) - return ret; - - memset(dst_vq, 0, sizeof(*dst_vq)); - dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; - dst_vq->io_modes = VB2_MMAP | VB2_DMABUF; - dst_vq->drv_priv = ctx; - dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer); - dst_vq->ops = &vpe_qops; - dst_vq->mem_ops = &vb2_dma_contig_memops; - dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; - dst_vq->lock = &dev->dev_mutex; - dst_vq->dev = dev->v4l2_dev.dev; - - return vb2_queue_init(dst_vq); -} - -static const struct v4l2_ctrl_config vpe_bufs_per_job = { - .ops = &vpe_ctrl_ops, - .id = V4L2_CID_VPE_BUFS_PER_JOB, - .name = "Buffers Per Transaction", - .type = V4L2_CTRL_TYPE_INTEGER, - .def = VPE_DEF_BUFS_PER_JOB, - .min = 1, - .max = VIDEO_MAX_FRAME, - .step = 1, -}; - -/* - * File operations - */ -static int vpe_open(struct file *file) -{ - struct vpe_dev *dev = video_drvdata(file); - struct vpe_q_data *s_q_data; - struct v4l2_ctrl_handler *hdl; - struct vpe_ctx *ctx; - struct v4l2_pix_format_mplane *pix; - int ret; - - vpe_dbg(dev, "vpe_open\n"); - - ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); - if (!ctx) - return -ENOMEM; - - ctx->dev = dev; - - if (mutex_lock_interruptible(&dev->dev_mutex)) { - ret = -ERESTARTSYS; - goto free_ctx; - } - - ret = vpdma_create_desc_list(&ctx->desc_list, VPE_DESC_LIST_SIZE, - VPDMA_LIST_TYPE_NORMAL); - if (ret != 0) - goto unlock; - - ret = vpdma_alloc_desc_buf(&ctx->mmr_adb, sizeof(struct vpe_mmr_adb)); - if (ret != 0) - goto free_desc_list; - - ret = vpdma_alloc_desc_buf(&ctx->sc_coeff_h, SC_COEF_SRAM_SIZE); - if (ret != 0) - goto free_mmr_adb; - - ret = vpdma_alloc_desc_buf(&ctx->sc_coeff_v, SC_COEF_SRAM_SIZE); - if (ret != 0) - goto free_sc_h; - - init_adb_hdrs(ctx); - - v4l2_fh_init(&ctx->fh, video_devdata(file)); - file->private_data = ctx; - - hdl = &ctx->hdl; - v4l2_ctrl_handler_init(hdl, 1); - v4l2_ctrl_new_custom(hdl, &vpe_bufs_per_job, NULL); - if (hdl->error) { - ret = hdl->error; - goto exit_fh; - } - ctx->fh.ctrl_handler = hdl; - v4l2_ctrl_handler_setup(hdl); - - s_q_data = &ctx->q_data[Q_DATA_SRC]; - pix = &s_q_data->format.fmt.pix_mp; - s_q_data->fmt = __find_format(V4L2_PIX_FMT_YUYV); - pix->pixelformat = s_q_data->fmt->fourcc; - s_q_data->format.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; - pix->width = 1920; - pix->height = 1080; - pix->num_planes = 1; - pix->plane_fmt[VPE_LUMA].bytesperline = (pix->width * - s_q_data->fmt->vpdma_fmt[VPE_LUMA]->depth) >> 3; - pix->plane_fmt[VPE_LUMA].sizeimage = - pix->plane_fmt[VPE_LUMA].bytesperline * - pix->height; - pix->colorspace = V4L2_COLORSPACE_REC709; - pix->xfer_func = V4L2_XFER_FUNC_DEFAULT; - pix->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT; - pix->quantization = V4L2_QUANTIZATION_DEFAULT; - pix->field = V4L2_FIELD_NONE; - s_q_data->c_rect.left = 0; - s_q_data->c_rect.top = 0; - s_q_data->c_rect.width = pix->width; - s_q_data->c_rect.height = pix->height; - s_q_data->flags = 0; - - ctx->q_data[Q_DATA_DST] = *s_q_data; - ctx->q_data[Q_DATA_DST].format.type = - V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; - - set_dei_shadow_registers(ctx); - set_src_registers(ctx); - set_dst_registers(ctx); - ret = set_srcdst_params(ctx); - if (ret) - goto exit_fh; - - ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(dev->m2m_dev, ctx, &queue_init); - - if (IS_ERR(ctx->fh.m2m_ctx)) { - ret = PTR_ERR(ctx->fh.m2m_ctx); - goto exit_fh; - } - - v4l2_fh_add(&ctx->fh); - - /* - * for now, just report the creation of the first instance, we can later - * optimize the driver to enable or disable clocks when the first - * instance is created or the last instance released - */ - if (atomic_inc_return(&dev->num_instances) == 1) - vpe_dbg(dev, "first instance created\n"); - - ctx->bufs_per_job = VPE_DEF_BUFS_PER_JOB; - - ctx->load_mmrs = true; - - vpe_dbg(dev, "created instance %p, m2m_ctx: %p\n", - ctx, ctx->fh.m2m_ctx); - - mutex_unlock(&dev->dev_mutex); - - return 0; -exit_fh: - v4l2_ctrl_handler_free(hdl); - v4l2_fh_exit(&ctx->fh); - vpdma_free_desc_buf(&ctx->sc_coeff_v); -free_sc_h: - vpdma_free_desc_buf(&ctx->sc_coeff_h); -free_mmr_adb: - vpdma_free_desc_buf(&ctx->mmr_adb); -free_desc_list: - vpdma_free_desc_list(&ctx->desc_list); -unlock: - mutex_unlock(&dev->dev_mutex); -free_ctx: - kfree(ctx); - return ret; -} - -static int vpe_release(struct file *file) -{ - struct vpe_dev *dev = video_drvdata(file); - struct vpe_ctx *ctx = file->private_data; - - vpe_dbg(dev, "releasing instance %p\n", ctx); - - mutex_lock(&dev->dev_mutex); - free_mv_buffers(ctx); - - vpdma_unmap_desc_buf(dev->vpdma, &ctx->desc_list.buf); - vpdma_unmap_desc_buf(dev->vpdma, &ctx->mmr_adb); - vpdma_unmap_desc_buf(dev->vpdma, &ctx->sc_coeff_h); - vpdma_unmap_desc_buf(dev->vpdma, &ctx->sc_coeff_v); - - vpdma_free_desc_list(&ctx->desc_list); - vpdma_free_desc_buf(&ctx->mmr_adb); - - vpdma_free_desc_buf(&ctx->sc_coeff_v); - vpdma_free_desc_buf(&ctx->sc_coeff_h); - - v4l2_fh_del(&ctx->fh); - v4l2_fh_exit(&ctx->fh); - v4l2_ctrl_handler_free(&ctx->hdl); - v4l2_m2m_ctx_release(ctx->fh.m2m_ctx); - - kfree(ctx); - - /* - * for now, just report the release of the last instance, we can later - * optimize the driver to enable or disable clocks when the first - * instance is created or the last instance released - */ - if (atomic_dec_return(&dev->num_instances) == 0) - vpe_dbg(dev, "last instance released\n"); - - mutex_unlock(&dev->dev_mutex); - - return 0; -} - -static const struct v4l2_file_operations vpe_fops = { - .owner = THIS_MODULE, - .open = vpe_open, - .release = vpe_release, - .poll = v4l2_m2m_fop_poll, - .unlocked_ioctl = video_ioctl2, - .mmap = v4l2_m2m_fop_mmap, -}; - -static const struct video_device vpe_videodev = { - .name = VPE_MODULE_NAME, - .fops = &vpe_fops, - .ioctl_ops = &vpe_ioctl_ops, - .minor = -1, - .release = video_device_release_empty, - .vfl_dir = VFL_DIR_M2M, - .device_caps = V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_STREAMING, -}; - -static const struct v4l2_m2m_ops m2m_ops = { - .device_run = device_run, - .job_ready = job_ready, - .job_abort = job_abort, -}; - -static int vpe_runtime_get(struct platform_device *pdev) -{ - int r; - - dev_dbg(&pdev->dev, "vpe_runtime_get\n"); - - r = pm_runtime_resume_and_get(&pdev->dev); - WARN_ON(r < 0); - return r; -} - -static void vpe_runtime_put(struct platform_device *pdev) -{ - - int r; - - dev_dbg(&pdev->dev, "vpe_runtime_put\n"); - - r = pm_runtime_put_sync(&pdev->dev); - WARN_ON(r < 0 && r != -ENOSYS); -} - -static void vpe_fw_cb(struct platform_device *pdev) -{ - struct vpe_dev *dev = platform_get_drvdata(pdev); - struct video_device *vfd; - int ret; - - vfd = &dev->vfd; - *vfd = vpe_videodev; - vfd->lock = &dev->dev_mutex; - vfd->v4l2_dev = &dev->v4l2_dev; - - ret = video_register_device(vfd, VFL_TYPE_VIDEO, 0); - if (ret) { - vpe_err(dev, "Failed to register video device\n"); - - vpe_set_clock_enable(dev, 0); - vpe_runtime_put(pdev); - pm_runtime_disable(&pdev->dev); - v4l2_m2m_release(dev->m2m_dev); - v4l2_device_unregister(&dev->v4l2_dev); - - return; - } - - video_set_drvdata(vfd, dev); - dev_info(dev->v4l2_dev.dev, "Device registered as /dev/video%d\n", - vfd->num); -} - -static int vpe_probe(struct platform_device *pdev) -{ - struct vpe_dev *dev; - int ret, irq, func; - - ret = dma_coerce_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)); - if (ret) { - dev_err(&pdev->dev, - "32-bit consistent DMA enable failed\n"); - return ret; - } - - dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL); - if (!dev) - return -ENOMEM; - - spin_lock_init(&dev->lock); - - ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev); - if (ret) - return ret; - - atomic_set(&dev->num_instances, 0); - mutex_init(&dev->dev_mutex); - - dev->res = platform_get_resource_byname(pdev, IORESOURCE_MEM, - "vpe_top"); - if (!dev->res) { - dev_err(&pdev->dev, "missing 'vpe_top' resources data\n"); - return -ENODEV; - } - - /* - * HACK: we get resource info from device tree in the form of a list of - * VPE sub blocks, the driver currently uses only the base of vpe_top - * for register access, the driver should be changed later to access - * registers based on the sub block base addresses - */ - dev->base = devm_ioremap(&pdev->dev, dev->res->start, SZ_32K); - if (!dev->base) { - ret = -ENOMEM; - goto v4l2_dev_unreg; - } - - irq = platform_get_irq(pdev, 0); - ret = devm_request_irq(&pdev->dev, irq, vpe_irq, 0, VPE_MODULE_NAME, - dev); - if (ret) - goto v4l2_dev_unreg; - - platform_set_drvdata(pdev, dev); - - dev->m2m_dev = v4l2_m2m_init(&m2m_ops); - if (IS_ERR(dev->m2m_dev)) { - vpe_err(dev, "Failed to init mem2mem device\n"); - ret = PTR_ERR(dev->m2m_dev); - goto v4l2_dev_unreg; - } - - pm_runtime_enable(&pdev->dev); - - ret = vpe_runtime_get(pdev); - if (ret < 0) - goto rel_m2m; - - /* Perform clk enable followed by reset */ - vpe_set_clock_enable(dev, 1); - - vpe_top_reset(dev); - - func = read_field_reg(dev, VPE_PID, VPE_PID_FUNC_MASK, - VPE_PID_FUNC_SHIFT); - vpe_dbg(dev, "VPE PID function %x\n", func); - - vpe_top_vpdma_reset(dev); - - dev->sc = sc_create(pdev, "sc"); - if (IS_ERR(dev->sc)) { - ret = PTR_ERR(dev->sc); - goto runtime_put; - } - - dev->csc = csc_create(pdev, "csc"); - if (IS_ERR(dev->csc)) { - ret = PTR_ERR(dev->csc); - goto runtime_put; - } - - dev->vpdma = &dev->vpdma_data; - ret = vpdma_create(pdev, dev->vpdma, vpe_fw_cb); - if (ret) - goto runtime_put; - - return 0; - -runtime_put: - vpe_runtime_put(pdev); -rel_m2m: - pm_runtime_disable(&pdev->dev); - v4l2_m2m_release(dev->m2m_dev); -v4l2_dev_unreg: - v4l2_device_unregister(&dev->v4l2_dev); - - return ret; -} - -static int vpe_remove(struct platform_device *pdev) -{ - struct vpe_dev *dev = platform_get_drvdata(pdev); - - v4l2_info(&dev->v4l2_dev, "Removing " VPE_MODULE_NAME); - - v4l2_m2m_release(dev->m2m_dev); - video_unregister_device(&dev->vfd); - v4l2_device_unregister(&dev->v4l2_dev); - - vpe_set_clock_enable(dev, 0); - vpe_runtime_put(pdev); - pm_runtime_disable(&pdev->dev); - - return 0; -} - -#if defined(CONFIG_OF) -static const struct of_device_id vpe_of_match[] = { - { - .compatible = "ti,dra7-vpe", - }, - {}, -}; -MODULE_DEVICE_TABLE(of, vpe_of_match); -#endif - -static struct platform_driver vpe_pdrv = { - .probe = vpe_probe, - .remove = vpe_remove, - .driver = { - .name = VPE_MODULE_NAME, - .of_match_table = of_match_ptr(vpe_of_match), - }, -}; - -module_platform_driver(vpe_pdrv); - -MODULE_DESCRIPTION("TI VPE driver"); -MODULE_AUTHOR("Dale Farnsworth, "); -MODULE_LICENSE("GPL"); diff --git a/drivers/media/platform/ti-vpe/vpe_regs.h b/drivers/media/platform/ti-vpe/vpe_regs.h deleted file mode 100644 index 1a1ad5ae1228..000000000000 --- a/drivers/media/platform/ti-vpe/vpe_regs.h +++ /dev/null @@ -1,306 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * Copyright (c) 2013 Texas Instruments Inc. - * - * David Griego, - * Dale Farnsworth, - * Archit Taneja, - */ - -#ifndef __TI_VPE_REGS_H -#define __TI_VPE_REGS_H - -/* VPE register offsets and field selectors */ - -/* VPE top level regs */ -#define VPE_PID 0x0000 -#define VPE_PID_MINOR_MASK 0x3f -#define VPE_PID_MINOR_SHIFT 0 -#define VPE_PID_CUSTOM_MASK 0x03 -#define VPE_PID_CUSTOM_SHIFT 6 -#define VPE_PID_MAJOR_MASK 0x07 -#define VPE_PID_MAJOR_SHIFT 8 -#define VPE_PID_RTL_MASK 0x1f -#define VPE_PID_RTL_SHIFT 11 -#define VPE_PID_FUNC_MASK 0xfff -#define VPE_PID_FUNC_SHIFT 16 -#define VPE_PID_SCHEME_MASK 0x03 -#define VPE_PID_SCHEME_SHIFT 30 - -#define VPE_SYSCONFIG 0x0010 -#define VPE_SYSCONFIG_IDLE_MASK 0x03 -#define VPE_SYSCONFIG_IDLE_SHIFT 2 -#define VPE_SYSCONFIG_STANDBY_MASK 0x03 -#define VPE_SYSCONFIG_STANDBY_SHIFT 4 -#define VPE_FORCE_IDLE_MODE 0 -#define VPE_NO_IDLE_MODE 1 -#define VPE_SMART_IDLE_MODE 2 -#define VPE_SMART_IDLE_WAKEUP_MODE 3 -#define VPE_FORCE_STANDBY_MODE 0 -#define VPE_NO_STANDBY_MODE 1 -#define VPE_SMART_STANDBY_MODE 2 -#define VPE_SMART_STANDBY_WAKEUP_MODE 3 - -#define VPE_INT0_STATUS0_RAW_SET 0x0020 -#define VPE_INT0_STATUS0_RAW VPE_INT0_STATUS0_RAW_SET -#define VPE_INT0_STATUS0_CLR 0x0028 -#define VPE_INT0_STATUS0 VPE_INT0_STATUS0_CLR -#define VPE_INT0_ENABLE0_SET 0x0030 -#define VPE_INT0_ENABLE0 VPE_INT0_ENABLE0_SET -#define VPE_INT0_ENABLE0_CLR 0x0038 -#define VPE_INT0_LIST0_COMPLETE BIT(0) -#define VPE_INT0_LIST0_NOTIFY BIT(1) -#define VPE_INT0_LIST1_COMPLETE BIT(2) -#define VPE_INT0_LIST1_NOTIFY BIT(3) -#define VPE_INT0_LIST2_COMPLETE BIT(4) -#define VPE_INT0_LIST2_NOTIFY BIT(5) -#define VPE_INT0_LIST3_COMPLETE BIT(6) -#define VPE_INT0_LIST3_NOTIFY BIT(7) -#define VPE_INT0_LIST4_COMPLETE BIT(8) -#define VPE_INT0_LIST4_NOTIFY BIT(9) -#define VPE_INT0_LIST5_COMPLETE BIT(10) -#define VPE_INT0_LIST5_NOTIFY BIT(11) -#define VPE_INT0_LIST6_COMPLETE BIT(12) -#define VPE_INT0_LIST6_NOTIFY BIT(13) -#define VPE_INT0_LIST7_COMPLETE BIT(14) -#define VPE_INT0_LIST7_NOTIFY BIT(15) -#define VPE_INT0_DESCRIPTOR BIT(16) -#define VPE_DEI_FMD_INT BIT(18) - -#define VPE_INT0_STATUS1_RAW_SET 0x0024 -#define VPE_INT0_STATUS1_RAW VPE_INT0_STATUS1_RAW_SET -#define VPE_INT0_STATUS1_CLR 0x002c -#define VPE_INT0_STATUS1 VPE_INT0_STATUS1_CLR -#define VPE_INT0_ENABLE1_SET 0x0034 -#define VPE_INT0_ENABLE1 VPE_INT0_ENABLE1_SET -#define VPE_INT0_ENABLE1_CLR 0x003c -#define VPE_INT0_CHANNEL_GROUP0 BIT(0) -#define VPE_INT0_CHANNEL_GROUP1 BIT(1) -#define VPE_INT0_CHANNEL_GROUP2 BIT(2) -#define VPE_INT0_CHANNEL_GROUP3 BIT(3) -#define VPE_INT0_CHANNEL_GROUP4 BIT(4) -#define VPE_INT0_CHANNEL_GROUP5 BIT(5) -#define VPE_INT0_CLIENT BIT(7) -#define VPE_DEI_ERROR_INT BIT(16) -#define VPE_DS1_UV_ERROR_INT BIT(22) - -#define VPE_INTC_EOI 0x00a0 - -#define VPE_CLK_ENABLE 0x0100 -#define VPE_VPEDMA_CLK_ENABLE BIT(0) -#define VPE_DATA_PATH_CLK_ENABLE BIT(1) - -#define VPE_CLK_RESET 0x0104 -#define VPE_VPDMA_CLK_RESET_MASK 0x1 -#define VPE_VPDMA_CLK_RESET_SHIFT 0 -#define VPE_DATA_PATH_CLK_RESET_MASK 0x1 -#define VPE_DATA_PATH_CLK_RESET_SHIFT 1 -#define VPE_MAIN_RESET_MASK 0x1 -#define VPE_MAIN_RESET_SHIFT 31 - -#define VPE_CLK_FORMAT_SELECT 0x010c -#define VPE_CSC_SRC_SELECT_MASK 0x03 -#define VPE_CSC_SRC_SELECT_SHIFT 0 -#define VPE_RGB_OUT_SELECT BIT(8) -#define VPE_DS_SRC_SELECT_MASK 0x07 -#define VPE_DS_SRC_SELECT_SHIFT 9 -#define VPE_DS_BYPASS BIT(16) -#define VPE_COLOR_SEPARATE_422 BIT(18) - -#define VPE_DS_SRC_DEI_SCALER (5 << VPE_DS_SRC_SELECT_SHIFT) -#define VPE_CSC_SRC_DEI_SCALER (3 << VPE_CSC_SRC_SELECT_SHIFT) - -#define VPE_CLK_RANGE_MAP 0x011c -#define VPE_RANGE_RANGE_MAP_Y_MASK 0x07 -#define VPE_RANGE_RANGE_MAP_Y_SHIFT 0 -#define VPE_RANGE_RANGE_MAP_UV_MASK 0x07 -#define VPE_RANGE_RANGE_MAP_UV_SHIFT 3 -#define VPE_RANGE_MAP_ON BIT(6) -#define VPE_RANGE_REDUCTION_ON BIT(28) - -/* VPE chrominance upsampler regs */ -#define VPE_US1_R0 0x0304 -#define VPE_US2_R0 0x0404 -#define VPE_US3_R0 0x0504 -#define VPE_US_C1_MASK 0x3fff -#define VPE_US_C1_SHIFT 2 -#define VPE_US_C0_MASK 0x3fff -#define VPE_US_C0_SHIFT 18 -#define VPE_US_MODE_MASK 0x03 -#define VPE_US_MODE_SHIFT 16 -#define VPE_ANCHOR_FID0_C1_MASK 0x3fff -#define VPE_ANCHOR_FID0_C1_SHIFT 2 -#define VPE_ANCHOR_FID0_C0_MASK 0x3fff -#define VPE_ANCHOR_FID0_C0_SHIFT 18 - -#define VPE_US1_R1 0x0308 -#define VPE_US2_R1 0x0408 -#define VPE_US3_R1 0x0508 -#define VPE_ANCHOR_FID0_C3_MASK 0x3fff -#define VPE_ANCHOR_FID0_C3_SHIFT 2 -#define VPE_ANCHOR_FID0_C2_MASK 0x3fff -#define VPE_ANCHOR_FID0_C2_SHIFT 18 - -#define VPE_US1_R2 0x030c -#define VPE_US2_R2 0x040c -#define VPE_US3_R2 0x050c -#define VPE_INTERP_FID0_C1_MASK 0x3fff -#define VPE_INTERP_FID0_C1_SHIFT 2 -#define VPE_INTERP_FID0_C0_MASK 0x3fff -#define VPE_INTERP_FID0_C0_SHIFT 18 - -#define VPE_US1_R3 0x0310 -#define VPE_US2_R3 0x0410 -#define VPE_US3_R3 0x0510 -#define VPE_INTERP_FID0_C3_MASK 0x3fff -#define VPE_INTERP_FID0_C3_SHIFT 2 -#define VPE_INTERP_FID0_C2_MASK 0x3fff -#define VPE_INTERP_FID0_C2_SHIFT 18 - -#define VPE_US1_R4 0x0314 -#define VPE_US2_R4 0x0414 -#define VPE_US3_R4 0x0514 -#define VPE_ANCHOR_FID1_C1_MASK 0x3fff -#define VPE_ANCHOR_FID1_C1_SHIFT 2 -#define VPE_ANCHOR_FID1_C0_MASK 0x3fff -#define VPE_ANCHOR_FID1_C0_SHIFT 18 - -#define VPE_US1_R5 0x0318 -#define VPE_US2_R5 0x0418 -#define VPE_US3_R5 0x0518 -#define VPE_ANCHOR_FID1_C3_MASK 0x3fff -#define VPE_ANCHOR_FID1_C3_SHIFT 2 -#define VPE_ANCHOR_FID1_C2_MASK 0x3fff -#define VPE_ANCHOR_FID1_C2_SHIFT 18 - -#define VPE_US1_R6 0x031c -#define VPE_US2_R6 0x041c -#define VPE_US3_R6 0x051c -#define VPE_INTERP_FID1_C1_MASK 0x3fff -#define VPE_INTERP_FID1_C1_SHIFT 2 -#define VPE_INTERP_FID1_C0_MASK 0x3fff -#define VPE_INTERP_FID1_C0_SHIFT 18 - -#define VPE_US1_R7 0x0320 -#define VPE_US2_R7 0x0420 -#define VPE_US3_R7 0x0520 -#define VPE_INTERP_FID0_C3_MASK 0x3fff -#define VPE_INTERP_FID0_C3_SHIFT 2 -#define VPE_INTERP_FID0_C2_MASK 0x3fff -#define VPE_INTERP_FID0_C2_SHIFT 18 - -/* VPE de-interlacer regs */ -#define VPE_DEI_FRAME_SIZE 0x0600 -#define VPE_DEI_WIDTH_MASK 0x07ff -#define VPE_DEI_WIDTH_SHIFT 0 -#define VPE_DEI_HEIGHT_MASK 0x07ff -#define VPE_DEI_HEIGHT_SHIFT 16 -#define VPE_DEI_INTERLACE_BYPASS BIT(29) -#define VPE_DEI_FIELD_FLUSH BIT(30) -#define VPE_DEI_PROGRESSIVE BIT(31) - -#define VPE_MDT_BYPASS 0x0604 -#define VPE_MDT_TEMPMAX_BYPASS BIT(0) -#define VPE_MDT_SPATMAX_BYPASS BIT(1) - -#define VPE_MDT_SF_THRESHOLD 0x0608 -#define VPE_MDT_SF_SC_THR1_MASK 0xff -#define VPE_MDT_SF_SC_THR1_SHIFT 0 -#define VPE_MDT_SF_SC_THR2_MASK 0xff -#define VPE_MDT_SF_SC_THR2_SHIFT 0 -#define VPE_MDT_SF_SC_THR3_MASK 0xff -#define VPE_MDT_SF_SC_THR3_SHIFT 0 - -#define VPE_EDI_CONFIG 0x060c -#define VPE_EDI_INP_MODE_MASK 0x03 -#define VPE_EDI_INP_MODE_SHIFT 0 -#define VPE_EDI_ENABLE_3D BIT(2) -#define VPE_EDI_ENABLE_CHROMA_3D BIT(3) -#define VPE_EDI_CHROMA3D_COR_THR_MASK 0xff -#define VPE_EDI_CHROMA3D_COR_THR_SHIFT 8 -#define VPE_EDI_DIR_COR_LOWER_THR_MASK 0xff -#define VPE_EDI_DIR_COR_LOWER_THR_SHIFT 16 -#define VPE_EDI_COR_SCALE_FACTOR_MASK 0xff -#define VPE_EDI_COR_SCALE_FACTOR_SHIFT 23 - -#define VPE_DEI_EDI_LUT_R0 0x0610 -#define VPE_EDI_LUT0_MASK 0x1f -#define VPE_EDI_LUT0_SHIFT 0 -#define VPE_EDI_LUT1_MASK 0x1f -#define VPE_EDI_LUT1_SHIFT 8 -#define VPE_EDI_LUT2_MASK 0x1f -#define VPE_EDI_LUT2_SHIFT 16 -#define VPE_EDI_LUT3_MASK 0x1f -#define VPE_EDI_LUT3_SHIFT 24 - -#define VPE_DEI_EDI_LUT_R1 0x0614 -#define VPE_EDI_LUT0_MASK 0x1f -#define VPE_EDI_LUT0_SHIFT 0 -#define VPE_EDI_LUT1_MASK 0x1f -#define VPE_EDI_LUT1_SHIFT 8 -#define VPE_EDI_LUT2_MASK 0x1f -#define VPE_EDI_LUT2_SHIFT 16 -#define VPE_EDI_LUT3_MASK 0x1f -#define VPE_EDI_LUT3_SHIFT 24 - -#define VPE_DEI_EDI_LUT_R2 0x0618 -#define VPE_EDI_LUT4_MASK 0x1f -#define VPE_EDI_LUT4_SHIFT 0 -#define VPE_EDI_LUT5_MASK 0x1f -#define VPE_EDI_LUT5_SHIFT 8 -#define VPE_EDI_LUT6_MASK 0x1f -#define VPE_EDI_LUT6_SHIFT 16 -#define VPE_EDI_LUT7_MASK 0x1f -#define VPE_EDI_LUT7_SHIFT 24 - -#define VPE_DEI_EDI_LUT_R3 0x061c -#define VPE_EDI_LUT8_MASK 0x1f -#define VPE_EDI_LUT8_SHIFT 0 -#define VPE_EDI_LUT9_MASK 0x1f -#define VPE_EDI_LUT9_SHIFT 8 -#define VPE_EDI_LUT10_MASK 0x1f -#define VPE_EDI_LUT10_SHIFT 16 -#define VPE_EDI_LUT11_MASK 0x1f -#define VPE_EDI_LUT11_SHIFT 24 - -#define VPE_DEI_FMD_WINDOW_R0 0x0620 -#define VPE_FMD_WINDOW_MINX_MASK 0x07ff -#define VPE_FMD_WINDOW_MINX_SHIFT 0 -#define VPE_FMD_WINDOW_MAXX_MASK 0x07ff -#define VPE_FMD_WINDOW_MAXX_SHIFT 16 -#define VPE_FMD_WINDOW_ENABLE BIT(31) - -#define VPE_DEI_FMD_WINDOW_R1 0x0624 -#define VPE_FMD_WINDOW_MINY_MASK 0x07ff -#define VPE_FMD_WINDOW_MINY_SHIFT 0 -#define VPE_FMD_WINDOW_MAXY_MASK 0x07ff -#define VPE_FMD_WINDOW_MAXY_SHIFT 16 - -#define VPE_DEI_FMD_CONTROL_R0 0x0628 -#define VPE_FMD_ENABLE BIT(0) -#define VPE_FMD_LOCK BIT(1) -#define VPE_FMD_JAM_DIR BIT(2) -#define VPE_FMD_BED_ENABLE BIT(3) -#define VPE_FMD_CAF_FIELD_THR_MASK 0xff -#define VPE_FMD_CAF_FIELD_THR_SHIFT 16 -#define VPE_FMD_CAF_LINE_THR_MASK 0xff -#define VPE_FMD_CAF_LINE_THR_SHIFT 24 - -#define VPE_DEI_FMD_CONTROL_R1 0x062c -#define VPE_FMD_CAF_THR_MASK 0x000fffff -#define VPE_FMD_CAF_THR_SHIFT 0 - -#define VPE_DEI_FMD_STATUS_R0 0x0630 -#define VPE_FMD_CAF_MASK 0x000fffff -#define VPE_FMD_CAF_SHIFT 0 -#define VPE_FMD_RESET BIT(24) - -#define VPE_DEI_FMD_STATUS_R1 0x0634 -#define VPE_FMD_FIELD_DIFF_MASK 0x0fffffff -#define VPE_FMD_FIELD_DIFF_SHIFT 0 - -#define VPE_DEI_FMD_STATUS_R2 0x0638 -#define VPE_FMD_FRAME_DIFF_MASK 0x000fffff -#define VPE_FMD_FRAME_DIFF_SHIFT 0 - -#endif diff --git a/drivers/media/platform/ti/Makefile b/drivers/media/platform/ti/Makefile new file mode 100644 index 000000000000..bbc737ccbbea --- /dev/null +++ b/drivers/media/platform/ti/Makefile @@ -0,0 +1,3 @@ +# SPDX-License-Identifier: GPL-2.0 +obj-y += cal/ +obj-y += vpe/ diff --git a/drivers/media/platform/ti/cal/Makefile b/drivers/media/platform/ti/cal/Makefile new file mode 100644 index 000000000000..45ac35585f0b --- /dev/null +++ b/drivers/media/platform/ti/cal/Makefile @@ -0,0 +1,3 @@ +# SPDX-License-Identifier: GPL-2.0 +obj-$(CONFIG_VIDEO_TI_CAL) += ti-cal.o +ti-cal-y := cal.o cal-camerarx.o cal-video.o diff --git a/drivers/media/platform/ti/cal/cal-camerarx.c b/drivers/media/platform/ti/cal/cal-camerarx.c new file mode 100644 index 000000000000..6b43a1525b45 --- /dev/null +++ b/drivers/media/platform/ti/cal/cal-camerarx.c @@ -0,0 +1,915 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * TI Camera Access Layer (CAL) - CAMERARX + * + * Copyright (c) 2015-2020 Texas Instruments Inc. + * + * Authors: + * Benoit Parrot + * Laurent Pinchart + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "cal.h" +#include "cal_regs.h" + +/* ------------------------------------------------------------------ + * I/O Register Accessors + * ------------------------------------------------------------------ + */ + +static inline u32 camerarx_read(struct cal_camerarx *phy, u32 offset) +{ + return ioread32(phy->base + offset); +} + +static inline void camerarx_write(struct cal_camerarx *phy, u32 offset, u32 val) +{ + iowrite32(val, phy->base + offset); +} + +/* ------------------------------------------------------------------ + * CAMERARX Management + * ------------------------------------------------------------------ + */ + +static s64 cal_camerarx_get_ext_link_freq(struct cal_camerarx *phy) +{ + struct v4l2_mbus_config_mipi_csi2 *mipi_csi2 = &phy->endpoint.bus.mipi_csi2; + u32 num_lanes = mipi_csi2->num_data_lanes; + const struct cal_format_info *fmtinfo; + u32 bpp; + s64 freq; + + fmtinfo = cal_format_by_code(phy->formats[CAL_CAMERARX_PAD_SINK].code); + if (!fmtinfo) + return -EINVAL; + + bpp = fmtinfo->bpp; + + freq = v4l2_get_link_freq(phy->source->ctrl_handler, bpp, 2 * num_lanes); + if (freq < 0) { + phy_err(phy, "failed to get link freq for subdev '%s'\n", + phy->source->name); + return freq; + } + + phy_dbg(3, phy, "Source Link Freq: %llu\n", freq); + + return freq; +} + +static void cal_camerarx_lane_config(struct cal_camerarx *phy) +{ + u32 val = cal_read(phy->cal, CAL_CSI2_COMPLEXIO_CFG(phy->instance)); + u32 lane_mask = CAL_CSI2_COMPLEXIO_CFG_CLOCK_POSITION_MASK; + u32 polarity_mask = CAL_CSI2_COMPLEXIO_CFG_CLOCK_POL_MASK; + struct v4l2_mbus_config_mipi_csi2 *mipi_csi2 = + &phy->endpoint.bus.mipi_csi2; + int lane; + + cal_set_field(&val, mipi_csi2->clock_lane + 1, lane_mask); + cal_set_field(&val, mipi_csi2->lane_polarities[0], polarity_mask); + for (lane = 0; lane < mipi_csi2->num_data_lanes; lane++) { + /* + * Every lane are one nibble apart starting with the + * clock followed by the data lanes so shift masks by 4. + */ + lane_mask <<= 4; + polarity_mask <<= 4; + cal_set_field(&val, mipi_csi2->data_lanes[lane] + 1, lane_mask); + cal_set_field(&val, mipi_csi2->lane_polarities[lane + 1], + polarity_mask); + } + + cal_write(phy->cal, CAL_CSI2_COMPLEXIO_CFG(phy->instance), val); + phy_dbg(3, phy, "CAL_CSI2_COMPLEXIO_CFG(%d) = 0x%08x\n", + phy->instance, val); +} + +static void cal_camerarx_enable(struct cal_camerarx *phy) +{ + u32 num_lanes = phy->cal->data->camerarx[phy->instance].num_lanes; + + regmap_field_write(phy->fields[F_CAMMODE], 0); + /* Always enable all lanes at the phy control level */ + regmap_field_write(phy->fields[F_LANEENABLE], (1 << num_lanes) - 1); + /* F_CSI_MODE is not present on every architecture */ + if (phy->fields[F_CSI_MODE]) + regmap_field_write(phy->fields[F_CSI_MODE], 1); + regmap_field_write(phy->fields[F_CTRLCLKEN], 1); +} + +void cal_camerarx_disable(struct cal_camerarx *phy) +{ + regmap_field_write(phy->fields[F_CTRLCLKEN], 0); +} + +/* + * TCLK values are OK at their reset values + */ +#define TCLK_TERM 0 +#define TCLK_MISS 1 +#define TCLK_SETTLE 14 + +static void cal_camerarx_config(struct cal_camerarx *phy, s64 link_freq) +{ + unsigned int reg0, reg1; + unsigned int ths_term, ths_settle; + + /* DPHY timing configuration */ + + /* THS_TERM: Programmed value = floor(20 ns/DDRClk period) */ + ths_term = div_s64(20 * link_freq, 1000 * 1000 * 1000); + phy_dbg(1, phy, "ths_term: %d (0x%02x)\n", ths_term, ths_term); + + /* THS_SETTLE: Programmed value = floor(105 ns/DDRClk period) + 4 */ + ths_settle = div_s64(105 * link_freq, 1000 * 1000 * 1000) + 4; + phy_dbg(1, phy, "ths_settle: %d (0x%02x)\n", ths_settle, ths_settle); + + reg0 = camerarx_read(phy, CAL_CSI2_PHY_REG0); + cal_set_field(®0, CAL_CSI2_PHY_REG0_HSCLOCKCONFIG_DISABLE, + CAL_CSI2_PHY_REG0_HSCLOCKCONFIG_MASK); + cal_set_field(®0, ths_term, CAL_CSI2_PHY_REG0_THS_TERM_MASK); + cal_set_field(®0, ths_settle, CAL_CSI2_PHY_REG0_THS_SETTLE_MASK); + + phy_dbg(1, phy, "CSI2_%d_REG0 = 0x%08x\n", phy->instance, reg0); + camerarx_write(phy, CAL_CSI2_PHY_REG0, reg0); + + reg1 = camerarx_read(phy, CAL_CSI2_PHY_REG1); + cal_set_field(®1, TCLK_TERM, CAL_CSI2_PHY_REG1_TCLK_TERM_MASK); + cal_set_field(®1, 0xb8, CAL_CSI2_PHY_REG1_DPHY_HS_SYNC_PATTERN_MASK); + cal_set_field(®1, TCLK_MISS, + CAL_CSI2_PHY_REG1_CTRLCLK_DIV_FACTOR_MASK); + cal_set_field(®1, TCLK_SETTLE, CAL_CSI2_PHY_REG1_TCLK_SETTLE_MASK); + + phy_dbg(1, phy, "CSI2_%d_REG1 = 0x%08x\n", phy->instance, reg1); + camerarx_write(phy, CAL_CSI2_PHY_REG1, reg1); +} + +static void cal_camerarx_power(struct cal_camerarx *phy, bool enable) +{ + u32 target_state; + unsigned int i; + + target_state = enable ? CAL_CSI2_COMPLEXIO_CFG_PWR_CMD_STATE_ON : + CAL_CSI2_COMPLEXIO_CFG_PWR_CMD_STATE_OFF; + + cal_write_field(phy->cal, CAL_CSI2_COMPLEXIO_CFG(phy->instance), + target_state, CAL_CSI2_COMPLEXIO_CFG_PWR_CMD_MASK); + + for (i = 0; i < 10; i++) { + u32 current_state; + + current_state = cal_read_field(phy->cal, + CAL_CSI2_COMPLEXIO_CFG(phy->instance), + CAL_CSI2_COMPLEXIO_CFG_PWR_STATUS_MASK); + + if (current_state == target_state) + break; + + usleep_range(1000, 1100); + } + + if (i == 10) + phy_err(phy, "Failed to power %s complexio\n", + enable ? "up" : "down"); +} + +static void cal_camerarx_wait_reset(struct cal_camerarx *phy) +{ + unsigned long timeout; + + timeout = jiffies + msecs_to_jiffies(750); + while (time_before(jiffies, timeout)) { + if (cal_read_field(phy->cal, + CAL_CSI2_COMPLEXIO_CFG(phy->instance), + CAL_CSI2_COMPLEXIO_CFG_RESET_DONE_MASK) == + CAL_CSI2_COMPLEXIO_CFG_RESET_DONE_RESETCOMPLETED) + break; + usleep_range(500, 5000); + } + + if (cal_read_field(phy->cal, CAL_CSI2_COMPLEXIO_CFG(phy->instance), + CAL_CSI2_COMPLEXIO_CFG_RESET_DONE_MASK) != + CAL_CSI2_COMPLEXIO_CFG_RESET_DONE_RESETCOMPLETED) + phy_err(phy, "Timeout waiting for Complex IO reset done\n"); +} + +static void cal_camerarx_wait_stop_state(struct cal_camerarx *phy) +{ + unsigned long timeout; + + timeout = jiffies + msecs_to_jiffies(750); + while (time_before(jiffies, timeout)) { + if (cal_read_field(phy->cal, + CAL_CSI2_TIMING(phy->instance), + CAL_CSI2_TIMING_FORCE_RX_MODE_IO1_MASK) == 0) + break; + usleep_range(500, 5000); + } + + if (cal_read_field(phy->cal, CAL_CSI2_TIMING(phy->instance), + CAL_CSI2_TIMING_FORCE_RX_MODE_IO1_MASK) != 0) + phy_err(phy, "Timeout waiting for stop state\n"); +} + +static void cal_camerarx_enable_irqs(struct cal_camerarx *phy) +{ + const u32 cio_err_mask = + CAL_CSI2_COMPLEXIO_IRQ_LANE_ERRORS_MASK | + CAL_CSI2_COMPLEXIO_IRQ_FIFO_OVR_MASK | + CAL_CSI2_COMPLEXIO_IRQ_SHORT_PACKET_MASK | + CAL_CSI2_COMPLEXIO_IRQ_ECC_NO_CORRECTION_MASK; + const u32 vc_err_mask = + CAL_CSI2_VC_IRQ_CS_IRQ_MASK(0) | + CAL_CSI2_VC_IRQ_CS_IRQ_MASK(1) | + CAL_CSI2_VC_IRQ_CS_IRQ_MASK(2) | + CAL_CSI2_VC_IRQ_CS_IRQ_MASK(3) | + CAL_CSI2_VC_IRQ_ECC_CORRECTION_IRQ_MASK(0) | + CAL_CSI2_VC_IRQ_ECC_CORRECTION_IRQ_MASK(1) | + CAL_CSI2_VC_IRQ_ECC_CORRECTION_IRQ_MASK(2) | + CAL_CSI2_VC_IRQ_ECC_CORRECTION_IRQ_MASK(3); + + /* Enable CIO & VC error IRQs. */ + cal_write(phy->cal, CAL_HL_IRQENABLE_SET(0), + CAL_HL_IRQ_CIO_MASK(phy->instance) | + CAL_HL_IRQ_VC_MASK(phy->instance)); + cal_write(phy->cal, CAL_CSI2_COMPLEXIO_IRQENABLE(phy->instance), + cio_err_mask); + cal_write(phy->cal, CAL_CSI2_VC_IRQENABLE(phy->instance), + vc_err_mask); +} + +static void cal_camerarx_disable_irqs(struct cal_camerarx *phy) +{ + /* Disable CIO error irqs */ + cal_write(phy->cal, CAL_HL_IRQENABLE_CLR(0), + CAL_HL_IRQ_CIO_MASK(phy->instance) | + CAL_HL_IRQ_VC_MASK(phy->instance)); + cal_write(phy->cal, CAL_CSI2_COMPLEXIO_IRQENABLE(phy->instance), 0); + cal_write(phy->cal, CAL_CSI2_VC_IRQENABLE(phy->instance), 0); +} + +static void cal_camerarx_ppi_enable(struct cal_camerarx *phy) +{ + cal_write_field(phy->cal, CAL_CSI2_PPI_CTRL(phy->instance), + 1, CAL_CSI2_PPI_CTRL_ECC_EN_MASK); + + cal_write_field(phy->cal, CAL_CSI2_PPI_CTRL(phy->instance), + 1, CAL_CSI2_PPI_CTRL_IF_EN_MASK); +} + +static void cal_camerarx_ppi_disable(struct cal_camerarx *phy) +{ + cal_write_field(phy->cal, CAL_CSI2_PPI_CTRL(phy->instance), + 0, CAL_CSI2_PPI_CTRL_IF_EN_MASK); +} + +static int cal_camerarx_start(struct cal_camerarx *phy) +{ + s64 link_freq; + u32 sscounter; + u32 val; + int ret; + + if (phy->enable_count > 0) { + phy->enable_count++; + return 0; + } + + link_freq = cal_camerarx_get_ext_link_freq(phy); + if (link_freq < 0) + return link_freq; + + ret = v4l2_subdev_call(phy->source, core, s_power, 1); + if (ret < 0 && ret != -ENOIOCTLCMD && ret != -ENODEV) { + phy_err(phy, "power on failed in subdev\n"); + return ret; + } + + cal_camerarx_enable_irqs(phy); + + /* + * CSI-2 PHY Link Initialization Sequence, according to the DRA74xP / + * DRA75xP / DRA76xP / DRA77xP TRM. The DRA71x / DRA72x and the AM65x / + * DRA80xM TRMs have a a slightly simplified sequence. + */ + + /* + * 1. Configure all CSI-2 low level protocol registers to be ready to + * receive signals/data from the CSI-2 PHY. + * + * i.-v. Configure the lanes position and polarity. + */ + cal_camerarx_lane_config(phy); + + /* + * vi.-vii. Configure D-PHY mode, enable the required lanes and + * enable the CAMERARX clock. + */ + cal_camerarx_enable(phy); + + /* + * 2. CSI PHY and link initialization sequence. + * + * a. Deassert the CSI-2 PHY reset. Do not wait for reset completion + * at this point, as it requires the external source to send the + * CSI-2 HS clock. + */ + cal_write_field(phy->cal, CAL_CSI2_COMPLEXIO_CFG(phy->instance), + CAL_CSI2_COMPLEXIO_CFG_RESET_CTRL_OPERATIONAL, + CAL_CSI2_COMPLEXIO_CFG_RESET_CTRL_MASK); + phy_dbg(3, phy, "CAL_CSI2_COMPLEXIO_CFG(%d) = 0x%08x De-assert Complex IO Reset\n", + phy->instance, + cal_read(phy->cal, CAL_CSI2_COMPLEXIO_CFG(phy->instance))); + + /* Dummy read to allow SCP reset to complete. */ + camerarx_read(phy, CAL_CSI2_PHY_REG0); + + /* Program the PHY timing parameters. */ + cal_camerarx_config(phy, link_freq); + + /* + * b. Assert the FORCERXMODE signal. + * + * The stop-state-counter is based on fclk cycles, and we always use + * the x16 and x4 settings, so stop-state-timeout = + * fclk-cycle * 16 * 4 * counter. + * + * Stop-state-timeout must be more than 100us as per CSI-2 spec, so we + * calculate a timeout that's 100us (rounding up). + */ + sscounter = DIV_ROUND_UP(clk_get_rate(phy->cal->fclk), 10000 * 16 * 4); + + val = cal_read(phy->cal, CAL_CSI2_TIMING(phy->instance)); + cal_set_field(&val, 1, CAL_CSI2_TIMING_STOP_STATE_X16_IO1_MASK); + cal_set_field(&val, 1, CAL_CSI2_TIMING_STOP_STATE_X4_IO1_MASK); + cal_set_field(&val, sscounter, + CAL_CSI2_TIMING_STOP_STATE_COUNTER_IO1_MASK); + cal_write(phy->cal, CAL_CSI2_TIMING(phy->instance), val); + phy_dbg(3, phy, "CAL_CSI2_TIMING(%d) = 0x%08x Stop States\n", + phy->instance, + cal_read(phy->cal, CAL_CSI2_TIMING(phy->instance))); + + /* Assert the FORCERXMODE signal. */ + cal_write_field(phy->cal, CAL_CSI2_TIMING(phy->instance), + 1, CAL_CSI2_TIMING_FORCE_RX_MODE_IO1_MASK); + phy_dbg(3, phy, "CAL_CSI2_TIMING(%d) = 0x%08x Force RXMODE\n", + phy->instance, + cal_read(phy->cal, CAL_CSI2_TIMING(phy->instance))); + + /* + * c. Connect pull-down on CSI-2 PHY link (using pad control). + * + * This is not required on DRA71x, DRA72x, AM65x and DRA80xM. Not + * implemented. + */ + + /* + * d. Power up the CSI-2 PHY. + * e. Check whether the state status reaches the ON state. + */ + cal_camerarx_power(phy, true); + + /* + * Start the source to enable the CSI-2 HS clock. We can now wait for + * CSI-2 PHY reset to complete. + */ + ret = v4l2_subdev_call(phy->source, video, s_stream, 1); + if (ret) { + v4l2_subdev_call(phy->source, core, s_power, 0); + cal_camerarx_disable_irqs(phy); + phy_err(phy, "stream on failed in subdev\n"); + return ret; + } + + cal_camerarx_wait_reset(phy); + + /* f. Wait for STOPSTATE=1 for all enabled lane modules. */ + cal_camerarx_wait_stop_state(phy); + + phy_dbg(1, phy, "CSI2_%u_REG1 = 0x%08x (bits 31-28 should be set)\n", + phy->instance, camerarx_read(phy, CAL_CSI2_PHY_REG1)); + + /* + * g. Disable pull-down on CSI-2 PHY link (using pad control). + * + * This is not required on DRA71x, DRA72x, AM65x and DRA80xM. Not + * implemented. + */ + + /* Finally, enable the PHY Protocol Interface (PPI). */ + cal_camerarx_ppi_enable(phy); + + phy->enable_count++; + + return 0; +} + +static void cal_camerarx_stop(struct cal_camerarx *phy) +{ + int ret; + + if (--phy->enable_count > 0) + return; + + cal_camerarx_ppi_disable(phy); + + cal_camerarx_disable_irqs(phy); + + cal_camerarx_power(phy, false); + + /* Assert Complex IO Reset */ + cal_write_field(phy->cal, CAL_CSI2_COMPLEXIO_CFG(phy->instance), + CAL_CSI2_COMPLEXIO_CFG_RESET_CTRL, + CAL_CSI2_COMPLEXIO_CFG_RESET_CTRL_MASK); + + phy_dbg(3, phy, "CAL_CSI2_COMPLEXIO_CFG(%d) = 0x%08x Complex IO in Reset\n", + phy->instance, + cal_read(phy->cal, CAL_CSI2_COMPLEXIO_CFG(phy->instance))); + + /* Disable the phy */ + cal_camerarx_disable(phy); + + if (v4l2_subdev_call(phy->source, video, s_stream, 0)) + phy_err(phy, "stream off failed in subdev\n"); + + ret = v4l2_subdev_call(phy->source, core, s_power, 0); + if (ret < 0 && ret != -ENOIOCTLCMD && ret != -ENODEV) + phy_err(phy, "power off failed in subdev\n"); +} + +/* + * Errata i913: CSI2 LDO Needs to be disabled when module is powered on + * + * Enabling CSI2 LDO shorts it to core supply. It is crucial the 2 CSI2 + * LDOs on the device are disabled if CSI-2 module is powered on + * (0x4845 B304 | 0x4845 B384 [28:27] = 0x1) or in ULPS (0x4845 B304 + * | 0x4845 B384 [28:27] = 0x2) mode. Common concerns include: high + * current draw on the module supply in active mode. + * + * Errata does not apply when CSI-2 module is powered off + * (0x4845 B304 | 0x4845 B384 [28:27] = 0x0). + * + * SW Workaround: + * Set the following register bits to disable the LDO, + * which is essentially CSI2 REG10 bit 6: + * + * Core 0: 0x4845 B828 = 0x0000 0040 + * Core 1: 0x4845 B928 = 0x0000 0040 + */ +void cal_camerarx_i913_errata(struct cal_camerarx *phy) +{ + u32 reg10 = camerarx_read(phy, CAL_CSI2_PHY_REG10); + + cal_set_field(®10, 1, CAL_CSI2_PHY_REG10_I933_LDO_DISABLE_MASK); + + phy_dbg(1, phy, "CSI2_%d_REG10 = 0x%08x\n", phy->instance, reg10); + camerarx_write(phy, CAL_CSI2_PHY_REG10, reg10); +} + +static int cal_camerarx_regmap_init(struct cal_dev *cal, + struct cal_camerarx *phy) +{ + const struct cal_camerarx_data *phy_data; + unsigned int i; + + if (!cal->data) + return -EINVAL; + + phy_data = &cal->data->camerarx[phy->instance]; + + for (i = 0; i < F_MAX_FIELDS; i++) { + struct reg_field field = { + .reg = cal->syscon_camerrx_offset, + .lsb = phy_data->fields[i].lsb, + .msb = phy_data->fields[i].msb, + }; + + /* + * Here we update the reg offset with the + * value found in DT + */ + phy->fields[i] = devm_regmap_field_alloc(cal->dev, + cal->syscon_camerrx, + field); + if (IS_ERR(phy->fields[i])) { + cal_err(cal, "Unable to allocate regmap fields\n"); + return PTR_ERR(phy->fields[i]); + } + } + + return 0; +} + +static int cal_camerarx_parse_dt(struct cal_camerarx *phy) +{ + struct v4l2_fwnode_endpoint *endpoint = &phy->endpoint; + char data_lanes[V4L2_MBUS_CSI2_MAX_DATA_LANES * 2]; + struct device_node *ep_node; + unsigned int i; + int ret; + + /* + * Find the endpoint node for the port corresponding to the PHY + * instance, and parse its CSI-2-related properties. + */ + ep_node = of_graph_get_endpoint_by_regs(phy->cal->dev->of_node, + phy->instance, 0); + if (!ep_node) { + /* + * The endpoint is not mandatory, not all PHY instances need to + * be connected in DT. + */ + phy_dbg(3, phy, "Port has no endpoint\n"); + return 0; + } + + endpoint->bus_type = V4L2_MBUS_CSI2_DPHY; + ret = v4l2_fwnode_endpoint_parse(of_fwnode_handle(ep_node), endpoint); + if (ret < 0) { + phy_err(phy, "Failed to parse endpoint\n"); + goto done; + } + + for (i = 0; i < endpoint->bus.mipi_csi2.num_data_lanes; i++) { + unsigned int lane = endpoint->bus.mipi_csi2.data_lanes[i]; + + if (lane > 4) { + phy_err(phy, "Invalid position %u for data lane %u\n", + lane, i); + ret = -EINVAL; + goto done; + } + + data_lanes[i*2] = '0' + lane; + data_lanes[i*2+1] = ' '; + } + + data_lanes[i*2-1] = '\0'; + + phy_dbg(3, phy, + "CSI-2 bus: clock lane <%u>, data lanes <%s>, flags 0x%08x\n", + endpoint->bus.mipi_csi2.clock_lane, data_lanes, + endpoint->bus.mipi_csi2.flags); + + /* Retrieve the connected device and store it for later use. */ + phy->source_ep_node = of_graph_get_remote_endpoint(ep_node); + phy->source_node = of_graph_get_port_parent(phy->source_ep_node); + if (!phy->source_node) { + phy_dbg(3, phy, "Can't get remote parent\n"); + of_node_put(phy->source_ep_node); + ret = -EINVAL; + goto done; + } + + phy_dbg(1, phy, "Found connected device %pOFn\n", phy->source_node); + +done: + of_node_put(ep_node); + return ret; +} + +/* ------------------------------------------------------------------ + * V4L2 Subdev Operations + * ------------------------------------------------------------------ + */ + +static inline struct cal_camerarx *to_cal_camerarx(struct v4l2_subdev *sd) +{ + return container_of(sd, struct cal_camerarx, subdev); +} + +static struct v4l2_mbus_framefmt * +cal_camerarx_get_pad_format(struct cal_camerarx *phy, + struct v4l2_subdev_state *sd_state, + unsigned int pad, u32 which) +{ + switch (which) { + case V4L2_SUBDEV_FORMAT_TRY: + return v4l2_subdev_get_try_format(&phy->subdev, sd_state, pad); + case V4L2_SUBDEV_FORMAT_ACTIVE: + return &phy->formats[pad]; + default: + return NULL; + } +} + +static int cal_camerarx_sd_s_stream(struct v4l2_subdev *sd, int enable) +{ + struct cal_camerarx *phy = to_cal_camerarx(sd); + int ret = 0; + + mutex_lock(&phy->mutex); + + if (enable) + ret = cal_camerarx_start(phy); + else + cal_camerarx_stop(phy); + + mutex_unlock(&phy->mutex); + + return ret; +} + +static int cal_camerarx_sd_enum_mbus_code(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state, + struct v4l2_subdev_mbus_code_enum *code) +{ + struct cal_camerarx *phy = to_cal_camerarx(sd); + int ret = 0; + + mutex_lock(&phy->mutex); + + /* No transcoding, source and sink codes must match. */ + if (cal_rx_pad_is_source(code->pad)) { + struct v4l2_mbus_framefmt *fmt; + + if (code->index > 0) { + ret = -EINVAL; + goto out; + } + + fmt = cal_camerarx_get_pad_format(phy, sd_state, + CAL_CAMERARX_PAD_SINK, + code->which); + code->code = fmt->code; + } else { + if (code->index >= cal_num_formats) { + ret = -EINVAL; + goto out; + } + + code->code = cal_formats[code->index].code; + } + +out: + mutex_unlock(&phy->mutex); + + return ret; +} + +static int cal_camerarx_sd_enum_frame_size(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state, + struct v4l2_subdev_frame_size_enum *fse) +{ + struct cal_camerarx *phy = to_cal_camerarx(sd); + const struct cal_format_info *fmtinfo; + int ret = 0; + + if (fse->index > 0) + return -EINVAL; + + mutex_lock(&phy->mutex); + + /* No transcoding, source and sink formats must match. */ + if (cal_rx_pad_is_source(fse->pad)) { + struct v4l2_mbus_framefmt *fmt; + + fmt = cal_camerarx_get_pad_format(phy, sd_state, + CAL_CAMERARX_PAD_SINK, + fse->which); + if (fse->code != fmt->code) { + ret = -EINVAL; + goto out; + } + + fse->min_width = fmt->width; + fse->max_width = fmt->width; + fse->min_height = fmt->height; + fse->max_height = fmt->height; + } else { + fmtinfo = cal_format_by_code(fse->code); + if (!fmtinfo) { + ret = -EINVAL; + goto out; + } + + fse->min_width = CAL_MIN_WIDTH_BYTES * 8 / ALIGN(fmtinfo->bpp, 8); + fse->max_width = CAL_MAX_WIDTH_BYTES * 8 / ALIGN(fmtinfo->bpp, 8); + fse->min_height = CAL_MIN_HEIGHT_LINES; + fse->max_height = CAL_MAX_HEIGHT_LINES; + } + +out: + mutex_unlock(&phy->mutex); + + return ret; +} + +static int cal_camerarx_sd_get_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state, + struct v4l2_subdev_format *format) +{ + struct cal_camerarx *phy = to_cal_camerarx(sd); + struct v4l2_mbus_framefmt *fmt; + + mutex_lock(&phy->mutex); + + fmt = cal_camerarx_get_pad_format(phy, sd_state, format->pad, + format->which); + format->format = *fmt; + + mutex_unlock(&phy->mutex); + + return 0; +} + +static int cal_camerarx_sd_set_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state, + struct v4l2_subdev_format *format) +{ + struct cal_camerarx *phy = to_cal_camerarx(sd); + const struct cal_format_info *fmtinfo; + struct v4l2_mbus_framefmt *fmt; + unsigned int bpp; + + /* No transcoding, source and sink formats must match. */ + if (cal_rx_pad_is_source(format->pad)) + return cal_camerarx_sd_get_fmt(sd, sd_state, format); + + /* + * Default to the first format if the requested media bus code isn't + * supported. + */ + fmtinfo = cal_format_by_code(format->format.code); + if (!fmtinfo) + fmtinfo = &cal_formats[0]; + + /* Clamp the size, update the code. The colorspace is accepted as-is. */ + bpp = ALIGN(fmtinfo->bpp, 8); + + format->format.width = clamp_t(unsigned int, format->format.width, + CAL_MIN_WIDTH_BYTES * 8 / bpp, + CAL_MAX_WIDTH_BYTES * 8 / bpp); + format->format.height = clamp_t(unsigned int, format->format.height, + CAL_MIN_HEIGHT_LINES, + CAL_MAX_HEIGHT_LINES); + format->format.code = fmtinfo->code; + format->format.field = V4L2_FIELD_NONE; + + /* Store the format and propagate it to the source pad. */ + + mutex_lock(&phy->mutex); + + fmt = cal_camerarx_get_pad_format(phy, sd_state, + CAL_CAMERARX_PAD_SINK, + format->which); + *fmt = format->format; + + fmt = cal_camerarx_get_pad_format(phy, sd_state, + CAL_CAMERARX_PAD_FIRST_SOURCE, + format->which); + *fmt = format->format; + + mutex_unlock(&phy->mutex); + + return 0; +} + +static int cal_camerarx_sd_init_cfg(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state) +{ + struct v4l2_subdev_format format = { + .which = sd_state ? V4L2_SUBDEV_FORMAT_TRY + : V4L2_SUBDEV_FORMAT_ACTIVE, + .pad = CAL_CAMERARX_PAD_SINK, + .format = { + .width = 640, + .height = 480, + .code = MEDIA_BUS_FMT_UYVY8_2X8, + .field = V4L2_FIELD_NONE, + .colorspace = V4L2_COLORSPACE_SRGB, + .ycbcr_enc = V4L2_YCBCR_ENC_601, + .quantization = V4L2_QUANTIZATION_LIM_RANGE, + .xfer_func = V4L2_XFER_FUNC_SRGB, + }, + }; + + return cal_camerarx_sd_set_fmt(sd, sd_state, &format); +} + +static const struct v4l2_subdev_video_ops cal_camerarx_video_ops = { + .s_stream = cal_camerarx_sd_s_stream, +}; + +static const struct v4l2_subdev_pad_ops cal_camerarx_pad_ops = { + .init_cfg = cal_camerarx_sd_init_cfg, + .enum_mbus_code = cal_camerarx_sd_enum_mbus_code, + .enum_frame_size = cal_camerarx_sd_enum_frame_size, + .get_fmt = cal_camerarx_sd_get_fmt, + .set_fmt = cal_camerarx_sd_set_fmt, +}; + +static const struct v4l2_subdev_ops cal_camerarx_subdev_ops = { + .video = &cal_camerarx_video_ops, + .pad = &cal_camerarx_pad_ops, +}; + +static struct media_entity_operations cal_camerarx_media_ops = { + .link_validate = v4l2_subdev_link_validate, +}; + +/* ------------------------------------------------------------------ + * Create and Destroy + * ------------------------------------------------------------------ + */ + +struct cal_camerarx *cal_camerarx_create(struct cal_dev *cal, + unsigned int instance) +{ + struct platform_device *pdev = to_platform_device(cal->dev); + struct cal_camerarx *phy; + struct v4l2_subdev *sd; + unsigned int i; + int ret; + + phy = kzalloc(sizeof(*phy), GFP_KERNEL); + if (!phy) + return ERR_PTR(-ENOMEM); + + phy->cal = cal; + phy->instance = instance; + + mutex_init(&phy->mutex); + + phy->res = platform_get_resource_byname(pdev, IORESOURCE_MEM, + (instance == 0) ? + "cal_rx_core0" : + "cal_rx_core1"); + phy->base = devm_ioremap_resource(cal->dev, phy->res); + if (IS_ERR(phy->base)) { + cal_err(cal, "failed to ioremap\n"); + ret = PTR_ERR(phy->base); + goto error; + } + + cal_dbg(1, cal, "ioresource %s at %pa - %pa\n", + phy->res->name, &phy->res->start, &phy->res->end); + + ret = cal_camerarx_regmap_init(cal, phy); + if (ret) + goto error; + + ret = cal_camerarx_parse_dt(phy); + if (ret) + goto error; + + /* Initialize the V4L2 subdev and media entity. */ + sd = &phy->subdev; + v4l2_subdev_init(sd, &cal_camerarx_subdev_ops); + sd->entity.function = MEDIA_ENT_F_VID_IF_BRIDGE; + sd->flags = V4L2_SUBDEV_FL_HAS_DEVNODE; + snprintf(sd->name, sizeof(sd->name), "CAMERARX%u", instance); + sd->dev = cal->dev; + + phy->pads[CAL_CAMERARX_PAD_SINK].flags = MEDIA_PAD_FL_SINK; + for (i = CAL_CAMERARX_PAD_FIRST_SOURCE; i < CAL_CAMERARX_NUM_PADS; ++i) + phy->pads[i].flags = MEDIA_PAD_FL_SOURCE; + sd->entity.ops = &cal_camerarx_media_ops; + ret = media_entity_pads_init(&sd->entity, ARRAY_SIZE(phy->pads), + phy->pads); + if (ret) + goto error; + + ret = cal_camerarx_sd_init_cfg(sd, NULL); + if (ret) + goto error; + + ret = v4l2_device_register_subdev(&cal->v4l2_dev, sd); + if (ret) + goto error; + + return phy; + +error: + media_entity_cleanup(&phy->subdev.entity); + kfree(phy); + return ERR_PTR(ret); +} + +void cal_camerarx_destroy(struct cal_camerarx *phy) +{ + if (!phy) + return; + + v4l2_device_unregister_subdev(&phy->subdev); + media_entity_cleanup(&phy->subdev.entity); + of_node_put(phy->source_ep_node); + of_node_put(phy->source_node); + mutex_destroy(&phy->mutex); + kfree(phy); +} diff --git a/drivers/media/platform/ti/cal/cal-video.c b/drivers/media/platform/ti/cal/cal-video.c new file mode 100644 index 000000000000..3e936a2ca36c --- /dev/null +++ b/drivers/media/platform/ti/cal/cal-video.c @@ -0,0 +1,1049 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * TI Camera Access Layer (CAL) - Video Device + * + * Copyright (c) 2015-2020 Texas Instruments Inc. + * + * Authors: + * Benoit Parrot + * Laurent Pinchart + */ + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "cal.h" + +/* Print Four-character-code (FOURCC) */ +static char *fourcc_to_str(u32 fmt) +{ + static char code[5]; + + code[0] = (unsigned char)(fmt & 0xff); + code[1] = (unsigned char)((fmt >> 8) & 0xff); + code[2] = (unsigned char)((fmt >> 16) & 0xff); + code[3] = (unsigned char)((fmt >> 24) & 0xff); + code[4] = '\0'; + + return code; +} + +/* ------------------------------------------------------------------ + * V4L2 Common IOCTLs + * ------------------------------------------------------------------ + */ + +static int cal_querycap(struct file *file, void *priv, + struct v4l2_capability *cap) +{ + struct cal_ctx *ctx = video_drvdata(file); + + strscpy(cap->driver, CAL_MODULE_NAME, sizeof(cap->driver)); + strscpy(cap->card, CAL_MODULE_NAME, sizeof(cap->card)); + + snprintf(cap->bus_info, sizeof(cap->bus_info), + "platform:%s", dev_name(ctx->cal->dev)); + return 0; +} + +static int cal_g_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct cal_ctx *ctx = video_drvdata(file); + + *f = ctx->v_fmt; + + return 0; +} + +/* ------------------------------------------------------------------ + * V4L2 Video Node Centric IOCTLs + * ------------------------------------------------------------------ + */ + +static const struct cal_format_info *find_format_by_pix(struct cal_ctx *ctx, + u32 pixelformat) +{ + const struct cal_format_info *fmtinfo; + unsigned int k; + + for (k = 0; k < ctx->num_active_fmt; k++) { + fmtinfo = ctx->active_fmt[k]; + if (fmtinfo->fourcc == pixelformat) + return fmtinfo; + } + + return NULL; +} + +static const struct cal_format_info *find_format_by_code(struct cal_ctx *ctx, + u32 code) +{ + const struct cal_format_info *fmtinfo; + unsigned int k; + + for (k = 0; k < ctx->num_active_fmt; k++) { + fmtinfo = ctx->active_fmt[k]; + if (fmtinfo->code == code) + return fmtinfo; + } + + return NULL; +} + +static int cal_legacy_enum_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_fmtdesc *f) +{ + struct cal_ctx *ctx = video_drvdata(file); + const struct cal_format_info *fmtinfo; + + if (f->index >= ctx->num_active_fmt) + return -EINVAL; + + fmtinfo = ctx->active_fmt[f->index]; + + f->pixelformat = fmtinfo->fourcc; + f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + return 0; +} + +static int __subdev_get_format(struct cal_ctx *ctx, + struct v4l2_mbus_framefmt *fmt) +{ + struct v4l2_subdev_format sd_fmt; + struct v4l2_mbus_framefmt *mbus_fmt = &sd_fmt.format; + int ret; + + sd_fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE; + sd_fmt.pad = 0; + + ret = v4l2_subdev_call(ctx->phy->source, pad, get_fmt, NULL, &sd_fmt); + if (ret) + return ret; + + *fmt = *mbus_fmt; + + ctx_dbg(1, ctx, "%s %dx%d code:%04X\n", __func__, + fmt->width, fmt->height, fmt->code); + + return 0; +} + +static int __subdev_set_format(struct cal_ctx *ctx, + struct v4l2_mbus_framefmt *fmt) +{ + struct v4l2_subdev_format sd_fmt; + struct v4l2_mbus_framefmt *mbus_fmt = &sd_fmt.format; + int ret; + + sd_fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE; + sd_fmt.pad = 0; + *mbus_fmt = *fmt; + + ret = v4l2_subdev_call(ctx->phy->source, pad, set_fmt, NULL, &sd_fmt); + if (ret) + return ret; + + ctx_dbg(1, ctx, "%s %dx%d code:%04X\n", __func__, + fmt->width, fmt->height, fmt->code); + + return 0; +} + +static void cal_calc_format_size(struct cal_ctx *ctx, + const struct cal_format_info *fmtinfo, + struct v4l2_format *f) +{ + u32 bpl, max_width; + + /* + * Maximum width is bound by the DMA max width in bytes. + * We need to recalculate the actual maxi width depending on the + * number of bytes per pixels required. + */ + max_width = CAL_MAX_WIDTH_BYTES / (ALIGN(fmtinfo->bpp, 8) >> 3); + v4l_bound_align_image(&f->fmt.pix.width, 48, max_width, 2, + &f->fmt.pix.height, 32, CAL_MAX_HEIGHT_LINES, + 0, 0); + + bpl = (f->fmt.pix.width * ALIGN(fmtinfo->bpp, 8)) >> 3; + f->fmt.pix.bytesperline = ALIGN(bpl, 16); + + f->fmt.pix.sizeimage = f->fmt.pix.height * + f->fmt.pix.bytesperline; + + ctx_dbg(3, ctx, "%s: fourcc: %s size: %dx%d bpl:%d img_size:%d\n", + __func__, fourcc_to_str(f->fmt.pix.pixelformat), + f->fmt.pix.width, f->fmt.pix.height, + f->fmt.pix.bytesperline, f->fmt.pix.sizeimage); +} + +static int cal_legacy_try_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct cal_ctx *ctx = video_drvdata(file); + const struct cal_format_info *fmtinfo; + struct v4l2_subdev_frame_size_enum fse; + int ret, found; + + fmtinfo = find_format_by_pix(ctx, f->fmt.pix.pixelformat); + if (!fmtinfo) { + ctx_dbg(3, ctx, "Fourcc format (0x%08x) not found.\n", + f->fmt.pix.pixelformat); + + /* Just get the first one enumerated */ + fmtinfo = ctx->active_fmt[0]; + f->fmt.pix.pixelformat = fmtinfo->fourcc; + } + + f->fmt.pix.field = ctx->v_fmt.fmt.pix.field; + + /* check for/find a valid width/height */ + ret = 0; + found = false; + fse.pad = 0; + fse.code = fmtinfo->code; + fse.which = V4L2_SUBDEV_FORMAT_ACTIVE; + for (fse.index = 0; ; fse.index++) { + ret = v4l2_subdev_call(ctx->phy->source, pad, enum_frame_size, + NULL, &fse); + if (ret) + break; + + if ((f->fmt.pix.width == fse.max_width) && + (f->fmt.pix.height == fse.max_height)) { + found = true; + break; + } else if ((f->fmt.pix.width >= fse.min_width) && + (f->fmt.pix.width <= fse.max_width) && + (f->fmt.pix.height >= fse.min_height) && + (f->fmt.pix.height <= fse.max_height)) { + found = true; + break; + } + } + + if (!found) { + /* use existing values as default */ + f->fmt.pix.width = ctx->v_fmt.fmt.pix.width; + f->fmt.pix.height = ctx->v_fmt.fmt.pix.height; + } + + /* + * Use current colorspace for now, it will get + * updated properly during s_fmt + */ + f->fmt.pix.colorspace = ctx->v_fmt.fmt.pix.colorspace; + cal_calc_format_size(ctx, fmtinfo, f); + return 0; +} + +static int cal_legacy_s_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct cal_ctx *ctx = video_drvdata(file); + struct vb2_queue *q = &ctx->vb_vidq; + struct v4l2_subdev_format sd_fmt = { + .which = V4L2_SUBDEV_FORMAT_ACTIVE, + .pad = CAL_CAMERARX_PAD_SINK, + }; + const struct cal_format_info *fmtinfo; + int ret; + + if (vb2_is_busy(q)) { + ctx_dbg(3, ctx, "%s device busy\n", __func__); + return -EBUSY; + } + + ret = cal_legacy_try_fmt_vid_cap(file, priv, f); + if (ret < 0) + return ret; + + fmtinfo = find_format_by_pix(ctx, f->fmt.pix.pixelformat); + + v4l2_fill_mbus_format(&sd_fmt.format, &f->fmt.pix, fmtinfo->code); + + ret = __subdev_set_format(ctx, &sd_fmt.format); + if (ret) + return ret; + + /* Just double check nothing has gone wrong */ + if (sd_fmt.format.code != fmtinfo->code) { + ctx_dbg(3, ctx, + "%s subdev changed format on us, this should not happen\n", + __func__); + return -EINVAL; + } + + v4l2_fill_pix_format(&ctx->v_fmt.fmt.pix, &sd_fmt.format); + ctx->v_fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + ctx->v_fmt.fmt.pix.pixelformat = fmtinfo->fourcc; + ctx->v_fmt.fmt.pix.field = sd_fmt.format.field; + cal_calc_format_size(ctx, fmtinfo, &ctx->v_fmt); + + v4l2_subdev_call(&ctx->phy->subdev, pad, set_fmt, NULL, &sd_fmt); + + ctx->fmtinfo = fmtinfo; + *f = ctx->v_fmt; + + return 0; +} + +static int cal_legacy_enum_framesizes(struct file *file, void *fh, + struct v4l2_frmsizeenum *fsize) +{ + struct cal_ctx *ctx = video_drvdata(file); + const struct cal_format_info *fmtinfo; + struct v4l2_subdev_frame_size_enum fse; + int ret; + + /* check for valid format */ + fmtinfo = find_format_by_pix(ctx, fsize->pixel_format); + if (!fmtinfo) { + ctx_dbg(3, ctx, "Invalid pixel code: %x\n", + fsize->pixel_format); + return -EINVAL; + } + + fse.index = fsize->index; + fse.pad = 0; + fse.code = fmtinfo->code; + fse.which = V4L2_SUBDEV_FORMAT_ACTIVE; + + ret = v4l2_subdev_call(ctx->phy->source, pad, enum_frame_size, NULL, + &fse); + if (ret) + return ret; + + ctx_dbg(1, ctx, "%s: index: %d code: %x W:[%d,%d] H:[%d,%d]\n", + __func__, fse.index, fse.code, fse.min_width, fse.max_width, + fse.min_height, fse.max_height); + + fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE; + fsize->discrete.width = fse.max_width; + fsize->discrete.height = fse.max_height; + + return 0; +} + +static int cal_legacy_enum_input(struct file *file, void *priv, + struct v4l2_input *inp) +{ + if (inp->index > 0) + return -EINVAL; + + inp->type = V4L2_INPUT_TYPE_CAMERA; + sprintf(inp->name, "Camera %u", inp->index); + return 0; +} + +static int cal_legacy_g_input(struct file *file, void *priv, unsigned int *i) +{ + *i = 0; + return 0; +} + +static int cal_legacy_s_input(struct file *file, void *priv, unsigned int i) +{ + return i > 0 ? -EINVAL : 0; +} + +/* timeperframe is arbitrary and continuous */ +static int cal_legacy_enum_frameintervals(struct file *file, void *priv, + struct v4l2_frmivalenum *fival) +{ + struct cal_ctx *ctx = video_drvdata(file); + const struct cal_format_info *fmtinfo; + struct v4l2_subdev_frame_interval_enum fie = { + .index = fival->index, + .width = fival->width, + .height = fival->height, + .which = V4L2_SUBDEV_FORMAT_ACTIVE, + }; + int ret; + + fmtinfo = find_format_by_pix(ctx, fival->pixel_format); + if (!fmtinfo) + return -EINVAL; + + fie.code = fmtinfo->code; + ret = v4l2_subdev_call(ctx->phy->source, pad, enum_frame_interval, + NULL, &fie); + if (ret) + return ret; + fival->type = V4L2_FRMIVAL_TYPE_DISCRETE; + fival->discrete = fie.interval; + + return 0; +} + +static int cal_legacy_g_parm(struct file *file, void *fh, struct v4l2_streamparm *a) +{ + struct cal_ctx *ctx = video_drvdata(file); + + return v4l2_g_parm_cap(video_devdata(file), ctx->phy->source, a); +} + +static int cal_legacy_s_parm(struct file *file, void *fh, struct v4l2_streamparm *a) +{ + struct cal_ctx *ctx = video_drvdata(file); + + return v4l2_s_parm_cap(video_devdata(file), ctx->phy->source, a); +} + +static const struct v4l2_ioctl_ops cal_ioctl_legacy_ops = { + .vidioc_querycap = cal_querycap, + .vidioc_enum_fmt_vid_cap = cal_legacy_enum_fmt_vid_cap, + .vidioc_g_fmt_vid_cap = cal_g_fmt_vid_cap, + .vidioc_try_fmt_vid_cap = cal_legacy_try_fmt_vid_cap, + .vidioc_s_fmt_vid_cap = cal_legacy_s_fmt_vid_cap, + .vidioc_enum_framesizes = cal_legacy_enum_framesizes, + .vidioc_reqbufs = vb2_ioctl_reqbufs, + .vidioc_create_bufs = vb2_ioctl_create_bufs, + .vidioc_prepare_buf = vb2_ioctl_prepare_buf, + .vidioc_querybuf = vb2_ioctl_querybuf, + .vidioc_qbuf = vb2_ioctl_qbuf, + .vidioc_dqbuf = vb2_ioctl_dqbuf, + .vidioc_expbuf = vb2_ioctl_expbuf, + .vidioc_enum_input = cal_legacy_enum_input, + .vidioc_g_input = cal_legacy_g_input, + .vidioc_s_input = cal_legacy_s_input, + .vidioc_enum_frameintervals = cal_legacy_enum_frameintervals, + .vidioc_streamon = vb2_ioctl_streamon, + .vidioc_streamoff = vb2_ioctl_streamoff, + .vidioc_log_status = v4l2_ctrl_log_status, + .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, + .vidioc_unsubscribe_event = v4l2_event_unsubscribe, + .vidioc_g_parm = cal_legacy_g_parm, + .vidioc_s_parm = cal_legacy_s_parm, +}; + +/* ------------------------------------------------------------------ + * V4L2 Media Controller Centric IOCTLs + * ------------------------------------------------------------------ + */ + +static int cal_mc_enum_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_fmtdesc *f) +{ + unsigned int i; + unsigned int idx; + + if (f->index >= cal_num_formats) + return -EINVAL; + + idx = 0; + + for (i = 0; i < cal_num_formats; ++i) { + if (f->mbus_code && cal_formats[i].code != f->mbus_code) + continue; + + if (idx == f->index) { + f->pixelformat = cal_formats[i].fourcc; + f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + return 0; + } + + idx++; + } + + return -EINVAL; +} + +static void cal_mc_try_fmt(struct cal_ctx *ctx, struct v4l2_format *f, + const struct cal_format_info **info) +{ + struct v4l2_pix_format *format = &f->fmt.pix; + const struct cal_format_info *fmtinfo; + unsigned int bpp; + + /* + * Default to the first format if the requested pixel format code isn't + * supported. + */ + fmtinfo = cal_format_by_fourcc(f->fmt.pix.pixelformat); + if (!fmtinfo) + fmtinfo = &cal_formats[0]; + + /* + * Clamp the size, update the pixel format. The field and colorspace are + * accepted as-is, except for V4L2_FIELD_ANY that is turned into + * V4L2_FIELD_NONE. + */ + bpp = ALIGN(fmtinfo->bpp, 8); + + format->width = clamp_t(unsigned int, format->width, + CAL_MIN_WIDTH_BYTES * 8 / bpp, + CAL_MAX_WIDTH_BYTES * 8 / bpp); + format->height = clamp_t(unsigned int, format->height, + CAL_MIN_HEIGHT_LINES, CAL_MAX_HEIGHT_LINES); + format->pixelformat = fmtinfo->fourcc; + + if (format->field == V4L2_FIELD_ANY) + format->field = V4L2_FIELD_NONE; + + /* + * Calculate the number of bytes per line and the image size. The + * hardware stores the stride as a number of 16 bytes words, in a + * signed 15-bit value. Only 14 bits are thus usable. + */ + format->bytesperline = ALIGN(clamp(format->bytesperline, + format->width * bpp / 8, + ((1U << 14) - 1) * 16), 16); + + format->sizeimage = format->height * format->bytesperline; + + format->colorspace = ctx->v_fmt.fmt.pix.colorspace; + + if (info) + *info = fmtinfo; + + ctx_dbg(3, ctx, "%s: %s %ux%u (bytesperline %u sizeimage %u)\n", + __func__, fourcc_to_str(format->pixelformat), + format->width, format->height, + format->bytesperline, format->sizeimage); +} + +static int cal_mc_try_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct cal_ctx *ctx = video_drvdata(file); + + cal_mc_try_fmt(ctx, f, NULL); + return 0; +} + +static int cal_mc_s_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct cal_ctx *ctx = video_drvdata(file); + const struct cal_format_info *fmtinfo; + + if (vb2_is_busy(&ctx->vb_vidq)) { + ctx_dbg(3, ctx, "%s device busy\n", __func__); + return -EBUSY; + } + + cal_mc_try_fmt(ctx, f, &fmtinfo); + + ctx->v_fmt = *f; + ctx->fmtinfo = fmtinfo; + + return 0; +} + +static int cal_mc_enum_framesizes(struct file *file, void *fh, + struct v4l2_frmsizeenum *fsize) +{ + struct cal_ctx *ctx = video_drvdata(file); + const struct cal_format_info *fmtinfo; + unsigned int bpp; + + if (fsize->index > 0) + return -EINVAL; + + fmtinfo = cal_format_by_fourcc(fsize->pixel_format); + if (!fmtinfo) { + ctx_dbg(3, ctx, "Invalid pixel format 0x%08x\n", + fsize->pixel_format); + return -EINVAL; + } + + bpp = ALIGN(fmtinfo->bpp, 8); + + fsize->type = V4L2_FRMSIZE_TYPE_STEPWISE; + fsize->stepwise.min_width = CAL_MIN_WIDTH_BYTES * 8 / bpp; + fsize->stepwise.max_width = CAL_MAX_WIDTH_BYTES * 8 / bpp; + fsize->stepwise.step_width = 64 / bpp; + fsize->stepwise.min_height = CAL_MIN_HEIGHT_LINES; + fsize->stepwise.max_height = CAL_MAX_HEIGHT_LINES; + fsize->stepwise.step_height = 1; + + return 0; +} + +static const struct v4l2_ioctl_ops cal_ioctl_mc_ops = { + .vidioc_querycap = cal_querycap, + .vidioc_enum_fmt_vid_cap = cal_mc_enum_fmt_vid_cap, + .vidioc_g_fmt_vid_cap = cal_g_fmt_vid_cap, + .vidioc_try_fmt_vid_cap = cal_mc_try_fmt_vid_cap, + .vidioc_s_fmt_vid_cap = cal_mc_s_fmt_vid_cap, + .vidioc_enum_framesizes = cal_mc_enum_framesizes, + .vidioc_reqbufs = vb2_ioctl_reqbufs, + .vidioc_create_bufs = vb2_ioctl_create_bufs, + .vidioc_prepare_buf = vb2_ioctl_prepare_buf, + .vidioc_querybuf = vb2_ioctl_querybuf, + .vidioc_qbuf = vb2_ioctl_qbuf, + .vidioc_dqbuf = vb2_ioctl_dqbuf, + .vidioc_expbuf = vb2_ioctl_expbuf, + .vidioc_streamon = vb2_ioctl_streamon, + .vidioc_streamoff = vb2_ioctl_streamoff, + .vidioc_log_status = v4l2_ctrl_log_status, +}; + +/* ------------------------------------------------------------------ + * videobuf2 Common Operations + * ------------------------------------------------------------------ + */ + +static int cal_queue_setup(struct vb2_queue *vq, + unsigned int *nbuffers, unsigned int *nplanes, + unsigned int sizes[], struct device *alloc_devs[]) +{ + struct cal_ctx *ctx = vb2_get_drv_priv(vq); + unsigned int size = ctx->v_fmt.fmt.pix.sizeimage; + + if (vq->num_buffers + *nbuffers < 3) + *nbuffers = 3 - vq->num_buffers; + + if (*nplanes) { + if (sizes[0] < size) + return -EINVAL; + size = sizes[0]; + } + + *nplanes = 1; + sizes[0] = size; + + ctx_dbg(3, ctx, "nbuffers=%d, size=%d\n", *nbuffers, sizes[0]); + + return 0; +} + +static int cal_buffer_prepare(struct vb2_buffer *vb) +{ + struct cal_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); + struct cal_buffer *buf = container_of(vb, struct cal_buffer, + vb.vb2_buf); + unsigned long size; + + size = ctx->v_fmt.fmt.pix.sizeimage; + if (vb2_plane_size(vb, 0) < size) { + ctx_err(ctx, + "data will not fit into plane (%lu < %lu)\n", + vb2_plane_size(vb, 0), size); + return -EINVAL; + } + + vb2_set_plane_payload(&buf->vb.vb2_buf, 0, size); + return 0; +} + +static void cal_buffer_queue(struct vb2_buffer *vb) +{ + struct cal_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); + struct cal_buffer *buf = container_of(vb, struct cal_buffer, + vb.vb2_buf); + unsigned long flags; + + /* recheck locking */ + spin_lock_irqsave(&ctx->dma.lock, flags); + list_add_tail(&buf->list, &ctx->dma.queue); + spin_unlock_irqrestore(&ctx->dma.lock, flags); +} + +static void cal_release_buffers(struct cal_ctx *ctx, + enum vb2_buffer_state state) +{ + struct cal_buffer *buf, *tmp; + + /* Release all queued buffers. */ + spin_lock_irq(&ctx->dma.lock); + + list_for_each_entry_safe(buf, tmp, &ctx->dma.queue, list) { + list_del(&buf->list); + vb2_buffer_done(&buf->vb.vb2_buf, state); + } + + if (ctx->dma.pending) { + vb2_buffer_done(&ctx->dma.pending->vb.vb2_buf, state); + ctx->dma.pending = NULL; + } + + if (ctx->dma.active) { + vb2_buffer_done(&ctx->dma.active->vb.vb2_buf, state); + ctx->dma.active = NULL; + } + + spin_unlock_irq(&ctx->dma.lock); +} + +/* ------------------------------------------------------------------ + * videobuf2 Operations + * ------------------------------------------------------------------ + */ + +static int cal_video_check_format(struct cal_ctx *ctx) +{ + const struct v4l2_mbus_framefmt *format; + struct media_pad *remote_pad; + + remote_pad = media_entity_remote_pad(&ctx->pad); + if (!remote_pad) + return -ENODEV; + + format = &ctx->phy->formats[remote_pad->index]; + + if (ctx->fmtinfo->code != format->code || + ctx->v_fmt.fmt.pix.height != format->height || + ctx->v_fmt.fmt.pix.width != format->width || + ctx->v_fmt.fmt.pix.field != format->field) + return -EPIPE; + + return 0; +} + +static int cal_start_streaming(struct vb2_queue *vq, unsigned int count) +{ + struct cal_ctx *ctx = vb2_get_drv_priv(vq); + struct cal_buffer *buf; + dma_addr_t addr; + int ret; + + ret = media_pipeline_start(&ctx->vdev.entity, &ctx->phy->pipe); + if (ret < 0) { + ctx_err(ctx, "Failed to start media pipeline: %d\n", ret); + goto error_release_buffers; + } + + /* + * Verify that the currently configured format matches the output of + * the connected CAMERARX. + */ + ret = cal_video_check_format(ctx); + if (ret < 0) { + ctx_dbg(3, ctx, + "Format mismatch between CAMERARX and video node\n"); + goto error_pipeline; + } + + ret = cal_ctx_prepare(ctx); + if (ret) { + ctx_err(ctx, "Failed to prepare context: %d\n", ret); + goto error_pipeline; + } + + spin_lock_irq(&ctx->dma.lock); + buf = list_first_entry(&ctx->dma.queue, struct cal_buffer, list); + ctx->dma.active = buf; + list_del(&buf->list); + spin_unlock_irq(&ctx->dma.lock); + + addr = vb2_dma_contig_plane_dma_addr(&buf->vb.vb2_buf, 0); + + ret = pm_runtime_resume_and_get(ctx->cal->dev); + if (ret < 0) + goto error_pipeline; + + cal_ctx_set_dma_addr(ctx, addr); + cal_ctx_start(ctx); + + ret = v4l2_subdev_call(&ctx->phy->subdev, video, s_stream, 1); + if (ret) + goto error_stop; + + if (cal_debug >= 4) + cal_quickdump_regs(ctx->cal); + + return 0; + +error_stop: + cal_ctx_stop(ctx); + pm_runtime_put_sync(ctx->cal->dev); + cal_ctx_unprepare(ctx); + +error_pipeline: + media_pipeline_stop(&ctx->vdev.entity); +error_release_buffers: + cal_release_buffers(ctx, VB2_BUF_STATE_QUEUED); + + return ret; +} + +static void cal_stop_streaming(struct vb2_queue *vq) +{ + struct cal_ctx *ctx = vb2_get_drv_priv(vq); + + cal_ctx_stop(ctx); + + v4l2_subdev_call(&ctx->phy->subdev, video, s_stream, 0); + + pm_runtime_put_sync(ctx->cal->dev); + + cal_ctx_unprepare(ctx); + + cal_release_buffers(ctx, VB2_BUF_STATE_ERROR); + + media_pipeline_stop(&ctx->vdev.entity); +} + +static const struct vb2_ops cal_video_qops = { + .queue_setup = cal_queue_setup, + .buf_prepare = cal_buffer_prepare, + .buf_queue = cal_buffer_queue, + .start_streaming = cal_start_streaming, + .stop_streaming = cal_stop_streaming, + .wait_prepare = vb2_ops_wait_prepare, + .wait_finish = vb2_ops_wait_finish, +}; + +/* ------------------------------------------------------------------ + * V4L2 Initialization and Registration + * ------------------------------------------------------------------ + */ + +static const struct v4l2_file_operations cal_fops = { + .owner = THIS_MODULE, + .open = v4l2_fh_open, + .release = vb2_fop_release, + .poll = vb2_fop_poll, + .unlocked_ioctl = video_ioctl2, /* V4L2 ioctl handler */ + .mmap = vb2_fop_mmap, +}; + +static int cal_ctx_v4l2_init_formats(struct cal_ctx *ctx) +{ + struct v4l2_subdev_mbus_code_enum mbus_code; + struct v4l2_mbus_framefmt mbus_fmt; + const struct cal_format_info *fmtinfo; + unsigned int i, j, k; + int ret = 0; + + /* Enumerate sub device formats and enable all matching local formats */ + ctx->active_fmt = devm_kcalloc(ctx->cal->dev, cal_num_formats, + sizeof(*ctx->active_fmt), GFP_KERNEL); + if (!ctx->active_fmt) + return -ENOMEM; + + ctx->num_active_fmt = 0; + + for (j = 0, i = 0; ; ++j) { + + memset(&mbus_code, 0, sizeof(mbus_code)); + mbus_code.index = j; + mbus_code.which = V4L2_SUBDEV_FORMAT_ACTIVE; + ret = v4l2_subdev_call(ctx->phy->source, pad, enum_mbus_code, + NULL, &mbus_code); + if (ret == -EINVAL) + break; + + if (ret) { + ctx_err(ctx, "Error enumerating mbus codes in subdev %s: %d\n", + ctx->phy->source->name, ret); + return ret; + } + + ctx_dbg(2, ctx, + "subdev %s: code: %04x idx: %u\n", + ctx->phy->source->name, mbus_code.code, j); + + for (k = 0; k < cal_num_formats; k++) { + fmtinfo = &cal_formats[k]; + + if (mbus_code.code == fmtinfo->code) { + ctx->active_fmt[i] = fmtinfo; + ctx_dbg(2, ctx, + "matched fourcc: %s: code: %04x idx: %u\n", + fourcc_to_str(fmtinfo->fourcc), + fmtinfo->code, i); + ctx->num_active_fmt = ++i; + } + } + } + + if (i == 0) { + ctx_err(ctx, "No suitable format reported by subdev %s\n", + ctx->phy->source->name); + return -EINVAL; + } + + ret = __subdev_get_format(ctx, &mbus_fmt); + if (ret) + return ret; + + fmtinfo = find_format_by_code(ctx, mbus_fmt.code); + if (!fmtinfo) { + ctx_dbg(3, ctx, "mbus code format (0x%08x) not found.\n", + mbus_fmt.code); + return -EINVAL; + } + + /* Save current format */ + v4l2_fill_pix_format(&ctx->v_fmt.fmt.pix, &mbus_fmt); + ctx->v_fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + ctx->v_fmt.fmt.pix.pixelformat = fmtinfo->fourcc; + cal_calc_format_size(ctx, fmtinfo, &ctx->v_fmt); + ctx->fmtinfo = fmtinfo; + + return 0; +} + +static int cal_ctx_v4l2_init_mc_format(struct cal_ctx *ctx) +{ + const struct cal_format_info *fmtinfo; + struct v4l2_pix_format *pix_fmt = &ctx->v_fmt.fmt.pix; + + fmtinfo = cal_format_by_code(MEDIA_BUS_FMT_UYVY8_2X8); + if (!fmtinfo) + return -EINVAL; + + pix_fmt->width = 640; + pix_fmt->height = 480; + pix_fmt->field = V4L2_FIELD_NONE; + pix_fmt->colorspace = V4L2_COLORSPACE_SRGB; + pix_fmt->ycbcr_enc = V4L2_YCBCR_ENC_601; + pix_fmt->quantization = V4L2_QUANTIZATION_LIM_RANGE; + pix_fmt->xfer_func = V4L2_XFER_FUNC_SRGB; + pix_fmt->pixelformat = fmtinfo->fourcc; + + ctx->v_fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + + /* Save current format */ + cal_calc_format_size(ctx, fmtinfo, &ctx->v_fmt); + ctx->fmtinfo = fmtinfo; + + return 0; +} + +int cal_ctx_v4l2_register(struct cal_ctx *ctx) +{ + struct video_device *vfd = &ctx->vdev; + int ret; + + if (!cal_mc_api) { + struct v4l2_ctrl_handler *hdl = &ctx->ctrl_handler; + + ret = cal_ctx_v4l2_init_formats(ctx); + if (ret) { + ctx_err(ctx, "Failed to init formats: %d\n", ret); + return ret; + } + + ret = v4l2_ctrl_add_handler(hdl, ctx->phy->source->ctrl_handler, + NULL, true); + if (ret < 0) { + ctx_err(ctx, "Failed to add source ctrl handler\n"); + return ret; + } + } else { + ret = cal_ctx_v4l2_init_mc_format(ctx); + if (ret) { + ctx_err(ctx, "Failed to init format: %d\n", ret); + return ret; + } + } + + ret = video_register_device(vfd, VFL_TYPE_VIDEO, cal_video_nr); + if (ret < 0) { + ctx_err(ctx, "Failed to register video device\n"); + return ret; + } + + ret = media_create_pad_link(&ctx->phy->subdev.entity, + CAL_CAMERARX_PAD_FIRST_SOURCE, + &vfd->entity, 0, + MEDIA_LNK_FL_IMMUTABLE | + MEDIA_LNK_FL_ENABLED); + if (ret) { + ctx_err(ctx, "Failed to create media link for context %u\n", + ctx->dma_ctx); + video_unregister_device(vfd); + return ret; + } + + ctx_info(ctx, "V4L2 device registered as %s\n", + video_device_node_name(vfd)); + + return 0; +} + +void cal_ctx_v4l2_unregister(struct cal_ctx *ctx) +{ + ctx_dbg(1, ctx, "unregistering %s\n", + video_device_node_name(&ctx->vdev)); + + video_unregister_device(&ctx->vdev); +} + +int cal_ctx_v4l2_init(struct cal_ctx *ctx) +{ + struct video_device *vfd = &ctx->vdev; + struct vb2_queue *q = &ctx->vb_vidq; + int ret; + + INIT_LIST_HEAD(&ctx->dma.queue); + spin_lock_init(&ctx->dma.lock); + mutex_init(&ctx->mutex); + init_waitqueue_head(&ctx->dma.wait); + + /* Initialize the vb2 queue. */ + q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + q->io_modes = VB2_MMAP | VB2_DMABUF; + q->drv_priv = ctx; + q->buf_struct_size = sizeof(struct cal_buffer); + q->ops = &cal_video_qops; + q->mem_ops = &vb2_dma_contig_memops; + q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; + q->lock = &ctx->mutex; + q->min_buffers_needed = 3; + q->dev = ctx->cal->dev; + + ret = vb2_queue_init(q); + if (ret) + return ret; + + /* Initialize the video device and media entity. */ + vfd->fops = &cal_fops; + vfd->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING + | (cal_mc_api ? V4L2_CAP_IO_MC : 0); + vfd->v4l2_dev = &ctx->cal->v4l2_dev; + vfd->queue = q; + snprintf(vfd->name, sizeof(vfd->name), "CAL output %u", ctx->dma_ctx); + vfd->release = video_device_release_empty; + vfd->ioctl_ops = cal_mc_api ? &cal_ioctl_mc_ops : &cal_ioctl_legacy_ops; + vfd->lock = &ctx->mutex; + video_set_drvdata(vfd, ctx); + + ctx->pad.flags = MEDIA_PAD_FL_SINK; + ret = media_entity_pads_init(&vfd->entity, 1, &ctx->pad); + if (ret < 0) + return ret; + + if (!cal_mc_api) { + /* Initialize the control handler. */ + struct v4l2_ctrl_handler *hdl = &ctx->ctrl_handler; + + ret = v4l2_ctrl_handler_init(hdl, 11); + if (ret < 0) { + ctx_err(ctx, "Failed to init ctrl handler\n"); + goto error; + } + + vfd->ctrl_handler = hdl; + } + + return 0; + +error: + media_entity_cleanup(&vfd->entity); + return ret; +} + +void cal_ctx_v4l2_cleanup(struct cal_ctx *ctx) +{ + if (!cal_mc_api) + v4l2_ctrl_handler_free(&ctx->ctrl_handler); + + media_entity_cleanup(&ctx->vdev.entity); +} diff --git a/drivers/media/platform/ti/cal/cal.c b/drivers/media/platform/ti/cal/cal.c new file mode 100644 index 000000000000..4a4a6c5983f7 --- /dev/null +++ b/drivers/media/platform/ti/cal/cal.c @@ -0,0 +1,1263 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * TI Camera Access Layer (CAL) - Driver + * + * Copyright (c) 2015-2020 Texas Instruments Inc. + * + * Authors: + * Benoit Parrot + * Laurent Pinchart + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "cal.h" +#include "cal_regs.h" + +MODULE_DESCRIPTION("TI CAL driver"); +MODULE_AUTHOR("Benoit Parrot, "); +MODULE_LICENSE("GPL v2"); +MODULE_VERSION("0.1.0"); + +int cal_video_nr = -1; +module_param_named(video_nr, cal_video_nr, uint, 0644); +MODULE_PARM_DESC(video_nr, "videoX start number, -1 is autodetect"); + +unsigned int cal_debug; +module_param_named(debug, cal_debug, uint, 0644); +MODULE_PARM_DESC(debug, "activates debug info"); + +#ifdef CONFIG_VIDEO_TI_CAL_MC +#define CAL_MC_API_DEFAULT 1 +#else +#define CAL_MC_API_DEFAULT 0 +#endif + +bool cal_mc_api = CAL_MC_API_DEFAULT; +module_param_named(mc_api, cal_mc_api, bool, 0444); +MODULE_PARM_DESC(mc_api, "activates the MC API"); + +/* ------------------------------------------------------------------ + * Format Handling + * ------------------------------------------------------------------ + */ + +const struct cal_format_info cal_formats[] = { + { + .fourcc = V4L2_PIX_FMT_YUYV, + .code = MEDIA_BUS_FMT_YUYV8_2X8, + .bpp = 16, + }, { + .fourcc = V4L2_PIX_FMT_UYVY, + .code = MEDIA_BUS_FMT_UYVY8_2X8, + .bpp = 16, + }, { + .fourcc = V4L2_PIX_FMT_YVYU, + .code = MEDIA_BUS_FMT_YVYU8_2X8, + .bpp = 16, + }, { + .fourcc = V4L2_PIX_FMT_VYUY, + .code = MEDIA_BUS_FMT_VYUY8_2X8, + .bpp = 16, + }, { + .fourcc = V4L2_PIX_FMT_RGB565, /* gggbbbbb rrrrrggg */ + .code = MEDIA_BUS_FMT_RGB565_2X8_LE, + .bpp = 16, + }, { + .fourcc = V4L2_PIX_FMT_RGB565X, /* rrrrrggg gggbbbbb */ + .code = MEDIA_BUS_FMT_RGB565_2X8_BE, + .bpp = 16, + }, { + .fourcc = V4L2_PIX_FMT_RGB555, /* gggbbbbb arrrrrgg */ + .code = MEDIA_BUS_FMT_RGB555_2X8_PADHI_LE, + .bpp = 16, + }, { + .fourcc = V4L2_PIX_FMT_RGB555X, /* arrrrrgg gggbbbbb */ + .code = MEDIA_BUS_FMT_RGB555_2X8_PADHI_BE, + .bpp = 16, + }, { + .fourcc = V4L2_PIX_FMT_RGB24, /* rgb */ + .code = MEDIA_BUS_FMT_RGB888_2X12_LE, + .bpp = 24, + }, { + .fourcc = V4L2_PIX_FMT_BGR24, /* bgr */ + .code = MEDIA_BUS_FMT_RGB888_2X12_BE, + .bpp = 24, + }, { + .fourcc = V4L2_PIX_FMT_RGB32, /* argb */ + .code = MEDIA_BUS_FMT_ARGB8888_1X32, + .bpp = 32, + }, { + .fourcc = V4L2_PIX_FMT_SBGGR8, + .code = MEDIA_BUS_FMT_SBGGR8_1X8, + .bpp = 8, + }, { + .fourcc = V4L2_PIX_FMT_SGBRG8, + .code = MEDIA_BUS_FMT_SGBRG8_1X8, + .bpp = 8, + }, { + .fourcc = V4L2_PIX_FMT_SGRBG8, + .code = MEDIA_BUS_FMT_SGRBG8_1X8, + .bpp = 8, + }, { + .fourcc = V4L2_PIX_FMT_SRGGB8, + .code = MEDIA_BUS_FMT_SRGGB8_1X8, + .bpp = 8, + }, { + .fourcc = V4L2_PIX_FMT_SBGGR10, + .code = MEDIA_BUS_FMT_SBGGR10_1X10, + .bpp = 10, + }, { + .fourcc = V4L2_PIX_FMT_SGBRG10, + .code = MEDIA_BUS_FMT_SGBRG10_1X10, + .bpp = 10, + }, { + .fourcc = V4L2_PIX_FMT_SGRBG10, + .code = MEDIA_BUS_FMT_SGRBG10_1X10, + .bpp = 10, + }, { + .fourcc = V4L2_PIX_FMT_SRGGB10, + .code = MEDIA_BUS_FMT_SRGGB10_1X10, + .bpp = 10, + }, { + .fourcc = V4L2_PIX_FMT_SBGGR12, + .code = MEDIA_BUS_FMT_SBGGR12_1X12, + .bpp = 12, + }, { + .fourcc = V4L2_PIX_FMT_SGBRG12, + .code = MEDIA_BUS_FMT_SGBRG12_1X12, + .bpp = 12, + }, { + .fourcc = V4L2_PIX_FMT_SGRBG12, + .code = MEDIA_BUS_FMT_SGRBG12_1X12, + .bpp = 12, + }, { + .fourcc = V4L2_PIX_FMT_SRGGB12, + .code = MEDIA_BUS_FMT_SRGGB12_1X12, + .bpp = 12, + }, +}; + +const unsigned int cal_num_formats = ARRAY_SIZE(cal_formats); + +const struct cal_format_info *cal_format_by_fourcc(u32 fourcc) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(cal_formats); ++i) { + if (cal_formats[i].fourcc == fourcc) + return &cal_formats[i]; + } + + return NULL; +} + +const struct cal_format_info *cal_format_by_code(u32 code) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(cal_formats); ++i) { + if (cal_formats[i].code == code) + return &cal_formats[i]; + } + + return NULL; +} + +/* ------------------------------------------------------------------ + * Platform Data + * ------------------------------------------------------------------ + */ + +static const struct cal_camerarx_data dra72x_cal_camerarx[] = { + { + .fields = { + [F_CTRLCLKEN] = { 10, 10 }, + [F_CAMMODE] = { 11, 12 }, + [F_LANEENABLE] = { 13, 16 }, + [F_CSI_MODE] = { 17, 17 }, + }, + .num_lanes = 4, + }, + { + .fields = { + [F_CTRLCLKEN] = { 0, 0 }, + [F_CAMMODE] = { 1, 2 }, + [F_LANEENABLE] = { 3, 4 }, + [F_CSI_MODE] = { 5, 5 }, + }, + .num_lanes = 2, + }, +}; + +static const struct cal_data dra72x_cal_data = { + .camerarx = dra72x_cal_camerarx, + .num_csi2_phy = ARRAY_SIZE(dra72x_cal_camerarx), +}; + +static const struct cal_data dra72x_es1_cal_data = { + .camerarx = dra72x_cal_camerarx, + .num_csi2_phy = ARRAY_SIZE(dra72x_cal_camerarx), + .flags = DRA72_CAL_PRE_ES2_LDO_DISABLE, +}; + +static const struct cal_camerarx_data dra76x_cal_csi_phy[] = { + { + .fields = { + [F_CTRLCLKEN] = { 8, 8 }, + [F_CAMMODE] = { 9, 10 }, + [F_CSI_MODE] = { 11, 11 }, + [F_LANEENABLE] = { 27, 31 }, + }, + .num_lanes = 5, + }, + { + .fields = { + [F_CTRLCLKEN] = { 0, 0 }, + [F_CAMMODE] = { 1, 2 }, + [F_CSI_MODE] = { 3, 3 }, + [F_LANEENABLE] = { 24, 26 }, + }, + .num_lanes = 3, + }, +}; + +static const struct cal_data dra76x_cal_data = { + .camerarx = dra76x_cal_csi_phy, + .num_csi2_phy = ARRAY_SIZE(dra76x_cal_csi_phy), +}; + +static const struct cal_camerarx_data am654_cal_csi_phy[] = { + { + .fields = { + [F_CTRLCLKEN] = { 15, 15 }, + [F_CAMMODE] = { 24, 25 }, + [F_LANEENABLE] = { 0, 4 }, + }, + .num_lanes = 5, + }, +}; + +static const struct cal_data am654_cal_data = { + .camerarx = am654_cal_csi_phy, + .num_csi2_phy = ARRAY_SIZE(am654_cal_csi_phy), +}; + +/* ------------------------------------------------------------------ + * I/O Register Accessors + * ------------------------------------------------------------------ + */ + +void cal_quickdump_regs(struct cal_dev *cal) +{ + unsigned int i; + + cal_info(cal, "CAL Registers @ 0x%pa:\n", &cal->res->start); + print_hex_dump(KERN_INFO, "", DUMP_PREFIX_OFFSET, 16, 4, + (__force const void *)cal->base, + resource_size(cal->res), false); + + for (i = 0; i < cal->data->num_csi2_phy; ++i) { + struct cal_camerarx *phy = cal->phy[i]; + + cal_info(cal, "CSI2 Core %u Registers @ %pa:\n", i, + &phy->res->start); + print_hex_dump(KERN_INFO, "", DUMP_PREFIX_OFFSET, 16, 4, + (__force const void *)phy->base, + resource_size(phy->res), + false); + } +} + +/* ------------------------------------------------------------------ + * Context Management + * ------------------------------------------------------------------ + */ + +#define CAL_MAX_PIX_PROC 4 + +static int cal_reserve_pix_proc(struct cal_dev *cal) +{ + unsigned long ret; + + spin_lock(&cal->v4l2_dev.lock); + + ret = find_first_zero_bit(&cal->reserved_pix_proc_mask, CAL_MAX_PIX_PROC); + + if (ret == CAL_MAX_PIX_PROC) { + spin_unlock(&cal->v4l2_dev.lock); + return -ENOSPC; + } + + cal->reserved_pix_proc_mask |= BIT(ret); + + spin_unlock(&cal->v4l2_dev.lock); + + return ret; +} + +static void cal_release_pix_proc(struct cal_dev *cal, unsigned int pix_proc_num) +{ + spin_lock(&cal->v4l2_dev.lock); + + cal->reserved_pix_proc_mask &= ~BIT(pix_proc_num); + + spin_unlock(&cal->v4l2_dev.lock); +} + +static void cal_ctx_csi2_config(struct cal_ctx *ctx) +{ + u32 val; + + val = cal_read(ctx->cal, CAL_CSI2_CTX(ctx->phy->instance, ctx->csi2_ctx)); + cal_set_field(&val, ctx->cport, CAL_CSI2_CTX_CPORT_MASK); + /* + * DT type: MIPI CSI-2 Specs + * 0x1: All - DT filter is disabled + * 0x24: RGB888 1 pixel = 3 bytes + * 0x2B: RAW10 4 pixels = 5 bytes + * 0x2A: RAW8 1 pixel = 1 byte + * 0x1E: YUV422 2 pixels = 4 bytes + */ + cal_set_field(&val, ctx->datatype, CAL_CSI2_CTX_DT_MASK); + cal_set_field(&val, ctx->vc, CAL_CSI2_CTX_VC_MASK); + cal_set_field(&val, ctx->v_fmt.fmt.pix.height, CAL_CSI2_CTX_LINES_MASK); + cal_set_field(&val, CAL_CSI2_CTX_ATT_PIX, CAL_CSI2_CTX_ATT_MASK); + cal_set_field(&val, CAL_CSI2_CTX_PACK_MODE_LINE, + CAL_CSI2_CTX_PACK_MODE_MASK); + cal_write(ctx->cal, CAL_CSI2_CTX(ctx->phy->instance, ctx->csi2_ctx), val); + ctx_dbg(3, ctx, "CAL_CSI2_CTX(%u, %u) = 0x%08x\n", + ctx->phy->instance, ctx->csi2_ctx, + cal_read(ctx->cal, CAL_CSI2_CTX(ctx->phy->instance, ctx->csi2_ctx))); +} + +static void cal_ctx_pix_proc_config(struct cal_ctx *ctx) +{ + u32 val, extract, pack; + + switch (ctx->fmtinfo->bpp) { + case 8: + extract = CAL_PIX_PROC_EXTRACT_B8; + pack = CAL_PIX_PROC_PACK_B8; + break; + case 10: + extract = CAL_PIX_PROC_EXTRACT_B10_MIPI; + pack = CAL_PIX_PROC_PACK_B16; + break; + case 12: + extract = CAL_PIX_PROC_EXTRACT_B12_MIPI; + pack = CAL_PIX_PROC_PACK_B16; + break; + case 16: + extract = CAL_PIX_PROC_EXTRACT_B16_LE; + pack = CAL_PIX_PROC_PACK_B16; + break; + default: + /* + * If you see this warning then it means that you added + * some new entry in the cal_formats[] array with a different + * bit per pixel values then the one supported below. + * Either add support for the new bpp value below or adjust + * the new entry to use one of the value below. + * + * Instead of failing here just use 8 bpp as a default. + */ + dev_warn_once(ctx->cal->dev, + "%s:%d:%s: bpp:%d unsupported! Overwritten with 8.\n", + __FILE__, __LINE__, __func__, ctx->fmtinfo->bpp); + extract = CAL_PIX_PROC_EXTRACT_B8; + pack = CAL_PIX_PROC_PACK_B8; + break; + } + + val = cal_read(ctx->cal, CAL_PIX_PROC(ctx->pix_proc)); + cal_set_field(&val, extract, CAL_PIX_PROC_EXTRACT_MASK); + cal_set_field(&val, CAL_PIX_PROC_DPCMD_BYPASS, CAL_PIX_PROC_DPCMD_MASK); + cal_set_field(&val, CAL_PIX_PROC_DPCME_BYPASS, CAL_PIX_PROC_DPCME_MASK); + cal_set_field(&val, pack, CAL_PIX_PROC_PACK_MASK); + cal_set_field(&val, ctx->cport, CAL_PIX_PROC_CPORT_MASK); + cal_set_field(&val, 1, CAL_PIX_PROC_EN_MASK); + cal_write(ctx->cal, CAL_PIX_PROC(ctx->pix_proc), val); + ctx_dbg(3, ctx, "CAL_PIX_PROC(%u) = 0x%08x\n", ctx->pix_proc, + cal_read(ctx->cal, CAL_PIX_PROC(ctx->pix_proc))); +} + +static void cal_ctx_wr_dma_config(struct cal_ctx *ctx) +{ + unsigned int stride = ctx->v_fmt.fmt.pix.bytesperline; + u32 val; + + val = cal_read(ctx->cal, CAL_WR_DMA_CTRL(ctx->dma_ctx)); + cal_set_field(&val, ctx->cport, CAL_WR_DMA_CTRL_CPORT_MASK); + cal_set_field(&val, ctx->v_fmt.fmt.pix.height, + CAL_WR_DMA_CTRL_YSIZE_MASK); + cal_set_field(&val, CAL_WR_DMA_CTRL_DTAG_PIX_DAT, + CAL_WR_DMA_CTRL_DTAG_MASK); + cal_set_field(&val, CAL_WR_DMA_CTRL_PATTERN_LINEAR, + CAL_WR_DMA_CTRL_PATTERN_MASK); + cal_set_field(&val, 1, CAL_WR_DMA_CTRL_STALL_RD_MASK); + cal_write(ctx->cal, CAL_WR_DMA_CTRL(ctx->dma_ctx), val); + ctx_dbg(3, ctx, "CAL_WR_DMA_CTRL(%d) = 0x%08x\n", ctx->dma_ctx, + cal_read(ctx->cal, CAL_WR_DMA_CTRL(ctx->dma_ctx))); + + cal_write_field(ctx->cal, CAL_WR_DMA_OFST(ctx->dma_ctx), + stride / 16, CAL_WR_DMA_OFST_MASK); + ctx_dbg(3, ctx, "CAL_WR_DMA_OFST(%d) = 0x%08x\n", ctx->dma_ctx, + cal_read(ctx->cal, CAL_WR_DMA_OFST(ctx->dma_ctx))); + + val = cal_read(ctx->cal, CAL_WR_DMA_XSIZE(ctx->dma_ctx)); + /* 64 bit word means no skipping */ + cal_set_field(&val, 0, CAL_WR_DMA_XSIZE_XSKIP_MASK); + /* + * The XSIZE field is expressed in 64-bit units and prevents overflows + * in case of synchronization issues by limiting the number of bytes + * written per line. + */ + cal_set_field(&val, stride / 8, CAL_WR_DMA_XSIZE_MASK); + cal_write(ctx->cal, CAL_WR_DMA_XSIZE(ctx->dma_ctx), val); + ctx_dbg(3, ctx, "CAL_WR_DMA_XSIZE(%d) = 0x%08x\n", ctx->dma_ctx, + cal_read(ctx->cal, CAL_WR_DMA_XSIZE(ctx->dma_ctx))); +} + +void cal_ctx_set_dma_addr(struct cal_ctx *ctx, dma_addr_t addr) +{ + cal_write(ctx->cal, CAL_WR_DMA_ADDR(ctx->dma_ctx), addr); +} + +static void cal_ctx_wr_dma_enable(struct cal_ctx *ctx) +{ + u32 val = cal_read(ctx->cal, CAL_WR_DMA_CTRL(ctx->dma_ctx)); + + cal_set_field(&val, CAL_WR_DMA_CTRL_MODE_CONST, + CAL_WR_DMA_CTRL_MODE_MASK); + cal_write(ctx->cal, CAL_WR_DMA_CTRL(ctx->dma_ctx), val); +} + +static void cal_ctx_wr_dma_disable(struct cal_ctx *ctx) +{ + u32 val = cal_read(ctx->cal, CAL_WR_DMA_CTRL(ctx->dma_ctx)); + + cal_set_field(&val, CAL_WR_DMA_CTRL_MODE_DIS, + CAL_WR_DMA_CTRL_MODE_MASK); + cal_write(ctx->cal, CAL_WR_DMA_CTRL(ctx->dma_ctx), val); +} + +static bool cal_ctx_wr_dma_stopped(struct cal_ctx *ctx) +{ + bool stopped; + + spin_lock_irq(&ctx->dma.lock); + stopped = ctx->dma.state == CAL_DMA_STOPPED; + spin_unlock_irq(&ctx->dma.lock); + + return stopped; +} + +int cal_ctx_prepare(struct cal_ctx *ctx) +{ + int ret; + + ctx->use_pix_proc = !ctx->fmtinfo->meta; + + if (ctx->use_pix_proc) { + ret = cal_reserve_pix_proc(ctx->cal); + if (ret < 0) { + ctx_err(ctx, "Failed to reserve pix proc: %d\n", ret); + return ret; + } + + ctx->pix_proc = ret; + } + + return 0; +} + +void cal_ctx_unprepare(struct cal_ctx *ctx) +{ + if (ctx->use_pix_proc) + cal_release_pix_proc(ctx->cal, ctx->pix_proc); +} + +void cal_ctx_start(struct cal_ctx *ctx) +{ + ctx->sequence = 0; + ctx->dma.state = CAL_DMA_RUNNING; + + /* Configure the CSI-2, pixel processing and write DMA contexts. */ + cal_ctx_csi2_config(ctx); + if (ctx->use_pix_proc) + cal_ctx_pix_proc_config(ctx); + cal_ctx_wr_dma_config(ctx); + + /* Enable IRQ_WDMA_END and IRQ_WDMA_START. */ + cal_write(ctx->cal, CAL_HL_IRQENABLE_SET(1), + CAL_HL_IRQ_WDMA_END_MASK(ctx->dma_ctx)); + cal_write(ctx->cal, CAL_HL_IRQENABLE_SET(2), + CAL_HL_IRQ_WDMA_START_MASK(ctx->dma_ctx)); + + cal_ctx_wr_dma_enable(ctx); +} + +void cal_ctx_stop(struct cal_ctx *ctx) +{ + long timeout; + + /* + * Request DMA stop and wait until it completes. If completion times + * out, forcefully disable the DMA. + */ + spin_lock_irq(&ctx->dma.lock); + ctx->dma.state = CAL_DMA_STOP_REQUESTED; + spin_unlock_irq(&ctx->dma.lock); + + timeout = wait_event_timeout(ctx->dma.wait, cal_ctx_wr_dma_stopped(ctx), + msecs_to_jiffies(500)); + if (!timeout) { + ctx_err(ctx, "failed to disable dma cleanly\n"); + cal_ctx_wr_dma_disable(ctx); + } + + /* Disable IRQ_WDMA_END and IRQ_WDMA_START. */ + cal_write(ctx->cal, CAL_HL_IRQENABLE_CLR(1), + CAL_HL_IRQ_WDMA_END_MASK(ctx->dma_ctx)); + cal_write(ctx->cal, CAL_HL_IRQENABLE_CLR(2), + CAL_HL_IRQ_WDMA_START_MASK(ctx->dma_ctx)); + + ctx->dma.state = CAL_DMA_STOPPED; + + /* Disable CSI2 context */ + cal_write(ctx->cal, CAL_CSI2_CTX(ctx->phy->instance, ctx->csi2_ctx), 0); + + /* Disable pix proc */ + if (ctx->use_pix_proc) + cal_write(ctx->cal, CAL_PIX_PROC(ctx->pix_proc), 0); +} + +/* ------------------------------------------------------------------ + * IRQ Handling + * ------------------------------------------------------------------ + */ + +static inline void cal_irq_wdma_start(struct cal_ctx *ctx) +{ + spin_lock(&ctx->dma.lock); + + if (ctx->dma.state == CAL_DMA_STOP_REQUESTED) { + /* + * If a stop is requested, disable the write DMA context + * immediately. The CAL_WR_DMA_CTRL_j.MODE field is shadowed, + * the current frame will complete and the DMA will then stop. + */ + cal_ctx_wr_dma_disable(ctx); + ctx->dma.state = CAL_DMA_STOP_PENDING; + } else if (!list_empty(&ctx->dma.queue) && !ctx->dma.pending) { + /* + * Otherwise, if a new buffer is available, queue it to the + * hardware. + */ + struct cal_buffer *buf; + dma_addr_t addr; + + buf = list_first_entry(&ctx->dma.queue, struct cal_buffer, + list); + addr = vb2_dma_contig_plane_dma_addr(&buf->vb.vb2_buf, 0); + cal_ctx_set_dma_addr(ctx, addr); + + ctx->dma.pending = buf; + list_del(&buf->list); + } + + spin_unlock(&ctx->dma.lock); +} + +static inline void cal_irq_wdma_end(struct cal_ctx *ctx) +{ + struct cal_buffer *buf = NULL; + + spin_lock(&ctx->dma.lock); + + /* If the DMA context was stopping, it is now stopped. */ + if (ctx->dma.state == CAL_DMA_STOP_PENDING) { + ctx->dma.state = CAL_DMA_STOPPED; + wake_up(&ctx->dma.wait); + } + + /* If a new buffer was queued, complete the current buffer. */ + if (ctx->dma.pending) { + buf = ctx->dma.active; + ctx->dma.active = ctx->dma.pending; + ctx->dma.pending = NULL; + } + + spin_unlock(&ctx->dma.lock); + + if (buf) { + buf->vb.vb2_buf.timestamp = ktime_get_ns(); + buf->vb.field = ctx->v_fmt.fmt.pix.field; + buf->vb.sequence = ctx->sequence++; + vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_DONE); + } +} + +static irqreturn_t cal_irq(int irq_cal, void *data) +{ + struct cal_dev *cal = data; + u32 status; + + status = cal_read(cal, CAL_HL_IRQSTATUS(0)); + if (status) { + unsigned int i; + + cal_write(cal, CAL_HL_IRQSTATUS(0), status); + + if (status & CAL_HL_IRQ_OCPO_ERR_MASK) + dev_err_ratelimited(cal->dev, "OCPO ERROR\n"); + + for (i = 0; i < cal->data->num_csi2_phy; ++i) { + if (status & CAL_HL_IRQ_CIO_MASK(i)) { + u32 cio_stat = cal_read(cal, + CAL_CSI2_COMPLEXIO_IRQSTATUS(i)); + + dev_err_ratelimited(cal->dev, + "CIO%u error: %#08x\n", i, cio_stat); + + cal_write(cal, CAL_CSI2_COMPLEXIO_IRQSTATUS(i), + cio_stat); + } + + if (status & CAL_HL_IRQ_VC_MASK(i)) { + u32 vc_stat = cal_read(cal, CAL_CSI2_VC_IRQSTATUS(i)); + + dev_err_ratelimited(cal->dev, + "CIO%u VC error: %#08x\n", + i, vc_stat); + + cal_write(cal, CAL_CSI2_VC_IRQSTATUS(i), vc_stat); + } + } + } + + /* Check which DMA just finished */ + status = cal_read(cal, CAL_HL_IRQSTATUS(1)); + if (status) { + unsigned int i; + + /* Clear Interrupt status */ + cal_write(cal, CAL_HL_IRQSTATUS(1), status); + + for (i = 0; i < cal->num_contexts; ++i) { + if (status & CAL_HL_IRQ_WDMA_END_MASK(i)) + cal_irq_wdma_end(cal->ctx[i]); + } + } + + /* Check which DMA just started */ + status = cal_read(cal, CAL_HL_IRQSTATUS(2)); + if (status) { + unsigned int i; + + /* Clear Interrupt status */ + cal_write(cal, CAL_HL_IRQSTATUS(2), status); + + for (i = 0; i < cal->num_contexts; ++i) { + if (status & CAL_HL_IRQ_WDMA_START_MASK(i)) + cal_irq_wdma_start(cal->ctx[i]); + } + } + + return IRQ_HANDLED; +} + +/* ------------------------------------------------------------------ + * Asynchronous V4L2 subdev binding + * ------------------------------------------------------------------ + */ + +struct cal_v4l2_async_subdev { + struct v4l2_async_subdev asd; /* Must be first */ + struct cal_camerarx *phy; +}; + +static inline struct cal_v4l2_async_subdev * +to_cal_asd(struct v4l2_async_subdev *asd) +{ + return container_of(asd, struct cal_v4l2_async_subdev, asd); +} + +static int cal_async_notifier_bound(struct v4l2_async_notifier *notifier, + struct v4l2_subdev *subdev, + struct v4l2_async_subdev *asd) +{ + struct cal_camerarx *phy = to_cal_asd(asd)->phy; + int pad; + int ret; + + if (phy->source) { + phy_info(phy, "Rejecting subdev %s (Already set!!)", + subdev->name); + return 0; + } + + phy->source = subdev; + phy_dbg(1, phy, "Using source %s for capture\n", subdev->name); + + pad = media_entity_get_fwnode_pad(&subdev->entity, + of_fwnode_handle(phy->source_ep_node), + MEDIA_PAD_FL_SOURCE); + if (pad < 0) { + phy_err(phy, "Source %s has no connected source pad\n", + subdev->name); + return pad; + } + + ret = media_create_pad_link(&subdev->entity, pad, + &phy->subdev.entity, CAL_CAMERARX_PAD_SINK, + MEDIA_LNK_FL_IMMUTABLE | + MEDIA_LNK_FL_ENABLED); + if (ret) { + phy_err(phy, "Failed to create media link for source %s\n", + subdev->name); + return ret; + } + + return 0; +} + +static int cal_async_notifier_complete(struct v4l2_async_notifier *notifier) +{ + struct cal_dev *cal = container_of(notifier, struct cal_dev, notifier); + unsigned int i; + int ret; + + for (i = 0; i < cal->num_contexts; ++i) { + ret = cal_ctx_v4l2_register(cal->ctx[i]); + if (ret) + goto err_ctx_unreg; + } + + if (!cal_mc_api) + return 0; + + ret = v4l2_device_register_subdev_nodes(&cal->v4l2_dev); + if (ret) + goto err_ctx_unreg; + + return 0; + +err_ctx_unreg: + for (; i > 0; --i) { + if (!cal->ctx[i - 1]) + continue; + + cal_ctx_v4l2_unregister(cal->ctx[i - 1]); + } + + return ret; +} + +static const struct v4l2_async_notifier_operations cal_async_notifier_ops = { + .bound = cal_async_notifier_bound, + .complete = cal_async_notifier_complete, +}; + +static int cal_async_notifier_register(struct cal_dev *cal) +{ + unsigned int i; + int ret; + + v4l2_async_nf_init(&cal->notifier); + cal->notifier.ops = &cal_async_notifier_ops; + + for (i = 0; i < cal->data->num_csi2_phy; ++i) { + struct cal_camerarx *phy = cal->phy[i]; + struct cal_v4l2_async_subdev *casd; + struct fwnode_handle *fwnode; + + if (!phy->source_node) + continue; + + fwnode = of_fwnode_handle(phy->source_node); + casd = v4l2_async_nf_add_fwnode(&cal->notifier, + fwnode, + struct cal_v4l2_async_subdev); + if (IS_ERR(casd)) { + phy_err(phy, "Failed to add subdev to notifier\n"); + ret = PTR_ERR(casd); + goto error; + } + + casd->phy = phy; + } + + ret = v4l2_async_nf_register(&cal->v4l2_dev, &cal->notifier); + if (ret) { + cal_err(cal, "Error registering async notifier\n"); + goto error; + } + + return 0; + +error: + v4l2_async_nf_cleanup(&cal->notifier); + return ret; +} + +static void cal_async_notifier_unregister(struct cal_dev *cal) +{ + v4l2_async_nf_unregister(&cal->notifier); + v4l2_async_nf_cleanup(&cal->notifier); +} + +/* ------------------------------------------------------------------ + * Media and V4L2 device handling + * ------------------------------------------------------------------ + */ + +/* + * Register user-facing devices. To be called at the end of the probe function + * when all resources are initialized and ready. + */ +static int cal_media_register(struct cal_dev *cal) +{ + int ret; + + ret = media_device_register(&cal->mdev); + if (ret) { + cal_err(cal, "Failed to register media device\n"); + return ret; + } + + /* + * Register the async notifier. This may trigger registration of the + * V4L2 video devices if all subdevs are ready. + */ + ret = cal_async_notifier_register(cal); + if (ret) { + media_device_unregister(&cal->mdev); + return ret; + } + + return 0; +} + +/* + * Unregister the user-facing devices, but don't free memory yet. To be called + * at the beginning of the remove function, to disallow access from userspace. + */ +static void cal_media_unregister(struct cal_dev *cal) +{ + unsigned int i; + + /* Unregister all the V4L2 video devices. */ + for (i = 0; i < cal->num_contexts; i++) + cal_ctx_v4l2_unregister(cal->ctx[i]); + + cal_async_notifier_unregister(cal); + media_device_unregister(&cal->mdev); +} + +/* + * Initialize the in-kernel objects. To be called at the beginning of the probe + * function, before the V4L2 device is used by the driver. + */ +static int cal_media_init(struct cal_dev *cal) +{ + struct media_device *mdev = &cal->mdev; + int ret; + + mdev->dev = cal->dev; + mdev->hw_revision = cal->revision; + strscpy(mdev->model, "CAL", sizeof(mdev->model)); + snprintf(mdev->bus_info, sizeof(mdev->bus_info), "platform:%s", + dev_name(mdev->dev)); + media_device_init(mdev); + + /* + * Initialize the V4L2 device (despite the function name, this performs + * initialization, not registration). + */ + cal->v4l2_dev.mdev = mdev; + ret = v4l2_device_register(cal->dev, &cal->v4l2_dev); + if (ret) { + cal_err(cal, "Failed to register V4L2 device\n"); + return ret; + } + + vb2_dma_contig_set_max_seg_size(cal->dev, DMA_BIT_MASK(32)); + + return 0; +} + +/* + * Cleanup the in-kernel objects, freeing memory. To be called at the very end + * of the remove sequence, when nothing (including userspace) can access the + * objects anymore. + */ +static void cal_media_cleanup(struct cal_dev *cal) +{ + v4l2_device_unregister(&cal->v4l2_dev); + media_device_cleanup(&cal->mdev); + + vb2_dma_contig_clear_max_seg_size(cal->dev); +} + +/* ------------------------------------------------------------------ + * Initialization and module stuff + * ------------------------------------------------------------------ + */ + +static struct cal_ctx *cal_ctx_create(struct cal_dev *cal, int inst) +{ + struct cal_ctx *ctx; + int ret; + + ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); + if (!ctx) + return NULL; + + ctx->cal = cal; + ctx->phy = cal->phy[inst]; + ctx->dma_ctx = inst; + ctx->csi2_ctx = inst; + ctx->cport = inst; + ctx->vc = 0; + ctx->datatype = CAL_CSI2_CTX_DT_ANY; + + ret = cal_ctx_v4l2_init(ctx); + if (ret) + return NULL; + + return ctx; +} + +static void cal_ctx_destroy(struct cal_ctx *ctx) +{ + cal_ctx_v4l2_cleanup(ctx); + + kfree(ctx); +} + +static const struct of_device_id cal_of_match[] = { + { + .compatible = "ti,dra72-cal", + .data = (void *)&dra72x_cal_data, + }, + { + .compatible = "ti,dra72-pre-es2-cal", + .data = (void *)&dra72x_es1_cal_data, + }, + { + .compatible = "ti,dra76-cal", + .data = (void *)&dra76x_cal_data, + }, + { + .compatible = "ti,am654-cal", + .data = (void *)&am654_cal_data, + }, + {}, +}; +MODULE_DEVICE_TABLE(of, cal_of_match); + +/* Get hardware revision and info. */ + +#define CAL_HL_HWINFO_VALUE 0xa3c90469 + +static void cal_get_hwinfo(struct cal_dev *cal) +{ + u32 hwinfo; + + cal->revision = cal_read(cal, CAL_HL_REVISION); + switch (FIELD_GET(CAL_HL_REVISION_SCHEME_MASK, cal->revision)) { + case CAL_HL_REVISION_SCHEME_H08: + cal_dbg(3, cal, "CAL HW revision %lu.%lu.%lu (0x%08x)\n", + FIELD_GET(CAL_HL_REVISION_MAJOR_MASK, cal->revision), + FIELD_GET(CAL_HL_REVISION_MINOR_MASK, cal->revision), + FIELD_GET(CAL_HL_REVISION_RTL_MASK, cal->revision), + cal->revision); + break; + + case CAL_HL_REVISION_SCHEME_LEGACY: + default: + cal_info(cal, "Unexpected CAL HW revision 0x%08x\n", + cal->revision); + break; + } + + hwinfo = cal_read(cal, CAL_HL_HWINFO); + if (hwinfo != CAL_HL_HWINFO_VALUE) + cal_info(cal, "CAL_HL_HWINFO = 0x%08x, expected 0x%08x\n", + hwinfo, CAL_HL_HWINFO_VALUE); +} + +static int cal_init_camerarx_regmap(struct cal_dev *cal) +{ + struct platform_device *pdev = to_platform_device(cal->dev); + struct device_node *np = cal->dev->of_node; + struct regmap_config config = { }; + struct regmap *syscon; + struct resource *res; + unsigned int offset; + void __iomem *base; + + syscon = syscon_regmap_lookup_by_phandle_args(np, "ti,camerrx-control", + 1, &offset); + if (!IS_ERR(syscon)) { + cal->syscon_camerrx = syscon; + cal->syscon_camerrx_offset = offset; + return 0; + } + + dev_warn(cal->dev, "failed to get ti,camerrx-control: %ld\n", + PTR_ERR(syscon)); + + /* + * Backward DTS compatibility. If syscon entry is not present then + * check if the camerrx_control resource is present. + */ + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, + "camerrx_control"); + base = devm_ioremap_resource(cal->dev, res); + if (IS_ERR(base)) { + cal_err(cal, "failed to ioremap camerrx_control\n"); + return PTR_ERR(base); + } + + cal_dbg(1, cal, "ioresource %s at %pa - %pa\n", + res->name, &res->start, &res->end); + + config.reg_bits = 32; + config.reg_stride = 4; + config.val_bits = 32; + config.max_register = resource_size(res) - 4; + + syscon = regmap_init_mmio(NULL, base, &config); + if (IS_ERR(syscon)) { + pr_err("regmap init failed\n"); + return PTR_ERR(syscon); + } + + /* + * In this case the base already point to the direct CM register so no + * need for an offset. + */ + cal->syscon_camerrx = syscon; + cal->syscon_camerrx_offset = 0; + + return 0; +} + +static int cal_probe(struct platform_device *pdev) +{ + struct cal_dev *cal; + bool connected = false; + unsigned int i; + int ret; + int irq; + + cal = devm_kzalloc(&pdev->dev, sizeof(*cal), GFP_KERNEL); + if (!cal) + return -ENOMEM; + + cal->data = of_device_get_match_data(&pdev->dev); + if (!cal->data) { + dev_err(&pdev->dev, "Could not get feature data based on compatible version\n"); + return -ENODEV; + } + + cal->dev = &pdev->dev; + platform_set_drvdata(pdev, cal); + + /* Acquire resources: clocks, CAMERARX regmap, I/O memory and IRQ. */ + cal->fclk = devm_clk_get(&pdev->dev, "fck"); + if (IS_ERR(cal->fclk)) { + dev_err(&pdev->dev, "cannot get CAL fclk\n"); + return PTR_ERR(cal->fclk); + } + + ret = cal_init_camerarx_regmap(cal); + if (ret < 0) + return ret; + + cal->res = platform_get_resource_byname(pdev, IORESOURCE_MEM, + "cal_top"); + cal->base = devm_ioremap_resource(&pdev->dev, cal->res); + if (IS_ERR(cal->base)) + return PTR_ERR(cal->base); + + cal_dbg(1, cal, "ioresource %s at %pa - %pa\n", + cal->res->name, &cal->res->start, &cal->res->end); + + irq = platform_get_irq(pdev, 0); + cal_dbg(1, cal, "got irq# %d\n", irq); + ret = devm_request_irq(&pdev->dev, irq, cal_irq, 0, CAL_MODULE_NAME, + cal); + if (ret) + return ret; + + /* Read the revision and hardware info to verify hardware access. */ + pm_runtime_enable(&pdev->dev); + ret = pm_runtime_resume_and_get(&pdev->dev); + if (ret) + goto error_pm_runtime; + + cal_get_hwinfo(cal); + pm_runtime_put_sync(&pdev->dev); + + /* Initialize the media device. */ + ret = cal_media_init(cal); + if (ret < 0) + goto error_pm_runtime; + + /* Create CAMERARX PHYs. */ + for (i = 0; i < cal->data->num_csi2_phy; ++i) { + cal->phy[i] = cal_camerarx_create(cal, i); + if (IS_ERR(cal->phy[i])) { + ret = PTR_ERR(cal->phy[i]); + cal->phy[i] = NULL; + goto error_camerarx; + } + + if (cal->phy[i]->source_node) + connected = true; + } + + if (!connected) { + cal_err(cal, "Neither port is configured, no point in staying up\n"); + ret = -ENODEV; + goto error_camerarx; + } + + /* Create contexts. */ + for (i = 0; i < cal->data->num_csi2_phy; ++i) { + if (!cal->phy[i]->source_node) + continue; + + cal->ctx[cal->num_contexts] = cal_ctx_create(cal, i); + if (!cal->ctx[cal->num_contexts]) { + cal_err(cal, "Failed to create context %u\n", cal->num_contexts); + ret = -ENODEV; + goto error_context; + } + + cal->num_contexts++; + } + + /* Register the media device. */ + ret = cal_media_register(cal); + if (ret) + goto error_context; + + return 0; + +error_context: + for (i = 0; i < cal->num_contexts; i++) + cal_ctx_destroy(cal->ctx[i]); + +error_camerarx: + for (i = 0; i < cal->data->num_csi2_phy; i++) + cal_camerarx_destroy(cal->phy[i]); + + cal_media_cleanup(cal); + +error_pm_runtime: + pm_runtime_disable(&pdev->dev); + + return ret; +} + +static int cal_remove(struct platform_device *pdev) +{ + struct cal_dev *cal = platform_get_drvdata(pdev); + unsigned int i; + int ret; + + cal_dbg(1, cal, "Removing %s\n", CAL_MODULE_NAME); + + ret = pm_runtime_resume_and_get(&pdev->dev); + + cal_media_unregister(cal); + + for (i = 0; i < cal->data->num_csi2_phy; i++) + cal_camerarx_disable(cal->phy[i]); + + for (i = 0; i < cal->num_contexts; i++) + cal_ctx_destroy(cal->ctx[i]); + + for (i = 0; i < cal->data->num_csi2_phy; i++) + cal_camerarx_destroy(cal->phy[i]); + + cal_media_cleanup(cal); + + if (ret >= 0) + pm_runtime_put_sync(&pdev->dev); + pm_runtime_disable(&pdev->dev); + + return 0; +} + +static int cal_runtime_resume(struct device *dev) +{ + struct cal_dev *cal = dev_get_drvdata(dev); + unsigned int i; + u32 val; + + if (cal->data->flags & DRA72_CAL_PRE_ES2_LDO_DISABLE) { + /* + * Apply errata on both port everytime we (re-)enable + * the clock + */ + for (i = 0; i < cal->data->num_csi2_phy; i++) + cal_camerarx_i913_errata(cal->phy[i]); + } + + /* + * Enable global interrupts that are not related to a particular + * CAMERARAX or context. + */ + cal_write(cal, CAL_HL_IRQENABLE_SET(0), CAL_HL_IRQ_OCPO_ERR_MASK); + + val = cal_read(cal, CAL_CTRL); + cal_set_field(&val, CAL_CTRL_BURSTSIZE_BURST128, + CAL_CTRL_BURSTSIZE_MASK); + cal_set_field(&val, 0xf, CAL_CTRL_TAGCNT_MASK); + cal_set_field(&val, CAL_CTRL_POSTED_WRITES_NONPOSTED, + CAL_CTRL_POSTED_WRITES_MASK); + cal_set_field(&val, 0xff, CAL_CTRL_MFLAGL_MASK); + cal_set_field(&val, 0xff, CAL_CTRL_MFLAGH_MASK); + cal_write(cal, CAL_CTRL, val); + cal_dbg(3, cal, "CAL_CTRL = 0x%08x\n", cal_read(cal, CAL_CTRL)); + + return 0; +} + +static const struct dev_pm_ops cal_pm_ops = { + .runtime_resume = cal_runtime_resume, +}; + +static struct platform_driver cal_pdrv = { + .probe = cal_probe, + .remove = cal_remove, + .driver = { + .name = CAL_MODULE_NAME, + .pm = &cal_pm_ops, + .of_match_table = cal_of_match, + }, +}; + +module_platform_driver(cal_pdrv); diff --git a/drivers/media/platform/ti/cal/cal.h b/drivers/media/platform/ti/cal/cal.h new file mode 100644 index 000000000000..527e22d022f3 --- /dev/null +++ b/drivers/media/platform/ti/cal/cal.h @@ -0,0 +1,343 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * TI Camera Access Layer (CAL) + * + * Copyright (c) 2015-2020 Texas Instruments Inc. + * + * Authors: + * Benoit Parrot + * Laurent Pinchart + */ +#ifndef __TI_CAL_H__ +#define __TI_CAL_H__ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#define CAL_MODULE_NAME "cal" +#define CAL_MAX_NUM_CONTEXT 8 +#define CAL_NUM_CSI2_PORTS 2 + +/* + * The width is limited by the size of the CAL_WR_DMA_XSIZE_j.XSIZE field, + * expressed in multiples of 64 bits. The height is limited by the size of the + * CAL_CSI2_CTXi_j.CTXi_LINES and CAL_WR_DMA_CTRL_j.YSIZE fields, expressed in + * lines. + */ +#define CAL_MIN_WIDTH_BYTES 16 +#define CAL_MAX_WIDTH_BYTES (8192 * 8) +#define CAL_MIN_HEIGHT_LINES 1 +#define CAL_MAX_HEIGHT_LINES 16383 + +#define CAL_CAMERARX_PAD_SINK 0 +#define CAL_CAMERARX_PAD_FIRST_SOURCE 1 +#define CAL_CAMERARX_NUM_SOURCE_PADS 1 +#define CAL_CAMERARX_NUM_PADS (1 + CAL_CAMERARX_NUM_SOURCE_PADS) + +static inline bool cal_rx_pad_is_sink(u32 pad) +{ + /* Camera RX has 1 sink pad, and N source pads */ + return pad == 0; +} + +static inline bool cal_rx_pad_is_source(u32 pad) +{ + /* Camera RX has 1 sink pad, and N source pads */ + return pad >= CAL_CAMERARX_PAD_FIRST_SOURCE && + pad <= CAL_CAMERARX_NUM_SOURCE_PADS; +} + +struct device; +struct device_node; +struct resource; +struct regmap; +struct regmap_fied; + +/* CTRL_CORE_CAMERRX_CONTROL register field id */ +enum cal_camerarx_field { + F_CTRLCLKEN, + F_CAMMODE, + F_LANEENABLE, + F_CSI_MODE, + F_MAX_FIELDS, +}; + +enum cal_dma_state { + CAL_DMA_RUNNING, + CAL_DMA_STOP_REQUESTED, + CAL_DMA_STOP_PENDING, + CAL_DMA_STOPPED, +}; + +struct cal_format_info { + u32 fourcc; + u32 code; + /* Bits per pixel */ + u8 bpp; + bool meta; +}; + +/* buffer for one video frame */ +struct cal_buffer { + /* common v4l buffer stuff -- must be first */ + struct vb2_v4l2_buffer vb; + struct list_head list; +}; + +/** + * struct cal_dmaqueue - Queue of DMA buffers + */ +struct cal_dmaqueue { + /** + * @lock: Protects all fields in the cal_dmaqueue. + */ + spinlock_t lock; + + /** + * @queue: Buffers queued to the driver and waiting for DMA processing. + * Buffers are added to the list by the vb2 .buffer_queue() operation, + * and move to @pending when they are scheduled for the next frame. + */ + struct list_head queue; + /** + * @pending: Buffer provided to the hardware to DMA the next frame. + * Will move to @active at the end of the current frame. + */ + struct cal_buffer *pending; + /** + * @active: Buffer being DMA'ed to for the current frame. Will be + * retired and given back to vb2 at the end of the current frame if + * a @pending buffer has been scheduled to replace it. + */ + struct cal_buffer *active; + + /** @state: State of the DMA engine. */ + enum cal_dma_state state; + /** @wait: Wait queue to signal a @state transition to CAL_DMA_STOPPED. */ + struct wait_queue_head wait; +}; + +struct cal_camerarx_data { + struct { + unsigned int lsb; + unsigned int msb; + } fields[F_MAX_FIELDS]; + unsigned int num_lanes; +}; + +struct cal_data { + const struct cal_camerarx_data *camerarx; + unsigned int num_csi2_phy; + unsigned int flags; +}; + +/* + * The Camera Adaptation Layer (CAL) module is paired with one or more complex + * I/O PHYs (CAMERARX). It contains multiple instances of CSI-2, processing and + * DMA contexts. + * + * The cal_dev structure represents the whole subsystem, including the CAL and + * the CAMERARX instances. Instances of struct cal_dev are named cal through the + * driver. + * + * The cal_camerarx structure represents one CAMERARX instance. Instances of + * cal_camerarx are named phy through the driver. + * + * The cal_ctx structure represents the combination of one CSI-2 context, one + * processing context and one DMA context. Instance of struct cal_ctx are named + * ctx through the driver. + */ + +struct cal_camerarx { + void __iomem *base; + struct resource *res; + struct regmap_field *fields[F_MAX_FIELDS]; + + struct cal_dev *cal; + unsigned int instance; + + struct v4l2_fwnode_endpoint endpoint; + struct device_node *source_ep_node; + struct device_node *source_node; + struct v4l2_subdev *source; + struct media_pipeline pipe; + + struct v4l2_subdev subdev; + struct media_pad pads[CAL_CAMERARX_NUM_PADS]; + struct v4l2_mbus_framefmt formats[CAL_CAMERARX_NUM_PADS]; + + /* + * Lock for camerarx ops. Protects: + * - formats + * - enable_count + */ + struct mutex mutex; + + unsigned int enable_count; +}; + +struct cal_dev { + struct clk *fclk; + int irq; + void __iomem *base; + struct resource *res; + struct device *dev; + + const struct cal_data *data; + u32 revision; + + /* Control Module handle */ + struct regmap *syscon_camerrx; + u32 syscon_camerrx_offset; + + /* Camera Core Module handle */ + struct cal_camerarx *phy[CAL_NUM_CSI2_PORTS]; + + u32 num_contexts; + struct cal_ctx *ctx[CAL_MAX_NUM_CONTEXT]; + + struct media_device mdev; + struct v4l2_device v4l2_dev; + struct v4l2_async_notifier notifier; + + unsigned long reserved_pix_proc_mask; +}; + +/* + * There is one cal_ctx structure for each camera core context. + */ +struct cal_ctx { + struct v4l2_ctrl_handler ctrl_handler; + struct video_device vdev; + struct media_pad pad; + + struct cal_dev *cal; + struct cal_camerarx *phy; + + /* v4l2_ioctl mutex */ + struct mutex mutex; + + struct cal_dmaqueue dma; + + /* video capture */ + const struct cal_format_info *fmtinfo; + /* Used to store current pixel format */ + struct v4l2_format v_fmt; + + /* Current subdev enumerated format (legacy) */ + const struct cal_format_info **active_fmt; + unsigned int num_active_fmt; + + unsigned int sequence; + struct vb2_queue vb_vidq; + u8 dma_ctx; + u8 cport; + u8 csi2_ctx; + u8 pix_proc; + u8 vc; + u8 datatype; + + bool use_pix_proc; +}; + +extern unsigned int cal_debug; +extern int cal_video_nr; +extern bool cal_mc_api; + +#define cal_dbg(level, cal, fmt, arg...) \ + do { \ + if (cal_debug >= (level)) \ + dev_printk(KERN_DEBUG, (cal)->dev, fmt, ##arg); \ + } while (0) +#define cal_info(cal, fmt, arg...) \ + dev_info((cal)->dev, fmt, ##arg) +#define cal_err(cal, fmt, arg...) \ + dev_err((cal)->dev, fmt, ##arg) + +#define ctx_dbg(level, ctx, fmt, arg...) \ + cal_dbg(level, (ctx)->cal, "ctx%u: " fmt, (ctx)->dma_ctx, ##arg) +#define ctx_info(ctx, fmt, arg...) \ + cal_info((ctx)->cal, "ctx%u: " fmt, (ctx)->dma_ctx, ##arg) +#define ctx_err(ctx, fmt, arg...) \ + cal_err((ctx)->cal, "ctx%u: " fmt, (ctx)->dma_ctx, ##arg) + +#define phy_dbg(level, phy, fmt, arg...) \ + cal_dbg(level, (phy)->cal, "phy%u: " fmt, (phy)->instance, ##arg) +#define phy_info(phy, fmt, arg...) \ + cal_info((phy)->cal, "phy%u: " fmt, (phy)->instance, ##arg) +#define phy_err(phy, fmt, arg...) \ + cal_err((phy)->cal, "phy%u: " fmt, (phy)->instance, ##arg) + +static inline u32 cal_read(struct cal_dev *cal, u32 offset) +{ + return ioread32(cal->base + offset); +} + +static inline void cal_write(struct cal_dev *cal, u32 offset, u32 val) +{ + iowrite32(val, cal->base + offset); +} + +static __always_inline u32 cal_read_field(struct cal_dev *cal, u32 offset, u32 mask) +{ + return FIELD_GET(mask, cal_read(cal, offset)); +} + +static inline void cal_write_field(struct cal_dev *cal, u32 offset, u32 value, + u32 mask) +{ + u32 val = cal_read(cal, offset); + + val &= ~mask; + val |= (value << __ffs(mask)) & mask; + cal_write(cal, offset, val); +} + +static inline void cal_set_field(u32 *valp, u32 field, u32 mask) +{ + u32 val = *valp; + + val &= ~mask; + val |= (field << __ffs(mask)) & mask; + *valp = val; +} + +extern const struct cal_format_info cal_formats[]; +extern const unsigned int cal_num_formats; +const struct cal_format_info *cal_format_by_fourcc(u32 fourcc); +const struct cal_format_info *cal_format_by_code(u32 code); + +void cal_quickdump_regs(struct cal_dev *cal); + +void cal_camerarx_disable(struct cal_camerarx *phy); +void cal_camerarx_i913_errata(struct cal_camerarx *phy); +struct cal_camerarx *cal_camerarx_create(struct cal_dev *cal, + unsigned int instance); +void cal_camerarx_destroy(struct cal_camerarx *phy); + +int cal_ctx_prepare(struct cal_ctx *ctx); +void cal_ctx_unprepare(struct cal_ctx *ctx); +void cal_ctx_set_dma_addr(struct cal_ctx *ctx, dma_addr_t addr); +void cal_ctx_start(struct cal_ctx *ctx); +void cal_ctx_stop(struct cal_ctx *ctx); + +int cal_ctx_v4l2_register(struct cal_ctx *ctx); +void cal_ctx_v4l2_unregister(struct cal_ctx *ctx); +int cal_ctx_v4l2_init(struct cal_ctx *ctx); +void cal_ctx_v4l2_cleanup(struct cal_ctx *ctx); + +#endif /* __TI_CAL_H__ */ diff --git a/drivers/media/platform/ti/cal/cal_regs.h b/drivers/media/platform/ti/cal/cal_regs.h new file mode 100644 index 000000000000..40e4f972fcb7 --- /dev/null +++ b/drivers/media/platform/ti/cal/cal_regs.h @@ -0,0 +1,463 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * TI CAL camera interface driver + * + * Copyright (c) 2015 Texas Instruments Inc. + * + * Benoit Parrot, + */ + +#ifndef __TI_CAL_REGS_H +#define __TI_CAL_REGS_H + +/* + * struct cal_dev.flags possibilities + * + * DRA72_CAL_PRE_ES2_LDO_DISABLE: + * Errata i913: CSI2 LDO Needs to be disabled when module is powered on + * + * Enabling CSI2 LDO shorts it to core supply. It is crucial the 2 CSI2 + * LDOs on the device are disabled if CSI-2 module is powered on + * (0x4845 B304 | 0x4845 B384 [28:27] = 0x1) or in ULPS (0x4845 B304 + * | 0x4845 B384 [28:27] = 0x2) mode. Common concerns include: high + * current draw on the module supply in active mode. + * + * Errata does not apply when CSI-2 module is powered off + * (0x4845 B304 | 0x4845 B384 [28:27] = 0x0). + * + * SW Workaround: + * Set the following register bits to disable the LDO, + * which is essentially CSI2 REG10 bit 6: + * + * Core 0: 0x4845 B828 = 0x0000 0040 + * Core 1: 0x4845 B928 = 0x0000 0040 + */ +#define DRA72_CAL_PRE_ES2_LDO_DISABLE BIT(0) + +/* CAL register offsets */ + +#define CAL_HL_REVISION 0x0000 +#define CAL_HL_HWINFO 0x0004 +#define CAL_HL_SYSCONFIG 0x0010 +#define CAL_HL_IRQ_EOI 0x001c +#define CAL_HL_IRQSTATUS_RAW(m) (0x20U + (m) * 0x10U) +#define CAL_HL_IRQSTATUS(m) (0x24U + (m) * 0x10U) +#define CAL_HL_IRQENABLE_SET(m) (0x28U + (m) * 0x10U) +#define CAL_HL_IRQENABLE_CLR(m) (0x2cU + (m) * 0x10U) +#define CAL_PIX_PROC(m) (0xc0U + (m) * 0x4U) +#define CAL_CTRL 0x100 +#define CAL_CTRL1 0x104 +#define CAL_LINE_NUMBER_EVT 0x108 +#define CAL_VPORT_CTRL1 0x120 +#define CAL_VPORT_CTRL2 0x124 +#define CAL_BYS_CTRL1 0x130 +#define CAL_BYS_CTRL2 0x134 +#define CAL_RD_DMA_CTRL 0x140 +#define CAL_RD_DMA_PIX_ADDR 0x144 +#define CAL_RD_DMA_PIX_OFST 0x148 +#define CAL_RD_DMA_XSIZE 0x14c +#define CAL_RD_DMA_YSIZE 0x150 +#define CAL_RD_DMA_INIT_ADDR 0x154 +#define CAL_RD_DMA_INIT_OFST 0x168 +#define CAL_RD_DMA_CTRL2 0x16c +#define CAL_WR_DMA_CTRL(m) (0x200U + (m) * 0x10U) +#define CAL_WR_DMA_ADDR(m) (0x204U + (m) * 0x10U) +#define CAL_WR_DMA_OFST(m) (0x208U + (m) * 0x10U) +#define CAL_WR_DMA_XSIZE(m) (0x20cU + (m) * 0x10U) +#define CAL_CSI2_PPI_CTRL(m) (0x300U + (m) * 0x80U) +#define CAL_CSI2_COMPLEXIO_CFG(m) (0x304U + (m) * 0x80U) +#define CAL_CSI2_COMPLEXIO_IRQSTATUS(m) (0x308U + (m) * 0x80U) +#define CAL_CSI2_SHORT_PACKET(m) (0x30cU + (m) * 0x80U) +#define CAL_CSI2_COMPLEXIO_IRQENABLE(m) (0x310U + (m) * 0x80U) +#define CAL_CSI2_TIMING(m) (0x314U + (m) * 0x80U) +#define CAL_CSI2_VC_IRQENABLE(m) (0x318U + (m) * 0x80U) +#define CAL_CSI2_VC_IRQSTATUS(m) (0x328U + (m) * 0x80U) +#define CAL_CSI2_CTX(phy, csi2_ctx) (0x330U + (phy) * 0x80U + (csi2_ctx) * 4) +#define CAL_CSI2_STATUS(phy, csi2_ctx) (0x350U + (phy) * 0x80U + (csi2_ctx) * 4) + +/* CAL CSI2 PHY register offsets */ +#define CAL_CSI2_PHY_REG0 0x000 +#define CAL_CSI2_PHY_REG1 0x004 +#define CAL_CSI2_PHY_REG2 0x008 +#define CAL_CSI2_PHY_REG10 0x028 + +/* CAL Control Module Core Camerrx Control register offsets */ +#define CM_CTRL_CORE_CAMERRX_CONTROL 0x000 + +/********************************************************************* +* Field Definition Macros +*********************************************************************/ + +#define CAL_HL_REVISION_MINOR_MASK GENMASK(5, 0) +#define CAL_HL_REVISION_CUSTOM_MASK GENMASK(7, 6) +#define CAL_HL_REVISION_MAJOR_MASK GENMASK(10, 8) +#define CAL_HL_REVISION_RTL_MASK GENMASK(15, 11) +#define CAL_HL_REVISION_FUNC_MASK GENMASK(27, 16) +#define CAL_HL_REVISION_SCHEME_MASK GENMASK(31, 30) +#define CAL_HL_REVISION_SCHEME_H08 1 +#define CAL_HL_REVISION_SCHEME_LEGACY 0 + +#define CAL_HL_HWINFO_WFIFO_MASK GENMASK(3, 0) +#define CAL_HL_HWINFO_RFIFO_MASK GENMASK(7, 4) +#define CAL_HL_HWINFO_PCTX_MASK GENMASK(12, 8) +#define CAL_HL_HWINFO_WCTX_MASK GENMASK(18, 13) +#define CAL_HL_HWINFO_VFIFO_MASK GENMASK(22, 19) +#define CAL_HL_HWINFO_NCPORT_MASK GENMASK(27, 23) +#define CAL_HL_HWINFO_NPPI_CTXS0_MASK GENMASK(29, 28) +#define CAL_HL_HWINFO_NPPI_CTXS1_MASK GENMASK(31, 30) +#define CAL_HL_HWINFO_NPPI_CONTEXTS_ZERO 0 +#define CAL_HL_HWINFO_NPPI_CONTEXTS_FOUR 1 +#define CAL_HL_HWINFO_NPPI_CONTEXTS_EIGHT 2 +#define CAL_HL_HWINFO_NPPI_CONTEXTS_RESERVED 3 + +#define CAL_HL_SYSCONFIG_SOFTRESET_MASK BIT(0) +#define CAL_HL_SYSCONFIG_SOFTRESET_DONE 0x0 +#define CAL_HL_SYSCONFIG_SOFTRESET_PENDING 0x1 +#define CAL_HL_SYSCONFIG_SOFTRESET_NOACTION 0x0 +#define CAL_HL_SYSCONFIG_SOFTRESET_RESET 0x1 +#define CAL_HL_SYSCONFIG_IDLE_MASK GENMASK(3, 2) +#define CAL_HL_SYSCONFIG_IDLEMODE_FORCE 0 +#define CAL_HL_SYSCONFIG_IDLEMODE_NO 1 +#define CAL_HL_SYSCONFIG_IDLEMODE_SMART1 2 +#define CAL_HL_SYSCONFIG_IDLEMODE_SMART2 3 + +#define CAL_HL_IRQ_EOI_LINE_NUMBER_MASK BIT(0) +#define CAL_HL_IRQ_EOI_LINE_NUMBER_READ0 0 +#define CAL_HL_IRQ_EOI_LINE_NUMBER_EOI0 0 + +#define CAL_HL_IRQ_WDMA_END_MASK(m) BIT(m) +#define CAL_HL_IRQ_WDMA_START_MASK(m) BIT(m) + +#define CAL_HL_IRQ_OCPO_ERR_MASK BIT(6) + +#define CAL_HL_IRQ_CIO_MASK(i) BIT(16 + (i) * 8) +#define CAL_HL_IRQ_VC_MASK(i) BIT(17 + (i) * 8) + +#define CAL_PIX_PROC_EN_MASK BIT(0) +#define CAL_PIX_PROC_EXTRACT_MASK GENMASK(4, 1) +#define CAL_PIX_PROC_EXTRACT_B6 0x0 +#define CAL_PIX_PROC_EXTRACT_B7 0x1 +#define CAL_PIX_PROC_EXTRACT_B8 0x2 +#define CAL_PIX_PROC_EXTRACT_B10 0x3 +#define CAL_PIX_PROC_EXTRACT_B10_MIPI 0x4 +#define CAL_PIX_PROC_EXTRACT_B12 0x5 +#define CAL_PIX_PROC_EXTRACT_B12_MIPI 0x6 +#define CAL_PIX_PROC_EXTRACT_B14 0x7 +#define CAL_PIX_PROC_EXTRACT_B14_MIPI 0x8 +#define CAL_PIX_PROC_EXTRACT_B16_BE 0x9 +#define CAL_PIX_PROC_EXTRACT_B16_LE 0xa +#define CAL_PIX_PROC_DPCMD_MASK GENMASK(9, 5) +#define CAL_PIX_PROC_DPCMD_BYPASS 0x0 +#define CAL_PIX_PROC_DPCMD_DPCM_10_8_1 0x2 +#define CAL_PIX_PROC_DPCMD_DPCM_12_8_1 0x8 +#define CAL_PIX_PROC_DPCMD_DPCM_10_7_1 0x4 +#define CAL_PIX_PROC_DPCMD_DPCM_10_7_2 0x5 +#define CAL_PIX_PROC_DPCMD_DPCM_10_6_1 0x6 +#define CAL_PIX_PROC_DPCMD_DPCM_10_6_2 0x7 +#define CAL_PIX_PROC_DPCMD_DPCM_12_7_1 0xa +#define CAL_PIX_PROC_DPCMD_DPCM_12_6_1 0xc +#define CAL_PIX_PROC_DPCMD_DPCM_14_10 0xe +#define CAL_PIX_PROC_DPCMD_DPCM_14_8_1 0x10 +#define CAL_PIX_PROC_DPCMD_DPCM_16_12_1 0x12 +#define CAL_PIX_PROC_DPCMD_DPCM_16_10_1 0x14 +#define CAL_PIX_PROC_DPCMD_DPCM_16_8_1 0x16 +#define CAL_PIX_PROC_DPCME_MASK GENMASK(15, 11) +#define CAL_PIX_PROC_DPCME_BYPASS 0x0 +#define CAL_PIX_PROC_DPCME_DPCM_10_8_1 0x2 +#define CAL_PIX_PROC_DPCME_DPCM_12_8_1 0x8 +#define CAL_PIX_PROC_DPCME_DPCM_14_10 0xe +#define CAL_PIX_PROC_DPCME_DPCM_14_8_1 0x10 +#define CAL_PIX_PROC_DPCME_DPCM_16_12_1 0x12 +#define CAL_PIX_PROC_DPCME_DPCM_16_10_1 0x14 +#define CAL_PIX_PROC_DPCME_DPCM_16_8_1 0x16 +#define CAL_PIX_PROC_PACK_MASK GENMASK(18, 16) +#define CAL_PIX_PROC_PACK_B8 0x0 +#define CAL_PIX_PROC_PACK_B10_MIPI 0x2 +#define CAL_PIX_PROC_PACK_B12 0x3 +#define CAL_PIX_PROC_PACK_B12_MIPI 0x4 +#define CAL_PIX_PROC_PACK_B16 0x5 +#define CAL_PIX_PROC_PACK_ARGB 0x6 +#define CAL_PIX_PROC_CPORT_MASK GENMASK(23, 19) + +#define CAL_CTRL_POSTED_WRITES_MASK BIT(0) +#define CAL_CTRL_POSTED_WRITES_NONPOSTED 0 +#define CAL_CTRL_POSTED_WRITES 1 +#define CAL_CTRL_TAGCNT_MASK GENMASK(4, 1) +#define CAL_CTRL_BURSTSIZE_MASK GENMASK(6, 5) +#define CAL_CTRL_BURSTSIZE_BURST16 0x0 +#define CAL_CTRL_BURSTSIZE_BURST32 0x1 +#define CAL_CTRL_BURSTSIZE_BURST64 0x2 +#define CAL_CTRL_BURSTSIZE_BURST128 0x3 +#define CAL_CTRL_LL_FORCE_STATE_MASK GENMASK(12, 7) +#define CAL_CTRL_MFLAGL_MASK GENMASK(20, 13) +#define CAL_CTRL_PWRSCPCLK_MASK BIT(21) +#define CAL_CTRL_PWRSCPCLK_AUTO 0 +#define CAL_CTRL_PWRSCPCLK_FORCE 1 +#define CAL_CTRL_RD_DMA_STALL_MASK BIT(22) +#define CAL_CTRL_MFLAGH_MASK GENMASK(31, 24) + +#define CAL_CTRL1_PPI_GROUPING_MASK GENMASK(1, 0) +#define CAL_CTRL1_PPI_GROUPING_DISABLED 0 +#define CAL_CTRL1_PPI_GROUPING_RESERVED 1 +#define CAL_CTRL1_PPI_GROUPING_0 2 +#define CAL_CTRL1_PPI_GROUPING_1 3 +#define CAL_CTRL1_INTERLEAVE01_MASK GENMASK(3, 2) +#define CAL_CTRL1_INTERLEAVE01_DISABLED 0 +#define CAL_CTRL1_INTERLEAVE01_PIX1 1 +#define CAL_CTRL1_INTERLEAVE01_PIX4 2 +#define CAL_CTRL1_INTERLEAVE01_RESERVED 3 +#define CAL_CTRL1_INTERLEAVE23_MASK GENMASK(5, 4) +#define CAL_CTRL1_INTERLEAVE23_DISABLED 0 +#define CAL_CTRL1_INTERLEAVE23_PIX1 1 +#define CAL_CTRL1_INTERLEAVE23_PIX4 2 +#define CAL_CTRL1_INTERLEAVE23_RESERVED 3 + +#define CAL_LINE_NUMBER_EVT_CPORT_MASK GENMASK(4, 0) +#define CAL_LINE_NUMBER_EVT_MASK GENMASK(29, 16) + +#define CAL_VPORT_CTRL1_PCLK_MASK GENMASK(16, 0) +#define CAL_VPORT_CTRL1_XBLK_MASK GENMASK(24, 17) +#define CAL_VPORT_CTRL1_YBLK_MASK GENMASK(30, 25) +#define CAL_VPORT_CTRL1_WIDTH_MASK BIT(31) +#define CAL_VPORT_CTRL1_WIDTH_ONE 0 +#define CAL_VPORT_CTRL1_WIDTH_TWO 1 + +#define CAL_VPORT_CTRL2_CPORT_MASK GENMASK(4, 0) +#define CAL_VPORT_CTRL2_FREERUNNING_MASK BIT(15) +#define CAL_VPORT_CTRL2_FREERUNNING_GATED 0 +#define CAL_VPORT_CTRL2_FREERUNNING_FREE 1 +#define CAL_VPORT_CTRL2_FS_RESETS_MASK BIT(16) +#define CAL_VPORT_CTRL2_FS_RESETS_NO 0 +#define CAL_VPORT_CTRL2_FS_RESETS_YES 1 +#define CAL_VPORT_CTRL2_FSM_RESET_MASK BIT(17) +#define CAL_VPORT_CTRL2_FSM_RESET_NOEFFECT 0 +#define CAL_VPORT_CTRL2_FSM_RESET 1 +#define CAL_VPORT_CTRL2_RDY_THR_MASK GENMASK(31, 18) + +#define CAL_BYS_CTRL1_PCLK_MASK GENMASK(16, 0) +#define CAL_BYS_CTRL1_XBLK_MASK GENMASK(24, 17) +#define CAL_BYS_CTRL1_YBLK_MASK GENMASK(30, 25) +#define CAL_BYS_CTRL1_BYSINEN_MASK BIT(31) + +#define CAL_BYS_CTRL2_CPORTIN_MASK GENMASK(4, 0) +#define CAL_BYS_CTRL2_CPORTOUT_MASK GENMASK(9, 5) +#define CAL_BYS_CTRL2_DUPLICATEDDATA_MASK BIT(10) +#define CAL_BYS_CTRL2_DUPLICATEDDATA_NO 0 +#define CAL_BYS_CTRL2_DUPLICATEDDATA_YES 1 +#define CAL_BYS_CTRL2_FREERUNNING_MASK BIT(11) +#define CAL_BYS_CTRL2_FREERUNNING_NO 0 +#define CAL_BYS_CTRL2_FREERUNNING_YES 1 + +#define CAL_RD_DMA_CTRL_GO_MASK BIT(0) +#define CAL_RD_DMA_CTRL_GO_DIS 0 +#define CAL_RD_DMA_CTRL_GO_EN 1 +#define CAL_RD_DMA_CTRL_GO_IDLE 0 +#define CAL_RD_DMA_CTRL_GO_BUSY 1 +#define CAL_RD_DMA_CTRL_INIT_MASK BIT(1) +#define CAL_RD_DMA_CTRL_BW_LIMITER_MASK GENMASK(10, 2) +#define CAL_RD_DMA_CTRL_OCP_TAG_CNT_MASK GENMASK(14, 11) +#define CAL_RD_DMA_CTRL_PCLK_MASK GENMASK(31, 15) + +#define CAL_RD_DMA_PIX_ADDR_MASK GENMASK(31, 3) + +#define CAL_RD_DMA_PIX_OFST_MASK GENMASK(31, 4) + +#define CAL_RD_DMA_XSIZE_MASK GENMASK(31, 19) + +#define CAL_RD_DMA_YSIZE_MASK GENMASK(29, 16) + +#define CAL_RD_DMA_INIT_ADDR_MASK GENMASK(31, 3) + +#define CAL_RD_DMA_INIT_OFST_MASK GENMASK(31, 3) + +#define CAL_RD_DMA_CTRL2_CIRC_MODE_MASK GENMASK(2, 0) +#define CAL_RD_DMA_CTRL2_CIRC_MODE_DIS 0 +#define CAL_RD_DMA_CTRL2_CIRC_MODE_ONE 1 +#define CAL_RD_DMA_CTRL2_CIRC_MODE_FOUR 2 +#define CAL_RD_DMA_CTRL2_CIRC_MODE_SIXTEEN 3 +#define CAL_RD_DMA_CTRL2_CIRC_MODE_SIXTYFOUR 4 +#define CAL_RD_DMA_CTRL2_CIRC_MODE_RESERVED 5 +#define CAL_RD_DMA_CTRL2_ICM_CSTART_MASK BIT(3) +#define CAL_RD_DMA_CTRL2_PATTERN_MASK GENMASK(5, 4) +#define CAL_RD_DMA_CTRL2_PATTERN_LINEAR 0 +#define CAL_RD_DMA_CTRL2_PATTERN_YUV420 1 +#define CAL_RD_DMA_CTRL2_PATTERN_RD2SKIP2 2 +#define CAL_RD_DMA_CTRL2_PATTERN_RD2SKIP4 3 +#define CAL_RD_DMA_CTRL2_BYSOUT_LE_WAIT_MASK BIT(6) +#define CAL_RD_DMA_CTRL2_BYSOUT_LE_WAIT_FREERUNNING 0 +#define CAL_RD_DMA_CTRL2_BYSOUT_LE_WAIT_WAITFORBYSOUT 1 +#define CAL_RD_DMA_CTRL2_CIRC_SIZE_MASK GENMASK(29, 16) + +#define CAL_WR_DMA_CTRL_MODE_MASK GENMASK(2, 0) +#define CAL_WR_DMA_CTRL_MODE_DIS 0 +#define CAL_WR_DMA_CTRL_MODE_SHD 1 +#define CAL_WR_DMA_CTRL_MODE_CNT 2 +#define CAL_WR_DMA_CTRL_MODE_CNT_INIT 3 +#define CAL_WR_DMA_CTRL_MODE_CONST 4 +#define CAL_WR_DMA_CTRL_MODE_RESERVED 5 +#define CAL_WR_DMA_CTRL_PATTERN_MASK GENMASK(4, 3) +#define CAL_WR_DMA_CTRL_PATTERN_LINEAR 0 +#define CAL_WR_DMA_CTRL_PATTERN_WR2SKIP2 2 +#define CAL_WR_DMA_CTRL_PATTERN_WR2SKIP4 3 +#define CAL_WR_DMA_CTRL_PATTERN_RESERVED 1 +#define CAL_WR_DMA_CTRL_ICM_PSTART_MASK BIT(5) +#define CAL_WR_DMA_CTRL_DTAG_MASK GENMASK(8, 6) +#define CAL_WR_DMA_CTRL_DTAG_ATT_HDR 0 +#define CAL_WR_DMA_CTRL_DTAG_ATT_DAT 1 +#define CAL_WR_DMA_CTRL_DTAG 2 +#define CAL_WR_DMA_CTRL_DTAG_PIX_HDR 3 +#define CAL_WR_DMA_CTRL_DTAG_PIX_DAT 4 +#define CAL_WR_DMA_CTRL_DTAG_D5 5 +#define CAL_WR_DMA_CTRL_DTAG_D6 6 +#define CAL_WR_DMA_CTRL_DTAG_D7 7 +#define CAL_WR_DMA_CTRL_CPORT_MASK GENMASK(13, 9) +#define CAL_WR_DMA_CTRL_STALL_RD_MASK BIT(14) +#define CAL_WR_DMA_CTRL_YSIZE_MASK GENMASK(31, 18) + +#define CAL_WR_DMA_ADDR_MASK GENMASK(31, 4) + +#define CAL_WR_DMA_OFST_MASK GENMASK(18, 4) +#define CAL_WR_DMA_OFST_CIRC_MODE_MASK GENMASK(23, 22) +#define CAL_WR_DMA_OFST_CIRC_MODE_ONE 1 +#define CAL_WR_DMA_OFST_CIRC_MODE_FOUR 2 +#define CAL_WR_DMA_OFST_CIRC_MODE_SIXTYFOUR 3 +#define CAL_WR_DMA_OFST_CIRC_MODE_DISABLED 0 +#define CAL_WR_DMA_OFST_CIRC_SIZE_MASK GENMASK(31, 24) + +#define CAL_WR_DMA_XSIZE_XSKIP_MASK GENMASK(15, 3) +#define CAL_WR_DMA_XSIZE_MASK GENMASK(31, 19) + +#define CAL_CSI2_PPI_CTRL_IF_EN_MASK BIT(0) +#define CAL_CSI2_PPI_CTRL_ECC_EN_MASK BIT(2) +#define CAL_CSI2_PPI_CTRL_FRAME_MASK BIT(3) +#define CAL_CSI2_PPI_CTRL_FRAME_IMMEDIATE 0 +#define CAL_CSI2_PPI_CTRL_FRAME 1 + +#define CAL_CSI2_COMPLEXIO_CFG_CLOCK_POSITION_MASK GENMASK(2, 0) +#define CAL_CSI2_COMPLEXIO_CFG_POSITION_5 5 +#define CAL_CSI2_COMPLEXIO_CFG_POSITION_4 4 +#define CAL_CSI2_COMPLEXIO_CFG_POSITION_3 3 +#define CAL_CSI2_COMPLEXIO_CFG_POSITION_2 2 +#define CAL_CSI2_COMPLEXIO_CFG_POSITION_1 1 +#define CAL_CSI2_COMPLEXIO_CFG_POSITION_NOT_USED 0 +#define CAL_CSI2_COMPLEXIO_CFG_CLOCK_POL_MASK BIT(3) +#define CAL_CSI2_COMPLEXIO_CFG_POL_PLUSMINUS 0 +#define CAL_CSI2_COMPLEXIO_CFG_POL_MINUSPLUS 1 +#define CAL_CSI2_COMPLEXIO_CFG_DATA1_POSITION_MASK GENMASK(6, 4) +#define CAL_CSI2_COMPLEXIO_CFG_DATA1_POL_MASK BIT(7) +#define CAL_CSI2_COMPLEXIO_CFG_DATA2_POSITION_MASK GENMASK(10, 8) +#define CAL_CSI2_COMPLEXIO_CFG_DATA2_POL_MASK BIT(11) +#define CAL_CSI2_COMPLEXIO_CFG_DATA3_POSITION_MASK GENMASK(14, 12) +#define CAL_CSI2_COMPLEXIO_CFG_DATA3_POL_MASK BIT(15) +#define CAL_CSI2_COMPLEXIO_CFG_DATA4_POSITION_MASK GENMASK(18, 16) +#define CAL_CSI2_COMPLEXIO_CFG_DATA4_POL_MASK BIT(19) +#define CAL_CSI2_COMPLEXIO_CFG_PWR_AUTO_MASK BIT(24) +#define CAL_CSI2_COMPLEXIO_CFG_PWR_STATUS_MASK GENMASK(26, 25) +#define CAL_CSI2_COMPLEXIO_CFG_PWR_STATUS_STATE_OFF 0 +#define CAL_CSI2_COMPLEXIO_CFG_PWR_STATUS_STATE_ON 1 +#define CAL_CSI2_COMPLEXIO_CFG_PWR_STATUS_STATE_ULP 2 +#define CAL_CSI2_COMPLEXIO_CFG_PWR_CMD_MASK GENMASK(28, 27) +#define CAL_CSI2_COMPLEXIO_CFG_PWR_CMD_STATE_OFF 0 +#define CAL_CSI2_COMPLEXIO_CFG_PWR_CMD_STATE_ON 1 +#define CAL_CSI2_COMPLEXIO_CFG_PWR_CMD_STATE_ULP 2 +#define CAL_CSI2_COMPLEXIO_CFG_RESET_DONE_MASK BIT(29) +#define CAL_CSI2_COMPLEXIO_CFG_RESET_DONE_RESETCOMPLETED 1 +#define CAL_CSI2_COMPLEXIO_CFG_RESET_DONE_RESETONGOING 0 +#define CAL_CSI2_COMPLEXIO_CFG_RESET_CTRL_MASK BIT(30) +#define CAL_CSI2_COMPLEXIO_CFG_RESET_CTRL 0 +#define CAL_CSI2_COMPLEXIO_CFG_RESET_CTRL_OPERATIONAL 1 + +#define CAL_CSI2_SHORT_PACKET_MASK GENMASK(23, 0) + +#define CAL_CSI2_COMPLEXIO_IRQ_ERRSOTHS1_MASK BIT(0) +#define CAL_CSI2_COMPLEXIO_IRQ_ERRSOTHS2_MASK BIT(1) +#define CAL_CSI2_COMPLEXIO_IRQ_ERRSOTHS3_MASK BIT(2) +#define CAL_CSI2_COMPLEXIO_IRQ_ERRSOTHS4_MASK BIT(3) +#define CAL_CSI2_COMPLEXIO_IRQ_ERRSOTHS5_MASK BIT(4) +#define CAL_CSI2_COMPLEXIO_IRQ_ERRSOTSYNCHS1_MASK BIT(5) +#define CAL_CSI2_COMPLEXIO_IRQ_ERRSOTSYNCHS2_MASK BIT(6) +#define CAL_CSI2_COMPLEXIO_IRQ_ERRSOTSYNCHS3_MASK BIT(7) +#define CAL_CSI2_COMPLEXIO_IRQ_ERRSOTSYNCHS4_MASK BIT(8) +#define CAL_CSI2_COMPLEXIO_IRQ_ERRSOTSYNCHS5_MASK BIT(9) +#define CAL_CSI2_COMPLEXIO_IRQ_ERRESC1_MASK BIT(10) +#define CAL_CSI2_COMPLEXIO_IRQ_ERRESC2_MASK BIT(11) +#define CAL_CSI2_COMPLEXIO_IRQ_ERRESC3_MASK BIT(12) +#define CAL_CSI2_COMPLEXIO_IRQ_ERRESC4_MASK BIT(13) +#define CAL_CSI2_COMPLEXIO_IRQ_ERRESC5_MASK BIT(14) +#define CAL_CSI2_COMPLEXIO_IRQ_ERRCONTROL1_MASK BIT(15) +#define CAL_CSI2_COMPLEXIO_IRQ_ERRCONTROL2_MASK BIT(16) +#define CAL_CSI2_COMPLEXIO_IRQ_ERRCONTROL3_MASK BIT(17) +#define CAL_CSI2_COMPLEXIO_IRQ_ERRCONTROL4_MASK BIT(18) +#define CAL_CSI2_COMPLEXIO_IRQ_ERRCONTROL5_MASK BIT(19) +#define CAL_CSI2_COMPLEXIO_IRQ_LANE_ERRORS_MASK GENMASK(19, 0) +#define CAL_CSI2_COMPLEXIO_IRQ_STATEULPM1_MASK BIT(20) +#define CAL_CSI2_COMPLEXIO_IRQ_STATEULPM2_MASK BIT(21) +#define CAL_CSI2_COMPLEXIO_IRQ_STATEULPM3_MASK BIT(22) +#define CAL_CSI2_COMPLEXIO_IRQ_STATEULPM4_MASK BIT(23) +#define CAL_CSI2_COMPLEXIO_IRQ_STATEULPM5_MASK BIT(24) +#define CAL_CSI2_COMPLEXIO_IRQ_STATEALLULPMENTER_MASK BIT(25) +#define CAL_CSI2_COMPLEXIO_IRQ_STATEALLULPMEXIT_MASK BIT(26) +#define CAL_CSI2_COMPLEXIO_IRQ_FIFO_OVR_MASK BIT(27) +#define CAL_CSI2_COMPLEXIO_IRQ_SHORT_PACKET_MASK BIT(28) +#define CAL_CSI2_COMPLEXIO_IRQ_ECC_NO_CORRECTION_MASK BIT(30) + +#define CAL_CSI2_TIMING_STOP_STATE_COUNTER_IO1_MASK GENMASK(12, 0) +#define CAL_CSI2_TIMING_STOP_STATE_X4_IO1_MASK BIT(13) +#define CAL_CSI2_TIMING_STOP_STATE_X16_IO1_MASK BIT(14) +#define CAL_CSI2_TIMING_FORCE_RX_MODE_IO1_MASK BIT(15) + +#define CAL_CSI2_VC_IRQ_FS_IRQ_MASK(n) BIT(0 + ((n) * 8)) +#define CAL_CSI2_VC_IRQ_FE_IRQ_MASK(n) BIT(1 + ((n) * 8)) +#define CAL_CSI2_VC_IRQ_LS_IRQ_MASK(n) BIT(2 + ((n) * 8)) +#define CAL_CSI2_VC_IRQ_LE_IRQ_MASK(n) BIT(3 + ((n) * 8)) +#define CAL_CSI2_VC_IRQ_CS_IRQ_MASK(n) BIT(4 + ((n) * 8)) +#define CAL_CSI2_VC_IRQ_ECC_CORRECTION_IRQ_MASK(n) BIT(5 + ((n) * 8)) + +#define CAL_CSI2_CTX_DT_MASK GENMASK(5, 0) +#define CAL_CSI2_CTX_DT_DISABLED 0 +#define CAL_CSI2_CTX_DT_ANY 1 +#define CAL_CSI2_CTX_VC_MASK GENMASK(7, 6) +#define CAL_CSI2_CTX_CPORT_MASK GENMASK(12, 8) +#define CAL_CSI2_CTX_ATT_MASK BIT(13) +#define CAL_CSI2_CTX_ATT_PIX 0 +#define CAL_CSI2_CTX_ATT 1 +#define CAL_CSI2_CTX_PACK_MODE_MASK BIT(14) +#define CAL_CSI2_CTX_PACK_MODE_LINE 0 +#define CAL_CSI2_CTX_PACK_MODE_FRAME 1 +#define CAL_CSI2_CTX_LINES_MASK GENMASK(29, 16) + +#define CAL_CSI2_STATUS_FRAME_MASK GENMASK(15, 0) + +#define CAL_CSI2_PHY_REG0_THS_SETTLE_MASK GENMASK(7, 0) +#define CAL_CSI2_PHY_REG0_THS_TERM_MASK GENMASK(15, 8) +#define CAL_CSI2_PHY_REG0_HSCLOCKCONFIG_MASK BIT(24) +#define CAL_CSI2_PHY_REG0_HSCLOCKCONFIG_DISABLE 1 +#define CAL_CSI2_PHY_REG0_HSCLOCKCONFIG_ENABLE 0 + +#define CAL_CSI2_PHY_REG1_TCLK_SETTLE_MASK GENMASK(7, 0) +#define CAL_CSI2_PHY_REG1_CTRLCLK_DIV_FACTOR_MASK GENMASK(9, 8) +#define CAL_CSI2_PHY_REG1_DPHY_HS_SYNC_PATTERN_MASK GENMASK(17, 10) +#define CAL_CSI2_PHY_REG1_TCLK_TERM_MASK GENMASK(24, 18) +#define CAL_CSI2_PHY_REG1_CLOCK_MISS_DETECTOR_STATUS_MASK BIT(25) +#define CAL_CSI2_PHY_REG1_CLOCK_MISS_DETECTOR_STATUS_ERROR 1 +#define CAL_CSI2_PHY_REG1_CLOCK_MISS_DETECTOR_STATUS_SUCCESS 0 +#define CAL_CSI2_PHY_REG1_RESET_DONE_STATUS_MASK GENMASK(29, 28) + +#define CAL_CSI2_PHY_REG10_I933_LDO_DISABLE_MASK BIT(6) + +#define CAL_CSI2_PHY_REG2_CCP2_SYNC_PATTERN_MASK GENMASK(23, 0) +#define CAL_CSI2_PHY_REG2_TRIGGER_CMD_RXTRIGESC3_MASK GENMASK(25, 24) +#define CAL_CSI2_PHY_REG2_TRIGGER_CMD_RXTRIGESC2_MASK GENMASK(27, 26) +#define CAL_CSI2_PHY_REG2_TRIGGER_CMD_RXTRIGESC1_MASK GENMASK(29, 28) +#define CAL_CSI2_PHY_REG2_TRIGGER_CMD_RXTRIGESC0_MASK GENMASK(31, 30) + +#define CM_CAMERRX_CTRL_CSI1_CTRLCLKEN_MASK BIT(0) +#define CM_CAMERRX_CTRL_CSI1_CAMMODE_MASK GENMASK(2, 1) +#define CM_CAMERRX_CTRL_CSI1_LANEENABLE_MASK GENMASK(4, 3) +#define CM_CAMERRX_CTRL_CSI1_MODE_MASK BIT(5) +#define CM_CAMERRX_CTRL_CSI0_CTRLCLKEN_MASK BIT(10) +#define CM_CAMERRX_CTRL_CSI0_CAMMODE_MASK GENMASK(12, 11) +#define CM_CAMERRX_CTRL_CSI0_LANEENABLE_MASK GENMASK(16, 13) +#define CM_CAMERRX_CTRL_CSI0_MODE_MASK BIT(17) + +#endif diff --git a/drivers/media/platform/ti/vpe/Makefile b/drivers/media/platform/ti/vpe/Makefile new file mode 100644 index 000000000000..3fadfe084f87 --- /dev/null +++ b/drivers/media/platform/ti/vpe/Makefile @@ -0,0 +1,12 @@ +# SPDX-License-Identifier: GPL-2.0 +obj-$(CONFIG_VIDEO_TI_VPE) += ti-vpe.o +obj-$(CONFIG_VIDEO_TI_VPDMA) += ti-vpdma.o +obj-$(CONFIG_VIDEO_TI_SC) += ti-sc.o +obj-$(CONFIG_VIDEO_TI_CSC) += ti-csc.o + +ti-vpe-y := vpe.o +ti-vpdma-y := vpdma.o +ti-sc-y := sc.o +ti-csc-y := csc.o + +ccflags-$(CONFIG_VIDEO_TI_VPE_DEBUG) += -DDEBUG diff --git a/drivers/media/platform/ti/vpe/csc.c b/drivers/media/platform/ti/vpe/csc.c new file mode 100644 index 000000000000..ff15bc589f1b --- /dev/null +++ b/drivers/media/platform/ti/vpe/csc.c @@ -0,0 +1,279 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Color space converter library + * + * Copyright (c) 2013 Texas Instruments Inc. + * + * David Griego, + * Dale Farnsworth, + * Archit Taneja, + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "csc.h" + +/* + * 12 coefficients in the order: + * a0, b0, c0, a1, b1, c1, a2, b2, c2, d0, d1, d2 + */ +struct quantization { + u16 coeff[12]; +}; + +struct colorspace { + struct quantization limited; + struct quantization full; +}; + +struct encoding_direction { + struct colorspace r601; + struct colorspace r709; +}; + +struct csc_coeffs { + struct encoding_direction y2r; + struct encoding_direction r2y; +}; + +/* default colorspace coefficients */ +static struct csc_coeffs csc_coeffs = { + .y2r = { + .r601 = { + .limited = { + { /* SDTV */ + 0x0400, 0x0000, 0x057D, 0x0400, 0x1EA7, 0x1D35, + 0x0400, 0x06EF, 0x1FFE, 0x0D40, 0x0210, 0x0C88, + } + }, + .full = { + { /* SDTV */ + 0x04A8, 0x1FFE, 0x0662, 0x04A8, 0x1E6F, 0x1CBF, + 0x04A8, 0x0812, 0x1FFF, 0x0C84, 0x0220, 0x0BAC, + } + }, + }, + .r709 = { + .limited = { + { /* HDTV */ + 0x0400, 0x0000, 0x0629, 0x0400, 0x1F45, 0x1E2B, + 0x0400, 0x0742, 0x0000, 0x0CEC, 0x0148, 0x0C60, + } + }, + .full = { + { /* HDTV */ + 0x04A8, 0x0000, 0x072C, 0x04A8, 0x1F26, 0x1DDE, + 0x04A8, 0x0873, 0x0000, 0x0C20, 0x0134, 0x0B7C, + } + }, + }, + }, + .r2y = { + .r601 = { + .limited = { + { /* SDTV */ + 0x0132, 0x0259, 0x0075, 0x1F50, 0x1EA5, 0x020B, + 0x020B, 0x1E4A, 0x1FAB, 0x0000, 0x0200, 0x0200, + } + }, + .full = { + { /* SDTV */ + 0x0107, 0x0204, 0x0064, 0x1F68, 0x1ED6, 0x01C2, + 0x01C2, 0x1E87, 0x1FB7, 0x0040, 0x0200, 0x0200, + } + }, + }, + .r709 = { + .limited = { + { /* HDTV */ + 0x00DA, 0x02DC, 0x004A, 0x1F88, 0x1E6C, 0x020C, + 0x020C, 0x1E24, 0x1FD0, 0x0000, 0x0200, 0x0200, + } + }, + .full = { + { /* HDTV */ + 0x00bb, 0x0275, 0x003f, 0x1f99, 0x1ea5, 0x01c2, + 0x01c2, 0x1e67, 0x1fd7, 0x0040, 0x0200, 0x0200, + } + }, + }, + }, + +}; + +void csc_dump_regs(struct csc_data *csc) +{ + struct device *dev = &csc->pdev->dev; + +#define DUMPREG(r) dev_dbg(dev, "%-35s %08x\n", #r, \ + ioread32(csc->base + CSC_##r)) + + dev_dbg(dev, "CSC Registers @ %pa:\n", &csc->res->start); + + DUMPREG(CSC00); + DUMPREG(CSC01); + DUMPREG(CSC02); + DUMPREG(CSC03); + DUMPREG(CSC04); + DUMPREG(CSC05); + +#undef DUMPREG +} +EXPORT_SYMBOL(csc_dump_regs); + +void csc_set_coeff_bypass(struct csc_data *csc, u32 *csc_reg5) +{ + *csc_reg5 |= CSC_BYPASS; +} +EXPORT_SYMBOL(csc_set_coeff_bypass); + +/* + * set the color space converter coefficient shadow register values + */ +void csc_set_coeff(struct csc_data *csc, u32 *csc_reg0, + struct v4l2_format *src_fmt, struct v4l2_format *dst_fmt) +{ + u32 *csc_reg5 = csc_reg0 + 5; + u32 *shadow_csc = csc_reg0; + u16 *coeff, *end_coeff; + const struct v4l2_pix_format *pix; + const struct v4l2_pix_format_mplane *mp; + const struct v4l2_format_info *src_finfo, *dst_finfo; + enum v4l2_ycbcr_encoding src_ycbcr_enc, dst_ycbcr_enc; + enum v4l2_quantization src_quantization, dst_quantization; + u32 src_pixelformat, dst_pixelformat; + + if (V4L2_TYPE_IS_MULTIPLANAR(src_fmt->type)) { + mp = &src_fmt->fmt.pix_mp; + src_pixelformat = mp->pixelformat; + src_ycbcr_enc = mp->ycbcr_enc; + src_quantization = mp->quantization; + } else { + pix = &src_fmt->fmt.pix; + src_pixelformat = pix->pixelformat; + src_ycbcr_enc = pix->ycbcr_enc; + src_quantization = pix->quantization; + } + + if (V4L2_TYPE_IS_MULTIPLANAR(dst_fmt->type)) { + mp = &dst_fmt->fmt.pix_mp; + dst_pixelformat = mp->pixelformat; + dst_ycbcr_enc = mp->ycbcr_enc; + dst_quantization = mp->quantization; + } else { + pix = &dst_fmt->fmt.pix; + dst_pixelformat = pix->pixelformat; + dst_ycbcr_enc = pix->ycbcr_enc; + dst_quantization = pix->quantization; + } + + src_finfo = v4l2_format_info(src_pixelformat); + dst_finfo = v4l2_format_info(dst_pixelformat); + + if (v4l2_is_format_yuv(src_finfo) && + v4l2_is_format_rgb(dst_finfo)) { + /* Y2R */ + + /* + * These are not the standard default values but are + * set this way for historical compatibility + */ + if (src_ycbcr_enc == V4L2_YCBCR_ENC_DEFAULT) + src_ycbcr_enc = V4L2_YCBCR_ENC_601; + + if (src_quantization == V4L2_QUANTIZATION_DEFAULT) + src_quantization = V4L2_QUANTIZATION_FULL_RANGE; + + if (src_ycbcr_enc == V4L2_YCBCR_ENC_601) { + if (src_quantization == V4L2_QUANTIZATION_FULL_RANGE) + coeff = csc_coeffs.y2r.r601.full.coeff; + else + coeff = csc_coeffs.y2r.r601.limited.coeff; + } else if (src_ycbcr_enc == V4L2_YCBCR_ENC_709) { + if (src_quantization == V4L2_QUANTIZATION_FULL_RANGE) + coeff = csc_coeffs.y2r.r709.full.coeff; + else + coeff = csc_coeffs.y2r.r709.limited.coeff; + } else { + /* Should never reach this, but it keeps gcc happy */ + coeff = csc_coeffs.y2r.r601.full.coeff; + } + } else if (v4l2_is_format_rgb(src_finfo) && + v4l2_is_format_yuv(dst_finfo)) { + /* R2Y */ + + /* + * These are not the standard default values but are + * set this way for historical compatibility + */ + if (dst_ycbcr_enc == V4L2_YCBCR_ENC_DEFAULT) + dst_ycbcr_enc = V4L2_YCBCR_ENC_601; + + if (dst_quantization == V4L2_QUANTIZATION_DEFAULT) + dst_quantization = V4L2_QUANTIZATION_FULL_RANGE; + + if (dst_ycbcr_enc == V4L2_YCBCR_ENC_601) { + if (dst_quantization == V4L2_QUANTIZATION_FULL_RANGE) + coeff = csc_coeffs.r2y.r601.full.coeff; + else + coeff = csc_coeffs.r2y.r601.limited.coeff; + } else if (dst_ycbcr_enc == V4L2_YCBCR_ENC_709) { + if (dst_quantization == V4L2_QUANTIZATION_FULL_RANGE) + coeff = csc_coeffs.r2y.r709.full.coeff; + else + coeff = csc_coeffs.r2y.r709.limited.coeff; + } else { + /* Should never reach this, but it keeps gcc happy */ + coeff = csc_coeffs.r2y.r601.full.coeff; + } + } else { + *csc_reg5 |= CSC_BYPASS; + return; + } + + end_coeff = coeff + 12; + + for (; coeff < end_coeff; coeff += 2) + *shadow_csc++ = (*(coeff + 1) << 16) | *coeff; +} +EXPORT_SYMBOL(csc_set_coeff); + +struct csc_data *csc_create(struct platform_device *pdev, const char *res_name) +{ + struct csc_data *csc; + + dev_dbg(&pdev->dev, "csc_create\n"); + + csc = devm_kzalloc(&pdev->dev, sizeof(*csc), GFP_KERNEL); + if (!csc) { + dev_err(&pdev->dev, "couldn't alloc csc_data\n"); + return ERR_PTR(-ENOMEM); + } + + csc->pdev = pdev; + + csc->res = platform_get_resource_byname(pdev, IORESOURCE_MEM, + res_name); + if (csc->res == NULL) { + dev_err(&pdev->dev, "missing '%s' platform resources data\n", + res_name); + return ERR_PTR(-ENODEV); + } + + csc->base = devm_ioremap_resource(&pdev->dev, csc->res); + if (IS_ERR(csc->base)) + return ERR_CAST(csc->base); + + return csc; +} +EXPORT_SYMBOL(csc_create); + +MODULE_DESCRIPTION("TI VIP/VPE Color Space Converter"); +MODULE_AUTHOR("Texas Instruments Inc."); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/platform/ti/vpe/csc.h b/drivers/media/platform/ti/vpe/csc.h new file mode 100644 index 000000000000..af2e86bccf57 --- /dev/null +++ b/drivers/media/platform/ti/vpe/csc.h @@ -0,0 +1,65 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2013 Texas Instruments Inc. + * + * David Griego, + * Dale Farnsworth, + * Archit Taneja, + */ +#ifndef TI_CSC_H +#define TI_CSC_H + +/* VPE color space converter regs */ +#define CSC_CSC00 0x00 +#define CSC_A0_MASK 0x1fff +#define CSC_A0_SHIFT 0 +#define CSC_B0_MASK 0x1fff +#define CSC_B0_SHIFT 16 + +#define CSC_CSC01 0x04 +#define CSC_C0_MASK 0x1fff +#define CSC_C0_SHIFT 0 +#define CSC_A1_MASK 0x1fff +#define CSC_A1_SHIFT 16 + +#define CSC_CSC02 0x08 +#define CSC_B1_MASK 0x1fff +#define CSC_B1_SHIFT 0 +#define CSC_C1_MASK 0x1fff +#define CSC_C1_SHIFT 16 + +#define CSC_CSC03 0x0c +#define CSC_A2_MASK 0x1fff +#define CSC_A2_SHIFT 0 +#define CSC_B2_MASK 0x1fff +#define CSC_B2_SHIFT 16 + +#define CSC_CSC04 0x10 +#define CSC_C2_MASK 0x1fff +#define CSC_C2_SHIFT 0 +#define CSC_D0_MASK 0x0fff +#define CSC_D0_SHIFT 16 + +#define CSC_CSC05 0x14 +#define CSC_D1_MASK 0x0fff +#define CSC_D1_SHIFT 0 +#define CSC_D2_MASK 0x0fff +#define CSC_D2_SHIFT 16 + +#define CSC_BYPASS (1 << 28) + +struct csc_data { + void __iomem *base; + struct resource *res; + + struct platform_device *pdev; +}; + +void csc_dump_regs(struct csc_data *csc); +void csc_set_coeff_bypass(struct csc_data *csc, u32 *csc_reg5); +void csc_set_coeff(struct csc_data *csc, u32 *csc_reg0, + struct v4l2_format *src_fmt, struct v4l2_format *dst_fmt); + +struct csc_data *csc_create(struct platform_device *pdev, const char *res_name); + +#endif diff --git a/drivers/media/platform/ti/vpe/sc.c b/drivers/media/platform/ti/vpe/sc.c new file mode 100644 index 000000000000..0202d278523f --- /dev/null +++ b/drivers/media/platform/ti/vpe/sc.c @@ -0,0 +1,306 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Scaler library + * + * Copyright (c) 2013 Texas Instruments Inc. + * + * David Griego, + * Dale Farnsworth, + * Archit Taneja, + */ + +#include +#include +#include +#include +#include + +#include "sc.h" +#include "sc_coeff.h" + +void sc_dump_regs(struct sc_data *sc) +{ + struct device *dev = &sc->pdev->dev; + +#define DUMPREG(r) dev_dbg(dev, "%-35s %08x\n", #r, \ + ioread32(sc->base + CFG_##r)) + + dev_dbg(dev, "SC Registers @ %pa:\n", &sc->res->start); + + DUMPREG(SC0); + DUMPREG(SC1); + DUMPREG(SC2); + DUMPREG(SC3); + DUMPREG(SC4); + DUMPREG(SC5); + DUMPREG(SC6); + DUMPREG(SC8); + DUMPREG(SC9); + DUMPREG(SC10); + DUMPREG(SC11); + DUMPREG(SC12); + DUMPREG(SC13); + DUMPREG(SC17); + DUMPREG(SC18); + DUMPREG(SC19); + DUMPREG(SC20); + DUMPREG(SC21); + DUMPREG(SC22); + DUMPREG(SC23); + DUMPREG(SC24); + DUMPREG(SC25); + +#undef DUMPREG +} +EXPORT_SYMBOL(sc_dump_regs); + +/* + * set the horizontal scaler coefficients according to the ratio of output to + * input widths, after accounting for up to two levels of decimation + */ +void sc_set_hs_coeffs(struct sc_data *sc, void *addr, unsigned int src_w, + unsigned int dst_w) +{ + int sixteenths; + int idx; + int i, j; + u16 *coeff_h = addr; + const u16 *cp; + + if (dst_w > src_w) { + idx = HS_UP_SCALE; + } else { + if ((dst_w << 1) < src_w) + dst_w <<= 1; /* first level decimation */ + if ((dst_w << 1) < src_w) + dst_w <<= 1; /* second level decimation */ + + if (dst_w == src_w) { + idx = HS_LE_16_16_SCALE; + } else { + sixteenths = (dst_w << 4) / src_w; + if (sixteenths < 8) + sixteenths = 8; + idx = HS_LT_9_16_SCALE + sixteenths - 8; + } + } + + cp = scaler_hs_coeffs[idx]; + + for (i = 0; i < SC_NUM_PHASES * 2; i++) { + for (j = 0; j < SC_H_NUM_TAPS; j++) + *coeff_h++ = *cp++; + /* + * for each phase, the scaler expects space for 8 coefficients + * in it's memory. For the horizontal scaler, we copy the first + * 7 coefficients and skip the last slot to move to the next + * row to hold coefficients for the next phase + */ + coeff_h += SC_NUM_TAPS_MEM_ALIGN - SC_H_NUM_TAPS; + } + + sc->load_coeff_h = true; +} +EXPORT_SYMBOL(sc_set_hs_coeffs); + +/* + * set the vertical scaler coefficients according to the ratio of output to + * input heights + */ +void sc_set_vs_coeffs(struct sc_data *sc, void *addr, unsigned int src_h, + unsigned int dst_h) +{ + int sixteenths; + int idx; + int i, j; + u16 *coeff_v = addr; + const u16 *cp; + + if (dst_h > src_h) { + idx = VS_UP_SCALE; + } else if (dst_h == src_h) { + idx = VS_1_TO_1_SCALE; + } else { + sixteenths = (dst_h << 4) / src_h; + if (sixteenths < 8) + sixteenths = 8; + idx = VS_LT_9_16_SCALE + sixteenths - 8; + } + + cp = scaler_vs_coeffs[idx]; + + for (i = 0; i < SC_NUM_PHASES * 2; i++) { + for (j = 0; j < SC_V_NUM_TAPS; j++) + *coeff_v++ = *cp++; + /* + * for the vertical scaler, we copy the first 5 coefficients and + * skip the last 3 slots to move to the next row to hold + * coefficients for the next phase + */ + coeff_v += SC_NUM_TAPS_MEM_ALIGN - SC_V_NUM_TAPS; + } + + sc->load_coeff_v = true; +} +EXPORT_SYMBOL(sc_set_vs_coeffs); + +void sc_config_scaler(struct sc_data *sc, u32 *sc_reg0, u32 *sc_reg8, + u32 *sc_reg17, unsigned int src_w, unsigned int src_h, + unsigned int dst_w, unsigned int dst_h) +{ + struct device *dev = &sc->pdev->dev; + u32 val; + int dcm_x, dcm_shift; + bool use_rav; + unsigned long lltmp; + u32 lin_acc_inc, lin_acc_inc_u; + u32 col_acc_offset; + u16 factor = 0; + int row_acc_init_rav = 0, row_acc_init_rav_b = 0; + u32 row_acc_inc = 0, row_acc_offset = 0, row_acc_offset_b = 0; + /* + * location of SC register in payload memory with respect to the first + * register in the mmr address data block + */ + u32 *sc_reg9 = sc_reg8 + 1; + u32 *sc_reg12 = sc_reg8 + 4; + u32 *sc_reg13 = sc_reg8 + 5; + u32 *sc_reg24 = sc_reg17 + 7; + + val = sc_reg0[0]; + + /* clear all the features(they may get enabled elsewhere later) */ + val &= ~(CFG_SELFGEN_FID | CFG_TRIM | CFG_ENABLE_SIN2_VER_INTP | + CFG_INTERLACE_I | CFG_DCM_4X | CFG_DCM_2X | CFG_AUTO_HS | + CFG_ENABLE_EV | CFG_USE_RAV | CFG_INVT_FID | CFG_SC_BYPASS | + CFG_INTERLACE_O | CFG_Y_PK_EN | CFG_HP_BYPASS | CFG_LINEAR); + + if (src_w == dst_w && src_h == dst_h) { + val |= CFG_SC_BYPASS; + sc_reg0[0] = val; + return; + } + + /* we only support linear scaling for now */ + val |= CFG_LINEAR; + + /* configure horizontal scaler */ + + /* enable 2X or 4X decimation */ + dcm_x = src_w / dst_w; + if (dcm_x > 4) { + val |= CFG_DCM_4X; + dcm_shift = 2; + } else if (dcm_x > 2) { + val |= CFG_DCM_2X; + dcm_shift = 1; + } else { + dcm_shift = 0; + } + + lltmp = dst_w - 1; + lin_acc_inc = div64_u64(((u64)(src_w >> dcm_shift) - 1) << 24, lltmp); + lin_acc_inc_u = 0; + col_acc_offset = 0; + + dev_dbg(dev, "hs config: src_w = %d, dst_w = %d, decimation = %s, lin_acc_inc = %08x\n", + src_w, dst_w, dcm_shift == 2 ? "4x" : + (dcm_shift == 1 ? "2x" : "none"), lin_acc_inc); + + /* configure vertical scaler */ + + /* use RAV for vertical scaler if vertical downscaling is > 4x */ + if (dst_h < (src_h >> 2)) { + use_rav = true; + val |= CFG_USE_RAV; + } else { + use_rav = false; + } + + if (use_rav) { + /* use RAV */ + factor = (u16) ((dst_h << 10) / src_h); + + row_acc_init_rav = factor + ((1 + factor) >> 1); + if (row_acc_init_rav >= 1024) + row_acc_init_rav -= 1024; + + row_acc_init_rav_b = row_acc_init_rav + + (1 + (row_acc_init_rav >> 1)) - + (1024 >> 1); + + if (row_acc_init_rav_b < 0) { + row_acc_init_rav_b += row_acc_init_rav; + row_acc_init_rav *= 2; + } + + dev_dbg(dev, "vs config(RAV): src_h = %d, dst_h = %d, factor = %d, acc_init = %08x, acc_init_b = %08x\n", + src_h, dst_h, factor, row_acc_init_rav, + row_acc_init_rav_b); + } else { + /* use polyphase */ + row_acc_inc = ((src_h - 1) << 16) / (dst_h - 1); + row_acc_offset = 0; + row_acc_offset_b = 0; + + dev_dbg(dev, "vs config(POLY): src_h = %d, dst_h = %d,row_acc_inc = %08x\n", + src_h, dst_h, row_acc_inc); + } + + + sc_reg0[0] = val; + sc_reg0[1] = row_acc_inc; + sc_reg0[2] = row_acc_offset; + sc_reg0[3] = row_acc_offset_b; + + sc_reg0[4] = ((lin_acc_inc_u & CFG_LIN_ACC_INC_U_MASK) << + CFG_LIN_ACC_INC_U_SHIFT) | (dst_w << CFG_TAR_W_SHIFT) | + (dst_h << CFG_TAR_H_SHIFT); + + sc_reg0[5] = (src_w << CFG_SRC_W_SHIFT) | (src_h << CFG_SRC_H_SHIFT); + + sc_reg0[6] = (row_acc_init_rav_b << CFG_ROW_ACC_INIT_RAV_B_SHIFT) | + (row_acc_init_rav << CFG_ROW_ACC_INIT_RAV_SHIFT); + + *sc_reg9 = lin_acc_inc; + + *sc_reg12 = col_acc_offset << CFG_COL_ACC_OFFSET_SHIFT; + + *sc_reg13 = factor; + + *sc_reg24 = (src_w << CFG_ORG_W_SHIFT) | (src_h << CFG_ORG_H_SHIFT); +} +EXPORT_SYMBOL(sc_config_scaler); + +struct sc_data *sc_create(struct platform_device *pdev, const char *res_name) +{ + struct sc_data *sc; + + dev_dbg(&pdev->dev, "sc_create\n"); + + sc = devm_kzalloc(&pdev->dev, sizeof(*sc), GFP_KERNEL); + if (!sc) { + dev_err(&pdev->dev, "couldn't alloc sc_data\n"); + return ERR_PTR(-ENOMEM); + } + + sc->pdev = pdev; + + sc->res = platform_get_resource_byname(pdev, IORESOURCE_MEM, res_name); + if (!sc->res) { + dev_err(&pdev->dev, "missing '%s' platform resources data\n", + res_name); + return ERR_PTR(-ENODEV); + } + + sc->base = devm_ioremap_resource(&pdev->dev, sc->res); + if (IS_ERR(sc->base)) + return ERR_CAST(sc->base); + + return sc; +} +EXPORT_SYMBOL(sc_create); + +MODULE_DESCRIPTION("TI VIP/VPE Scaler"); +MODULE_AUTHOR("Texas Instruments Inc."); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/platform/ti/vpe/sc.h b/drivers/media/platform/ti/vpe/sc.h new file mode 100644 index 000000000000..d55de44d5257 --- /dev/null +++ b/drivers/media/platform/ti/vpe/sc.h @@ -0,0 +1,208 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2013 Texas Instruments Inc. + * + * David Griego, + * Dale Farnsworth, + * Archit Taneja, + */ +#ifndef TI_SC_H +#define TI_SC_H + +/* Scaler regs */ +#define CFG_SC0 0x0 +#define CFG_INTERLACE_O (1 << 0) +#define CFG_LINEAR (1 << 1) +#define CFG_SC_BYPASS (1 << 2) +#define CFG_INVT_FID (1 << 3) +#define CFG_USE_RAV (1 << 4) +#define CFG_ENABLE_EV (1 << 5) +#define CFG_AUTO_HS (1 << 6) +#define CFG_DCM_2X (1 << 7) +#define CFG_DCM_4X (1 << 8) +#define CFG_HP_BYPASS (1 << 9) +#define CFG_INTERLACE_I (1 << 10) +#define CFG_ENABLE_SIN2_VER_INTP (1 << 11) +#define CFG_Y_PK_EN (1 << 14) +#define CFG_TRIM (1 << 15) +#define CFG_SELFGEN_FID (1 << 16) + +#define CFG_SC1 0x4 +#define CFG_ROW_ACC_INC_MASK 0x07ffffff +#define CFG_ROW_ACC_INC_SHIFT 0 + +#define CFG_SC2 0x08 +#define CFG_ROW_ACC_OFFSET_MASK 0x0fffffff +#define CFG_ROW_ACC_OFFSET_SHIFT 0 + +#define CFG_SC3 0x0c +#define CFG_ROW_ACC_OFFSET_B_MASK 0x0fffffff +#define CFG_ROW_ACC_OFFSET_B_SHIFT 0 + +#define CFG_SC4 0x10 +#define CFG_TAR_H_MASK 0x07ff +#define CFG_TAR_H_SHIFT 0 +#define CFG_TAR_W_MASK 0x07ff +#define CFG_TAR_W_SHIFT 12 +#define CFG_LIN_ACC_INC_U_MASK 0x07 +#define CFG_LIN_ACC_INC_U_SHIFT 24 +#define CFG_NLIN_ACC_INIT_U_MASK 0x07 +#define CFG_NLIN_ACC_INIT_U_SHIFT 28 + +#define CFG_SC5 0x14 +#define CFG_SRC_H_MASK 0x07ff +#define CFG_SRC_H_SHIFT 0 +#define CFG_SRC_W_MASK 0x07ff +#define CFG_SRC_W_SHIFT 12 +#define CFG_NLIN_ACC_INC_U_MASK 0x07 +#define CFG_NLIN_ACC_INC_U_SHIFT 24 + +#define CFG_SC6 0x18 +#define CFG_ROW_ACC_INIT_RAV_MASK 0x03ff +#define CFG_ROW_ACC_INIT_RAV_SHIFT 0 +#define CFG_ROW_ACC_INIT_RAV_B_MASK 0x03ff +#define CFG_ROW_ACC_INIT_RAV_B_SHIFT 10 + +#define CFG_SC8 0x20 +#define CFG_NLIN_LEFT_MASK 0x07ff +#define CFG_NLIN_LEFT_SHIFT 0 +#define CFG_NLIN_RIGHT_MASK 0x07ff +#define CFG_NLIN_RIGHT_SHIFT 12 + +#define CFG_SC9 0x24 +#define CFG_LIN_ACC_INC CFG_SC9 + +#define CFG_SC10 0x28 +#define CFG_NLIN_ACC_INIT CFG_SC10 + +#define CFG_SC11 0x2c +#define CFG_NLIN_ACC_INC CFG_SC11 + +#define CFG_SC12 0x30 +#define CFG_COL_ACC_OFFSET_MASK 0x01ffffff +#define CFG_COL_ACC_OFFSET_SHIFT 0 + +#define CFG_SC13 0x34 +#define CFG_SC_FACTOR_RAV_MASK 0xff +#define CFG_SC_FACTOR_RAV_SHIFT 0 +#define CFG_CHROMA_INTP_THR_MASK 0x03ff +#define CFG_CHROMA_INTP_THR_SHIFT 12 +#define CFG_DELTA_CHROMA_THR_MASK 0x0f +#define CFG_DELTA_CHROMA_THR_SHIFT 24 + +#define CFG_SC17 0x44 +#define CFG_EV_THR_MASK 0x03ff +#define CFG_EV_THR_SHIFT 12 +#define CFG_DELTA_LUMA_THR_MASK 0x0f +#define CFG_DELTA_LUMA_THR_SHIFT 24 +#define CFG_DELTA_EV_THR_MASK 0x0f +#define CFG_DELTA_EV_THR_SHIFT 28 + +#define CFG_SC18 0x48 +#define CFG_HS_FACTOR_MASK 0x03ff +#define CFG_HS_FACTOR_SHIFT 0 +#define CFG_CONF_DEFAULT_MASK 0x01ff +#define CFG_CONF_DEFAULT_SHIFT 16 + +#define CFG_SC19 0x4c +#define CFG_HPF_COEFF0_MASK 0xff +#define CFG_HPF_COEFF0_SHIFT 0 +#define CFG_HPF_COEFF1_MASK 0xff +#define CFG_HPF_COEFF1_SHIFT 8 +#define CFG_HPF_COEFF2_MASK 0xff +#define CFG_HPF_COEFF2_SHIFT 16 +#define CFG_HPF_COEFF3_MASK 0xff +#define CFG_HPF_COEFF3_SHIFT 23 + +#define CFG_SC20 0x50 +#define CFG_HPF_COEFF4_MASK 0xff +#define CFG_HPF_COEFF4_SHIFT 0 +#define CFG_HPF_COEFF5_MASK 0xff +#define CFG_HPF_COEFF5_SHIFT 8 +#define CFG_HPF_NORM_SHIFT_MASK 0x07 +#define CFG_HPF_NORM_SHIFT_SHIFT 16 +#define CFG_NL_LIMIT_MASK 0x1ff +#define CFG_NL_LIMIT_SHIFT 20 + +#define CFG_SC21 0x54 +#define CFG_NL_LO_THR_MASK 0x01ff +#define CFG_NL_LO_THR_SHIFT 0 +#define CFG_NL_LO_SLOPE_MASK 0xff +#define CFG_NL_LO_SLOPE_SHIFT 16 + +#define CFG_SC22 0x58 +#define CFG_NL_HI_THR_MASK 0x01ff +#define CFG_NL_HI_THR_SHIFT 0 +#define CFG_NL_HI_SLOPE_SH_MASK 0x07 +#define CFG_NL_HI_SLOPE_SH_SHIFT 16 + +#define CFG_SC23 0x5c +#define CFG_GRADIENT_THR_MASK 0x07ff +#define CFG_GRADIENT_THR_SHIFT 0 +#define CFG_GRADIENT_THR_RANGE_MASK 0x0f +#define CFG_GRADIENT_THR_RANGE_SHIFT 12 +#define CFG_MIN_GY_THR_MASK 0xff +#define CFG_MIN_GY_THR_SHIFT 16 +#define CFG_MIN_GY_THR_RANGE_MASK 0x0f +#define CFG_MIN_GY_THR_RANGE_SHIFT 28 + +#define CFG_SC24 0x60 +#define CFG_ORG_H_MASK 0x07ff +#define CFG_ORG_H_SHIFT 0 +#define CFG_ORG_W_MASK 0x07ff +#define CFG_ORG_W_SHIFT 16 + +#define CFG_SC25 0x64 +#define CFG_OFF_H_MASK 0x07ff +#define CFG_OFF_H_SHIFT 0 +#define CFG_OFF_W_MASK 0x07ff +#define CFG_OFF_W_SHIFT 16 + +/* number of phases supported by the polyphase scalers */ +#define SC_NUM_PHASES 32 + +/* number of taps used by horizontal polyphase scaler */ +#define SC_H_NUM_TAPS 7 + +/* number of taps used by vertical polyphase scaler */ +#define SC_V_NUM_TAPS 5 + +/* number of taps expected by the scaler in it's coefficient memory */ +#define SC_NUM_TAPS_MEM_ALIGN 8 + +/* Maximum frame width the scaler can handle (in pixels) */ +#define SC_MAX_PIXEL_WIDTH 2047 + +/* Maximum frame height the scaler can handle (in lines) */ +#define SC_MAX_PIXEL_HEIGHT 2047 + +/* + * coefficient memory size in bytes: + * num phases x num sets(luma and chroma) x num taps(aligned) x coeff size + */ +#define SC_COEF_SRAM_SIZE (SC_NUM_PHASES * 2 * SC_NUM_TAPS_MEM_ALIGN * 2) + +struct sc_data { + void __iomem *base; + struct resource *res; + + dma_addr_t loaded_coeff_h; /* loaded h coeffs in SC */ + dma_addr_t loaded_coeff_v; /* loaded v coeffs in SC */ + + bool load_coeff_h; /* have new h SC coeffs */ + bool load_coeff_v; /* have new v SC coeffs */ + + struct platform_device *pdev; +}; + +void sc_dump_regs(struct sc_data *sc); +void sc_set_hs_coeffs(struct sc_data *sc, void *addr, unsigned int src_w, + unsigned int dst_w); +void sc_set_vs_coeffs(struct sc_data *sc, void *addr, unsigned int src_h, + unsigned int dst_h); +void sc_config_scaler(struct sc_data *sc, u32 *sc_reg0, u32 *sc_reg8, + u32 *sc_reg17, unsigned int src_w, unsigned int src_h, + unsigned int dst_w, unsigned int dst_h); +struct sc_data *sc_create(struct platform_device *pdev, const char *res_name); + +#endif diff --git a/drivers/media/platform/ti/vpe/sc_coeff.h b/drivers/media/platform/ti/vpe/sc_coeff.h new file mode 100644 index 000000000000..c525d1764099 --- /dev/null +++ b/drivers/media/platform/ti/vpe/sc_coeff.h @@ -0,0 +1,1339 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * VPE SC coefs + * + * Copyright (c) 2013 Texas Instruments Inc. + * + * David Griego, + * Dale Farnsworth, + * Archit Taneja, + */ + +#ifndef __TI_SC_COEFF_H +#define __TI_SC_COEFF_H + +/* horizontal scaler coefficients */ +enum { + HS_UP_SCALE = 0, + HS_LT_9_16_SCALE, + HS_LT_10_16_SCALE, + HS_LT_11_16_SCALE, + HS_LT_12_16_SCALE, + HS_LT_13_16_SCALE, + HS_LT_14_16_SCALE, + HS_LT_15_16_SCALE, + HS_LE_16_16_SCALE, +}; + +static const u16 scaler_hs_coeffs[13][SC_NUM_PHASES * 2 * SC_H_NUM_TAPS] = { + [HS_UP_SCALE] = { + /* Luma */ + 0x001F, 0x1F90, 0x00D2, 0x06FE, 0x00D2, 0x1F90, 0x001F, + 0x001C, 0x1F9E, 0x009F, 0x06FB, 0x0108, 0x1F82, 0x0022, + 0x0019, 0x1FAC, 0x006F, 0x06F3, 0x0140, 0x1F74, 0x0025, + 0x0016, 0x1FB9, 0x0041, 0x06E7, 0x017B, 0x1F66, 0x0028, + 0x0013, 0x1FC6, 0x0017, 0x06D6, 0x01B7, 0x1F58, 0x002B, + 0x0010, 0x1FD3, 0x1FEF, 0x06C0, 0x01F6, 0x1F4B, 0x002D, + 0x000E, 0x1FDF, 0x1FCB, 0x06A5, 0x0235, 0x1F3F, 0x002F, + 0x000B, 0x1FEA, 0x1FAA, 0x0686, 0x0277, 0x1F33, 0x0031, + 0x0009, 0x1FF5, 0x1F8C, 0x0663, 0x02B8, 0x1F28, 0x0033, + 0x0007, 0x1FFF, 0x1F72, 0x063A, 0x02FB, 0x1F1F, 0x0034, + 0x0005, 0x0008, 0x1F5A, 0x060F, 0x033E, 0x1F17, 0x0035, + 0x0003, 0x0010, 0x1F46, 0x05E0, 0x0382, 0x1F10, 0x0035, + 0x0002, 0x0017, 0x1F34, 0x05AF, 0x03C5, 0x1F0B, 0x0034, + 0x0001, 0x001E, 0x1F26, 0x0579, 0x0407, 0x1F08, 0x0033, + 0x0000, 0x0023, 0x1F1A, 0x0541, 0x0449, 0x1F07, 0x0032, + 0x1FFF, 0x0028, 0x1F12, 0x0506, 0x048A, 0x1F08, 0x002F, + 0x002C, 0x1F0C, 0x04C8, 0x04C8, 0x1F0C, 0x002C, 0x0000, + 0x002F, 0x1F08, 0x048A, 0x0506, 0x1F12, 0x0028, 0x1FFF, + 0x0032, 0x1F07, 0x0449, 0x0541, 0x1F1A, 0x0023, 0x0000, + 0x0033, 0x1F08, 0x0407, 0x0579, 0x1F26, 0x001E, 0x0001, + 0x0034, 0x1F0B, 0x03C5, 0x05AF, 0x1F34, 0x0017, 0x0002, + 0x0035, 0x1F10, 0x0382, 0x05E0, 0x1F46, 0x0010, 0x0003, + 0x0035, 0x1F17, 0x033E, 0x060F, 0x1F5A, 0x0008, 0x0005, + 0x0034, 0x1F1F, 0x02FB, 0x063A, 0x1F72, 0x1FFF, 0x0007, + 0x0033, 0x1F28, 0x02B8, 0x0663, 0x1F8C, 0x1FF5, 0x0009, + 0x0031, 0x1F33, 0x0277, 0x0686, 0x1FAA, 0x1FEA, 0x000B, + 0x002F, 0x1F3F, 0x0235, 0x06A5, 0x1FCB, 0x1FDF, 0x000E, + 0x002D, 0x1F4B, 0x01F6, 0x06C0, 0x1FEF, 0x1FD3, 0x0010, + 0x002B, 0x1F58, 0x01B7, 0x06D6, 0x0017, 0x1FC6, 0x0013, + 0x0028, 0x1F66, 0x017B, 0x06E7, 0x0041, 0x1FB9, 0x0016, + 0x0025, 0x1F74, 0x0140, 0x06F3, 0x006F, 0x1FAC, 0x0019, + 0x0022, 0x1F82, 0x0108, 0x06FB, 0x009F, 0x1F9E, 0x001C, + /* Chroma */ + 0x001F, 0x1F90, 0x00D2, 0x06FE, 0x00D2, 0x1F90, 0x001F, + 0x001C, 0x1F9E, 0x009F, 0x06FB, 0x0108, 0x1F82, 0x0022, + 0x0019, 0x1FAC, 0x006F, 0x06F3, 0x0140, 0x1F74, 0x0025, + 0x0016, 0x1FB9, 0x0041, 0x06E7, 0x017B, 0x1F66, 0x0028, + 0x0013, 0x1FC6, 0x0017, 0x06D6, 0x01B7, 0x1F58, 0x002B, + 0x0010, 0x1FD3, 0x1FEF, 0x06C0, 0x01F6, 0x1F4B, 0x002D, + 0x000E, 0x1FDF, 0x1FCB, 0x06A5, 0x0235, 0x1F3F, 0x002F, + 0x000B, 0x1FEA, 0x1FAA, 0x0686, 0x0277, 0x1F33, 0x0031, + 0x0009, 0x1FF5, 0x1F8C, 0x0663, 0x02B8, 0x1F28, 0x0033, + 0x0007, 0x1FFF, 0x1F72, 0x063A, 0x02FB, 0x1F1F, 0x0034, + 0x0005, 0x0008, 0x1F5A, 0x060F, 0x033E, 0x1F17, 0x0035, + 0x0003, 0x0010, 0x1F46, 0x05E0, 0x0382, 0x1F10, 0x0035, + 0x0002, 0x0017, 0x1F34, 0x05AF, 0x03C5, 0x1F0B, 0x0034, + 0x0001, 0x001E, 0x1F26, 0x0579, 0x0407, 0x1F08, 0x0033, + 0x0000, 0x0023, 0x1F1A, 0x0541, 0x0449, 0x1F07, 0x0032, + 0x1FFF, 0x0028, 0x1F12, 0x0506, 0x048A, 0x1F08, 0x002F, + 0x002C, 0x1F0C, 0x04C8, 0x04C8, 0x1F0C, 0x002C, 0x0000, + 0x002F, 0x1F08, 0x048A, 0x0506, 0x1F12, 0x0028, 0x1FFF, + 0x0032, 0x1F07, 0x0449, 0x0541, 0x1F1A, 0x0023, 0x0000, + 0x0033, 0x1F08, 0x0407, 0x0579, 0x1F26, 0x001E, 0x0001, + 0x0034, 0x1F0B, 0x03C5, 0x05AF, 0x1F34, 0x0017, 0x0002, + 0x0035, 0x1F10, 0x0382, 0x05E0, 0x1F46, 0x0010, 0x0003, + 0x0035, 0x1F17, 0x033E, 0x060F, 0x1F5A, 0x0008, 0x0005, + 0x0034, 0x1F1F, 0x02FB, 0x063A, 0x1F72, 0x1FFF, 0x0007, + 0x0033, 0x1F28, 0x02B8, 0x0663, 0x1F8C, 0x1FF5, 0x0009, + 0x0031, 0x1F33, 0x0277, 0x0686, 0x1FAA, 0x1FEA, 0x000B, + 0x002F, 0x1F3F, 0x0235, 0x06A5, 0x1FCB, 0x1FDF, 0x000E, + 0x002D, 0x1F4B, 0x01F6, 0x06C0, 0x1FEF, 0x1FD3, 0x0010, + 0x002B, 0x1F58, 0x01B7, 0x06D6, 0x0017, 0x1FC6, 0x0013, + 0x0028, 0x1F66, 0x017B, 0x06E7, 0x0041, 0x1FB9, 0x0016, + 0x0025, 0x1F74, 0x0140, 0x06F3, 0x006F, 0x1FAC, 0x0019, + 0x0022, 0x1F82, 0x0108, 0x06FB, 0x009F, 0x1F9E, 0x001C, + }, + [HS_LT_9_16_SCALE] = { + /* Luma */ + 0x1FA3, 0x005E, 0x024A, 0x036A, 0x024A, 0x005E, 0x1FA3, + 0x1FA3, 0x0052, 0x023A, 0x036A, 0x0259, 0x006A, 0x1FA4, + 0x1FA3, 0x0046, 0x022A, 0x036A, 0x0269, 0x0076, 0x1FA4, + 0x1FA3, 0x003B, 0x021A, 0x0368, 0x0278, 0x0083, 0x1FA5, + 0x1FA4, 0x0031, 0x020A, 0x0365, 0x0286, 0x0090, 0x1FA6, + 0x1FA5, 0x0026, 0x01F9, 0x0362, 0x0294, 0x009E, 0x1FA8, + 0x1FA6, 0x001C, 0x01E8, 0x035E, 0x02A3, 0x00AB, 0x1FAA, + 0x1FA7, 0x0013, 0x01D7, 0x035A, 0x02B0, 0x00B9, 0x1FAC, + 0x1FA9, 0x000A, 0x01C6, 0x0354, 0x02BD, 0x00C7, 0x1FAF, + 0x1FAA, 0x0001, 0x01B6, 0x034E, 0x02C9, 0x00D6, 0x1FB2, + 0x1FAC, 0x1FF9, 0x01A5, 0x0347, 0x02D5, 0x00E5, 0x1FB5, + 0x1FAE, 0x1FF1, 0x0194, 0x0340, 0x02E1, 0x00F3, 0x1FB9, + 0x1FB0, 0x1FEA, 0x0183, 0x0338, 0x02EC, 0x0102, 0x1FBD, + 0x1FB2, 0x1FE3, 0x0172, 0x0330, 0x02F6, 0x0112, 0x1FC1, + 0x1FB4, 0x1FDC, 0x0161, 0x0327, 0x0301, 0x0121, 0x1FC6, + 0x1FB7, 0x1FD6, 0x0151, 0x031D, 0x030A, 0x0130, 0x1FCB, + 0x1FD2, 0x0136, 0x02F8, 0x02F8, 0x0136, 0x1FD2, 0x0000, + 0x1FCB, 0x0130, 0x030A, 0x031D, 0x0151, 0x1FD6, 0x1FB7, + 0x1FC6, 0x0121, 0x0301, 0x0327, 0x0161, 0x1FDC, 0x1FB4, + 0x1FC1, 0x0112, 0x02F6, 0x0330, 0x0172, 0x1FE3, 0x1FB2, + 0x1FBD, 0x0102, 0x02EC, 0x0338, 0x0183, 0x1FEA, 0x1FB0, + 0x1FB9, 0x00F3, 0x02E1, 0x0340, 0x0194, 0x1FF1, 0x1FAE, + 0x1FB5, 0x00E5, 0x02D5, 0x0347, 0x01A5, 0x1FF9, 0x1FAC, + 0x1FB2, 0x00D6, 0x02C9, 0x034E, 0x01B6, 0x0001, 0x1FAA, + 0x1FAF, 0x00C7, 0x02BD, 0x0354, 0x01C6, 0x000A, 0x1FA9, + 0x1FAC, 0x00B9, 0x02B0, 0x035A, 0x01D7, 0x0013, 0x1FA7, + 0x1FAA, 0x00AB, 0x02A3, 0x035E, 0x01E8, 0x001C, 0x1FA6, + 0x1FA8, 0x009E, 0x0294, 0x0362, 0x01F9, 0x0026, 0x1FA5, + 0x1FA6, 0x0090, 0x0286, 0x0365, 0x020A, 0x0031, 0x1FA4, + 0x1FA5, 0x0083, 0x0278, 0x0368, 0x021A, 0x003B, 0x1FA3, + 0x1FA4, 0x0076, 0x0269, 0x036A, 0x022A, 0x0046, 0x1FA3, + 0x1FA4, 0x006A, 0x0259, 0x036A, 0x023A, 0x0052, 0x1FA3, + /* Chroma */ + 0x1FA3, 0x005E, 0x024A, 0x036A, 0x024A, 0x005E, 0x1FA3, + 0x1FA3, 0x0052, 0x023A, 0x036A, 0x0259, 0x006A, 0x1FA4, + 0x1FA3, 0x0046, 0x022A, 0x036A, 0x0269, 0x0076, 0x1FA4, + 0x1FA3, 0x003B, 0x021A, 0x0368, 0x0278, 0x0083, 0x1FA5, + 0x1FA4, 0x0031, 0x020A, 0x0365, 0x0286, 0x0090, 0x1FA6, + 0x1FA5, 0x0026, 0x01F9, 0x0362, 0x0294, 0x009E, 0x1FA8, + 0x1FA6, 0x001C, 0x01E8, 0x035E, 0x02A3, 0x00AB, 0x1FAA, + 0x1FA7, 0x0013, 0x01D7, 0x035A, 0x02B0, 0x00B9, 0x1FAC, + 0x1FA9, 0x000A, 0x01C6, 0x0354, 0x02BD, 0x00C7, 0x1FAF, + 0x1FAA, 0x0001, 0x01B6, 0x034E, 0x02C9, 0x00D6, 0x1FB2, + 0x1FAC, 0x1FF9, 0x01A5, 0x0347, 0x02D5, 0x00E5, 0x1FB5, + 0x1FAE, 0x1FF1, 0x0194, 0x0340, 0x02E1, 0x00F3, 0x1FB9, + 0x1FB0, 0x1FEA, 0x0183, 0x0338, 0x02EC, 0x0102, 0x1FBD, + 0x1FB2, 0x1FE3, 0x0172, 0x0330, 0x02F6, 0x0112, 0x1FC1, + 0x1FB4, 0x1FDC, 0x0161, 0x0327, 0x0301, 0x0121, 0x1FC6, + 0x1FB7, 0x1FD6, 0x0151, 0x031D, 0x030A, 0x0130, 0x1FCB, + 0x1FD2, 0x0136, 0x02F8, 0x02F8, 0x0136, 0x1FD2, 0x0000, + 0x1FCB, 0x0130, 0x030A, 0x031D, 0x0151, 0x1FD6, 0x1FB7, + 0x1FC6, 0x0121, 0x0301, 0x0327, 0x0161, 0x1FDC, 0x1FB4, + 0x1FC1, 0x0112, 0x02F6, 0x0330, 0x0172, 0x1FE3, 0x1FB2, + 0x1FBD, 0x0102, 0x02EC, 0x0338, 0x0183, 0x1FEA, 0x1FB0, + 0x1FB9, 0x00F3, 0x02E1, 0x0340, 0x0194, 0x1FF1, 0x1FAE, + 0x1FB5, 0x00E5, 0x02D5, 0x0347, 0x01A5, 0x1FF9, 0x1FAC, + 0x1FB2, 0x00D6, 0x02C9, 0x034E, 0x01B6, 0x0001, 0x1FAA, + 0x1FAF, 0x00C7, 0x02BD, 0x0354, 0x01C6, 0x000A, 0x1FA9, + 0x1FAC, 0x00B9, 0x02B0, 0x035A, 0x01D7, 0x0013, 0x1FA7, + 0x1FAA, 0x00AB, 0x02A3, 0x035E, 0x01E8, 0x001C, 0x1FA6, + 0x1FA8, 0x009E, 0x0294, 0x0362, 0x01F9, 0x0026, 0x1FA5, + 0x1FA6, 0x0090, 0x0286, 0x0365, 0x020A, 0x0031, 0x1FA4, + 0x1FA5, 0x0083, 0x0278, 0x0368, 0x021A, 0x003B, 0x1FA3, + 0x1FA4, 0x0076, 0x0269, 0x036A, 0x022A, 0x0046, 0x1FA3, + 0x1FA4, 0x006A, 0x0259, 0x036A, 0x023A, 0x0052, 0x1FA3, + }, + [HS_LT_10_16_SCALE] = { + /* Luma */ + 0x1F8D, 0x000C, 0x026A, 0x03FA, 0x026A, 0x000C, 0x1F8D, + 0x1F8F, 0x0000, 0x0255, 0x03FA, 0x027F, 0x0019, 0x1F8A, + 0x1F92, 0x1FF5, 0x023F, 0x03F8, 0x0293, 0x0027, 0x1F88, + 0x1F95, 0x1FEA, 0x022A, 0x03F6, 0x02A7, 0x0034, 0x1F86, + 0x1F99, 0x1FDF, 0x0213, 0x03F2, 0x02BB, 0x0043, 0x1F85, + 0x1F9C, 0x1FD5, 0x01FE, 0x03ED, 0x02CF, 0x0052, 0x1F83, + 0x1FA0, 0x1FCC, 0x01E8, 0x03E7, 0x02E1, 0x0061, 0x1F83, + 0x1FA4, 0x1FC3, 0x01D2, 0x03E0, 0x02F4, 0x0071, 0x1F82, + 0x1FA7, 0x1FBB, 0x01BC, 0x03D9, 0x0306, 0x0081, 0x1F82, + 0x1FAB, 0x1FB4, 0x01A6, 0x03D0, 0x0317, 0x0092, 0x1F82, + 0x1FAF, 0x1FAD, 0x0190, 0x03C7, 0x0327, 0x00A3, 0x1F83, + 0x1FB3, 0x1FA7, 0x017A, 0x03BC, 0x0337, 0x00B5, 0x1F84, + 0x1FB8, 0x1FA1, 0x0165, 0x03B0, 0x0346, 0x00C7, 0x1F85, + 0x1FBC, 0x1F9C, 0x0150, 0x03A4, 0x0354, 0x00D9, 0x1F87, + 0x1FC0, 0x1F98, 0x013A, 0x0397, 0x0361, 0x00EC, 0x1F8A, + 0x1FC4, 0x1F93, 0x0126, 0x0389, 0x036F, 0x00FE, 0x1F8D, + 0x1F93, 0x010A, 0x0363, 0x0363, 0x010A, 0x1F93, 0x0000, + 0x1F8D, 0x00FE, 0x036F, 0x0389, 0x0126, 0x1F93, 0x1FC4, + 0x1F8A, 0x00EC, 0x0361, 0x0397, 0x013A, 0x1F98, 0x1FC0, + 0x1F87, 0x00D9, 0x0354, 0x03A4, 0x0150, 0x1F9C, 0x1FBC, + 0x1F85, 0x00C7, 0x0346, 0x03B0, 0x0165, 0x1FA1, 0x1FB8, + 0x1F84, 0x00B5, 0x0337, 0x03BC, 0x017A, 0x1FA7, 0x1FB3, + 0x1F83, 0x00A3, 0x0327, 0x03C7, 0x0190, 0x1FAD, 0x1FAF, + 0x1F82, 0x0092, 0x0317, 0x03D0, 0x01A6, 0x1FB4, 0x1FAB, + 0x1F82, 0x0081, 0x0306, 0x03D9, 0x01BC, 0x1FBB, 0x1FA7, + 0x1F82, 0x0071, 0x02F4, 0x03E0, 0x01D2, 0x1FC3, 0x1FA4, + 0x1F83, 0x0061, 0x02E1, 0x03E7, 0x01E8, 0x1FCC, 0x1FA0, + 0x1F83, 0x0052, 0x02CF, 0x03ED, 0x01FE, 0x1FD5, 0x1F9C, + 0x1F85, 0x0043, 0x02BB, 0x03F2, 0x0213, 0x1FDF, 0x1F99, + 0x1F86, 0x0034, 0x02A7, 0x03F6, 0x022A, 0x1FEA, 0x1F95, + 0x1F88, 0x0027, 0x0293, 0x03F8, 0x023F, 0x1FF5, 0x1F92, + 0x1F8A, 0x0019, 0x027F, 0x03FA, 0x0255, 0x0000, 0x1F8F, + /* Chroma */ + 0x1F8D, 0x000C, 0x026A, 0x03FA, 0x026A, 0x000C, 0x1F8D, + 0x1F8F, 0x0000, 0x0255, 0x03FA, 0x027F, 0x0019, 0x1F8A, + 0x1F92, 0x1FF5, 0x023F, 0x03F8, 0x0293, 0x0027, 0x1F88, + 0x1F95, 0x1FEA, 0x022A, 0x03F6, 0x02A7, 0x0034, 0x1F86, + 0x1F99, 0x1FDF, 0x0213, 0x03F2, 0x02BB, 0x0043, 0x1F85, + 0x1F9C, 0x1FD5, 0x01FE, 0x03ED, 0x02CF, 0x0052, 0x1F83, + 0x1FA0, 0x1FCC, 0x01E8, 0x03E7, 0x02E1, 0x0061, 0x1F83, + 0x1FA4, 0x1FC3, 0x01D2, 0x03E0, 0x02F4, 0x0071, 0x1F82, + 0x1FA7, 0x1FBB, 0x01BC, 0x03D9, 0x0306, 0x0081, 0x1F82, + 0x1FAB, 0x1FB4, 0x01A6, 0x03D0, 0x0317, 0x0092, 0x1F82, + 0x1FAF, 0x1FAD, 0x0190, 0x03C7, 0x0327, 0x00A3, 0x1F83, + 0x1FB3, 0x1FA7, 0x017A, 0x03BC, 0x0337, 0x00B5, 0x1F84, + 0x1FB8, 0x1FA1, 0x0165, 0x03B0, 0x0346, 0x00C7, 0x1F85, + 0x1FBC, 0x1F9C, 0x0150, 0x03A4, 0x0354, 0x00D9, 0x1F87, + 0x1FC0, 0x1F98, 0x013A, 0x0397, 0x0361, 0x00EC, 0x1F8A, + 0x1FC4, 0x1F93, 0x0126, 0x0389, 0x036F, 0x00FE, 0x1F8D, + 0x1F93, 0x010A, 0x0363, 0x0363, 0x010A, 0x1F93, 0x0000, + 0x1F8D, 0x00FE, 0x036F, 0x0389, 0x0126, 0x1F93, 0x1FC4, + 0x1F8A, 0x00EC, 0x0361, 0x0397, 0x013A, 0x1F98, 0x1FC0, + 0x1F87, 0x00D9, 0x0354, 0x03A4, 0x0150, 0x1F9C, 0x1FBC, + 0x1F85, 0x00C7, 0x0346, 0x03B0, 0x0165, 0x1FA1, 0x1FB8, + 0x1F84, 0x00B5, 0x0337, 0x03BC, 0x017A, 0x1FA7, 0x1FB3, + 0x1F83, 0x00A3, 0x0327, 0x03C7, 0x0190, 0x1FAD, 0x1FAF, + 0x1F82, 0x0092, 0x0317, 0x03D0, 0x01A6, 0x1FB4, 0x1FAB, + 0x1F82, 0x0081, 0x0306, 0x03D9, 0x01BC, 0x1FBB, 0x1FA7, + 0x1F82, 0x0071, 0x02F4, 0x03E0, 0x01D2, 0x1FC3, 0x1FA4, + 0x1F83, 0x0061, 0x02E1, 0x03E7, 0x01E8, 0x1FCC, 0x1FA0, + 0x1F83, 0x0052, 0x02CF, 0x03ED, 0x01FE, 0x1FD5, 0x1F9C, + 0x1F85, 0x0043, 0x02BB, 0x03F2, 0x0213, 0x1FDF, 0x1F99, + 0x1F86, 0x0034, 0x02A7, 0x03F6, 0x022A, 0x1FEA, 0x1F95, + 0x1F88, 0x0027, 0x0293, 0x03F8, 0x023F, 0x1FF5, 0x1F92, + 0x1F8A, 0x0019, 0x027F, 0x03FA, 0x0255, 0x0000, 0x1F8F, + }, + [HS_LT_11_16_SCALE] = { + /* Luma */ + 0x1F95, 0x1FB5, 0x0272, 0x0488, 0x0272, 0x1FB5, 0x1F95, + 0x1F9B, 0x1FAA, 0x0257, 0x0486, 0x028D, 0x1FC1, 0x1F90, + 0x1FA0, 0x1FA0, 0x023C, 0x0485, 0x02A8, 0x1FCD, 0x1F8A, + 0x1FA6, 0x1F96, 0x0221, 0x0481, 0x02C2, 0x1FDB, 0x1F85, + 0x1FAC, 0x1F8E, 0x0205, 0x047C, 0x02DC, 0x1FE9, 0x1F80, + 0x1FB1, 0x1F86, 0x01E9, 0x0476, 0x02F6, 0x1FF8, 0x1F7C, + 0x1FB7, 0x1F7F, 0x01CE, 0x046E, 0x030F, 0x0008, 0x1F77, + 0x1FBD, 0x1F79, 0x01B3, 0x0465, 0x0326, 0x0019, 0x1F73, + 0x1FC3, 0x1F73, 0x0197, 0x045B, 0x033E, 0x002A, 0x1F70, + 0x1FC8, 0x1F6F, 0x017D, 0x044E, 0x0355, 0x003C, 0x1F6D, + 0x1FCE, 0x1F6B, 0x0162, 0x0441, 0x036B, 0x004F, 0x1F6A, + 0x1FD3, 0x1F68, 0x0148, 0x0433, 0x0380, 0x0063, 0x1F67, + 0x1FD8, 0x1F65, 0x012E, 0x0424, 0x0395, 0x0077, 0x1F65, + 0x1FDE, 0x1F63, 0x0115, 0x0413, 0x03A8, 0x008B, 0x1F64, + 0x1FE3, 0x1F62, 0x00FC, 0x0403, 0x03BA, 0x00A0, 0x1F62, + 0x1FE7, 0x1F62, 0x00E4, 0x03EF, 0x03CC, 0x00B6, 0x1F62, + 0x1F63, 0x00CA, 0x03D3, 0x03D3, 0x00CA, 0x1F63, 0x0000, + 0x1F62, 0x00B6, 0x03CC, 0x03EF, 0x00E4, 0x1F62, 0x1FE7, + 0x1F62, 0x00A0, 0x03BA, 0x0403, 0x00FC, 0x1F62, 0x1FE3, + 0x1F64, 0x008B, 0x03A8, 0x0413, 0x0115, 0x1F63, 0x1FDE, + 0x1F65, 0x0077, 0x0395, 0x0424, 0x012E, 0x1F65, 0x1FD8, + 0x1F67, 0x0063, 0x0380, 0x0433, 0x0148, 0x1F68, 0x1FD3, + 0x1F6A, 0x004F, 0x036B, 0x0441, 0x0162, 0x1F6B, 0x1FCE, + 0x1F6D, 0x003C, 0x0355, 0x044E, 0x017D, 0x1F6F, 0x1FC8, + 0x1F70, 0x002A, 0x033E, 0x045B, 0x0197, 0x1F73, 0x1FC3, + 0x1F73, 0x0019, 0x0326, 0x0465, 0x01B3, 0x1F79, 0x1FBD, + 0x1F77, 0x0008, 0x030F, 0x046E, 0x01CE, 0x1F7F, 0x1FB7, + 0x1F7C, 0x1FF8, 0x02F6, 0x0476, 0x01E9, 0x1F86, 0x1FB1, + 0x1F80, 0x1FE9, 0x02DC, 0x047C, 0x0205, 0x1F8E, 0x1FAC, + 0x1F85, 0x1FDB, 0x02C2, 0x0481, 0x0221, 0x1F96, 0x1FA6, + 0x1F8A, 0x1FCD, 0x02A8, 0x0485, 0x023C, 0x1FA0, 0x1FA0, + 0x1F90, 0x1FC1, 0x028D, 0x0486, 0x0257, 0x1FAA, 0x1F9B, + /* Chroma */ + 0x1F95, 0x1FB5, 0x0272, 0x0488, 0x0272, 0x1FB5, 0x1F95, + 0x1F9B, 0x1FAA, 0x0257, 0x0486, 0x028D, 0x1FC1, 0x1F90, + 0x1FA0, 0x1FA0, 0x023C, 0x0485, 0x02A8, 0x1FCD, 0x1F8A, + 0x1FA6, 0x1F96, 0x0221, 0x0481, 0x02C2, 0x1FDB, 0x1F85, + 0x1FAC, 0x1F8E, 0x0205, 0x047C, 0x02DC, 0x1FE9, 0x1F80, + 0x1FB1, 0x1F86, 0x01E9, 0x0476, 0x02F6, 0x1FF8, 0x1F7C, + 0x1FB7, 0x1F7F, 0x01CE, 0x046E, 0x030F, 0x0008, 0x1F77, + 0x1FBD, 0x1F79, 0x01B3, 0x0465, 0x0326, 0x0019, 0x1F73, + 0x1FC3, 0x1F73, 0x0197, 0x045B, 0x033E, 0x002A, 0x1F70, + 0x1FC8, 0x1F6F, 0x017D, 0x044E, 0x0355, 0x003C, 0x1F6D, + 0x1FCE, 0x1F6B, 0x0162, 0x0441, 0x036B, 0x004F, 0x1F6A, + 0x1FD3, 0x1F68, 0x0148, 0x0433, 0x0380, 0x0063, 0x1F67, + 0x1FD8, 0x1F65, 0x012E, 0x0424, 0x0395, 0x0077, 0x1F65, + 0x1FDE, 0x1F63, 0x0115, 0x0413, 0x03A8, 0x008B, 0x1F64, + 0x1FE3, 0x1F62, 0x00FC, 0x0403, 0x03BA, 0x00A0, 0x1F62, + 0x1FE7, 0x1F62, 0x00E4, 0x03EF, 0x03CC, 0x00B6, 0x1F62, + 0x1F63, 0x00CA, 0x03D3, 0x03D3, 0x00CA, 0x1F63, 0x0000, + 0x1F62, 0x00B6, 0x03CC, 0x03EF, 0x00E4, 0x1F62, 0x1FE7, + 0x1F62, 0x00A0, 0x03BA, 0x0403, 0x00FC, 0x1F62, 0x1FE3, + 0x1F64, 0x008B, 0x03A8, 0x0413, 0x0115, 0x1F63, 0x1FDE, + 0x1F65, 0x0077, 0x0395, 0x0424, 0x012E, 0x1F65, 0x1FD8, + 0x1F67, 0x0063, 0x0380, 0x0433, 0x0148, 0x1F68, 0x1FD3, + 0x1F6A, 0x004F, 0x036B, 0x0441, 0x0162, 0x1F6B, 0x1FCE, + 0x1F6D, 0x003C, 0x0355, 0x044E, 0x017D, 0x1F6F, 0x1FC8, + 0x1F70, 0x002A, 0x033E, 0x045B, 0x0197, 0x1F73, 0x1FC3, + 0x1F73, 0x0019, 0x0326, 0x0465, 0x01B3, 0x1F79, 0x1FBD, + 0x1F77, 0x0008, 0x030F, 0x046E, 0x01CE, 0x1F7F, 0x1FB7, + 0x1F7C, 0x1FF8, 0x02F6, 0x0476, 0x01E9, 0x1F86, 0x1FB1, + 0x1F80, 0x1FE9, 0x02DC, 0x047C, 0x0205, 0x1F8E, 0x1FAC, + 0x1F85, 0x1FDB, 0x02C2, 0x0481, 0x0221, 0x1F96, 0x1FA6, + 0x1F8A, 0x1FCD, 0x02A8, 0x0485, 0x023C, 0x1FA0, 0x1FA0, + 0x1F90, 0x1FC1, 0x028D, 0x0486, 0x0257, 0x1FAA, 0x1F9B, + }, + [HS_LT_12_16_SCALE] = { + /* Luma */ + 0x1FBB, 0x1F65, 0x025E, 0x0504, 0x025E, 0x1F65, 0x1FBB, + 0x1FC3, 0x1F5D, 0x023C, 0x0503, 0x027F, 0x1F6E, 0x1FB4, + 0x1FCA, 0x1F56, 0x021B, 0x0501, 0x02A0, 0x1F78, 0x1FAC, + 0x1FD1, 0x1F50, 0x01FA, 0x04FD, 0x02C0, 0x1F83, 0x1FA5, + 0x1FD8, 0x1F4B, 0x01D9, 0x04F6, 0x02E1, 0x1F90, 0x1F9D, + 0x1FDF, 0x1F47, 0x01B8, 0x04EF, 0x0301, 0x1F9D, 0x1F95, + 0x1FE6, 0x1F43, 0x0198, 0x04E5, 0x0321, 0x1FAB, 0x1F8E, + 0x1FEC, 0x1F41, 0x0178, 0x04DA, 0x0340, 0x1FBB, 0x1F86, + 0x1FF2, 0x1F40, 0x0159, 0x04CC, 0x035E, 0x1FCC, 0x1F7F, + 0x1FF8, 0x1F40, 0x013A, 0x04BE, 0x037B, 0x1FDD, 0x1F78, + 0x1FFE, 0x1F40, 0x011B, 0x04AD, 0x0398, 0x1FF0, 0x1F72, + 0x0003, 0x1F41, 0x00FD, 0x049C, 0x03B4, 0x0004, 0x1F6B, + 0x0008, 0x1F43, 0x00E0, 0x0489, 0x03CE, 0x0019, 0x1F65, + 0x000D, 0x1F46, 0x00C4, 0x0474, 0x03E8, 0x002E, 0x1F5F, + 0x0011, 0x1F49, 0x00A9, 0x045E, 0x0400, 0x0045, 0x1F5A, + 0x0015, 0x1F4D, 0x008E, 0x0447, 0x0418, 0x005C, 0x1F55, + 0x1F4F, 0x0076, 0x043B, 0x043B, 0x0076, 0x1F4F, 0x0000, + 0x1F55, 0x005C, 0x0418, 0x0447, 0x008E, 0x1F4D, 0x0015, + 0x1F5A, 0x0045, 0x0400, 0x045E, 0x00A9, 0x1F49, 0x0011, + 0x1F5F, 0x002E, 0x03E8, 0x0474, 0x00C4, 0x1F46, 0x000D, + 0x1F65, 0x0019, 0x03CE, 0x0489, 0x00E0, 0x1F43, 0x0008, + 0x1F6B, 0x0004, 0x03B4, 0x049C, 0x00FD, 0x1F41, 0x0003, + 0x1F72, 0x1FF0, 0x0398, 0x04AD, 0x011B, 0x1F40, 0x1FFE, + 0x1F78, 0x1FDD, 0x037B, 0x04BE, 0x013A, 0x1F40, 0x1FF8, + 0x1F7F, 0x1FCC, 0x035E, 0x04CC, 0x0159, 0x1F40, 0x1FF2, + 0x1F86, 0x1FBB, 0x0340, 0x04DA, 0x0178, 0x1F41, 0x1FEC, + 0x1F8E, 0x1FAB, 0x0321, 0x04E5, 0x0198, 0x1F43, 0x1FE6, + 0x1F95, 0x1F9D, 0x0301, 0x04EF, 0x01B8, 0x1F47, 0x1FDF, + 0x1F9D, 0x1F90, 0x02E1, 0x04F6, 0x01D9, 0x1F4B, 0x1FD8, + 0x1FA5, 0x1F83, 0x02C0, 0x04FD, 0x01FA, 0x1F50, 0x1FD1, + 0x1FAC, 0x1F78, 0x02A0, 0x0501, 0x021B, 0x1F56, 0x1FCA, + 0x1FB4, 0x1F6E, 0x027F, 0x0503, 0x023C, 0x1F5D, 0x1FC3, + /* Chroma */ + 0x1FBB, 0x1F65, 0x025E, 0x0504, 0x025E, 0x1F65, 0x1FBB, + 0x1FC3, 0x1F5D, 0x023C, 0x0503, 0x027F, 0x1F6E, 0x1FB4, + 0x1FCA, 0x1F56, 0x021B, 0x0501, 0x02A0, 0x1F78, 0x1FAC, + 0x1FD1, 0x1F50, 0x01FA, 0x04FD, 0x02C0, 0x1F83, 0x1FA5, + 0x1FD8, 0x1F4B, 0x01D9, 0x04F6, 0x02E1, 0x1F90, 0x1F9D, + 0x1FDF, 0x1F47, 0x01B8, 0x04EF, 0x0301, 0x1F9D, 0x1F95, + 0x1FE6, 0x1F43, 0x0198, 0x04E5, 0x0321, 0x1FAB, 0x1F8E, + 0x1FEC, 0x1F41, 0x0178, 0x04DA, 0x0340, 0x1FBB, 0x1F86, + 0x1FF2, 0x1F40, 0x0159, 0x04CC, 0x035E, 0x1FCC, 0x1F7F, + 0x1FF8, 0x1F40, 0x013A, 0x04BE, 0x037B, 0x1FDD, 0x1F78, + 0x1FFE, 0x1F40, 0x011B, 0x04AD, 0x0398, 0x1FF0, 0x1F72, + 0x0003, 0x1F41, 0x00FD, 0x049C, 0x03B4, 0x0004, 0x1F6B, + 0x0008, 0x1F43, 0x00E0, 0x0489, 0x03CE, 0x0019, 0x1F65, + 0x000D, 0x1F46, 0x00C4, 0x0474, 0x03E8, 0x002E, 0x1F5F, + 0x0011, 0x1F49, 0x00A9, 0x045E, 0x0400, 0x0045, 0x1F5A, + 0x0015, 0x1F4D, 0x008E, 0x0447, 0x0418, 0x005C, 0x1F55, + 0x1F4F, 0x0076, 0x043B, 0x043B, 0x0076, 0x1F4F, 0x0000, + 0x1F55, 0x005C, 0x0418, 0x0447, 0x008E, 0x1F4D, 0x0015, + 0x1F5A, 0x0045, 0x0400, 0x045E, 0x00A9, 0x1F49, 0x0011, + 0x1F5F, 0x002E, 0x03E8, 0x0474, 0x00C4, 0x1F46, 0x000D, + 0x1F65, 0x0019, 0x03CE, 0x0489, 0x00E0, 0x1F43, 0x0008, + 0x1F6B, 0x0004, 0x03B4, 0x049C, 0x00FD, 0x1F41, 0x0003, + 0x1F72, 0x1FF0, 0x0398, 0x04AD, 0x011B, 0x1F40, 0x1FFE, + 0x1F78, 0x1FDD, 0x037B, 0x04BE, 0x013A, 0x1F40, 0x1FF8, + 0x1F7F, 0x1FCC, 0x035E, 0x04CC, 0x0159, 0x1F40, 0x1FF2, + 0x1F86, 0x1FBB, 0x0340, 0x04DA, 0x0178, 0x1F41, 0x1FEC, + 0x1F8E, 0x1FAB, 0x0321, 0x04E5, 0x0198, 0x1F43, 0x1FE6, + 0x1F95, 0x1F9D, 0x0301, 0x04EF, 0x01B8, 0x1F47, 0x1FDF, + 0x1F9D, 0x1F90, 0x02E1, 0x04F6, 0x01D9, 0x1F4B, 0x1FD8, + 0x1FA5, 0x1F83, 0x02C0, 0x04FD, 0x01FA, 0x1F50, 0x1FD1, + 0x1FAC, 0x1F78, 0x02A0, 0x0501, 0x021B, 0x1F56, 0x1FCA, + 0x1FB4, 0x1F6E, 0x027F, 0x0503, 0x023C, 0x1F5D, 0x1FC3, + }, + [HS_LT_13_16_SCALE] = { + /* Luma */ + 0x1FF4, 0x1F29, 0x022D, 0x056C, 0x022D, 0x1F29, 0x1FF4, + 0x1FFC, 0x1F26, 0x0206, 0x056A, 0x0254, 0x1F2E, 0x1FEC, + 0x0003, 0x1F24, 0x01E0, 0x0567, 0x027A, 0x1F34, 0x1FE4, + 0x000A, 0x1F23, 0x01BA, 0x0561, 0x02A2, 0x1F3B, 0x1FDB, + 0x0011, 0x1F22, 0x0194, 0x055B, 0x02C9, 0x1F43, 0x1FD2, + 0x0017, 0x1F23, 0x016F, 0x0551, 0x02F0, 0x1F4D, 0x1FC9, + 0x001D, 0x1F25, 0x014B, 0x0545, 0x0316, 0x1F58, 0x1FC0, + 0x0022, 0x1F28, 0x0127, 0x0538, 0x033C, 0x1F65, 0x1FB6, + 0x0027, 0x1F2C, 0x0104, 0x0528, 0x0361, 0x1F73, 0x1FAD, + 0x002B, 0x1F30, 0x00E2, 0x0518, 0x0386, 0x1F82, 0x1FA3, + 0x002F, 0x1F36, 0x00C2, 0x0504, 0x03AA, 0x1F92, 0x1F99, + 0x0032, 0x1F3C, 0x00A2, 0x04EF, 0x03CD, 0x1FA4, 0x1F90, + 0x0035, 0x1F42, 0x0083, 0x04D9, 0x03EF, 0x1FB8, 0x1F86, + 0x0038, 0x1F49, 0x0065, 0x04C0, 0x0410, 0x1FCD, 0x1F7D, + 0x003A, 0x1F51, 0x0048, 0x04A6, 0x0431, 0x1FE3, 0x1F73, + 0x003C, 0x1F59, 0x002D, 0x048A, 0x0450, 0x1FFA, 0x1F6A, + 0x1F5D, 0x0014, 0x048F, 0x048F, 0x0014, 0x1F5D, 0x0000, + 0x1F6A, 0x1FFA, 0x0450, 0x048A, 0x002D, 0x1F59, 0x003C, + 0x1F73, 0x1FE3, 0x0431, 0x04A6, 0x0048, 0x1F51, 0x003A, + 0x1F7D, 0x1FCD, 0x0410, 0x04C0, 0x0065, 0x1F49, 0x0038, + 0x1F86, 0x1FB8, 0x03EF, 0x04D9, 0x0083, 0x1F42, 0x0035, + 0x1F90, 0x1FA4, 0x03CD, 0x04EF, 0x00A2, 0x1F3C, 0x0032, + 0x1F99, 0x1F92, 0x03AA, 0x0504, 0x00C2, 0x1F36, 0x002F, + 0x1FA3, 0x1F82, 0x0386, 0x0518, 0x00E2, 0x1F30, 0x002B, + 0x1FAD, 0x1F73, 0x0361, 0x0528, 0x0104, 0x1F2C, 0x0027, + 0x1FB6, 0x1F65, 0x033C, 0x0538, 0x0127, 0x1F28, 0x0022, + 0x1FC0, 0x1F58, 0x0316, 0x0545, 0x014B, 0x1F25, 0x001D, + 0x1FC9, 0x1F4D, 0x02F0, 0x0551, 0x016F, 0x1F23, 0x0017, + 0x1FD2, 0x1F43, 0x02C9, 0x055B, 0x0194, 0x1F22, 0x0011, + 0x1FDB, 0x1F3B, 0x02A2, 0x0561, 0x01BA, 0x1F23, 0x000A, + 0x1FE4, 0x1F34, 0x027A, 0x0567, 0x01E0, 0x1F24, 0x0003, + 0x1FEC, 0x1F2E, 0x0254, 0x056A, 0x0206, 0x1F26, 0x1FFC, + /* Chroma */ + 0x1FF4, 0x1F29, 0x022D, 0x056C, 0x022D, 0x1F29, 0x1FF4, + 0x1FFC, 0x1F26, 0x0206, 0x056A, 0x0254, 0x1F2E, 0x1FEC, + 0x0003, 0x1F24, 0x01E0, 0x0567, 0x027A, 0x1F34, 0x1FE4, + 0x000A, 0x1F23, 0x01BA, 0x0561, 0x02A2, 0x1F3B, 0x1FDB, + 0x0011, 0x1F22, 0x0194, 0x055B, 0x02C9, 0x1F43, 0x1FD2, + 0x0017, 0x1F23, 0x016F, 0x0551, 0x02F0, 0x1F4D, 0x1FC9, + 0x001D, 0x1F25, 0x014B, 0x0545, 0x0316, 0x1F58, 0x1FC0, + 0x0022, 0x1F28, 0x0127, 0x0538, 0x033C, 0x1F65, 0x1FB6, + 0x0027, 0x1F2C, 0x0104, 0x0528, 0x0361, 0x1F73, 0x1FAD, + 0x002B, 0x1F30, 0x00E2, 0x0518, 0x0386, 0x1F82, 0x1FA3, + 0x002F, 0x1F36, 0x00C2, 0x0504, 0x03AA, 0x1F92, 0x1F99, + 0x0032, 0x1F3C, 0x00A2, 0x04EF, 0x03CD, 0x1FA4, 0x1F90, + 0x0035, 0x1F42, 0x0083, 0x04D9, 0x03EF, 0x1FB8, 0x1F86, + 0x0038, 0x1F49, 0x0065, 0x04C0, 0x0410, 0x1FCD, 0x1F7D, + 0x003A, 0x1F51, 0x0048, 0x04A6, 0x0431, 0x1FE3, 0x1F73, + 0x003C, 0x1F59, 0x002D, 0x048A, 0x0450, 0x1FFA, 0x1F6A, + 0x1F5D, 0x0014, 0x048F, 0x048F, 0x0014, 0x1F5D, 0x0000, + 0x1F6A, 0x1FFA, 0x0450, 0x048A, 0x002D, 0x1F59, 0x003C, + 0x1F73, 0x1FE3, 0x0431, 0x04A6, 0x0048, 0x1F51, 0x003A, + 0x1F7D, 0x1FCD, 0x0410, 0x04C0, 0x0065, 0x1F49, 0x0038, + 0x1F86, 0x1FB8, 0x03EF, 0x04D9, 0x0083, 0x1F42, 0x0035, + 0x1F90, 0x1FA4, 0x03CD, 0x04EF, 0x00A2, 0x1F3C, 0x0032, + 0x1F99, 0x1F92, 0x03AA, 0x0504, 0x00C2, 0x1F36, 0x002F, + 0x1FA3, 0x1F82, 0x0386, 0x0518, 0x00E2, 0x1F30, 0x002B, + 0x1FAD, 0x1F73, 0x0361, 0x0528, 0x0104, 0x1F2C, 0x0027, + 0x1FB6, 0x1F65, 0x033C, 0x0538, 0x0127, 0x1F28, 0x0022, + 0x1FC0, 0x1F58, 0x0316, 0x0545, 0x014B, 0x1F25, 0x001D, + 0x1FC9, 0x1F4D, 0x02F0, 0x0551, 0x016F, 0x1F23, 0x0017, + 0x1FD2, 0x1F43, 0x02C9, 0x055B, 0x0194, 0x1F22, 0x0011, + 0x1FDB, 0x1F3B, 0x02A2, 0x0561, 0x01BA, 0x1F23, 0x000A, + 0x1FE4, 0x1F34, 0x027A, 0x0567, 0x01E0, 0x1F24, 0x0003, + 0x1FEC, 0x1F2E, 0x0254, 0x056A, 0x0206, 0x1F26, 0x1FFC, + }, + [HS_LT_14_16_SCALE] = { + /* Luma */ + 0x002F, 0x1F0B, 0x01E7, 0x05BE, 0x01E7, 0x1F0B, 0x002F, + 0x0035, 0x1F0D, 0x01BC, 0x05BD, 0x0213, 0x1F0A, 0x0028, + 0x003A, 0x1F11, 0x0191, 0x05BA, 0x023F, 0x1F0A, 0x0021, + 0x003F, 0x1F15, 0x0167, 0x05B3, 0x026C, 0x1F0C, 0x001A, + 0x0043, 0x1F1B, 0x013E, 0x05AA, 0x0299, 0x1F0F, 0x0012, + 0x0046, 0x1F21, 0x0116, 0x05A1, 0x02C6, 0x1F13, 0x0009, + 0x0049, 0x1F28, 0x00EF, 0x0593, 0x02F4, 0x1F19, 0x0000, + 0x004C, 0x1F30, 0x00C9, 0x0584, 0x0321, 0x1F20, 0x1FF6, + 0x004E, 0x1F39, 0x00A4, 0x0572, 0x034D, 0x1F2A, 0x1FEC, + 0x004F, 0x1F43, 0x0080, 0x055E, 0x037A, 0x1F34, 0x1FE2, + 0x0050, 0x1F4D, 0x005E, 0x0548, 0x03A5, 0x1F41, 0x1FD7, + 0x0050, 0x1F57, 0x003D, 0x0531, 0x03D1, 0x1F4F, 0x1FCB, + 0x0050, 0x1F62, 0x001E, 0x0516, 0x03FB, 0x1F5F, 0x1FC0, + 0x004F, 0x1F6D, 0x0000, 0x04FA, 0x0425, 0x1F71, 0x1FB4, + 0x004E, 0x1F79, 0x1FE4, 0x04DC, 0x044D, 0x1F84, 0x1FA8, + 0x004D, 0x1F84, 0x1FCA, 0x04BC, 0x0474, 0x1F99, 0x1F9C, + 0x1F8C, 0x1FAE, 0x04C6, 0x04C6, 0x1FAE, 0x1F8C, 0x0000, + 0x1F9C, 0x1F99, 0x0474, 0x04BC, 0x1FCA, 0x1F84, 0x004D, + 0x1FA8, 0x1F84, 0x044D, 0x04DC, 0x1FE4, 0x1F79, 0x004E, + 0x1FB4, 0x1F71, 0x0425, 0x04FA, 0x0000, 0x1F6D, 0x004F, + 0x1FC0, 0x1F5F, 0x03FB, 0x0516, 0x001E, 0x1F62, 0x0050, + 0x1FCB, 0x1F4F, 0x03D1, 0x0531, 0x003D, 0x1F57, 0x0050, + 0x1FD7, 0x1F41, 0x03A5, 0x0548, 0x005E, 0x1F4D, 0x0050, + 0x1FE2, 0x1F34, 0x037A, 0x055E, 0x0080, 0x1F43, 0x004F, + 0x1FEC, 0x1F2A, 0x034D, 0x0572, 0x00A4, 0x1F39, 0x004E, + 0x1FF6, 0x1F20, 0x0321, 0x0584, 0x00C9, 0x1F30, 0x004C, + 0x0000, 0x1F19, 0x02F4, 0x0593, 0x00EF, 0x1F28, 0x0049, + 0x0009, 0x1F13, 0x02C6, 0x05A1, 0x0116, 0x1F21, 0x0046, + 0x0012, 0x1F0F, 0x0299, 0x05AA, 0x013E, 0x1F1B, 0x0043, + 0x001A, 0x1F0C, 0x026C, 0x05B3, 0x0167, 0x1F15, 0x003F, + 0x0021, 0x1F0A, 0x023F, 0x05BA, 0x0191, 0x1F11, 0x003A, + 0x0028, 0x1F0A, 0x0213, 0x05BD, 0x01BC, 0x1F0D, 0x0035, + /* Chroma */ + 0x002F, 0x1F0B, 0x01E7, 0x05BE, 0x01E7, 0x1F0B, 0x002F, + 0x0035, 0x1F0D, 0x01BC, 0x05BD, 0x0213, 0x1F0A, 0x0028, + 0x003A, 0x1F11, 0x0191, 0x05BA, 0x023F, 0x1F0A, 0x0021, + 0x003F, 0x1F15, 0x0167, 0x05B3, 0x026C, 0x1F0C, 0x001A, + 0x0043, 0x1F1B, 0x013E, 0x05AA, 0x0299, 0x1F0F, 0x0012, + 0x0046, 0x1F21, 0x0116, 0x05A1, 0x02C6, 0x1F13, 0x0009, + 0x0049, 0x1F28, 0x00EF, 0x0593, 0x02F4, 0x1F19, 0x0000, + 0x004C, 0x1F30, 0x00C9, 0x0584, 0x0321, 0x1F20, 0x1FF6, + 0x004E, 0x1F39, 0x00A4, 0x0572, 0x034D, 0x1F2A, 0x1FEC, + 0x004F, 0x1F43, 0x0080, 0x055E, 0x037A, 0x1F34, 0x1FE2, + 0x0050, 0x1F4D, 0x005E, 0x0548, 0x03A5, 0x1F41, 0x1FD7, + 0x0050, 0x1F57, 0x003D, 0x0531, 0x03D1, 0x1F4F, 0x1FCB, + 0x0050, 0x1F62, 0x001E, 0x0516, 0x03FB, 0x1F5F, 0x1FC0, + 0x004F, 0x1F6D, 0x0000, 0x04FA, 0x0425, 0x1F71, 0x1FB4, + 0x004E, 0x1F79, 0x1FE4, 0x04DC, 0x044D, 0x1F84, 0x1FA8, + 0x004D, 0x1F84, 0x1FCA, 0x04BC, 0x0474, 0x1F99, 0x1F9C, + 0x1F8C, 0x1FAE, 0x04C6, 0x04C6, 0x1FAE, 0x1F8C, 0x0000, + 0x1F9C, 0x1F99, 0x0474, 0x04BC, 0x1FCA, 0x1F84, 0x004D, + 0x1FA8, 0x1F84, 0x044D, 0x04DC, 0x1FE4, 0x1F79, 0x004E, + 0x1FB4, 0x1F71, 0x0425, 0x04FA, 0x0000, 0x1F6D, 0x004F, + 0x1FC0, 0x1F5F, 0x03FB, 0x0516, 0x001E, 0x1F62, 0x0050, + 0x1FCB, 0x1F4F, 0x03D1, 0x0531, 0x003D, 0x1F57, 0x0050, + 0x1FD7, 0x1F41, 0x03A5, 0x0548, 0x005E, 0x1F4D, 0x0050, + 0x1FE2, 0x1F34, 0x037A, 0x055E, 0x0080, 0x1F43, 0x004F, + 0x1FEC, 0x1F2A, 0x034D, 0x0572, 0x00A4, 0x1F39, 0x004E, + 0x1FF6, 0x1F20, 0x0321, 0x0584, 0x00C9, 0x1F30, 0x004C, + 0x0000, 0x1F19, 0x02F4, 0x0593, 0x00EF, 0x1F28, 0x0049, + 0x0009, 0x1F13, 0x02C6, 0x05A1, 0x0116, 0x1F21, 0x0046, + 0x0012, 0x1F0F, 0x0299, 0x05AA, 0x013E, 0x1F1B, 0x0043, + 0x001A, 0x1F0C, 0x026C, 0x05B3, 0x0167, 0x1F15, 0x003F, + 0x0021, 0x1F0A, 0x023F, 0x05BA, 0x0191, 0x1F11, 0x003A, + 0x0028, 0x1F0A, 0x0213, 0x05BD, 0x01BC, 0x1F0D, 0x0035, + }, + [HS_LT_15_16_SCALE] = { + /* Luma */ + 0x005B, 0x1F0A, 0x0195, 0x060C, 0x0195, 0x1F0A, 0x005B, + 0x005D, 0x1F13, 0x0166, 0x0609, 0x01C6, 0x1F03, 0x0058, + 0x005F, 0x1F1C, 0x0138, 0x0605, 0x01F7, 0x1EFD, 0x0054, + 0x0060, 0x1F26, 0x010B, 0x05FF, 0x0229, 0x1EF8, 0x004F, + 0x0060, 0x1F31, 0x00DF, 0x05F5, 0x025C, 0x1EF5, 0x004A, + 0x0060, 0x1F3D, 0x00B5, 0x05E8, 0x028F, 0x1EF3, 0x0044, + 0x005F, 0x1F49, 0x008C, 0x05DA, 0x02C3, 0x1EF2, 0x003D, + 0x005E, 0x1F56, 0x0065, 0x05C7, 0x02F6, 0x1EF4, 0x0036, + 0x005C, 0x1F63, 0x003F, 0x05B3, 0x032B, 0x1EF7, 0x002D, + 0x0059, 0x1F71, 0x001B, 0x059D, 0x035F, 0x1EFB, 0x0024, + 0x0057, 0x1F7F, 0x1FF9, 0x0583, 0x0392, 0x1F02, 0x001A, + 0x0053, 0x1F8D, 0x1FD9, 0x0567, 0x03C5, 0x1F0B, 0x0010, + 0x0050, 0x1F9B, 0x1FBB, 0x0548, 0x03F8, 0x1F15, 0x0005, + 0x004C, 0x1FA9, 0x1F9E, 0x0528, 0x042A, 0x1F22, 0x1FF9, + 0x0048, 0x1FB7, 0x1F84, 0x0505, 0x045A, 0x1F31, 0x1FED, + 0x0043, 0x1FC5, 0x1F6C, 0x04E0, 0x048A, 0x1F42, 0x1FE0, + 0x1FD1, 0x1F50, 0x04DF, 0x04DF, 0x1F50, 0x1FD1, 0x0000, + 0x1FE0, 0x1F42, 0x048A, 0x04E0, 0x1F6C, 0x1FC5, 0x0043, + 0x1FED, 0x1F31, 0x045A, 0x0505, 0x1F84, 0x1FB7, 0x0048, + 0x1FF9, 0x1F22, 0x042A, 0x0528, 0x1F9E, 0x1FA9, 0x004C, + 0x0005, 0x1F15, 0x03F8, 0x0548, 0x1FBB, 0x1F9B, 0x0050, + 0x0010, 0x1F0B, 0x03C5, 0x0567, 0x1FD9, 0x1F8D, 0x0053, + 0x001A, 0x1F02, 0x0392, 0x0583, 0x1FF9, 0x1F7F, 0x0057, + 0x0024, 0x1EFB, 0x035F, 0x059D, 0x001B, 0x1F71, 0x0059, + 0x002D, 0x1EF7, 0x032B, 0x05B3, 0x003F, 0x1F63, 0x005C, + 0x0036, 0x1EF4, 0x02F6, 0x05C7, 0x0065, 0x1F56, 0x005E, + 0x003D, 0x1EF2, 0x02C3, 0x05DA, 0x008C, 0x1F49, 0x005F, + 0x0044, 0x1EF3, 0x028F, 0x05E8, 0x00B5, 0x1F3D, 0x0060, + 0x004A, 0x1EF5, 0x025C, 0x05F5, 0x00DF, 0x1F31, 0x0060, + 0x004F, 0x1EF8, 0x0229, 0x05FF, 0x010B, 0x1F26, 0x0060, + 0x0054, 0x1EFD, 0x01F7, 0x0605, 0x0138, 0x1F1C, 0x005F, + 0x0058, 0x1F03, 0x01C6, 0x0609, 0x0166, 0x1F13, 0x005D, + /* Chroma */ + 0x005B, 0x1F0A, 0x0195, 0x060C, 0x0195, 0x1F0A, 0x005B, + 0x005D, 0x1F13, 0x0166, 0x0609, 0x01C6, 0x1F03, 0x0058, + 0x005F, 0x1F1C, 0x0138, 0x0605, 0x01F7, 0x1EFD, 0x0054, + 0x0060, 0x1F26, 0x010B, 0x05FF, 0x0229, 0x1EF8, 0x004F, + 0x0060, 0x1F31, 0x00DF, 0x05F5, 0x025C, 0x1EF5, 0x004A, + 0x0060, 0x1F3D, 0x00B5, 0x05E8, 0x028F, 0x1EF3, 0x0044, + 0x005F, 0x1F49, 0x008C, 0x05DA, 0x02C3, 0x1EF2, 0x003D, + 0x005E, 0x1F56, 0x0065, 0x05C7, 0x02F6, 0x1EF4, 0x0036, + 0x005C, 0x1F63, 0x003F, 0x05B3, 0x032B, 0x1EF7, 0x002D, + 0x0059, 0x1F71, 0x001B, 0x059D, 0x035F, 0x1EFB, 0x0024, + 0x0057, 0x1F7F, 0x1FF9, 0x0583, 0x0392, 0x1F02, 0x001A, + 0x0053, 0x1F8D, 0x1FD9, 0x0567, 0x03C5, 0x1F0B, 0x0010, + 0x0050, 0x1F9B, 0x1FBB, 0x0548, 0x03F8, 0x1F15, 0x0005, + 0x004C, 0x1FA9, 0x1F9E, 0x0528, 0x042A, 0x1F22, 0x1FF9, + 0x0048, 0x1FB7, 0x1F84, 0x0505, 0x045A, 0x1F31, 0x1FED, + 0x0043, 0x1FC5, 0x1F6C, 0x04E0, 0x048A, 0x1F42, 0x1FE0, + 0x1FD1, 0x1F50, 0x04DF, 0x04DF, 0x1F50, 0x1FD1, 0x0000, + 0x1FE0, 0x1F42, 0x048A, 0x04E0, 0x1F6C, 0x1FC5, 0x0043, + 0x1FED, 0x1F31, 0x045A, 0x0505, 0x1F84, 0x1FB7, 0x0048, + 0x1FF9, 0x1F22, 0x042A, 0x0528, 0x1F9E, 0x1FA9, 0x004C, + 0x0005, 0x1F15, 0x03F8, 0x0548, 0x1FBB, 0x1F9B, 0x0050, + 0x0010, 0x1F0B, 0x03C5, 0x0567, 0x1FD9, 0x1F8D, 0x0053, + 0x001A, 0x1F02, 0x0392, 0x0583, 0x1FF9, 0x1F7F, 0x0057, + 0x0024, 0x1EFB, 0x035F, 0x059D, 0x001B, 0x1F71, 0x0059, + 0x002D, 0x1EF7, 0x032B, 0x05B3, 0x003F, 0x1F63, 0x005C, + 0x0036, 0x1EF4, 0x02F6, 0x05C7, 0x0065, 0x1F56, 0x005E, + 0x003D, 0x1EF2, 0x02C3, 0x05DA, 0x008C, 0x1F49, 0x005F, + 0x0044, 0x1EF3, 0x028F, 0x05E8, 0x00B5, 0x1F3D, 0x0060, + 0x004A, 0x1EF5, 0x025C, 0x05F5, 0x00DF, 0x1F31, 0x0060, + 0x004F, 0x1EF8, 0x0229, 0x05FF, 0x010B, 0x1F26, 0x0060, + 0x0054, 0x1EFD, 0x01F7, 0x0605, 0x0138, 0x1F1C, 0x005F, + 0x0058, 0x1F03, 0x01C6, 0x0609, 0x0166, 0x1F13, 0x005D, + }, + [HS_LE_16_16_SCALE] = { + /* Luma */ + 0x006E, 0x1F24, 0x013E, 0x0660, 0x013E, 0x1F24, 0x006E, + 0x006C, 0x1F33, 0x010B, 0x065D, 0x0172, 0x1F17, 0x0070, + 0x0069, 0x1F41, 0x00DA, 0x0659, 0x01A8, 0x1F0B, 0x0070, + 0x0066, 0x1F51, 0x00AA, 0x0650, 0x01DF, 0x1F00, 0x0070, + 0x0062, 0x1F61, 0x007D, 0x0644, 0x0217, 0x1EF6, 0x006F, + 0x005E, 0x1F71, 0x0051, 0x0636, 0x0250, 0x1EED, 0x006D, + 0x0059, 0x1F81, 0x0028, 0x0624, 0x028A, 0x1EE5, 0x006B, + 0x0054, 0x1F91, 0x0000, 0x060F, 0x02C5, 0x1EE0, 0x0067, + 0x004E, 0x1FA2, 0x1FDB, 0x05F6, 0x0300, 0x1EDC, 0x0063, + 0x0049, 0x1FB2, 0x1FB8, 0x05DB, 0x033B, 0x1EDA, 0x005D, + 0x0043, 0x1FC3, 0x1F98, 0x05BC, 0x0376, 0x1ED9, 0x0057, + 0x003D, 0x1FD3, 0x1F7A, 0x059B, 0x03B1, 0x1EDB, 0x004F, + 0x0036, 0x1FE2, 0x1F5E, 0x0578, 0x03EC, 0x1EDF, 0x0047, + 0x0030, 0x1FF1, 0x1F45, 0x0551, 0x0426, 0x1EE6, 0x003D, + 0x002A, 0x0000, 0x1F2E, 0x0528, 0x045F, 0x1EEE, 0x0033, + 0x0023, 0x000E, 0x1F19, 0x04FD, 0x0498, 0x1EFA, 0x0027, + 0x001B, 0x1F04, 0x04E1, 0x04E1, 0x1F04, 0x001B, 0x0000, + 0x0027, 0x1EFA, 0x0498, 0x04FD, 0x1F19, 0x000E, 0x0023, + 0x0033, 0x1EEE, 0x045F, 0x0528, 0x1F2E, 0x0000, 0x002A, + 0x003D, 0x1EE6, 0x0426, 0x0551, 0x1F45, 0x1FF1, 0x0030, + 0x0047, 0x1EDF, 0x03EC, 0x0578, 0x1F5E, 0x1FE2, 0x0036, + 0x004F, 0x1EDB, 0x03B1, 0x059B, 0x1F7A, 0x1FD3, 0x003D, + 0x0057, 0x1ED9, 0x0376, 0x05BC, 0x1F98, 0x1FC3, 0x0043, + 0x005D, 0x1EDA, 0x033B, 0x05DB, 0x1FB8, 0x1FB2, 0x0049, + 0x0063, 0x1EDC, 0x0300, 0x05F6, 0x1FDB, 0x1FA2, 0x004E, + 0x0067, 0x1EE0, 0x02C5, 0x060F, 0x0000, 0x1F91, 0x0054, + 0x006B, 0x1EE5, 0x028A, 0x0624, 0x0028, 0x1F81, 0x0059, + 0x006D, 0x1EED, 0x0250, 0x0636, 0x0051, 0x1F71, 0x005E, + 0x006F, 0x1EF6, 0x0217, 0x0644, 0x007D, 0x1F61, 0x0062, + 0x0070, 0x1F00, 0x01DF, 0x0650, 0x00AA, 0x1F51, 0x0066, + 0x0070, 0x1F0B, 0x01A8, 0x0659, 0x00DA, 0x1F41, 0x0069, + 0x0070, 0x1F17, 0x0172, 0x065D, 0x010B, 0x1F33, 0x006C, + /* Chroma */ + 0x006E, 0x1F24, 0x013E, 0x0660, 0x013E, 0x1F24, 0x006E, + 0x006C, 0x1F33, 0x010B, 0x065D, 0x0172, 0x1F17, 0x0070, + 0x0069, 0x1F41, 0x00DA, 0x0659, 0x01A8, 0x1F0B, 0x0070, + 0x0066, 0x1F51, 0x00AA, 0x0650, 0x01DF, 0x1F00, 0x0070, + 0x0062, 0x1F61, 0x007D, 0x0644, 0x0217, 0x1EF6, 0x006F, + 0x005E, 0x1F71, 0x0051, 0x0636, 0x0250, 0x1EED, 0x006D, + 0x0059, 0x1F81, 0x0028, 0x0624, 0x028A, 0x1EE5, 0x006B, + 0x0054, 0x1F91, 0x0000, 0x060F, 0x02C5, 0x1EE0, 0x0067, + 0x004E, 0x1FA2, 0x1FDB, 0x05F6, 0x0300, 0x1EDC, 0x0063, + 0x0049, 0x1FB2, 0x1FB8, 0x05DB, 0x033B, 0x1EDA, 0x005D, + 0x0043, 0x1FC3, 0x1F98, 0x05BC, 0x0376, 0x1ED9, 0x0057, + 0x003D, 0x1FD3, 0x1F7A, 0x059B, 0x03B1, 0x1EDB, 0x004F, + 0x0036, 0x1FE2, 0x1F5E, 0x0578, 0x03EC, 0x1EDF, 0x0047, + 0x0030, 0x1FF1, 0x1F45, 0x0551, 0x0426, 0x1EE6, 0x003D, + 0x002A, 0x0000, 0x1F2E, 0x0528, 0x045F, 0x1EEE, 0x0033, + 0x0023, 0x000E, 0x1F19, 0x04FD, 0x0498, 0x1EFA, 0x0027, + 0x001B, 0x1F04, 0x04E1, 0x04E1, 0x1F04, 0x001B, 0x0000, + 0x0027, 0x1EFA, 0x0498, 0x04FD, 0x1F19, 0x000E, 0x0023, + 0x0033, 0x1EEE, 0x045F, 0x0528, 0x1F2E, 0x0000, 0x002A, + 0x003D, 0x1EE6, 0x0426, 0x0551, 0x1F45, 0x1FF1, 0x0030, + 0x0047, 0x1EDF, 0x03EC, 0x0578, 0x1F5E, 0x1FE2, 0x0036, + 0x004F, 0x1EDB, 0x03B1, 0x059B, 0x1F7A, 0x1FD3, 0x003D, + 0x0057, 0x1ED9, 0x0376, 0x05BC, 0x1F98, 0x1FC3, 0x0043, + 0x005D, 0x1EDA, 0x033B, 0x05DB, 0x1FB8, 0x1FB2, 0x0049, + 0x0063, 0x1EDC, 0x0300, 0x05F6, 0x1FDB, 0x1FA2, 0x004E, + 0x0067, 0x1EE0, 0x02C5, 0x060F, 0x0000, 0x1F91, 0x0054, + 0x006B, 0x1EE5, 0x028A, 0x0624, 0x0028, 0x1F81, 0x0059, + 0x006D, 0x1EED, 0x0250, 0x0636, 0x0051, 0x1F71, 0x005E, + 0x006F, 0x1EF6, 0x0217, 0x0644, 0x007D, 0x1F61, 0x0062, + 0x0070, 0x1F00, 0x01DF, 0x0650, 0x00AA, 0x1F51, 0x0066, + 0x0070, 0x1F0B, 0x01A8, 0x0659, 0x00DA, 0x1F41, 0x0069, + 0x0070, 0x1F17, 0x0172, 0x065D, 0x010B, 0x1F33, 0x006C, + }, +}; + +/* vertical scaler coefficients */ +enum { + VS_UP_SCALE = 0, + VS_LT_9_16_SCALE, + VS_LT_10_16_SCALE, + VS_LT_11_16_SCALE, + VS_LT_12_16_SCALE, + VS_LT_13_16_SCALE, + VS_LT_14_16_SCALE, + VS_LT_15_16_SCALE, + VS_LT_16_16_SCALE, + VS_1_TO_1_SCALE, +}; + +static const u16 scaler_vs_coeffs[15][SC_NUM_PHASES * 2 * SC_V_NUM_TAPS] = { + [VS_UP_SCALE] = { + /* Luma */ + 0x1FD1, 0x00B1, 0x06FC, 0x00B1, 0x1FD1, + 0x1FD8, 0x0085, 0x06F9, 0x00E1, 0x1FC9, + 0x1FDF, 0x005B, 0x06F2, 0x0114, 0x1FC0, + 0x1FE5, 0x0035, 0x06E5, 0x014A, 0x1FB7, + 0x1FEB, 0x0012, 0x06D3, 0x0182, 0x1FAE, + 0x1FF1, 0x1FF3, 0x06BA, 0x01BD, 0x1FA5, + 0x1FF5, 0x1FD7, 0x069D, 0x01FB, 0x1F9C, + 0x1FF9, 0x1FBE, 0x067C, 0x023A, 0x1F93, + 0x1FFD, 0x1FA8, 0x0656, 0x027B, 0x1F8A, + 0x0000, 0x1F95, 0x062B, 0x02BF, 0x1F81, + 0x0002, 0x1F86, 0x05FC, 0x0303, 0x1F79, + 0x0004, 0x1F79, 0x05CA, 0x0347, 0x1F72, + 0x0005, 0x1F6F, 0x0594, 0x038D, 0x1F6B, + 0x0006, 0x1F67, 0x055B, 0x03D2, 0x1F66, + 0x0007, 0x1F62, 0x051E, 0x0417, 0x1F62, + 0x0007, 0x1F5F, 0x04DF, 0x045C, 0x1F5F, + 0x1F5E, 0x04A2, 0x04A2, 0x1F5E, 0x0000, + 0x1F5F, 0x045C, 0x04DF, 0x1F5F, 0x0007, + 0x1F62, 0x0417, 0x051E, 0x1F62, 0x0007, + 0x1F66, 0x03D2, 0x055B, 0x1F67, 0x0006, + 0x1F6B, 0x038D, 0x0594, 0x1F6F, 0x0005, + 0x1F72, 0x0347, 0x05CA, 0x1F79, 0x0004, + 0x1F79, 0x0303, 0x05FC, 0x1F86, 0x0002, + 0x1F81, 0x02BF, 0x062B, 0x1F95, 0x0000, + 0x1F8A, 0x027B, 0x0656, 0x1FA8, 0x1FFD, + 0x1F93, 0x023A, 0x067C, 0x1FBE, 0x1FF9, + 0x1F9C, 0x01FB, 0x069D, 0x1FD7, 0x1FF5, + 0x1FA5, 0x01BD, 0x06BA, 0x1FF3, 0x1FF1, + 0x1FAE, 0x0182, 0x06D3, 0x0012, 0x1FEB, + 0x1FB7, 0x014A, 0x06E5, 0x0035, 0x1FE5, + 0x1FC0, 0x0114, 0x06F2, 0x005B, 0x1FDF, + 0x1FC9, 0x00E1, 0x06F9, 0x0085, 0x1FD8, + /* Chroma */ + 0x1FD1, 0x00B1, 0x06FC, 0x00B1, 0x1FD1, + 0x1FD8, 0x0085, 0x06F9, 0x00E1, 0x1FC9, + 0x1FDF, 0x005B, 0x06F2, 0x0114, 0x1FC0, + 0x1FE5, 0x0035, 0x06E5, 0x014A, 0x1FB7, + 0x1FEB, 0x0012, 0x06D3, 0x0182, 0x1FAE, + 0x1FF1, 0x1FF3, 0x06BA, 0x01BD, 0x1FA5, + 0x1FF5, 0x1FD7, 0x069D, 0x01FB, 0x1F9C, + 0x1FF9, 0x1FBE, 0x067C, 0x023A, 0x1F93, + 0x1FFD, 0x1FA8, 0x0656, 0x027B, 0x1F8A, + 0x0000, 0x1F95, 0x062B, 0x02BF, 0x1F81, + 0x0002, 0x1F86, 0x05FC, 0x0303, 0x1F79, + 0x0004, 0x1F79, 0x05CA, 0x0347, 0x1F72, + 0x0005, 0x1F6F, 0x0594, 0x038D, 0x1F6B, + 0x0006, 0x1F67, 0x055B, 0x03D2, 0x1F66, + 0x0007, 0x1F62, 0x051E, 0x0417, 0x1F62, + 0x0007, 0x1F5F, 0x04DF, 0x045C, 0x1F5F, + 0x1F5E, 0x04A2, 0x04A2, 0x1F5E, 0x0000, + 0x1F5F, 0x045C, 0x04DF, 0x1F5F, 0x0007, + 0x1F62, 0x0417, 0x051E, 0x1F62, 0x0007, + 0x1F66, 0x03D2, 0x055B, 0x1F67, 0x0006, + 0x1F6B, 0x038D, 0x0594, 0x1F6F, 0x0005, + 0x1F72, 0x0347, 0x05CA, 0x1F79, 0x0004, + 0x1F79, 0x0303, 0x05FC, 0x1F86, 0x0002, + 0x1F81, 0x02BF, 0x062B, 0x1F95, 0x0000, + 0x1F8A, 0x027B, 0x0656, 0x1FA8, 0x1FFD, + 0x1F93, 0x023A, 0x067C, 0x1FBE, 0x1FF9, + 0x1F9C, 0x01FB, 0x069D, 0x1FD7, 0x1FF5, + 0x1FA5, 0x01BD, 0x06BA, 0x1FF3, 0x1FF1, + 0x1FAE, 0x0182, 0x06D3, 0x0012, 0x1FEB, + 0x1FB7, 0x014A, 0x06E5, 0x0035, 0x1FE5, + 0x1FC0, 0x0114, 0x06F2, 0x005B, 0x1FDF, + 0x1FC9, 0x00E1, 0x06F9, 0x0085, 0x1FD8, + }, + [VS_LT_9_16_SCALE] = { + /* Luma */ + 0x001C, 0x01F6, 0x03DC, 0x01F6, 0x001C, + 0x0018, 0x01DF, 0x03DB, 0x020C, 0x0022, + 0x0013, 0x01C9, 0x03D9, 0x0223, 0x0028, + 0x000F, 0x01B3, 0x03D6, 0x023A, 0x002E, + 0x000C, 0x019D, 0x03D2, 0x0250, 0x0035, + 0x0009, 0x0188, 0x03CC, 0x0266, 0x003D, + 0x0006, 0x0173, 0x03C5, 0x027D, 0x0045, + 0x0004, 0x015E, 0x03BD, 0x0293, 0x004E, + 0x0002, 0x014A, 0x03B4, 0x02A8, 0x0058, + 0x0000, 0x0136, 0x03AA, 0x02BE, 0x0062, + 0x1FFF, 0x0123, 0x039E, 0x02D3, 0x006D, + 0x1FFE, 0x0110, 0x0392, 0x02E8, 0x0078, + 0x1FFD, 0x00FE, 0x0384, 0x02FC, 0x0085, + 0x1FFD, 0x00ED, 0x0376, 0x030F, 0x0091, + 0x1FFC, 0x00DC, 0x0367, 0x0322, 0x009F, + 0x1FFC, 0x00CC, 0x0357, 0x0334, 0x00AD, + 0x00BC, 0x0344, 0x0344, 0x00BC, 0x0000, + 0x00AD, 0x0334, 0x0357, 0x00CC, 0x1FFC, + 0x009F, 0x0322, 0x0367, 0x00DC, 0x1FFC, + 0x0091, 0x030F, 0x0376, 0x00ED, 0x1FFD, + 0x0085, 0x02FC, 0x0384, 0x00FE, 0x1FFD, + 0x0078, 0x02E8, 0x0392, 0x0110, 0x1FFE, + 0x006D, 0x02D3, 0x039E, 0x0123, 0x1FFF, + 0x0062, 0x02BE, 0x03AA, 0x0136, 0x0000, + 0x0058, 0x02A8, 0x03B4, 0x014A, 0x0002, + 0x004E, 0x0293, 0x03BD, 0x015E, 0x0004, + 0x0045, 0x027D, 0x03C5, 0x0173, 0x0006, + 0x003D, 0x0266, 0x03CC, 0x0188, 0x0009, + 0x0035, 0x0250, 0x03D2, 0x019D, 0x000C, + 0x002E, 0x023A, 0x03D6, 0x01B3, 0x000F, + 0x0028, 0x0223, 0x03D9, 0x01C9, 0x0013, + 0x0022, 0x020C, 0x03DB, 0x01DF, 0x0018, + /* Chroma */ + 0x001C, 0x01F6, 0x03DC, 0x01F6, 0x001C, + 0x0018, 0x01DF, 0x03DB, 0x020C, 0x0022, + 0x0013, 0x01C9, 0x03D9, 0x0223, 0x0028, + 0x000F, 0x01B3, 0x03D6, 0x023A, 0x002E, + 0x000C, 0x019D, 0x03D2, 0x0250, 0x0035, + 0x0009, 0x0188, 0x03CC, 0x0266, 0x003D, + 0x0006, 0x0173, 0x03C5, 0x027D, 0x0045, + 0x0004, 0x015E, 0x03BD, 0x0293, 0x004E, + 0x0002, 0x014A, 0x03B4, 0x02A8, 0x0058, + 0x0000, 0x0136, 0x03AA, 0x02BE, 0x0062, + 0x1FFF, 0x0123, 0x039E, 0x02D3, 0x006D, + 0x1FFE, 0x0110, 0x0392, 0x02E8, 0x0078, + 0x1FFD, 0x00FE, 0x0384, 0x02FC, 0x0085, + 0x1FFD, 0x00ED, 0x0376, 0x030F, 0x0091, + 0x1FFC, 0x00DC, 0x0367, 0x0322, 0x009F, + 0x1FFC, 0x00CC, 0x0357, 0x0334, 0x00AD, + 0x00BC, 0x0344, 0x0344, 0x00BC, 0x0000, + 0x00AD, 0x0334, 0x0357, 0x00CC, 0x1FFC, + 0x009F, 0x0322, 0x0367, 0x00DC, 0x1FFC, + 0x0091, 0x030F, 0x0376, 0x00ED, 0x1FFD, + 0x0085, 0x02FC, 0x0384, 0x00FE, 0x1FFD, + 0x0078, 0x02E8, 0x0392, 0x0110, 0x1FFE, + 0x006D, 0x02D3, 0x039E, 0x0123, 0x1FFF, + 0x0062, 0x02BE, 0x03AA, 0x0136, 0x0000, + 0x0058, 0x02A8, 0x03B4, 0x014A, 0x0002, + 0x004E, 0x0293, 0x03BD, 0x015E, 0x0004, + 0x0045, 0x027D, 0x03C5, 0x0173, 0x0006, + 0x003D, 0x0266, 0x03CC, 0x0188, 0x0009, + 0x0035, 0x0250, 0x03D2, 0x019D, 0x000C, + 0x002E, 0x023A, 0x03D6, 0x01B3, 0x000F, + 0x0028, 0x0223, 0x03D9, 0x01C9, 0x0013, + 0x0022, 0x020C, 0x03DB, 0x01DF, 0x0018, + }, + [VS_LT_10_16_SCALE] = { + /* Luma */ + 0x0003, 0x01E9, 0x0428, 0x01E9, 0x0003, + 0x0000, 0x01D0, 0x0426, 0x0203, 0x0007, + 0x1FFD, 0x01B7, 0x0424, 0x021C, 0x000C, + 0x1FFB, 0x019E, 0x0420, 0x0236, 0x0011, + 0x1FF9, 0x0186, 0x041A, 0x0250, 0x0017, + 0x1FF7, 0x016E, 0x0414, 0x026A, 0x001D, + 0x1FF6, 0x0157, 0x040B, 0x0284, 0x0024, + 0x1FF5, 0x0140, 0x0401, 0x029E, 0x002C, + 0x1FF4, 0x012A, 0x03F6, 0x02B7, 0x0035, + 0x1FF4, 0x0115, 0x03E9, 0x02D0, 0x003E, + 0x1FF4, 0x0100, 0x03DB, 0x02E9, 0x0048, + 0x1FF4, 0x00EC, 0x03CC, 0x0301, 0x0053, + 0x1FF4, 0x00D9, 0x03BC, 0x0318, 0x005F, + 0x1FF5, 0x00C7, 0x03AA, 0x032F, 0x006B, + 0x1FF6, 0x00B5, 0x0398, 0x0345, 0x0078, + 0x1FF6, 0x00A5, 0x0384, 0x035B, 0x0086, + 0x0094, 0x036C, 0x036C, 0x0094, 0x0000, + 0x0086, 0x035B, 0x0384, 0x00A5, 0x1FF6, + 0x0078, 0x0345, 0x0398, 0x00B5, 0x1FF6, + 0x006B, 0x032F, 0x03AA, 0x00C7, 0x1FF5, + 0x005F, 0x0318, 0x03BC, 0x00D9, 0x1FF4, + 0x0053, 0x0301, 0x03CC, 0x00EC, 0x1FF4, + 0x0048, 0x02E9, 0x03DB, 0x0100, 0x1FF4, + 0x003E, 0x02D0, 0x03E9, 0x0115, 0x1FF4, + 0x0035, 0x02B7, 0x03F6, 0x012A, 0x1FF4, + 0x002C, 0x029E, 0x0401, 0x0140, 0x1FF5, + 0x0024, 0x0284, 0x040B, 0x0157, 0x1FF6, + 0x001D, 0x026A, 0x0414, 0x016E, 0x1FF7, + 0x0017, 0x0250, 0x041A, 0x0186, 0x1FF9, + 0x0011, 0x0236, 0x0420, 0x019E, 0x1FFB, + 0x000C, 0x021C, 0x0424, 0x01B7, 0x1FFD, + 0x0007, 0x0203, 0x0426, 0x01D0, 0x0000, + /* Chroma */ + 0x0003, 0x01E9, 0x0428, 0x01E9, 0x0003, + 0x0000, 0x01D0, 0x0426, 0x0203, 0x0007, + 0x1FFD, 0x01B7, 0x0424, 0x021C, 0x000C, + 0x1FFB, 0x019E, 0x0420, 0x0236, 0x0011, + 0x1FF9, 0x0186, 0x041A, 0x0250, 0x0017, + 0x1FF7, 0x016E, 0x0414, 0x026A, 0x001D, + 0x1FF6, 0x0157, 0x040B, 0x0284, 0x0024, + 0x1FF5, 0x0140, 0x0401, 0x029E, 0x002C, + 0x1FF4, 0x012A, 0x03F6, 0x02B7, 0x0035, + 0x1FF4, 0x0115, 0x03E9, 0x02D0, 0x003E, + 0x1FF4, 0x0100, 0x03DB, 0x02E9, 0x0048, + 0x1FF4, 0x00EC, 0x03CC, 0x0301, 0x0053, + 0x1FF4, 0x00D9, 0x03BC, 0x0318, 0x005F, + 0x1FF5, 0x00C7, 0x03AA, 0x032F, 0x006B, + 0x1FF6, 0x00B5, 0x0398, 0x0345, 0x0078, + 0x1FF6, 0x00A5, 0x0384, 0x035B, 0x0086, + 0x0094, 0x036C, 0x036C, 0x0094, 0x0000, + 0x0086, 0x035B, 0x0384, 0x00A5, 0x1FF6, + 0x0078, 0x0345, 0x0398, 0x00B5, 0x1FF6, + 0x006B, 0x032F, 0x03AA, 0x00C7, 0x1FF5, + 0x005F, 0x0318, 0x03BC, 0x00D9, 0x1FF4, + 0x0053, 0x0301, 0x03CC, 0x00EC, 0x1FF4, + 0x0048, 0x02E9, 0x03DB, 0x0100, 0x1FF4, + 0x003E, 0x02D0, 0x03E9, 0x0115, 0x1FF4, + 0x0035, 0x02B7, 0x03F6, 0x012A, 0x1FF4, + 0x002C, 0x029E, 0x0401, 0x0140, 0x1FF5, + 0x0024, 0x0284, 0x040B, 0x0157, 0x1FF6, + 0x001D, 0x026A, 0x0414, 0x016E, 0x1FF7, + 0x0017, 0x0250, 0x041A, 0x0186, 0x1FF9, + 0x0011, 0x0236, 0x0420, 0x019E, 0x1FFB, + 0x000C, 0x021C, 0x0424, 0x01B7, 0x1FFD, + 0x0007, 0x0203, 0x0426, 0x01D0, 0x0000, + }, + [VS_LT_11_16_SCALE] = { + /* Luma */ + 0x1FEC, 0x01D6, 0x047C, 0x01D6, 0x1FEC, + 0x1FEA, 0x01BA, 0x047B, 0x01F3, 0x1FEE, + 0x1FE9, 0x019D, 0x0478, 0x0211, 0x1FF1, + 0x1FE8, 0x0182, 0x0473, 0x022E, 0x1FF5, + 0x1FE8, 0x0167, 0x046C, 0x024C, 0x1FF9, + 0x1FE8, 0x014D, 0x0464, 0x026A, 0x1FFD, + 0x1FE8, 0x0134, 0x0459, 0x0288, 0x0003, + 0x1FE9, 0x011B, 0x044D, 0x02A6, 0x0009, + 0x1FE9, 0x0104, 0x0440, 0x02C3, 0x0010, + 0x1FEA, 0x00ED, 0x0430, 0x02E1, 0x0018, + 0x1FEB, 0x00D7, 0x0420, 0x02FD, 0x0021, + 0x1FED, 0x00C2, 0x040D, 0x0319, 0x002B, + 0x1FEE, 0x00AE, 0x03F9, 0x0336, 0x0035, + 0x1FF0, 0x009C, 0x03E3, 0x0350, 0x0041, + 0x1FF1, 0x008A, 0x03CD, 0x036B, 0x004D, + 0x1FF3, 0x0079, 0x03B5, 0x0384, 0x005B, + 0x0069, 0x0397, 0x0397, 0x0069, 0x0000, + 0x005B, 0x0384, 0x03B5, 0x0079, 0x1FF3, + 0x004D, 0x036B, 0x03CD, 0x008A, 0x1FF1, + 0x0041, 0x0350, 0x03E3, 0x009C, 0x1FF0, + 0x0035, 0x0336, 0x03F9, 0x00AE, 0x1FEE, + 0x002B, 0x0319, 0x040D, 0x00C2, 0x1FED, + 0x0021, 0x02FD, 0x0420, 0x00D7, 0x1FEB, + 0x0018, 0x02E1, 0x0430, 0x00ED, 0x1FEA, + 0x0010, 0x02C3, 0x0440, 0x0104, 0x1FE9, + 0x0009, 0x02A6, 0x044D, 0x011B, 0x1FE9, + 0x0003, 0x0288, 0x0459, 0x0134, 0x1FE8, + 0x1FFD, 0x026A, 0x0464, 0x014D, 0x1FE8, + 0x1FF9, 0x024C, 0x046C, 0x0167, 0x1FE8, + 0x1FF5, 0x022E, 0x0473, 0x0182, 0x1FE8, + 0x1FF1, 0x0211, 0x0478, 0x019D, 0x1FE9, + 0x1FEE, 0x01F3, 0x047B, 0x01BA, 0x1FEA, + /* Chroma */ + 0x1FEC, 0x01D6, 0x047C, 0x01D6, 0x1FEC, + 0x1FEA, 0x01BA, 0x047B, 0x01F3, 0x1FEE, + 0x1FE9, 0x019D, 0x0478, 0x0211, 0x1FF1, + 0x1FE8, 0x0182, 0x0473, 0x022E, 0x1FF5, + 0x1FE8, 0x0167, 0x046C, 0x024C, 0x1FF9, + 0x1FE8, 0x014D, 0x0464, 0x026A, 0x1FFD, + 0x1FE8, 0x0134, 0x0459, 0x0288, 0x0003, + 0x1FE9, 0x011B, 0x044D, 0x02A6, 0x0009, + 0x1FE9, 0x0104, 0x0440, 0x02C3, 0x0010, + 0x1FEA, 0x00ED, 0x0430, 0x02E1, 0x0018, + 0x1FEB, 0x00D7, 0x0420, 0x02FD, 0x0021, + 0x1FED, 0x00C2, 0x040D, 0x0319, 0x002B, + 0x1FEE, 0x00AE, 0x03F9, 0x0336, 0x0035, + 0x1FF0, 0x009C, 0x03E3, 0x0350, 0x0041, + 0x1FF1, 0x008A, 0x03CD, 0x036B, 0x004D, + 0x1FF3, 0x0079, 0x03B5, 0x0384, 0x005B, + 0x0069, 0x0397, 0x0397, 0x0069, 0x0000, + 0x005B, 0x0384, 0x03B5, 0x0079, 0x1FF3, + 0x004D, 0x036B, 0x03CD, 0x008A, 0x1FF1, + 0x0041, 0x0350, 0x03E3, 0x009C, 0x1FF0, + 0x0035, 0x0336, 0x03F9, 0x00AE, 0x1FEE, + 0x002B, 0x0319, 0x040D, 0x00C2, 0x1FED, + 0x0021, 0x02FD, 0x0420, 0x00D7, 0x1FEB, + 0x0018, 0x02E1, 0x0430, 0x00ED, 0x1FEA, + 0x0010, 0x02C3, 0x0440, 0x0104, 0x1FE9, + 0x0009, 0x02A6, 0x044D, 0x011B, 0x1FE9, + 0x0003, 0x0288, 0x0459, 0x0134, 0x1FE8, + 0x1FFD, 0x026A, 0x0464, 0x014D, 0x1FE8, + 0x1FF9, 0x024C, 0x046C, 0x0167, 0x1FE8, + 0x1FF5, 0x022E, 0x0473, 0x0182, 0x1FE8, + 0x1FF1, 0x0211, 0x0478, 0x019D, 0x1FE9, + 0x1FEE, 0x01F3, 0x047B, 0x01BA, 0x1FEA, + }, + [VS_LT_12_16_SCALE] = { + /* Luma */ + 0x1FD8, 0x01BC, 0x04D8, 0x01BC, 0x1FD8, + 0x1FD8, 0x019C, 0x04D8, 0x01DC, 0x1FD8, + 0x1FD8, 0x017D, 0x04D4, 0x01FE, 0x1FD9, + 0x1FD9, 0x015E, 0x04CF, 0x0220, 0x1FDA, + 0x1FDB, 0x0141, 0x04C7, 0x0241, 0x1FDC, + 0x1FDC, 0x0125, 0x04BC, 0x0264, 0x1FDF, + 0x1FDE, 0x0109, 0x04B0, 0x0286, 0x1FE3, + 0x1FE0, 0x00EF, 0x04A1, 0x02A9, 0x1FE7, + 0x1FE2, 0x00D6, 0x0491, 0x02CB, 0x1FEC, + 0x1FE4, 0x00BE, 0x047E, 0x02EE, 0x1FF2, + 0x1FE6, 0x00A7, 0x046A, 0x030F, 0x1FFA, + 0x1FE9, 0x0092, 0x0453, 0x0330, 0x0002, + 0x1FEB, 0x007E, 0x043B, 0x0351, 0x000B, + 0x1FED, 0x006B, 0x0421, 0x0372, 0x0015, + 0x1FEF, 0x005A, 0x0406, 0x0391, 0x0020, + 0x1FF1, 0x0049, 0x03EA, 0x03AF, 0x002D, + 0x003A, 0x03C6, 0x03C6, 0x003A, 0x0000, + 0x002D, 0x03AF, 0x03EA, 0x0049, 0x1FF1, + 0x0020, 0x0391, 0x0406, 0x005A, 0x1FEF, + 0x0015, 0x0372, 0x0421, 0x006B, 0x1FED, + 0x000B, 0x0351, 0x043B, 0x007E, 0x1FEB, + 0x0002, 0x0330, 0x0453, 0x0092, 0x1FE9, + 0x1FFA, 0x030F, 0x046A, 0x00A7, 0x1FE6, + 0x1FF2, 0x02EE, 0x047E, 0x00BE, 0x1FE4, + 0x1FEC, 0x02CB, 0x0491, 0x00D6, 0x1FE2, + 0x1FE7, 0x02A9, 0x04A1, 0x00EF, 0x1FE0, + 0x1FE3, 0x0286, 0x04B0, 0x0109, 0x1FDE, + 0x1FDF, 0x0264, 0x04BC, 0x0125, 0x1FDC, + 0x1FDC, 0x0241, 0x04C7, 0x0141, 0x1FDB, + 0x1FDA, 0x0220, 0x04CF, 0x015E, 0x1FD9, + 0x1FD9, 0x01FE, 0x04D4, 0x017D, 0x1FD8, + 0x1FD8, 0x01DC, 0x04D8, 0x019C, 0x1FD8, + /* Chroma */ + 0x1FD8, 0x01BC, 0x04D8, 0x01BC, 0x1FD8, + 0x1FD8, 0x019C, 0x04D8, 0x01DC, 0x1FD8, + 0x1FD8, 0x017D, 0x04D4, 0x01FE, 0x1FD9, + 0x1FD9, 0x015E, 0x04CF, 0x0220, 0x1FDA, + 0x1FDB, 0x0141, 0x04C7, 0x0241, 0x1FDC, + 0x1FDC, 0x0125, 0x04BC, 0x0264, 0x1FDF, + 0x1FDE, 0x0109, 0x04B0, 0x0286, 0x1FE3, + 0x1FE0, 0x00EF, 0x04A1, 0x02A9, 0x1FE7, + 0x1FE2, 0x00D6, 0x0491, 0x02CB, 0x1FEC, + 0x1FE4, 0x00BE, 0x047E, 0x02EE, 0x1FF2, + 0x1FE6, 0x00A7, 0x046A, 0x030F, 0x1FFA, + 0x1FE9, 0x0092, 0x0453, 0x0330, 0x0002, + 0x1FEB, 0x007E, 0x043B, 0x0351, 0x000B, + 0x1FED, 0x006B, 0x0421, 0x0372, 0x0015, + 0x1FEF, 0x005A, 0x0406, 0x0391, 0x0020, + 0x1FF1, 0x0049, 0x03EA, 0x03AF, 0x002D, + 0x003A, 0x03C6, 0x03C6, 0x003A, 0x0000, + 0x002D, 0x03AF, 0x03EA, 0x0049, 0x1FF1, + 0x0020, 0x0391, 0x0406, 0x005A, 0x1FEF, + 0x0015, 0x0372, 0x0421, 0x006B, 0x1FED, + 0x000B, 0x0351, 0x043B, 0x007E, 0x1FEB, + 0x0002, 0x0330, 0x0453, 0x0092, 0x1FE9, + 0x1FFA, 0x030F, 0x046A, 0x00A7, 0x1FE6, + 0x1FF2, 0x02EE, 0x047E, 0x00BE, 0x1FE4, + 0x1FEC, 0x02CB, 0x0491, 0x00D6, 0x1FE2, + 0x1FE7, 0x02A9, 0x04A1, 0x00EF, 0x1FE0, + 0x1FE3, 0x0286, 0x04B0, 0x0109, 0x1FDE, + 0x1FDF, 0x0264, 0x04BC, 0x0125, 0x1FDC, + 0x1FDC, 0x0241, 0x04C7, 0x0141, 0x1FDB, + 0x1FDA, 0x0220, 0x04CF, 0x015E, 0x1FD9, + 0x1FD9, 0x01FE, 0x04D4, 0x017D, 0x1FD8, + 0x1FD8, 0x01DC, 0x04D8, 0x019C, 0x1FD8, + }, + [VS_LT_13_16_SCALE] = { + /* Luma */ + 0x1FC8, 0x0199, 0x053E, 0x0199, 0x1FC8, + 0x1FCA, 0x0175, 0x053E, 0x01BD, 0x1FC6, + 0x1FCD, 0x0153, 0x0539, 0x01E2, 0x1FC5, + 0x1FCF, 0x0132, 0x0532, 0x0209, 0x1FC4, + 0x1FD2, 0x0112, 0x0529, 0x022F, 0x1FC4, + 0x1FD5, 0x00F4, 0x051C, 0x0256, 0x1FC5, + 0x1FD8, 0x00D7, 0x050D, 0x027E, 0x1FC6, + 0x1FDC, 0x00BB, 0x04FB, 0x02A6, 0x1FC8, + 0x1FDF, 0x00A1, 0x04E7, 0x02CE, 0x1FCB, + 0x1FE2, 0x0089, 0x04D1, 0x02F5, 0x1FCF, + 0x1FE5, 0x0072, 0x04B8, 0x031D, 0x1FD4, + 0x1FE8, 0x005D, 0x049E, 0x0344, 0x1FD9, + 0x1FEB, 0x0049, 0x0480, 0x036B, 0x1FE1, + 0x1FEE, 0x0037, 0x0462, 0x0390, 0x1FE9, + 0x1FF0, 0x0026, 0x0442, 0x03B6, 0x1FF2, + 0x1FF2, 0x0017, 0x0420, 0x03DA, 0x1FFD, + 0x0009, 0x03F7, 0x03F7, 0x0009, 0x0000, + 0x1FFD, 0x03DA, 0x0420, 0x0017, 0x1FF2, + 0x1FF2, 0x03B6, 0x0442, 0x0026, 0x1FF0, + 0x1FE9, 0x0390, 0x0462, 0x0037, 0x1FEE, + 0x1FE1, 0x036B, 0x0480, 0x0049, 0x1FEB, + 0x1FD9, 0x0344, 0x049E, 0x005D, 0x1FE8, + 0x1FD4, 0x031D, 0x04B8, 0x0072, 0x1FE5, + 0x1FCF, 0x02F5, 0x04D1, 0x0089, 0x1FE2, + 0x1FCB, 0x02CE, 0x04E7, 0x00A1, 0x1FDF, + 0x1FC8, 0x02A6, 0x04FB, 0x00BB, 0x1FDC, + 0x1FC6, 0x027E, 0x050D, 0x00D7, 0x1FD8, + 0x1FC5, 0x0256, 0x051C, 0x00F4, 0x1FD5, + 0x1FC4, 0x022F, 0x0529, 0x0112, 0x1FD2, + 0x1FC4, 0x0209, 0x0532, 0x0132, 0x1FCF, + 0x1FC5, 0x01E2, 0x0539, 0x0153, 0x1FCD, + 0x1FC6, 0x01BD, 0x053E, 0x0175, 0x1FCA, + /* Chroma */ + 0x1FC8, 0x0199, 0x053E, 0x0199, 0x1FC8, + 0x1FCA, 0x0175, 0x053E, 0x01BD, 0x1FC6, + 0x1FCD, 0x0153, 0x0539, 0x01E2, 0x1FC5, + 0x1FCF, 0x0132, 0x0532, 0x0209, 0x1FC4, + 0x1FD2, 0x0112, 0x0529, 0x022F, 0x1FC4, + 0x1FD5, 0x00F4, 0x051C, 0x0256, 0x1FC5, + 0x1FD8, 0x00D7, 0x050D, 0x027E, 0x1FC6, + 0x1FDC, 0x00BB, 0x04FB, 0x02A6, 0x1FC8, + 0x1FDF, 0x00A1, 0x04E7, 0x02CE, 0x1FCB, + 0x1FE2, 0x0089, 0x04D1, 0x02F5, 0x1FCF, + 0x1FE5, 0x0072, 0x04B8, 0x031D, 0x1FD4, + 0x1FE8, 0x005D, 0x049E, 0x0344, 0x1FD9, + 0x1FEB, 0x0049, 0x0480, 0x036B, 0x1FE1, + 0x1FEE, 0x0037, 0x0462, 0x0390, 0x1FE9, + 0x1FF0, 0x0026, 0x0442, 0x03B6, 0x1FF2, + 0x1FF2, 0x0017, 0x0420, 0x03DA, 0x1FFD, + 0x0009, 0x03F7, 0x03F7, 0x0009, 0x0000, + 0x1FFD, 0x03DA, 0x0420, 0x0017, 0x1FF2, + 0x1FF2, 0x03B6, 0x0442, 0x0026, 0x1FF0, + 0x1FE9, 0x0390, 0x0462, 0x0037, 0x1FEE, + 0x1FE1, 0x036B, 0x0480, 0x0049, 0x1FEB, + 0x1FD9, 0x0344, 0x049E, 0x005D, 0x1FE8, + 0x1FD4, 0x031D, 0x04B8, 0x0072, 0x1FE5, + 0x1FCF, 0x02F5, 0x04D1, 0x0089, 0x1FE2, + 0x1FCB, 0x02CE, 0x04E7, 0x00A1, 0x1FDF, + 0x1FC8, 0x02A6, 0x04FB, 0x00BB, 0x1FDC, + 0x1FC6, 0x027E, 0x050D, 0x00D7, 0x1FD8, + 0x1FC5, 0x0256, 0x051C, 0x00F4, 0x1FD5, + 0x1FC4, 0x022F, 0x0529, 0x0112, 0x1FD2, + 0x1FC4, 0x0209, 0x0532, 0x0132, 0x1FCF, + 0x1FC5, 0x01E2, 0x0539, 0x0153, 0x1FCD, + 0x1FC6, 0x01BD, 0x053E, 0x0175, 0x1FCA, + }, + [VS_LT_14_16_SCALE] = { + /* Luma */ + 0x1FBF, 0x016C, 0x05AA, 0x016C, 0x1FBF, + 0x1FC3, 0x0146, 0x05A8, 0x0194, 0x1FBB, + 0x1FC7, 0x0121, 0x05A3, 0x01BD, 0x1FB8, + 0x1FCB, 0x00FD, 0x059B, 0x01E8, 0x1FB5, + 0x1FD0, 0x00DC, 0x058F, 0x0213, 0x1FB2, + 0x1FD4, 0x00BC, 0x0580, 0x0240, 0x1FB0, + 0x1FD8, 0x009E, 0x056E, 0x026D, 0x1FAF, + 0x1FDC, 0x0082, 0x055A, 0x029A, 0x1FAE, + 0x1FE0, 0x0067, 0x0542, 0x02C9, 0x1FAE, + 0x1FE4, 0x004F, 0x0528, 0x02F6, 0x1FAF, + 0x1FE8, 0x0038, 0x050A, 0x0325, 0x1FB1, + 0x1FEB, 0x0024, 0x04EB, 0x0352, 0x1FB4, + 0x1FEE, 0x0011, 0x04C8, 0x0380, 0x1FB9, + 0x1FF1, 0x0000, 0x04A4, 0x03AC, 0x1FBF, + 0x1FF4, 0x1FF1, 0x047D, 0x03D8, 0x1FC6, + 0x1FF6, 0x1FE4, 0x0455, 0x0403, 0x1FCE, + 0x1FD8, 0x0428, 0x0428, 0x1FD8, 0x0000, + 0x1FCE, 0x0403, 0x0455, 0x1FE4, 0x1FF6, + 0x1FC6, 0x03D8, 0x047D, 0x1FF1, 0x1FF4, + 0x1FBF, 0x03AC, 0x04A4, 0x0000, 0x1FF1, + 0x1FB9, 0x0380, 0x04C8, 0x0011, 0x1FEE, + 0x1FB4, 0x0352, 0x04EB, 0x0024, 0x1FEB, + 0x1FB1, 0x0325, 0x050A, 0x0038, 0x1FE8, + 0x1FAF, 0x02F6, 0x0528, 0x004F, 0x1FE4, + 0x1FAE, 0x02C9, 0x0542, 0x0067, 0x1FE0, + 0x1FAE, 0x029A, 0x055A, 0x0082, 0x1FDC, + 0x1FAF, 0x026D, 0x056E, 0x009E, 0x1FD8, + 0x1FB0, 0x0240, 0x0580, 0x00BC, 0x1FD4, + 0x1FB2, 0x0213, 0x058F, 0x00DC, 0x1FD0, + 0x1FB5, 0x01E8, 0x059B, 0x00FD, 0x1FCB, + 0x1FB8, 0x01BD, 0x05A3, 0x0121, 0x1FC7, + 0x1FBB, 0x0194, 0x05A8, 0x0146, 0x1FC3, + /* Chroma */ + 0x1FBF, 0x016C, 0x05AA, 0x016C, 0x1FBF, + 0x1FC3, 0x0146, 0x05A8, 0x0194, 0x1FBB, + 0x1FC7, 0x0121, 0x05A3, 0x01BD, 0x1FB8, + 0x1FCB, 0x00FD, 0x059B, 0x01E8, 0x1FB5, + 0x1FD0, 0x00DC, 0x058F, 0x0213, 0x1FB2, + 0x1FD4, 0x00BC, 0x0580, 0x0240, 0x1FB0, + 0x1FD8, 0x009E, 0x056E, 0x026D, 0x1FAF, + 0x1FDC, 0x0082, 0x055A, 0x029A, 0x1FAE, + 0x1FE0, 0x0067, 0x0542, 0x02C9, 0x1FAE, + 0x1FE4, 0x004F, 0x0528, 0x02F6, 0x1FAF, + 0x1FE8, 0x0038, 0x050A, 0x0325, 0x1FB1, + 0x1FEB, 0x0024, 0x04EB, 0x0352, 0x1FB4, + 0x1FEE, 0x0011, 0x04C8, 0x0380, 0x1FB9, + 0x1FF1, 0x0000, 0x04A4, 0x03AC, 0x1FBF, + 0x1FF4, 0x1FF1, 0x047D, 0x03D8, 0x1FC6, + 0x1FF6, 0x1FE4, 0x0455, 0x0403, 0x1FCE, + 0x1FD8, 0x0428, 0x0428, 0x1FD8, 0x0000, + 0x1FCE, 0x0403, 0x0455, 0x1FE4, 0x1FF6, + 0x1FC6, 0x03D8, 0x047D, 0x1FF1, 0x1FF4, + 0x1FBF, 0x03AC, 0x04A4, 0x0000, 0x1FF1, + 0x1FB9, 0x0380, 0x04C8, 0x0011, 0x1FEE, + 0x1FB4, 0x0352, 0x04EB, 0x0024, 0x1FEB, + 0x1FB1, 0x0325, 0x050A, 0x0038, 0x1FE8, + 0x1FAF, 0x02F6, 0x0528, 0x004F, 0x1FE4, + 0x1FAE, 0x02C9, 0x0542, 0x0067, 0x1FE0, + 0x1FAE, 0x029A, 0x055A, 0x0082, 0x1FDC, + 0x1FAF, 0x026D, 0x056E, 0x009E, 0x1FD8, + 0x1FB0, 0x0240, 0x0580, 0x00BC, 0x1FD4, + 0x1FB2, 0x0213, 0x058F, 0x00DC, 0x1FD0, + 0x1FB5, 0x01E8, 0x059B, 0x00FD, 0x1FCB, + 0x1FB8, 0x01BD, 0x05A3, 0x0121, 0x1FC7, + 0x1FBB, 0x0194, 0x05A8, 0x0146, 0x1FC3, + }, + [VS_LT_15_16_SCALE] = { + /* Luma */ + 0x1FBD, 0x0136, 0x061A, 0x0136, 0x1FBD, + 0x1FC3, 0x010D, 0x0617, 0x0161, 0x1FB8, + 0x1FC9, 0x00E6, 0x0611, 0x018E, 0x1FB2, + 0x1FCE, 0x00C1, 0x0607, 0x01BD, 0x1FAD, + 0x1FD4, 0x009E, 0x05F9, 0x01ED, 0x1FA8, + 0x1FD9, 0x007D, 0x05E8, 0x021F, 0x1FA3, + 0x1FDE, 0x005E, 0x05D3, 0x0252, 0x1F9F, + 0x1FE2, 0x0042, 0x05BC, 0x0285, 0x1F9B, + 0x1FE7, 0x0029, 0x059F, 0x02B9, 0x1F98, + 0x1FEA, 0x0011, 0x0580, 0x02EF, 0x1F96, + 0x1FEE, 0x1FFC, 0x055D, 0x0324, 0x1F95, + 0x1FF1, 0x1FE9, 0x0538, 0x0359, 0x1F95, + 0x1FF4, 0x1FD8, 0x0510, 0x038E, 0x1F96, + 0x1FF7, 0x1FC9, 0x04E5, 0x03C2, 0x1F99, + 0x1FF9, 0x1FBD, 0x04B8, 0x03F5, 0x1F9D, + 0x1FFB, 0x1FB2, 0x0489, 0x0428, 0x1FA2, + 0x1FAA, 0x0456, 0x0456, 0x1FAA, 0x0000, + 0x1FA2, 0x0428, 0x0489, 0x1FB2, 0x1FFB, + 0x1F9D, 0x03F5, 0x04B8, 0x1FBD, 0x1FF9, + 0x1F99, 0x03C2, 0x04E5, 0x1FC9, 0x1FF7, + 0x1F96, 0x038E, 0x0510, 0x1FD8, 0x1FF4, + 0x1F95, 0x0359, 0x0538, 0x1FE9, 0x1FF1, + 0x1F95, 0x0324, 0x055D, 0x1FFC, 0x1FEE, + 0x1F96, 0x02EF, 0x0580, 0x0011, 0x1FEA, + 0x1F98, 0x02B9, 0x059F, 0x0029, 0x1FE7, + 0x1F9B, 0x0285, 0x05BC, 0x0042, 0x1FE2, + 0x1F9F, 0x0252, 0x05D3, 0x005E, 0x1FDE, + 0x1FA3, 0x021F, 0x05E8, 0x007D, 0x1FD9, + 0x1FA8, 0x01ED, 0x05F9, 0x009E, 0x1FD4, + 0x1FAD, 0x01BD, 0x0607, 0x00C1, 0x1FCE, + 0x1FB2, 0x018E, 0x0611, 0x00E6, 0x1FC9, + 0x1FB8, 0x0161, 0x0617, 0x010D, 0x1FC3, + /* Chroma */ + 0x1FBD, 0x0136, 0x061A, 0x0136, 0x1FBD, + 0x1FC3, 0x010D, 0x0617, 0x0161, 0x1FB8, + 0x1FC9, 0x00E6, 0x0611, 0x018E, 0x1FB2, + 0x1FCE, 0x00C1, 0x0607, 0x01BD, 0x1FAD, + 0x1FD4, 0x009E, 0x05F9, 0x01ED, 0x1FA8, + 0x1FD9, 0x007D, 0x05E8, 0x021F, 0x1FA3, + 0x1FDE, 0x005E, 0x05D3, 0x0252, 0x1F9F, + 0x1FE2, 0x0042, 0x05BC, 0x0285, 0x1F9B, + 0x1FE7, 0x0029, 0x059F, 0x02B9, 0x1F98, + 0x1FEA, 0x0011, 0x0580, 0x02EF, 0x1F96, + 0x1FEE, 0x1FFC, 0x055D, 0x0324, 0x1F95, + 0x1FF1, 0x1FE9, 0x0538, 0x0359, 0x1F95, + 0x1FF4, 0x1FD8, 0x0510, 0x038E, 0x1F96, + 0x1FF7, 0x1FC9, 0x04E5, 0x03C2, 0x1F99, + 0x1FF9, 0x1FBD, 0x04B8, 0x03F5, 0x1F9D, + 0x1FFB, 0x1FB2, 0x0489, 0x0428, 0x1FA2, + 0x1FAA, 0x0456, 0x0456, 0x1FAA, 0x0000, + 0x1FA2, 0x0428, 0x0489, 0x1FB2, 0x1FFB, + 0x1F9D, 0x03F5, 0x04B8, 0x1FBD, 0x1FF9, + 0x1F99, 0x03C2, 0x04E5, 0x1FC9, 0x1FF7, + 0x1F96, 0x038E, 0x0510, 0x1FD8, 0x1FF4, + 0x1F95, 0x0359, 0x0538, 0x1FE9, 0x1FF1, + 0x1F95, 0x0324, 0x055D, 0x1FFC, 0x1FEE, + 0x1F96, 0x02EF, 0x0580, 0x0011, 0x1FEA, + 0x1F98, 0x02B9, 0x059F, 0x0029, 0x1FE7, + 0x1F9B, 0x0285, 0x05BC, 0x0042, 0x1FE2, + 0x1F9F, 0x0252, 0x05D3, 0x005E, 0x1FDE, + 0x1FA3, 0x021F, 0x05E8, 0x007D, 0x1FD9, + 0x1FA8, 0x01ED, 0x05F9, 0x009E, 0x1FD4, + 0x1FAD, 0x01BD, 0x0607, 0x00C1, 0x1FCE, + 0x1FB2, 0x018E, 0x0611, 0x00E6, 0x1FC9, + 0x1FB8, 0x0161, 0x0617, 0x010D, 0x1FC3, + }, + [VS_LT_16_16_SCALE] = { + /* Luma */ + 0x1FC3, 0x00F8, 0x068A, 0x00F8, 0x1FC3, + 0x1FCA, 0x00CC, 0x0689, 0x0125, 0x1FBC, + 0x1FD1, 0x00A3, 0x0681, 0x0156, 0x1FB5, + 0x1FD7, 0x007D, 0x0676, 0x0188, 0x1FAE, + 0x1FDD, 0x005A, 0x0666, 0x01BD, 0x1FA6, + 0x1FE3, 0x0039, 0x0652, 0x01F3, 0x1F9F, + 0x1FE8, 0x001B, 0x0639, 0x022C, 0x1F98, + 0x1FEC, 0x0000, 0x061D, 0x0265, 0x1F92, + 0x1FF0, 0x1FE8, 0x05FC, 0x02A0, 0x1F8C, + 0x1FF4, 0x1FD2, 0x05D7, 0x02DC, 0x1F87, + 0x1FF7, 0x1FBF, 0x05AF, 0x0319, 0x1F82, + 0x1FFA, 0x1FAF, 0x0583, 0x0356, 0x1F7E, + 0x1FFC, 0x1FA1, 0x0554, 0x0393, 0x1F7C, + 0x1FFE, 0x1F95, 0x0523, 0x03CF, 0x1F7B, + 0x0000, 0x1F8C, 0x04EE, 0x040B, 0x1F7B, + 0x0001, 0x1F85, 0x04B8, 0x0446, 0x1F7C, + 0x1F80, 0x0480, 0x0480, 0x1F80, 0x0000, + 0x1F7C, 0x0446, 0x04B8, 0x1F85, 0x0001, + 0x1F7B, 0x040B, 0x04EE, 0x1F8C, 0x0000, + 0x1F7B, 0x03CF, 0x0523, 0x1F95, 0x1FFE, + 0x1F7C, 0x0393, 0x0554, 0x1FA1, 0x1FFC, + 0x1F7E, 0x0356, 0x0583, 0x1FAF, 0x1FFA, + 0x1F82, 0x0319, 0x05AF, 0x1FBF, 0x1FF7, + 0x1F87, 0x02DC, 0x05D7, 0x1FD2, 0x1FF4, + 0x1F8C, 0x02A0, 0x05FC, 0x1FE8, 0x1FF0, + 0x1F92, 0x0265, 0x061D, 0x0000, 0x1FEC, + 0x1F98, 0x022C, 0x0639, 0x001B, 0x1FE8, + 0x1F9F, 0x01F3, 0x0652, 0x0039, 0x1FE3, + 0x1FA6, 0x01BD, 0x0666, 0x005A, 0x1FDD, + 0x1FAE, 0x0188, 0x0676, 0x007D, 0x1FD7, + 0x1FB5, 0x0156, 0x0681, 0x00A3, 0x1FD1, + 0x1FBC, 0x0125, 0x0689, 0x00CC, 0x1FCA, + /* Chroma */ + 0x1FC3, 0x00F8, 0x068A, 0x00F8, 0x1FC3, + 0x1FCA, 0x00CC, 0x0689, 0x0125, 0x1FBC, + 0x1FD1, 0x00A3, 0x0681, 0x0156, 0x1FB5, + 0x1FD7, 0x007D, 0x0676, 0x0188, 0x1FAE, + 0x1FDD, 0x005A, 0x0666, 0x01BD, 0x1FA6, + 0x1FE3, 0x0039, 0x0652, 0x01F3, 0x1F9F, + 0x1FE8, 0x001B, 0x0639, 0x022C, 0x1F98, + 0x1FEC, 0x0000, 0x061D, 0x0265, 0x1F92, + 0x1FF0, 0x1FE8, 0x05FC, 0x02A0, 0x1F8C, + 0x1FF4, 0x1FD2, 0x05D7, 0x02DC, 0x1F87, + 0x1FF7, 0x1FBF, 0x05AF, 0x0319, 0x1F82, + 0x1FFA, 0x1FAF, 0x0583, 0x0356, 0x1F7E, + 0x1FFC, 0x1FA1, 0x0554, 0x0393, 0x1F7C, + 0x1FFE, 0x1F95, 0x0523, 0x03CF, 0x1F7B, + 0x0000, 0x1F8C, 0x04EE, 0x040B, 0x1F7B, + 0x0001, 0x1F85, 0x04B8, 0x0446, 0x1F7C, + 0x1F80, 0x0480, 0x0480, 0x1F80, 0x0000, + 0x1F7C, 0x0446, 0x04B8, 0x1F85, 0x0001, + 0x1F7B, 0x040B, 0x04EE, 0x1F8C, 0x0000, + 0x1F7B, 0x03CF, 0x0523, 0x1F95, 0x1FFE, + 0x1F7C, 0x0393, 0x0554, 0x1FA1, 0x1FFC, + 0x1F7E, 0x0356, 0x0583, 0x1FAF, 0x1FFA, + 0x1F82, 0x0319, 0x05AF, 0x1FBF, 0x1FF7, + 0x1F87, 0x02DC, 0x05D7, 0x1FD2, 0x1FF4, + 0x1F8C, 0x02A0, 0x05FC, 0x1FE8, 0x1FF0, + 0x1F92, 0x0265, 0x061D, 0x0000, 0x1FEC, + 0x1F98, 0x022C, 0x0639, 0x001B, 0x1FE8, + 0x1F9F, 0x01F3, 0x0652, 0x0039, 0x1FE3, + 0x1FA6, 0x01BD, 0x0666, 0x005A, 0x1FDD, + 0x1FAE, 0x0188, 0x0676, 0x007D, 0x1FD7, + 0x1FB5, 0x0156, 0x0681, 0x00A3, 0x1FD1, + 0x1FBC, 0x0125, 0x0689, 0x00CC, 0x1FCA, + }, + [VS_1_TO_1_SCALE] = { + /* Luma */ + 0x0000, 0x0000, 0x0800, 0x0000, 0x0000, + 0x1FD8, 0x0085, 0x06F9, 0x00E1, 0x1FC9, + 0x1FDF, 0x005B, 0x06F2, 0x0114, 0x1FC0, + 0x1FE5, 0x0035, 0x06E5, 0x014A, 0x1FB7, + 0x1FEB, 0x0012, 0x06D3, 0x0182, 0x1FAE, + 0x1FF1, 0x1FF3, 0x06BA, 0x01BD, 0x1FA5, + 0x1FF5, 0x1FD7, 0x069D, 0x01FB, 0x1F9C, + 0x1FF9, 0x1FBE, 0x067C, 0x023A, 0x1F93, + 0x1FFD, 0x1FA8, 0x0656, 0x027B, 0x1F8A, + 0x0000, 0x1F95, 0x062B, 0x02BF, 0x1F81, + 0x0002, 0x1F86, 0x05FC, 0x0303, 0x1F79, + 0x0004, 0x1F79, 0x05CA, 0x0347, 0x1F72, + 0x0005, 0x1F6F, 0x0594, 0x038D, 0x1F6B, + 0x0006, 0x1F67, 0x055B, 0x03D2, 0x1F66, + 0x0007, 0x1F62, 0x051E, 0x0417, 0x1F62, + 0x0007, 0x1F5F, 0x04DF, 0x045C, 0x1F5F, + 0x1F5E, 0x04A2, 0x04A2, 0x1F5E, 0x0000, + 0x1F5F, 0x045C, 0x04DF, 0x1F5F, 0x0007, + 0x1F62, 0x0417, 0x051E, 0x1F62, 0x0007, + 0x1F66, 0x03D2, 0x055B, 0x1F67, 0x0006, + 0x1F6B, 0x038D, 0x0594, 0x1F6F, 0x0005, + 0x1F72, 0x0347, 0x05CA, 0x1F79, 0x0004, + 0x1F79, 0x0303, 0x05FC, 0x1F86, 0x0002, + 0x1F81, 0x02BF, 0x062B, 0x1F95, 0x0000, + 0x1F8A, 0x027B, 0x0656, 0x1FA8, 0x1FFD, + 0x1F93, 0x023A, 0x067C, 0x1FBE, 0x1FF9, + 0x1F9C, 0x01FB, 0x069D, 0x1FD7, 0x1FF5, + 0x1FA5, 0x01BD, 0x06BA, 0x1FF3, 0x1FF1, + 0x1FAE, 0x0182, 0x06D3, 0x0012, 0x1FEB, + 0x1FB7, 0x014A, 0x06E5, 0x0035, 0x1FE5, + 0x1FC0, 0x0114, 0x06F2, 0x005B, 0x1FDF, + 0x1FC9, 0x00E1, 0x06F9, 0x0085, 0x1FD8, + /* Chroma */ + 0x0000, 0x0000, 0x0800, 0x0000, 0x0000, + 0x1FD8, 0x0085, 0x06F9, 0x00E1, 0x1FC9, + 0x1FDF, 0x005B, 0x06F2, 0x0114, 0x1FC0, + 0x1FE5, 0x0035, 0x06E5, 0x014A, 0x1FB7, + 0x1FEB, 0x0012, 0x06D3, 0x0182, 0x1FAE, + 0x1FF1, 0x1FF3, 0x06BA, 0x01BD, 0x1FA5, + 0x1FF5, 0x1FD7, 0x069D, 0x01FB, 0x1F9C, + 0x1FF9, 0x1FBE, 0x067C, 0x023A, 0x1F93, + 0x1FFD, 0x1FA8, 0x0656, 0x027B, 0x1F8A, + 0x0000, 0x1F95, 0x062B, 0x02BF, 0x1F81, + 0x0002, 0x1F86, 0x05FC, 0x0303, 0x1F79, + 0x0004, 0x1F79, 0x05CA, 0x0347, 0x1F72, + 0x0005, 0x1F6F, 0x0594, 0x038D, 0x1F6B, + 0x0006, 0x1F67, 0x055B, 0x03D2, 0x1F66, + 0x0007, 0x1F62, 0x051E, 0x0417, 0x1F62, + 0x0007, 0x1F5F, 0x04DF, 0x045C, 0x1F5F, + 0x1F5E, 0x04A2, 0x04A2, 0x1F5E, 0x0000, + 0x1F5F, 0x045C, 0x04DF, 0x1F5F, 0x0007, + 0x1F62, 0x0417, 0x051E, 0x1F62, 0x0007, + 0x1F66, 0x03D2, 0x055B, 0x1F67, 0x0006, + 0x1F6B, 0x038D, 0x0594, 0x1F6F, 0x0005, + 0x1F72, 0x0347, 0x05CA, 0x1F79, 0x0004, + 0x1F79, 0x0303, 0x05FC, 0x1F86, 0x0002, + 0x1F81, 0x02BF, 0x062B, 0x1F95, 0x0000, + 0x1F8A, 0x027B, 0x0656, 0x1FA8, 0x1FFD, + 0x1F93, 0x023A, 0x067C, 0x1FBE, 0x1FF9, + 0x1F9C, 0x01FB, 0x069D, 0x1FD7, 0x1FF5, + 0x1FA5, 0x01BD, 0x06BA, 0x1FF3, 0x1FF1, + 0x1FAE, 0x0182, 0x06D3, 0x0012, 0x1FEB, + 0x1FB7, 0x014A, 0x06E5, 0x0035, 0x1FE5, + 0x1FC0, 0x0114, 0x06F2, 0x005B, 0x1FDF, + 0x1FC9, 0x00E1, 0x06F9, 0x0085, 0x1FD8, + }, +}; +#endif diff --git a/drivers/media/platform/ti/vpe/vpdma.c b/drivers/media/platform/ti/vpe/vpdma.c new file mode 100644 index 000000000000..f8998a8ad371 --- /dev/null +++ b/drivers/media/platform/ti/vpe/vpdma.c @@ -0,0 +1,1176 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * VPDMA helper library + * + * Copyright (c) 2013 Texas Instruments Inc. + * + * David Griego, + * Dale Farnsworth, + * Archit Taneja, + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "vpdma.h" +#include "vpdma_priv.h" + +#define VPDMA_FIRMWARE "vpdma-1b8.bin" + +const struct vpdma_data_format vpdma_yuv_fmts[] = { + [VPDMA_DATA_FMT_Y444] = { + .type = VPDMA_DATA_FMT_TYPE_YUV, + .data_type = DATA_TYPE_Y444, + .depth = 8, + }, + [VPDMA_DATA_FMT_Y422] = { + .type = VPDMA_DATA_FMT_TYPE_YUV, + .data_type = DATA_TYPE_Y422, + .depth = 8, + }, + [VPDMA_DATA_FMT_Y420] = { + .type = VPDMA_DATA_FMT_TYPE_YUV, + .data_type = DATA_TYPE_Y420, + .depth = 8, + }, + [VPDMA_DATA_FMT_C444] = { + .type = VPDMA_DATA_FMT_TYPE_YUV, + .data_type = DATA_TYPE_C444, + .depth = 8, + }, + [VPDMA_DATA_FMT_C422] = { + .type = VPDMA_DATA_FMT_TYPE_YUV, + .data_type = DATA_TYPE_C422, + .depth = 8, + }, + [VPDMA_DATA_FMT_C420] = { + .type = VPDMA_DATA_FMT_TYPE_YUV, + .data_type = DATA_TYPE_C420, + .depth = 4, + }, + [VPDMA_DATA_FMT_CB420] = { + .type = VPDMA_DATA_FMT_TYPE_YUV, + .data_type = DATA_TYPE_CB420, + .depth = 4, + }, + [VPDMA_DATA_FMT_YCR422] = { + .type = VPDMA_DATA_FMT_TYPE_YUV, + .data_type = DATA_TYPE_YCR422, + .depth = 16, + }, + [VPDMA_DATA_FMT_YC444] = { + .type = VPDMA_DATA_FMT_TYPE_YUV, + .data_type = DATA_TYPE_YC444, + .depth = 24, + }, + [VPDMA_DATA_FMT_CRY422] = { + .type = VPDMA_DATA_FMT_TYPE_YUV, + .data_type = DATA_TYPE_CRY422, + .depth = 16, + }, + [VPDMA_DATA_FMT_CBY422] = { + .type = VPDMA_DATA_FMT_TYPE_YUV, + .data_type = DATA_TYPE_CBY422, + .depth = 16, + }, + [VPDMA_DATA_FMT_YCB422] = { + .type = VPDMA_DATA_FMT_TYPE_YUV, + .data_type = DATA_TYPE_YCB422, + .depth = 16, + }, +}; +EXPORT_SYMBOL(vpdma_yuv_fmts); + +const struct vpdma_data_format vpdma_rgb_fmts[] = { + [VPDMA_DATA_FMT_RGB565] = { + .type = VPDMA_DATA_FMT_TYPE_RGB, + .data_type = DATA_TYPE_RGB16_565, + .depth = 16, + }, + [VPDMA_DATA_FMT_ARGB16_1555] = { + .type = VPDMA_DATA_FMT_TYPE_RGB, + .data_type = DATA_TYPE_ARGB_1555, + .depth = 16, + }, + [VPDMA_DATA_FMT_ARGB16] = { + .type = VPDMA_DATA_FMT_TYPE_RGB, + .data_type = DATA_TYPE_ARGB_4444, + .depth = 16, + }, + [VPDMA_DATA_FMT_RGBA16_5551] = { + .type = VPDMA_DATA_FMT_TYPE_RGB, + .data_type = DATA_TYPE_RGBA_5551, + .depth = 16, + }, + [VPDMA_DATA_FMT_RGBA16] = { + .type = VPDMA_DATA_FMT_TYPE_RGB, + .data_type = DATA_TYPE_RGBA_4444, + .depth = 16, + }, + [VPDMA_DATA_FMT_ARGB24] = { + .type = VPDMA_DATA_FMT_TYPE_RGB, + .data_type = DATA_TYPE_ARGB24_6666, + .depth = 24, + }, + [VPDMA_DATA_FMT_RGB24] = { + .type = VPDMA_DATA_FMT_TYPE_RGB, + .data_type = DATA_TYPE_RGB24_888, + .depth = 24, + }, + [VPDMA_DATA_FMT_ARGB32] = { + .type = VPDMA_DATA_FMT_TYPE_RGB, + .data_type = DATA_TYPE_ARGB32_8888, + .depth = 32, + }, + [VPDMA_DATA_FMT_RGBA24] = { + .type = VPDMA_DATA_FMT_TYPE_RGB, + .data_type = DATA_TYPE_RGBA24_6666, + .depth = 24, + }, + [VPDMA_DATA_FMT_RGBA32] = { + .type = VPDMA_DATA_FMT_TYPE_RGB, + .data_type = DATA_TYPE_RGBA32_8888, + .depth = 32, + }, + [VPDMA_DATA_FMT_BGR565] = { + .type = VPDMA_DATA_FMT_TYPE_RGB, + .data_type = DATA_TYPE_BGR16_565, + .depth = 16, + }, + [VPDMA_DATA_FMT_ABGR16_1555] = { + .type = VPDMA_DATA_FMT_TYPE_RGB, + .data_type = DATA_TYPE_ABGR_1555, + .depth = 16, + }, + [VPDMA_DATA_FMT_ABGR16] = { + .type = VPDMA_DATA_FMT_TYPE_RGB, + .data_type = DATA_TYPE_ABGR_4444, + .depth = 16, + }, + [VPDMA_DATA_FMT_BGRA16_5551] = { + .type = VPDMA_DATA_FMT_TYPE_RGB, + .data_type = DATA_TYPE_BGRA_5551, + .depth = 16, + }, + [VPDMA_DATA_FMT_BGRA16] = { + .type = VPDMA_DATA_FMT_TYPE_RGB, + .data_type = DATA_TYPE_BGRA_4444, + .depth = 16, + }, + [VPDMA_DATA_FMT_ABGR24] = { + .type = VPDMA_DATA_FMT_TYPE_RGB, + .data_type = DATA_TYPE_ABGR24_6666, + .depth = 24, + }, + [VPDMA_DATA_FMT_BGR24] = { + .type = VPDMA_DATA_FMT_TYPE_RGB, + .data_type = DATA_TYPE_BGR24_888, + .depth = 24, + }, + [VPDMA_DATA_FMT_ABGR32] = { + .type = VPDMA_DATA_FMT_TYPE_RGB, + .data_type = DATA_TYPE_ABGR32_8888, + .depth = 32, + }, + [VPDMA_DATA_FMT_BGRA24] = { + .type = VPDMA_DATA_FMT_TYPE_RGB, + .data_type = DATA_TYPE_BGRA24_6666, + .depth = 24, + }, + [VPDMA_DATA_FMT_BGRA32] = { + .type = VPDMA_DATA_FMT_TYPE_RGB, + .data_type = DATA_TYPE_BGRA32_8888, + .depth = 32, + }, +}; +EXPORT_SYMBOL(vpdma_rgb_fmts); + +/* + * To handle RAW format we are re-using the CBY422 + * vpdma data type so that we use the vpdma to re-order + * the incoming bytes, as the parser assumes that the + * first byte presented on the bus is the MSB of a 2 + * bytes value. + * RAW8 handles from 1 to 8 bits + * RAW16 handles from 9 to 16 bits + */ +const struct vpdma_data_format vpdma_raw_fmts[] = { + [VPDMA_DATA_FMT_RAW8] = { + .type = VPDMA_DATA_FMT_TYPE_YUV, + .data_type = DATA_TYPE_CBY422, + .depth = 8, + }, + [VPDMA_DATA_FMT_RAW16] = { + .type = VPDMA_DATA_FMT_TYPE_YUV, + .data_type = DATA_TYPE_CBY422, + .depth = 16, + }, +}; +EXPORT_SYMBOL(vpdma_raw_fmts); + +const struct vpdma_data_format vpdma_misc_fmts[] = { + [VPDMA_DATA_FMT_MV] = { + .type = VPDMA_DATA_FMT_TYPE_MISC, + .data_type = DATA_TYPE_MV, + .depth = 4, + }, +}; +EXPORT_SYMBOL(vpdma_misc_fmts); + +struct vpdma_channel_info { + int num; /* VPDMA channel number */ + int cstat_offset; /* client CSTAT register offset */ +}; + +static const struct vpdma_channel_info chan_info[] = { + [VPE_CHAN_LUMA1_IN] = { + .num = VPE_CHAN_NUM_LUMA1_IN, + .cstat_offset = VPDMA_DEI_LUMA1_CSTAT, + }, + [VPE_CHAN_CHROMA1_IN] = { + .num = VPE_CHAN_NUM_CHROMA1_IN, + .cstat_offset = VPDMA_DEI_CHROMA1_CSTAT, + }, + [VPE_CHAN_LUMA2_IN] = { + .num = VPE_CHAN_NUM_LUMA2_IN, + .cstat_offset = VPDMA_DEI_LUMA2_CSTAT, + }, + [VPE_CHAN_CHROMA2_IN] = { + .num = VPE_CHAN_NUM_CHROMA2_IN, + .cstat_offset = VPDMA_DEI_CHROMA2_CSTAT, + }, + [VPE_CHAN_LUMA3_IN] = { + .num = VPE_CHAN_NUM_LUMA3_IN, + .cstat_offset = VPDMA_DEI_LUMA3_CSTAT, + }, + [VPE_CHAN_CHROMA3_IN] = { + .num = VPE_CHAN_NUM_CHROMA3_IN, + .cstat_offset = VPDMA_DEI_CHROMA3_CSTAT, + }, + [VPE_CHAN_MV_IN] = { + .num = VPE_CHAN_NUM_MV_IN, + .cstat_offset = VPDMA_DEI_MV_IN_CSTAT, + }, + [VPE_CHAN_MV_OUT] = { + .num = VPE_CHAN_NUM_MV_OUT, + .cstat_offset = VPDMA_DEI_MV_OUT_CSTAT, + }, + [VPE_CHAN_LUMA_OUT] = { + .num = VPE_CHAN_NUM_LUMA_OUT, + .cstat_offset = VPDMA_VIP_UP_Y_CSTAT, + }, + [VPE_CHAN_CHROMA_OUT] = { + .num = VPE_CHAN_NUM_CHROMA_OUT, + .cstat_offset = VPDMA_VIP_UP_UV_CSTAT, + }, + [VPE_CHAN_RGB_OUT] = { + .num = VPE_CHAN_NUM_RGB_OUT, + .cstat_offset = VPDMA_VIP_UP_Y_CSTAT, + }, +}; + +static u32 read_reg(struct vpdma_data *vpdma, int offset) +{ + return ioread32(vpdma->base + offset); +} + +static void write_reg(struct vpdma_data *vpdma, int offset, u32 value) +{ + iowrite32(value, vpdma->base + offset); +} + +static int read_field_reg(struct vpdma_data *vpdma, int offset, + u32 mask, int shift) +{ + return (read_reg(vpdma, offset) & (mask << shift)) >> shift; +} + +static void write_field_reg(struct vpdma_data *vpdma, int offset, u32 field, + u32 mask, int shift) +{ + u32 val = read_reg(vpdma, offset); + + val &= ~(mask << shift); + val |= (field & mask) << shift; + + write_reg(vpdma, offset, val); +} + +void vpdma_dump_regs(struct vpdma_data *vpdma) +{ + struct device *dev = &vpdma->pdev->dev; + +#define DUMPREG(r) dev_dbg(dev, "%-35s %08x\n", #r, read_reg(vpdma, VPDMA_##r)) + + dev_dbg(dev, "VPDMA Registers:\n"); + + DUMPREG(PID); + DUMPREG(LIST_ADDR); + DUMPREG(LIST_ATTR); + DUMPREG(LIST_STAT_SYNC); + DUMPREG(BG_RGB); + DUMPREG(BG_YUV); + DUMPREG(SETUP); + DUMPREG(MAX_SIZE1); + DUMPREG(MAX_SIZE2); + DUMPREG(MAX_SIZE3); + + /* + * dumping registers of only group0 and group3, because VPE channels + * lie within group0 and group3 registers + */ + DUMPREG(INT_CHAN_STAT(0)); + DUMPREG(INT_CHAN_MASK(0)); + DUMPREG(INT_CHAN_STAT(3)); + DUMPREG(INT_CHAN_MASK(3)); + DUMPREG(INT_CLIENT0_STAT); + DUMPREG(INT_CLIENT0_MASK); + DUMPREG(INT_CLIENT1_STAT); + DUMPREG(INT_CLIENT1_MASK); + DUMPREG(INT_LIST0_STAT); + DUMPREG(INT_LIST0_MASK); + + /* + * these are registers specific to VPE clients, we can make this + * function dump client registers specific to VPE or VIP based on + * who is using it + */ + DUMPREG(DEI_CHROMA1_CSTAT); + DUMPREG(DEI_LUMA1_CSTAT); + DUMPREG(DEI_CHROMA2_CSTAT); + DUMPREG(DEI_LUMA2_CSTAT); + DUMPREG(DEI_CHROMA3_CSTAT); + DUMPREG(DEI_LUMA3_CSTAT); + DUMPREG(DEI_MV_IN_CSTAT); + DUMPREG(DEI_MV_OUT_CSTAT); + DUMPREG(VIP_UP_Y_CSTAT); + DUMPREG(VIP_UP_UV_CSTAT); + DUMPREG(VPI_CTL_CSTAT); +} +EXPORT_SYMBOL(vpdma_dump_regs); + +/* + * Allocate a DMA buffer + */ +int vpdma_alloc_desc_buf(struct vpdma_buf *buf, size_t size) +{ + buf->size = size; + buf->mapped = false; + buf->addr = kzalloc(size, GFP_KERNEL); + if (!buf->addr) + return -ENOMEM; + + WARN_ON(((unsigned long)buf->addr & VPDMA_DESC_ALIGN) != 0); + + return 0; +} +EXPORT_SYMBOL(vpdma_alloc_desc_buf); + +void vpdma_free_desc_buf(struct vpdma_buf *buf) +{ + WARN_ON(buf->mapped); + kfree(buf->addr); + buf->addr = NULL; + buf->size = 0; +} +EXPORT_SYMBOL(vpdma_free_desc_buf); + +/* + * map descriptor/payload DMA buffer, enabling DMA access + */ +int vpdma_map_desc_buf(struct vpdma_data *vpdma, struct vpdma_buf *buf) +{ + struct device *dev = &vpdma->pdev->dev; + + WARN_ON(buf->mapped); + buf->dma_addr = dma_map_single(dev, buf->addr, buf->size, + DMA_BIDIRECTIONAL); + if (dma_mapping_error(dev, buf->dma_addr)) { + dev_err(dev, "failed to map buffer\n"); + return -EINVAL; + } + + buf->mapped = true; + + return 0; +} +EXPORT_SYMBOL(vpdma_map_desc_buf); + +/* + * unmap descriptor/payload DMA buffer, disabling DMA access and + * allowing the main processor to access the data + */ +void vpdma_unmap_desc_buf(struct vpdma_data *vpdma, struct vpdma_buf *buf) +{ + struct device *dev = &vpdma->pdev->dev; + + if (buf->mapped) + dma_unmap_single(dev, buf->dma_addr, buf->size, + DMA_BIDIRECTIONAL); + + buf->mapped = false; +} +EXPORT_SYMBOL(vpdma_unmap_desc_buf); + +/* + * Cleanup all pending descriptors of a list + * First, stop the current list being processed. + * If the VPDMA was busy, this step makes vpdma to accept post lists. + * To cleanup the internal FSM, post abort list descriptor for all the + * channels from @channels array of size @size. + */ +int vpdma_list_cleanup(struct vpdma_data *vpdma, int list_num, + int *channels, int size) +{ + struct vpdma_desc_list abort_list; + int i, ret, timeout = 500; + + write_reg(vpdma, VPDMA_LIST_ATTR, + (list_num << VPDMA_LIST_NUM_SHFT) | + (1 << VPDMA_LIST_STOP_SHFT)); + + if (size <= 0 || !channels) + return 0; + + ret = vpdma_create_desc_list(&abort_list, + size * sizeof(struct vpdma_dtd), VPDMA_LIST_TYPE_NORMAL); + if (ret) + return ret; + + for (i = 0; i < size; i++) + vpdma_add_abort_channel_ctd(&abort_list, channels[i]); + + ret = vpdma_map_desc_buf(vpdma, &abort_list.buf); + if (ret) + goto free_desc; + ret = vpdma_submit_descs(vpdma, &abort_list, list_num); + if (ret) + goto unmap_desc; + + while (vpdma_list_busy(vpdma, list_num) && --timeout) + ; + + if (timeout == 0) { + dev_err(&vpdma->pdev->dev, "Timed out cleaning up VPDMA list\n"); + ret = -EBUSY; + } + +unmap_desc: + vpdma_unmap_desc_buf(vpdma, &abort_list.buf); +free_desc: + vpdma_free_desc_buf(&abort_list.buf); + + return ret; +} +EXPORT_SYMBOL(vpdma_list_cleanup); + +/* + * create a descriptor list, the user of this list will append configuration, + * control and data descriptors to this list, this list will be submitted to + * VPDMA. VPDMA's list parser will go through each descriptor and perform the + * required DMA operations + */ +int vpdma_create_desc_list(struct vpdma_desc_list *list, size_t size, int type) +{ + int r; + + r = vpdma_alloc_desc_buf(&list->buf, size); + if (r) + return r; + + list->next = list->buf.addr; + + list->type = type; + + return 0; +} +EXPORT_SYMBOL(vpdma_create_desc_list); + +/* + * once a descriptor list is parsed by VPDMA, we reset the list by emptying it, + * to allow new descriptors to be added to the list. + */ +void vpdma_reset_desc_list(struct vpdma_desc_list *list) +{ + list->next = list->buf.addr; +} +EXPORT_SYMBOL(vpdma_reset_desc_list); + +/* + * free the buffer allocated for the VPDMA descriptor list, this should be + * called when the user doesn't want to use VPDMA any more. + */ +void vpdma_free_desc_list(struct vpdma_desc_list *list) +{ + vpdma_free_desc_buf(&list->buf); + + list->next = NULL; +} +EXPORT_SYMBOL(vpdma_free_desc_list); + +bool vpdma_list_busy(struct vpdma_data *vpdma, int list_num) +{ + return read_reg(vpdma, VPDMA_LIST_STAT_SYNC) & BIT(list_num + 16); +} +EXPORT_SYMBOL(vpdma_list_busy); + +/* + * submit a list of DMA descriptors to the VPE VPDMA, do not wait for completion + */ +int vpdma_submit_descs(struct vpdma_data *vpdma, + struct vpdma_desc_list *list, int list_num) +{ + int list_size; + unsigned long flags; + + if (vpdma_list_busy(vpdma, list_num)) + return -EBUSY; + + /* 16-byte granularity */ + list_size = (list->next - list->buf.addr) >> 4; + + spin_lock_irqsave(&vpdma->lock, flags); + write_reg(vpdma, VPDMA_LIST_ADDR, (u32) list->buf.dma_addr); + + write_reg(vpdma, VPDMA_LIST_ATTR, + (list_num << VPDMA_LIST_NUM_SHFT) | + (list->type << VPDMA_LIST_TYPE_SHFT) | + list_size); + spin_unlock_irqrestore(&vpdma->lock, flags); + + return 0; +} +EXPORT_SYMBOL(vpdma_submit_descs); + +static void dump_dtd(struct vpdma_dtd *dtd); + +void vpdma_update_dma_addr(struct vpdma_data *vpdma, + struct vpdma_desc_list *list, dma_addr_t dma_addr, + void *write_dtd, int drop, int idx) +{ + struct vpdma_dtd *dtd = list->buf.addr; + dma_addr_t write_desc_addr; + int offset; + + dtd += idx; + vpdma_unmap_desc_buf(vpdma, &list->buf); + + dtd->start_addr = dma_addr; + + /* Calculate write address from the offset of write_dtd from start + * of the list->buf + */ + offset = (void *)write_dtd - list->buf.addr; + write_desc_addr = list->buf.dma_addr + offset; + + if (drop) + dtd->desc_write_addr = dtd_desc_write_addr(write_desc_addr, + 1, 1, 0); + else + dtd->desc_write_addr = dtd_desc_write_addr(write_desc_addr, + 1, 0, 0); + + vpdma_map_desc_buf(vpdma, &list->buf); + + dump_dtd(dtd); +} +EXPORT_SYMBOL(vpdma_update_dma_addr); + +void vpdma_set_max_size(struct vpdma_data *vpdma, int reg_addr, + u32 width, u32 height) +{ + if (reg_addr != VPDMA_MAX_SIZE1 && reg_addr != VPDMA_MAX_SIZE2 && + reg_addr != VPDMA_MAX_SIZE3) + reg_addr = VPDMA_MAX_SIZE1; + + write_field_reg(vpdma, reg_addr, width - 1, + VPDMA_MAX_SIZE_WIDTH_MASK, VPDMA_MAX_SIZE_WIDTH_SHFT); + + write_field_reg(vpdma, reg_addr, height - 1, + VPDMA_MAX_SIZE_HEIGHT_MASK, VPDMA_MAX_SIZE_HEIGHT_SHFT); + +} +EXPORT_SYMBOL(vpdma_set_max_size); + +static void dump_cfd(struct vpdma_cfd *cfd) +{ + int class; + + class = cfd_get_class(cfd); + + pr_debug("config descriptor of payload class: %s\n", + class == CFD_CLS_BLOCK ? "simple block" : + "address data block"); + + if (class == CFD_CLS_BLOCK) + pr_debug("word0: dst_addr_offset = 0x%08x\n", + cfd->dest_addr_offset); + + if (class == CFD_CLS_BLOCK) + pr_debug("word1: num_data_wrds = %d\n", cfd->block_len); + + pr_debug("word2: payload_addr = 0x%08x\n", cfd->payload_addr); + + pr_debug("word3: pkt_type = %d, direct = %d, class = %d, dest = %d, payload_len = %d\n", + cfd_get_pkt_type(cfd), + cfd_get_direct(cfd), class, cfd_get_dest(cfd), + cfd_get_payload_len(cfd)); +} + +/* + * append a configuration descriptor to the given descriptor list, where the + * payload is in the form of a simple data block specified in the descriptor + * header, this is used to upload scaler coefficients to the scaler module + */ +void vpdma_add_cfd_block(struct vpdma_desc_list *list, int client, + struct vpdma_buf *blk, u32 dest_offset) +{ + struct vpdma_cfd *cfd; + int len = blk->size; + + WARN_ON(blk->dma_addr & VPDMA_DESC_ALIGN); + + cfd = list->next; + WARN_ON((void *)(cfd + 1) > (list->buf.addr + list->buf.size)); + + cfd->dest_addr_offset = dest_offset; + cfd->block_len = len; + cfd->payload_addr = (u32) blk->dma_addr; + cfd->ctl_payload_len = cfd_pkt_payload_len(CFD_INDIRECT, CFD_CLS_BLOCK, + client, len >> 4); + + list->next = cfd + 1; + + dump_cfd(cfd); +} +EXPORT_SYMBOL(vpdma_add_cfd_block); + +/* + * append a configuration descriptor to the given descriptor list, where the + * payload is in the address data block format, this is used to a configure a + * discontiguous set of MMRs + */ +void vpdma_add_cfd_adb(struct vpdma_desc_list *list, int client, + struct vpdma_buf *adb) +{ + struct vpdma_cfd *cfd; + unsigned int len = adb->size; + + WARN_ON(len & VPDMA_ADB_SIZE_ALIGN); + WARN_ON(adb->dma_addr & VPDMA_DESC_ALIGN); + + cfd = list->next; + BUG_ON((void *)(cfd + 1) > (list->buf.addr + list->buf.size)); + + cfd->w0 = 0; + cfd->w1 = 0; + cfd->payload_addr = (u32) adb->dma_addr; + cfd->ctl_payload_len = cfd_pkt_payload_len(CFD_INDIRECT, CFD_CLS_ADB, + client, len >> 4); + + list->next = cfd + 1; + + dump_cfd(cfd); +}; +EXPORT_SYMBOL(vpdma_add_cfd_adb); + +/* + * control descriptor format change based on what type of control descriptor it + * is, we only use 'sync on channel' control descriptors for now, so assume it's + * that + */ +static void dump_ctd(struct vpdma_ctd *ctd) +{ + pr_debug("control descriptor\n"); + + pr_debug("word3: pkt_type = %d, source = %d, ctl_type = %d\n", + ctd_get_pkt_type(ctd), ctd_get_source(ctd), ctd_get_ctl(ctd)); +} + +/* + * append a 'sync on channel' type control descriptor to the given descriptor + * list, this descriptor stalls the VPDMA list till the time DMA is completed + * on the specified channel + */ +void vpdma_add_sync_on_channel_ctd(struct vpdma_desc_list *list, + enum vpdma_channel chan) +{ + struct vpdma_ctd *ctd; + + ctd = list->next; + WARN_ON((void *)(ctd + 1) > (list->buf.addr + list->buf.size)); + + ctd->w0 = 0; + ctd->w1 = 0; + ctd->w2 = 0; + ctd->type_source_ctl = ctd_type_source_ctl(chan_info[chan].num, + CTD_TYPE_SYNC_ON_CHANNEL); + + list->next = ctd + 1; + + dump_ctd(ctd); +} +EXPORT_SYMBOL(vpdma_add_sync_on_channel_ctd); + +/* + * append an 'abort_channel' type control descriptor to the given descriptor + * list, this descriptor aborts any DMA transaction happening using the + * specified channel + */ +void vpdma_add_abort_channel_ctd(struct vpdma_desc_list *list, + int chan_num) +{ + struct vpdma_ctd *ctd; + + ctd = list->next; + WARN_ON((void *)(ctd + 1) > (list->buf.addr + list->buf.size)); + + ctd->w0 = 0; + ctd->w1 = 0; + ctd->w2 = 0; + ctd->type_source_ctl = ctd_type_source_ctl(chan_num, + CTD_TYPE_ABORT_CHANNEL); + + list->next = ctd + 1; + + dump_ctd(ctd); +} +EXPORT_SYMBOL(vpdma_add_abort_channel_ctd); + +static void dump_dtd(struct vpdma_dtd *dtd) +{ + int dir, chan; + + dir = dtd_get_dir(dtd); + chan = dtd_get_chan(dtd); + + pr_debug("%s data transfer descriptor for channel %d\n", + dir == DTD_DIR_OUT ? "outbound" : "inbound", chan); + + pr_debug("word0: data_type = %d, notify = %d, field = %d, 1D = %d, even_ln_skp = %d, odd_ln_skp = %d, line_stride = %d\n", + dtd_get_data_type(dtd), dtd_get_notify(dtd), dtd_get_field(dtd), + dtd_get_1d(dtd), dtd_get_even_line_skip(dtd), + dtd_get_odd_line_skip(dtd), dtd_get_line_stride(dtd)); + + if (dir == DTD_DIR_IN) + pr_debug("word1: line_length = %d, xfer_height = %d\n", + dtd_get_line_length(dtd), dtd_get_xfer_height(dtd)); + + pr_debug("word2: start_addr = %x\n", dtd->start_addr); + + pr_debug("word3: pkt_type = %d, mode = %d, dir = %d, chan = %d, pri = %d, next_chan = %d\n", + dtd_get_pkt_type(dtd), + dtd_get_mode(dtd), dir, chan, dtd_get_priority(dtd), + dtd_get_next_chan(dtd)); + + if (dir == DTD_DIR_IN) + pr_debug("word4: frame_width = %d, frame_height = %d\n", + dtd_get_frame_width(dtd), dtd_get_frame_height(dtd)); + else + pr_debug("word4: desc_write_addr = 0x%08x, write_desc = %d, drp_data = %d, use_desc_reg = %d\n", + dtd_get_desc_write_addr(dtd), dtd_get_write_desc(dtd), + dtd_get_drop_data(dtd), dtd_get_use_desc(dtd)); + + if (dir == DTD_DIR_IN) + pr_debug("word5: hor_start = %d, ver_start = %d\n", + dtd_get_h_start(dtd), dtd_get_v_start(dtd)); + else + pr_debug("word5: max_width %d, max_height %d\n", + dtd_get_max_width(dtd), dtd_get_max_height(dtd)); + + pr_debug("word6: client specific attr0 = 0x%08x\n", dtd->client_attr0); + pr_debug("word7: client specific attr1 = 0x%08x\n", dtd->client_attr1); +} + +/* + * append an outbound data transfer descriptor to the given descriptor list, + * this sets up a 'client to memory' VPDMA transfer for the given VPDMA channel + * + * @list: vpdma desc list to which we add this descriptor + * @width: width of the image in pixels in memory + * @c_rect: compose params of output image + * @fmt: vpdma data format of the buffer + * dma_addr: dma address as seen by VPDMA + * max_width: enum for maximum width of data transfer + * max_height: enum for maximum height of data transfer + * chan: VPDMA channel + * flags: VPDMA flags to configure some descriptor fields + */ +void vpdma_add_out_dtd(struct vpdma_desc_list *list, int width, + int stride, const struct v4l2_rect *c_rect, + const struct vpdma_data_format *fmt, dma_addr_t dma_addr, + int max_w, int max_h, enum vpdma_channel chan, u32 flags) +{ + vpdma_rawchan_add_out_dtd(list, width, stride, c_rect, fmt, dma_addr, + max_w, max_h, chan_info[chan].num, flags); +} +EXPORT_SYMBOL(vpdma_add_out_dtd); + +void vpdma_rawchan_add_out_dtd(struct vpdma_desc_list *list, int width, + int stride, const struct v4l2_rect *c_rect, + const struct vpdma_data_format *fmt, dma_addr_t dma_addr, + int max_w, int max_h, int raw_vpdma_chan, u32 flags) +{ + int priority = 0; + int field = 0; + int notify = 1; + int channel, next_chan; + struct v4l2_rect rect = *c_rect; + int depth = fmt->depth; + struct vpdma_dtd *dtd; + + channel = next_chan = raw_vpdma_chan; + + if (fmt->type == VPDMA_DATA_FMT_TYPE_YUV && + (fmt->data_type == DATA_TYPE_C420 || + fmt->data_type == DATA_TYPE_CB420)) { + rect.height >>= 1; + rect.top >>= 1; + depth = 8; + } + + dma_addr += rect.top * stride + (rect.left * depth >> 3); + + dtd = list->next; + WARN_ON((void *)(dtd + 1) > (list->buf.addr + list->buf.size)); + + dtd->type_ctl_stride = dtd_type_ctl_stride(fmt->data_type, + notify, + field, + !!(flags & VPDMA_DATA_FRAME_1D), + !!(flags & VPDMA_DATA_EVEN_LINE_SKIP), + !!(flags & VPDMA_DATA_ODD_LINE_SKIP), + stride); + dtd->w1 = 0; + dtd->start_addr = (u32) dma_addr; + dtd->pkt_ctl = dtd_pkt_ctl(!!(flags & VPDMA_DATA_MODE_TILED), + DTD_DIR_OUT, channel, priority, next_chan); + dtd->desc_write_addr = dtd_desc_write_addr(0, 0, 0, 0); + dtd->max_width_height = dtd_max_width_height(max_w, max_h); + dtd->client_attr0 = 0; + dtd->client_attr1 = 0; + + list->next = dtd + 1; + + dump_dtd(dtd); +} +EXPORT_SYMBOL(vpdma_rawchan_add_out_dtd); + +/* + * append an inbound data transfer descriptor to the given descriptor list, + * this sets up a 'memory to client' VPDMA transfer for the given VPDMA channel + * + * @list: vpdma desc list to which we add this descriptor + * @width: width of the image in pixels in memory(not the cropped width) + * @c_rect: crop params of input image + * @fmt: vpdma data format of the buffer + * dma_addr: dma address as seen by VPDMA + * chan: VPDMA channel + * field: top or bottom field info of the input image + * flags: VPDMA flags to configure some descriptor fields + * frame_width/height: the complete width/height of the image presented to the + * client (this makes sense when multiple channels are + * connected to the same client, forming a larger frame) + * start_h, start_v: position where the given channel starts providing pixel + * data to the client (makes sense when multiple channels + * contribute to the client) + */ +void vpdma_add_in_dtd(struct vpdma_desc_list *list, int width, + int stride, const struct v4l2_rect *c_rect, + const struct vpdma_data_format *fmt, dma_addr_t dma_addr, + enum vpdma_channel chan, int field, u32 flags, int frame_width, + int frame_height, int start_h, int start_v) +{ + int priority = 0; + int notify = 1; + int depth = fmt->depth; + int channel, next_chan; + struct v4l2_rect rect = *c_rect; + struct vpdma_dtd *dtd; + + channel = next_chan = chan_info[chan].num; + + if (fmt->type == VPDMA_DATA_FMT_TYPE_YUV && + (fmt->data_type == DATA_TYPE_C420 || + fmt->data_type == DATA_TYPE_CB420)) { + rect.height >>= 1; + rect.top >>= 1; + depth = 8; + } + + dma_addr += rect.top * stride + (rect.left * depth >> 3); + + dtd = list->next; + WARN_ON((void *)(dtd + 1) > (list->buf.addr + list->buf.size)); + + dtd->type_ctl_stride = dtd_type_ctl_stride(fmt->data_type, + notify, + field, + !!(flags & VPDMA_DATA_FRAME_1D), + !!(flags & VPDMA_DATA_EVEN_LINE_SKIP), + !!(flags & VPDMA_DATA_ODD_LINE_SKIP), + stride); + + dtd->xfer_length_height = dtd_xfer_length_height(rect.width, + rect.height); + dtd->start_addr = (u32) dma_addr; + dtd->pkt_ctl = dtd_pkt_ctl(!!(flags & VPDMA_DATA_MODE_TILED), + DTD_DIR_IN, channel, priority, next_chan); + dtd->frame_width_height = dtd_frame_width_height(frame_width, + frame_height); + dtd->start_h_v = dtd_start_h_v(start_h, start_v); + dtd->client_attr0 = 0; + dtd->client_attr1 = 0; + + list->next = dtd + 1; + + dump_dtd(dtd); +} +EXPORT_SYMBOL(vpdma_add_in_dtd); + +int vpdma_hwlist_alloc(struct vpdma_data *vpdma, void *priv) +{ + int i, list_num = -1; + unsigned long flags; + + spin_lock_irqsave(&vpdma->lock, flags); + for (i = 0; i < VPDMA_MAX_NUM_LIST && vpdma->hwlist_used[i]; i++) + ; + + if (i < VPDMA_MAX_NUM_LIST) { + list_num = i; + vpdma->hwlist_used[i] = true; + vpdma->hwlist_priv[i] = priv; + } + spin_unlock_irqrestore(&vpdma->lock, flags); + + return list_num; +} +EXPORT_SYMBOL(vpdma_hwlist_alloc); + +void *vpdma_hwlist_get_priv(struct vpdma_data *vpdma, int list_num) +{ + if (!vpdma || list_num >= VPDMA_MAX_NUM_LIST) + return NULL; + + return vpdma->hwlist_priv[list_num]; +} +EXPORT_SYMBOL(vpdma_hwlist_get_priv); + +void *vpdma_hwlist_release(struct vpdma_data *vpdma, int list_num) +{ + void *priv; + unsigned long flags; + + spin_lock_irqsave(&vpdma->lock, flags); + vpdma->hwlist_used[list_num] = false; + priv = vpdma->hwlist_priv; + spin_unlock_irqrestore(&vpdma->lock, flags); + + return priv; +} +EXPORT_SYMBOL(vpdma_hwlist_release); + +/* set or clear the mask for list complete interrupt */ +void vpdma_enable_list_complete_irq(struct vpdma_data *vpdma, int irq_num, + int list_num, bool enable) +{ + u32 reg_addr = VPDMA_INT_LIST0_MASK + VPDMA_INTX_OFFSET * irq_num; + u32 val; + + val = read_reg(vpdma, reg_addr); + if (enable) + val |= (1 << (list_num * 2)); + else + val &= ~(1 << (list_num * 2)); + write_reg(vpdma, reg_addr, val); +} +EXPORT_SYMBOL(vpdma_enable_list_complete_irq); + +/* get the LIST_STAT register */ +unsigned int vpdma_get_list_stat(struct vpdma_data *vpdma, int irq_num) +{ + u32 reg_addr = VPDMA_INT_LIST0_STAT + VPDMA_INTX_OFFSET * irq_num; + + return read_reg(vpdma, reg_addr); +} +EXPORT_SYMBOL(vpdma_get_list_stat); + +/* get the LIST_MASK register */ +unsigned int vpdma_get_list_mask(struct vpdma_data *vpdma, int irq_num) +{ + u32 reg_addr = VPDMA_INT_LIST0_MASK + VPDMA_INTX_OFFSET * irq_num; + + return read_reg(vpdma, reg_addr); +} +EXPORT_SYMBOL(vpdma_get_list_mask); + +/* clear previously occurred list interrupts in the LIST_STAT register */ +void vpdma_clear_list_stat(struct vpdma_data *vpdma, int irq_num, + int list_num) +{ + u32 reg_addr = VPDMA_INT_LIST0_STAT + VPDMA_INTX_OFFSET * irq_num; + + write_reg(vpdma, reg_addr, 3 << (list_num * 2)); +} +EXPORT_SYMBOL(vpdma_clear_list_stat); + +void vpdma_set_bg_color(struct vpdma_data *vpdma, + struct vpdma_data_format *fmt, u32 color) +{ + if (fmt->type == VPDMA_DATA_FMT_TYPE_RGB) + write_reg(vpdma, VPDMA_BG_RGB, color); + else if (fmt->type == VPDMA_DATA_FMT_TYPE_YUV) + write_reg(vpdma, VPDMA_BG_YUV, color); +} +EXPORT_SYMBOL(vpdma_set_bg_color); + +/* + * configures the output mode of the line buffer for the given client, the + * line buffer content can either be mirrored(each line repeated twice) or + * passed to the client as is + */ +void vpdma_set_line_mode(struct vpdma_data *vpdma, int line_mode, + enum vpdma_channel chan) +{ + int client_cstat = chan_info[chan].cstat_offset; + + write_field_reg(vpdma, client_cstat, line_mode, + VPDMA_CSTAT_LINE_MODE_MASK, VPDMA_CSTAT_LINE_MODE_SHIFT); +} +EXPORT_SYMBOL(vpdma_set_line_mode); + +/* + * configures the event which should trigger VPDMA transfer for the given + * client + */ +void vpdma_set_frame_start_event(struct vpdma_data *vpdma, + enum vpdma_frame_start_event fs_event, + enum vpdma_channel chan) +{ + int client_cstat = chan_info[chan].cstat_offset; + + write_field_reg(vpdma, client_cstat, fs_event, + VPDMA_CSTAT_FRAME_START_MASK, VPDMA_CSTAT_FRAME_START_SHIFT); +} +EXPORT_SYMBOL(vpdma_set_frame_start_event); + +static void vpdma_firmware_cb(const struct firmware *f, void *context) +{ + struct vpdma_data *vpdma = context; + struct vpdma_buf fw_dma_buf; + int i, r; + + dev_dbg(&vpdma->pdev->dev, "firmware callback\n"); + + if (!f || !f->data) { + dev_err(&vpdma->pdev->dev, "couldn't get firmware\n"); + return; + } + + /* already initialized */ + if (read_field_reg(vpdma, VPDMA_LIST_ATTR, VPDMA_LIST_RDY_MASK, + VPDMA_LIST_RDY_SHFT)) { + vpdma->cb(vpdma->pdev); + return; + } + + r = vpdma_alloc_desc_buf(&fw_dma_buf, f->size); + if (r) { + dev_err(&vpdma->pdev->dev, + "failed to allocate dma buffer for firmware\n"); + goto rel_fw; + } + + memcpy(fw_dma_buf.addr, f->data, f->size); + + vpdma_map_desc_buf(vpdma, &fw_dma_buf); + + write_reg(vpdma, VPDMA_LIST_ADDR, (u32) fw_dma_buf.dma_addr); + + for (i = 0; i < 100; i++) { /* max 1 second */ + msleep_interruptible(10); + + if (read_field_reg(vpdma, VPDMA_LIST_ATTR, VPDMA_LIST_RDY_MASK, + VPDMA_LIST_RDY_SHFT)) + break; + } + + if (i == 100) { + dev_err(&vpdma->pdev->dev, "firmware upload failed\n"); + goto free_buf; + } + + vpdma->cb(vpdma->pdev); + +free_buf: + vpdma_unmap_desc_buf(vpdma, &fw_dma_buf); + + vpdma_free_desc_buf(&fw_dma_buf); +rel_fw: + release_firmware(f); +} + +static int vpdma_load_firmware(struct vpdma_data *vpdma) +{ + int r; + struct device *dev = &vpdma->pdev->dev; + + r = request_firmware_nowait(THIS_MODULE, 1, + (const char *) VPDMA_FIRMWARE, dev, GFP_KERNEL, vpdma, + vpdma_firmware_cb); + if (r) { + dev_err(dev, "firmware not available %s\n", VPDMA_FIRMWARE); + return r; + } else { + dev_info(dev, "loading firmware %s\n", VPDMA_FIRMWARE); + } + + return 0; +} + +int vpdma_create(struct platform_device *pdev, struct vpdma_data *vpdma, + void (*cb)(struct platform_device *pdev)) +{ + struct resource *res; + int r; + + dev_dbg(&pdev->dev, "vpdma_create\n"); + + vpdma->pdev = pdev; + vpdma->cb = cb; + spin_lock_init(&vpdma->lock); + + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "vpdma"); + if (res == NULL) { + dev_err(&pdev->dev, "missing platform resources data\n"); + return -ENODEV; + } + + vpdma->base = devm_ioremap(&pdev->dev, res->start, resource_size(res)); + if (!vpdma->base) { + dev_err(&pdev->dev, "failed to ioremap\n"); + return -ENOMEM; + } + + r = vpdma_load_firmware(vpdma); + if (r) { + pr_err("failed to load firmware %s\n", VPDMA_FIRMWARE); + return r; + } + + return 0; +} +EXPORT_SYMBOL(vpdma_create); + +MODULE_AUTHOR("Texas Instruments Inc."); +MODULE_FIRMWARE(VPDMA_FIRMWARE); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/platform/ti/vpe/vpdma.h b/drivers/media/platform/ti/vpe/vpdma.h new file mode 100644 index 000000000000..393fcbb3cb40 --- /dev/null +++ b/drivers/media/platform/ti/vpe/vpdma.h @@ -0,0 +1,284 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2013 Texas Instruments Inc. + * + * David Griego, + * Dale Farnsworth, + * Archit Taneja, + */ + +#ifndef __TI_VPDMA_H_ +#define __TI_VPDMA_H_ + +#define VPDMA_MAX_NUM_LIST 8 +/* + * A vpdma_buf tracks the size, DMA address and mapping status of each + * driver DMA area. + */ +struct vpdma_buf { + void *addr; + dma_addr_t dma_addr; + size_t size; + bool mapped; +}; + +struct vpdma_desc_list { + struct vpdma_buf buf; + void *next; + int type; +}; + +struct vpdma_data { + void __iomem *base; + + struct platform_device *pdev; + + spinlock_t lock; + bool hwlist_used[VPDMA_MAX_NUM_LIST]; + void *hwlist_priv[VPDMA_MAX_NUM_LIST]; + /* callback to VPE driver when the firmware is loaded */ + void (*cb)(struct platform_device *pdev); +}; + +enum vpdma_data_format_type { + VPDMA_DATA_FMT_TYPE_YUV, + VPDMA_DATA_FMT_TYPE_RGB, + VPDMA_DATA_FMT_TYPE_MISC, +}; + +struct vpdma_data_format { + enum vpdma_data_format_type type; + int data_type; + u8 depth; +}; + +#define VPDMA_DESC_ALIGN 16 /* 16-byte descriptor alignment */ +#define VPDMA_STRIDE_ALIGN 16 /* + * line stride of source and dest + * buffers should be 16 byte aligned + */ +#define VPDMA_MAX_STRIDE 65520 /* Max line stride 16 byte aligned */ +#define VPDMA_DTD_DESC_SIZE 32 /* 8 words */ +#define VPDMA_CFD_CTD_DESC_SIZE 16 /* 4 words */ + +#define VPDMA_LIST_TYPE_NORMAL 0 +#define VPDMA_LIST_TYPE_SELF_MODIFYING 1 +#define VPDMA_LIST_TYPE_DOORBELL 2 + +enum vpdma_yuv_formats { + VPDMA_DATA_FMT_Y444 = 0, + VPDMA_DATA_FMT_Y422, + VPDMA_DATA_FMT_Y420, + VPDMA_DATA_FMT_C444, + VPDMA_DATA_FMT_C422, + VPDMA_DATA_FMT_C420, + VPDMA_DATA_FMT_CB420, + VPDMA_DATA_FMT_YCR422, + VPDMA_DATA_FMT_YC444, + VPDMA_DATA_FMT_CRY422, + VPDMA_DATA_FMT_CBY422, + VPDMA_DATA_FMT_YCB422, +}; + +enum vpdma_rgb_formats { + VPDMA_DATA_FMT_RGB565 = 0, + VPDMA_DATA_FMT_ARGB16_1555, + VPDMA_DATA_FMT_ARGB16, + VPDMA_DATA_FMT_RGBA16_5551, + VPDMA_DATA_FMT_RGBA16, + VPDMA_DATA_FMT_ARGB24, + VPDMA_DATA_FMT_RGB24, + VPDMA_DATA_FMT_ARGB32, + VPDMA_DATA_FMT_RGBA24, + VPDMA_DATA_FMT_RGBA32, + VPDMA_DATA_FMT_BGR565, + VPDMA_DATA_FMT_ABGR16_1555, + VPDMA_DATA_FMT_ABGR16, + VPDMA_DATA_FMT_BGRA16_5551, + VPDMA_DATA_FMT_BGRA16, + VPDMA_DATA_FMT_ABGR24, + VPDMA_DATA_FMT_BGR24, + VPDMA_DATA_FMT_ABGR32, + VPDMA_DATA_FMT_BGRA24, + VPDMA_DATA_FMT_BGRA32, +}; + +enum vpdma_raw_formats { + VPDMA_DATA_FMT_RAW8 = 0, + VPDMA_DATA_FMT_RAW16, +}; + +enum vpdma_misc_formats { + VPDMA_DATA_FMT_MV = 0, +}; + +extern const struct vpdma_data_format vpdma_yuv_fmts[]; +extern const struct vpdma_data_format vpdma_rgb_fmts[]; +extern const struct vpdma_data_format vpdma_raw_fmts[]; +extern const struct vpdma_data_format vpdma_misc_fmts[]; + +enum vpdma_frame_start_event { + VPDMA_FSEVENT_HDMI_FID = 0, + VPDMA_FSEVENT_DVO2_FID, + VPDMA_FSEVENT_HDCOMP_FID, + VPDMA_FSEVENT_SD_FID, + VPDMA_FSEVENT_LM_FID0, + VPDMA_FSEVENT_LM_FID1, + VPDMA_FSEVENT_LM_FID2, + VPDMA_FSEVENT_CHANNEL_ACTIVE, +}; + +/* max width configurations */ +enum vpdma_max_width { + MAX_OUT_WIDTH_UNLIMITED = 0, + MAX_OUT_WIDTH_REG1, + MAX_OUT_WIDTH_REG2, + MAX_OUT_WIDTH_REG3, + MAX_OUT_WIDTH_352, + MAX_OUT_WIDTH_768, + MAX_OUT_WIDTH_1280, + MAX_OUT_WIDTH_1920, +}; + +/* max height configurations */ +enum vpdma_max_height { + MAX_OUT_HEIGHT_UNLIMITED = 0, + MAX_OUT_HEIGHT_REG1, + MAX_OUT_HEIGHT_REG2, + MAX_OUT_HEIGHT_REG3, + MAX_OUT_HEIGHT_288, + MAX_OUT_HEIGHT_576, + MAX_OUT_HEIGHT_720, + MAX_OUT_HEIGHT_1080, +}; + +/* + * VPDMA channel numbers + */ +enum vpdma_channel { + VPE_CHAN_LUMA1_IN, + VPE_CHAN_CHROMA1_IN, + VPE_CHAN_LUMA2_IN, + VPE_CHAN_CHROMA2_IN, + VPE_CHAN_LUMA3_IN, + VPE_CHAN_CHROMA3_IN, + VPE_CHAN_MV_IN, + VPE_CHAN_MV_OUT, + VPE_CHAN_LUMA_OUT, + VPE_CHAN_CHROMA_OUT, + VPE_CHAN_RGB_OUT, +}; + +#define VIP_CHAN_VIP2_OFFSET 70 +#define VIP_CHAN_MULT_PORTB_OFFSET 16 +#define VIP_CHAN_YUV_PORTB_OFFSET 2 +#define VIP_CHAN_RGB_PORTB_OFFSET 1 + +#define VPDMA_MAX_CHANNELS 256 + +/* flags for VPDMA data descriptors */ +#define VPDMA_DATA_ODD_LINE_SKIP (1 << 0) +#define VPDMA_DATA_EVEN_LINE_SKIP (1 << 1) +#define VPDMA_DATA_FRAME_1D (1 << 2) +#define VPDMA_DATA_MODE_TILED (1 << 3) + +/* + * client identifiers used for configuration descriptors + */ +#define CFD_MMR_CLIENT 0 +#define CFD_SC_CLIENT 4 + +/* Address data block header format */ +struct vpdma_adb_hdr { + u32 offset; + u32 nwords; + u32 reserved0; + u32 reserved1; +}; + +/* helpers for creating ADB headers for config descriptors MMRs as client */ +#define ADB_ADDR(dma_buf, str, fld) ((dma_buf)->addr + offsetof(str, fld)) +#define MMR_ADB_ADDR(buf, str, fld) ADB_ADDR(&(buf), struct str, fld) + +#define VPDMA_SET_MMR_ADB_HDR(buf, str, hdr, regs, offset_a) \ + do { \ + struct vpdma_adb_hdr *h; \ + struct str *adb = NULL; \ + h = MMR_ADB_ADDR(buf, str, hdr); \ + h->offset = (offset_a); \ + h->nwords = sizeof(adb->regs) >> 2; \ + } while (0) + +/* vpdma descriptor buffer allocation and management */ +int vpdma_alloc_desc_buf(struct vpdma_buf *buf, size_t size); +void vpdma_free_desc_buf(struct vpdma_buf *buf); +int vpdma_map_desc_buf(struct vpdma_data *vpdma, struct vpdma_buf *buf); +void vpdma_unmap_desc_buf(struct vpdma_data *vpdma, struct vpdma_buf *buf); + +/* vpdma descriptor list funcs */ +int vpdma_create_desc_list(struct vpdma_desc_list *list, size_t size, int type); +void vpdma_reset_desc_list(struct vpdma_desc_list *list); +void vpdma_free_desc_list(struct vpdma_desc_list *list); +int vpdma_submit_descs(struct vpdma_data *vpdma, struct vpdma_desc_list *list, + int list_num); +bool vpdma_list_busy(struct vpdma_data *vpdma, int list_num); +void vpdma_update_dma_addr(struct vpdma_data *vpdma, + struct vpdma_desc_list *list, dma_addr_t dma_addr, + void *write_dtd, int drop, int idx); + +/* VPDMA hardware list funcs */ +int vpdma_hwlist_alloc(struct vpdma_data *vpdma, void *priv); +void *vpdma_hwlist_get_priv(struct vpdma_data *vpdma, int list_num); +void *vpdma_hwlist_release(struct vpdma_data *vpdma, int list_num); + +/* helpers for creating vpdma descriptors */ +void vpdma_add_cfd_block(struct vpdma_desc_list *list, int client, + struct vpdma_buf *blk, u32 dest_offset); +void vpdma_add_cfd_adb(struct vpdma_desc_list *list, int client, + struct vpdma_buf *adb); +void vpdma_add_sync_on_channel_ctd(struct vpdma_desc_list *list, + enum vpdma_channel chan); +void vpdma_add_abort_channel_ctd(struct vpdma_desc_list *list, + int chan_num); +void vpdma_add_out_dtd(struct vpdma_desc_list *list, int width, + int stride, const struct v4l2_rect *c_rect, + const struct vpdma_data_format *fmt, dma_addr_t dma_addr, + int max_w, int max_h, enum vpdma_channel chan, u32 flags); +void vpdma_rawchan_add_out_dtd(struct vpdma_desc_list *list, int width, + int stride, const struct v4l2_rect *c_rect, + const struct vpdma_data_format *fmt, dma_addr_t dma_addr, + int max_w, int max_h, int raw_vpdma_chan, u32 flags); + +void vpdma_add_in_dtd(struct vpdma_desc_list *list, int width, + int stride, const struct v4l2_rect *c_rect, + const struct vpdma_data_format *fmt, dma_addr_t dma_addr, + enum vpdma_channel chan, int field, u32 flags, int frame_width, + int frame_height, int start_h, int start_v); +int vpdma_list_cleanup(struct vpdma_data *vpdma, int list_num, + int *channels, int size); + +/* vpdma list interrupt management */ +void vpdma_enable_list_complete_irq(struct vpdma_data *vpdma, int irq_num, + int list_num, bool enable); +void vpdma_clear_list_stat(struct vpdma_data *vpdma, int irq_num, + int list_num); +unsigned int vpdma_get_list_stat(struct vpdma_data *vpdma, int irq_num); +unsigned int vpdma_get_list_mask(struct vpdma_data *vpdma, int irq_num); + +/* vpdma client configuration */ +void vpdma_set_line_mode(struct vpdma_data *vpdma, int line_mode, + enum vpdma_channel chan); +void vpdma_set_frame_start_event(struct vpdma_data *vpdma, + enum vpdma_frame_start_event fs_event, enum vpdma_channel chan); +void vpdma_set_max_size(struct vpdma_data *vpdma, int reg_addr, + u32 width, u32 height); + +void vpdma_set_bg_color(struct vpdma_data *vpdma, + struct vpdma_data_format *fmt, u32 color); +void vpdma_dump_regs(struct vpdma_data *vpdma); + +/* initialize vpdma, passed with VPE's platform device pointer */ +int vpdma_create(struct platform_device *pdev, struct vpdma_data *vpdma, + void (*cb)(struct platform_device *pdev)); + +#endif diff --git a/drivers/media/platform/ti/vpe/vpdma_priv.h b/drivers/media/platform/ti/vpe/vpdma_priv.h new file mode 100644 index 000000000000..0bbee45338bd --- /dev/null +++ b/drivers/media/platform/ti/vpe/vpdma_priv.h @@ -0,0 +1,639 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2013 Texas Instruments Inc. + * + * David Griego, + * Dale Farnsworth, + * Archit Taneja, + */ + +#ifndef _TI_VPDMA_PRIV_H_ +#define _TI_VPDMA_PRIV_H_ + +/* + * VPDMA Register offsets + */ + +/* Top level */ +#define VPDMA_PID 0x00 +#define VPDMA_LIST_ADDR 0x04 +#define VPDMA_LIST_ATTR 0x08 +#define VPDMA_LIST_STAT_SYNC 0x0c +#define VPDMA_BG_RGB 0x18 +#define VPDMA_BG_YUV 0x1c +#define VPDMA_SETUP 0x30 +#define VPDMA_MAX_SIZE1 0x34 +#define VPDMA_MAX_SIZE2 0x38 +#define VPDMA_MAX_SIZE3 0x3c +#define VPDMA_MAX_SIZE_WIDTH_MASK 0xffff +#define VPDMA_MAX_SIZE_WIDTH_SHFT 16 +#define VPDMA_MAX_SIZE_HEIGHT_MASK 0xffff +#define VPDMA_MAX_SIZE_HEIGHT_SHFT 0 + +/* Interrupts */ +#define VPDMA_INT_CHAN_STAT(grp) (0x40 + grp * 8) +#define VPDMA_INT_CHAN_MASK(grp) (VPDMA_INT_CHAN_STAT(grp) + 4) +#define VPDMA_INT_CLIENT0_STAT 0x78 +#define VPDMA_INT_CLIENT0_MASK 0x7c +#define VPDMA_INT_CLIENT1_STAT 0x80 +#define VPDMA_INT_CLIENT1_MASK 0x84 +#define VPDMA_INT_LIST0_STAT 0x88 +#define VPDMA_INT_LIST0_MASK 0x8c + +#define VPDMA_INTX_OFFSET 0x50 + +#define VPDMA_PERFMON(i) (0x200 + i * 4) + +/* VIP/VPE client registers */ +#define VPDMA_DEI_CHROMA1_CSTAT 0x0300 +#define VPDMA_DEI_LUMA1_CSTAT 0x0304 +#define VPDMA_DEI_LUMA2_CSTAT 0x0308 +#define VPDMA_DEI_CHROMA2_CSTAT 0x030c +#define VPDMA_DEI_LUMA3_CSTAT 0x0310 +#define VPDMA_DEI_CHROMA3_CSTAT 0x0314 +#define VPDMA_DEI_MV_IN_CSTAT 0x0330 +#define VPDMA_DEI_MV_OUT_CSTAT 0x033c +#define VPDMA_VIP_LO_Y_CSTAT 0x0388 +#define VPDMA_VIP_LO_UV_CSTAT 0x038c +#define VPDMA_VIP_UP_Y_CSTAT 0x0390 +#define VPDMA_VIP_UP_UV_CSTAT 0x0394 +#define VPDMA_VPI_CTL_CSTAT 0x03d0 + +/* Reg field info for VPDMA_CLIENT_CSTAT registers */ +#define VPDMA_CSTAT_LINE_MODE_MASK 0x03 +#define VPDMA_CSTAT_LINE_MODE_SHIFT 8 +#define VPDMA_CSTAT_FRAME_START_MASK 0xf +#define VPDMA_CSTAT_FRAME_START_SHIFT 10 + +#define VPDMA_LIST_NUM_MASK 0x07 +#define VPDMA_LIST_NUM_SHFT 24 +#define VPDMA_LIST_STOP_SHFT 20 +#define VPDMA_LIST_RDY_MASK 0x01 +#define VPDMA_LIST_RDY_SHFT 19 +#define VPDMA_LIST_TYPE_MASK 0x03 +#define VPDMA_LIST_TYPE_SHFT 16 +#define VPDMA_LIST_SIZE_MASK 0xffff + +/* + * The YUV data type definition below are taken from + * both the TRM and i839 Errata information. + * Use the correct data type considering byte + * reordering of components. + * + * Also since the single use of "C" in the 422 case + * to mean "Cr" (i.e. V component). It was decided + * to explicitly label them CR to remove any confusion. + * Bear in mind that the type label refer to the memory + * packed order (LSB - MSB). + */ +#define DATA_TYPE_Y444 0x0 +#define DATA_TYPE_Y422 0x1 +#define DATA_TYPE_Y420 0x2 +#define DATA_TYPE_C444 0x4 +#define DATA_TYPE_C422 0x5 +#define DATA_TYPE_C420 0x6 +#define DATA_TYPE_CB420 0x16 +#define DATA_TYPE_YC444 0x8 +#define DATA_TYPE_YCB422 0x7 +#define DATA_TYPE_YCR422 0x17 +#define DATA_TYPE_CBY422 0x27 +#define DATA_TYPE_CRY422 0x37 + +/* + * The RGB data type definition below are defined + * to follow Errata i819. + * The initial values were taken from: + * VPDMA_data_type_mapping_v0.2vayu_c.pdf + * But some of the ARGB definition appeared to be wrong + * in the document also. As they would yield RGBA instead. + * They have been corrected based on experimentation. + */ +#define DATA_TYPE_RGB16_565 0x10 +#define DATA_TYPE_ARGB_1555 0x13 +#define DATA_TYPE_ARGB_4444 0x14 +#define DATA_TYPE_RGBA_5551 0x11 +#define DATA_TYPE_RGBA_4444 0x12 +#define DATA_TYPE_ARGB24_6666 0x18 +#define DATA_TYPE_RGB24_888 0x16 +#define DATA_TYPE_ARGB32_8888 0x17 +#define DATA_TYPE_RGBA24_6666 0x15 +#define DATA_TYPE_RGBA32_8888 0x19 +#define DATA_TYPE_BGR16_565 0x0 +#define DATA_TYPE_ABGR_1555 0x3 +#define DATA_TYPE_ABGR_4444 0x4 +#define DATA_TYPE_BGRA_5551 0x1 +#define DATA_TYPE_BGRA_4444 0x2 +#define DATA_TYPE_ABGR24_6666 0x8 +#define DATA_TYPE_BGR24_888 0x6 +#define DATA_TYPE_ABGR32_8888 0x7 +#define DATA_TYPE_BGRA24_6666 0x5 +#define DATA_TYPE_BGRA32_8888 0x9 + +#define DATA_TYPE_MV 0x3 + +/* VPDMA channel numbers, some are common between VIP/VPE and appear twice */ +#define VPE_CHAN_NUM_LUMA1_IN 0 +#define VPE_CHAN_NUM_CHROMA1_IN 1 +#define VPE_CHAN_NUM_LUMA2_IN 2 +#define VPE_CHAN_NUM_CHROMA2_IN 3 +#define VPE_CHAN_NUM_LUMA3_IN 4 +#define VPE_CHAN_NUM_CHROMA3_IN 5 +#define VPE_CHAN_NUM_MV_IN 12 +#define VPE_CHAN_NUM_MV_OUT 15 +#define VIP1_CHAN_NUM_MULT_PORT_A_SRC0 38 +#define VIP1_CHAN_NUM_MULT_ANC_A_SRC0 70 +#define VPE_CHAN_NUM_LUMA_OUT 102 +#define VPE_CHAN_NUM_CHROMA_OUT 103 +#define VIP1_CHAN_NUM_PORT_A_LUMA 102 +#define VIP1_CHAN_NUM_PORT_A_CHROMA 103 +#define VPE_CHAN_NUM_RGB_OUT 106 +#define VIP1_CHAN_NUM_PORT_A_RGB 106 +#define VIP1_CHAN_NUM_PORT_B_RGB 107 +/* + * a VPDMA address data block payload for a configuration descriptor needs to + * have each sub block length as a multiple of 16 bytes. Therefore, the overall + * size of the payload also needs to be a multiple of 16 bytes. The sub block + * lengths should be ensured to be aligned by the VPDMA user. + */ +#define VPDMA_ADB_SIZE_ALIGN 0x0f + +/* + * data transfer descriptor + */ +struct vpdma_dtd { + u32 type_ctl_stride; + union { + u32 xfer_length_height; + u32 w1; + }; + u32 start_addr; + u32 pkt_ctl; + union { + u32 frame_width_height; /* inbound */ + u32 desc_write_addr; /* outbound */ + }; + union { + u32 start_h_v; /* inbound */ + u32 max_width_height; /* outbound */ + }; + u32 client_attr0; + u32 client_attr1; +}; + +/* Data Transfer Descriptor specifics */ +#define DTD_NO_NOTIFY 0 +#define DTD_NOTIFY 1 + +#define DTD_PKT_TYPE 0xa +#define DTD_DIR_IN 0 +#define DTD_DIR_OUT 1 + +/* type_ctl_stride */ +#define DTD_DATA_TYPE_MASK 0x3f +#define DTD_DATA_TYPE_SHFT 26 +#define DTD_NOTIFY_MASK 0x01 +#define DTD_NOTIFY_SHFT 25 +#define DTD_FIELD_MASK 0x01 +#define DTD_FIELD_SHFT 24 +#define DTD_1D_MASK 0x01 +#define DTD_1D_SHFT 23 +#define DTD_EVEN_LINE_SKIP_MASK 0x01 +#define DTD_EVEN_LINE_SKIP_SHFT 20 +#define DTD_ODD_LINE_SKIP_MASK 0x01 +#define DTD_ODD_LINE_SKIP_SHFT 16 +#define DTD_LINE_STRIDE_MASK 0xffff +#define DTD_LINE_STRIDE_SHFT 0 + +/* xfer_length_height */ +#define DTD_LINE_LENGTH_MASK 0xffff +#define DTD_LINE_LENGTH_SHFT 16 +#define DTD_XFER_HEIGHT_MASK 0xffff +#define DTD_XFER_HEIGHT_SHFT 0 + +/* pkt_ctl */ +#define DTD_PKT_TYPE_MASK 0x1f +#define DTD_PKT_TYPE_SHFT 27 +#define DTD_MODE_MASK 0x01 +#define DTD_MODE_SHFT 26 +#define DTD_DIR_MASK 0x01 +#define DTD_DIR_SHFT 25 +#define DTD_CHAN_MASK 0x01ff +#define DTD_CHAN_SHFT 16 +#define DTD_PRI_MASK 0x0f +#define DTD_PRI_SHFT 9 +#define DTD_NEXT_CHAN_MASK 0x01ff +#define DTD_NEXT_CHAN_SHFT 0 + +/* frame_width_height */ +#define DTD_FRAME_WIDTH_MASK 0xffff +#define DTD_FRAME_WIDTH_SHFT 16 +#define DTD_FRAME_HEIGHT_MASK 0xffff +#define DTD_FRAME_HEIGHT_SHFT 0 + +/* start_h_v */ +#define DTD_H_START_MASK 0xffff +#define DTD_H_START_SHFT 16 +#define DTD_V_START_MASK 0xffff +#define DTD_V_START_SHFT 0 + +#define DTD_DESC_START_MASK 0xffffffe0 +#define DTD_DESC_START_SHIFT 5 +#define DTD_WRITE_DESC_MASK 0x01 +#define DTD_WRITE_DESC_SHIFT 2 +#define DTD_DROP_DATA_MASK 0x01 +#define DTD_DROP_DATA_SHIFT 1 +#define DTD_USE_DESC_MASK 0x01 +#define DTD_USE_DESC_SHIFT 0 + +/* max_width_height */ +#define DTD_MAX_WIDTH_MASK 0x07 +#define DTD_MAX_WIDTH_SHFT 4 +#define DTD_MAX_HEIGHT_MASK 0x07 +#define DTD_MAX_HEIGHT_SHFT 0 + +static inline u32 dtd_type_ctl_stride(int type, bool notify, int field, + bool one_d, bool even_line_skip, bool odd_line_skip, + int line_stride) +{ + return (type << DTD_DATA_TYPE_SHFT) | (notify << DTD_NOTIFY_SHFT) | + (field << DTD_FIELD_SHFT) | (one_d << DTD_1D_SHFT) | + (even_line_skip << DTD_EVEN_LINE_SKIP_SHFT) | + (odd_line_skip << DTD_ODD_LINE_SKIP_SHFT) | + line_stride; +} + +static inline u32 dtd_xfer_length_height(int line_length, int xfer_height) +{ + return (line_length << DTD_LINE_LENGTH_SHFT) | xfer_height; +} + +static inline u32 dtd_pkt_ctl(bool mode, bool dir, int chan, int pri, + int next_chan) +{ + return (DTD_PKT_TYPE << DTD_PKT_TYPE_SHFT) | (mode << DTD_MODE_SHFT) | + (dir << DTD_DIR_SHFT) | (chan << DTD_CHAN_SHFT) | + (pri << DTD_PRI_SHFT) | next_chan; +} + +static inline u32 dtd_frame_width_height(int width, int height) +{ + return (width << DTD_FRAME_WIDTH_SHFT) | height; +} + +static inline u32 dtd_desc_write_addr(unsigned int addr, bool write_desc, + bool drop_data, bool use_desc) +{ + return (addr & DTD_DESC_START_MASK) | + (write_desc << DTD_WRITE_DESC_SHIFT) | + (drop_data << DTD_DROP_DATA_SHIFT) | + use_desc; +} + +static inline u32 dtd_start_h_v(int h_start, int v_start) +{ + return (h_start << DTD_H_START_SHFT) | v_start; +} + +static inline u32 dtd_max_width_height(int max_width, int max_height) +{ + return (max_width << DTD_MAX_WIDTH_SHFT) | max_height; +} + +static inline int dtd_get_data_type(struct vpdma_dtd *dtd) +{ + return dtd->type_ctl_stride >> DTD_DATA_TYPE_SHFT; +} + +static inline bool dtd_get_notify(struct vpdma_dtd *dtd) +{ + return (dtd->type_ctl_stride >> DTD_NOTIFY_SHFT) & DTD_NOTIFY_MASK; +} + +static inline int dtd_get_field(struct vpdma_dtd *dtd) +{ + return (dtd->type_ctl_stride >> DTD_FIELD_SHFT) & DTD_FIELD_MASK; +} + +static inline bool dtd_get_1d(struct vpdma_dtd *dtd) +{ + return (dtd->type_ctl_stride >> DTD_1D_SHFT) & DTD_1D_MASK; +} + +static inline bool dtd_get_even_line_skip(struct vpdma_dtd *dtd) +{ + return (dtd->type_ctl_stride >> DTD_EVEN_LINE_SKIP_SHFT) + & DTD_EVEN_LINE_SKIP_MASK; +} + +static inline bool dtd_get_odd_line_skip(struct vpdma_dtd *dtd) +{ + return (dtd->type_ctl_stride >> DTD_ODD_LINE_SKIP_SHFT) + & DTD_ODD_LINE_SKIP_MASK; +} + +static inline int dtd_get_line_stride(struct vpdma_dtd *dtd) +{ + return dtd->type_ctl_stride & DTD_LINE_STRIDE_MASK; +} + +static inline int dtd_get_line_length(struct vpdma_dtd *dtd) +{ + return dtd->xfer_length_height >> DTD_LINE_LENGTH_SHFT; +} + +static inline int dtd_get_xfer_height(struct vpdma_dtd *dtd) +{ + return dtd->xfer_length_height & DTD_XFER_HEIGHT_MASK; +} + +static inline int dtd_get_pkt_type(struct vpdma_dtd *dtd) +{ + return dtd->pkt_ctl >> DTD_PKT_TYPE_SHFT; +} + +static inline bool dtd_get_mode(struct vpdma_dtd *dtd) +{ + return (dtd->pkt_ctl >> DTD_MODE_SHFT) & DTD_MODE_MASK; +} + +static inline bool dtd_get_dir(struct vpdma_dtd *dtd) +{ + return (dtd->pkt_ctl >> DTD_DIR_SHFT) & DTD_DIR_MASK; +} + +static inline int dtd_get_chan(struct vpdma_dtd *dtd) +{ + return (dtd->pkt_ctl >> DTD_CHAN_SHFT) & DTD_CHAN_MASK; +} + +static inline int dtd_get_priority(struct vpdma_dtd *dtd) +{ + return (dtd->pkt_ctl >> DTD_PRI_SHFT) & DTD_PRI_MASK; +} + +static inline int dtd_get_next_chan(struct vpdma_dtd *dtd) +{ + return (dtd->pkt_ctl >> DTD_NEXT_CHAN_SHFT) & DTD_NEXT_CHAN_MASK; +} + +static inline int dtd_get_frame_width(struct vpdma_dtd *dtd) +{ + return dtd->frame_width_height >> DTD_FRAME_WIDTH_SHFT; +} + +static inline int dtd_get_frame_height(struct vpdma_dtd *dtd) +{ + return dtd->frame_width_height & DTD_FRAME_HEIGHT_MASK; +} + +static inline int dtd_get_desc_write_addr(struct vpdma_dtd *dtd) +{ + return dtd->desc_write_addr & DTD_DESC_START_MASK; +} + +static inline bool dtd_get_write_desc(struct vpdma_dtd *dtd) +{ + return (dtd->desc_write_addr >> DTD_WRITE_DESC_SHIFT) & + DTD_WRITE_DESC_MASK; +} + +static inline bool dtd_get_drop_data(struct vpdma_dtd *dtd) +{ + return (dtd->desc_write_addr >> DTD_DROP_DATA_SHIFT) & + DTD_DROP_DATA_MASK; +} + +static inline bool dtd_get_use_desc(struct vpdma_dtd *dtd) +{ + return dtd->desc_write_addr & DTD_USE_DESC_MASK; +} + +static inline int dtd_get_h_start(struct vpdma_dtd *dtd) +{ + return dtd->start_h_v >> DTD_H_START_SHFT; +} + +static inline int dtd_get_v_start(struct vpdma_dtd *dtd) +{ + return dtd->start_h_v & DTD_V_START_MASK; +} + +static inline int dtd_get_max_width(struct vpdma_dtd *dtd) +{ + return (dtd->max_width_height >> DTD_MAX_WIDTH_SHFT) & + DTD_MAX_WIDTH_MASK; +} + +static inline int dtd_get_max_height(struct vpdma_dtd *dtd) +{ + return (dtd->max_width_height >> DTD_MAX_HEIGHT_SHFT) & + DTD_MAX_HEIGHT_MASK; +} + +/* + * configuration descriptor + */ +struct vpdma_cfd { + union { + u32 dest_addr_offset; + u32 w0; + }; + union { + u32 block_len; /* in words */ + u32 w1; + }; + u32 payload_addr; + u32 ctl_payload_len; /* in words */ +}; + +/* Configuration descriptor specifics */ + +#define CFD_PKT_TYPE 0xb + +#define CFD_DIRECT 1 +#define CFD_INDIRECT 0 +#define CFD_CLS_ADB 0 +#define CFD_CLS_BLOCK 1 + +/* block_len */ +#define CFD__BLOCK_LEN_MASK 0xffff +#define CFD__BLOCK_LEN_SHFT 0 + +/* ctl_payload_len */ +#define CFD_PKT_TYPE_MASK 0x1f +#define CFD_PKT_TYPE_SHFT 27 +#define CFD_DIRECT_MASK 0x01 +#define CFD_DIRECT_SHFT 26 +#define CFD_CLASS_MASK 0x03 +#define CFD_CLASS_SHFT 24 +#define CFD_DEST_MASK 0xff +#define CFD_DEST_SHFT 16 +#define CFD_PAYLOAD_LEN_MASK 0xffff +#define CFD_PAYLOAD_LEN_SHFT 0 + +static inline u32 cfd_pkt_payload_len(bool direct, int cls, int dest, + int payload_len) +{ + return (CFD_PKT_TYPE << CFD_PKT_TYPE_SHFT) | + (direct << CFD_DIRECT_SHFT) | + (cls << CFD_CLASS_SHFT) | + (dest << CFD_DEST_SHFT) | + payload_len; +} + +static inline int cfd_get_pkt_type(struct vpdma_cfd *cfd) +{ + return cfd->ctl_payload_len >> CFD_PKT_TYPE_SHFT; +} + +static inline bool cfd_get_direct(struct vpdma_cfd *cfd) +{ + return (cfd->ctl_payload_len >> CFD_DIRECT_SHFT) & CFD_DIRECT_MASK; +} + +static inline bool cfd_get_class(struct vpdma_cfd *cfd) +{ + return (cfd->ctl_payload_len >> CFD_CLASS_SHFT) & CFD_CLASS_MASK; +} + +static inline int cfd_get_dest(struct vpdma_cfd *cfd) +{ + return (cfd->ctl_payload_len >> CFD_DEST_SHFT) & CFD_DEST_MASK; +} + +static inline int cfd_get_payload_len(struct vpdma_cfd *cfd) +{ + return cfd->ctl_payload_len & CFD_PAYLOAD_LEN_MASK; +} + +/* + * control descriptor + */ +struct vpdma_ctd { + union { + u32 timer_value; + u32 list_addr; + u32 w0; + }; + union { + u32 pixel_line_count; + u32 list_size; + u32 w1; + }; + union { + u32 event; + u32 fid_ctl; + u32 w2; + }; + u32 type_source_ctl; +}; + +/* control descriptor types */ +#define CTD_TYPE_SYNC_ON_CLIENT 0 +#define CTD_TYPE_SYNC_ON_LIST 1 +#define CTD_TYPE_SYNC_ON_EXT 2 +#define CTD_TYPE_SYNC_ON_LM_TIMER 3 +#define CTD_TYPE_SYNC_ON_CHANNEL 4 +#define CTD_TYPE_CHNG_CLIENT_IRQ 5 +#define CTD_TYPE_SEND_IRQ 6 +#define CTD_TYPE_RELOAD_LIST 7 +#define CTD_TYPE_ABORT_CHANNEL 8 + +#define CTD_PKT_TYPE 0xc + +/* timer_value */ +#define CTD_TIMER_VALUE_MASK 0xffff +#define CTD_TIMER_VALUE_SHFT 0 + +/* pixel_line_count */ +#define CTD_PIXEL_COUNT_MASK 0xffff +#define CTD_PIXEL_COUNT_SHFT 16 +#define CTD_LINE_COUNT_MASK 0xffff +#define CTD_LINE_COUNT_SHFT 0 + +/* list_size */ +#define CTD_LIST_SIZE_MASK 0xffff +#define CTD_LIST_SIZE_SHFT 0 + +/* event */ +#define CTD_EVENT_MASK 0x0f +#define CTD_EVENT_SHFT 0 + +/* fid_ctl */ +#define CTD_FID2_MASK 0x03 +#define CTD_FID2_SHFT 4 +#define CTD_FID1_MASK 0x03 +#define CTD_FID1_SHFT 2 +#define CTD_FID0_MASK 0x03 +#define CTD_FID0_SHFT 0 + +/* type_source_ctl */ +#define CTD_PKT_TYPE_MASK 0x1f +#define CTD_PKT_TYPE_SHFT 27 +#define CTD_SOURCE_MASK 0xff +#define CTD_SOURCE_SHFT 16 +#define CTD_CONTROL_MASK 0x0f +#define CTD_CONTROL_SHFT 0 + +static inline u32 ctd_pixel_line_count(int pixel_count, int line_count) +{ + return (pixel_count << CTD_PIXEL_COUNT_SHFT) | line_count; +} + +static inline u32 ctd_set_fid_ctl(int fid0, int fid1, int fid2) +{ + return (fid2 << CTD_FID2_SHFT) | (fid1 << CTD_FID1_SHFT) | fid0; +} + +static inline u32 ctd_type_source_ctl(int source, int control) +{ + return (CTD_PKT_TYPE << CTD_PKT_TYPE_SHFT) | + (source << CTD_SOURCE_SHFT) | control; +} + +static inline u32 ctd_get_pixel_count(struct vpdma_ctd *ctd) +{ + return ctd->pixel_line_count >> CTD_PIXEL_COUNT_SHFT; +} + +static inline int ctd_get_line_count(struct vpdma_ctd *ctd) +{ + return ctd->pixel_line_count & CTD_LINE_COUNT_MASK; +} + +static inline int ctd_get_event(struct vpdma_ctd *ctd) +{ + return ctd->event & CTD_EVENT_MASK; +} + +static inline int ctd_get_fid2_ctl(struct vpdma_ctd *ctd) +{ + return (ctd->fid_ctl >> CTD_FID2_SHFT) & CTD_FID2_MASK; +} + +static inline int ctd_get_fid1_ctl(struct vpdma_ctd *ctd) +{ + return (ctd->fid_ctl >> CTD_FID1_SHFT) & CTD_FID1_MASK; +} + +static inline int ctd_get_fid0_ctl(struct vpdma_ctd *ctd) +{ + return ctd->fid_ctl & CTD_FID2_MASK; +} + +static inline int ctd_get_pkt_type(struct vpdma_ctd *ctd) +{ + return ctd->type_source_ctl >> CTD_PKT_TYPE_SHFT; +} + +static inline int ctd_get_source(struct vpdma_ctd *ctd) +{ + return (ctd->type_source_ctl >> CTD_SOURCE_SHFT) & CTD_SOURCE_MASK; +} + +static inline int ctd_get_ctl(struct vpdma_ctd *ctd) +{ + return ctd->type_source_ctl & CTD_CONTROL_MASK; +} + +#endif diff --git a/drivers/media/platform/ti/vpe/vpe.c b/drivers/media/platform/ti/vpe/vpe.c new file mode 100644 index 000000000000..5b1c5d96a407 --- /dev/null +++ b/drivers/media/platform/ti/vpe/vpe.c @@ -0,0 +1,2665 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * TI VPE mem2mem driver, based on the virtual v4l2-mem2mem example driver + * + * Copyright (c) 2013 Texas Instruments Inc. + * David Griego, + * Dale Farnsworth, + * Archit Taneja, + * + * Copyright (c) 2009-2010 Samsung Electronics Co., Ltd. + * Pawel Osciak, + * Marek Szyprowski, + * + * Based on the virtual v4l2-mem2mem example device + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "vpdma.h" +#include "vpdma_priv.h" +#include "vpe_regs.h" +#include "sc.h" +#include "csc.h" + +#define VPE_MODULE_NAME "vpe" + +/* minimum and maximum frame sizes */ +#define MIN_W 32 +#define MIN_H 32 +#define MAX_W 2048 +#define MAX_H 2048 + +/* required alignments */ +#define S_ALIGN 0 /* multiple of 1 */ +#define H_ALIGN 1 /* multiple of 2 */ + +/* flags that indicate a format can be used for capture/output */ +#define VPE_FMT_TYPE_CAPTURE (1 << 0) +#define VPE_FMT_TYPE_OUTPUT (1 << 1) + +/* used as plane indices */ +#define VPE_MAX_PLANES 2 +#define VPE_LUMA 0 +#define VPE_CHROMA 1 + +/* per m2m context info */ +#define VPE_MAX_SRC_BUFS 3 /* need 3 src fields to de-interlace */ + +#define VPE_DEF_BUFS_PER_JOB 1 /* default one buffer per batch job */ + +/* + * each VPE context can need up to 3 config descriptors, 7 input descriptors, + * 3 output descriptors, and 10 control descriptors + */ +#define VPE_DESC_LIST_SIZE (10 * VPDMA_DTD_DESC_SIZE + \ + 13 * VPDMA_CFD_CTD_DESC_SIZE) + +#define vpe_dbg(vpedev, fmt, arg...) \ + dev_dbg((vpedev)->v4l2_dev.dev, fmt, ##arg) +#define vpe_err(vpedev, fmt, arg...) \ + dev_err((vpedev)->v4l2_dev.dev, fmt, ##arg) + +struct vpe_us_coeffs { + unsigned short anchor_fid0_c0; + unsigned short anchor_fid0_c1; + unsigned short anchor_fid0_c2; + unsigned short anchor_fid0_c3; + unsigned short interp_fid0_c0; + unsigned short interp_fid0_c1; + unsigned short interp_fid0_c2; + unsigned short interp_fid0_c3; + unsigned short anchor_fid1_c0; + unsigned short anchor_fid1_c1; + unsigned short anchor_fid1_c2; + unsigned short anchor_fid1_c3; + unsigned short interp_fid1_c0; + unsigned short interp_fid1_c1; + unsigned short interp_fid1_c2; + unsigned short interp_fid1_c3; +}; + +/* + * Default upsampler coefficients + */ +static const struct vpe_us_coeffs us_coeffs[] = { + { + /* Coefficients for progressive input */ + 0x00C8, 0x0348, 0x0018, 0x3FD8, 0x3FB8, 0x0378, 0x00E8, 0x3FE8, + 0x00C8, 0x0348, 0x0018, 0x3FD8, 0x3FB8, 0x0378, 0x00E8, 0x3FE8, + }, + { + /* Coefficients for Top Field Interlaced input */ + 0x0051, 0x03D5, 0x3FE3, 0x3FF7, 0x3FB5, 0x02E9, 0x018F, 0x3FD3, + /* Coefficients for Bottom Field Interlaced input */ + 0x016B, 0x0247, 0x00B1, 0x3F9D, 0x3FCF, 0x03DB, 0x005D, 0x3FF9, + }, +}; + +/* + * the following registers are for configuring some of the parameters of the + * motion and edge detection blocks inside DEI, these generally remain the same, + * these could be passed later via userspace if some one needs to tweak these. + */ +struct vpe_dei_regs { + unsigned long mdt_spacial_freq_thr_reg; /* VPE_DEI_REG2 */ + unsigned long edi_config_reg; /* VPE_DEI_REG3 */ + unsigned long edi_lut_reg0; /* VPE_DEI_REG4 */ + unsigned long edi_lut_reg1; /* VPE_DEI_REG5 */ + unsigned long edi_lut_reg2; /* VPE_DEI_REG6 */ + unsigned long edi_lut_reg3; /* VPE_DEI_REG7 */ +}; + +/* + * default expert DEI register values, unlikely to be modified. + */ +static const struct vpe_dei_regs dei_regs = { + .mdt_spacial_freq_thr_reg = 0x020C0804u, + .edi_config_reg = 0x0118100Cu, + .edi_lut_reg0 = 0x08040200u, + .edi_lut_reg1 = 0x1010100Cu, + .edi_lut_reg2 = 0x10101010u, + .edi_lut_reg3 = 0x10101010u, +}; + +/* + * The port_data structure contains per-port data. + */ +struct vpe_port_data { + enum vpdma_channel channel; /* VPDMA channel */ + u8 vb_index; /* input frame f, f-1, f-2 index */ + u8 vb_part; /* plane index for co-panar formats */ +}; + +/* + * Define indices into the port_data tables + */ +#define VPE_PORT_LUMA1_IN 0 +#define VPE_PORT_CHROMA1_IN 1 +#define VPE_PORT_LUMA2_IN 2 +#define VPE_PORT_CHROMA2_IN 3 +#define VPE_PORT_LUMA3_IN 4 +#define VPE_PORT_CHROMA3_IN 5 +#define VPE_PORT_MV_IN 6 +#define VPE_PORT_MV_OUT 7 +#define VPE_PORT_LUMA_OUT 8 +#define VPE_PORT_CHROMA_OUT 9 +#define VPE_PORT_RGB_OUT 10 + +static const struct vpe_port_data port_data[11] = { + [VPE_PORT_LUMA1_IN] = { + .channel = VPE_CHAN_LUMA1_IN, + .vb_index = 0, + .vb_part = VPE_LUMA, + }, + [VPE_PORT_CHROMA1_IN] = { + .channel = VPE_CHAN_CHROMA1_IN, + .vb_index = 0, + .vb_part = VPE_CHROMA, + }, + [VPE_PORT_LUMA2_IN] = { + .channel = VPE_CHAN_LUMA2_IN, + .vb_index = 1, + .vb_part = VPE_LUMA, + }, + [VPE_PORT_CHROMA2_IN] = { + .channel = VPE_CHAN_CHROMA2_IN, + .vb_index = 1, + .vb_part = VPE_CHROMA, + }, + [VPE_PORT_LUMA3_IN] = { + .channel = VPE_CHAN_LUMA3_IN, + .vb_index = 2, + .vb_part = VPE_LUMA, + }, + [VPE_PORT_CHROMA3_IN] = { + .channel = VPE_CHAN_CHROMA3_IN, + .vb_index = 2, + .vb_part = VPE_CHROMA, + }, + [VPE_PORT_MV_IN] = { + .channel = VPE_CHAN_MV_IN, + }, + [VPE_PORT_MV_OUT] = { + .channel = VPE_CHAN_MV_OUT, + }, + [VPE_PORT_LUMA_OUT] = { + .channel = VPE_CHAN_LUMA_OUT, + .vb_part = VPE_LUMA, + }, + [VPE_PORT_CHROMA_OUT] = { + .channel = VPE_CHAN_CHROMA_OUT, + .vb_part = VPE_CHROMA, + }, + [VPE_PORT_RGB_OUT] = { + .channel = VPE_CHAN_RGB_OUT, + .vb_part = VPE_LUMA, + }, +}; + + +/* driver info for each of the supported video formats */ +struct vpe_fmt { + u32 fourcc; /* standard format identifier */ + u8 types; /* CAPTURE and/or OUTPUT */ + u8 coplanar; /* set for unpacked Luma and Chroma */ + /* vpdma format info for each plane */ + struct vpdma_data_format const *vpdma_fmt[VPE_MAX_PLANES]; +}; + +static struct vpe_fmt vpe_formats[] = { + { + .fourcc = V4L2_PIX_FMT_NV16, + .types = VPE_FMT_TYPE_CAPTURE | VPE_FMT_TYPE_OUTPUT, + .coplanar = 1, + .vpdma_fmt = { &vpdma_yuv_fmts[VPDMA_DATA_FMT_Y444], + &vpdma_yuv_fmts[VPDMA_DATA_FMT_C444], + }, + }, + { + .fourcc = V4L2_PIX_FMT_NV12, + .types = VPE_FMT_TYPE_CAPTURE | VPE_FMT_TYPE_OUTPUT, + .coplanar = 1, + .vpdma_fmt = { &vpdma_yuv_fmts[VPDMA_DATA_FMT_Y420], + &vpdma_yuv_fmts[VPDMA_DATA_FMT_C420], + }, + }, + { + .fourcc = V4L2_PIX_FMT_NV21, + .types = VPE_FMT_TYPE_CAPTURE | VPE_FMT_TYPE_OUTPUT, + .coplanar = 1, + .vpdma_fmt = { &vpdma_yuv_fmts[VPDMA_DATA_FMT_Y420], + &vpdma_yuv_fmts[VPDMA_DATA_FMT_CB420], + }, + }, + { + .fourcc = V4L2_PIX_FMT_YUYV, + .types = VPE_FMT_TYPE_CAPTURE | VPE_FMT_TYPE_OUTPUT, + .coplanar = 0, + .vpdma_fmt = { &vpdma_yuv_fmts[VPDMA_DATA_FMT_YCB422], + }, + }, + { + .fourcc = V4L2_PIX_FMT_UYVY, + .types = VPE_FMT_TYPE_CAPTURE | VPE_FMT_TYPE_OUTPUT, + .coplanar = 0, + .vpdma_fmt = { &vpdma_yuv_fmts[VPDMA_DATA_FMT_CBY422], + }, + }, + { + .fourcc = V4L2_PIX_FMT_RGB24, + .types = VPE_FMT_TYPE_CAPTURE, + .coplanar = 0, + .vpdma_fmt = { &vpdma_rgb_fmts[VPDMA_DATA_FMT_RGB24], + }, + }, + { + .fourcc = V4L2_PIX_FMT_RGB32, + .types = VPE_FMT_TYPE_CAPTURE, + .coplanar = 0, + .vpdma_fmt = { &vpdma_rgb_fmts[VPDMA_DATA_FMT_ARGB32], + }, + }, + { + .fourcc = V4L2_PIX_FMT_BGR24, + .types = VPE_FMT_TYPE_CAPTURE, + .coplanar = 0, + .vpdma_fmt = { &vpdma_rgb_fmts[VPDMA_DATA_FMT_BGR24], + }, + }, + { + .fourcc = V4L2_PIX_FMT_BGR32, + .types = VPE_FMT_TYPE_CAPTURE, + .coplanar = 0, + .vpdma_fmt = { &vpdma_rgb_fmts[VPDMA_DATA_FMT_ABGR32], + }, + }, + { + .fourcc = V4L2_PIX_FMT_RGB565, + .types = VPE_FMT_TYPE_CAPTURE, + .coplanar = 0, + .vpdma_fmt = { &vpdma_rgb_fmts[VPDMA_DATA_FMT_RGB565], + }, + }, + { + .fourcc = V4L2_PIX_FMT_RGB555, + .types = VPE_FMT_TYPE_CAPTURE, + .coplanar = 0, + .vpdma_fmt = { &vpdma_rgb_fmts[VPDMA_DATA_FMT_RGBA16_5551], + }, + }, +}; + +/* + * per-queue, driver-specific private data. + * there is one source queue and one destination queue for each m2m context. + */ +struct vpe_q_data { + /* current v4l2 format info */ + struct v4l2_format format; + unsigned int flags; + struct v4l2_rect c_rect; /* crop/compose rectangle */ + struct vpe_fmt *fmt; /* format info */ +}; + +/* vpe_q_data flag bits */ +#define Q_DATA_FRAME_1D BIT(0) +#define Q_DATA_MODE_TILED BIT(1) +#define Q_DATA_INTERLACED_ALTERNATE BIT(2) +#define Q_DATA_INTERLACED_SEQ_TB BIT(3) +#define Q_DATA_INTERLACED_SEQ_BT BIT(4) + +#define Q_IS_SEQ_XX (Q_DATA_INTERLACED_SEQ_TB | \ + Q_DATA_INTERLACED_SEQ_BT) + +#define Q_IS_INTERLACED (Q_DATA_INTERLACED_ALTERNATE | \ + Q_DATA_INTERLACED_SEQ_TB | \ + Q_DATA_INTERLACED_SEQ_BT) + +enum { + Q_DATA_SRC = 0, + Q_DATA_DST = 1, +}; + +/* find our format description corresponding to the passed v4l2_format */ +static struct vpe_fmt *__find_format(u32 fourcc) +{ + struct vpe_fmt *fmt; + unsigned int k; + + for (k = 0; k < ARRAY_SIZE(vpe_formats); k++) { + fmt = &vpe_formats[k]; + if (fmt->fourcc == fourcc) + return fmt; + } + + return NULL; +} + +static struct vpe_fmt *find_format(struct v4l2_format *f) +{ + return __find_format(f->fmt.pix.pixelformat); +} + +/* + * there is one vpe_dev structure in the driver, it is shared by + * all instances. + */ +struct vpe_dev { + struct v4l2_device v4l2_dev; + struct video_device vfd; + struct v4l2_m2m_dev *m2m_dev; + + atomic_t num_instances; /* count of driver instances */ + dma_addr_t loaded_mmrs; /* shadow mmrs in device */ + struct mutex dev_mutex; + spinlock_t lock; + + int irq; + void __iomem *base; + struct resource *res; + + struct vpdma_data vpdma_data; + struct vpdma_data *vpdma; /* vpdma data handle */ + struct sc_data *sc; /* scaler data handle */ + struct csc_data *csc; /* csc data handle */ +}; + +/* + * There is one vpe_ctx structure for each m2m context. + */ +struct vpe_ctx { + struct v4l2_fh fh; + struct vpe_dev *dev; + struct v4l2_ctrl_handler hdl; + + unsigned int field; /* current field */ + unsigned int sequence; /* current frame/field seq */ + unsigned int aborting; /* abort after next irq */ + + unsigned int bufs_per_job; /* input buffers per batch */ + unsigned int bufs_completed; /* bufs done in this batch */ + + struct vpe_q_data q_data[2]; /* src & dst queue data */ + struct vb2_v4l2_buffer *src_vbs[VPE_MAX_SRC_BUFS]; + struct vb2_v4l2_buffer *dst_vb; + + dma_addr_t mv_buf_dma[2]; /* dma addrs of motion vector in/out bufs */ + void *mv_buf[2]; /* virtual addrs of motion vector bufs */ + size_t mv_buf_size; /* current motion vector buffer size */ + struct vpdma_buf mmr_adb; /* shadow reg addr/data block */ + struct vpdma_buf sc_coeff_h; /* h coeff buffer */ + struct vpdma_buf sc_coeff_v; /* v coeff buffer */ + struct vpdma_desc_list desc_list; /* DMA descriptor list */ + + bool deinterlacing; /* using de-interlacer */ + bool load_mmrs; /* have new shadow reg values */ + + unsigned int src_mv_buf_selector; +}; + + +/* + * M2M devices get 2 queues. + * Return the queue given the type. + */ +static struct vpe_q_data *get_q_data(struct vpe_ctx *ctx, + enum v4l2_buf_type type) +{ + switch (type) { + case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: + case V4L2_BUF_TYPE_VIDEO_OUTPUT: + return &ctx->q_data[Q_DATA_SRC]; + case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: + case V4L2_BUF_TYPE_VIDEO_CAPTURE: + return &ctx->q_data[Q_DATA_DST]; + default: + return NULL; + } + return NULL; +} + +static u32 read_reg(struct vpe_dev *dev, int offset) +{ + return ioread32(dev->base + offset); +} + +static void write_reg(struct vpe_dev *dev, int offset, u32 value) +{ + iowrite32(value, dev->base + offset); +} + +/* register field read/write helpers */ +static int get_field(u32 value, u32 mask, int shift) +{ + return (value & (mask << shift)) >> shift; +} + +static int read_field_reg(struct vpe_dev *dev, int offset, u32 mask, int shift) +{ + return get_field(read_reg(dev, offset), mask, shift); +} + +static void write_field(u32 *valp, u32 field, u32 mask, int shift) +{ + u32 val = *valp; + + val &= ~(mask << shift); + val |= (field & mask) << shift; + *valp = val; +} + +static void write_field_reg(struct vpe_dev *dev, int offset, u32 field, + u32 mask, int shift) +{ + u32 val = read_reg(dev, offset); + + write_field(&val, field, mask, shift); + + write_reg(dev, offset, val); +} + +/* + * DMA address/data block for the shadow registers + */ +struct vpe_mmr_adb { + struct vpdma_adb_hdr out_fmt_hdr; + u32 out_fmt_reg[1]; + u32 out_fmt_pad[3]; + struct vpdma_adb_hdr us1_hdr; + u32 us1_regs[8]; + struct vpdma_adb_hdr us2_hdr; + u32 us2_regs[8]; + struct vpdma_adb_hdr us3_hdr; + u32 us3_regs[8]; + struct vpdma_adb_hdr dei_hdr; + u32 dei_regs[8]; + struct vpdma_adb_hdr sc_hdr0; + u32 sc_regs0[7]; + u32 sc_pad0[1]; + struct vpdma_adb_hdr sc_hdr8; + u32 sc_regs8[6]; + u32 sc_pad8[2]; + struct vpdma_adb_hdr sc_hdr17; + u32 sc_regs17[9]; + u32 sc_pad17[3]; + struct vpdma_adb_hdr csc_hdr; + u32 csc_regs[6]; + u32 csc_pad[2]; +}; + +#define GET_OFFSET_TOP(ctx, obj, reg) \ + ((obj)->res->start - ctx->dev->res->start + reg) + +#define VPE_SET_MMR_ADB_HDR(ctx, hdr, regs, offset_a) \ + VPDMA_SET_MMR_ADB_HDR(ctx->mmr_adb, vpe_mmr_adb, hdr, regs, offset_a) +/* + * Set the headers for all of the address/data block structures. + */ +static void init_adb_hdrs(struct vpe_ctx *ctx) +{ + VPE_SET_MMR_ADB_HDR(ctx, out_fmt_hdr, out_fmt_reg, VPE_CLK_FORMAT_SELECT); + VPE_SET_MMR_ADB_HDR(ctx, us1_hdr, us1_regs, VPE_US1_R0); + VPE_SET_MMR_ADB_HDR(ctx, us2_hdr, us2_regs, VPE_US2_R0); + VPE_SET_MMR_ADB_HDR(ctx, us3_hdr, us3_regs, VPE_US3_R0); + VPE_SET_MMR_ADB_HDR(ctx, dei_hdr, dei_regs, VPE_DEI_FRAME_SIZE); + VPE_SET_MMR_ADB_HDR(ctx, sc_hdr0, sc_regs0, + GET_OFFSET_TOP(ctx, ctx->dev->sc, CFG_SC0)); + VPE_SET_MMR_ADB_HDR(ctx, sc_hdr8, sc_regs8, + GET_OFFSET_TOP(ctx, ctx->dev->sc, CFG_SC8)); + VPE_SET_MMR_ADB_HDR(ctx, sc_hdr17, sc_regs17, + GET_OFFSET_TOP(ctx, ctx->dev->sc, CFG_SC17)); + VPE_SET_MMR_ADB_HDR(ctx, csc_hdr, csc_regs, + GET_OFFSET_TOP(ctx, ctx->dev->csc, CSC_CSC00)); +}; + +/* + * Allocate or re-allocate the motion vector DMA buffers + * There are two buffers, one for input and one for output. + * However, the roles are reversed after each field is processed. + * In other words, after each field is processed, the previous + * output (dst) MV buffer becomes the new input (src) MV buffer. + */ +static int realloc_mv_buffers(struct vpe_ctx *ctx, size_t size) +{ + struct device *dev = ctx->dev->v4l2_dev.dev; + + if (ctx->mv_buf_size == size) + return 0; + + if (ctx->mv_buf[0]) + dma_free_coherent(dev, ctx->mv_buf_size, ctx->mv_buf[0], + ctx->mv_buf_dma[0]); + + if (ctx->mv_buf[1]) + dma_free_coherent(dev, ctx->mv_buf_size, ctx->mv_buf[1], + ctx->mv_buf_dma[1]); + + if (size == 0) + return 0; + + ctx->mv_buf[0] = dma_alloc_coherent(dev, size, &ctx->mv_buf_dma[0], + GFP_KERNEL); + if (!ctx->mv_buf[0]) { + vpe_err(ctx->dev, "failed to allocate motion vector buffer\n"); + return -ENOMEM; + } + + ctx->mv_buf[1] = dma_alloc_coherent(dev, size, &ctx->mv_buf_dma[1], + GFP_KERNEL); + if (!ctx->mv_buf[1]) { + vpe_err(ctx->dev, "failed to allocate motion vector buffer\n"); + dma_free_coherent(dev, size, ctx->mv_buf[0], + ctx->mv_buf_dma[0]); + + return -ENOMEM; + } + + ctx->mv_buf_size = size; + ctx->src_mv_buf_selector = 0; + + return 0; +} + +static void free_mv_buffers(struct vpe_ctx *ctx) +{ + realloc_mv_buffers(ctx, 0); +} + +/* + * While de-interlacing, we keep the two most recent input buffers + * around. This function frees those two buffers when we have + * finished processing the current stream. + */ +static void free_vbs(struct vpe_ctx *ctx) +{ + struct vpe_dev *dev = ctx->dev; + unsigned long flags; + + if (ctx->src_vbs[2] == NULL) + return; + + spin_lock_irqsave(&dev->lock, flags); + if (ctx->src_vbs[2]) { + v4l2_m2m_buf_done(ctx->src_vbs[2], VB2_BUF_STATE_DONE); + if (ctx->src_vbs[1] && (ctx->src_vbs[1] != ctx->src_vbs[2])) + v4l2_m2m_buf_done(ctx->src_vbs[1], VB2_BUF_STATE_DONE); + ctx->src_vbs[2] = NULL; + ctx->src_vbs[1] = NULL; + } + spin_unlock_irqrestore(&dev->lock, flags); +} + +/* + * Enable or disable the VPE clocks + */ +static void vpe_set_clock_enable(struct vpe_dev *dev, bool on) +{ + u32 val = 0; + + if (on) + val = VPE_DATA_PATH_CLK_ENABLE | VPE_VPEDMA_CLK_ENABLE; + write_reg(dev, VPE_CLK_ENABLE, val); +} + +static void vpe_top_reset(struct vpe_dev *dev) +{ + + write_field_reg(dev, VPE_CLK_RESET, 1, VPE_DATA_PATH_CLK_RESET_MASK, + VPE_DATA_PATH_CLK_RESET_SHIFT); + + usleep_range(100, 150); + + write_field_reg(dev, VPE_CLK_RESET, 0, VPE_DATA_PATH_CLK_RESET_MASK, + VPE_DATA_PATH_CLK_RESET_SHIFT); +} + +static void vpe_top_vpdma_reset(struct vpe_dev *dev) +{ + write_field_reg(dev, VPE_CLK_RESET, 1, VPE_VPDMA_CLK_RESET_MASK, + VPE_VPDMA_CLK_RESET_SHIFT); + + usleep_range(100, 150); + + write_field_reg(dev, VPE_CLK_RESET, 0, VPE_VPDMA_CLK_RESET_MASK, + VPE_VPDMA_CLK_RESET_SHIFT); +} + +/* + * Load the correct of upsampler coefficients into the shadow MMRs + */ +static void set_us_coefficients(struct vpe_ctx *ctx) +{ + struct vpe_mmr_adb *mmr_adb = ctx->mmr_adb.addr; + struct vpe_q_data *s_q_data = &ctx->q_data[Q_DATA_SRC]; + u32 *us1_reg = &mmr_adb->us1_regs[0]; + u32 *us2_reg = &mmr_adb->us2_regs[0]; + u32 *us3_reg = &mmr_adb->us3_regs[0]; + const unsigned short *cp, *end_cp; + + cp = &us_coeffs[0].anchor_fid0_c0; + + if (s_q_data->flags & Q_IS_INTERLACED) /* interlaced */ + cp += sizeof(us_coeffs[0]) / sizeof(*cp); + + end_cp = cp + sizeof(us_coeffs[0]) / sizeof(*cp); + + while (cp < end_cp) { + write_field(us1_reg, *cp++, VPE_US_C0_MASK, VPE_US_C0_SHIFT); + write_field(us1_reg, *cp++, VPE_US_C1_MASK, VPE_US_C1_SHIFT); + *us2_reg++ = *us1_reg; + *us3_reg++ = *us1_reg++; + } + ctx->load_mmrs = true; +} + +/* + * Set the upsampler config mode and the VPDMA line mode in the shadow MMRs. + */ +static void set_cfg_modes(struct vpe_ctx *ctx) +{ + struct vpe_fmt *fmt = ctx->q_data[Q_DATA_SRC].fmt; + struct vpe_mmr_adb *mmr_adb = ctx->mmr_adb.addr; + u32 *us1_reg0 = &mmr_adb->us1_regs[0]; + u32 *us2_reg0 = &mmr_adb->us2_regs[0]; + u32 *us3_reg0 = &mmr_adb->us3_regs[0]; + int cfg_mode = 1; + + /* + * Cfg Mode 0: YUV420 source, enable upsampler, DEI is de-interlacing. + * Cfg Mode 1: YUV422 source, disable upsampler, DEI is de-interlacing. + */ + + if (fmt->fourcc == V4L2_PIX_FMT_NV12 || + fmt->fourcc == V4L2_PIX_FMT_NV21) + cfg_mode = 0; + + write_field(us1_reg0, cfg_mode, VPE_US_MODE_MASK, VPE_US_MODE_SHIFT); + write_field(us2_reg0, cfg_mode, VPE_US_MODE_MASK, VPE_US_MODE_SHIFT); + write_field(us3_reg0, cfg_mode, VPE_US_MODE_MASK, VPE_US_MODE_SHIFT); + + ctx->load_mmrs = true; +} + +static void set_line_modes(struct vpe_ctx *ctx) +{ + struct vpe_fmt *fmt = ctx->q_data[Q_DATA_SRC].fmt; + int line_mode = 1; + + if (fmt->fourcc == V4L2_PIX_FMT_NV12 || + fmt->fourcc == V4L2_PIX_FMT_NV21) + line_mode = 0; /* double lines to line buffer */ + + /* regs for now */ + vpdma_set_line_mode(ctx->dev->vpdma, line_mode, VPE_CHAN_CHROMA1_IN); + vpdma_set_line_mode(ctx->dev->vpdma, line_mode, VPE_CHAN_CHROMA2_IN); + vpdma_set_line_mode(ctx->dev->vpdma, line_mode, VPE_CHAN_CHROMA3_IN); + + /* frame start for input luma */ + vpdma_set_frame_start_event(ctx->dev->vpdma, VPDMA_FSEVENT_CHANNEL_ACTIVE, + VPE_CHAN_LUMA1_IN); + vpdma_set_frame_start_event(ctx->dev->vpdma, VPDMA_FSEVENT_CHANNEL_ACTIVE, + VPE_CHAN_LUMA2_IN); + vpdma_set_frame_start_event(ctx->dev->vpdma, VPDMA_FSEVENT_CHANNEL_ACTIVE, + VPE_CHAN_LUMA3_IN); + + /* frame start for input chroma */ + vpdma_set_frame_start_event(ctx->dev->vpdma, VPDMA_FSEVENT_CHANNEL_ACTIVE, + VPE_CHAN_CHROMA1_IN); + vpdma_set_frame_start_event(ctx->dev->vpdma, VPDMA_FSEVENT_CHANNEL_ACTIVE, + VPE_CHAN_CHROMA2_IN); + vpdma_set_frame_start_event(ctx->dev->vpdma, VPDMA_FSEVENT_CHANNEL_ACTIVE, + VPE_CHAN_CHROMA3_IN); + + /* frame start for MV in client */ + vpdma_set_frame_start_event(ctx->dev->vpdma, VPDMA_FSEVENT_CHANNEL_ACTIVE, + VPE_CHAN_MV_IN); +} + +/* + * Set the shadow registers that are modified when the source + * format changes. + */ +static void set_src_registers(struct vpe_ctx *ctx) +{ + set_us_coefficients(ctx); +} + +/* + * Set the shadow registers that are modified when the destination + * format changes. + */ +static void set_dst_registers(struct vpe_ctx *ctx) +{ + struct vpe_mmr_adb *mmr_adb = ctx->mmr_adb.addr; + struct vpe_fmt *fmt = ctx->q_data[Q_DATA_DST].fmt; + const struct v4l2_format_info *finfo; + u32 val = 0; + + finfo = v4l2_format_info(fmt->fourcc); + if (v4l2_is_format_rgb(finfo)) { + val |= VPE_RGB_OUT_SELECT; + vpdma_set_bg_color(ctx->dev->vpdma, + (struct vpdma_data_format *)fmt->vpdma_fmt[0], 0xff); + } else if (fmt->fourcc == V4L2_PIX_FMT_NV16) + val |= VPE_COLOR_SEPARATE_422; + + /* + * the source of CHR_DS and CSC is always the scaler, irrespective of + * whether it's used or not + */ + val |= VPE_DS_SRC_DEI_SCALER | VPE_CSC_SRC_DEI_SCALER; + + if (fmt->fourcc != V4L2_PIX_FMT_NV12 && + fmt->fourcc != V4L2_PIX_FMT_NV21) + val |= VPE_DS_BYPASS; + + mmr_adb->out_fmt_reg[0] = val; + + ctx->load_mmrs = true; +} + +/* + * Set the de-interlacer shadow register values + */ +static void set_dei_regs(struct vpe_ctx *ctx) +{ + struct vpe_mmr_adb *mmr_adb = ctx->mmr_adb.addr; + struct vpe_q_data *s_q_data = &ctx->q_data[Q_DATA_SRC]; + unsigned int src_h = s_q_data->c_rect.height; + unsigned int src_w = s_q_data->c_rect.width; + u32 *dei_mmr0 = &mmr_adb->dei_regs[0]; + bool deinterlace = true; + u32 val = 0; + + /* + * according to TRM, we should set DEI in progressive bypass mode when + * the input content is progressive, however, DEI is bypassed correctly + * for both progressive and interlace content in interlace bypass mode. + * It has been recommended not to use progressive bypass mode. + */ + if (!(s_q_data->flags & Q_IS_INTERLACED) || !ctx->deinterlacing) { + deinterlace = false; + val = VPE_DEI_INTERLACE_BYPASS; + } + + src_h = deinterlace ? src_h * 2 : src_h; + + val |= (src_h << VPE_DEI_HEIGHT_SHIFT) | + (src_w << VPE_DEI_WIDTH_SHIFT) | + VPE_DEI_FIELD_FLUSH; + + *dei_mmr0 = val; + + ctx->load_mmrs = true; +} + +static void set_dei_shadow_registers(struct vpe_ctx *ctx) +{ + struct vpe_mmr_adb *mmr_adb = ctx->mmr_adb.addr; + u32 *dei_mmr = &mmr_adb->dei_regs[0]; + const struct vpe_dei_regs *cur = &dei_regs; + + dei_mmr[2] = cur->mdt_spacial_freq_thr_reg; + dei_mmr[3] = cur->edi_config_reg; + dei_mmr[4] = cur->edi_lut_reg0; + dei_mmr[5] = cur->edi_lut_reg1; + dei_mmr[6] = cur->edi_lut_reg2; + dei_mmr[7] = cur->edi_lut_reg3; + + ctx->load_mmrs = true; +} + +static void config_edi_input_mode(struct vpe_ctx *ctx, int mode) +{ + struct vpe_mmr_adb *mmr_adb = ctx->mmr_adb.addr; + u32 *edi_config_reg = &mmr_adb->dei_regs[3]; + + if (mode & 0x2) + write_field(edi_config_reg, 1, 1, 2); /* EDI_ENABLE_3D */ + + if (mode & 0x3) + write_field(edi_config_reg, 1, 1, 3); /* EDI_CHROMA_3D */ + + write_field(edi_config_reg, mode, VPE_EDI_INP_MODE_MASK, + VPE_EDI_INP_MODE_SHIFT); + + ctx->load_mmrs = true; +} + +/* + * Set the shadow registers whose values are modified when either the + * source or destination format is changed. + */ +static int set_srcdst_params(struct vpe_ctx *ctx) +{ + struct vpe_q_data *s_q_data = &ctx->q_data[Q_DATA_SRC]; + struct vpe_q_data *d_q_data = &ctx->q_data[Q_DATA_DST]; + struct vpe_mmr_adb *mmr_adb = ctx->mmr_adb.addr; + unsigned int src_w = s_q_data->c_rect.width; + unsigned int src_h = s_q_data->c_rect.height; + unsigned int dst_w = d_q_data->c_rect.width; + unsigned int dst_h = d_q_data->c_rect.height; + struct v4l2_pix_format_mplane *spix; + size_t mv_buf_size; + int ret; + + ctx->sequence = 0; + ctx->field = V4L2_FIELD_TOP; + spix = &s_q_data->format.fmt.pix_mp; + + if ((s_q_data->flags & Q_IS_INTERLACED) && + !(d_q_data->flags & Q_IS_INTERLACED)) { + int bytes_per_line; + const struct vpdma_data_format *mv = + &vpdma_misc_fmts[VPDMA_DATA_FMT_MV]; + + /* + * we make sure that the source image has a 16 byte aligned + * stride, we need to do the same for the motion vector buffer + * by aligning it's stride to the next 16 byte boundary. this + * extra space will not be used by the de-interlacer, but will + * ensure that vpdma operates correctly + */ + bytes_per_line = ALIGN((spix->width * mv->depth) >> 3, + VPDMA_STRIDE_ALIGN); + mv_buf_size = bytes_per_line * spix->height; + + ctx->deinterlacing = true; + src_h <<= 1; + } else { + ctx->deinterlacing = false; + mv_buf_size = 0; + } + + free_vbs(ctx); + ctx->src_vbs[2] = ctx->src_vbs[1] = ctx->src_vbs[0] = NULL; + + ret = realloc_mv_buffers(ctx, mv_buf_size); + if (ret) + return ret; + + set_cfg_modes(ctx); + set_dei_regs(ctx); + + csc_set_coeff(ctx->dev->csc, &mmr_adb->csc_regs[0], + &s_q_data->format, &d_q_data->format); + + sc_set_hs_coeffs(ctx->dev->sc, ctx->sc_coeff_h.addr, src_w, dst_w); + sc_set_vs_coeffs(ctx->dev->sc, ctx->sc_coeff_v.addr, src_h, dst_h); + + sc_config_scaler(ctx->dev->sc, &mmr_adb->sc_regs0[0], + &mmr_adb->sc_regs8[0], &mmr_adb->sc_regs17[0], + src_w, src_h, dst_w, dst_h); + + return 0; +} + +/* + * mem2mem callbacks + */ + +/* + * job_ready() - check whether an instance is ready to be scheduled to run + */ +static int job_ready(void *priv) +{ + struct vpe_ctx *ctx = priv; + + /* + * This check is needed as this might be called directly from driver + * When called by m2m framework, this will always satisfy, but when + * called from vpe_irq, this might fail. (src stream with zero buffers) + */ + if (v4l2_m2m_num_src_bufs_ready(ctx->fh.m2m_ctx) <= 0 || + v4l2_m2m_num_dst_bufs_ready(ctx->fh.m2m_ctx) <= 0) + return 0; + + return 1; +} + +static void job_abort(void *priv) +{ + struct vpe_ctx *ctx = priv; + + /* Will cancel the transaction in the next interrupt handler */ + ctx->aborting = 1; +} + +static void vpe_dump_regs(struct vpe_dev *dev) +{ +#define DUMPREG(r) vpe_dbg(dev, "%-35s %08x\n", #r, read_reg(dev, VPE_##r)) + + vpe_dbg(dev, "VPE Registers:\n"); + + DUMPREG(PID); + DUMPREG(SYSCONFIG); + DUMPREG(INT0_STATUS0_RAW); + DUMPREG(INT0_STATUS0); + DUMPREG(INT0_ENABLE0); + DUMPREG(INT0_STATUS1_RAW); + DUMPREG(INT0_STATUS1); + DUMPREG(INT0_ENABLE1); + DUMPREG(CLK_ENABLE); + DUMPREG(CLK_RESET); + DUMPREG(CLK_FORMAT_SELECT); + DUMPREG(CLK_RANGE_MAP); + DUMPREG(US1_R0); + DUMPREG(US1_R1); + DUMPREG(US1_R2); + DUMPREG(US1_R3); + DUMPREG(US1_R4); + DUMPREG(US1_R5); + DUMPREG(US1_R6); + DUMPREG(US1_R7); + DUMPREG(US2_R0); + DUMPREG(US2_R1); + DUMPREG(US2_R2); + DUMPREG(US2_R3); + DUMPREG(US2_R4); + DUMPREG(US2_R5); + DUMPREG(US2_R6); + DUMPREG(US2_R7); + DUMPREG(US3_R0); + DUMPREG(US3_R1); + DUMPREG(US3_R2); + DUMPREG(US3_R3); + DUMPREG(US3_R4); + DUMPREG(US3_R5); + DUMPREG(US3_R6); + DUMPREG(US3_R7); + DUMPREG(DEI_FRAME_SIZE); + DUMPREG(MDT_BYPASS); + DUMPREG(MDT_SF_THRESHOLD); + DUMPREG(EDI_CONFIG); + DUMPREG(DEI_EDI_LUT_R0); + DUMPREG(DEI_EDI_LUT_R1); + DUMPREG(DEI_EDI_LUT_R2); + DUMPREG(DEI_EDI_LUT_R3); + DUMPREG(DEI_FMD_WINDOW_R0); + DUMPREG(DEI_FMD_WINDOW_R1); + DUMPREG(DEI_FMD_CONTROL_R0); + DUMPREG(DEI_FMD_CONTROL_R1); + DUMPREG(DEI_FMD_STATUS_R0); + DUMPREG(DEI_FMD_STATUS_R1); + DUMPREG(DEI_FMD_STATUS_R2); +#undef DUMPREG + + sc_dump_regs(dev->sc); + csc_dump_regs(dev->csc); +} + +static void add_out_dtd(struct vpe_ctx *ctx, int port) +{ + struct vpe_q_data *q_data = &ctx->q_data[Q_DATA_DST]; + const struct vpe_port_data *p_data = &port_data[port]; + struct vb2_buffer *vb = &ctx->dst_vb->vb2_buf; + struct vpe_fmt *fmt = q_data->fmt; + const struct vpdma_data_format *vpdma_fmt; + int mv_buf_selector = !ctx->src_mv_buf_selector; + struct v4l2_pix_format_mplane *pix; + dma_addr_t dma_addr; + u32 flags = 0; + u32 offset = 0; + u32 stride; + + if (port == VPE_PORT_MV_OUT) { + vpdma_fmt = &vpdma_misc_fmts[VPDMA_DATA_FMT_MV]; + dma_addr = ctx->mv_buf_dma[mv_buf_selector]; + q_data = &ctx->q_data[Q_DATA_SRC]; + pix = &q_data->format.fmt.pix_mp; + stride = ALIGN((pix->width * vpdma_fmt->depth) >> 3, + VPDMA_STRIDE_ALIGN); + } else { + /* to incorporate interleaved formats */ + int plane = fmt->coplanar ? p_data->vb_part : 0; + + pix = &q_data->format.fmt.pix_mp; + vpdma_fmt = fmt->vpdma_fmt[plane]; + /* + * If we are using a single plane buffer and + * we need to set a separate vpdma chroma channel. + */ + if (pix->num_planes == 1 && plane) { + dma_addr = vb2_dma_contig_plane_dma_addr(vb, 0); + /* Compute required offset */ + offset = pix->plane_fmt[0].bytesperline * pix->height; + } else { + dma_addr = vb2_dma_contig_plane_dma_addr(vb, plane); + /* Use address as is, no offset */ + offset = 0; + } + if (!dma_addr) { + vpe_err(ctx->dev, + "acquiring output buffer(%d) dma_addr failed\n", + port); + return; + } + /* Apply the offset */ + dma_addr += offset; + stride = pix->plane_fmt[VPE_LUMA].bytesperline; + } + + if (q_data->flags & Q_DATA_FRAME_1D) + flags |= VPDMA_DATA_FRAME_1D; + if (q_data->flags & Q_DATA_MODE_TILED) + flags |= VPDMA_DATA_MODE_TILED; + + vpdma_set_max_size(ctx->dev->vpdma, VPDMA_MAX_SIZE1, + MAX_W, MAX_H); + + vpdma_add_out_dtd(&ctx->desc_list, pix->width, + stride, &q_data->c_rect, + vpdma_fmt, dma_addr, MAX_OUT_WIDTH_REG1, + MAX_OUT_HEIGHT_REG1, p_data->channel, flags); +} + +static void add_in_dtd(struct vpe_ctx *ctx, int port) +{ + struct vpe_q_data *q_data = &ctx->q_data[Q_DATA_SRC]; + const struct vpe_port_data *p_data = &port_data[port]; + struct vb2_buffer *vb = &ctx->src_vbs[p_data->vb_index]->vb2_buf; + struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); + struct vpe_fmt *fmt = q_data->fmt; + struct v4l2_pix_format_mplane *pix; + const struct vpdma_data_format *vpdma_fmt; + int mv_buf_selector = ctx->src_mv_buf_selector; + int field = vbuf->field == V4L2_FIELD_BOTTOM; + int frame_width, frame_height; + dma_addr_t dma_addr; + u32 flags = 0; + u32 offset = 0; + u32 stride; + + pix = &q_data->format.fmt.pix_mp; + if (port == VPE_PORT_MV_IN) { + vpdma_fmt = &vpdma_misc_fmts[VPDMA_DATA_FMT_MV]; + dma_addr = ctx->mv_buf_dma[mv_buf_selector]; + stride = ALIGN((pix->width * vpdma_fmt->depth) >> 3, + VPDMA_STRIDE_ALIGN); + } else { + /* to incorporate interleaved formats */ + int plane = fmt->coplanar ? p_data->vb_part : 0; + + vpdma_fmt = fmt->vpdma_fmt[plane]; + /* + * If we are using a single plane buffer and + * we need to set a separate vpdma chroma channel. + */ + if (pix->num_planes == 1 && plane) { + dma_addr = vb2_dma_contig_plane_dma_addr(vb, 0); + /* Compute required offset */ + offset = pix->plane_fmt[0].bytesperline * pix->height; + } else { + dma_addr = vb2_dma_contig_plane_dma_addr(vb, plane); + /* Use address as is, no offset */ + offset = 0; + } + if (!dma_addr) { + vpe_err(ctx->dev, + "acquiring output buffer(%d) dma_addr failed\n", + port); + return; + } + /* Apply the offset */ + dma_addr += offset; + stride = pix->plane_fmt[VPE_LUMA].bytesperline; + + /* + * field used in VPDMA desc = 0 (top) / 1 (bottom) + * Use top or bottom field from same vb alternately + * For each de-interlacing operation, f,f-1,f-2 should be one + * of TBT or BTB + */ + if (q_data->flags & Q_DATA_INTERLACED_SEQ_TB || + q_data->flags & Q_DATA_INTERLACED_SEQ_BT) { + /* Select initial value based on format */ + if (q_data->flags & Q_DATA_INTERLACED_SEQ_BT) + field = 1; + else + field = 0; + + /* Toggle for each vb_index and each operation */ + field = (field + p_data->vb_index + ctx->sequence) % 2; + + if (field) { + int height = pix->height / 2; + int bpp; + + if (fmt->fourcc == V4L2_PIX_FMT_NV12 || + fmt->fourcc == V4L2_PIX_FMT_NV21) + bpp = 1; + else + bpp = vpdma_fmt->depth >> 3; + + if (plane) + height /= 2; + + dma_addr += pix->width * height * bpp; + } + } + } + + if (q_data->flags & Q_DATA_FRAME_1D) + flags |= VPDMA_DATA_FRAME_1D; + if (q_data->flags & Q_DATA_MODE_TILED) + flags |= VPDMA_DATA_MODE_TILED; + + frame_width = q_data->c_rect.width; + frame_height = q_data->c_rect.height; + + if (p_data->vb_part && (fmt->fourcc == V4L2_PIX_FMT_NV12 || + fmt->fourcc == V4L2_PIX_FMT_NV21)) + frame_height /= 2; + + vpdma_add_in_dtd(&ctx->desc_list, pix->width, stride, + &q_data->c_rect, vpdma_fmt, dma_addr, + p_data->channel, field, flags, frame_width, + frame_height, 0, 0); +} + +/* + * Enable the expected IRQ sources + */ +static void enable_irqs(struct vpe_ctx *ctx) +{ + write_reg(ctx->dev, VPE_INT0_ENABLE0_SET, VPE_INT0_LIST0_COMPLETE); + write_reg(ctx->dev, VPE_INT0_ENABLE1_SET, VPE_DEI_ERROR_INT | + VPE_DS1_UV_ERROR_INT); + + vpdma_enable_list_complete_irq(ctx->dev->vpdma, 0, 0, true); +} + +static void disable_irqs(struct vpe_ctx *ctx) +{ + write_reg(ctx->dev, VPE_INT0_ENABLE0_CLR, 0xffffffff); + write_reg(ctx->dev, VPE_INT0_ENABLE1_CLR, 0xffffffff); + + vpdma_enable_list_complete_irq(ctx->dev->vpdma, 0, 0, false); +} + +/* device_run() - prepares and starts the device + * + * This function is only called when both the source and destination + * buffers are in place. + */ +static void device_run(void *priv) +{ + struct vpe_ctx *ctx = priv; + struct sc_data *sc = ctx->dev->sc; + struct vpe_q_data *d_q_data = &ctx->q_data[Q_DATA_DST]; + struct vpe_q_data *s_q_data = &ctx->q_data[Q_DATA_SRC]; + const struct v4l2_format_info *d_finfo; + + d_finfo = v4l2_format_info(d_q_data->fmt->fourcc); + + if (ctx->deinterlacing && s_q_data->flags & Q_IS_SEQ_XX && + ctx->sequence % 2 == 0) { + /* When using SEQ_XX type buffers, each buffer has two fields + * each buffer has two fields (top & bottom) + * Removing one buffer is actually getting two fields + * Alternate between two operations:- + * Even : consume one field but DO NOT REMOVE from queue + * Odd : consume other field and REMOVE from queue + */ + ctx->src_vbs[0] = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx); + WARN_ON(ctx->src_vbs[0] == NULL); + } else { + ctx->src_vbs[0] = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx); + WARN_ON(ctx->src_vbs[0] == NULL); + } + + ctx->dst_vb = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx); + WARN_ON(ctx->dst_vb == NULL); + + if (ctx->deinterlacing) { + + if (ctx->src_vbs[2] == NULL) { + ctx->src_vbs[2] = ctx->src_vbs[0]; + WARN_ON(ctx->src_vbs[2] == NULL); + ctx->src_vbs[1] = ctx->src_vbs[0]; + WARN_ON(ctx->src_vbs[1] == NULL); + } + + /* + * we have output the first 2 frames through line average, we + * now switch to EDI de-interlacer + */ + if (ctx->sequence == 2) + config_edi_input_mode(ctx, 0x3); /* EDI (Y + UV) */ + } + + /* config descriptors */ + if (ctx->dev->loaded_mmrs != ctx->mmr_adb.dma_addr || ctx->load_mmrs) { + vpdma_map_desc_buf(ctx->dev->vpdma, &ctx->mmr_adb); + vpdma_add_cfd_adb(&ctx->desc_list, CFD_MMR_CLIENT, &ctx->mmr_adb); + + set_line_modes(ctx); + + ctx->dev->loaded_mmrs = ctx->mmr_adb.dma_addr; + ctx->load_mmrs = false; + } + + if (sc->loaded_coeff_h != ctx->sc_coeff_h.dma_addr || + sc->load_coeff_h) { + vpdma_map_desc_buf(ctx->dev->vpdma, &ctx->sc_coeff_h); + vpdma_add_cfd_block(&ctx->desc_list, CFD_SC_CLIENT, + &ctx->sc_coeff_h, 0); + + sc->loaded_coeff_h = ctx->sc_coeff_h.dma_addr; + sc->load_coeff_h = false; + } + + if (sc->loaded_coeff_v != ctx->sc_coeff_v.dma_addr || + sc->load_coeff_v) { + vpdma_map_desc_buf(ctx->dev->vpdma, &ctx->sc_coeff_v); + vpdma_add_cfd_block(&ctx->desc_list, CFD_SC_CLIENT, + &ctx->sc_coeff_v, SC_COEF_SRAM_SIZE >> 4); + + sc->loaded_coeff_v = ctx->sc_coeff_v.dma_addr; + sc->load_coeff_v = false; + } + + /* output data descriptors */ + if (ctx->deinterlacing) + add_out_dtd(ctx, VPE_PORT_MV_OUT); + + if (v4l2_is_format_rgb(d_finfo)) { + add_out_dtd(ctx, VPE_PORT_RGB_OUT); + } else { + add_out_dtd(ctx, VPE_PORT_LUMA_OUT); + if (d_q_data->fmt->coplanar) + add_out_dtd(ctx, VPE_PORT_CHROMA_OUT); + } + + /* input data descriptors */ + if (ctx->deinterlacing) { + add_in_dtd(ctx, VPE_PORT_LUMA3_IN); + add_in_dtd(ctx, VPE_PORT_CHROMA3_IN); + + add_in_dtd(ctx, VPE_PORT_LUMA2_IN); + add_in_dtd(ctx, VPE_PORT_CHROMA2_IN); + } + + add_in_dtd(ctx, VPE_PORT_LUMA1_IN); + add_in_dtd(ctx, VPE_PORT_CHROMA1_IN); + + if (ctx->deinterlacing) + add_in_dtd(ctx, VPE_PORT_MV_IN); + + /* sync on channel control descriptors for input ports */ + vpdma_add_sync_on_channel_ctd(&ctx->desc_list, VPE_CHAN_LUMA1_IN); + vpdma_add_sync_on_channel_ctd(&ctx->desc_list, VPE_CHAN_CHROMA1_IN); + + if (ctx->deinterlacing) { + vpdma_add_sync_on_channel_ctd(&ctx->desc_list, + VPE_CHAN_LUMA2_IN); + vpdma_add_sync_on_channel_ctd(&ctx->desc_list, + VPE_CHAN_CHROMA2_IN); + + vpdma_add_sync_on_channel_ctd(&ctx->desc_list, + VPE_CHAN_LUMA3_IN); + vpdma_add_sync_on_channel_ctd(&ctx->desc_list, + VPE_CHAN_CHROMA3_IN); + + vpdma_add_sync_on_channel_ctd(&ctx->desc_list, VPE_CHAN_MV_IN); + } + + /* sync on channel control descriptors for output ports */ + if (v4l2_is_format_rgb(d_finfo)) { + vpdma_add_sync_on_channel_ctd(&ctx->desc_list, + VPE_CHAN_RGB_OUT); + } else { + vpdma_add_sync_on_channel_ctd(&ctx->desc_list, + VPE_CHAN_LUMA_OUT); + if (d_q_data->fmt->coplanar) + vpdma_add_sync_on_channel_ctd(&ctx->desc_list, + VPE_CHAN_CHROMA_OUT); + } + + if (ctx->deinterlacing) + vpdma_add_sync_on_channel_ctd(&ctx->desc_list, VPE_CHAN_MV_OUT); + + enable_irqs(ctx); + + vpdma_map_desc_buf(ctx->dev->vpdma, &ctx->desc_list.buf); + vpdma_submit_descs(ctx->dev->vpdma, &ctx->desc_list, 0); +} + +static void dei_error(struct vpe_ctx *ctx) +{ + dev_warn(ctx->dev->v4l2_dev.dev, + "received DEI error interrupt\n"); +} + +static void ds1_uv_error(struct vpe_ctx *ctx) +{ + dev_warn(ctx->dev->v4l2_dev.dev, + "received downsampler error interrupt\n"); +} + +static irqreturn_t vpe_irq(int irq_vpe, void *data) +{ + struct vpe_dev *dev = (struct vpe_dev *)data; + struct vpe_ctx *ctx; + struct vpe_q_data *d_q_data; + struct vb2_v4l2_buffer *s_vb, *d_vb; + unsigned long flags; + u32 irqst0, irqst1; + bool list_complete = false; + + irqst0 = read_reg(dev, VPE_INT0_STATUS0); + if (irqst0) { + write_reg(dev, VPE_INT0_STATUS0_CLR, irqst0); + vpe_dbg(dev, "INT0_STATUS0 = 0x%08x\n", irqst0); + } + + irqst1 = read_reg(dev, VPE_INT0_STATUS1); + if (irqst1) { + write_reg(dev, VPE_INT0_STATUS1_CLR, irqst1); + vpe_dbg(dev, "INT0_STATUS1 = 0x%08x\n", irqst1); + } + + ctx = v4l2_m2m_get_curr_priv(dev->m2m_dev); + if (!ctx) { + vpe_err(dev, "instance released before end of transaction\n"); + goto handled; + } + + if (irqst1) { + if (irqst1 & VPE_DEI_ERROR_INT) { + irqst1 &= ~VPE_DEI_ERROR_INT; + dei_error(ctx); + } + if (irqst1 & VPE_DS1_UV_ERROR_INT) { + irqst1 &= ~VPE_DS1_UV_ERROR_INT; + ds1_uv_error(ctx); + } + } + + if (irqst0) { + if (irqst0 & VPE_INT0_LIST0_COMPLETE) + vpdma_clear_list_stat(ctx->dev->vpdma, 0, 0); + + irqst0 &= ~(VPE_INT0_LIST0_COMPLETE); + list_complete = true; + } + + if (irqst0 | irqst1) { + dev_warn(dev->v4l2_dev.dev, "Unexpected interrupt: INT0_STATUS0 = 0x%08x, INT0_STATUS1 = 0x%08x\n", + irqst0, irqst1); + } + + /* + * Setup next operation only when list complete IRQ occurs + * otherwise, skip the following code + */ + if (!list_complete) + goto handled; + + disable_irqs(ctx); + + vpdma_unmap_desc_buf(dev->vpdma, &ctx->desc_list.buf); + vpdma_unmap_desc_buf(dev->vpdma, &ctx->mmr_adb); + vpdma_unmap_desc_buf(dev->vpdma, &ctx->sc_coeff_h); + vpdma_unmap_desc_buf(dev->vpdma, &ctx->sc_coeff_v); + + vpdma_reset_desc_list(&ctx->desc_list); + + /* the previous dst mv buffer becomes the next src mv buffer */ + ctx->src_mv_buf_selector = !ctx->src_mv_buf_selector; + + s_vb = ctx->src_vbs[0]; + d_vb = ctx->dst_vb; + + d_vb->flags = s_vb->flags; + d_vb->vb2_buf.timestamp = s_vb->vb2_buf.timestamp; + + if (s_vb->flags & V4L2_BUF_FLAG_TIMECODE) + d_vb->timecode = s_vb->timecode; + + d_vb->sequence = ctx->sequence; + s_vb->sequence = ctx->sequence; + + d_q_data = &ctx->q_data[Q_DATA_DST]; + if (d_q_data->flags & Q_IS_INTERLACED) { + d_vb->field = ctx->field; + if (ctx->field == V4L2_FIELD_BOTTOM) { + ctx->sequence++; + ctx->field = V4L2_FIELD_TOP; + } else { + WARN_ON(ctx->field != V4L2_FIELD_TOP); + ctx->field = V4L2_FIELD_BOTTOM; + } + } else { + d_vb->field = V4L2_FIELD_NONE; + ctx->sequence++; + } + + if (ctx->deinterlacing) { + /* + * Allow source buffer to be dequeued only if it won't be used + * in the next iteration. All vbs are initialized to first + * buffer and we are shifting buffers every iteration, for the + * first two iterations, no buffer will be dequeued. + * This ensures that driver will keep (n-2)th (n-1)th and (n)th + * field when deinterlacing is enabled + */ + if (ctx->src_vbs[2] != ctx->src_vbs[1]) + s_vb = ctx->src_vbs[2]; + else + s_vb = NULL; + } + + spin_lock_irqsave(&dev->lock, flags); + + if (s_vb) + v4l2_m2m_buf_done(s_vb, VB2_BUF_STATE_DONE); + + v4l2_m2m_buf_done(d_vb, VB2_BUF_STATE_DONE); + + spin_unlock_irqrestore(&dev->lock, flags); + + if (ctx->deinterlacing) { + ctx->src_vbs[2] = ctx->src_vbs[1]; + ctx->src_vbs[1] = ctx->src_vbs[0]; + } + + /* + * Since the vb2_buf_done has already been called fir therse + * buffer we can now NULL them out so that we won't try + * to clean out stray pointer later on. + */ + ctx->src_vbs[0] = NULL; + ctx->dst_vb = NULL; + + if (ctx->aborting) + goto finished; + + ctx->bufs_completed++; + if (ctx->bufs_completed < ctx->bufs_per_job && job_ready(ctx)) { + device_run(ctx); + goto handled; + } + +finished: + vpe_dbg(ctx->dev, "finishing transaction\n"); + ctx->bufs_completed = 0; + v4l2_m2m_job_finish(dev->m2m_dev, ctx->fh.m2m_ctx); +handled: + return IRQ_HANDLED; +} + +/* + * video ioctls + */ +static int vpe_querycap(struct file *file, void *priv, + struct v4l2_capability *cap) +{ + strscpy(cap->driver, VPE_MODULE_NAME, sizeof(cap->driver)); + strscpy(cap->card, VPE_MODULE_NAME, sizeof(cap->card)); + snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s", + VPE_MODULE_NAME); + return 0; +} + +static int __enum_fmt(struct v4l2_fmtdesc *f, u32 type) +{ + int i, index; + struct vpe_fmt *fmt = NULL; + + index = 0; + for (i = 0; i < ARRAY_SIZE(vpe_formats); ++i) { + if (vpe_formats[i].types & type) { + if (index == f->index) { + fmt = &vpe_formats[i]; + break; + } + index++; + } + } + + if (!fmt) + return -EINVAL; + + f->pixelformat = fmt->fourcc; + return 0; +} + +static int vpe_enum_fmt(struct file *file, void *priv, + struct v4l2_fmtdesc *f) +{ + if (V4L2_TYPE_IS_OUTPUT(f->type)) + return __enum_fmt(f, VPE_FMT_TYPE_OUTPUT); + + return __enum_fmt(f, VPE_FMT_TYPE_CAPTURE); +} + +static int vpe_g_fmt(struct file *file, void *priv, struct v4l2_format *f) +{ + struct v4l2_pix_format_mplane *pix = &f->fmt.pix_mp; + struct vpe_ctx *ctx = file->private_data; + struct vb2_queue *vq; + struct vpe_q_data *q_data; + + vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type); + if (!vq) + return -EINVAL; + + q_data = get_q_data(ctx, f->type); + if (!q_data) + return -EINVAL; + + *f = q_data->format; + + if (V4L2_TYPE_IS_CAPTURE(f->type)) { + struct vpe_q_data *s_q_data; + struct v4l2_pix_format_mplane *spix; + + /* get colorimetry from the source queue */ + s_q_data = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE); + spix = &s_q_data->format.fmt.pix_mp; + + pix->colorspace = spix->colorspace; + pix->xfer_func = spix->xfer_func; + pix->ycbcr_enc = spix->ycbcr_enc; + pix->quantization = spix->quantization; + } + + return 0; +} + +static int __vpe_try_fmt(struct vpe_ctx *ctx, struct v4l2_format *f, + struct vpe_fmt *fmt, int type) +{ + struct v4l2_pix_format_mplane *pix = &f->fmt.pix_mp; + struct v4l2_plane_pix_format *plane_fmt; + unsigned int w_align; + int i, depth, depth_bytes, height; + unsigned int stride = 0; + const struct v4l2_format_info *finfo; + + if (!fmt || !(fmt->types & type)) { + vpe_dbg(ctx->dev, "Fourcc format (0x%08x) invalid.\n", + pix->pixelformat); + fmt = __find_format(V4L2_PIX_FMT_YUYV); + } + + if (pix->field != V4L2_FIELD_NONE && + pix->field != V4L2_FIELD_ALTERNATE && + pix->field != V4L2_FIELD_SEQ_TB && + pix->field != V4L2_FIELD_SEQ_BT) + pix->field = V4L2_FIELD_NONE; + + depth = fmt->vpdma_fmt[VPE_LUMA]->depth; + + /* + * the line stride should 16 byte aligned for VPDMA to work, based on + * the bytes per pixel, figure out how much the width should be aligned + * to make sure line stride is 16 byte aligned + */ + depth_bytes = depth >> 3; + + if (depth_bytes == 3) { + /* + * if bpp is 3(as in some RGB formats), the pixel width doesn't + * really help in ensuring line stride is 16 byte aligned + */ + w_align = 4; + } else { + /* + * for the remainder bpp(4, 2 and 1), the pixel width alignment + * can ensure a line stride alignment of 16 bytes. For example, + * if bpp is 2, then the line stride can be 16 byte aligned if + * the width is 8 byte aligned + */ + + /* + * HACK: using order_base_2() here causes lots of asm output + * errors with smatch, on i386: + * ./arch/x86/include/asm/bitops.h:457:22: + * warning: asm output is not an lvalue + * Perhaps some gcc optimization is doing the wrong thing + * there. + * Let's get rid of them by doing the calculus on two steps + */ + w_align = roundup_pow_of_two(VPDMA_DESC_ALIGN / depth_bytes); + w_align = ilog2(w_align); + } + + v4l_bound_align_image(&pix->width, MIN_W, MAX_W, w_align, + &pix->height, MIN_H, MAX_H, H_ALIGN, + S_ALIGN); + + if (!pix->num_planes || pix->num_planes > 2) + pix->num_planes = fmt->coplanar ? 2 : 1; + else if (pix->num_planes > 1 && !fmt->coplanar) + pix->num_planes = 1; + + pix->pixelformat = fmt->fourcc; + finfo = v4l2_format_info(fmt->fourcc); + + /* + * For the actual image parameters, we need to consider the field + * height of the image for SEQ_XX buffers. + */ + if (pix->field == V4L2_FIELD_SEQ_TB || pix->field == V4L2_FIELD_SEQ_BT) + height = pix->height / 2; + else + height = pix->height; + + if (!pix->colorspace) { + if (v4l2_is_format_rgb(finfo)) { + pix->colorspace = V4L2_COLORSPACE_SRGB; + } else { + if (height > 1280) /* HD */ + pix->colorspace = V4L2_COLORSPACE_REC709; + else /* SD */ + pix->colorspace = V4L2_COLORSPACE_SMPTE170M; + } + } + + for (i = 0; i < pix->num_planes; i++) { + plane_fmt = &pix->plane_fmt[i]; + depth = fmt->vpdma_fmt[i]->depth; + + stride = (pix->width * fmt->vpdma_fmt[VPE_LUMA]->depth) >> 3; + if (stride > plane_fmt->bytesperline) + plane_fmt->bytesperline = stride; + + plane_fmt->bytesperline = clamp_t(u32, plane_fmt->bytesperline, + stride, + VPDMA_MAX_STRIDE); + + plane_fmt->bytesperline = ALIGN(plane_fmt->bytesperline, + VPDMA_STRIDE_ALIGN); + + if (i == VPE_LUMA) { + plane_fmt->sizeimage = pix->height * + plane_fmt->bytesperline; + + if (pix->num_planes == 1 && fmt->coplanar) + plane_fmt->sizeimage += pix->height * + plane_fmt->bytesperline * + fmt->vpdma_fmt[VPE_CHROMA]->depth >> 3; + + } else { /* i == VIP_CHROMA */ + plane_fmt->sizeimage = (pix->height * + plane_fmt->bytesperline * + depth) >> 3; + } + } + + return 0; +} + +static int vpe_try_fmt(struct file *file, void *priv, struct v4l2_format *f) +{ + struct vpe_ctx *ctx = file->private_data; + struct vpe_fmt *fmt = find_format(f); + + if (V4L2_TYPE_IS_OUTPUT(f->type)) + return __vpe_try_fmt(ctx, f, fmt, VPE_FMT_TYPE_OUTPUT); + else + return __vpe_try_fmt(ctx, f, fmt, VPE_FMT_TYPE_CAPTURE); +} + +static int __vpe_s_fmt(struct vpe_ctx *ctx, struct v4l2_format *f) +{ + struct v4l2_pix_format_mplane *pix = &f->fmt.pix_mp; + struct v4l2_pix_format_mplane *qpix; + struct vpe_q_data *q_data; + struct vb2_queue *vq; + + vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type); + if (!vq) + return -EINVAL; + + if (vb2_is_busy(vq)) { + vpe_err(ctx->dev, "queue busy\n"); + return -EBUSY; + } + + q_data = get_q_data(ctx, f->type); + if (!q_data) + return -EINVAL; + + qpix = &q_data->format.fmt.pix_mp; + q_data->fmt = find_format(f); + q_data->format = *f; + + q_data->c_rect.left = 0; + q_data->c_rect.top = 0; + q_data->c_rect.width = pix->width; + q_data->c_rect.height = pix->height; + + if (qpix->field == V4L2_FIELD_ALTERNATE) + q_data->flags |= Q_DATA_INTERLACED_ALTERNATE; + else if (qpix->field == V4L2_FIELD_SEQ_TB) + q_data->flags |= Q_DATA_INTERLACED_SEQ_TB; + else if (qpix->field == V4L2_FIELD_SEQ_BT) + q_data->flags |= Q_DATA_INTERLACED_SEQ_BT; + else + q_data->flags &= ~Q_IS_INTERLACED; + + /* the crop height is halved for the case of SEQ_XX buffers */ + if (q_data->flags & Q_IS_SEQ_XX) + q_data->c_rect.height /= 2; + + vpe_dbg(ctx->dev, "Setting format for type %d, wxh: %dx%d, fmt: %d bpl_y %d", + f->type, pix->width, pix->height, pix->pixelformat, + pix->plane_fmt[0].bytesperline); + if (pix->num_planes == 2) + vpe_dbg(ctx->dev, " bpl_uv %d\n", + pix->plane_fmt[1].bytesperline); + + return 0; +} + +static int vpe_s_fmt(struct file *file, void *priv, struct v4l2_format *f) +{ + int ret; + struct vpe_ctx *ctx = file->private_data; + + ret = vpe_try_fmt(file, priv, f); + if (ret) + return ret; + + ret = __vpe_s_fmt(ctx, f); + if (ret) + return ret; + + if (V4L2_TYPE_IS_OUTPUT(f->type)) + set_src_registers(ctx); + else + set_dst_registers(ctx); + + return set_srcdst_params(ctx); +} + +static int __vpe_try_selection(struct vpe_ctx *ctx, struct v4l2_selection *s) +{ + struct vpe_q_data *q_data; + struct v4l2_pix_format_mplane *pix; + int height; + + if ((s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) && + (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)) + return -EINVAL; + + q_data = get_q_data(ctx, s->type); + if (!q_data) + return -EINVAL; + + pix = &q_data->format.fmt.pix_mp; + + switch (s->target) { + case V4L2_SEL_TGT_COMPOSE: + /* + * COMPOSE target is only valid for capture buffer type, return + * error for output buffer type + */ + if (s->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) + return -EINVAL; + break; + case V4L2_SEL_TGT_CROP: + /* + * CROP target is only valid for output buffer type, return + * error for capture buffer type + */ + if (s->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) + return -EINVAL; + break; + /* + * bound and default crop/compose targets are invalid targets to + * try/set + */ + default: + return -EINVAL; + } + + /* + * For SEQ_XX buffers, crop height should be less than the height of + * the field height, not the buffer height + */ + if (q_data->flags & Q_IS_SEQ_XX) + height = pix->height / 2; + else + height = pix->height; + + if (s->r.top < 0 || s->r.left < 0) { + vpe_err(ctx->dev, "negative values for top and left\n"); + s->r.top = s->r.left = 0; + } + + v4l_bound_align_image(&s->r.width, MIN_W, pix->width, 1, + &s->r.height, MIN_H, height, H_ALIGN, S_ALIGN); + + /* adjust left/top if cropping rectangle is out of bounds */ + if (s->r.left + s->r.width > pix->width) + s->r.left = pix->width - s->r.width; + if (s->r.top + s->r.height > pix->height) + s->r.top = pix->height - s->r.height; + + return 0; +} + +static int vpe_g_selection(struct file *file, void *fh, + struct v4l2_selection *s) +{ + struct vpe_ctx *ctx = file->private_data; + struct vpe_q_data *q_data; + struct v4l2_pix_format_mplane *pix; + bool use_c_rect = false; + + if ((s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) && + (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)) + return -EINVAL; + + q_data = get_q_data(ctx, s->type); + if (!q_data) + return -EINVAL; + + pix = &q_data->format.fmt.pix_mp; + + switch (s->target) { + case V4L2_SEL_TGT_COMPOSE_DEFAULT: + case V4L2_SEL_TGT_COMPOSE_BOUNDS: + if (s->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) + return -EINVAL; + break; + case V4L2_SEL_TGT_CROP_BOUNDS: + case V4L2_SEL_TGT_CROP_DEFAULT: + if (s->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) + return -EINVAL; + break; + case V4L2_SEL_TGT_COMPOSE: + if (s->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) + return -EINVAL; + use_c_rect = true; + break; + case V4L2_SEL_TGT_CROP: + if (s->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) + return -EINVAL; + use_c_rect = true; + break; + default: + return -EINVAL; + } + + if (use_c_rect) { + /* + * for CROP/COMPOSE target type, return c_rect params from the + * respective buffer type + */ + s->r = q_data->c_rect; + } else { + /* + * for DEFAULT/BOUNDS target type, return width and height from + * S_FMT of the respective buffer type + */ + s->r.left = 0; + s->r.top = 0; + s->r.width = pix->width; + s->r.height = pix->height; + } + + return 0; +} + + +static int vpe_s_selection(struct file *file, void *fh, + struct v4l2_selection *s) +{ + struct vpe_ctx *ctx = file->private_data; + struct vpe_q_data *q_data; + struct v4l2_selection sel = *s; + int ret; + + ret = __vpe_try_selection(ctx, &sel); + if (ret) + return ret; + + q_data = get_q_data(ctx, sel.type); + if (!q_data) + return -EINVAL; + + if ((q_data->c_rect.left == sel.r.left) && + (q_data->c_rect.top == sel.r.top) && + (q_data->c_rect.width == sel.r.width) && + (q_data->c_rect.height == sel.r.height)) { + vpe_dbg(ctx->dev, + "requested crop/compose values are already set\n"); + return 0; + } + + q_data->c_rect = sel.r; + + return set_srcdst_params(ctx); +} + +/* + * defines number of buffers/frames a context can process with VPE before + * switching to a different context. default value is 1 buffer per context + */ +#define V4L2_CID_VPE_BUFS_PER_JOB (V4L2_CID_USER_TI_VPE_BASE + 0) + +static int vpe_s_ctrl(struct v4l2_ctrl *ctrl) +{ + struct vpe_ctx *ctx = + container_of(ctrl->handler, struct vpe_ctx, hdl); + + switch (ctrl->id) { + case V4L2_CID_VPE_BUFS_PER_JOB: + ctx->bufs_per_job = ctrl->val; + break; + + default: + vpe_err(ctx->dev, "Invalid control\n"); + return -EINVAL; + } + + return 0; +} + +static const struct v4l2_ctrl_ops vpe_ctrl_ops = { + .s_ctrl = vpe_s_ctrl, +}; + +static const struct v4l2_ioctl_ops vpe_ioctl_ops = { + .vidioc_querycap = vpe_querycap, + + .vidioc_enum_fmt_vid_cap = vpe_enum_fmt, + .vidioc_g_fmt_vid_cap_mplane = vpe_g_fmt, + .vidioc_try_fmt_vid_cap_mplane = vpe_try_fmt, + .vidioc_s_fmt_vid_cap_mplane = vpe_s_fmt, + + .vidioc_enum_fmt_vid_out = vpe_enum_fmt, + .vidioc_g_fmt_vid_out_mplane = vpe_g_fmt, + .vidioc_try_fmt_vid_out_mplane = vpe_try_fmt, + .vidioc_s_fmt_vid_out_mplane = vpe_s_fmt, + + .vidioc_g_selection = vpe_g_selection, + .vidioc_s_selection = vpe_s_selection, + + .vidioc_reqbufs = v4l2_m2m_ioctl_reqbufs, + .vidioc_querybuf = v4l2_m2m_ioctl_querybuf, + .vidioc_qbuf = v4l2_m2m_ioctl_qbuf, + .vidioc_dqbuf = v4l2_m2m_ioctl_dqbuf, + .vidioc_expbuf = v4l2_m2m_ioctl_expbuf, + .vidioc_streamon = v4l2_m2m_ioctl_streamon, + .vidioc_streamoff = v4l2_m2m_ioctl_streamoff, + + .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, + .vidioc_unsubscribe_event = v4l2_event_unsubscribe, +}; + +/* + * Queue operations + */ +static int vpe_queue_setup(struct vb2_queue *vq, + unsigned int *nbuffers, unsigned int *nplanes, + unsigned int sizes[], struct device *alloc_devs[]) +{ + int i; + struct vpe_ctx *ctx = vb2_get_drv_priv(vq); + struct vpe_q_data *q_data; + struct v4l2_pix_format_mplane *pix; + + q_data = get_q_data(ctx, vq->type); + if (!q_data) + return -EINVAL; + + pix = &q_data->format.fmt.pix_mp; + *nplanes = pix->num_planes; + + for (i = 0; i < *nplanes; i++) + sizes[i] = pix->plane_fmt[i].sizeimage; + + vpe_dbg(ctx->dev, "get %d buffer(s) of size %d", *nbuffers, + sizes[VPE_LUMA]); + if (*nplanes == 2) + vpe_dbg(ctx->dev, " and %d\n", sizes[VPE_CHROMA]); + + return 0; +} + +static int vpe_buf_prepare(struct vb2_buffer *vb) +{ + struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); + struct vpe_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); + struct vpe_q_data *q_data; + struct v4l2_pix_format_mplane *pix; + int i; + + vpe_dbg(ctx->dev, "type: %d\n", vb->vb2_queue->type); + + q_data = get_q_data(ctx, vb->vb2_queue->type); + if (!q_data) + return -EINVAL; + + pix = &q_data->format.fmt.pix_mp; + + if (vb->vb2_queue->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { + if (!(q_data->flags & Q_IS_INTERLACED)) { + vbuf->field = V4L2_FIELD_NONE; + } else { + if (vbuf->field != V4L2_FIELD_TOP && + vbuf->field != V4L2_FIELD_BOTTOM && + vbuf->field != V4L2_FIELD_SEQ_TB && + vbuf->field != V4L2_FIELD_SEQ_BT) + return -EINVAL; + } + } + + for (i = 0; i < pix->num_planes; i++) { + if (vb2_plane_size(vb, i) < pix->plane_fmt[i].sizeimage) { + vpe_err(ctx->dev, + "data will not fit into plane (%lu < %lu)\n", + vb2_plane_size(vb, i), + (long)pix->plane_fmt[i].sizeimage); + return -EINVAL; + } + } + + for (i = 0; i < pix->num_planes; i++) + vb2_set_plane_payload(vb, i, pix->plane_fmt[i].sizeimage); + + return 0; +} + +static void vpe_buf_queue(struct vb2_buffer *vb) +{ + struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); + struct vpe_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); + + v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vbuf); +} + +static int check_srcdst_sizes(struct vpe_ctx *ctx) +{ + struct vpe_q_data *s_q_data = &ctx->q_data[Q_DATA_SRC]; + struct vpe_q_data *d_q_data = &ctx->q_data[Q_DATA_DST]; + unsigned int src_w = s_q_data->c_rect.width; + unsigned int src_h = s_q_data->c_rect.height; + unsigned int dst_w = d_q_data->c_rect.width; + unsigned int dst_h = d_q_data->c_rect.height; + + if (src_w == dst_w && src_h == dst_h) + return 0; + + if (src_h <= SC_MAX_PIXEL_HEIGHT && + src_w <= SC_MAX_PIXEL_WIDTH && + dst_h <= SC_MAX_PIXEL_HEIGHT && + dst_w <= SC_MAX_PIXEL_WIDTH) + return 0; + + return -1; +} + +static void vpe_return_all_buffers(struct vpe_ctx *ctx, struct vb2_queue *q, + enum vb2_buffer_state state) +{ + struct vb2_v4l2_buffer *vb; + unsigned long flags; + + for (;;) { + if (V4L2_TYPE_IS_OUTPUT(q->type)) + vb = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx); + else + vb = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx); + if (!vb) + break; + spin_lock_irqsave(&ctx->dev->lock, flags); + v4l2_m2m_buf_done(vb, state); + spin_unlock_irqrestore(&ctx->dev->lock, flags); + } + + /* + * Cleanup the in-transit vb2 buffers that have been + * removed from their respective queue already but for + * which procecessing has not been completed yet. + */ + if (V4L2_TYPE_IS_OUTPUT(q->type)) { + spin_lock_irqsave(&ctx->dev->lock, flags); + + if (ctx->src_vbs[2]) + v4l2_m2m_buf_done(ctx->src_vbs[2], state); + + if (ctx->src_vbs[1] && (ctx->src_vbs[1] != ctx->src_vbs[2])) + v4l2_m2m_buf_done(ctx->src_vbs[1], state); + + if (ctx->src_vbs[0] && + (ctx->src_vbs[0] != ctx->src_vbs[1]) && + (ctx->src_vbs[0] != ctx->src_vbs[2])) + v4l2_m2m_buf_done(ctx->src_vbs[0], state); + + ctx->src_vbs[2] = NULL; + ctx->src_vbs[1] = NULL; + ctx->src_vbs[0] = NULL; + + spin_unlock_irqrestore(&ctx->dev->lock, flags); + } else { + if (ctx->dst_vb) { + spin_lock_irqsave(&ctx->dev->lock, flags); + + v4l2_m2m_buf_done(ctx->dst_vb, state); + ctx->dst_vb = NULL; + spin_unlock_irqrestore(&ctx->dev->lock, flags); + } + } +} + +static int vpe_start_streaming(struct vb2_queue *q, unsigned int count) +{ + struct vpe_ctx *ctx = vb2_get_drv_priv(q); + + /* Check any of the size exceed maximum scaling sizes */ + if (check_srcdst_sizes(ctx)) { + vpe_err(ctx->dev, + "Conversion setup failed, check source and destination parameters\n" + ); + vpe_return_all_buffers(ctx, q, VB2_BUF_STATE_QUEUED); + return -EINVAL; + } + + if (ctx->deinterlacing) + config_edi_input_mode(ctx, 0x0); + + if (ctx->sequence != 0) + set_srcdst_params(ctx); + + return 0; +} + +static void vpe_stop_streaming(struct vb2_queue *q) +{ + struct vpe_ctx *ctx = vb2_get_drv_priv(q); + + vpe_dump_regs(ctx->dev); + vpdma_dump_regs(ctx->dev->vpdma); + + vpe_return_all_buffers(ctx, q, VB2_BUF_STATE_ERROR); +} + +static const struct vb2_ops vpe_qops = { + .queue_setup = vpe_queue_setup, + .buf_prepare = vpe_buf_prepare, + .buf_queue = vpe_buf_queue, + .wait_prepare = vb2_ops_wait_prepare, + .wait_finish = vb2_ops_wait_finish, + .start_streaming = vpe_start_streaming, + .stop_streaming = vpe_stop_streaming, +}; + +static int queue_init(void *priv, struct vb2_queue *src_vq, + struct vb2_queue *dst_vq) +{ + struct vpe_ctx *ctx = priv; + struct vpe_dev *dev = ctx->dev; + int ret; + + memset(src_vq, 0, sizeof(*src_vq)); + src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; + src_vq->io_modes = VB2_MMAP | VB2_DMABUF; + src_vq->drv_priv = ctx; + src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer); + src_vq->ops = &vpe_qops; + src_vq->mem_ops = &vb2_dma_contig_memops; + src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; + src_vq->lock = &dev->dev_mutex; + src_vq->dev = dev->v4l2_dev.dev; + + ret = vb2_queue_init(src_vq); + if (ret) + return ret; + + memset(dst_vq, 0, sizeof(*dst_vq)); + dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + dst_vq->io_modes = VB2_MMAP | VB2_DMABUF; + dst_vq->drv_priv = ctx; + dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer); + dst_vq->ops = &vpe_qops; + dst_vq->mem_ops = &vb2_dma_contig_memops; + dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; + dst_vq->lock = &dev->dev_mutex; + dst_vq->dev = dev->v4l2_dev.dev; + + return vb2_queue_init(dst_vq); +} + +static const struct v4l2_ctrl_config vpe_bufs_per_job = { + .ops = &vpe_ctrl_ops, + .id = V4L2_CID_VPE_BUFS_PER_JOB, + .name = "Buffers Per Transaction", + .type = V4L2_CTRL_TYPE_INTEGER, + .def = VPE_DEF_BUFS_PER_JOB, + .min = 1, + .max = VIDEO_MAX_FRAME, + .step = 1, +}; + +/* + * File operations + */ +static int vpe_open(struct file *file) +{ + struct vpe_dev *dev = video_drvdata(file); + struct vpe_q_data *s_q_data; + struct v4l2_ctrl_handler *hdl; + struct vpe_ctx *ctx; + struct v4l2_pix_format_mplane *pix; + int ret; + + vpe_dbg(dev, "vpe_open\n"); + + ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); + if (!ctx) + return -ENOMEM; + + ctx->dev = dev; + + if (mutex_lock_interruptible(&dev->dev_mutex)) { + ret = -ERESTARTSYS; + goto free_ctx; + } + + ret = vpdma_create_desc_list(&ctx->desc_list, VPE_DESC_LIST_SIZE, + VPDMA_LIST_TYPE_NORMAL); + if (ret != 0) + goto unlock; + + ret = vpdma_alloc_desc_buf(&ctx->mmr_adb, sizeof(struct vpe_mmr_adb)); + if (ret != 0) + goto free_desc_list; + + ret = vpdma_alloc_desc_buf(&ctx->sc_coeff_h, SC_COEF_SRAM_SIZE); + if (ret != 0) + goto free_mmr_adb; + + ret = vpdma_alloc_desc_buf(&ctx->sc_coeff_v, SC_COEF_SRAM_SIZE); + if (ret != 0) + goto free_sc_h; + + init_adb_hdrs(ctx); + + v4l2_fh_init(&ctx->fh, video_devdata(file)); + file->private_data = ctx; + + hdl = &ctx->hdl; + v4l2_ctrl_handler_init(hdl, 1); + v4l2_ctrl_new_custom(hdl, &vpe_bufs_per_job, NULL); + if (hdl->error) { + ret = hdl->error; + goto exit_fh; + } + ctx->fh.ctrl_handler = hdl; + v4l2_ctrl_handler_setup(hdl); + + s_q_data = &ctx->q_data[Q_DATA_SRC]; + pix = &s_q_data->format.fmt.pix_mp; + s_q_data->fmt = __find_format(V4L2_PIX_FMT_YUYV); + pix->pixelformat = s_q_data->fmt->fourcc; + s_q_data->format.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; + pix->width = 1920; + pix->height = 1080; + pix->num_planes = 1; + pix->plane_fmt[VPE_LUMA].bytesperline = (pix->width * + s_q_data->fmt->vpdma_fmt[VPE_LUMA]->depth) >> 3; + pix->plane_fmt[VPE_LUMA].sizeimage = + pix->plane_fmt[VPE_LUMA].bytesperline * + pix->height; + pix->colorspace = V4L2_COLORSPACE_REC709; + pix->xfer_func = V4L2_XFER_FUNC_DEFAULT; + pix->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT; + pix->quantization = V4L2_QUANTIZATION_DEFAULT; + pix->field = V4L2_FIELD_NONE; + s_q_data->c_rect.left = 0; + s_q_data->c_rect.top = 0; + s_q_data->c_rect.width = pix->width; + s_q_data->c_rect.height = pix->height; + s_q_data->flags = 0; + + ctx->q_data[Q_DATA_DST] = *s_q_data; + ctx->q_data[Q_DATA_DST].format.type = + V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + + set_dei_shadow_registers(ctx); + set_src_registers(ctx); + set_dst_registers(ctx); + ret = set_srcdst_params(ctx); + if (ret) + goto exit_fh; + + ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(dev->m2m_dev, ctx, &queue_init); + + if (IS_ERR(ctx->fh.m2m_ctx)) { + ret = PTR_ERR(ctx->fh.m2m_ctx); + goto exit_fh; + } + + v4l2_fh_add(&ctx->fh); + + /* + * for now, just report the creation of the first instance, we can later + * optimize the driver to enable or disable clocks when the first + * instance is created or the last instance released + */ + if (atomic_inc_return(&dev->num_instances) == 1) + vpe_dbg(dev, "first instance created\n"); + + ctx->bufs_per_job = VPE_DEF_BUFS_PER_JOB; + + ctx->load_mmrs = true; + + vpe_dbg(dev, "created instance %p, m2m_ctx: %p\n", + ctx, ctx->fh.m2m_ctx); + + mutex_unlock(&dev->dev_mutex); + + return 0; +exit_fh: + v4l2_ctrl_handler_free(hdl); + v4l2_fh_exit(&ctx->fh); + vpdma_free_desc_buf(&ctx->sc_coeff_v); +free_sc_h: + vpdma_free_desc_buf(&ctx->sc_coeff_h); +free_mmr_adb: + vpdma_free_desc_buf(&ctx->mmr_adb); +free_desc_list: + vpdma_free_desc_list(&ctx->desc_list); +unlock: + mutex_unlock(&dev->dev_mutex); +free_ctx: + kfree(ctx); + return ret; +} + +static int vpe_release(struct file *file) +{ + struct vpe_dev *dev = video_drvdata(file); + struct vpe_ctx *ctx = file->private_data; + + vpe_dbg(dev, "releasing instance %p\n", ctx); + + mutex_lock(&dev->dev_mutex); + free_mv_buffers(ctx); + + vpdma_unmap_desc_buf(dev->vpdma, &ctx->desc_list.buf); + vpdma_unmap_desc_buf(dev->vpdma, &ctx->mmr_adb); + vpdma_unmap_desc_buf(dev->vpdma, &ctx->sc_coeff_h); + vpdma_unmap_desc_buf(dev->vpdma, &ctx->sc_coeff_v); + + vpdma_free_desc_list(&ctx->desc_list); + vpdma_free_desc_buf(&ctx->mmr_adb); + + vpdma_free_desc_buf(&ctx->sc_coeff_v); + vpdma_free_desc_buf(&ctx->sc_coeff_h); + + v4l2_fh_del(&ctx->fh); + v4l2_fh_exit(&ctx->fh); + v4l2_ctrl_handler_free(&ctx->hdl); + v4l2_m2m_ctx_release(ctx->fh.m2m_ctx); + + kfree(ctx); + + /* + * for now, just report the release of the last instance, we can later + * optimize the driver to enable or disable clocks when the first + * instance is created or the last instance released + */ + if (atomic_dec_return(&dev->num_instances) == 0) + vpe_dbg(dev, "last instance released\n"); + + mutex_unlock(&dev->dev_mutex); + + return 0; +} + +static const struct v4l2_file_operations vpe_fops = { + .owner = THIS_MODULE, + .open = vpe_open, + .release = vpe_release, + .poll = v4l2_m2m_fop_poll, + .unlocked_ioctl = video_ioctl2, + .mmap = v4l2_m2m_fop_mmap, +}; + +static const struct video_device vpe_videodev = { + .name = VPE_MODULE_NAME, + .fops = &vpe_fops, + .ioctl_ops = &vpe_ioctl_ops, + .minor = -1, + .release = video_device_release_empty, + .vfl_dir = VFL_DIR_M2M, + .device_caps = V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_STREAMING, +}; + +static const struct v4l2_m2m_ops m2m_ops = { + .device_run = device_run, + .job_ready = job_ready, + .job_abort = job_abort, +}; + +static int vpe_runtime_get(struct platform_device *pdev) +{ + int r; + + dev_dbg(&pdev->dev, "vpe_runtime_get\n"); + + r = pm_runtime_resume_and_get(&pdev->dev); + WARN_ON(r < 0); + return r; +} + +static void vpe_runtime_put(struct platform_device *pdev) +{ + + int r; + + dev_dbg(&pdev->dev, "vpe_runtime_put\n"); + + r = pm_runtime_put_sync(&pdev->dev); + WARN_ON(r < 0 && r != -ENOSYS); +} + +static void vpe_fw_cb(struct platform_device *pdev) +{ + struct vpe_dev *dev = platform_get_drvdata(pdev); + struct video_device *vfd; + int ret; + + vfd = &dev->vfd; + *vfd = vpe_videodev; + vfd->lock = &dev->dev_mutex; + vfd->v4l2_dev = &dev->v4l2_dev; + + ret = video_register_device(vfd, VFL_TYPE_VIDEO, 0); + if (ret) { + vpe_err(dev, "Failed to register video device\n"); + + vpe_set_clock_enable(dev, 0); + vpe_runtime_put(pdev); + pm_runtime_disable(&pdev->dev); + v4l2_m2m_release(dev->m2m_dev); + v4l2_device_unregister(&dev->v4l2_dev); + + return; + } + + video_set_drvdata(vfd, dev); + dev_info(dev->v4l2_dev.dev, "Device registered as /dev/video%d\n", + vfd->num); +} + +static int vpe_probe(struct platform_device *pdev) +{ + struct vpe_dev *dev; + int ret, irq, func; + + ret = dma_coerce_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)); + if (ret) { + dev_err(&pdev->dev, + "32-bit consistent DMA enable failed\n"); + return ret; + } + + dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL); + if (!dev) + return -ENOMEM; + + spin_lock_init(&dev->lock); + + ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev); + if (ret) + return ret; + + atomic_set(&dev->num_instances, 0); + mutex_init(&dev->dev_mutex); + + dev->res = platform_get_resource_byname(pdev, IORESOURCE_MEM, + "vpe_top"); + if (!dev->res) { + dev_err(&pdev->dev, "missing 'vpe_top' resources data\n"); + return -ENODEV; + } + + /* + * HACK: we get resource info from device tree in the form of a list of + * VPE sub blocks, the driver currently uses only the base of vpe_top + * for register access, the driver should be changed later to access + * registers based on the sub block base addresses + */ + dev->base = devm_ioremap(&pdev->dev, dev->res->start, SZ_32K); + if (!dev->base) { + ret = -ENOMEM; + goto v4l2_dev_unreg; + } + + irq = platform_get_irq(pdev, 0); + ret = devm_request_irq(&pdev->dev, irq, vpe_irq, 0, VPE_MODULE_NAME, + dev); + if (ret) + goto v4l2_dev_unreg; + + platform_set_drvdata(pdev, dev); + + dev->m2m_dev = v4l2_m2m_init(&m2m_ops); + if (IS_ERR(dev->m2m_dev)) { + vpe_err(dev, "Failed to init mem2mem device\n"); + ret = PTR_ERR(dev->m2m_dev); + goto v4l2_dev_unreg; + } + + pm_runtime_enable(&pdev->dev); + + ret = vpe_runtime_get(pdev); + if (ret < 0) + goto rel_m2m; + + /* Perform clk enable followed by reset */ + vpe_set_clock_enable(dev, 1); + + vpe_top_reset(dev); + + func = read_field_reg(dev, VPE_PID, VPE_PID_FUNC_MASK, + VPE_PID_FUNC_SHIFT); + vpe_dbg(dev, "VPE PID function %x\n", func); + + vpe_top_vpdma_reset(dev); + + dev->sc = sc_create(pdev, "sc"); + if (IS_ERR(dev->sc)) { + ret = PTR_ERR(dev->sc); + goto runtime_put; + } + + dev->csc = csc_create(pdev, "csc"); + if (IS_ERR(dev->csc)) { + ret = PTR_ERR(dev->csc); + goto runtime_put; + } + + dev->vpdma = &dev->vpdma_data; + ret = vpdma_create(pdev, dev->vpdma, vpe_fw_cb); + if (ret) + goto runtime_put; + + return 0; + +runtime_put: + vpe_runtime_put(pdev); +rel_m2m: + pm_runtime_disable(&pdev->dev); + v4l2_m2m_release(dev->m2m_dev); +v4l2_dev_unreg: + v4l2_device_unregister(&dev->v4l2_dev); + + return ret; +} + +static int vpe_remove(struct platform_device *pdev) +{ + struct vpe_dev *dev = platform_get_drvdata(pdev); + + v4l2_info(&dev->v4l2_dev, "Removing " VPE_MODULE_NAME); + + v4l2_m2m_release(dev->m2m_dev); + video_unregister_device(&dev->vfd); + v4l2_device_unregister(&dev->v4l2_dev); + + vpe_set_clock_enable(dev, 0); + vpe_runtime_put(pdev); + pm_runtime_disable(&pdev->dev); + + return 0; +} + +#if defined(CONFIG_OF) +static const struct of_device_id vpe_of_match[] = { + { + .compatible = "ti,dra7-vpe", + }, + {}, +}; +MODULE_DEVICE_TABLE(of, vpe_of_match); +#endif + +static struct platform_driver vpe_pdrv = { + .probe = vpe_probe, + .remove = vpe_remove, + .driver = { + .name = VPE_MODULE_NAME, + .of_match_table = of_match_ptr(vpe_of_match), + }, +}; + +module_platform_driver(vpe_pdrv); + +MODULE_DESCRIPTION("TI VPE driver"); +MODULE_AUTHOR("Dale Farnsworth, "); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/platform/ti/vpe/vpe_regs.h b/drivers/media/platform/ti/vpe/vpe_regs.h new file mode 100644 index 000000000000..1a1ad5ae1228 --- /dev/null +++ b/drivers/media/platform/ti/vpe/vpe_regs.h @@ -0,0 +1,306 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2013 Texas Instruments Inc. + * + * David Griego, + * Dale Farnsworth, + * Archit Taneja, + */ + +#ifndef __TI_VPE_REGS_H +#define __TI_VPE_REGS_H + +/* VPE register offsets and field selectors */ + +/* VPE top level regs */ +#define VPE_PID 0x0000 +#define VPE_PID_MINOR_MASK 0x3f +#define VPE_PID_MINOR_SHIFT 0 +#define VPE_PID_CUSTOM_MASK 0x03 +#define VPE_PID_CUSTOM_SHIFT 6 +#define VPE_PID_MAJOR_MASK 0x07 +#define VPE_PID_MAJOR_SHIFT 8 +#define VPE_PID_RTL_MASK 0x1f +#define VPE_PID_RTL_SHIFT 11 +#define VPE_PID_FUNC_MASK 0xfff +#define VPE_PID_FUNC_SHIFT 16 +#define VPE_PID_SCHEME_MASK 0x03 +#define VPE_PID_SCHEME_SHIFT 30 + +#define VPE_SYSCONFIG 0x0010 +#define VPE_SYSCONFIG_IDLE_MASK 0x03 +#define VPE_SYSCONFIG_IDLE_SHIFT 2 +#define VPE_SYSCONFIG_STANDBY_MASK 0x03 +#define VPE_SYSCONFIG_STANDBY_SHIFT 4 +#define VPE_FORCE_IDLE_MODE 0 +#define VPE_NO_IDLE_MODE 1 +#define VPE_SMART_IDLE_MODE 2 +#define VPE_SMART_IDLE_WAKEUP_MODE 3 +#define VPE_FORCE_STANDBY_MODE 0 +#define VPE_NO_STANDBY_MODE 1 +#define VPE_SMART_STANDBY_MODE 2 +#define VPE_SMART_STANDBY_WAKEUP_MODE 3 + +#define VPE_INT0_STATUS0_RAW_SET 0x0020 +#define VPE_INT0_STATUS0_RAW VPE_INT0_STATUS0_RAW_SET +#define VPE_INT0_STATUS0_CLR 0x0028 +#define VPE_INT0_STATUS0 VPE_INT0_STATUS0_CLR +#define VPE_INT0_ENABLE0_SET 0x0030 +#define VPE_INT0_ENABLE0 VPE_INT0_ENABLE0_SET +#define VPE_INT0_ENABLE0_CLR 0x0038 +#define VPE_INT0_LIST0_COMPLETE BIT(0) +#define VPE_INT0_LIST0_NOTIFY BIT(1) +#define VPE_INT0_LIST1_COMPLETE BIT(2) +#define VPE_INT0_LIST1_NOTIFY BIT(3) +#define VPE_INT0_LIST2_COMPLETE BIT(4) +#define VPE_INT0_LIST2_NOTIFY BIT(5) +#define VPE_INT0_LIST3_COMPLETE BIT(6) +#define VPE_INT0_LIST3_NOTIFY BIT(7) +#define VPE_INT0_LIST4_COMPLETE BIT(8) +#define VPE_INT0_LIST4_NOTIFY BIT(9) +#define VPE_INT0_LIST5_COMPLETE BIT(10) +#define VPE_INT0_LIST5_NOTIFY BIT(11) +#define VPE_INT0_LIST6_COMPLETE BIT(12) +#define VPE_INT0_LIST6_NOTIFY BIT(13) +#define VPE_INT0_LIST7_COMPLETE BIT(14) +#define VPE_INT0_LIST7_NOTIFY BIT(15) +#define VPE_INT0_DESCRIPTOR BIT(16) +#define VPE_DEI_FMD_INT BIT(18) + +#define VPE_INT0_STATUS1_RAW_SET 0x0024 +#define VPE_INT0_STATUS1_RAW VPE_INT0_STATUS1_RAW_SET +#define VPE_INT0_STATUS1_CLR 0x002c +#define VPE_INT0_STATUS1 VPE_INT0_STATUS1_CLR +#define VPE_INT0_ENABLE1_SET 0x0034 +#define VPE_INT0_ENABLE1 VPE_INT0_ENABLE1_SET +#define VPE_INT0_ENABLE1_CLR 0x003c +#define VPE_INT0_CHANNEL_GROUP0 BIT(0) +#define VPE_INT0_CHANNEL_GROUP1 BIT(1) +#define VPE_INT0_CHANNEL_GROUP2 BIT(2) +#define VPE_INT0_CHANNEL_GROUP3 BIT(3) +#define VPE_INT0_CHANNEL_GROUP4 BIT(4) +#define VPE_INT0_CHANNEL_GROUP5 BIT(5) +#define VPE_INT0_CLIENT BIT(7) +#define VPE_DEI_ERROR_INT BIT(16) +#define VPE_DS1_UV_ERROR_INT BIT(22) + +#define VPE_INTC_EOI 0x00a0 + +#define VPE_CLK_ENABLE 0x0100 +#define VPE_VPEDMA_CLK_ENABLE BIT(0) +#define VPE_DATA_PATH_CLK_ENABLE BIT(1) + +#define VPE_CLK_RESET 0x0104 +#define VPE_VPDMA_CLK_RESET_MASK 0x1 +#define VPE_VPDMA_CLK_RESET_SHIFT 0 +#define VPE_DATA_PATH_CLK_RESET_MASK 0x1 +#define VPE_DATA_PATH_CLK_RESET_SHIFT 1 +#define VPE_MAIN_RESET_MASK 0x1 +#define VPE_MAIN_RESET_SHIFT 31 + +#define VPE_CLK_FORMAT_SELECT 0x010c +#define VPE_CSC_SRC_SELECT_MASK 0x03 +#define VPE_CSC_SRC_SELECT_SHIFT 0 +#define VPE_RGB_OUT_SELECT BIT(8) +#define VPE_DS_SRC_SELECT_MASK 0x07 +#define VPE_DS_SRC_SELECT_SHIFT 9 +#define VPE_DS_BYPASS BIT(16) +#define VPE_COLOR_SEPARATE_422 BIT(18) + +#define VPE_DS_SRC_DEI_SCALER (5 << VPE_DS_SRC_SELECT_SHIFT) +#define VPE_CSC_SRC_DEI_SCALER (3 << VPE_CSC_SRC_SELECT_SHIFT) + +#define VPE_CLK_RANGE_MAP 0x011c +#define VPE_RANGE_RANGE_MAP_Y_MASK 0x07 +#define VPE_RANGE_RANGE_MAP_Y_SHIFT 0 +#define VPE_RANGE_RANGE_MAP_UV_MASK 0x07 +#define VPE_RANGE_RANGE_MAP_UV_SHIFT 3 +#define VPE_RANGE_MAP_ON BIT(6) +#define VPE_RANGE_REDUCTION_ON BIT(28) + +/* VPE chrominance upsampler regs */ +#define VPE_US1_R0 0x0304 +#define VPE_US2_R0 0x0404 +#define VPE_US3_R0 0x0504 +#define VPE_US_C1_MASK 0x3fff +#define VPE_US_C1_SHIFT 2 +#define VPE_US_C0_MASK 0x3fff +#define VPE_US_C0_SHIFT 18 +#define VPE_US_MODE_MASK 0x03 +#define VPE_US_MODE_SHIFT 16 +#define VPE_ANCHOR_FID0_C1_MASK 0x3fff +#define VPE_ANCHOR_FID0_C1_SHIFT 2 +#define VPE_ANCHOR_FID0_C0_MASK 0x3fff +#define VPE_ANCHOR_FID0_C0_SHIFT 18 + +#define VPE_US1_R1 0x0308 +#define VPE_US2_R1 0x0408 +#define VPE_US3_R1 0x0508 +#define VPE_ANCHOR_FID0_C3_MASK 0x3fff +#define VPE_ANCHOR_FID0_C3_SHIFT 2 +#define VPE_ANCHOR_FID0_C2_MASK 0x3fff +#define VPE_ANCHOR_FID0_C2_SHIFT 18 + +#define VPE_US1_R2 0x030c +#define VPE_US2_R2 0x040c +#define VPE_US3_R2 0x050c +#define VPE_INTERP_FID0_C1_MASK 0x3fff +#define VPE_INTERP_FID0_C1_SHIFT 2 +#define VPE_INTERP_FID0_C0_MASK 0x3fff +#define VPE_INTERP_FID0_C0_SHIFT 18 + +#define VPE_US1_R3 0x0310 +#define VPE_US2_R3 0x0410 +#define VPE_US3_R3 0x0510 +#define VPE_INTERP_FID0_C3_MASK 0x3fff +#define VPE_INTERP_FID0_C3_SHIFT 2 +#define VPE_INTERP_FID0_C2_MASK 0x3fff +#define VPE_INTERP_FID0_C2_SHIFT 18 + +#define VPE_US1_R4 0x0314 +#define VPE_US2_R4 0x0414 +#define VPE_US3_R4 0x0514 +#define VPE_ANCHOR_FID1_C1_MASK 0x3fff +#define VPE_ANCHOR_FID1_C1_SHIFT 2 +#define VPE_ANCHOR_FID1_C0_MASK 0x3fff +#define VPE_ANCHOR_FID1_C0_SHIFT 18 + +#define VPE_US1_R5 0x0318 +#define VPE_US2_R5 0x0418 +#define VPE_US3_R5 0x0518 +#define VPE_ANCHOR_FID1_C3_MASK 0x3fff +#define VPE_ANCHOR_FID1_C3_SHIFT 2 +#define VPE_ANCHOR_FID1_C2_MASK 0x3fff +#define VPE_ANCHOR_FID1_C2_SHIFT 18 + +#define VPE_US1_R6 0x031c +#define VPE_US2_R6 0x041c +#define VPE_US3_R6 0x051c +#define VPE_INTERP_FID1_C1_MASK 0x3fff +#define VPE_INTERP_FID1_C1_SHIFT 2 +#define VPE_INTERP_FID1_C0_MASK 0x3fff +#define VPE_INTERP_FID1_C0_SHIFT 18 + +#define VPE_US1_R7 0x0320 +#define VPE_US2_R7 0x0420 +#define VPE_US3_R7 0x0520 +#define VPE_INTERP_FID0_C3_MASK 0x3fff +#define VPE_INTERP_FID0_C3_SHIFT 2 +#define VPE_INTERP_FID0_C2_MASK 0x3fff +#define VPE_INTERP_FID0_C2_SHIFT 18 + +/* VPE de-interlacer regs */ +#define VPE_DEI_FRAME_SIZE 0x0600 +#define VPE_DEI_WIDTH_MASK 0x07ff +#define VPE_DEI_WIDTH_SHIFT 0 +#define VPE_DEI_HEIGHT_MASK 0x07ff +#define VPE_DEI_HEIGHT_SHIFT 16 +#define VPE_DEI_INTERLACE_BYPASS BIT(29) +#define VPE_DEI_FIELD_FLUSH BIT(30) +#define VPE_DEI_PROGRESSIVE BIT(31) + +#define VPE_MDT_BYPASS 0x0604 +#define VPE_MDT_TEMPMAX_BYPASS BIT(0) +#define VPE_MDT_SPATMAX_BYPASS BIT(1) + +#define VPE_MDT_SF_THRESHOLD 0x0608 +#define VPE_MDT_SF_SC_THR1_MASK 0xff +#define VPE_MDT_SF_SC_THR1_SHIFT 0 +#define VPE_MDT_SF_SC_THR2_MASK 0xff +#define VPE_MDT_SF_SC_THR2_SHIFT 0 +#define VPE_MDT_SF_SC_THR3_MASK 0xff +#define VPE_MDT_SF_SC_THR3_SHIFT 0 + +#define VPE_EDI_CONFIG 0x060c +#define VPE_EDI_INP_MODE_MASK 0x03 +#define VPE_EDI_INP_MODE_SHIFT 0 +#define VPE_EDI_ENABLE_3D BIT(2) +#define VPE_EDI_ENABLE_CHROMA_3D BIT(3) +#define VPE_EDI_CHROMA3D_COR_THR_MASK 0xff +#define VPE_EDI_CHROMA3D_COR_THR_SHIFT 8 +#define VPE_EDI_DIR_COR_LOWER_THR_MASK 0xff +#define VPE_EDI_DIR_COR_LOWER_THR_SHIFT 16 +#define VPE_EDI_COR_SCALE_FACTOR_MASK 0xff +#define VPE_EDI_COR_SCALE_FACTOR_SHIFT 23 + +#define VPE_DEI_EDI_LUT_R0 0x0610 +#define VPE_EDI_LUT0_MASK 0x1f +#define VPE_EDI_LUT0_SHIFT 0 +#define VPE_EDI_LUT1_MASK 0x1f +#define VPE_EDI_LUT1_SHIFT 8 +#define VPE_EDI_LUT2_MASK 0x1f +#define VPE_EDI_LUT2_SHIFT 16 +#define VPE_EDI_LUT3_MASK 0x1f +#define VPE_EDI_LUT3_SHIFT 24 + +#define VPE_DEI_EDI_LUT_R1 0x0614 +#define VPE_EDI_LUT0_MASK 0x1f +#define VPE_EDI_LUT0_SHIFT 0 +#define VPE_EDI_LUT1_MASK 0x1f +#define VPE_EDI_LUT1_SHIFT 8 +#define VPE_EDI_LUT2_MASK 0x1f +#define VPE_EDI_LUT2_SHIFT 16 +#define VPE_EDI_LUT3_MASK 0x1f +#define VPE_EDI_LUT3_SHIFT 24 + +#define VPE_DEI_EDI_LUT_R2 0x0618 +#define VPE_EDI_LUT4_MASK 0x1f +#define VPE_EDI_LUT4_SHIFT 0 +#define VPE_EDI_LUT5_MASK 0x1f +#define VPE_EDI_LUT5_SHIFT 8 +#define VPE_EDI_LUT6_MASK 0x1f +#define VPE_EDI_LUT6_SHIFT 16 +#define VPE_EDI_LUT7_MASK 0x1f +#define VPE_EDI_LUT7_SHIFT 24 + +#define VPE_DEI_EDI_LUT_R3 0x061c +#define VPE_EDI_LUT8_MASK 0x1f +#define VPE_EDI_LUT8_SHIFT 0 +#define VPE_EDI_LUT9_MASK 0x1f +#define VPE_EDI_LUT9_SHIFT 8 +#define VPE_EDI_LUT10_MASK 0x1f +#define VPE_EDI_LUT10_SHIFT 16 +#define VPE_EDI_LUT11_MASK 0x1f +#define VPE_EDI_LUT11_SHIFT 24 + +#define VPE_DEI_FMD_WINDOW_R0 0x0620 +#define VPE_FMD_WINDOW_MINX_MASK 0x07ff +#define VPE_FMD_WINDOW_MINX_SHIFT 0 +#define VPE_FMD_WINDOW_MAXX_MASK 0x07ff +#define VPE_FMD_WINDOW_MAXX_SHIFT 16 +#define VPE_FMD_WINDOW_ENABLE BIT(31) + +#define VPE_DEI_FMD_WINDOW_R1 0x0624 +#define VPE_FMD_WINDOW_MINY_MASK 0x07ff +#define VPE_FMD_WINDOW_MINY_SHIFT 0 +#define VPE_FMD_WINDOW_MAXY_MASK 0x07ff +#define VPE_FMD_WINDOW_MAXY_SHIFT 16 + +#define VPE_DEI_FMD_CONTROL_R0 0x0628 +#define VPE_FMD_ENABLE BIT(0) +#define VPE_FMD_LOCK BIT(1) +#define VPE_FMD_JAM_DIR BIT(2) +#define VPE_FMD_BED_ENABLE BIT(3) +#define VPE_FMD_CAF_FIELD_THR_MASK 0xff +#define VPE_FMD_CAF_FIELD_THR_SHIFT 16 +#define VPE_FMD_CAF_LINE_THR_MASK 0xff +#define VPE_FMD_CAF_LINE_THR_SHIFT 24 + +#define VPE_DEI_FMD_CONTROL_R1 0x062c +#define VPE_FMD_CAF_THR_MASK 0x000fffff +#define VPE_FMD_CAF_THR_SHIFT 0 + +#define VPE_DEI_FMD_STATUS_R0 0x0630 +#define VPE_FMD_CAF_MASK 0x000fffff +#define VPE_FMD_CAF_SHIFT 0 +#define VPE_FMD_RESET BIT(24) + +#define VPE_DEI_FMD_STATUS_R1 0x0634 +#define VPE_FMD_FIELD_DIFF_MASK 0x0fffffff +#define VPE_FMD_FIELD_DIFF_SHIFT 0 + +#define VPE_DEI_FMD_STATUS_R2 0x0638 +#define VPE_FMD_FRAME_DIFF_MASK 0x000fffff +#define VPE_FMD_FRAME_DIFF_SHIFT 0 + +#endif -- cgit v1.2.3