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