diff options
Diffstat (limited to 'drivers/media/platform/exynos4-is/fimc-reg.c')
-rw-r--r-- | drivers/media/platform/exynos4-is/fimc-reg.c | 837 |
1 files changed, 837 insertions, 0 deletions
diff --git a/drivers/media/platform/exynos4-is/fimc-reg.c b/drivers/media/platform/exynos4-is/fimc-reg.c new file mode 100644 index 000000000000..c276eb8e9711 --- /dev/null +++ b/drivers/media/platform/exynos4-is/fimc-reg.c | |||
@@ -0,0 +1,837 @@ | |||
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 | |||
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 | |||
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 | |||
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 | |||
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 | |||
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 | |||
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 | |||
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 | |||
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 | |||
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 | |||
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 | |||
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 | |||
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 | |||
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 | |||
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 | |||
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 | |||
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 | |||
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 | |||
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 | |||
454 | cfg |= (FIMC_REG_MSCTRL_IN_BURST_COUNT(4) | ||
455 | | FIMC_REG_MSCTRL_INPUT_MEMORY | ||
456 | | FIMC_REG_MSCTRL_FIFO_CTRL_FULL); | ||
457 | |||
458 | switch (frame->fmt->color) { | ||
459 | case FIMC_FMT_RGB565...FIMC_FMT_RGB888: | ||
460 | cfg |= FIMC_REG_MSCTRL_INFORMAT_RGB; | ||
461 | break; | ||
462 | case FIMC_FMT_YCBCR420: | ||
463 | cfg |= FIMC_REG_MSCTRL_INFORMAT_YCBCR420; | ||
464 | |||
465 | if (frame->fmt->colplanes == 2) | ||
466 | cfg |= ctx->in_order_2p | FIMC_REG_MSCTRL_C_INT_IN_2PLANE; | ||
467 | else | ||
468 | cfg |= FIMC_REG_MSCTRL_C_INT_IN_3PLANE; | ||
469 | |||
470 | break; | ||
471 | case FIMC_FMT_YCBYCR422...FIMC_FMT_CRYCBY422: | ||
472 | if (frame->fmt->colplanes == 1) { | ||
473 | cfg |= ctx->in_order_1p | ||
474 | | FIMC_REG_MSCTRL_INFORMAT_YCBCR422_1P; | ||
475 | } else { | ||
476 | cfg |= FIMC_REG_MSCTRL_INFORMAT_YCBCR422; | ||
477 | |||
478 | if (frame->fmt->colplanes == 2) | ||
479 | cfg |= ctx->in_order_2p | ||
480 | | FIMC_REG_MSCTRL_C_INT_IN_2PLANE; | ||
481 | else | ||
482 | cfg |= FIMC_REG_MSCTRL_C_INT_IN_3PLANE; | ||
483 | } | ||
484 | break; | ||
485 | default: | ||
486 | break; | ||
487 | } | ||
488 | |||
489 | writel(cfg, dev->regs + FIMC_REG_MSCTRL); | ||
490 | |||
491 | /* Input/output DMA linear/tiled mode. */ | ||
492 | cfg = readl(dev->regs + FIMC_REG_CIDMAPARAM); | ||
493 | cfg &= ~FIMC_REG_CIDMAPARAM_TILE_MASK; | ||
494 | |||
495 | if (tiled_fmt(ctx->s_frame.fmt)) | ||
496 | cfg |= FIMC_REG_CIDMAPARAM_R_64X32; | ||
497 | |||
498 | if (tiled_fmt(ctx->d_frame.fmt)) | ||
499 | cfg |= FIMC_REG_CIDMAPARAM_W_64X32; | ||
500 | |||
501 | writel(cfg, dev->regs + FIMC_REG_CIDMAPARAM); | ||
502 | } | ||
503 | |||
504 | |||
505 | void fimc_hw_set_input_path(struct fimc_ctx *ctx) | ||
506 | { | ||
507 | struct fimc_dev *dev = ctx->fimc_dev; | ||
508 | |||
509 | u32 cfg = readl(dev->regs + FIMC_REG_MSCTRL); | ||
510 | cfg &= ~FIMC_REG_MSCTRL_INPUT_MASK; | ||
511 | |||
512 | if (ctx->in_path == FIMC_IO_DMA) | ||
513 | cfg |= FIMC_REG_MSCTRL_INPUT_MEMORY; | ||
514 | else | ||
515 | cfg |= FIMC_REG_MSCTRL_INPUT_EXTCAM; | ||
516 | |||
517 | writel(cfg, dev->regs + FIMC_REG_MSCTRL); | ||
518 | } | ||
519 | |||
520 | void fimc_hw_set_output_path(struct fimc_ctx *ctx) | ||
521 | { | ||
522 | struct fimc_dev *dev = ctx->fimc_dev; | ||
523 | |||
524 | u32 cfg = readl(dev->regs + FIMC_REG_CISCCTRL); | ||
525 | cfg &= ~FIMC_REG_CISCCTRL_LCDPATHEN_FIFO; | ||
526 | if (ctx->out_path == FIMC_IO_LCDFIFO) | ||
527 | cfg |= FIMC_REG_CISCCTRL_LCDPATHEN_FIFO; | ||
528 | writel(cfg, dev->regs + FIMC_REG_CISCCTRL); | ||
529 | } | ||
530 | |||
531 | void fimc_hw_set_input_addr(struct fimc_dev *dev, struct fimc_addr *paddr) | ||
532 | { | ||
533 | u32 cfg = readl(dev->regs + FIMC_REG_CIREAL_ISIZE); | ||
534 | cfg |= FIMC_REG_CIREAL_ISIZE_ADDR_CH_DIS; | ||
535 | writel(cfg, dev->regs + FIMC_REG_CIREAL_ISIZE); | ||
536 | |||
537 | writel(paddr->y, dev->regs + FIMC_REG_CIIYSA(0)); | ||
538 | writel(paddr->cb, dev->regs + FIMC_REG_CIICBSA(0)); | ||
539 | writel(paddr->cr, dev->regs + FIMC_REG_CIICRSA(0)); | ||
540 | |||
541 | cfg &= ~FIMC_REG_CIREAL_ISIZE_ADDR_CH_DIS; | ||
542 | writel(cfg, dev->regs + FIMC_REG_CIREAL_ISIZE); | ||
543 | } | ||
544 | |||
545 | void fimc_hw_set_output_addr(struct fimc_dev *dev, | ||
546 | struct fimc_addr *paddr, int index) | ||
547 | { | ||
548 | int i = (index == -1) ? 0 : index; | ||
549 | do { | ||
550 | writel(paddr->y, dev->regs + FIMC_REG_CIOYSA(i)); | ||
551 | writel(paddr->cb, dev->regs + FIMC_REG_CIOCBSA(i)); | ||
552 | writel(paddr->cr, dev->regs + FIMC_REG_CIOCRSA(i)); | ||
553 | dbg("dst_buf[%d]: 0x%X, cb: 0x%X, cr: 0x%X", | ||
554 | i, paddr->y, paddr->cb, paddr->cr); | ||
555 | } while (index == -1 && ++i < FIMC_MAX_OUT_BUFS); | ||
556 | } | ||
557 | |||
558 | int fimc_hw_set_camera_polarity(struct fimc_dev *fimc, | ||
559 | struct fimc_source_info *cam) | ||
560 | { | ||
561 | u32 cfg = readl(fimc->regs + FIMC_REG_CIGCTRL); | ||
562 | |||
563 | cfg &= ~(FIMC_REG_CIGCTRL_INVPOLPCLK | FIMC_REG_CIGCTRL_INVPOLVSYNC | | ||
564 | FIMC_REG_CIGCTRL_INVPOLHREF | FIMC_REG_CIGCTRL_INVPOLHSYNC | | ||
565 | FIMC_REG_CIGCTRL_INVPOLFIELD); | ||
566 | |||
567 | if (cam->flags & V4L2_MBUS_PCLK_SAMPLE_FALLING) | ||
568 | cfg |= FIMC_REG_CIGCTRL_INVPOLPCLK; | ||
569 | |||
570 | if (cam->flags & V4L2_MBUS_VSYNC_ACTIVE_LOW) | ||
571 | cfg |= FIMC_REG_CIGCTRL_INVPOLVSYNC; | ||
572 | |||
573 | if (cam->flags & V4L2_MBUS_HSYNC_ACTIVE_LOW) | ||
574 | cfg |= FIMC_REG_CIGCTRL_INVPOLHREF; | ||
575 | |||
576 | if (cam->flags & V4L2_MBUS_HSYNC_ACTIVE_LOW) | ||
577 | cfg |= FIMC_REG_CIGCTRL_INVPOLHSYNC; | ||
578 | |||
579 | if (cam->flags & V4L2_MBUS_FIELD_EVEN_LOW) | ||
580 | cfg |= FIMC_REG_CIGCTRL_INVPOLFIELD; | ||
581 | |||
582 | writel(cfg, fimc->regs + FIMC_REG_CIGCTRL); | ||
583 | |||
584 | return 0; | ||
585 | } | ||
586 | |||
587 | struct mbus_pixfmt_desc { | ||
588 | u32 pixelcode; | ||
589 | u32 cisrcfmt; | ||
590 | u16 bus_width; | ||
591 | }; | ||
592 | |||
593 | static const struct mbus_pixfmt_desc pix_desc[] = { | ||
594 | { V4L2_MBUS_FMT_YUYV8_2X8, FIMC_REG_CISRCFMT_ORDER422_YCBYCR, 8 }, | ||
595 | { V4L2_MBUS_FMT_YVYU8_2X8, FIMC_REG_CISRCFMT_ORDER422_YCRYCB, 8 }, | ||
596 | { V4L2_MBUS_FMT_VYUY8_2X8, FIMC_REG_CISRCFMT_ORDER422_CRYCBY, 8 }, | ||
597 | { V4L2_MBUS_FMT_UYVY8_2X8, FIMC_REG_CISRCFMT_ORDER422_CBYCRY, 8 }, | ||
598 | }; | ||
599 | |||
600 | int fimc_hw_set_camera_source(struct fimc_dev *fimc, | ||
601 | struct fimc_source_info *source) | ||
602 | { | ||
603 | struct fimc_vid_cap *vc = &fimc->vid_cap; | ||
604 | struct fimc_frame *f = &vc->ctx->s_frame; | ||
605 | u32 bus_width, cfg = 0; | ||
606 | int i; | ||
607 | |||
608 | switch (source->fimc_bus_type) { | ||
609 | case FIMC_BUS_TYPE_ITU_601: | ||
610 | case FIMC_BUS_TYPE_ITU_656: | ||
611 | for (i = 0; i < ARRAY_SIZE(pix_desc); i++) { | ||
612 | if (vc->ci_fmt.code == pix_desc[i].pixelcode) { | ||
613 | cfg = pix_desc[i].cisrcfmt; | ||
614 | bus_width = pix_desc[i].bus_width; | ||
615 | break; | ||
616 | } | ||
617 | } | ||
618 | |||
619 | if (i == ARRAY_SIZE(pix_desc)) { | ||
620 | v4l2_err(&vc->vfd, | ||
621 | "Camera color format not supported: %d\n", | ||
622 | vc->ci_fmt.code); | ||
623 | return -EINVAL; | ||
624 | } | ||
625 | |||
626 | if (source->fimc_bus_type == FIMC_BUS_TYPE_ITU_601) { | ||
627 | if (bus_width == 8) | ||
628 | cfg |= FIMC_REG_CISRCFMT_ITU601_8BIT; | ||
629 | else if (bus_width == 16) | ||
630 | cfg |= FIMC_REG_CISRCFMT_ITU601_16BIT; | ||
631 | } /* else defaults to ITU-R BT.656 8-bit */ | ||
632 | break; | ||
633 | case FIMC_BUS_TYPE_MIPI_CSI2: | ||
634 | if (fimc_fmt_is_user_defined(f->fmt->color)) | ||
635 | cfg |= FIMC_REG_CISRCFMT_ITU601_8BIT; | ||
636 | break; | ||
637 | default: | ||
638 | case FIMC_BUS_TYPE_ISP_WRITEBACK: | ||
639 | /* Anything to do here ? */ | ||
640 | break; | ||
641 | } | ||
642 | |||
643 | cfg |= (f->o_width << 16) | f->o_height; | ||
644 | writel(cfg, fimc->regs + FIMC_REG_CISRCFMT); | ||
645 | return 0; | ||
646 | } | ||
647 | |||
648 | void fimc_hw_set_camera_offset(struct fimc_dev *fimc, struct fimc_frame *f) | ||
649 | { | ||
650 | u32 hoff2, voff2; | ||
651 | |||
652 | u32 cfg = readl(fimc->regs + FIMC_REG_CIWDOFST); | ||
653 | |||
654 | cfg &= ~(FIMC_REG_CIWDOFST_HOROFF_MASK | FIMC_REG_CIWDOFST_VEROFF_MASK); | ||
655 | cfg |= FIMC_REG_CIWDOFST_OFF_EN | | ||
656 | (f->offs_h << 16) | f->offs_v; | ||
657 | |||
658 | writel(cfg, fimc->regs + FIMC_REG_CIWDOFST); | ||
659 | |||
660 | /* See CIWDOFSTn register description in the datasheet for details. */ | ||
661 | hoff2 = f->o_width - f->width - f->offs_h; | ||
662 | voff2 = f->o_height - f->height - f->offs_v; | ||
663 | cfg = (hoff2 << 16) | voff2; | ||
664 | writel(cfg, fimc->regs + FIMC_REG_CIWDOFST2); | ||
665 | } | ||
666 | |||
667 | int fimc_hw_set_camera_type(struct fimc_dev *fimc, | ||
668 | struct fimc_source_info *source) | ||
669 | { | ||
670 | struct fimc_vid_cap *vid_cap = &fimc->vid_cap; | ||
671 | u32 csis_data_alignment = 32; | ||
672 | u32 cfg, tmp; | ||
673 | |||
674 | cfg = readl(fimc->regs + FIMC_REG_CIGCTRL); | ||
675 | |||
676 | /* Select ITU B interface, disable Writeback path and test pattern. */ | ||
677 | cfg &= ~(FIMC_REG_CIGCTRL_TESTPAT_MASK | FIMC_REG_CIGCTRL_SELCAM_ITU_A | | ||
678 | FIMC_REG_CIGCTRL_SELCAM_MIPI | FIMC_REG_CIGCTRL_CAMIF_SELWB | | ||
679 | FIMC_REG_CIGCTRL_SELCAM_MIPI_A | FIMC_REG_CIGCTRL_CAM_JPEG | | ||
680 | FIMC_REG_CIGCTRL_SELWB_A); | ||
681 | |||
682 | switch (source->fimc_bus_type) { | ||
683 | case FIMC_BUS_TYPE_MIPI_CSI2: | ||
684 | cfg |= FIMC_REG_CIGCTRL_SELCAM_MIPI; | ||
685 | |||
686 | if (source->mux_id == 0) | ||
687 | cfg |= FIMC_REG_CIGCTRL_SELCAM_MIPI_A; | ||
688 | |||
689 | /* TODO: add remaining supported formats. */ | ||
690 | switch (vid_cap->ci_fmt.code) { | ||
691 | case V4L2_MBUS_FMT_VYUY8_2X8: | ||
692 | tmp = FIMC_REG_CSIIMGFMT_YCBCR422_8BIT; | ||
693 | break; | ||
694 | case V4L2_MBUS_FMT_JPEG_1X8: | ||
695 | case V4L2_MBUS_FMT_S5C_UYVY_JPEG_1X8: | ||
696 | tmp = FIMC_REG_CSIIMGFMT_USER(1); | ||
697 | cfg |= FIMC_REG_CIGCTRL_CAM_JPEG; | ||
698 | break; | ||
699 | default: | ||
700 | v4l2_err(&vid_cap->vfd, | ||
701 | "Not supported camera pixel format: %#x\n", | ||
702 | vid_cap->ci_fmt.code); | ||
703 | return -EINVAL; | ||
704 | } | ||
705 | tmp |= (csis_data_alignment == 32) << 8; | ||
706 | |||
707 | writel(tmp, fimc->regs + FIMC_REG_CSIIMGFMT); | ||
708 | break; | ||
709 | case FIMC_BUS_TYPE_ITU_601...FIMC_BUS_TYPE_ITU_656: | ||
710 | if (source->mux_id == 0) /* ITU-A, ITU-B: 0, 1 */ | ||
711 | cfg |= FIMC_REG_CIGCTRL_SELCAM_ITU_A; | ||
712 | break; | ||
713 | case FIMC_BUS_TYPE_LCD_WRITEBACK_A: | ||
714 | cfg |= FIMC_REG_CIGCTRL_CAMIF_SELWB; | ||
715 | /* fall through */ | ||
716 | case FIMC_BUS_TYPE_ISP_WRITEBACK: | ||
717 | if (fimc->variant->has_isp_wb) | ||
718 | cfg |= FIMC_REG_CIGCTRL_CAMIF_SELWB; | ||
719 | else | ||
720 | WARN_ONCE(1, "ISP Writeback input is not supported\n"); | ||
721 | break; | ||
722 | default: | ||
723 | v4l2_err(&vid_cap->vfd, "Invalid FIMC bus type selected: %d\n", | ||
724 | source->fimc_bus_type); | ||
725 | return -EINVAL; | ||
726 | } | ||
727 | writel(cfg, fimc->regs + FIMC_REG_CIGCTRL); | ||
728 | |||
729 | return 0; | ||
730 | } | ||
731 | |||
732 | void fimc_hw_clear_irq(struct fimc_dev *dev) | ||
733 | { | ||
734 | u32 cfg = readl(dev->regs + FIMC_REG_CIGCTRL); | ||
735 | cfg |= FIMC_REG_CIGCTRL_IRQ_CLR; | ||
736 | writel(cfg, dev->regs + FIMC_REG_CIGCTRL); | ||
737 | } | ||
738 | |||
739 | void fimc_hw_enable_scaler(struct fimc_dev *dev, bool on) | ||
740 | { | ||
741 | u32 cfg = readl(dev->regs + FIMC_REG_CISCCTRL); | ||
742 | if (on) | ||
743 | cfg |= FIMC_REG_CISCCTRL_SCALERSTART; | ||
744 | else | ||
745 | cfg &= ~FIMC_REG_CISCCTRL_SCALERSTART; | ||
746 | writel(cfg, dev->regs + FIMC_REG_CISCCTRL); | ||
747 | } | ||
748 | |||
749 | void fimc_hw_activate_input_dma(struct fimc_dev *dev, bool on) | ||
750 | { | ||
751 | u32 cfg = readl(dev->regs + FIMC_REG_MSCTRL); | ||
752 | if (on) | ||
753 | cfg |= FIMC_REG_MSCTRL_ENVID; | ||
754 | else | ||
755 | cfg &= ~FIMC_REG_MSCTRL_ENVID; | ||
756 | writel(cfg, dev->regs + FIMC_REG_MSCTRL); | ||
757 | } | ||
758 | |||
759 | /* Return an index to the buffer actually being written. */ | ||
760 | s32 fimc_hw_get_frame_index(struct fimc_dev *dev) | ||
761 | { | ||
762 | s32 reg; | ||
763 | |||
764 | if (dev->drv_data->cistatus2) { | ||
765 | reg = readl(dev->regs + FIMC_REG_CISTATUS2) & 0x3f; | ||
766 | return reg - 1; | ||
767 | } | ||
768 | |||
769 | reg = readl(dev->regs + FIMC_REG_CISTATUS); | ||
770 | |||
771 | return (reg & FIMC_REG_CISTATUS_FRAMECNT_MASK) >> | ||
772 | FIMC_REG_CISTATUS_FRAMECNT_SHIFT; | ||
773 | } | ||
774 | |||
775 | /* Return an index to the buffer being written previously. */ | ||
776 | s32 fimc_hw_get_prev_frame_index(struct fimc_dev *dev) | ||
777 | { | ||
778 | s32 reg; | ||
779 | |||
780 | if (!dev->drv_data->cistatus2) | ||
781 | return -1; | ||
782 | |||
783 | reg = readl(dev->regs + FIMC_REG_CISTATUS2); | ||
784 | return ((reg >> 7) & 0x3f) - 1; | ||
785 | } | ||
786 | |||
787 | /* Locking: the caller holds fimc->slock */ | ||
788 | void fimc_activate_capture(struct fimc_ctx *ctx) | ||
789 | { | ||
790 | fimc_hw_enable_scaler(ctx->fimc_dev, ctx->scaler.enabled); | ||
791 | fimc_hw_enable_capture(ctx); | ||
792 | } | ||
793 | |||
794 | void fimc_deactivate_capture(struct fimc_dev *fimc) | ||
795 | { | ||
796 | fimc_hw_en_lastirq(fimc, true); | ||
797 | fimc_hw_disable_capture(fimc); | ||
798 | fimc_hw_enable_scaler(fimc, false); | ||
799 | fimc_hw_en_lastirq(fimc, false); | ||
800 | } | ||
801 | |||
802 | int fimc_hw_camblk_cfg_writeback(struct fimc_dev *fimc) | ||
803 | { | ||
804 | struct regmap *map = fimc->sysreg; | ||
805 | unsigned int mask, val, camblk_cfg; | ||
806 | int ret; | ||
807 | |||
808 | ret = regmap_read(map, SYSREG_CAMBLK, &camblk_cfg); | ||
809 | if (ret < 0 || ((camblk_cfg & 0x00700000) >> 20 != 0x3)) | ||
810 | return ret; | ||
811 | |||
812 | if (!WARN(fimc->id >= 3, "not supported id: %d\n", fimc->id)) | ||
813 | val = 0x1 << (fimc->id + 20); | ||
814 | else | ||
815 | val = 0; | ||
816 | |||
817 | mask = SYSREG_CAMBLK_FIFORST_ISP | SYSREG_CAMBLK_ISPWB_FULL_EN; | ||
818 | ret = regmap_update_bits(map, SYSREG_CAMBLK, mask, val); | ||
819 | if (ret < 0) | ||
820 | return ret; | ||
821 | |||
822 | usleep_range(1000, 2000); | ||
823 | |||
824 | val |= SYSREG_CAMBLK_FIFORST_ISP; | ||
825 | ret = regmap_update_bits(map, SYSREG_CAMBLK, mask, val); | ||
826 | if (ret < 0) | ||
827 | return ret; | ||
828 | |||
829 | mask = SYSREG_ISPBLK_FIFORST_CAM_BLK; | ||
830 | ret = regmap_update_bits(map, SYSREG_ISPBLK, mask, ~mask); | ||
831 | if (ret < 0) | ||
832 | return ret; | ||
833 | |||
834 | usleep_range(1000, 2000); | ||
835 | |||
836 | return regmap_update_bits(map, SYSREG_ISPBLK, mask, mask); | ||
837 | } | ||