1// SPDX-License-Identifier: GPL-2.0-only
2/*
3 * Register interface file for Samsung Camera Interface (FIMC) driver
4 *
5 * Copyright (C) 2010 - 2013 Samsung Electronics Co., Ltd.
6 * Sylwester Nawrocki <s.nawrocki@samsung.com>
7*/
8
9#include <linux/delay.h>
10#include <linux/io.h>
11#include <linux/regmap.h>
12
13#include <media/drv-intf/exynos-fimc.h>
14#include "media-dev.h"
15
16#include "fimc-reg.h"
17#include "fimc-core.h"
18
19void fimc_hw_reset(struct fimc_dev *dev)
20{
21	u32 cfg;
22
23	cfg = readl(dev->regs + FIMC_REG_CISRCFMT);
24	cfg |= FIMC_REG_CISRCFMT_ITU601_8BIT;
25	writel(cfg, dev->regs + FIMC_REG_CISRCFMT);
26
27	/* Software reset. */
28	cfg = readl(dev->regs + FIMC_REG_CIGCTRL);
29	cfg |= (FIMC_REG_CIGCTRL_SWRST | FIMC_REG_CIGCTRL_IRQ_LEVEL);
30	writel(cfg, dev->regs + FIMC_REG_CIGCTRL);
31	udelay(10);
32
33	cfg = readl(dev->regs + FIMC_REG_CIGCTRL);
34	cfg &= ~FIMC_REG_CIGCTRL_SWRST;
35	writel(cfg, dev->regs + FIMC_REG_CIGCTRL);
36
37	if (dev->drv_data->out_buf_count > 4)
38		fimc_hw_set_dma_seq(dev, 0xF);
39}
40
41static u32 fimc_hw_get_in_flip(struct fimc_ctx *ctx)
42{
43	u32 flip = FIMC_REG_MSCTRL_FLIP_NORMAL;
44
45	if (ctx->hflip)
46		flip = FIMC_REG_MSCTRL_FLIP_Y_MIRROR;
47	if (ctx->vflip)
48		flip = FIMC_REG_MSCTRL_FLIP_X_MIRROR;
49
50	if (ctx->rotation <= 90)
51		return flip;
52
53	return (flip ^ FIMC_REG_MSCTRL_FLIP_180) & FIMC_REG_MSCTRL_FLIP_180;
54}
55
56static u32 fimc_hw_get_target_flip(struct fimc_ctx *ctx)
57{
58	u32 flip = FIMC_REG_CITRGFMT_FLIP_NORMAL;
59
60	if (ctx->hflip)
61		flip |= FIMC_REG_CITRGFMT_FLIP_Y_MIRROR;
62	if (ctx->vflip)
63		flip |= FIMC_REG_CITRGFMT_FLIP_X_MIRROR;
64
65	if (ctx->rotation <= 90)
66		return flip;
67
68	return (flip ^ FIMC_REG_CITRGFMT_FLIP_180) & FIMC_REG_CITRGFMT_FLIP_180;
69}
70
71void fimc_hw_set_rotation(struct fimc_ctx *ctx)
72{
73	u32 cfg, flip;
74	struct fimc_dev *dev = ctx->fimc_dev;
75
76	cfg = readl(dev->regs + FIMC_REG_CITRGFMT);
77	cfg &= ~(FIMC_REG_CITRGFMT_INROT90 | FIMC_REG_CITRGFMT_OUTROT90 |
78		 FIMC_REG_CITRGFMT_FLIP_180);
79
80	/*
81	 * The input and output rotator cannot work simultaneously.
82	 * Use the output rotator in output DMA mode or the input rotator
83	 * in direct fifo output mode.
84	 */
85	if (ctx->rotation == 90 || ctx->rotation == 270) {
86		if (ctx->out_path == FIMC_IO_LCDFIFO)
87			cfg |= FIMC_REG_CITRGFMT_INROT90;
88		else
89			cfg |= FIMC_REG_CITRGFMT_OUTROT90;
90	}
91
92	if (ctx->out_path == FIMC_IO_DMA) {
93		cfg |= fimc_hw_get_target_flip(ctx);
94		writel(cfg, dev->regs + FIMC_REG_CITRGFMT);
95	} else {
96		/* LCD FIFO path */
97		flip = readl(dev->regs + FIMC_REG_MSCTRL);
98		flip &= ~FIMC_REG_MSCTRL_FLIP_MASK;
99		flip |= fimc_hw_get_in_flip(ctx);
100		writel(flip, dev->regs + FIMC_REG_MSCTRL);
101	}
102}
103
104void fimc_hw_set_target_format(struct fimc_ctx *ctx)
105{
106	u32 cfg;
107	struct fimc_dev *dev = ctx->fimc_dev;
108	const struct fimc_frame *frame = &ctx->d_frame;
109
110	dbg("w= %d, h= %d color: %d", frame->width,
111	    frame->height, frame->fmt->color);
112
113	cfg = readl(dev->regs + FIMC_REG_CITRGFMT);
114	cfg &= ~(FIMC_REG_CITRGFMT_FMT_MASK | FIMC_REG_CITRGFMT_HSIZE_MASK |
115		 FIMC_REG_CITRGFMT_VSIZE_MASK);
116
117	switch (frame->fmt->color) {
118	case FIMC_FMT_RGB444...FIMC_FMT_RGB888:
119		cfg |= FIMC_REG_CITRGFMT_RGB;
120		break;
121	case FIMC_FMT_YCBCR420:
122		cfg |= FIMC_REG_CITRGFMT_YCBCR420;
123		break;
124	case FIMC_FMT_YCBYCR422...FIMC_FMT_CRYCBY422:
125		if (frame->fmt->colplanes == 1)
126			cfg |= FIMC_REG_CITRGFMT_YCBCR422_1P;
127		else
128			cfg |= FIMC_REG_CITRGFMT_YCBCR422;
129		break;
130	default:
131		break;
132	}
133
134	if (ctx->rotation == 90 || ctx->rotation == 270)
135		cfg |= (frame->height << 16) | frame->width;
136	else
137		cfg |= (frame->width << 16) | frame->height;
138
139	writel(cfg, dev->regs + FIMC_REG_CITRGFMT);
140
141	cfg = readl(dev->regs + FIMC_REG_CITAREA);
142	cfg &= ~FIMC_REG_CITAREA_MASK;
143	cfg |= (frame->width * frame->height);
144	writel(cfg, dev->regs + FIMC_REG_CITAREA);
145}
146
147static void fimc_hw_set_out_dma_size(struct fimc_ctx *ctx)
148{
149	struct fimc_dev *dev = ctx->fimc_dev;
150	const struct fimc_frame *frame = &ctx->d_frame;
151	u32 cfg;
152
153	cfg = (frame->f_height << 16) | frame->f_width;
154	writel(cfg, dev->regs + FIMC_REG_ORGOSIZE);
155
156	/* Select color space conversion equation (HD/SD size).*/
157	cfg = readl(dev->regs + FIMC_REG_CIGCTRL);
158	if (frame->f_width >= 1280) /* HD */
159		cfg |= FIMC_REG_CIGCTRL_CSC_ITU601_709;
160	else	/* SD */
161		cfg &= ~FIMC_REG_CIGCTRL_CSC_ITU601_709;
162	writel(cfg, dev->regs + FIMC_REG_CIGCTRL);
163
164}
165
166void fimc_hw_set_out_dma(struct fimc_ctx *ctx)
167{
168	struct fimc_dev *dev = ctx->fimc_dev;
169	const struct fimc_frame *frame = &ctx->d_frame;
170	const struct fimc_dma_offset *offset = &frame->dma_offset;
171	const struct fimc_fmt *fmt = frame->fmt;
172	u32 cfg;
173
174	/* Set the input dma offsets. */
175	cfg = (offset->y_v << 16) | offset->y_h;
176	writel(cfg, dev->regs + FIMC_REG_CIOYOFF);
177
178	cfg = (offset->cb_v << 16) | offset->cb_h;
179	writel(cfg, dev->regs + FIMC_REG_CIOCBOFF);
180
181	cfg = (offset->cr_v << 16) | offset->cr_h;
182	writel(cfg, dev->regs + FIMC_REG_CIOCROFF);
183
184	fimc_hw_set_out_dma_size(ctx);
185
186	/* Configure chroma components order. */
187	cfg = readl(dev->regs + FIMC_REG_CIOCTRL);
188
189	cfg &= ~(FIMC_REG_CIOCTRL_ORDER2P_MASK |
190		 FIMC_REG_CIOCTRL_ORDER422_MASK |
191		 FIMC_REG_CIOCTRL_YCBCR_PLANE_MASK |
192		 FIMC_REG_CIOCTRL_RGB16FMT_MASK);
193
194	if (fmt->colplanes == 1)
195		cfg |= ctx->out_order_1p;
196	else if (fmt->colplanes == 2)
197		cfg |= ctx->out_order_2p | FIMC_REG_CIOCTRL_YCBCR_2PLANE;
198	else if (fmt->colplanes == 3)
199		cfg |= FIMC_REG_CIOCTRL_YCBCR_3PLANE;
200
201	if (fmt->color == FIMC_FMT_RGB565)
202		cfg |= FIMC_REG_CIOCTRL_RGB565;
203	else if (fmt->color == FIMC_FMT_RGB555)
204		cfg |= FIMC_REG_CIOCTRL_ARGB1555;
205	else if (fmt->color == FIMC_FMT_RGB444)
206		cfg |= FIMC_REG_CIOCTRL_ARGB4444;
207
208	writel(cfg, dev->regs + FIMC_REG_CIOCTRL);
209}
210
211static void fimc_hw_en_autoload(struct fimc_dev *dev, int enable)
212{
213	u32 cfg = readl(dev->regs + FIMC_REG_ORGISIZE);
214	if (enable)
215		cfg |= FIMC_REG_CIREAL_ISIZE_AUTOLOAD_EN;
216	else
217		cfg &= ~FIMC_REG_CIREAL_ISIZE_AUTOLOAD_EN;
218	writel(cfg, dev->regs + FIMC_REG_ORGISIZE);
219}
220
221void fimc_hw_en_lastirq(struct fimc_dev *dev, int enable)
222{
223	u32 cfg = readl(dev->regs + FIMC_REG_CIOCTRL);
224	if (enable)
225		cfg |= FIMC_REG_CIOCTRL_LASTIRQ_ENABLE;
226	else
227		cfg &= ~FIMC_REG_CIOCTRL_LASTIRQ_ENABLE;
228	writel(cfg, dev->regs + FIMC_REG_CIOCTRL);
229}
230
231void fimc_hw_set_prescaler(struct fimc_ctx *ctx)
232{
233	struct fimc_dev *dev =  ctx->fimc_dev;
234	struct fimc_scaler *sc = &ctx->scaler;
235	u32 cfg, shfactor;
236
237	shfactor = 10 - (sc->hfactor + sc->vfactor);
238	cfg = shfactor << 28;
239
240	cfg |= (sc->pre_hratio << 16) | sc->pre_vratio;
241	writel(cfg, dev->regs + FIMC_REG_CISCPRERATIO);
242
243	cfg = (sc->pre_dst_width << 16) | sc->pre_dst_height;
244	writel(cfg, dev->regs + FIMC_REG_CISCPREDST);
245}
246
247static void fimc_hw_set_scaler(struct fimc_ctx *ctx)
248{
249	struct fimc_dev *dev = ctx->fimc_dev;
250	struct fimc_scaler *sc = &ctx->scaler;
251	const struct fimc_frame *src_frame = &ctx->s_frame;
252	const struct fimc_frame *dst_frame = &ctx->d_frame;
253
254	u32 cfg = readl(dev->regs + FIMC_REG_CISCCTRL);
255
256	cfg &= ~(FIMC_REG_CISCCTRL_CSCR2Y_WIDE | FIMC_REG_CISCCTRL_CSCY2R_WIDE |
257		 FIMC_REG_CISCCTRL_SCALEUP_H | FIMC_REG_CISCCTRL_SCALEUP_V |
258		 FIMC_REG_CISCCTRL_SCALERBYPASS | FIMC_REG_CISCCTRL_ONE2ONE |
259		 FIMC_REG_CISCCTRL_INRGB_FMT_MASK | FIMC_REG_CISCCTRL_OUTRGB_FMT_MASK |
260		 FIMC_REG_CISCCTRL_INTERLACE | FIMC_REG_CISCCTRL_RGB_EXT);
261
262	if (!(ctx->flags & FIMC_COLOR_RANGE_NARROW))
263		cfg |= (FIMC_REG_CISCCTRL_CSCR2Y_WIDE |
264			FIMC_REG_CISCCTRL_CSCY2R_WIDE);
265
266	if (!sc->enabled)
267		cfg |= FIMC_REG_CISCCTRL_SCALERBYPASS;
268
269	if (sc->scaleup_h)
270		cfg |= FIMC_REG_CISCCTRL_SCALEUP_H;
271
272	if (sc->scaleup_v)
273		cfg |= FIMC_REG_CISCCTRL_SCALEUP_V;
274
275	if (sc->copy_mode)
276		cfg |= FIMC_REG_CISCCTRL_ONE2ONE;
277
278	if (ctx->in_path == FIMC_IO_DMA) {
279		switch (src_frame->fmt->color) {
280		case FIMC_FMT_RGB565:
281			cfg |= FIMC_REG_CISCCTRL_INRGB_FMT_RGB565;
282			break;
283		case FIMC_FMT_RGB666:
284			cfg |= FIMC_REG_CISCCTRL_INRGB_FMT_RGB666;
285			break;
286		case FIMC_FMT_RGB888:
287			cfg |= FIMC_REG_CISCCTRL_INRGB_FMT_RGB888;
288			break;
289		}
290	}
291
292	if (ctx->out_path == FIMC_IO_DMA) {
293		u32 color = dst_frame->fmt->color;
294
295		if (color >= FIMC_FMT_RGB444 && color <= FIMC_FMT_RGB565)
296			cfg |= FIMC_REG_CISCCTRL_OUTRGB_FMT_RGB565;
297		else if (color == FIMC_FMT_RGB666)
298			cfg |= FIMC_REG_CISCCTRL_OUTRGB_FMT_RGB666;
299		else if (color == FIMC_FMT_RGB888)
300			cfg |= FIMC_REG_CISCCTRL_OUTRGB_FMT_RGB888;
301	} else {
302		cfg |= FIMC_REG_CISCCTRL_OUTRGB_FMT_RGB888;
303
304		if (ctx->flags & FIMC_SCAN_MODE_INTERLACED)
305			cfg |= FIMC_REG_CISCCTRL_INTERLACE;
306	}
307
308	writel(cfg, dev->regs + FIMC_REG_CISCCTRL);
309}
310
311void fimc_hw_set_mainscaler(struct fimc_ctx *ctx)
312{
313	struct fimc_dev *dev = ctx->fimc_dev;
314	const struct fimc_variant *variant = dev->variant;
315	struct fimc_scaler *sc = &ctx->scaler;
316	u32 cfg;
317
318	dbg("main_hratio= 0x%X  main_vratio= 0x%X",
319	    sc->main_hratio, sc->main_vratio);
320
321	fimc_hw_set_scaler(ctx);
322
323	cfg = readl(dev->regs + FIMC_REG_CISCCTRL);
324	cfg &= ~(FIMC_REG_CISCCTRL_MHRATIO_MASK |
325		 FIMC_REG_CISCCTRL_MVRATIO_MASK);
326
327	if (variant->has_mainscaler_ext) {
328		cfg |= FIMC_REG_CISCCTRL_MHRATIO_EXT(sc->main_hratio);
329		cfg |= FIMC_REG_CISCCTRL_MVRATIO_EXT(sc->main_vratio);
330		writel(cfg, dev->regs + FIMC_REG_CISCCTRL);
331
332		cfg = readl(dev->regs + FIMC_REG_CIEXTEN);
333
334		cfg &= ~(FIMC_REG_CIEXTEN_MVRATIO_EXT_MASK |
335			 FIMC_REG_CIEXTEN_MHRATIO_EXT_MASK);
336		cfg |= FIMC_REG_CIEXTEN_MHRATIO_EXT(sc->main_hratio);
337		cfg |= FIMC_REG_CIEXTEN_MVRATIO_EXT(sc->main_vratio);
338		writel(cfg, dev->regs + FIMC_REG_CIEXTEN);
339	} else {
340		cfg |= FIMC_REG_CISCCTRL_MHRATIO(sc->main_hratio);
341		cfg |= FIMC_REG_CISCCTRL_MVRATIO(sc->main_vratio);
342		writel(cfg, dev->regs + FIMC_REG_CISCCTRL);
343	}
344}
345
346void fimc_hw_enable_capture(struct fimc_ctx *ctx)
347{
348	struct fimc_dev *dev = ctx->fimc_dev;
349	u32 cfg;
350
351	cfg = readl(dev->regs + FIMC_REG_CIIMGCPT);
352	cfg |= FIMC_REG_CIIMGCPT_CPT_FREN_ENABLE;
353
354	if (ctx->scaler.enabled)
355		cfg |= FIMC_REG_CIIMGCPT_IMGCPTEN_SC;
356	else
357		cfg &= FIMC_REG_CIIMGCPT_IMGCPTEN_SC;
358
359	cfg |= FIMC_REG_CIIMGCPT_IMGCPTEN;
360	writel(cfg, dev->regs + FIMC_REG_CIIMGCPT);
361}
362
363void fimc_hw_disable_capture(struct fimc_dev *dev)
364{
365	u32 cfg = readl(dev->regs + FIMC_REG_CIIMGCPT);
366	cfg &= ~(FIMC_REG_CIIMGCPT_IMGCPTEN |
367		 FIMC_REG_CIIMGCPT_IMGCPTEN_SC);
368	writel(cfg, dev->regs + FIMC_REG_CIIMGCPT);
369}
370
371void fimc_hw_set_effect(struct fimc_ctx *ctx)
372{
373	struct fimc_dev *dev = ctx->fimc_dev;
374	struct fimc_effect *effect = &ctx->effect;
375	u32 cfg = 0;
376
377	if (effect->type != FIMC_REG_CIIMGEFF_FIN_BYPASS) {
378		cfg |= FIMC_REG_CIIMGEFF_IE_SC_AFTER |
379			FIMC_REG_CIIMGEFF_IE_ENABLE;
380		cfg |= effect->type;
381		if (effect->type == FIMC_REG_CIIMGEFF_FIN_ARBITRARY)
382			cfg |= (effect->pat_cb << 13) | effect->pat_cr;
383	}
384
385	writel(cfg, dev->regs + FIMC_REG_CIIMGEFF);
386}
387
388void fimc_hw_set_rgb_alpha(struct fimc_ctx *ctx)
389{
390	struct fimc_dev *dev = ctx->fimc_dev;
391	const struct fimc_frame *frame = &ctx->d_frame;
392	u32 cfg;
393
394	if (!(frame->fmt->flags & FMT_HAS_ALPHA))
395		return;
396
397	cfg = readl(dev->regs + FIMC_REG_CIOCTRL);
398	cfg &= ~FIMC_REG_CIOCTRL_ALPHA_OUT_MASK;
399	cfg |= (frame->alpha << 4);
400	writel(cfg, dev->regs + FIMC_REG_CIOCTRL);
401}
402
403static void fimc_hw_set_in_dma_size(struct fimc_ctx *ctx)
404{
405	struct fimc_dev *dev = ctx->fimc_dev;
406	const struct fimc_frame *frame = &ctx->s_frame;
407	u32 cfg_o = 0;
408	u32 cfg_r = 0;
409
410	if (FIMC_IO_LCDFIFO == ctx->out_path)
411		cfg_r |= FIMC_REG_CIREAL_ISIZE_AUTOLOAD_EN;
412
413	cfg_o |= (frame->f_height << 16) | frame->f_width;
414	cfg_r |= (frame->height << 16) | frame->width;
415
416	writel(cfg_o, dev->regs + FIMC_REG_ORGISIZE);
417	writel(cfg_r, dev->regs + FIMC_REG_CIREAL_ISIZE);
418}
419
420void fimc_hw_set_in_dma(struct fimc_ctx *ctx)
421{
422	struct fimc_dev *dev = ctx->fimc_dev;
423	const struct fimc_frame *frame = &ctx->s_frame;
424	const struct fimc_dma_offset *offset = &frame->dma_offset;
425	u32 cfg;
426
427	/* Set the pixel offsets. */
428	cfg = (offset->y_v << 16) | offset->y_h;
429	writel(cfg, dev->regs + FIMC_REG_CIIYOFF);
430
431	cfg = (offset->cb_v << 16) | offset->cb_h;
432	writel(cfg, dev->regs + FIMC_REG_CIICBOFF);
433
434	cfg = (offset->cr_v << 16) | offset->cr_h;
435	writel(cfg, dev->regs + FIMC_REG_CIICROFF);
436
437	/* Input original and real size. */
438	fimc_hw_set_in_dma_size(ctx);
439
440	/* Use DMA autoload only in FIFO mode. */
441	fimc_hw_en_autoload(dev, ctx->out_path == FIMC_IO_LCDFIFO);
442
443	/* Set the input DMA to process single frame only. */
444	cfg = readl(dev->regs + FIMC_REG_MSCTRL);
445	cfg &= ~(FIMC_REG_MSCTRL_INFORMAT_MASK
446		 | FIMC_REG_MSCTRL_IN_BURST_COUNT_MASK
447		 | FIMC_REG_MSCTRL_INPUT_MASK
448		 | FIMC_REG_MSCTRL_C_INT_IN_MASK
449		 | FIMC_REG_MSCTRL_2P_IN_ORDER_MASK
450		 | FIMC_REG_MSCTRL_ORDER422_MASK);
451
452	cfg |= (FIMC_REG_MSCTRL_IN_BURST_COUNT(4)
453		| FIMC_REG_MSCTRL_INPUT_MEMORY
454		| FIMC_REG_MSCTRL_FIFO_CTRL_FULL);
455
456	switch (frame->fmt->color) {
457	case FIMC_FMT_RGB565...FIMC_FMT_RGB888:
458		cfg |= FIMC_REG_MSCTRL_INFORMAT_RGB;
459		break;
460	case FIMC_FMT_YCBCR420:
461		cfg |= FIMC_REG_MSCTRL_INFORMAT_YCBCR420;
462
463		if (frame->fmt->colplanes == 2)
464			cfg |= ctx->in_order_2p | FIMC_REG_MSCTRL_C_INT_IN_2PLANE;
465		else
466			cfg |= FIMC_REG_MSCTRL_C_INT_IN_3PLANE;
467
468		break;
469	case FIMC_FMT_YCBYCR422...FIMC_FMT_CRYCBY422:
470		if (frame->fmt->colplanes == 1) {
471			cfg |= ctx->in_order_1p
472				| FIMC_REG_MSCTRL_INFORMAT_YCBCR422_1P;
473		} else {
474			cfg |= FIMC_REG_MSCTRL_INFORMAT_YCBCR422;
475
476			if (frame->fmt->colplanes == 2)
477				cfg |= ctx->in_order_2p
478					| FIMC_REG_MSCTRL_C_INT_IN_2PLANE;
479			else
480				cfg |= FIMC_REG_MSCTRL_C_INT_IN_3PLANE;
481		}
482		break;
483	default:
484		break;
485	}
486
487	writel(cfg, dev->regs + FIMC_REG_MSCTRL);
488
489	/* Input/output DMA linear/tiled mode. */
490	cfg = readl(dev->regs + FIMC_REG_CIDMAPARAM);
491	cfg &= ~FIMC_REG_CIDMAPARAM_TILE_MASK;
492
493	if (tiled_fmt(ctx->s_frame.fmt))
494		cfg |= FIMC_REG_CIDMAPARAM_R_64X32;
495
496	if (tiled_fmt(ctx->d_frame.fmt))
497		cfg |= FIMC_REG_CIDMAPARAM_W_64X32;
498
499	writel(cfg, dev->regs + FIMC_REG_CIDMAPARAM);
500}
501
502
503void fimc_hw_set_input_path(struct fimc_ctx *ctx)
504{
505	struct fimc_dev *dev = ctx->fimc_dev;
506
507	u32 cfg = readl(dev->regs + FIMC_REG_MSCTRL);
508	cfg &= ~FIMC_REG_MSCTRL_INPUT_MASK;
509
510	if (ctx->in_path == FIMC_IO_DMA)
511		cfg |= FIMC_REG_MSCTRL_INPUT_MEMORY;
512	else
513		cfg |= FIMC_REG_MSCTRL_INPUT_EXTCAM;
514
515	writel(cfg, dev->regs + FIMC_REG_MSCTRL);
516}
517
518void fimc_hw_set_output_path(struct fimc_ctx *ctx)
519{
520	struct fimc_dev *dev = ctx->fimc_dev;
521
522	u32 cfg = readl(dev->regs + FIMC_REG_CISCCTRL);
523	cfg &= ~FIMC_REG_CISCCTRL_LCDPATHEN_FIFO;
524	if (ctx->out_path == FIMC_IO_LCDFIFO)
525		cfg |= FIMC_REG_CISCCTRL_LCDPATHEN_FIFO;
526	writel(cfg, dev->regs + FIMC_REG_CISCCTRL);
527}
528
529void fimc_hw_set_input_addr(struct fimc_dev *dev, const struct fimc_addr *addr)
530{
531	u32 cfg = readl(dev->regs + FIMC_REG_CIREAL_ISIZE);
532	cfg |= FIMC_REG_CIREAL_ISIZE_ADDR_CH_DIS;
533	writel(cfg, dev->regs + FIMC_REG_CIREAL_ISIZE);
534
535	writel(addr->y, dev->regs + FIMC_REG_CIIYSA(0));
536	writel(addr->cb, dev->regs + FIMC_REG_CIICBSA(0));
537	writel(addr->cr, dev->regs + FIMC_REG_CIICRSA(0));
538
539	cfg &= ~FIMC_REG_CIREAL_ISIZE_ADDR_CH_DIS;
540	writel(cfg, dev->regs + FIMC_REG_CIREAL_ISIZE);
541}
542
543void fimc_hw_set_output_addr(struct fimc_dev *dev,
544			     const struct fimc_addr *addr, int index)
545{
546	int i = (index == -1) ? 0 : index;
547	do {
548		writel(addr->y, dev->regs + FIMC_REG_CIOYSA(i));
549		writel(addr->cb, dev->regs + FIMC_REG_CIOCBSA(i));
550		writel(addr->cr, dev->regs + FIMC_REG_CIOCRSA(i));
551		dbg("dst_buf[%d]: 0x%X, cb: 0x%X, cr: 0x%X",
552		    i, addr->y, addr->cb, addr->cr);
553	} while (index == -1 && ++i < FIMC_MAX_OUT_BUFS);
554}
555
556int fimc_hw_set_camera_polarity(struct fimc_dev *fimc,
557				const struct fimc_source_info *cam)
558{
559	u32 cfg = readl(fimc->regs + FIMC_REG_CIGCTRL);
560
561	cfg &= ~(FIMC_REG_CIGCTRL_INVPOLPCLK | FIMC_REG_CIGCTRL_INVPOLVSYNC |
562		 FIMC_REG_CIGCTRL_INVPOLHREF | FIMC_REG_CIGCTRL_INVPOLHSYNC |
563		 FIMC_REG_CIGCTRL_INVPOLFIELD);
564
565	if (cam->flags & V4L2_MBUS_PCLK_SAMPLE_FALLING)
566		cfg |= FIMC_REG_CIGCTRL_INVPOLPCLK;
567
568	if (cam->flags & V4L2_MBUS_VSYNC_ACTIVE_LOW)
569		cfg |= FIMC_REG_CIGCTRL_INVPOLVSYNC;
570
571	if (cam->flags & V4L2_MBUS_HSYNC_ACTIVE_LOW)
572		cfg |= FIMC_REG_CIGCTRL_INVPOLHREF;
573
574	if (cam->flags & V4L2_MBUS_HSYNC_ACTIVE_LOW)
575		cfg |= FIMC_REG_CIGCTRL_INVPOLHSYNC;
576
577	if (cam->flags & V4L2_MBUS_FIELD_EVEN_LOW)
578		cfg |= FIMC_REG_CIGCTRL_INVPOLFIELD;
579
580	writel(cfg, fimc->regs + FIMC_REG_CIGCTRL);
581
582	return 0;
583}
584
585struct mbus_pixfmt_desc {
586	u32 pixelcode;
587	u32 cisrcfmt;
588	u16 bus_width;
589};
590
591static const struct mbus_pixfmt_desc pix_desc[] = {
592	{ MEDIA_BUS_FMT_YUYV8_2X8, FIMC_REG_CISRCFMT_ORDER422_YCBYCR, 8 },
593	{ MEDIA_BUS_FMT_YVYU8_2X8, FIMC_REG_CISRCFMT_ORDER422_YCRYCB, 8 },
594	{ MEDIA_BUS_FMT_VYUY8_2X8, FIMC_REG_CISRCFMT_ORDER422_CRYCBY, 8 },
595	{ MEDIA_BUS_FMT_UYVY8_2X8, FIMC_REG_CISRCFMT_ORDER422_CBYCRY, 8 },
596};
597
598int fimc_hw_set_camera_source(struct fimc_dev *fimc,
599			      struct fimc_source_info *source)
600{
601	const struct fimc_vid_cap *vc = &fimc->vid_cap;
602	const struct fimc_frame *f = &vc->ctx->s_frame;
603	u32 bus_width, cfg = 0;
604	int i;
605
606	switch (source->fimc_bus_type) {
607	case FIMC_BUS_TYPE_ITU_601:
608	case FIMC_BUS_TYPE_ITU_656:
609		if (fimc_fmt_is_user_defined(f->fmt->color)) {
610			cfg |= FIMC_REG_CISRCFMT_ITU601_8BIT;
611			break;
612		}
613
614		for (i = 0; i < ARRAY_SIZE(pix_desc); i++) {
615			if (vc->ci_fmt.code == pix_desc[i].pixelcode) {
616				cfg = pix_desc[i].cisrcfmt;
617				bus_width = pix_desc[i].bus_width;
618				break;
619			}
620		}
621
622		if (i == ARRAY_SIZE(pix_desc)) {
623			v4l2_err(&vc->ve.vdev,
624				 "Camera color format not supported: %d\n",
625				 vc->ci_fmt.code);
626			return -EINVAL;
627		}
628
629		if (source->fimc_bus_type == FIMC_BUS_TYPE_ITU_601) {
630			if (bus_width == 8)
631				cfg |= FIMC_REG_CISRCFMT_ITU601_8BIT;
632			else if (bus_width == 16)
633				cfg |= FIMC_REG_CISRCFMT_ITU601_16BIT;
634		} /* else defaults to ITU-R BT.656 8-bit */
635		break;
636	case FIMC_BUS_TYPE_MIPI_CSI2:
637		if (fimc_fmt_is_user_defined(f->fmt->color))
638			cfg |= FIMC_REG_CISRCFMT_ITU601_8BIT;
639		break;
640	default:
641	case FIMC_BUS_TYPE_ISP_WRITEBACK:
642		/* Anything to do here ? */
643		break;
644	}
645
646	cfg |= (f->o_width << 16) | f->o_height;
647	writel(cfg, fimc->regs + FIMC_REG_CISRCFMT);
648	return 0;
649}
650
651void fimc_hw_set_camera_offset(struct fimc_dev *fimc, const struct fimc_frame *f)
652{
653	u32 hoff2, voff2;
654
655	u32 cfg = readl(fimc->regs + FIMC_REG_CIWDOFST);
656
657	cfg &= ~(FIMC_REG_CIWDOFST_HOROFF_MASK | FIMC_REG_CIWDOFST_VEROFF_MASK);
658	cfg |=  FIMC_REG_CIWDOFST_OFF_EN |
659		(f->offs_h << 16) | f->offs_v;
660
661	writel(cfg, fimc->regs + FIMC_REG_CIWDOFST);
662
663	/* See CIWDOFSTn register description in the datasheet for details. */
664	hoff2 = f->o_width - f->width - f->offs_h;
665	voff2 = f->o_height - f->height - f->offs_v;
666	cfg = (hoff2 << 16) | voff2;
667	writel(cfg, fimc->regs + FIMC_REG_CIWDOFST2);
668}
669
670int fimc_hw_set_camera_type(struct fimc_dev *fimc,
671			    const struct fimc_source_info *source)
672{
673	const struct fimc_vid_cap *vid_cap = &fimc->vid_cap;
674	u32 csis_data_alignment = 32;
675	u32 cfg, tmp;
676
677	cfg = readl(fimc->regs + FIMC_REG_CIGCTRL);
678
679	/* Select ITU B interface, disable Writeback path and test pattern. */
680	cfg &= ~(FIMC_REG_CIGCTRL_TESTPAT_MASK | FIMC_REG_CIGCTRL_SELCAM_ITU_A |
681		FIMC_REG_CIGCTRL_SELCAM_MIPI | FIMC_REG_CIGCTRL_CAMIF_SELWB |
682		FIMC_REG_CIGCTRL_SELCAM_MIPI_A | FIMC_REG_CIGCTRL_CAM_JPEG |
683		FIMC_REG_CIGCTRL_SELWB_A);
684
685	switch (source->fimc_bus_type) {
686	case FIMC_BUS_TYPE_MIPI_CSI2:
687		cfg |= FIMC_REG_CIGCTRL_SELCAM_MIPI;
688
689		if (source->mux_id == 0)
690			cfg |= FIMC_REG_CIGCTRL_SELCAM_MIPI_A;
691
692		/* TODO: add remaining supported formats. */
693		switch (vid_cap->ci_fmt.code) {
694		case MEDIA_BUS_FMT_VYUY8_2X8:
695			tmp = FIMC_REG_CSIIMGFMT_YCBCR422_8BIT;
696			break;
697		case MEDIA_BUS_FMT_JPEG_1X8:
698		case MEDIA_BUS_FMT_S5C_UYVY_JPEG_1X8:
699			tmp = FIMC_REG_CSIIMGFMT_USER(1);
700			cfg |= FIMC_REG_CIGCTRL_CAM_JPEG;
701			break;
702		default:
703			v4l2_err(&vid_cap->ve.vdev,
704				 "Not supported camera pixel format: %#x\n",
705				 vid_cap->ci_fmt.code);
706			return -EINVAL;
707		}
708		tmp |= (csis_data_alignment == 32) << 8;
709
710		writel(tmp, fimc->regs + FIMC_REG_CSIIMGFMT);
711		break;
712	case FIMC_BUS_TYPE_ITU_601...FIMC_BUS_TYPE_ITU_656:
713		if (source->mux_id == 0) /* ITU-A, ITU-B: 0, 1 */
714			cfg |= FIMC_REG_CIGCTRL_SELCAM_ITU_A;
715		if (vid_cap->ci_fmt.code == MEDIA_BUS_FMT_JPEG_1X8)
716			cfg |= FIMC_REG_CIGCTRL_CAM_JPEG;
717		break;
718	case FIMC_BUS_TYPE_LCD_WRITEBACK_A:
719		cfg |= FIMC_REG_CIGCTRL_CAMIF_SELWB;
720		fallthrough;
721	case FIMC_BUS_TYPE_ISP_WRITEBACK:
722		if (fimc->variant->has_isp_wb)
723			cfg |= FIMC_REG_CIGCTRL_CAMIF_SELWB;
724		else
725			WARN_ONCE(1, "ISP Writeback input is not supported\n");
726		break;
727	default:
728		v4l2_err(&vid_cap->ve.vdev,
729			 "Invalid FIMC bus type selected: %d\n",
730			 source->fimc_bus_type);
731		return -EINVAL;
732	}
733	writel(cfg, fimc->regs + FIMC_REG_CIGCTRL);
734
735	return 0;
736}
737
738void fimc_hw_clear_irq(struct fimc_dev *dev)
739{
740	u32 cfg = readl(dev->regs + FIMC_REG_CIGCTRL);
741	cfg |= FIMC_REG_CIGCTRL_IRQ_CLR;
742	writel(cfg, dev->regs + FIMC_REG_CIGCTRL);
743}
744
745void fimc_hw_enable_scaler(struct fimc_dev *dev, bool on)
746{
747	u32 cfg = readl(dev->regs + FIMC_REG_CISCCTRL);
748	if (on)
749		cfg |= FIMC_REG_CISCCTRL_SCALERSTART;
750	else
751		cfg &= ~FIMC_REG_CISCCTRL_SCALERSTART;
752	writel(cfg, dev->regs + FIMC_REG_CISCCTRL);
753}
754
755void fimc_hw_activate_input_dma(struct fimc_dev *dev, bool on)
756{
757	u32 cfg = readl(dev->regs + FIMC_REG_MSCTRL);
758	if (on)
759		cfg |= FIMC_REG_MSCTRL_ENVID;
760	else
761		cfg &= ~FIMC_REG_MSCTRL_ENVID;
762	writel(cfg, dev->regs + FIMC_REG_MSCTRL);
763}
764
765/* Return an index to the buffer actually being written. */
766s32 fimc_hw_get_frame_index(struct fimc_dev *dev)
767{
768	s32 reg;
769
770	if (dev->drv_data->cistatus2) {
771		reg = readl(dev->regs + FIMC_REG_CISTATUS2) & 0x3f;
772		return reg - 1;
773	}
774
775	reg = readl(dev->regs + FIMC_REG_CISTATUS);
776
777	return (reg & FIMC_REG_CISTATUS_FRAMECNT_MASK) >>
778		FIMC_REG_CISTATUS_FRAMECNT_SHIFT;
779}
780
781/* Return an index to the buffer being written previously. */
782s32 fimc_hw_get_prev_frame_index(struct fimc_dev *dev)
783{
784	s32 reg;
785
786	if (!dev->drv_data->cistatus2)
787		return -1;
788
789	reg = readl(dev->regs + FIMC_REG_CISTATUS2);
790	return ((reg >> 7) & 0x3f) - 1;
791}
792
793/* Locking: the caller holds fimc->slock */
794void fimc_activate_capture(struct fimc_ctx *ctx)
795{
796	fimc_hw_enable_scaler(ctx->fimc_dev, ctx->scaler.enabled);
797	fimc_hw_enable_capture(ctx);
798}
799
800void fimc_deactivate_capture(struct fimc_dev *fimc)
801{
802	fimc_hw_en_lastirq(fimc, true);
803	fimc_hw_disable_capture(fimc);
804	fimc_hw_enable_scaler(fimc, false);
805	fimc_hw_en_lastirq(fimc, false);
806}
807
808int fimc_hw_camblk_cfg_writeback(struct fimc_dev *fimc)
809{
810	struct regmap *map = fimc->sysreg;
811	unsigned int mask, val, camblk_cfg;
812	int ret;
813
814	if (map == NULL)
815		return 0;
816
817	ret = regmap_read(map, SYSREG_CAMBLK, &camblk_cfg);
818	if (ret < 0 || ((camblk_cfg & 0x00700000) >> 20 != 0x3))
819		return ret;
820
821	if (!WARN(fimc->id >= 3, "not supported id: %d\n", fimc->id))
822		val = 0x1 << (fimc->id + 20);
823	else
824		val = 0;
825
826	mask = SYSREG_CAMBLK_FIFORST_ISP | SYSREG_CAMBLK_ISPWB_FULL_EN;
827	ret = regmap_update_bits(map, SYSREG_CAMBLK, mask, val);
828	if (ret < 0)
829		return ret;
830
831	usleep_range(1000, 2000);
832
833	val |= SYSREG_CAMBLK_FIFORST_ISP;
834	ret = regmap_update_bits(map, SYSREG_CAMBLK, mask, val);
835	if (ret < 0)
836		return ret;
837
838	mask = SYSREG_ISPBLK_FIFORST_CAM_BLK;
839	ret = regmap_update_bits(map, SYSREG_ISPBLK, mask, ~mask);
840	if (ret < 0)
841		return ret;
842
843	usleep_range(1000, 2000);
844
845	return regmap_update_bits(map, SYSREG_ISPBLK, mask, mask);
846}
847