162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Register interface file for Samsung Camera Interface (FIMC) driver 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2010 - 2013 Samsung Electronics Co., Ltd. 662306a36Sopenharmony_ci * Sylwester Nawrocki <s.nawrocki@samsung.com> 762306a36Sopenharmony_ci*/ 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci#include <linux/delay.h> 1062306a36Sopenharmony_ci#include <linux/io.h> 1162306a36Sopenharmony_ci#include <linux/regmap.h> 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_ci#include <media/drv-intf/exynos-fimc.h> 1462306a36Sopenharmony_ci#include "media-dev.h" 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_ci#include "fimc-reg.h" 1762306a36Sopenharmony_ci#include "fimc-core.h" 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_civoid fimc_hw_reset(struct fimc_dev *dev) 2062306a36Sopenharmony_ci{ 2162306a36Sopenharmony_ci u32 cfg; 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_ci cfg = readl(dev->regs + FIMC_REG_CISRCFMT); 2462306a36Sopenharmony_ci cfg |= FIMC_REG_CISRCFMT_ITU601_8BIT; 2562306a36Sopenharmony_ci writel(cfg, dev->regs + FIMC_REG_CISRCFMT); 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ci /* Software reset. */ 2862306a36Sopenharmony_ci cfg = readl(dev->regs + FIMC_REG_CIGCTRL); 2962306a36Sopenharmony_ci cfg |= (FIMC_REG_CIGCTRL_SWRST | FIMC_REG_CIGCTRL_IRQ_LEVEL); 3062306a36Sopenharmony_ci writel(cfg, dev->regs + FIMC_REG_CIGCTRL); 3162306a36Sopenharmony_ci udelay(10); 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_ci cfg = readl(dev->regs + FIMC_REG_CIGCTRL); 3462306a36Sopenharmony_ci cfg &= ~FIMC_REG_CIGCTRL_SWRST; 3562306a36Sopenharmony_ci writel(cfg, dev->regs + FIMC_REG_CIGCTRL); 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_ci if (dev->drv_data->out_buf_count > 4) 3862306a36Sopenharmony_ci fimc_hw_set_dma_seq(dev, 0xF); 3962306a36Sopenharmony_ci} 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_cistatic u32 fimc_hw_get_in_flip(struct fimc_ctx *ctx) 4262306a36Sopenharmony_ci{ 4362306a36Sopenharmony_ci u32 flip = FIMC_REG_MSCTRL_FLIP_NORMAL; 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_ci if (ctx->hflip) 4662306a36Sopenharmony_ci flip = FIMC_REG_MSCTRL_FLIP_Y_MIRROR; 4762306a36Sopenharmony_ci if (ctx->vflip) 4862306a36Sopenharmony_ci flip = FIMC_REG_MSCTRL_FLIP_X_MIRROR; 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_ci if (ctx->rotation <= 90) 5162306a36Sopenharmony_ci return flip; 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_ci return (flip ^ FIMC_REG_MSCTRL_FLIP_180) & FIMC_REG_MSCTRL_FLIP_180; 5462306a36Sopenharmony_ci} 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_cistatic u32 fimc_hw_get_target_flip(struct fimc_ctx *ctx) 5762306a36Sopenharmony_ci{ 5862306a36Sopenharmony_ci u32 flip = FIMC_REG_CITRGFMT_FLIP_NORMAL; 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_ci if (ctx->hflip) 6162306a36Sopenharmony_ci flip |= FIMC_REG_CITRGFMT_FLIP_Y_MIRROR; 6262306a36Sopenharmony_ci if (ctx->vflip) 6362306a36Sopenharmony_ci flip |= FIMC_REG_CITRGFMT_FLIP_X_MIRROR; 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ci if (ctx->rotation <= 90) 6662306a36Sopenharmony_ci return flip; 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_ci return (flip ^ FIMC_REG_CITRGFMT_FLIP_180) & FIMC_REG_CITRGFMT_FLIP_180; 6962306a36Sopenharmony_ci} 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_civoid fimc_hw_set_rotation(struct fimc_ctx *ctx) 7262306a36Sopenharmony_ci{ 7362306a36Sopenharmony_ci u32 cfg, flip; 7462306a36Sopenharmony_ci struct fimc_dev *dev = ctx->fimc_dev; 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ci cfg = readl(dev->regs + FIMC_REG_CITRGFMT); 7762306a36Sopenharmony_ci cfg &= ~(FIMC_REG_CITRGFMT_INROT90 | FIMC_REG_CITRGFMT_OUTROT90 | 7862306a36Sopenharmony_ci FIMC_REG_CITRGFMT_FLIP_180); 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_ci /* 8162306a36Sopenharmony_ci * The input and output rotator cannot work simultaneously. 8262306a36Sopenharmony_ci * Use the output rotator in output DMA mode or the input rotator 8362306a36Sopenharmony_ci * in direct fifo output mode. 8462306a36Sopenharmony_ci */ 8562306a36Sopenharmony_ci if (ctx->rotation == 90 || ctx->rotation == 270) { 8662306a36Sopenharmony_ci if (ctx->out_path == FIMC_IO_LCDFIFO) 8762306a36Sopenharmony_ci cfg |= FIMC_REG_CITRGFMT_INROT90; 8862306a36Sopenharmony_ci else 8962306a36Sopenharmony_ci cfg |= FIMC_REG_CITRGFMT_OUTROT90; 9062306a36Sopenharmony_ci } 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci if (ctx->out_path == FIMC_IO_DMA) { 9362306a36Sopenharmony_ci cfg |= fimc_hw_get_target_flip(ctx); 9462306a36Sopenharmony_ci writel(cfg, dev->regs + FIMC_REG_CITRGFMT); 9562306a36Sopenharmony_ci } else { 9662306a36Sopenharmony_ci /* LCD FIFO path */ 9762306a36Sopenharmony_ci flip = readl(dev->regs + FIMC_REG_MSCTRL); 9862306a36Sopenharmony_ci flip &= ~FIMC_REG_MSCTRL_FLIP_MASK; 9962306a36Sopenharmony_ci flip |= fimc_hw_get_in_flip(ctx); 10062306a36Sopenharmony_ci writel(flip, dev->regs + FIMC_REG_MSCTRL); 10162306a36Sopenharmony_ci } 10262306a36Sopenharmony_ci} 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_civoid fimc_hw_set_target_format(struct fimc_ctx *ctx) 10562306a36Sopenharmony_ci{ 10662306a36Sopenharmony_ci u32 cfg; 10762306a36Sopenharmony_ci struct fimc_dev *dev = ctx->fimc_dev; 10862306a36Sopenharmony_ci struct fimc_frame *frame = &ctx->d_frame; 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_ci dbg("w= %d, h= %d color: %d", frame->width, 11162306a36Sopenharmony_ci frame->height, frame->fmt->color); 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ci cfg = readl(dev->regs + FIMC_REG_CITRGFMT); 11462306a36Sopenharmony_ci cfg &= ~(FIMC_REG_CITRGFMT_FMT_MASK | FIMC_REG_CITRGFMT_HSIZE_MASK | 11562306a36Sopenharmony_ci FIMC_REG_CITRGFMT_VSIZE_MASK); 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_ci switch (frame->fmt->color) { 11862306a36Sopenharmony_ci case FIMC_FMT_RGB444...FIMC_FMT_RGB888: 11962306a36Sopenharmony_ci cfg |= FIMC_REG_CITRGFMT_RGB; 12062306a36Sopenharmony_ci break; 12162306a36Sopenharmony_ci case FIMC_FMT_YCBCR420: 12262306a36Sopenharmony_ci cfg |= FIMC_REG_CITRGFMT_YCBCR420; 12362306a36Sopenharmony_ci break; 12462306a36Sopenharmony_ci case FIMC_FMT_YCBYCR422...FIMC_FMT_CRYCBY422: 12562306a36Sopenharmony_ci if (frame->fmt->colplanes == 1) 12662306a36Sopenharmony_ci cfg |= FIMC_REG_CITRGFMT_YCBCR422_1P; 12762306a36Sopenharmony_ci else 12862306a36Sopenharmony_ci cfg |= FIMC_REG_CITRGFMT_YCBCR422; 12962306a36Sopenharmony_ci break; 13062306a36Sopenharmony_ci default: 13162306a36Sopenharmony_ci break; 13262306a36Sopenharmony_ci } 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_ci if (ctx->rotation == 90 || ctx->rotation == 270) 13562306a36Sopenharmony_ci cfg |= (frame->height << 16) | frame->width; 13662306a36Sopenharmony_ci else 13762306a36Sopenharmony_ci cfg |= (frame->width << 16) | frame->height; 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_ci writel(cfg, dev->regs + FIMC_REG_CITRGFMT); 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_ci cfg = readl(dev->regs + FIMC_REG_CITAREA); 14262306a36Sopenharmony_ci cfg &= ~FIMC_REG_CITAREA_MASK; 14362306a36Sopenharmony_ci cfg |= (frame->width * frame->height); 14462306a36Sopenharmony_ci writel(cfg, dev->regs + FIMC_REG_CITAREA); 14562306a36Sopenharmony_ci} 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_cistatic void fimc_hw_set_out_dma_size(struct fimc_ctx *ctx) 14862306a36Sopenharmony_ci{ 14962306a36Sopenharmony_ci struct fimc_dev *dev = ctx->fimc_dev; 15062306a36Sopenharmony_ci struct fimc_frame *frame = &ctx->d_frame; 15162306a36Sopenharmony_ci u32 cfg; 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_ci cfg = (frame->f_height << 16) | frame->f_width; 15462306a36Sopenharmony_ci writel(cfg, dev->regs + FIMC_REG_ORGOSIZE); 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_ci /* Select color space conversion equation (HD/SD size).*/ 15762306a36Sopenharmony_ci cfg = readl(dev->regs + FIMC_REG_CIGCTRL); 15862306a36Sopenharmony_ci if (frame->f_width >= 1280) /* HD */ 15962306a36Sopenharmony_ci cfg |= FIMC_REG_CIGCTRL_CSC_ITU601_709; 16062306a36Sopenharmony_ci else /* SD */ 16162306a36Sopenharmony_ci cfg &= ~FIMC_REG_CIGCTRL_CSC_ITU601_709; 16262306a36Sopenharmony_ci writel(cfg, dev->regs + FIMC_REG_CIGCTRL); 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_ci} 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_civoid fimc_hw_set_out_dma(struct fimc_ctx *ctx) 16762306a36Sopenharmony_ci{ 16862306a36Sopenharmony_ci struct fimc_dev *dev = ctx->fimc_dev; 16962306a36Sopenharmony_ci struct fimc_frame *frame = &ctx->d_frame; 17062306a36Sopenharmony_ci struct fimc_dma_offset *offset = &frame->dma_offset; 17162306a36Sopenharmony_ci struct fimc_fmt *fmt = frame->fmt; 17262306a36Sopenharmony_ci u32 cfg; 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_ci /* Set the input dma offsets. */ 17562306a36Sopenharmony_ci cfg = (offset->y_v << 16) | offset->y_h; 17662306a36Sopenharmony_ci writel(cfg, dev->regs + FIMC_REG_CIOYOFF); 17762306a36Sopenharmony_ci 17862306a36Sopenharmony_ci cfg = (offset->cb_v << 16) | offset->cb_h; 17962306a36Sopenharmony_ci writel(cfg, dev->regs + FIMC_REG_CIOCBOFF); 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_ci cfg = (offset->cr_v << 16) | offset->cr_h; 18262306a36Sopenharmony_ci writel(cfg, dev->regs + FIMC_REG_CIOCROFF); 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_ci fimc_hw_set_out_dma_size(ctx); 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_ci /* Configure chroma components order. */ 18762306a36Sopenharmony_ci cfg = readl(dev->regs + FIMC_REG_CIOCTRL); 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_ci cfg &= ~(FIMC_REG_CIOCTRL_ORDER2P_MASK | 19062306a36Sopenharmony_ci FIMC_REG_CIOCTRL_ORDER422_MASK | 19162306a36Sopenharmony_ci FIMC_REG_CIOCTRL_YCBCR_PLANE_MASK | 19262306a36Sopenharmony_ci FIMC_REG_CIOCTRL_RGB16FMT_MASK); 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_ci if (fmt->colplanes == 1) 19562306a36Sopenharmony_ci cfg |= ctx->out_order_1p; 19662306a36Sopenharmony_ci else if (fmt->colplanes == 2) 19762306a36Sopenharmony_ci cfg |= ctx->out_order_2p | FIMC_REG_CIOCTRL_YCBCR_2PLANE; 19862306a36Sopenharmony_ci else if (fmt->colplanes == 3) 19962306a36Sopenharmony_ci cfg |= FIMC_REG_CIOCTRL_YCBCR_3PLANE; 20062306a36Sopenharmony_ci 20162306a36Sopenharmony_ci if (fmt->color == FIMC_FMT_RGB565) 20262306a36Sopenharmony_ci cfg |= FIMC_REG_CIOCTRL_RGB565; 20362306a36Sopenharmony_ci else if (fmt->color == FIMC_FMT_RGB555) 20462306a36Sopenharmony_ci cfg |= FIMC_REG_CIOCTRL_ARGB1555; 20562306a36Sopenharmony_ci else if (fmt->color == FIMC_FMT_RGB444) 20662306a36Sopenharmony_ci cfg |= FIMC_REG_CIOCTRL_ARGB4444; 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_ci writel(cfg, dev->regs + FIMC_REG_CIOCTRL); 20962306a36Sopenharmony_ci} 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_cistatic void fimc_hw_en_autoload(struct fimc_dev *dev, int enable) 21262306a36Sopenharmony_ci{ 21362306a36Sopenharmony_ci u32 cfg = readl(dev->regs + FIMC_REG_ORGISIZE); 21462306a36Sopenharmony_ci if (enable) 21562306a36Sopenharmony_ci cfg |= FIMC_REG_CIREAL_ISIZE_AUTOLOAD_EN; 21662306a36Sopenharmony_ci else 21762306a36Sopenharmony_ci cfg &= ~FIMC_REG_CIREAL_ISIZE_AUTOLOAD_EN; 21862306a36Sopenharmony_ci writel(cfg, dev->regs + FIMC_REG_ORGISIZE); 21962306a36Sopenharmony_ci} 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_civoid fimc_hw_en_lastirq(struct fimc_dev *dev, int enable) 22262306a36Sopenharmony_ci{ 22362306a36Sopenharmony_ci u32 cfg = readl(dev->regs + FIMC_REG_CIOCTRL); 22462306a36Sopenharmony_ci if (enable) 22562306a36Sopenharmony_ci cfg |= FIMC_REG_CIOCTRL_LASTIRQ_ENABLE; 22662306a36Sopenharmony_ci else 22762306a36Sopenharmony_ci cfg &= ~FIMC_REG_CIOCTRL_LASTIRQ_ENABLE; 22862306a36Sopenharmony_ci writel(cfg, dev->regs + FIMC_REG_CIOCTRL); 22962306a36Sopenharmony_ci} 23062306a36Sopenharmony_ci 23162306a36Sopenharmony_civoid fimc_hw_set_prescaler(struct fimc_ctx *ctx) 23262306a36Sopenharmony_ci{ 23362306a36Sopenharmony_ci struct fimc_dev *dev = ctx->fimc_dev; 23462306a36Sopenharmony_ci struct fimc_scaler *sc = &ctx->scaler; 23562306a36Sopenharmony_ci u32 cfg, shfactor; 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_ci shfactor = 10 - (sc->hfactor + sc->vfactor); 23862306a36Sopenharmony_ci cfg = shfactor << 28; 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_ci cfg |= (sc->pre_hratio << 16) | sc->pre_vratio; 24162306a36Sopenharmony_ci writel(cfg, dev->regs + FIMC_REG_CISCPRERATIO); 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_ci cfg = (sc->pre_dst_width << 16) | sc->pre_dst_height; 24462306a36Sopenharmony_ci writel(cfg, dev->regs + FIMC_REG_CISCPREDST); 24562306a36Sopenharmony_ci} 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_cistatic void fimc_hw_set_scaler(struct fimc_ctx *ctx) 24862306a36Sopenharmony_ci{ 24962306a36Sopenharmony_ci struct fimc_dev *dev = ctx->fimc_dev; 25062306a36Sopenharmony_ci struct fimc_scaler *sc = &ctx->scaler; 25162306a36Sopenharmony_ci struct fimc_frame *src_frame = &ctx->s_frame; 25262306a36Sopenharmony_ci struct fimc_frame *dst_frame = &ctx->d_frame; 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_ci u32 cfg = readl(dev->regs + FIMC_REG_CISCCTRL); 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_ci cfg &= ~(FIMC_REG_CISCCTRL_CSCR2Y_WIDE | FIMC_REG_CISCCTRL_CSCY2R_WIDE | 25762306a36Sopenharmony_ci FIMC_REG_CISCCTRL_SCALEUP_H | FIMC_REG_CISCCTRL_SCALEUP_V | 25862306a36Sopenharmony_ci FIMC_REG_CISCCTRL_SCALERBYPASS | FIMC_REG_CISCCTRL_ONE2ONE | 25962306a36Sopenharmony_ci FIMC_REG_CISCCTRL_INRGB_FMT_MASK | FIMC_REG_CISCCTRL_OUTRGB_FMT_MASK | 26062306a36Sopenharmony_ci FIMC_REG_CISCCTRL_INTERLACE | FIMC_REG_CISCCTRL_RGB_EXT); 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_ci if (!(ctx->flags & FIMC_COLOR_RANGE_NARROW)) 26362306a36Sopenharmony_ci cfg |= (FIMC_REG_CISCCTRL_CSCR2Y_WIDE | 26462306a36Sopenharmony_ci FIMC_REG_CISCCTRL_CSCY2R_WIDE); 26562306a36Sopenharmony_ci 26662306a36Sopenharmony_ci if (!sc->enabled) 26762306a36Sopenharmony_ci cfg |= FIMC_REG_CISCCTRL_SCALERBYPASS; 26862306a36Sopenharmony_ci 26962306a36Sopenharmony_ci if (sc->scaleup_h) 27062306a36Sopenharmony_ci cfg |= FIMC_REG_CISCCTRL_SCALEUP_H; 27162306a36Sopenharmony_ci 27262306a36Sopenharmony_ci if (sc->scaleup_v) 27362306a36Sopenharmony_ci cfg |= FIMC_REG_CISCCTRL_SCALEUP_V; 27462306a36Sopenharmony_ci 27562306a36Sopenharmony_ci if (sc->copy_mode) 27662306a36Sopenharmony_ci cfg |= FIMC_REG_CISCCTRL_ONE2ONE; 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_ci if (ctx->in_path == FIMC_IO_DMA) { 27962306a36Sopenharmony_ci switch (src_frame->fmt->color) { 28062306a36Sopenharmony_ci case FIMC_FMT_RGB565: 28162306a36Sopenharmony_ci cfg |= FIMC_REG_CISCCTRL_INRGB_FMT_RGB565; 28262306a36Sopenharmony_ci break; 28362306a36Sopenharmony_ci case FIMC_FMT_RGB666: 28462306a36Sopenharmony_ci cfg |= FIMC_REG_CISCCTRL_INRGB_FMT_RGB666; 28562306a36Sopenharmony_ci break; 28662306a36Sopenharmony_ci case FIMC_FMT_RGB888: 28762306a36Sopenharmony_ci cfg |= FIMC_REG_CISCCTRL_INRGB_FMT_RGB888; 28862306a36Sopenharmony_ci break; 28962306a36Sopenharmony_ci } 29062306a36Sopenharmony_ci } 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_ci if (ctx->out_path == FIMC_IO_DMA) { 29362306a36Sopenharmony_ci u32 color = dst_frame->fmt->color; 29462306a36Sopenharmony_ci 29562306a36Sopenharmony_ci if (color >= FIMC_FMT_RGB444 && color <= FIMC_FMT_RGB565) 29662306a36Sopenharmony_ci cfg |= FIMC_REG_CISCCTRL_OUTRGB_FMT_RGB565; 29762306a36Sopenharmony_ci else if (color == FIMC_FMT_RGB666) 29862306a36Sopenharmony_ci cfg |= FIMC_REG_CISCCTRL_OUTRGB_FMT_RGB666; 29962306a36Sopenharmony_ci else if (color == FIMC_FMT_RGB888) 30062306a36Sopenharmony_ci cfg |= FIMC_REG_CISCCTRL_OUTRGB_FMT_RGB888; 30162306a36Sopenharmony_ci } else { 30262306a36Sopenharmony_ci cfg |= FIMC_REG_CISCCTRL_OUTRGB_FMT_RGB888; 30362306a36Sopenharmony_ci 30462306a36Sopenharmony_ci if (ctx->flags & FIMC_SCAN_MODE_INTERLACED) 30562306a36Sopenharmony_ci cfg |= FIMC_REG_CISCCTRL_INTERLACE; 30662306a36Sopenharmony_ci } 30762306a36Sopenharmony_ci 30862306a36Sopenharmony_ci writel(cfg, dev->regs + FIMC_REG_CISCCTRL); 30962306a36Sopenharmony_ci} 31062306a36Sopenharmony_ci 31162306a36Sopenharmony_civoid fimc_hw_set_mainscaler(struct fimc_ctx *ctx) 31262306a36Sopenharmony_ci{ 31362306a36Sopenharmony_ci struct fimc_dev *dev = ctx->fimc_dev; 31462306a36Sopenharmony_ci const struct fimc_variant *variant = dev->variant; 31562306a36Sopenharmony_ci struct fimc_scaler *sc = &ctx->scaler; 31662306a36Sopenharmony_ci u32 cfg; 31762306a36Sopenharmony_ci 31862306a36Sopenharmony_ci dbg("main_hratio= 0x%X main_vratio= 0x%X", 31962306a36Sopenharmony_ci sc->main_hratio, sc->main_vratio); 32062306a36Sopenharmony_ci 32162306a36Sopenharmony_ci fimc_hw_set_scaler(ctx); 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_ci cfg = readl(dev->regs + FIMC_REG_CISCCTRL); 32462306a36Sopenharmony_ci cfg &= ~(FIMC_REG_CISCCTRL_MHRATIO_MASK | 32562306a36Sopenharmony_ci FIMC_REG_CISCCTRL_MVRATIO_MASK); 32662306a36Sopenharmony_ci 32762306a36Sopenharmony_ci if (variant->has_mainscaler_ext) { 32862306a36Sopenharmony_ci cfg |= FIMC_REG_CISCCTRL_MHRATIO_EXT(sc->main_hratio); 32962306a36Sopenharmony_ci cfg |= FIMC_REG_CISCCTRL_MVRATIO_EXT(sc->main_vratio); 33062306a36Sopenharmony_ci writel(cfg, dev->regs + FIMC_REG_CISCCTRL); 33162306a36Sopenharmony_ci 33262306a36Sopenharmony_ci cfg = readl(dev->regs + FIMC_REG_CIEXTEN); 33362306a36Sopenharmony_ci 33462306a36Sopenharmony_ci cfg &= ~(FIMC_REG_CIEXTEN_MVRATIO_EXT_MASK | 33562306a36Sopenharmony_ci FIMC_REG_CIEXTEN_MHRATIO_EXT_MASK); 33662306a36Sopenharmony_ci cfg |= FIMC_REG_CIEXTEN_MHRATIO_EXT(sc->main_hratio); 33762306a36Sopenharmony_ci cfg |= FIMC_REG_CIEXTEN_MVRATIO_EXT(sc->main_vratio); 33862306a36Sopenharmony_ci writel(cfg, dev->regs + FIMC_REG_CIEXTEN); 33962306a36Sopenharmony_ci } else { 34062306a36Sopenharmony_ci cfg |= FIMC_REG_CISCCTRL_MHRATIO(sc->main_hratio); 34162306a36Sopenharmony_ci cfg |= FIMC_REG_CISCCTRL_MVRATIO(sc->main_vratio); 34262306a36Sopenharmony_ci writel(cfg, dev->regs + FIMC_REG_CISCCTRL); 34362306a36Sopenharmony_ci } 34462306a36Sopenharmony_ci} 34562306a36Sopenharmony_ci 34662306a36Sopenharmony_civoid fimc_hw_enable_capture(struct fimc_ctx *ctx) 34762306a36Sopenharmony_ci{ 34862306a36Sopenharmony_ci struct fimc_dev *dev = ctx->fimc_dev; 34962306a36Sopenharmony_ci u32 cfg; 35062306a36Sopenharmony_ci 35162306a36Sopenharmony_ci cfg = readl(dev->regs + FIMC_REG_CIIMGCPT); 35262306a36Sopenharmony_ci cfg |= FIMC_REG_CIIMGCPT_CPT_FREN_ENABLE; 35362306a36Sopenharmony_ci 35462306a36Sopenharmony_ci if (ctx->scaler.enabled) 35562306a36Sopenharmony_ci cfg |= FIMC_REG_CIIMGCPT_IMGCPTEN_SC; 35662306a36Sopenharmony_ci else 35762306a36Sopenharmony_ci cfg &= FIMC_REG_CIIMGCPT_IMGCPTEN_SC; 35862306a36Sopenharmony_ci 35962306a36Sopenharmony_ci cfg |= FIMC_REG_CIIMGCPT_IMGCPTEN; 36062306a36Sopenharmony_ci writel(cfg, dev->regs + FIMC_REG_CIIMGCPT); 36162306a36Sopenharmony_ci} 36262306a36Sopenharmony_ci 36362306a36Sopenharmony_civoid fimc_hw_disable_capture(struct fimc_dev *dev) 36462306a36Sopenharmony_ci{ 36562306a36Sopenharmony_ci u32 cfg = readl(dev->regs + FIMC_REG_CIIMGCPT); 36662306a36Sopenharmony_ci cfg &= ~(FIMC_REG_CIIMGCPT_IMGCPTEN | 36762306a36Sopenharmony_ci FIMC_REG_CIIMGCPT_IMGCPTEN_SC); 36862306a36Sopenharmony_ci writel(cfg, dev->regs + FIMC_REG_CIIMGCPT); 36962306a36Sopenharmony_ci} 37062306a36Sopenharmony_ci 37162306a36Sopenharmony_civoid fimc_hw_set_effect(struct fimc_ctx *ctx) 37262306a36Sopenharmony_ci{ 37362306a36Sopenharmony_ci struct fimc_dev *dev = ctx->fimc_dev; 37462306a36Sopenharmony_ci struct fimc_effect *effect = &ctx->effect; 37562306a36Sopenharmony_ci u32 cfg = 0; 37662306a36Sopenharmony_ci 37762306a36Sopenharmony_ci if (effect->type != FIMC_REG_CIIMGEFF_FIN_BYPASS) { 37862306a36Sopenharmony_ci cfg |= FIMC_REG_CIIMGEFF_IE_SC_AFTER | 37962306a36Sopenharmony_ci FIMC_REG_CIIMGEFF_IE_ENABLE; 38062306a36Sopenharmony_ci cfg |= effect->type; 38162306a36Sopenharmony_ci if (effect->type == FIMC_REG_CIIMGEFF_FIN_ARBITRARY) 38262306a36Sopenharmony_ci cfg |= (effect->pat_cb << 13) | effect->pat_cr; 38362306a36Sopenharmony_ci } 38462306a36Sopenharmony_ci 38562306a36Sopenharmony_ci writel(cfg, dev->regs + FIMC_REG_CIIMGEFF); 38662306a36Sopenharmony_ci} 38762306a36Sopenharmony_ci 38862306a36Sopenharmony_civoid fimc_hw_set_rgb_alpha(struct fimc_ctx *ctx) 38962306a36Sopenharmony_ci{ 39062306a36Sopenharmony_ci struct fimc_dev *dev = ctx->fimc_dev; 39162306a36Sopenharmony_ci struct fimc_frame *frame = &ctx->d_frame; 39262306a36Sopenharmony_ci u32 cfg; 39362306a36Sopenharmony_ci 39462306a36Sopenharmony_ci if (!(frame->fmt->flags & FMT_HAS_ALPHA)) 39562306a36Sopenharmony_ci return; 39662306a36Sopenharmony_ci 39762306a36Sopenharmony_ci cfg = readl(dev->regs + FIMC_REG_CIOCTRL); 39862306a36Sopenharmony_ci cfg &= ~FIMC_REG_CIOCTRL_ALPHA_OUT_MASK; 39962306a36Sopenharmony_ci cfg |= (frame->alpha << 4); 40062306a36Sopenharmony_ci writel(cfg, dev->regs + FIMC_REG_CIOCTRL); 40162306a36Sopenharmony_ci} 40262306a36Sopenharmony_ci 40362306a36Sopenharmony_cistatic void fimc_hw_set_in_dma_size(struct fimc_ctx *ctx) 40462306a36Sopenharmony_ci{ 40562306a36Sopenharmony_ci struct fimc_dev *dev = ctx->fimc_dev; 40662306a36Sopenharmony_ci struct fimc_frame *frame = &ctx->s_frame; 40762306a36Sopenharmony_ci u32 cfg_o = 0; 40862306a36Sopenharmony_ci u32 cfg_r = 0; 40962306a36Sopenharmony_ci 41062306a36Sopenharmony_ci if (FIMC_IO_LCDFIFO == ctx->out_path) 41162306a36Sopenharmony_ci cfg_r |= FIMC_REG_CIREAL_ISIZE_AUTOLOAD_EN; 41262306a36Sopenharmony_ci 41362306a36Sopenharmony_ci cfg_o |= (frame->f_height << 16) | frame->f_width; 41462306a36Sopenharmony_ci cfg_r |= (frame->height << 16) | frame->width; 41562306a36Sopenharmony_ci 41662306a36Sopenharmony_ci writel(cfg_o, dev->regs + FIMC_REG_ORGISIZE); 41762306a36Sopenharmony_ci writel(cfg_r, dev->regs + FIMC_REG_CIREAL_ISIZE); 41862306a36Sopenharmony_ci} 41962306a36Sopenharmony_ci 42062306a36Sopenharmony_civoid fimc_hw_set_in_dma(struct fimc_ctx *ctx) 42162306a36Sopenharmony_ci{ 42262306a36Sopenharmony_ci struct fimc_dev *dev = ctx->fimc_dev; 42362306a36Sopenharmony_ci struct fimc_frame *frame = &ctx->s_frame; 42462306a36Sopenharmony_ci struct fimc_dma_offset *offset = &frame->dma_offset; 42562306a36Sopenharmony_ci u32 cfg; 42662306a36Sopenharmony_ci 42762306a36Sopenharmony_ci /* Set the pixel offsets. */ 42862306a36Sopenharmony_ci cfg = (offset->y_v << 16) | offset->y_h; 42962306a36Sopenharmony_ci writel(cfg, dev->regs + FIMC_REG_CIIYOFF); 43062306a36Sopenharmony_ci 43162306a36Sopenharmony_ci cfg = (offset->cb_v << 16) | offset->cb_h; 43262306a36Sopenharmony_ci writel(cfg, dev->regs + FIMC_REG_CIICBOFF); 43362306a36Sopenharmony_ci 43462306a36Sopenharmony_ci cfg = (offset->cr_v << 16) | offset->cr_h; 43562306a36Sopenharmony_ci writel(cfg, dev->regs + FIMC_REG_CIICROFF); 43662306a36Sopenharmony_ci 43762306a36Sopenharmony_ci /* Input original and real size. */ 43862306a36Sopenharmony_ci fimc_hw_set_in_dma_size(ctx); 43962306a36Sopenharmony_ci 44062306a36Sopenharmony_ci /* Use DMA autoload only in FIFO mode. */ 44162306a36Sopenharmony_ci fimc_hw_en_autoload(dev, ctx->out_path == FIMC_IO_LCDFIFO); 44262306a36Sopenharmony_ci 44362306a36Sopenharmony_ci /* Set the input DMA to process single frame only. */ 44462306a36Sopenharmony_ci cfg = readl(dev->regs + FIMC_REG_MSCTRL); 44562306a36Sopenharmony_ci cfg &= ~(FIMC_REG_MSCTRL_INFORMAT_MASK 44662306a36Sopenharmony_ci | FIMC_REG_MSCTRL_IN_BURST_COUNT_MASK 44762306a36Sopenharmony_ci | FIMC_REG_MSCTRL_INPUT_MASK 44862306a36Sopenharmony_ci | FIMC_REG_MSCTRL_C_INT_IN_MASK 44962306a36Sopenharmony_ci | FIMC_REG_MSCTRL_2P_IN_ORDER_MASK 45062306a36Sopenharmony_ci | FIMC_REG_MSCTRL_ORDER422_MASK); 45162306a36Sopenharmony_ci 45262306a36Sopenharmony_ci cfg |= (FIMC_REG_MSCTRL_IN_BURST_COUNT(4) 45362306a36Sopenharmony_ci | FIMC_REG_MSCTRL_INPUT_MEMORY 45462306a36Sopenharmony_ci | FIMC_REG_MSCTRL_FIFO_CTRL_FULL); 45562306a36Sopenharmony_ci 45662306a36Sopenharmony_ci switch (frame->fmt->color) { 45762306a36Sopenharmony_ci case FIMC_FMT_RGB565...FIMC_FMT_RGB888: 45862306a36Sopenharmony_ci cfg |= FIMC_REG_MSCTRL_INFORMAT_RGB; 45962306a36Sopenharmony_ci break; 46062306a36Sopenharmony_ci case FIMC_FMT_YCBCR420: 46162306a36Sopenharmony_ci cfg |= FIMC_REG_MSCTRL_INFORMAT_YCBCR420; 46262306a36Sopenharmony_ci 46362306a36Sopenharmony_ci if (frame->fmt->colplanes == 2) 46462306a36Sopenharmony_ci cfg |= ctx->in_order_2p | FIMC_REG_MSCTRL_C_INT_IN_2PLANE; 46562306a36Sopenharmony_ci else 46662306a36Sopenharmony_ci cfg |= FIMC_REG_MSCTRL_C_INT_IN_3PLANE; 46762306a36Sopenharmony_ci 46862306a36Sopenharmony_ci break; 46962306a36Sopenharmony_ci case FIMC_FMT_YCBYCR422...FIMC_FMT_CRYCBY422: 47062306a36Sopenharmony_ci if (frame->fmt->colplanes == 1) { 47162306a36Sopenharmony_ci cfg |= ctx->in_order_1p 47262306a36Sopenharmony_ci | FIMC_REG_MSCTRL_INFORMAT_YCBCR422_1P; 47362306a36Sopenharmony_ci } else { 47462306a36Sopenharmony_ci cfg |= FIMC_REG_MSCTRL_INFORMAT_YCBCR422; 47562306a36Sopenharmony_ci 47662306a36Sopenharmony_ci if (frame->fmt->colplanes == 2) 47762306a36Sopenharmony_ci cfg |= ctx->in_order_2p 47862306a36Sopenharmony_ci | FIMC_REG_MSCTRL_C_INT_IN_2PLANE; 47962306a36Sopenharmony_ci else 48062306a36Sopenharmony_ci cfg |= FIMC_REG_MSCTRL_C_INT_IN_3PLANE; 48162306a36Sopenharmony_ci } 48262306a36Sopenharmony_ci break; 48362306a36Sopenharmony_ci default: 48462306a36Sopenharmony_ci break; 48562306a36Sopenharmony_ci } 48662306a36Sopenharmony_ci 48762306a36Sopenharmony_ci writel(cfg, dev->regs + FIMC_REG_MSCTRL); 48862306a36Sopenharmony_ci 48962306a36Sopenharmony_ci /* Input/output DMA linear/tiled mode. */ 49062306a36Sopenharmony_ci cfg = readl(dev->regs + FIMC_REG_CIDMAPARAM); 49162306a36Sopenharmony_ci cfg &= ~FIMC_REG_CIDMAPARAM_TILE_MASK; 49262306a36Sopenharmony_ci 49362306a36Sopenharmony_ci if (tiled_fmt(ctx->s_frame.fmt)) 49462306a36Sopenharmony_ci cfg |= FIMC_REG_CIDMAPARAM_R_64X32; 49562306a36Sopenharmony_ci 49662306a36Sopenharmony_ci if (tiled_fmt(ctx->d_frame.fmt)) 49762306a36Sopenharmony_ci cfg |= FIMC_REG_CIDMAPARAM_W_64X32; 49862306a36Sopenharmony_ci 49962306a36Sopenharmony_ci writel(cfg, dev->regs + FIMC_REG_CIDMAPARAM); 50062306a36Sopenharmony_ci} 50162306a36Sopenharmony_ci 50262306a36Sopenharmony_ci 50362306a36Sopenharmony_civoid fimc_hw_set_input_path(struct fimc_ctx *ctx) 50462306a36Sopenharmony_ci{ 50562306a36Sopenharmony_ci struct fimc_dev *dev = ctx->fimc_dev; 50662306a36Sopenharmony_ci 50762306a36Sopenharmony_ci u32 cfg = readl(dev->regs + FIMC_REG_MSCTRL); 50862306a36Sopenharmony_ci cfg &= ~FIMC_REG_MSCTRL_INPUT_MASK; 50962306a36Sopenharmony_ci 51062306a36Sopenharmony_ci if (ctx->in_path == FIMC_IO_DMA) 51162306a36Sopenharmony_ci cfg |= FIMC_REG_MSCTRL_INPUT_MEMORY; 51262306a36Sopenharmony_ci else 51362306a36Sopenharmony_ci cfg |= FIMC_REG_MSCTRL_INPUT_EXTCAM; 51462306a36Sopenharmony_ci 51562306a36Sopenharmony_ci writel(cfg, dev->regs + FIMC_REG_MSCTRL); 51662306a36Sopenharmony_ci} 51762306a36Sopenharmony_ci 51862306a36Sopenharmony_civoid fimc_hw_set_output_path(struct fimc_ctx *ctx) 51962306a36Sopenharmony_ci{ 52062306a36Sopenharmony_ci struct fimc_dev *dev = ctx->fimc_dev; 52162306a36Sopenharmony_ci 52262306a36Sopenharmony_ci u32 cfg = readl(dev->regs + FIMC_REG_CISCCTRL); 52362306a36Sopenharmony_ci cfg &= ~FIMC_REG_CISCCTRL_LCDPATHEN_FIFO; 52462306a36Sopenharmony_ci if (ctx->out_path == FIMC_IO_LCDFIFO) 52562306a36Sopenharmony_ci cfg |= FIMC_REG_CISCCTRL_LCDPATHEN_FIFO; 52662306a36Sopenharmony_ci writel(cfg, dev->regs + FIMC_REG_CISCCTRL); 52762306a36Sopenharmony_ci} 52862306a36Sopenharmony_ci 52962306a36Sopenharmony_civoid fimc_hw_set_input_addr(struct fimc_dev *dev, struct fimc_addr *addr) 53062306a36Sopenharmony_ci{ 53162306a36Sopenharmony_ci u32 cfg = readl(dev->regs + FIMC_REG_CIREAL_ISIZE); 53262306a36Sopenharmony_ci cfg |= FIMC_REG_CIREAL_ISIZE_ADDR_CH_DIS; 53362306a36Sopenharmony_ci writel(cfg, dev->regs + FIMC_REG_CIREAL_ISIZE); 53462306a36Sopenharmony_ci 53562306a36Sopenharmony_ci writel(addr->y, dev->regs + FIMC_REG_CIIYSA(0)); 53662306a36Sopenharmony_ci writel(addr->cb, dev->regs + FIMC_REG_CIICBSA(0)); 53762306a36Sopenharmony_ci writel(addr->cr, dev->regs + FIMC_REG_CIICRSA(0)); 53862306a36Sopenharmony_ci 53962306a36Sopenharmony_ci cfg &= ~FIMC_REG_CIREAL_ISIZE_ADDR_CH_DIS; 54062306a36Sopenharmony_ci writel(cfg, dev->regs + FIMC_REG_CIREAL_ISIZE); 54162306a36Sopenharmony_ci} 54262306a36Sopenharmony_ci 54362306a36Sopenharmony_civoid fimc_hw_set_output_addr(struct fimc_dev *dev, 54462306a36Sopenharmony_ci struct fimc_addr *addr, int index) 54562306a36Sopenharmony_ci{ 54662306a36Sopenharmony_ci int i = (index == -1) ? 0 : index; 54762306a36Sopenharmony_ci do { 54862306a36Sopenharmony_ci writel(addr->y, dev->regs + FIMC_REG_CIOYSA(i)); 54962306a36Sopenharmony_ci writel(addr->cb, dev->regs + FIMC_REG_CIOCBSA(i)); 55062306a36Sopenharmony_ci writel(addr->cr, dev->regs + FIMC_REG_CIOCRSA(i)); 55162306a36Sopenharmony_ci dbg("dst_buf[%d]: 0x%X, cb: 0x%X, cr: 0x%X", 55262306a36Sopenharmony_ci i, addr->y, addr->cb, addr->cr); 55362306a36Sopenharmony_ci } while (index == -1 && ++i < FIMC_MAX_OUT_BUFS); 55462306a36Sopenharmony_ci} 55562306a36Sopenharmony_ci 55662306a36Sopenharmony_ciint fimc_hw_set_camera_polarity(struct fimc_dev *fimc, 55762306a36Sopenharmony_ci struct fimc_source_info *cam) 55862306a36Sopenharmony_ci{ 55962306a36Sopenharmony_ci u32 cfg = readl(fimc->regs + FIMC_REG_CIGCTRL); 56062306a36Sopenharmony_ci 56162306a36Sopenharmony_ci cfg &= ~(FIMC_REG_CIGCTRL_INVPOLPCLK | FIMC_REG_CIGCTRL_INVPOLVSYNC | 56262306a36Sopenharmony_ci FIMC_REG_CIGCTRL_INVPOLHREF | FIMC_REG_CIGCTRL_INVPOLHSYNC | 56362306a36Sopenharmony_ci FIMC_REG_CIGCTRL_INVPOLFIELD); 56462306a36Sopenharmony_ci 56562306a36Sopenharmony_ci if (cam->flags & V4L2_MBUS_PCLK_SAMPLE_FALLING) 56662306a36Sopenharmony_ci cfg |= FIMC_REG_CIGCTRL_INVPOLPCLK; 56762306a36Sopenharmony_ci 56862306a36Sopenharmony_ci if (cam->flags & V4L2_MBUS_VSYNC_ACTIVE_LOW) 56962306a36Sopenharmony_ci cfg |= FIMC_REG_CIGCTRL_INVPOLVSYNC; 57062306a36Sopenharmony_ci 57162306a36Sopenharmony_ci if (cam->flags & V4L2_MBUS_HSYNC_ACTIVE_LOW) 57262306a36Sopenharmony_ci cfg |= FIMC_REG_CIGCTRL_INVPOLHREF; 57362306a36Sopenharmony_ci 57462306a36Sopenharmony_ci if (cam->flags & V4L2_MBUS_HSYNC_ACTIVE_LOW) 57562306a36Sopenharmony_ci cfg |= FIMC_REG_CIGCTRL_INVPOLHSYNC; 57662306a36Sopenharmony_ci 57762306a36Sopenharmony_ci if (cam->flags & V4L2_MBUS_FIELD_EVEN_LOW) 57862306a36Sopenharmony_ci cfg |= FIMC_REG_CIGCTRL_INVPOLFIELD; 57962306a36Sopenharmony_ci 58062306a36Sopenharmony_ci writel(cfg, fimc->regs + FIMC_REG_CIGCTRL); 58162306a36Sopenharmony_ci 58262306a36Sopenharmony_ci return 0; 58362306a36Sopenharmony_ci} 58462306a36Sopenharmony_ci 58562306a36Sopenharmony_cistruct mbus_pixfmt_desc { 58662306a36Sopenharmony_ci u32 pixelcode; 58762306a36Sopenharmony_ci u32 cisrcfmt; 58862306a36Sopenharmony_ci u16 bus_width; 58962306a36Sopenharmony_ci}; 59062306a36Sopenharmony_ci 59162306a36Sopenharmony_cistatic const struct mbus_pixfmt_desc pix_desc[] = { 59262306a36Sopenharmony_ci { MEDIA_BUS_FMT_YUYV8_2X8, FIMC_REG_CISRCFMT_ORDER422_YCBYCR, 8 }, 59362306a36Sopenharmony_ci { MEDIA_BUS_FMT_YVYU8_2X8, FIMC_REG_CISRCFMT_ORDER422_YCRYCB, 8 }, 59462306a36Sopenharmony_ci { MEDIA_BUS_FMT_VYUY8_2X8, FIMC_REG_CISRCFMT_ORDER422_CRYCBY, 8 }, 59562306a36Sopenharmony_ci { MEDIA_BUS_FMT_UYVY8_2X8, FIMC_REG_CISRCFMT_ORDER422_CBYCRY, 8 }, 59662306a36Sopenharmony_ci}; 59762306a36Sopenharmony_ci 59862306a36Sopenharmony_ciint fimc_hw_set_camera_source(struct fimc_dev *fimc, 59962306a36Sopenharmony_ci struct fimc_source_info *source) 60062306a36Sopenharmony_ci{ 60162306a36Sopenharmony_ci struct fimc_vid_cap *vc = &fimc->vid_cap; 60262306a36Sopenharmony_ci struct fimc_frame *f = &vc->ctx->s_frame; 60362306a36Sopenharmony_ci u32 bus_width, cfg = 0; 60462306a36Sopenharmony_ci int i; 60562306a36Sopenharmony_ci 60662306a36Sopenharmony_ci switch (source->fimc_bus_type) { 60762306a36Sopenharmony_ci case FIMC_BUS_TYPE_ITU_601: 60862306a36Sopenharmony_ci case FIMC_BUS_TYPE_ITU_656: 60962306a36Sopenharmony_ci if (fimc_fmt_is_user_defined(f->fmt->color)) { 61062306a36Sopenharmony_ci cfg |= FIMC_REG_CISRCFMT_ITU601_8BIT; 61162306a36Sopenharmony_ci break; 61262306a36Sopenharmony_ci } 61362306a36Sopenharmony_ci 61462306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(pix_desc); i++) { 61562306a36Sopenharmony_ci if (vc->ci_fmt.code == pix_desc[i].pixelcode) { 61662306a36Sopenharmony_ci cfg = pix_desc[i].cisrcfmt; 61762306a36Sopenharmony_ci bus_width = pix_desc[i].bus_width; 61862306a36Sopenharmony_ci break; 61962306a36Sopenharmony_ci } 62062306a36Sopenharmony_ci } 62162306a36Sopenharmony_ci 62262306a36Sopenharmony_ci if (i == ARRAY_SIZE(pix_desc)) { 62362306a36Sopenharmony_ci v4l2_err(&vc->ve.vdev, 62462306a36Sopenharmony_ci "Camera color format not supported: %d\n", 62562306a36Sopenharmony_ci vc->ci_fmt.code); 62662306a36Sopenharmony_ci return -EINVAL; 62762306a36Sopenharmony_ci } 62862306a36Sopenharmony_ci 62962306a36Sopenharmony_ci if (source->fimc_bus_type == FIMC_BUS_TYPE_ITU_601) { 63062306a36Sopenharmony_ci if (bus_width == 8) 63162306a36Sopenharmony_ci cfg |= FIMC_REG_CISRCFMT_ITU601_8BIT; 63262306a36Sopenharmony_ci else if (bus_width == 16) 63362306a36Sopenharmony_ci cfg |= FIMC_REG_CISRCFMT_ITU601_16BIT; 63462306a36Sopenharmony_ci } /* else defaults to ITU-R BT.656 8-bit */ 63562306a36Sopenharmony_ci break; 63662306a36Sopenharmony_ci case FIMC_BUS_TYPE_MIPI_CSI2: 63762306a36Sopenharmony_ci if (fimc_fmt_is_user_defined(f->fmt->color)) 63862306a36Sopenharmony_ci cfg |= FIMC_REG_CISRCFMT_ITU601_8BIT; 63962306a36Sopenharmony_ci break; 64062306a36Sopenharmony_ci default: 64162306a36Sopenharmony_ci case FIMC_BUS_TYPE_ISP_WRITEBACK: 64262306a36Sopenharmony_ci /* Anything to do here ? */ 64362306a36Sopenharmony_ci break; 64462306a36Sopenharmony_ci } 64562306a36Sopenharmony_ci 64662306a36Sopenharmony_ci cfg |= (f->o_width << 16) | f->o_height; 64762306a36Sopenharmony_ci writel(cfg, fimc->regs + FIMC_REG_CISRCFMT); 64862306a36Sopenharmony_ci return 0; 64962306a36Sopenharmony_ci} 65062306a36Sopenharmony_ci 65162306a36Sopenharmony_civoid fimc_hw_set_camera_offset(struct fimc_dev *fimc, struct fimc_frame *f) 65262306a36Sopenharmony_ci{ 65362306a36Sopenharmony_ci u32 hoff2, voff2; 65462306a36Sopenharmony_ci 65562306a36Sopenharmony_ci u32 cfg = readl(fimc->regs + FIMC_REG_CIWDOFST); 65662306a36Sopenharmony_ci 65762306a36Sopenharmony_ci cfg &= ~(FIMC_REG_CIWDOFST_HOROFF_MASK | FIMC_REG_CIWDOFST_VEROFF_MASK); 65862306a36Sopenharmony_ci cfg |= FIMC_REG_CIWDOFST_OFF_EN | 65962306a36Sopenharmony_ci (f->offs_h << 16) | f->offs_v; 66062306a36Sopenharmony_ci 66162306a36Sopenharmony_ci writel(cfg, fimc->regs + FIMC_REG_CIWDOFST); 66262306a36Sopenharmony_ci 66362306a36Sopenharmony_ci /* See CIWDOFSTn register description in the datasheet for details. */ 66462306a36Sopenharmony_ci hoff2 = f->o_width - f->width - f->offs_h; 66562306a36Sopenharmony_ci voff2 = f->o_height - f->height - f->offs_v; 66662306a36Sopenharmony_ci cfg = (hoff2 << 16) | voff2; 66762306a36Sopenharmony_ci writel(cfg, fimc->regs + FIMC_REG_CIWDOFST2); 66862306a36Sopenharmony_ci} 66962306a36Sopenharmony_ci 67062306a36Sopenharmony_ciint fimc_hw_set_camera_type(struct fimc_dev *fimc, 67162306a36Sopenharmony_ci struct fimc_source_info *source) 67262306a36Sopenharmony_ci{ 67362306a36Sopenharmony_ci struct fimc_vid_cap *vid_cap = &fimc->vid_cap; 67462306a36Sopenharmony_ci u32 csis_data_alignment = 32; 67562306a36Sopenharmony_ci u32 cfg, tmp; 67662306a36Sopenharmony_ci 67762306a36Sopenharmony_ci cfg = readl(fimc->regs + FIMC_REG_CIGCTRL); 67862306a36Sopenharmony_ci 67962306a36Sopenharmony_ci /* Select ITU B interface, disable Writeback path and test pattern. */ 68062306a36Sopenharmony_ci cfg &= ~(FIMC_REG_CIGCTRL_TESTPAT_MASK | FIMC_REG_CIGCTRL_SELCAM_ITU_A | 68162306a36Sopenharmony_ci FIMC_REG_CIGCTRL_SELCAM_MIPI | FIMC_REG_CIGCTRL_CAMIF_SELWB | 68262306a36Sopenharmony_ci FIMC_REG_CIGCTRL_SELCAM_MIPI_A | FIMC_REG_CIGCTRL_CAM_JPEG | 68362306a36Sopenharmony_ci FIMC_REG_CIGCTRL_SELWB_A); 68462306a36Sopenharmony_ci 68562306a36Sopenharmony_ci switch (source->fimc_bus_type) { 68662306a36Sopenharmony_ci case FIMC_BUS_TYPE_MIPI_CSI2: 68762306a36Sopenharmony_ci cfg |= FIMC_REG_CIGCTRL_SELCAM_MIPI; 68862306a36Sopenharmony_ci 68962306a36Sopenharmony_ci if (source->mux_id == 0) 69062306a36Sopenharmony_ci cfg |= FIMC_REG_CIGCTRL_SELCAM_MIPI_A; 69162306a36Sopenharmony_ci 69262306a36Sopenharmony_ci /* TODO: add remaining supported formats. */ 69362306a36Sopenharmony_ci switch (vid_cap->ci_fmt.code) { 69462306a36Sopenharmony_ci case MEDIA_BUS_FMT_VYUY8_2X8: 69562306a36Sopenharmony_ci tmp = FIMC_REG_CSIIMGFMT_YCBCR422_8BIT; 69662306a36Sopenharmony_ci break; 69762306a36Sopenharmony_ci case MEDIA_BUS_FMT_JPEG_1X8: 69862306a36Sopenharmony_ci case MEDIA_BUS_FMT_S5C_UYVY_JPEG_1X8: 69962306a36Sopenharmony_ci tmp = FIMC_REG_CSIIMGFMT_USER(1); 70062306a36Sopenharmony_ci cfg |= FIMC_REG_CIGCTRL_CAM_JPEG; 70162306a36Sopenharmony_ci break; 70262306a36Sopenharmony_ci default: 70362306a36Sopenharmony_ci v4l2_err(&vid_cap->ve.vdev, 70462306a36Sopenharmony_ci "Not supported camera pixel format: %#x\n", 70562306a36Sopenharmony_ci vid_cap->ci_fmt.code); 70662306a36Sopenharmony_ci return -EINVAL; 70762306a36Sopenharmony_ci } 70862306a36Sopenharmony_ci tmp |= (csis_data_alignment == 32) << 8; 70962306a36Sopenharmony_ci 71062306a36Sopenharmony_ci writel(tmp, fimc->regs + FIMC_REG_CSIIMGFMT); 71162306a36Sopenharmony_ci break; 71262306a36Sopenharmony_ci case FIMC_BUS_TYPE_ITU_601...FIMC_BUS_TYPE_ITU_656: 71362306a36Sopenharmony_ci if (source->mux_id == 0) /* ITU-A, ITU-B: 0, 1 */ 71462306a36Sopenharmony_ci cfg |= FIMC_REG_CIGCTRL_SELCAM_ITU_A; 71562306a36Sopenharmony_ci if (vid_cap->ci_fmt.code == MEDIA_BUS_FMT_JPEG_1X8) 71662306a36Sopenharmony_ci cfg |= FIMC_REG_CIGCTRL_CAM_JPEG; 71762306a36Sopenharmony_ci break; 71862306a36Sopenharmony_ci case FIMC_BUS_TYPE_LCD_WRITEBACK_A: 71962306a36Sopenharmony_ci cfg |= FIMC_REG_CIGCTRL_CAMIF_SELWB; 72062306a36Sopenharmony_ci fallthrough; 72162306a36Sopenharmony_ci case FIMC_BUS_TYPE_ISP_WRITEBACK: 72262306a36Sopenharmony_ci if (fimc->variant->has_isp_wb) 72362306a36Sopenharmony_ci cfg |= FIMC_REG_CIGCTRL_CAMIF_SELWB; 72462306a36Sopenharmony_ci else 72562306a36Sopenharmony_ci WARN_ONCE(1, "ISP Writeback input is not supported\n"); 72662306a36Sopenharmony_ci break; 72762306a36Sopenharmony_ci default: 72862306a36Sopenharmony_ci v4l2_err(&vid_cap->ve.vdev, 72962306a36Sopenharmony_ci "Invalid FIMC bus type selected: %d\n", 73062306a36Sopenharmony_ci source->fimc_bus_type); 73162306a36Sopenharmony_ci return -EINVAL; 73262306a36Sopenharmony_ci } 73362306a36Sopenharmony_ci writel(cfg, fimc->regs + FIMC_REG_CIGCTRL); 73462306a36Sopenharmony_ci 73562306a36Sopenharmony_ci return 0; 73662306a36Sopenharmony_ci} 73762306a36Sopenharmony_ci 73862306a36Sopenharmony_civoid fimc_hw_clear_irq(struct fimc_dev *dev) 73962306a36Sopenharmony_ci{ 74062306a36Sopenharmony_ci u32 cfg = readl(dev->regs + FIMC_REG_CIGCTRL); 74162306a36Sopenharmony_ci cfg |= FIMC_REG_CIGCTRL_IRQ_CLR; 74262306a36Sopenharmony_ci writel(cfg, dev->regs + FIMC_REG_CIGCTRL); 74362306a36Sopenharmony_ci} 74462306a36Sopenharmony_ci 74562306a36Sopenharmony_civoid fimc_hw_enable_scaler(struct fimc_dev *dev, bool on) 74662306a36Sopenharmony_ci{ 74762306a36Sopenharmony_ci u32 cfg = readl(dev->regs + FIMC_REG_CISCCTRL); 74862306a36Sopenharmony_ci if (on) 74962306a36Sopenharmony_ci cfg |= FIMC_REG_CISCCTRL_SCALERSTART; 75062306a36Sopenharmony_ci else 75162306a36Sopenharmony_ci cfg &= ~FIMC_REG_CISCCTRL_SCALERSTART; 75262306a36Sopenharmony_ci writel(cfg, dev->regs + FIMC_REG_CISCCTRL); 75362306a36Sopenharmony_ci} 75462306a36Sopenharmony_ci 75562306a36Sopenharmony_civoid fimc_hw_activate_input_dma(struct fimc_dev *dev, bool on) 75662306a36Sopenharmony_ci{ 75762306a36Sopenharmony_ci u32 cfg = readl(dev->regs + FIMC_REG_MSCTRL); 75862306a36Sopenharmony_ci if (on) 75962306a36Sopenharmony_ci cfg |= FIMC_REG_MSCTRL_ENVID; 76062306a36Sopenharmony_ci else 76162306a36Sopenharmony_ci cfg &= ~FIMC_REG_MSCTRL_ENVID; 76262306a36Sopenharmony_ci writel(cfg, dev->regs + FIMC_REG_MSCTRL); 76362306a36Sopenharmony_ci} 76462306a36Sopenharmony_ci 76562306a36Sopenharmony_ci/* Return an index to the buffer actually being written. */ 76662306a36Sopenharmony_cis32 fimc_hw_get_frame_index(struct fimc_dev *dev) 76762306a36Sopenharmony_ci{ 76862306a36Sopenharmony_ci s32 reg; 76962306a36Sopenharmony_ci 77062306a36Sopenharmony_ci if (dev->drv_data->cistatus2) { 77162306a36Sopenharmony_ci reg = readl(dev->regs + FIMC_REG_CISTATUS2) & 0x3f; 77262306a36Sopenharmony_ci return reg - 1; 77362306a36Sopenharmony_ci } 77462306a36Sopenharmony_ci 77562306a36Sopenharmony_ci reg = readl(dev->regs + FIMC_REG_CISTATUS); 77662306a36Sopenharmony_ci 77762306a36Sopenharmony_ci return (reg & FIMC_REG_CISTATUS_FRAMECNT_MASK) >> 77862306a36Sopenharmony_ci FIMC_REG_CISTATUS_FRAMECNT_SHIFT; 77962306a36Sopenharmony_ci} 78062306a36Sopenharmony_ci 78162306a36Sopenharmony_ci/* Return an index to the buffer being written previously. */ 78262306a36Sopenharmony_cis32 fimc_hw_get_prev_frame_index(struct fimc_dev *dev) 78362306a36Sopenharmony_ci{ 78462306a36Sopenharmony_ci s32 reg; 78562306a36Sopenharmony_ci 78662306a36Sopenharmony_ci if (!dev->drv_data->cistatus2) 78762306a36Sopenharmony_ci return -1; 78862306a36Sopenharmony_ci 78962306a36Sopenharmony_ci reg = readl(dev->regs + FIMC_REG_CISTATUS2); 79062306a36Sopenharmony_ci return ((reg >> 7) & 0x3f) - 1; 79162306a36Sopenharmony_ci} 79262306a36Sopenharmony_ci 79362306a36Sopenharmony_ci/* Locking: the caller holds fimc->slock */ 79462306a36Sopenharmony_civoid fimc_activate_capture(struct fimc_ctx *ctx) 79562306a36Sopenharmony_ci{ 79662306a36Sopenharmony_ci fimc_hw_enable_scaler(ctx->fimc_dev, ctx->scaler.enabled); 79762306a36Sopenharmony_ci fimc_hw_enable_capture(ctx); 79862306a36Sopenharmony_ci} 79962306a36Sopenharmony_ci 80062306a36Sopenharmony_civoid fimc_deactivate_capture(struct fimc_dev *fimc) 80162306a36Sopenharmony_ci{ 80262306a36Sopenharmony_ci fimc_hw_en_lastirq(fimc, true); 80362306a36Sopenharmony_ci fimc_hw_disable_capture(fimc); 80462306a36Sopenharmony_ci fimc_hw_enable_scaler(fimc, false); 80562306a36Sopenharmony_ci fimc_hw_en_lastirq(fimc, false); 80662306a36Sopenharmony_ci} 80762306a36Sopenharmony_ci 80862306a36Sopenharmony_ciint fimc_hw_camblk_cfg_writeback(struct fimc_dev *fimc) 80962306a36Sopenharmony_ci{ 81062306a36Sopenharmony_ci struct regmap *map = fimc->sysreg; 81162306a36Sopenharmony_ci unsigned int mask, val, camblk_cfg; 81262306a36Sopenharmony_ci int ret; 81362306a36Sopenharmony_ci 81462306a36Sopenharmony_ci if (map == NULL) 81562306a36Sopenharmony_ci return 0; 81662306a36Sopenharmony_ci 81762306a36Sopenharmony_ci ret = regmap_read(map, SYSREG_CAMBLK, &camblk_cfg); 81862306a36Sopenharmony_ci if (ret < 0 || ((camblk_cfg & 0x00700000) >> 20 != 0x3)) 81962306a36Sopenharmony_ci return ret; 82062306a36Sopenharmony_ci 82162306a36Sopenharmony_ci if (!WARN(fimc->id >= 3, "not supported id: %d\n", fimc->id)) 82262306a36Sopenharmony_ci val = 0x1 << (fimc->id + 20); 82362306a36Sopenharmony_ci else 82462306a36Sopenharmony_ci val = 0; 82562306a36Sopenharmony_ci 82662306a36Sopenharmony_ci mask = SYSREG_CAMBLK_FIFORST_ISP | SYSREG_CAMBLK_ISPWB_FULL_EN; 82762306a36Sopenharmony_ci ret = regmap_update_bits(map, SYSREG_CAMBLK, mask, val); 82862306a36Sopenharmony_ci if (ret < 0) 82962306a36Sopenharmony_ci return ret; 83062306a36Sopenharmony_ci 83162306a36Sopenharmony_ci usleep_range(1000, 2000); 83262306a36Sopenharmony_ci 83362306a36Sopenharmony_ci val |= SYSREG_CAMBLK_FIFORST_ISP; 83462306a36Sopenharmony_ci ret = regmap_update_bits(map, SYSREG_CAMBLK, mask, val); 83562306a36Sopenharmony_ci if (ret < 0) 83662306a36Sopenharmony_ci return ret; 83762306a36Sopenharmony_ci 83862306a36Sopenharmony_ci mask = SYSREG_ISPBLK_FIFORST_CAM_BLK; 83962306a36Sopenharmony_ci ret = regmap_update_bits(map, SYSREG_ISPBLK, mask, ~mask); 84062306a36Sopenharmony_ci if (ret < 0) 84162306a36Sopenharmony_ci return ret; 84262306a36Sopenharmony_ci 84362306a36Sopenharmony_ci usleep_range(1000, 2000); 84462306a36Sopenharmony_ci 84562306a36Sopenharmony_ci return regmap_update_bits(map, SYSREG_ISPBLK, mask, mask); 84662306a36Sopenharmony_ci} 847