Commit | Line | Data |
---|---|---|
babde1c2 SN |
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 | ||
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 | ||
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 | */ | |
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 | ||
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] = { | |
27ffaeb0 BB |
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 }, | |
babde1c2 SN |
103 | }; |
104 | ||
105 | /* Set camera input pixel format and resolution */ | |
106 | void camif_hw_set_source_format(struct camif_dev *camif) | |
107 | { | |
108 | struct v4l2_mbus_framefmt *mf = &camif->mbus_fmt; | |
d345a5e5 | 109 | int i; |
babde1c2 SN |
110 | u32 cfg; |
111 | ||
d345a5e5 | 112 | for (i = ARRAY_SIZE(src_pixfmt_map) - 1; i >= 0; i--) { |
babde1c2 SN |
113 | if (src_pixfmt_map[i][0] == mf->code) |
114 | break; | |
115 | } | |
d345a5e5 DC |
116 | if (i < 0) { |
117 | i = 0; | |
babde1c2 SN |
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) */ | |
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 | ||
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 */ | |
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 | ||
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 | ||
c0a566f3 MCC |
217 | pr_debug("dst_buf[%d]: %pad, cb: %pad, cr: %pad\n", |
218 | i, &paddr->y, &paddr->cb, &paddr->cr); | |
babde1c2 SN |
219 | } |
220 | ||
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 | ||
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 | ||
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 | ||
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 | ||
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 | ||
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 | ||
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 | ||
4eb1d01d | 382 | static void camif_s3c244x_hw_set_scaler(struct camif_vp *vp) |
babde1c2 SN |
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 | ||
4eb1d01d | 429 | static void camif_s3c64xx_hw_set_scaler(struct camif_vp *vp) |
babde1c2 SN |
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 | ||
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 | ||
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 | ||
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 | ||
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 | ||
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 | ||
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); | |
99b63ac8 | 604 | dev_info(camif->dev, "%s:\t0x%08x\n", registers[i].name, cfg); |
babde1c2 SN |
605 | } |
606 | } |