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