• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Samsung s3c24xx/s3c64xx SoC CAMIF driver
3  *
4  * Copyright (C) 2012 Sylwester Nawrocki <sylvester.nawrocki@gmail.com>
5  * Copyright (C) 2012 Tomasz Figa <tomasz.figa@gmail.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 #define pr_fmt(fmt) "%s:%d " fmt, __func__, __LINE__
12 
13 #include <linux/delay.h>
14 #include "camif-regs.h"
15 
16 #define camif_write(_camif, _off, _val)	writel(_val, (_camif)->io_base + (_off))
17 #define camif_read(_camif, _off)	readl((_camif)->io_base + (_off))
18 
camif_hw_reset(struct camif_dev * camif)19 void camif_hw_reset(struct camif_dev *camif)
20 {
21 	u32 cfg;
22 
23 	cfg = camif_read(camif, S3C_CAMIF_REG_CISRCFMT);
24 	cfg |= CISRCFMT_ITU601_8BIT;
25 	camif_write(camif, S3C_CAMIF_REG_CISRCFMT, cfg);
26 
27 	/* S/W reset */
28 	cfg = camif_read(camif, S3C_CAMIF_REG_CIGCTRL);
29 	cfg |= CIGCTRL_SWRST;
30 	if (camif->variant->ip_revision == S3C6410_CAMIF_IP_REV)
31 		cfg |= CIGCTRL_IRQ_LEVEL;
32 	camif_write(camif, S3C_CAMIF_REG_CIGCTRL, cfg);
33 	udelay(10);
34 
35 	cfg = camif_read(camif, S3C_CAMIF_REG_CIGCTRL);
36 	cfg &= ~CIGCTRL_SWRST;
37 	camif_write(camif, S3C_CAMIF_REG_CIGCTRL, cfg);
38 	udelay(10);
39 }
40 
camif_hw_clear_pending_irq(struct camif_vp * vp)41 void camif_hw_clear_pending_irq(struct camif_vp *vp)
42 {
43 	u32 cfg = camif_read(vp->camif, S3C_CAMIF_REG_CIGCTRL);
44 	cfg |= CIGCTRL_IRQ_CLR(vp->id);
45 	camif_write(vp->camif, S3C_CAMIF_REG_CIGCTRL, cfg);
46 }
47 
48 /*
49  * Sets video test pattern (off, color bar, horizontal or vertical gradient).
50  * External sensor pixel clock must be active for the test pattern to work.
51  */
camif_hw_set_test_pattern(struct camif_dev * camif,unsigned int pattern)52 void camif_hw_set_test_pattern(struct camif_dev *camif, unsigned int pattern)
53 {
54 	u32 cfg = camif_read(camif, S3C_CAMIF_REG_CIGCTRL);
55 	cfg &= ~CIGCTRL_TESTPATTERN_MASK;
56 	cfg |= (pattern << 27);
57 	camif_write(camif, S3C_CAMIF_REG_CIGCTRL, cfg);
58 }
59 
camif_hw_set_effect(struct camif_dev * camif,unsigned int effect,unsigned int cr,unsigned int cb)60 void camif_hw_set_effect(struct camif_dev *camif, unsigned int effect,
61 			unsigned int cr, unsigned int cb)
62 {
63 	static const struct v4l2_control colorfx[] = {
64 		{ V4L2_COLORFX_NONE,		CIIMGEFF_FIN_BYPASS },
65 		{ V4L2_COLORFX_BW,		CIIMGEFF_FIN_ARBITRARY },
66 		{ V4L2_COLORFX_SEPIA,		CIIMGEFF_FIN_ARBITRARY },
67 		{ V4L2_COLORFX_NEGATIVE,	CIIMGEFF_FIN_NEGATIVE },
68 		{ V4L2_COLORFX_ART_FREEZE,	CIIMGEFF_FIN_ARTFREEZE },
69 		{ V4L2_COLORFX_EMBOSS,		CIIMGEFF_FIN_EMBOSSING },
70 		{ V4L2_COLORFX_SILHOUETTE,	CIIMGEFF_FIN_SILHOUETTE },
71 		{ V4L2_COLORFX_SET_CBCR,	CIIMGEFF_FIN_ARBITRARY },
72 	};
73 	unsigned int i, cfg;
74 
75 	for (i = 0; i < ARRAY_SIZE(colorfx); i++)
76 		if (colorfx[i].id == effect)
77 			break;
78 
79 	if (i == ARRAY_SIZE(colorfx))
80 		return;
81 
82 	cfg = camif_read(camif, S3C_CAMIF_REG_CIIMGEFF(camif->vp->offset));
83 	/* Set effect */
84 	cfg &= ~CIIMGEFF_FIN_MASK;
85 	cfg |= colorfx[i].value;
86 	/* Set both paths */
87 	if (camif->variant->ip_revision >= S3C6400_CAMIF_IP_REV) {
88 		if (effect == V4L2_COLORFX_NONE)
89 			cfg &= ~CIIMGEFF_IE_ENABLE_MASK;
90 		else
91 			cfg |= CIIMGEFF_IE_ENABLE_MASK;
92 	}
93 	cfg &= ~CIIMGEFF_PAT_CBCR_MASK;
94 	cfg |= cr | (cb << 13);
95 	camif_write(camif, S3C_CAMIF_REG_CIIMGEFF(camif->vp->offset), cfg);
96 }
97 
98 static const u32 src_pixfmt_map[8][2] = {
99 	{ MEDIA_BUS_FMT_YUYV8_2X8, CISRCFMT_ORDER422_YCBYCR },
100 	{ MEDIA_BUS_FMT_YVYU8_2X8, CISRCFMT_ORDER422_YCRYCB },
101 	{ MEDIA_BUS_FMT_UYVY8_2X8, CISRCFMT_ORDER422_CBYCRY },
102 	{ MEDIA_BUS_FMT_VYUY8_2X8, CISRCFMT_ORDER422_CRYCBY },
103 };
104 
105 /* Set camera input pixel format and resolution */
camif_hw_set_source_format(struct camif_dev * camif)106 void camif_hw_set_source_format(struct camif_dev *camif)
107 {
108 	struct v4l2_mbus_framefmt *mf = &camif->mbus_fmt;
109 	int i;
110 	u32 cfg;
111 
112 	for (i = ARRAY_SIZE(src_pixfmt_map) - 1; i >= 0; i--) {
113 		if (src_pixfmt_map[i][0] == mf->code)
114 			break;
115 	}
116 	if (i < 0) {
117 		i = 0;
118 		dev_err(camif->dev,
119 			"Unsupported pixel code, falling back to %#08x\n",
120 			src_pixfmt_map[i][0]);
121 	}
122 
123 	cfg = camif_read(camif, S3C_CAMIF_REG_CISRCFMT);
124 	cfg &= ~(CISRCFMT_ORDER422_MASK | CISRCFMT_SIZE_CAM_MASK);
125 	cfg |= (mf->width << 16) | mf->height;
126 	cfg |= src_pixfmt_map[i][1];
127 	camif_write(camif, S3C_CAMIF_REG_CISRCFMT, cfg);
128 }
129 
130 /* Set the camera host input window offsets (cropping) */
camif_hw_set_camera_crop(struct camif_dev * camif)131 void camif_hw_set_camera_crop(struct camif_dev *camif)
132 {
133 	struct v4l2_mbus_framefmt *mf = &camif->mbus_fmt;
134 	struct v4l2_rect *crop = &camif->camif_crop;
135 	u32 hoff2, voff2;
136 	u32 cfg;
137 
138 	/* Note: s3c244x requirement: left = f_width - rect.width / 2 */
139 	cfg = camif_read(camif, S3C_CAMIF_REG_CIWDOFST);
140 	cfg &= ~(CIWDOFST_OFST_MASK | CIWDOFST_WINOFSEN);
141 	cfg |= (crop->left << 16) | crop->top;
142 	if (crop->left != 0 || crop->top != 0)
143 		cfg |= CIWDOFST_WINOFSEN;
144 	camif_write(camif, S3C_CAMIF_REG_CIWDOFST, cfg);
145 
146 	if (camif->variant->ip_revision == S3C6410_CAMIF_IP_REV) {
147 		hoff2 = mf->width - crop->width - crop->left;
148 		voff2 = mf->height - crop->height - crop->top;
149 		cfg = (hoff2 << 16) | voff2;
150 		camif_write(camif, S3C_CAMIF_REG_CIWDOFST2, cfg);
151 	}
152 }
153 
camif_hw_clear_fifo_overflow(struct camif_vp * vp)154 void camif_hw_clear_fifo_overflow(struct camif_vp *vp)
155 {
156 	struct camif_dev *camif = vp->camif;
157 	u32 cfg;
158 
159 	cfg = camif_read(camif, S3C_CAMIF_REG_CIWDOFST);
160 	if (vp->id == 0)
161 		cfg |= (CIWDOFST_CLROVCOFIY | CIWDOFST_CLROVCOFICB |
162 			CIWDOFST_CLROVCOFICR);
163 	else
164 		cfg |= (/* CIWDOFST_CLROVPRFIY | */ CIWDOFST_CLROVPRFICB |
165 			CIWDOFST_CLROVPRFICR);
166 	camif_write(camif, S3C_CAMIF_REG_CIWDOFST, cfg);
167 }
168 
169 /* Set video bus signals polarity */
camif_hw_set_camera_bus(struct camif_dev * camif)170 void camif_hw_set_camera_bus(struct camif_dev *camif)
171 {
172 	unsigned int flags = camif->pdata.sensor.flags;
173 
174 	u32 cfg = camif_read(camif, S3C_CAMIF_REG_CIGCTRL);
175 
176 	cfg &= ~(CIGCTRL_INVPOLPCLK | CIGCTRL_INVPOLVSYNC |
177 		 CIGCTRL_INVPOLHREF | CIGCTRL_INVPOLFIELD);
178 
179 	if (flags & V4L2_MBUS_PCLK_SAMPLE_FALLING)
180 		cfg |= CIGCTRL_INVPOLPCLK;
181 
182 	if (flags & V4L2_MBUS_VSYNC_ACTIVE_LOW)
183 		cfg |= CIGCTRL_INVPOLVSYNC;
184 	/*
185 	 * HREF is normally high during frame active data
186 	 * transmission and low during horizontal synchronization
187 	 * period. Thus HREF active high means HSYNC active low.
188 	 */
189 	if (flags & V4L2_MBUS_HSYNC_ACTIVE_HIGH)
190 		cfg |= CIGCTRL_INVPOLHREF; /* HREF active low */
191 
192 	if (camif->variant->ip_revision == S3C6410_CAMIF_IP_REV) {
193 		if (flags & V4L2_MBUS_FIELD_EVEN_LOW)
194 			cfg |= CIGCTRL_INVPOLFIELD;
195 		cfg |= CIGCTRL_FIELDMODE;
196 	}
197 
198 	pr_debug("Setting CIGCTRL to: %#x\n", cfg);
199 
200 	camif_write(camif, S3C_CAMIF_REG_CIGCTRL, cfg);
201 }
202 
camif_hw_set_output_addr(struct camif_vp * vp,struct camif_addr * paddr,int i)203 void camif_hw_set_output_addr(struct camif_vp *vp,
204 			      struct camif_addr *paddr, int i)
205 {
206 	struct camif_dev *camif = vp->camif;
207 
208 	camif_write(camif, S3C_CAMIF_REG_CIYSA(vp->id, i), paddr->y);
209 	if (camif->variant->ip_revision == S3C6410_CAMIF_IP_REV
210 		|| vp->id == VP_CODEC) {
211 		camif_write(camif, S3C_CAMIF_REG_CICBSA(vp->id, i),
212 								paddr->cb);
213 		camif_write(camif, S3C_CAMIF_REG_CICRSA(vp->id, i),
214 								paddr->cr);
215 	}
216 
217 	pr_debug("dst_buf[%d]: %pad, cb: %pad, cr: %pad\n",
218 		 i, &paddr->y, &paddr->cb, &paddr->cr);
219 }
220 
camif_hw_set_out_dma_size(struct camif_vp * vp)221 static void camif_hw_set_out_dma_size(struct camif_vp *vp)
222 {
223 	struct camif_frame *frame = &vp->out_frame;
224 	u32 cfg;
225 
226 	cfg = camif_read(vp->camif, S3C_CAMIF_REG_CITRGFMT(vp->id, vp->offset));
227 	cfg &= ~CITRGFMT_TARGETSIZE_MASK;
228 	cfg |= (frame->f_width << 16) | frame->f_height;
229 	camif_write(vp->camif, S3C_CAMIF_REG_CITRGFMT(vp->id, vp->offset), cfg);
230 }
231 
camif_get_dma_burst(u32 width,u32 ybpp,u32 * mburst,u32 * rburst)232 static void camif_get_dma_burst(u32 width, u32 ybpp, u32 *mburst, u32 *rburst)
233 {
234 	unsigned int nwords = width * ybpp / 4;
235 	unsigned int div, rem;
236 
237 	if (WARN_ON(width < 8 || (width * ybpp) & 7))
238 		return;
239 
240 	for (div = 16; div >= 2; div /= 2) {
241 		if (nwords < div)
242 			continue;
243 
244 		rem = nwords & (div - 1);
245 		if (rem == 0) {
246 			*mburst = div;
247 			*rburst = div;
248 			break;
249 		}
250 		if (rem == div / 2 || rem == div / 4) {
251 			*mburst = div;
252 			*rburst = rem;
253 			break;
254 		}
255 	}
256 }
257 
camif_hw_set_output_dma(struct camif_vp * vp)258 void camif_hw_set_output_dma(struct camif_vp *vp)
259 {
260 	struct camif_dev *camif = vp->camif;
261 	struct camif_frame *frame = &vp->out_frame;
262 	const struct camif_fmt *fmt = vp->out_fmt;
263 	unsigned int ymburst = 0, yrburst = 0;
264 	u32 cfg;
265 
266 	camif_hw_set_out_dma_size(vp);
267 
268 	if (camif->variant->ip_revision == S3C6410_CAMIF_IP_REV) {
269 		struct camif_dma_offset *offset = &frame->dma_offset;
270 		/* Set the input dma offsets. */
271 		cfg = S3C_CISS_OFFS_INITIAL(offset->initial);
272 		cfg |= S3C_CISS_OFFS_LINE(offset->line);
273 		camif_write(camif, S3C_CAMIF_REG_CISSY(vp->id), cfg);
274 		camif_write(camif, S3C_CAMIF_REG_CISSCB(vp->id), cfg);
275 		camif_write(camif, S3C_CAMIF_REG_CISSCR(vp->id), cfg);
276 	}
277 
278 	/* Configure DMA burst values */
279 	camif_get_dma_burst(frame->rect.width, fmt->ybpp, &ymburst, &yrburst);
280 
281 	cfg = camif_read(camif, S3C_CAMIF_REG_CICTRL(vp->id, vp->offset));
282 	cfg &= ~CICTRL_BURST_MASK;
283 
284 	cfg |= CICTRL_YBURST1(ymburst) | CICTRL_YBURST2(yrburst);
285 	cfg |= CICTRL_CBURST1(ymburst / 2) | CICTRL_CBURST2(yrburst / 2);
286 
287 	camif_write(camif, S3C_CAMIF_REG_CICTRL(vp->id, vp->offset), cfg);
288 
289 	pr_debug("ymburst: %u, yrburst: %u\n", ymburst, yrburst);
290 }
291 
camif_hw_set_input_path(struct camif_vp * vp)292 void camif_hw_set_input_path(struct camif_vp *vp)
293 {
294 	u32 cfg = camif_read(vp->camif, S3C_CAMIF_REG_MSCTRL(vp->id));
295 	cfg &= ~MSCTRL_SEL_DMA_CAM;
296 	camif_write(vp->camif, S3C_CAMIF_REG_MSCTRL(vp->id), cfg);
297 }
298 
camif_hw_set_target_format(struct camif_vp * vp)299 void camif_hw_set_target_format(struct camif_vp *vp)
300 {
301 	struct camif_dev *camif = vp->camif;
302 	struct camif_frame *frame = &vp->out_frame;
303 	u32 cfg;
304 
305 	pr_debug("fw: %d, fh: %d color: %d\n", frame->f_width,
306 		 frame->f_height, vp->out_fmt->color);
307 
308 	cfg = camif_read(camif, S3C_CAMIF_REG_CITRGFMT(vp->id, vp->offset));
309 	cfg &= ~CITRGFMT_TARGETSIZE_MASK;
310 
311 	if (camif->variant->ip_revision == S3C244X_CAMIF_IP_REV) {
312 		/* We currently support only YCbCr 4:2:2 at the camera input */
313 		cfg |= CITRGFMT_IN422;
314 		cfg &= ~CITRGFMT_OUT422;
315 		if (vp->out_fmt->color == IMG_FMT_YCBCR422P)
316 			cfg |= CITRGFMT_OUT422;
317 	} else {
318 		cfg &= ~CITRGFMT_OUTFORMAT_MASK;
319 		switch (vp->out_fmt->color) {
320 		case IMG_FMT_RGB565...IMG_FMT_XRGB8888:
321 			cfg |= CITRGFMT_OUTFORMAT_RGB;
322 			break;
323 		case IMG_FMT_YCBCR420...IMG_FMT_YCRCB420:
324 			cfg |= CITRGFMT_OUTFORMAT_YCBCR420;
325 			break;
326 		case IMG_FMT_YCBCR422P:
327 			cfg |= CITRGFMT_OUTFORMAT_YCBCR422;
328 			break;
329 		case IMG_FMT_YCBYCR422...IMG_FMT_CRYCBY422:
330 			cfg |= CITRGFMT_OUTFORMAT_YCBCR422I;
331 			break;
332 		}
333 	}
334 
335 	/* Rotation is only supported by s3c64xx */
336 	if (vp->rotation == 90 || vp->rotation == 270)
337 		cfg |= (frame->f_height << 16) | frame->f_width;
338 	else
339 		cfg |= (frame->f_width << 16) | frame->f_height;
340 	camif_write(camif, S3C_CAMIF_REG_CITRGFMT(vp->id, vp->offset), cfg);
341 
342 	/* Target area, output pixel width * height */
343 	cfg = camif_read(camif, S3C_CAMIF_REG_CITAREA(vp->id, vp->offset));
344 	cfg &= ~CITAREA_MASK;
345 	cfg |= (frame->f_width * frame->f_height);
346 	camif_write(camif, S3C_CAMIF_REG_CITAREA(vp->id, vp->offset), cfg);
347 }
348 
camif_hw_set_flip(struct camif_vp * vp)349 void camif_hw_set_flip(struct camif_vp *vp)
350 {
351 	u32 cfg = camif_read(vp->camif,
352 				S3C_CAMIF_REG_CITRGFMT(vp->id, vp->offset));
353 
354 	cfg &= ~CITRGFMT_FLIP_MASK;
355 
356 	if (vp->hflip)
357 		cfg |= CITRGFMT_FLIP_Y_MIRROR;
358 	if (vp->vflip)
359 		cfg |= CITRGFMT_FLIP_X_MIRROR;
360 
361 	camif_write(vp->camif, S3C_CAMIF_REG_CITRGFMT(vp->id, vp->offset), cfg);
362 }
363 
camif_hw_set_prescaler(struct camif_vp * vp)364 static void camif_hw_set_prescaler(struct camif_vp *vp)
365 {
366 	struct camif_dev *camif = vp->camif;
367 	struct camif_scaler *sc = &vp->scaler;
368 	u32 cfg, shfactor, addr;
369 
370 	addr = S3C_CAMIF_REG_CISCPRERATIO(vp->id, vp->offset);
371 
372 	shfactor = 10 - (sc->h_shift + sc->v_shift);
373 	cfg = shfactor << 28;
374 
375 	cfg |= (sc->pre_h_ratio << 16) | sc->pre_v_ratio;
376 	camif_write(camif, addr, cfg);
377 
378 	cfg = (sc->pre_dst_width << 16) | sc->pre_dst_height;
379 	camif_write(camif, S3C_CAMIF_REG_CISCPREDST(vp->id, vp->offset), cfg);
380 }
381 
camif_s3c244x_hw_set_scaler(struct camif_vp * vp)382 static void camif_s3c244x_hw_set_scaler(struct camif_vp *vp)
383 {
384 	struct camif_dev *camif = vp->camif;
385 	struct camif_scaler *scaler = &vp->scaler;
386 	unsigned int color = vp->out_fmt->color;
387 	u32 cfg;
388 
389 	camif_hw_set_prescaler(vp);
390 
391 	cfg = camif_read(camif, S3C_CAMIF_REG_CISCCTRL(vp->id, vp->offset));
392 
393 	cfg &= ~(CISCCTRL_SCALEUP_MASK | CISCCTRL_SCALERBYPASS |
394 		 CISCCTRL_MAIN_RATIO_MASK | CIPRSCCTRL_RGB_FORMAT_24BIT);
395 
396 	if (scaler->enable) {
397 		if (scaler->scaleup_h) {
398 			if (vp->id == VP_CODEC)
399 				cfg |= CISCCTRL_SCALEUP_H;
400 			else
401 				cfg |= CIPRSCCTRL_SCALEUP_H;
402 		}
403 		if (scaler->scaleup_v) {
404 			if (vp->id == VP_CODEC)
405 				cfg |= CISCCTRL_SCALEUP_V;
406 			else
407 				cfg |= CIPRSCCTRL_SCALEUP_V;
408 		}
409 	} else {
410 		if (vp->id == VP_CODEC)
411 			cfg |= CISCCTRL_SCALERBYPASS;
412 	}
413 
414 	cfg |= ((scaler->main_h_ratio & 0x1ff) << 16);
415 	cfg |= scaler->main_v_ratio & 0x1ff;
416 
417 	if (vp->id == VP_PREVIEW) {
418 		if (color == IMG_FMT_XRGB8888)
419 			cfg |= CIPRSCCTRL_RGB_FORMAT_24BIT;
420 		cfg |= CIPRSCCTRL_SAMPLE;
421 	}
422 
423 	camif_write(camif, S3C_CAMIF_REG_CISCCTRL(vp->id, vp->offset), cfg);
424 
425 	pr_debug("main: h_ratio: %#x, v_ratio: %#x",
426 		 scaler->main_h_ratio, scaler->main_v_ratio);
427 }
428 
camif_s3c64xx_hw_set_scaler(struct camif_vp * vp)429 static void camif_s3c64xx_hw_set_scaler(struct camif_vp *vp)
430 {
431 	struct camif_dev *camif = vp->camif;
432 	struct camif_scaler *scaler = &vp->scaler;
433 	unsigned int color = vp->out_fmt->color;
434 	u32 cfg;
435 
436 	camif_hw_set_prescaler(vp);
437 
438 	cfg = camif_read(camif, S3C_CAMIF_REG_CISCCTRL(vp->id, vp->offset));
439 
440 	cfg &= ~(CISCCTRL_CSCR2Y_WIDE | CISCCTRL_CSCY2R_WIDE
441 		| CISCCTRL_SCALEUP_H | CISCCTRL_SCALEUP_V
442 		| CISCCTRL_SCALERBYPASS | CISCCTRL_ONE2ONE
443 		| CISCCTRL_INRGB_FMT_MASK | CISCCTRL_OUTRGB_FMT_MASK
444 		| CISCCTRL_INTERLACE | CISCCTRL_EXTRGB_EXTENSION
445 		| CISCCTRL_MAIN_RATIO_MASK);
446 
447 	cfg |= (CISCCTRL_CSCR2Y_WIDE | CISCCTRL_CSCY2R_WIDE);
448 
449 	if (!scaler->enable) {
450 		cfg |= CISCCTRL_SCALERBYPASS;
451 	} else {
452 		if (scaler->scaleup_h)
453 			cfg |= CISCCTRL_SCALEUP_H;
454 		if (scaler->scaleup_v)
455 			cfg |= CISCCTRL_SCALEUP_V;
456 		if (scaler->copy)
457 			cfg |= CISCCTRL_ONE2ONE;
458 	}
459 
460 	switch (color) {
461 	case IMG_FMT_RGB666:
462 		cfg |= CISCCTRL_OUTRGB_FMT_RGB666;
463 		break;
464 	case IMG_FMT_XRGB8888:
465 		cfg |= CISCCTRL_OUTRGB_FMT_RGB888;
466 		break;
467 	}
468 
469 	cfg |= (scaler->main_h_ratio & 0x1ff) << 16;
470 	cfg |= scaler->main_v_ratio & 0x1ff;
471 
472 	camif_write(camif, S3C_CAMIF_REG_CISCCTRL(vp->id, vp->offset), cfg);
473 
474 	pr_debug("main: h_ratio: %#x, v_ratio: %#x",
475 		 scaler->main_h_ratio, scaler->main_v_ratio);
476 }
477 
camif_hw_set_scaler(struct camif_vp * vp)478 void camif_hw_set_scaler(struct camif_vp *vp)
479 {
480 	unsigned int ip_rev = vp->camif->variant->ip_revision;
481 
482 	if (ip_rev == S3C244X_CAMIF_IP_REV)
483 		camif_s3c244x_hw_set_scaler(vp);
484 	else
485 		camif_s3c64xx_hw_set_scaler(vp);
486 }
487 
camif_hw_enable_scaler(struct camif_vp * vp,bool on)488 void camif_hw_enable_scaler(struct camif_vp *vp, bool on)
489 {
490 	u32 addr = S3C_CAMIF_REG_CISCCTRL(vp->id, vp->offset);
491 	u32 cfg;
492 
493 	cfg = camif_read(vp->camif, addr);
494 	if (on)
495 		cfg |= CISCCTRL_SCALERSTART;
496 	else
497 		cfg &= ~CISCCTRL_SCALERSTART;
498 	camif_write(vp->camif, addr, cfg);
499 }
500 
camif_hw_set_lastirq(struct camif_vp * vp,int enable)501 void camif_hw_set_lastirq(struct camif_vp *vp, int enable)
502 {
503 	u32 addr = S3C_CAMIF_REG_CICTRL(vp->id, vp->offset);
504 	u32 cfg;
505 
506 	cfg = camif_read(vp->camif, addr);
507 	if (enable)
508 		cfg |= CICTRL_LASTIRQ_ENABLE;
509 	else
510 		cfg &= ~CICTRL_LASTIRQ_ENABLE;
511 	camif_write(vp->camif, addr, cfg);
512 }
513 
camif_hw_enable_capture(struct camif_vp * vp)514 void camif_hw_enable_capture(struct camif_vp *vp)
515 {
516 	struct camif_dev *camif = vp->camif;
517 	u32 cfg;
518 
519 	cfg = camif_read(camif, S3C_CAMIF_REG_CIIMGCPT(vp->offset));
520 	camif->stream_count++;
521 
522 	if (camif->variant->ip_revision == S3C6410_CAMIF_IP_REV)
523 		cfg |= CIIMGCPT_CPT_FREN_ENABLE(vp->id);
524 
525 	if (vp->scaler.enable)
526 		cfg |= CIIMGCPT_IMGCPTEN_SC(vp->id);
527 
528 	if (camif->stream_count == 1)
529 		cfg |= CIIMGCPT_IMGCPTEN;
530 
531 	camif_write(camif, S3C_CAMIF_REG_CIIMGCPT(vp->offset), cfg);
532 
533 	pr_debug("CIIMGCPT: %#x, camif->stream_count: %d\n",
534 		 cfg, camif->stream_count);
535 }
536 
camif_hw_disable_capture(struct camif_vp * vp)537 void camif_hw_disable_capture(struct camif_vp *vp)
538 {
539 	struct camif_dev *camif = vp->camif;
540 	u32 cfg;
541 
542 	cfg = camif_read(camif, S3C_CAMIF_REG_CIIMGCPT(vp->offset));
543 	cfg &= ~CIIMGCPT_IMGCPTEN_SC(vp->id);
544 
545 	if (WARN_ON(--(camif->stream_count) < 0))
546 		camif->stream_count = 0;
547 
548 	if (camif->stream_count == 0)
549 		cfg &= ~CIIMGCPT_IMGCPTEN;
550 
551 	pr_debug("CIIMGCPT: %#x, camif->stream_count: %d\n",
552 		 cfg, camif->stream_count);
553 
554 	camif_write(camif, S3C_CAMIF_REG_CIIMGCPT(vp->offset), cfg);
555 }
556 
camif_hw_dump_regs(struct camif_dev * camif,const char * label)557 void camif_hw_dump_regs(struct camif_dev *camif, const char *label)
558 {
559 	struct {
560 		u32 offset;
561 		const char * const name;
562 	} registers[] = {
563 		{ S3C_CAMIF_REG_CISRCFMT,		"CISRCFMT" },
564 		{ S3C_CAMIF_REG_CIWDOFST,		"CIWDOFST" },
565 		{ S3C_CAMIF_REG_CIGCTRL,		"CIGCTRL" },
566 		{ S3C_CAMIF_REG_CIWDOFST2,		"CIWDOFST2" },
567 		{ S3C_CAMIF_REG_CIYSA(0, 0),		"CICOYSA0" },
568 		{ S3C_CAMIF_REG_CICBSA(0, 0),		"CICOCBSA0" },
569 		{ S3C_CAMIF_REG_CICRSA(0, 0),		"CICOCRSA0" },
570 		{ S3C_CAMIF_REG_CIYSA(0, 1),		"CICOYSA1" },
571 		{ S3C_CAMIF_REG_CICBSA(0, 1),		"CICOCBSA1" },
572 		{ S3C_CAMIF_REG_CICRSA(0, 1),		"CICOCRSA1" },
573 		{ S3C_CAMIF_REG_CIYSA(0, 2),		"CICOYSA2" },
574 		{ S3C_CAMIF_REG_CICBSA(0, 2),		"CICOCBSA2" },
575 		{ S3C_CAMIF_REG_CICRSA(0, 2),		"CICOCRSA2" },
576 		{ S3C_CAMIF_REG_CIYSA(0, 3),		"CICOYSA3" },
577 		{ S3C_CAMIF_REG_CICBSA(0, 3),		"CICOCBSA3" },
578 		{ S3C_CAMIF_REG_CICRSA(0, 3),		"CICOCRSA3" },
579 		{ S3C_CAMIF_REG_CIYSA(1, 0),		"CIPRYSA0" },
580 		{ S3C_CAMIF_REG_CIYSA(1, 1),		"CIPRYSA1" },
581 		{ S3C_CAMIF_REG_CIYSA(1, 2),		"CIPRYSA2" },
582 		{ S3C_CAMIF_REG_CIYSA(1, 3),		"CIPRYSA3" },
583 		{ S3C_CAMIF_REG_CITRGFMT(0, 0),		"CICOTRGFMT" },
584 		{ S3C_CAMIF_REG_CITRGFMT(1, 0),		"CIPRTRGFMT" },
585 		{ S3C_CAMIF_REG_CICTRL(0, 0),		"CICOCTRL" },
586 		{ S3C_CAMIF_REG_CICTRL(1, 0),		"CIPRCTRL" },
587 		{ S3C_CAMIF_REG_CISCPREDST(0, 0),	"CICOSCPREDST" },
588 		{ S3C_CAMIF_REG_CISCPREDST(1, 0),	"CIPRSCPREDST" },
589 		{ S3C_CAMIF_REG_CISCPRERATIO(0, 0),	"CICOSCPRERATIO" },
590 		{ S3C_CAMIF_REG_CISCPRERATIO(1, 0),	"CIPRSCPRERATIO" },
591 		{ S3C_CAMIF_REG_CISCCTRL(0, 0),		"CICOSCCTRL" },
592 		{ S3C_CAMIF_REG_CISCCTRL(1, 0),		"CIPRSCCTRL" },
593 		{ S3C_CAMIF_REG_CITAREA(0, 0),		"CICOTAREA" },
594 		{ S3C_CAMIF_REG_CITAREA(1, 0),		"CIPRTAREA" },
595 		{ S3C_CAMIF_REG_CISTATUS(0, 0),		"CICOSTATUS" },
596 		{ S3C_CAMIF_REG_CISTATUS(1, 0),		"CIPRSTATUS" },
597 		{ S3C_CAMIF_REG_CIIMGCPT(0),		"CIIMGCPT" },
598 	};
599 	u32 i;
600 
601 	pr_info("--- %s ---\n", label);
602 	for (i = 0; i < ARRAY_SIZE(registers); i++) {
603 		u32 cfg = readl(camif->io_base + registers[i].offset);
604 		dev_info(camif->dev, "%s:\t0x%08x\n", registers[i].name, cfg);
605 	}
606 }
607