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