1/*
2 * Register interface file for Samsung Camera Interface (FIMC) driver
3 *
4 * Copyright (c) 2010 Samsung Electronics
5 *
6 * Sylwester Nawrocki, s.nawrocki@samsung.com
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11*/
12
13#include <linux/io.h>
14#include <linux/delay.h>
15#include <mach/map.h>
16#include <media/s5p_fimc.h>
17
18#include "fimc-core.h"
19
20
21void fimc_hw_reset(struct fimc_dev *dev)
22{
23	u32 cfg;
24
25	cfg = readl(dev->regs + S5P_CISRCFMT);
26	cfg |= S5P_CISRCFMT_ITU601_8BIT;
27	writel(cfg, dev->regs + S5P_CISRCFMT);
28
29	/* Software reset. */
30	cfg = readl(dev->regs + S5P_CIGCTRL);
31	cfg |= (S5P_CIGCTRL_SWRST | S5P_CIGCTRL_IRQ_LEVEL);
32	writel(cfg, dev->regs + S5P_CIGCTRL);
33	udelay(10);
34
35	cfg = readl(dev->regs + S5P_CIGCTRL);
36	cfg &= ~S5P_CIGCTRL_SWRST;
37	writel(cfg, dev->regs + S5P_CIGCTRL);
38
39	if (dev->variant->out_buf_count > 4)
40		fimc_hw_set_dma_seq(dev, 0xF);
41}
42
43static u32 fimc_hw_get_in_flip(struct fimc_ctx *ctx)
44{
45	u32 flip = S5P_MSCTRL_FLIP_NORMAL;
46
47	if (ctx->hflip)
48		flip = S5P_MSCTRL_FLIP_X_MIRROR;
49	if (ctx->vflip)
50		flip = S5P_MSCTRL_FLIP_Y_MIRROR;
51
52	if (ctx->rotation <= 90)
53		return flip;
54
55	return (flip ^ S5P_MSCTRL_FLIP_180) & S5P_MSCTRL_FLIP_180;
56}
57
58static u32 fimc_hw_get_target_flip(struct fimc_ctx *ctx)
59{
60	u32 flip = S5P_CITRGFMT_FLIP_NORMAL;
61
62	if (ctx->hflip)
63		flip |= S5P_CITRGFMT_FLIP_X_MIRROR;
64	if (ctx->vflip)
65		flip |= S5P_CITRGFMT_FLIP_Y_MIRROR;
66
67	if (ctx->rotation <= 90)
68		return flip;
69
70	return (flip ^ S5P_CITRGFMT_FLIP_180) & S5P_CITRGFMT_FLIP_180;
71}
72
73void fimc_hw_set_rotation(struct fimc_ctx *ctx)
74{
75	u32 cfg, flip;
76	struct fimc_dev *dev = ctx->fimc_dev;
77
78	cfg = readl(dev->regs + S5P_CITRGFMT);
79	cfg &= ~(S5P_CITRGFMT_INROT90 | S5P_CITRGFMT_OUTROT90 |
80		 S5P_CITRGFMT_FLIP_180);
81
82	/*
83	 * The input and output rotator cannot work simultaneously.
84	 * Use the output rotator in output DMA mode or the input rotator
85	 * in direct fifo output mode.
86	 */
87	if (ctx->rotation == 90 || ctx->rotation == 270) {
88		if (ctx->out_path == FIMC_LCDFIFO)
89			cfg |= S5P_CITRGFMT_INROT90;
90		else
91			cfg |= S5P_CITRGFMT_OUTROT90;
92	}
93
94	if (ctx->out_path == FIMC_DMA) {
95		cfg |= fimc_hw_get_target_flip(ctx);
96		writel(cfg, dev->regs + S5P_CITRGFMT);
97	} else {
98		/* LCD FIFO path */
99		flip = readl(dev->regs + S5P_MSCTRL);
100		flip &= ~S5P_MSCTRL_FLIP_MASK;
101		flip |= fimc_hw_get_in_flip(ctx);
102		writel(flip, dev->regs + S5P_MSCTRL);
103	}
104}
105
106void fimc_hw_set_target_format(struct fimc_ctx *ctx)
107{
108	u32 cfg;
109	struct fimc_dev *dev = ctx->fimc_dev;
110	struct fimc_frame *frame = &ctx->d_frame;
111
112	dbg("w= %d, h= %d color: %d", frame->width,
113		frame->height, frame->fmt->color);
114
115	cfg = readl(dev->regs + S5P_CITRGFMT);
116	cfg &= ~(S5P_CITRGFMT_FMT_MASK | S5P_CITRGFMT_HSIZE_MASK |
117		  S5P_CITRGFMT_VSIZE_MASK);
118
119	switch (frame->fmt->color) {
120	case S5P_FIMC_RGB444...S5P_FIMC_RGB888:
121		cfg |= S5P_CITRGFMT_RGB;
122		break;
123	case S5P_FIMC_YCBCR420:
124		cfg |= S5P_CITRGFMT_YCBCR420;
125		break;
126	case S5P_FIMC_YCBYCR422...S5P_FIMC_CRYCBY422:
127		if (frame->fmt->colplanes == 1)
128			cfg |= S5P_CITRGFMT_YCBCR422_1P;
129		else
130			cfg |= S5P_CITRGFMT_YCBCR422;
131		break;
132	default:
133		break;
134	}
135
136	if (ctx->rotation == 90 || ctx->rotation == 270) {
137		cfg |= S5P_CITRGFMT_HSIZE(frame->height);
138		cfg |= S5P_CITRGFMT_VSIZE(frame->width);
139	} else {
140
141		cfg |= S5P_CITRGFMT_HSIZE(frame->width);
142		cfg |= S5P_CITRGFMT_VSIZE(frame->height);
143	}
144
145	writel(cfg, dev->regs + S5P_CITRGFMT);
146
147	cfg = readl(dev->regs + S5P_CITAREA) & ~S5P_CITAREA_MASK;
148	cfg |= (frame->width * frame->height);
149	writel(cfg, dev->regs + S5P_CITAREA);
150}
151
152static void fimc_hw_set_out_dma_size(struct fimc_ctx *ctx)
153{
154	struct fimc_dev *dev = ctx->fimc_dev;
155	struct fimc_frame *frame = &ctx->d_frame;
156	u32 cfg;
157
158	cfg = S5P_ORIG_SIZE_HOR(frame->f_width);
159	cfg |= S5P_ORIG_SIZE_VER(frame->f_height);
160	writel(cfg, dev->regs + S5P_ORGOSIZE);
161
162	/* Select color space conversion equation (HD/SD size).*/
163	cfg = readl(dev->regs + S5P_CIGCTRL);
164	if (frame->f_width >= 1280) /* HD */
165		cfg |= S5P_CIGCTRL_CSC_ITU601_709;
166	else	/* SD */
167		cfg &= ~S5P_CIGCTRL_CSC_ITU601_709;
168	writel(cfg, dev->regs + S5P_CIGCTRL);
169
170}
171
172void fimc_hw_set_out_dma(struct fimc_ctx *ctx)
173{
174	u32 cfg;
175	struct fimc_dev *dev = ctx->fimc_dev;
176	struct fimc_frame *frame = &ctx->d_frame;
177	struct fimc_dma_offset *offset = &frame->dma_offset;
178	struct fimc_fmt *fmt = frame->fmt;
179
180	/* Set the input dma offsets. */
181	cfg = 0;
182	cfg |= S5P_CIO_OFFS_HOR(offset->y_h);
183	cfg |= S5P_CIO_OFFS_VER(offset->y_v);
184	writel(cfg, dev->regs + S5P_CIOYOFF);
185
186	cfg = 0;
187	cfg |= S5P_CIO_OFFS_HOR(offset->cb_h);
188	cfg |= S5P_CIO_OFFS_VER(offset->cb_v);
189	writel(cfg, dev->regs + S5P_CIOCBOFF);
190
191	cfg = 0;
192	cfg |= S5P_CIO_OFFS_HOR(offset->cr_h);
193	cfg |= S5P_CIO_OFFS_VER(offset->cr_v);
194	writel(cfg, dev->regs + S5P_CIOCROFF);
195
196	fimc_hw_set_out_dma_size(ctx);
197
198	/* Configure chroma components order. */
199	cfg = readl(dev->regs + S5P_CIOCTRL);
200
201	cfg &= ~(S5P_CIOCTRL_ORDER2P_MASK | S5P_CIOCTRL_ORDER422_MASK |
202		 S5P_CIOCTRL_YCBCR_PLANE_MASK | S5P_CIOCTRL_RGB16FMT_MASK);
203
204	if (fmt->colplanes == 1)
205		cfg |= ctx->out_order_1p;
206	else if (fmt->colplanes == 2)
207		cfg |= ctx->out_order_2p | S5P_CIOCTRL_YCBCR_2PLANE;
208	else if (fmt->colplanes == 3)
209		cfg |= S5P_CIOCTRL_YCBCR_3PLANE;
210
211	if (fmt->color == S5P_FIMC_RGB565)
212		cfg |= S5P_CIOCTRL_RGB565;
213	else if (fmt->color == S5P_FIMC_RGB555)
214		cfg |= S5P_CIOCTRL_ARGB1555;
215	else if (fmt->color == S5P_FIMC_RGB444)
216		cfg |= S5P_CIOCTRL_ARGB4444;
217
218	writel(cfg, dev->regs + S5P_CIOCTRL);
219}
220
221static void fimc_hw_en_autoload(struct fimc_dev *dev, int enable)
222{
223	u32 cfg = readl(dev->regs + S5P_ORGISIZE);
224	if (enable)
225		cfg |= S5P_CIREAL_ISIZE_AUTOLOAD_EN;
226	else
227		cfg &= ~S5P_CIREAL_ISIZE_AUTOLOAD_EN;
228	writel(cfg, dev->regs + S5P_ORGISIZE);
229}
230
231void fimc_hw_en_lastirq(struct fimc_dev *dev, int enable)
232{
233	u32 cfg = readl(dev->regs + S5P_CIOCTRL);
234	if (enable)
235		cfg |= S5P_CIOCTRL_LASTIRQ_ENABLE;
236	else
237		cfg &= ~S5P_CIOCTRL_LASTIRQ_ENABLE;
238	writel(cfg, dev->regs + S5P_CIOCTRL);
239}
240
241void fimc_hw_set_prescaler(struct fimc_ctx *ctx)
242{
243	struct fimc_dev *dev =  ctx->fimc_dev;
244	struct fimc_scaler *sc = &ctx->scaler;
245	u32 cfg, shfactor;
246
247	shfactor = 10 - (sc->hfactor + sc->vfactor);
248
249	cfg = S5P_CISCPRERATIO_SHFACTOR(shfactor);
250	cfg |= S5P_CISCPRERATIO_HOR(sc->pre_hratio);
251	cfg |= S5P_CISCPRERATIO_VER(sc->pre_vratio);
252	writel(cfg, dev->regs + S5P_CISCPRERATIO);
253
254	cfg = S5P_CISCPREDST_WIDTH(sc->pre_dst_width);
255	cfg |= S5P_CISCPREDST_HEIGHT(sc->pre_dst_height);
256	writel(cfg, dev->regs + S5P_CISCPREDST);
257}
258
259static void fimc_hw_set_scaler(struct fimc_ctx *ctx)
260{
261	struct fimc_dev *dev = ctx->fimc_dev;
262	struct fimc_scaler *sc = &ctx->scaler;
263	struct fimc_frame *src_frame = &ctx->s_frame;
264	struct fimc_frame *dst_frame = &ctx->d_frame;
265
266	u32 cfg = readl(dev->regs + S5P_CISCCTRL);
267
268	cfg &= ~(S5P_CISCCTRL_CSCR2Y_WIDE | S5P_CISCCTRL_CSCY2R_WIDE |
269		 S5P_CISCCTRL_SCALEUP_H | S5P_CISCCTRL_SCALEUP_V |
270		 S5P_CISCCTRL_SCALERBYPASS | S5P_CISCCTRL_ONE2ONE |
271		 S5P_CISCCTRL_INRGB_FMT_MASK | S5P_CISCCTRL_OUTRGB_FMT_MASK |
272		 S5P_CISCCTRL_INTERLACE | S5P_CISCCTRL_RGB_EXT);
273
274	if (!(ctx->flags & FIMC_COLOR_RANGE_NARROW))
275		cfg |= (S5P_CISCCTRL_CSCR2Y_WIDE | S5P_CISCCTRL_CSCY2R_WIDE);
276
277	if (!sc->enabled)
278		cfg |= S5P_CISCCTRL_SCALERBYPASS;
279
280	if (sc->scaleup_h)
281		cfg |= S5P_CISCCTRL_SCALEUP_H;
282
283	if (sc->scaleup_v)
284		cfg |= S5P_CISCCTRL_SCALEUP_V;
285
286	if (sc->copy_mode)
287		cfg |= S5P_CISCCTRL_ONE2ONE;
288
289	if (ctx->in_path == FIMC_DMA) {
290		switch (src_frame->fmt->color) {
291		case S5P_FIMC_RGB565:
292			cfg |= S5P_CISCCTRL_INRGB_FMT_RGB565;
293			break;
294		case S5P_FIMC_RGB666:
295			cfg |= S5P_CISCCTRL_INRGB_FMT_RGB666;
296			break;
297		case S5P_FIMC_RGB888:
298			cfg |= S5P_CISCCTRL_INRGB_FMT_RGB888;
299			break;
300		}
301	}
302
303	if (ctx->out_path == FIMC_DMA) {
304		u32 color = dst_frame->fmt->color;
305
306		if (color >= S5P_FIMC_RGB444 && color <= S5P_FIMC_RGB565)
307			cfg |= S5P_CISCCTRL_OUTRGB_FMT_RGB565;
308		else if (color == S5P_FIMC_RGB666)
309			cfg |= S5P_CISCCTRL_OUTRGB_FMT_RGB666;
310		else if (color == S5P_FIMC_RGB888)
311			cfg |= S5P_CISCCTRL_OUTRGB_FMT_RGB888;
312	} else {
313		cfg |= S5P_CISCCTRL_OUTRGB_FMT_RGB888;
314
315		if (ctx->flags & FIMC_SCAN_MODE_INTERLACED)
316			cfg |= S5P_CISCCTRL_INTERLACE;
317	}
318
319	writel(cfg, dev->regs + S5P_CISCCTRL);
320}
321
322void fimc_hw_set_mainscaler(struct fimc_ctx *ctx)
323{
324	struct fimc_dev *dev = ctx->fimc_dev;
325	struct samsung_fimc_variant *variant = dev->variant;
326	struct fimc_scaler *sc = &ctx->scaler;
327	u32 cfg;
328
329	dbg("main_hratio= 0x%X  main_vratio= 0x%X",
330		sc->main_hratio, sc->main_vratio);
331
332	fimc_hw_set_scaler(ctx);
333
334	cfg = readl(dev->regs + S5P_CISCCTRL);
335	cfg &= ~(S5P_CISCCTRL_MHRATIO_MASK | S5P_CISCCTRL_MVRATIO_MASK);
336
337	if (variant->has_mainscaler_ext) {
338		cfg |= S5P_CISCCTRL_MHRATIO_EXT(sc->main_hratio);
339		cfg |= S5P_CISCCTRL_MVRATIO_EXT(sc->main_vratio);
340		writel(cfg, dev->regs + S5P_CISCCTRL);
341
342		cfg = readl(dev->regs + S5P_CIEXTEN);
343
344		cfg &= ~(S5P_CIEXTEN_MVRATIO_EXT_MASK |
345			 S5P_CIEXTEN_MHRATIO_EXT_MASK);
346		cfg |= S5P_CIEXTEN_MHRATIO_EXT(sc->main_hratio);
347		cfg |= S5P_CIEXTEN_MVRATIO_EXT(sc->main_vratio);
348		writel(cfg, dev->regs + S5P_CIEXTEN);
349	} else {
350		cfg |= S5P_CISCCTRL_MHRATIO(sc->main_hratio);
351		cfg |= S5P_CISCCTRL_MVRATIO(sc->main_vratio);
352		writel(cfg, dev->regs + S5P_CISCCTRL);
353	}
354}
355
356void fimc_hw_en_capture(struct fimc_ctx *ctx)
357{
358	struct fimc_dev *dev = ctx->fimc_dev;
359
360	u32 cfg = readl(dev->regs + S5P_CIIMGCPT);
361
362	if (ctx->out_path == FIMC_DMA) {
363		/* one shot mode */
364		cfg |= S5P_CIIMGCPT_CPT_FREN_ENABLE | S5P_CIIMGCPT_IMGCPTEN;
365	} else {
366		/* Continuous frame capture mode (freerun). */
367		cfg &= ~(S5P_CIIMGCPT_CPT_FREN_ENABLE |
368			 S5P_CIIMGCPT_CPT_FRMOD_CNT);
369		cfg |= S5P_CIIMGCPT_IMGCPTEN;
370	}
371
372	if (ctx->scaler.enabled)
373		cfg |= S5P_CIIMGCPT_IMGCPTEN_SC;
374
375	writel(cfg | S5P_CIIMGCPT_IMGCPTEN, dev->regs + S5P_CIIMGCPT);
376}
377
378void fimc_hw_set_effect(struct fimc_ctx *ctx, bool active)
379{
380	struct fimc_dev *dev = ctx->fimc_dev;
381	struct fimc_effect *effect = &ctx->effect;
382	u32 cfg = 0;
383
384	if (active) {
385		cfg |= S5P_CIIMGEFF_IE_SC_AFTER | S5P_CIIMGEFF_IE_ENABLE;
386		cfg |= effect->type;
387		if (effect->type == S5P_FIMC_EFFECT_ARBITRARY) {
388			cfg |= S5P_CIIMGEFF_PAT_CB(effect->pat_cb);
389			cfg |= S5P_CIIMGEFF_PAT_CR(effect->pat_cr);
390		}
391	}
392
393	writel(cfg, dev->regs + S5P_CIIMGEFF);
394}
395
396void fimc_hw_set_rgb_alpha(struct fimc_ctx *ctx)
397{
398	struct fimc_dev *dev = ctx->fimc_dev;
399	struct fimc_frame *frame = &ctx->d_frame;
400	u32 cfg;
401
402	if (!(frame->fmt->flags & FMT_HAS_ALPHA))
403		return;
404
405	cfg = readl(dev->regs + S5P_CIOCTRL);
406	cfg &= ~S5P_CIOCTRL_ALPHA_OUT_MASK;
407	cfg |= (frame->alpha << 4);
408	writel(cfg, dev->regs + S5P_CIOCTRL);
409}
410
411static void fimc_hw_set_in_dma_size(struct fimc_ctx *ctx)
412{
413	struct fimc_dev *dev = ctx->fimc_dev;
414	struct fimc_frame *frame = &ctx->s_frame;
415	u32 cfg_o = 0;
416	u32 cfg_r = 0;
417
418	if (FIMC_LCDFIFO == ctx->out_path)
419		cfg_r |= S5P_CIREAL_ISIZE_AUTOLOAD_EN;
420
421	cfg_o |= S5P_ORIG_SIZE_HOR(frame->f_width);
422	cfg_o |= S5P_ORIG_SIZE_VER(frame->f_height);
423	cfg_r |= S5P_CIREAL_ISIZE_WIDTH(frame->width);
424	cfg_r |= S5P_CIREAL_ISIZE_HEIGHT(frame->height);
425
426	writel(cfg_o, dev->regs + S5P_ORGISIZE);
427	writel(cfg_r, dev->regs + S5P_CIREAL_ISIZE);
428}
429
430void fimc_hw_set_in_dma(struct fimc_ctx *ctx)
431{
432	struct fimc_dev *dev = ctx->fimc_dev;
433	struct fimc_frame *frame = &ctx->s_frame;
434	struct fimc_dma_offset *offset = &frame->dma_offset;
435	u32 cfg;
436
437	/* Set the pixel offsets. */
438	cfg = S5P_CIO_OFFS_HOR(offset->y_h);
439	cfg |= S5P_CIO_OFFS_VER(offset->y_v);
440	writel(cfg, dev->regs + S5P_CIIYOFF);
441
442	cfg = S5P_CIO_OFFS_HOR(offset->cb_h);
443	cfg |= S5P_CIO_OFFS_VER(offset->cb_v);
444	writel(cfg, dev->regs + S5P_CIICBOFF);
445
446	cfg = S5P_CIO_OFFS_HOR(offset->cr_h);
447	cfg |= S5P_CIO_OFFS_VER(offset->cr_v);
448	writel(cfg, dev->regs + S5P_CIICROFF);
449
450	/* Input original and real size. */
451	fimc_hw_set_in_dma_size(ctx);
452
453	/* Use DMA autoload only in FIFO mode. */
454	fimc_hw_en_autoload(dev, ctx->out_path == FIMC_LCDFIFO);
455
456	/* Set the input DMA to process single frame only. */
457	cfg = readl(dev->regs + S5P_MSCTRL);
458	cfg &= ~(S5P_MSCTRL_INFORMAT_MASK
459		| S5P_MSCTRL_IN_BURST_COUNT_MASK
460		| S5P_MSCTRL_INPUT_MASK
461		| S5P_MSCTRL_C_INT_IN_MASK
462		| S5P_MSCTRL_2P_IN_ORDER_MASK);
463
464	cfg |= (S5P_MSCTRL_IN_BURST_COUNT(4)
465		| S5P_MSCTRL_INPUT_MEMORY
466		| S5P_MSCTRL_FIFO_CTRL_FULL);
467
468	switch (frame->fmt->color) {
469	case S5P_FIMC_RGB565...S5P_FIMC_RGB888:
470		cfg |= S5P_MSCTRL_INFORMAT_RGB;
471		break;
472	case S5P_FIMC_YCBCR420:
473		cfg |= S5P_MSCTRL_INFORMAT_YCBCR420;
474
475		if (frame->fmt->colplanes == 2)
476			cfg |= ctx->in_order_2p | S5P_MSCTRL_C_INT_IN_2PLANE;
477		else
478			cfg |= S5P_MSCTRL_C_INT_IN_3PLANE;
479
480		break;
481	case S5P_FIMC_YCBYCR422...S5P_FIMC_CRYCBY422:
482		if (frame->fmt->colplanes == 1) {
483			cfg |= ctx->in_order_1p
484				| S5P_MSCTRL_INFORMAT_YCBCR422_1P;
485		} else {
486			cfg |= S5P_MSCTRL_INFORMAT_YCBCR422;
487
488			if (frame->fmt->colplanes == 2)
489				cfg |= ctx->in_order_2p
490					| S5P_MSCTRL_C_INT_IN_2PLANE;
491			else
492				cfg |= S5P_MSCTRL_C_INT_IN_3PLANE;
493		}
494		break;
495	default:
496		break;
497	}
498
499	writel(cfg, dev->regs + S5P_MSCTRL);
500
501	/* Input/output DMA linear/tiled mode. */
502	cfg = readl(dev->regs + S5P_CIDMAPARAM);
503	cfg &= ~S5P_CIDMAPARAM_TILE_MASK;
504
505	if (tiled_fmt(ctx->s_frame.fmt))
506		cfg |= S5P_CIDMAPARAM_R_64X32;
507
508	if (tiled_fmt(ctx->d_frame.fmt))
509		cfg |= S5P_CIDMAPARAM_W_64X32;
510
511	writel(cfg, dev->regs + S5P_CIDMAPARAM);
512}
513
514
515void fimc_hw_set_input_path(struct fimc_ctx *ctx)
516{
517	struct fimc_dev *dev = ctx->fimc_dev;
518
519	u32 cfg = readl(dev->regs + S5P_MSCTRL);
520	cfg &= ~S5P_MSCTRL_INPUT_MASK;
521
522	if (ctx->in_path == FIMC_DMA)
523		cfg |= S5P_MSCTRL_INPUT_MEMORY;
524	else
525		cfg |= S5P_MSCTRL_INPUT_EXTCAM;
526
527	writel(cfg, dev->regs + S5P_MSCTRL);
528}
529
530void fimc_hw_set_output_path(struct fimc_ctx *ctx)
531{
532	struct fimc_dev *dev = ctx->fimc_dev;
533
534	u32 cfg = readl(dev->regs + S5P_CISCCTRL);
535	cfg &= ~S5P_CISCCTRL_LCDPATHEN_FIFO;
536	if (ctx->out_path == FIMC_LCDFIFO)
537		cfg |= S5P_CISCCTRL_LCDPATHEN_FIFO;
538	writel(cfg, dev->regs + S5P_CISCCTRL);
539}
540
541void fimc_hw_set_input_addr(struct fimc_dev *dev, struct fimc_addr *paddr)
542{
543	u32 cfg = readl(dev->regs + S5P_CIREAL_ISIZE);
544	cfg |= S5P_CIREAL_ISIZE_ADDR_CH_DIS;
545	writel(cfg, dev->regs + S5P_CIREAL_ISIZE);
546
547	writel(paddr->y, dev->regs + S5P_CIIYSA(0));
548	writel(paddr->cb, dev->regs + S5P_CIICBSA(0));
549	writel(paddr->cr, dev->regs + S5P_CIICRSA(0));
550
551	cfg &= ~S5P_CIREAL_ISIZE_ADDR_CH_DIS;
552	writel(cfg, dev->regs + S5P_CIREAL_ISIZE);
553}
554
555void fimc_hw_set_output_addr(struct fimc_dev *dev,
556			     struct fimc_addr *paddr, int index)
557{
558	int i = (index == -1) ? 0 : index;
559	do {
560		writel(paddr->y, dev->regs + S5P_CIOYSA(i));
561		writel(paddr->cb, dev->regs + S5P_CIOCBSA(i));
562		writel(paddr->cr, dev->regs + S5P_CIOCRSA(i));
563		dbg("dst_buf[%d]: 0x%X, cb: 0x%X, cr: 0x%X",
564		    i, paddr->y, paddr->cb, paddr->cr);
565	} while (index == -1 && ++i < FIMC_MAX_OUT_BUFS);
566}
567
568int fimc_hw_set_camera_polarity(struct fimc_dev *fimc,
569				struct s5p_fimc_isp_info *cam)
570{
571	u32 cfg = readl(fimc->regs + S5P_CIGCTRL);
572
573	cfg &= ~(S5P_CIGCTRL_INVPOLPCLK | S5P_CIGCTRL_INVPOLVSYNC |
574		 S5P_CIGCTRL_INVPOLHREF | S5P_CIGCTRL_INVPOLHSYNC |
575		 S5P_CIGCTRL_INVPOLFIELD);
576
577	if (cam->flags & V4L2_MBUS_PCLK_SAMPLE_FALLING)
578		cfg |= S5P_CIGCTRL_INVPOLPCLK;
579
580	if (cam->flags & V4L2_MBUS_VSYNC_ACTIVE_LOW)
581		cfg |= S5P_CIGCTRL_INVPOLVSYNC;
582
583	if (cam->flags & V4L2_MBUS_HSYNC_ACTIVE_LOW)
584		cfg |= S5P_CIGCTRL_INVPOLHREF;
585
586	if (cam->flags & V4L2_MBUS_HSYNC_ACTIVE_LOW)
587		cfg |= S5P_CIGCTRL_INVPOLHSYNC;
588
589	if (cam->flags & V4L2_MBUS_FIELD_EVEN_LOW)
590		cfg |= S5P_CIGCTRL_INVPOLFIELD;
591
592	writel(cfg, fimc->regs + S5P_CIGCTRL);
593
594	return 0;
595}
596
597int fimc_hw_set_camera_source(struct fimc_dev *fimc,
598			      struct s5p_fimc_isp_info *cam)
599{
600	struct fimc_frame *f = &fimc->vid_cap.ctx->s_frame;
601	u32 cfg = 0;
602	u32 bus_width;
603	int i;
604
605	static const struct {
606		u32 pixelcode;
607		u32 cisrcfmt;
608		u16 bus_width;
609	} pix_desc[] = {
610		{ V4L2_MBUS_FMT_YUYV8_2X8, S5P_CISRCFMT_ORDER422_YCBYCR, 8 },
611		{ V4L2_MBUS_FMT_YVYU8_2X8, S5P_CISRCFMT_ORDER422_YCRYCB, 8 },
612		{ V4L2_MBUS_FMT_VYUY8_2X8, S5P_CISRCFMT_ORDER422_CRYCBY, 8 },
613		{ V4L2_MBUS_FMT_UYVY8_2X8, S5P_CISRCFMT_ORDER422_CBYCRY, 8 },
614		/* TODO: Add pixel codes for 16-bit bus width */
615	};
616
617	if (cam->bus_type == FIMC_ITU_601 || cam->bus_type == FIMC_ITU_656) {
618		for (i = 0; i < ARRAY_SIZE(pix_desc); i++) {
619			if (fimc->vid_cap.mf.code == pix_desc[i].pixelcode) {
620				cfg = pix_desc[i].cisrcfmt;
621				bus_width = pix_desc[i].bus_width;
622				break;
623			}
624		}
625
626		if (i == ARRAY_SIZE(pix_desc)) {
627			v4l2_err(fimc->vid_cap.vfd,
628				 "Camera color format not supported: %d\n",
629				 fimc->vid_cap.mf.code);
630			return -EINVAL;
631		}
632
633		if (cam->bus_type == FIMC_ITU_601) {
634			if (bus_width == 8)
635				cfg |= S5P_CISRCFMT_ITU601_8BIT;
636			else if (bus_width == 16)
637				cfg |= S5P_CISRCFMT_ITU601_16BIT;
638		} /* else defaults to ITU-R BT.656 8-bit */
639	} else if (cam->bus_type == FIMC_MIPI_CSI2) {
640		if (fimc_fmt_is_jpeg(f->fmt->color))
641			cfg |= S5P_CISRCFMT_ITU601_8BIT;
642	}
643
644	cfg |= S5P_CISRCFMT_HSIZE(f->o_width) | S5P_CISRCFMT_VSIZE(f->o_height);
645	writel(cfg, fimc->regs + S5P_CISRCFMT);
646	return 0;
647}
648
649
650int fimc_hw_set_camera_offset(struct fimc_dev *fimc, struct fimc_frame *f)
651{
652	u32 hoff2, voff2;
653
654	u32 cfg = readl(fimc->regs + S5P_CIWDOFST);
655
656	cfg &= ~(S5P_CIWDOFST_HOROFF_MASK | S5P_CIWDOFST_VEROFF_MASK);
657	cfg |=  S5P_CIWDOFST_OFF_EN |
658		S5P_CIWDOFST_HOROFF(f->offs_h) |
659		S5P_CIWDOFST_VEROFF(f->offs_v);
660
661	writel(cfg, fimc->regs + S5P_CIWDOFST);
662
663	/* See CIWDOFSTn register description in the datasheet for details. */
664	hoff2 = f->o_width - f->width - f->offs_h;
665	voff2 = f->o_height - f->height - f->offs_v;
666	cfg = S5P_CIWDOFST2_HOROFF(hoff2) | S5P_CIWDOFST2_VEROFF(voff2);
667
668	writel(cfg, fimc->regs + S5P_CIWDOFST2);
669	return 0;
670}
671
672int fimc_hw_set_camera_type(struct fimc_dev *fimc,
673			    struct s5p_fimc_isp_info *cam)
674{
675	u32 cfg, tmp;
676	struct fimc_vid_cap *vid_cap = &fimc->vid_cap;
677
678	cfg = readl(fimc->regs + S5P_CIGCTRL);
679
680	/* Select ITU B interface, disable Writeback path and test pattern. */
681	cfg &= ~(S5P_CIGCTRL_TESTPAT_MASK | S5P_CIGCTRL_SELCAM_ITU_A |
682		S5P_CIGCTRL_SELCAM_MIPI | S5P_CIGCTRL_CAMIF_SELWB |
683		S5P_CIGCTRL_SELCAM_MIPI_A | S5P_CIGCTRL_CAM_JPEG);
684
685	if (cam->bus_type == FIMC_MIPI_CSI2) {
686		cfg |= S5P_CIGCTRL_SELCAM_MIPI;
687
688		if (cam->mux_id == 0)
689			cfg |= S5P_CIGCTRL_SELCAM_MIPI_A;
690
691		/* TODO: add remaining supported formats. */
692		switch (vid_cap->mf.code) {
693		case V4L2_MBUS_FMT_VYUY8_2X8:
694			tmp = S5P_CSIIMGFMT_YCBCR422_8BIT;
695			break;
696		case V4L2_MBUS_FMT_JPEG_1X8:
697			tmp = S5P_CSIIMGFMT_USER(1);
698			cfg |= S5P_CIGCTRL_CAM_JPEG;
699			break;
700		default:
701			v4l2_err(fimc->vid_cap.vfd,
702				 "Not supported camera pixel format: %d",
703				 vid_cap->mf.code);
704			return -EINVAL;
705		}
706		tmp |= (cam->csi_data_align == 32) << 8;
707
708		writel(tmp, fimc->regs + S5P_CSIIMGFMT);
709
710	} else if (cam->bus_type == FIMC_ITU_601 ||
711		   cam->bus_type == FIMC_ITU_656) {
712		if (cam->mux_id == 0) /* ITU-A, ITU-B: 0, 1 */
713			cfg |= S5P_CIGCTRL_SELCAM_ITU_A;
714	} else if (cam->bus_type == FIMC_LCD_WB) {
715		cfg |= S5P_CIGCTRL_CAMIF_SELWB;
716	} else {
717		err("invalid camera bus type selected\n");
718		return -EINVAL;
719	}
720	writel(cfg, fimc->regs + S5P_CIGCTRL);
721
722	return 0;
723}
724