2 * Copyright (c) 2011 - 2012 Samsung Electronics Co., Ltd.
3 * http://www.samsung.com
5 * Samsung EXYNOS5 SoC series G-Scaler driver
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published
9 * by the Free Software Foundation, either version 2 of the License,
10 * or (at your option) any later version.
14 #include <linux/delay.h>
18 void gsc_hw_set_sw_reset(struct gsc_dev
*dev
)
20 writel(GSC_SW_RESET_SRESET
, dev
->regs
+ GSC_SW_RESET
);
23 int gsc_wait_reset(struct gsc_dev
*dev
)
25 unsigned long end
= jiffies
+ msecs_to_jiffies(50);
28 while (time_before(jiffies
, end
)) {
29 cfg
= readl(dev
->regs
+ GSC_SW_RESET
);
38 void gsc_hw_set_frm_done_irq_mask(struct gsc_dev
*dev
, bool mask
)
42 cfg
= readl(dev
->regs
+ GSC_IRQ
);
44 cfg
|= GSC_IRQ_FRMDONE_MASK
;
46 cfg
&= ~GSC_IRQ_FRMDONE_MASK
;
47 writel(cfg
, dev
->regs
+ GSC_IRQ
);
50 void gsc_hw_set_gsc_irq_enable(struct gsc_dev
*dev
, bool mask
)
54 cfg
= readl(dev
->regs
+ GSC_IRQ
);
56 cfg
|= GSC_IRQ_ENABLE
;
58 cfg
&= ~GSC_IRQ_ENABLE
;
59 writel(cfg
, dev
->regs
+ GSC_IRQ
);
62 void gsc_hw_set_input_buf_masking(struct gsc_dev
*dev
, u32 shift
,
65 u32 cfg
= readl(dev
->regs
+ GSC_IN_BASE_ADDR_Y_MASK
);
66 u32 mask
= 1 << shift
;
69 cfg
|= enable
<< shift
;
71 writel(cfg
, dev
->regs
+ GSC_IN_BASE_ADDR_Y_MASK
);
72 writel(cfg
, dev
->regs
+ GSC_IN_BASE_ADDR_CB_MASK
);
73 writel(cfg
, dev
->regs
+ GSC_IN_BASE_ADDR_CR_MASK
);
76 void gsc_hw_set_output_buf_masking(struct gsc_dev
*dev
, u32 shift
,
79 u32 cfg
= readl(dev
->regs
+ GSC_OUT_BASE_ADDR_Y_MASK
);
80 u32 mask
= 1 << shift
;
83 cfg
|= enable
<< shift
;
85 writel(cfg
, dev
->regs
+ GSC_OUT_BASE_ADDR_Y_MASK
);
86 writel(cfg
, dev
->regs
+ GSC_OUT_BASE_ADDR_CB_MASK
);
87 writel(cfg
, dev
->regs
+ GSC_OUT_BASE_ADDR_CR_MASK
);
90 void gsc_hw_set_input_addr(struct gsc_dev
*dev
, struct gsc_addr
*addr
,
93 pr_debug("src_buf[%d]: 0x%X, cb: 0x%X, cr: 0x%X", index
,
94 addr
->y
, addr
->cb
, addr
->cr
);
95 writel(addr
->y
, dev
->regs
+ GSC_IN_BASE_ADDR_Y(index
));
96 writel(addr
->cb
, dev
->regs
+ GSC_IN_BASE_ADDR_CB(index
));
97 writel(addr
->cr
, dev
->regs
+ GSC_IN_BASE_ADDR_CR(index
));
101 void gsc_hw_set_output_addr(struct gsc_dev
*dev
,
102 struct gsc_addr
*addr
, int index
)
104 pr_debug("dst_buf[%d]: 0x%X, cb: 0x%X, cr: 0x%X",
105 index
, addr
->y
, addr
->cb
, addr
->cr
);
106 writel(addr
->y
, dev
->regs
+ GSC_OUT_BASE_ADDR_Y(index
));
107 writel(addr
->cb
, dev
->regs
+ GSC_OUT_BASE_ADDR_CB(index
));
108 writel(addr
->cr
, dev
->regs
+ GSC_OUT_BASE_ADDR_CR(index
));
111 void gsc_hw_set_input_path(struct gsc_ctx
*ctx
)
113 struct gsc_dev
*dev
= ctx
->gsc_dev
;
115 u32 cfg
= readl(dev
->regs
+ GSC_IN_CON
);
116 cfg
&= ~(GSC_IN_PATH_MASK
| GSC_IN_LOCAL_SEL_MASK
);
118 if (ctx
->in_path
== GSC_DMA
)
119 cfg
|= GSC_IN_PATH_MEMORY
;
121 writel(cfg
, dev
->regs
+ GSC_IN_CON
);
124 void gsc_hw_set_in_size(struct gsc_ctx
*ctx
)
126 struct gsc_dev
*dev
= ctx
->gsc_dev
;
127 struct gsc_frame
*frame
= &ctx
->s_frame
;
130 /* Set input pixel offset */
131 cfg
= GSC_SRCIMG_OFFSET_X(frame
->crop
.left
);
132 cfg
|= GSC_SRCIMG_OFFSET_Y(frame
->crop
.top
);
133 writel(cfg
, dev
->regs
+ GSC_SRCIMG_OFFSET
);
135 /* Set input original size */
136 cfg
= GSC_SRCIMG_WIDTH(frame
->f_width
);
137 cfg
|= GSC_SRCIMG_HEIGHT(frame
->f_height
);
138 writel(cfg
, dev
->regs
+ GSC_SRCIMG_SIZE
);
140 /* Set input cropped size */
141 cfg
= GSC_CROPPED_WIDTH(frame
->crop
.width
);
142 cfg
|= GSC_CROPPED_HEIGHT(frame
->crop
.height
);
143 writel(cfg
, dev
->regs
+ GSC_CROPPED_SIZE
);
146 void gsc_hw_set_in_image_rgb(struct gsc_ctx
*ctx
)
148 struct gsc_dev
*dev
= ctx
->gsc_dev
;
149 struct gsc_frame
*frame
= &ctx
->s_frame
;
152 cfg
= readl(dev
->regs
+ GSC_IN_CON
);
153 if (frame
->colorspace
== V4L2_COLORSPACE_REC709
)
154 cfg
|= GSC_IN_RGB_HD_WIDE
;
156 cfg
|= GSC_IN_RGB_SD_WIDE
;
158 if (frame
->fmt
->pixelformat
== V4L2_PIX_FMT_RGB565X
)
159 cfg
|= GSC_IN_RGB565
;
160 else if (frame
->fmt
->pixelformat
== V4L2_PIX_FMT_RGB32
)
161 cfg
|= GSC_IN_XRGB8888
;
163 writel(cfg
, dev
->regs
+ GSC_IN_CON
);
166 void gsc_hw_set_in_image_format(struct gsc_ctx
*ctx
)
168 struct gsc_dev
*dev
= ctx
->gsc_dev
;
169 struct gsc_frame
*frame
= &ctx
->s_frame
;
173 cfg
= readl(dev
->regs
+ GSC_IN_CON
);
174 cfg
&= ~(GSC_IN_RGB_TYPE_MASK
| GSC_IN_YUV422_1P_ORDER_MASK
|
175 GSC_IN_CHROMA_ORDER_MASK
| GSC_IN_FORMAT_MASK
|
176 GSC_IN_TILE_TYPE_MASK
| GSC_IN_TILE_MODE
);
177 writel(cfg
, dev
->regs
+ GSC_IN_CON
);
179 if (is_rgb(frame
->fmt
->color
)) {
180 gsc_hw_set_in_image_rgb(ctx
);
183 for (i
= 0; i
< frame
->fmt
->num_planes
; i
++)
184 depth
+= frame
->fmt
->depth
[i
];
186 switch (frame
->fmt
->num_comp
) {
188 cfg
|= GSC_IN_YUV422_1P
;
189 if (frame
->fmt
->yorder
== GSC_LSB_Y
)
190 cfg
|= GSC_IN_YUV422_1P_ORDER_LSB_Y
;
192 cfg
|= GSC_IN_YUV422_1P_OEDER_LSB_C
;
193 if (frame
->fmt
->corder
== GSC_CBCR
)
194 cfg
|= GSC_IN_CHROMA_ORDER_CBCR
;
196 cfg
|= GSC_IN_CHROMA_ORDER_CRCB
;
200 cfg
|= GSC_IN_YUV420_2P
;
202 cfg
|= GSC_IN_YUV422_2P
;
203 if (frame
->fmt
->corder
== GSC_CBCR
)
204 cfg
|= GSC_IN_CHROMA_ORDER_CBCR
;
206 cfg
|= GSC_IN_CHROMA_ORDER_CRCB
;
210 cfg
|= GSC_IN_YUV420_3P
;
212 cfg
|= GSC_IN_YUV422_3P
;
216 if (is_tiled(frame
->fmt
))
217 cfg
|= GSC_IN_TILE_C_16x8
| GSC_IN_TILE_MODE
;
219 writel(cfg
, dev
->regs
+ GSC_IN_CON
);
222 void gsc_hw_set_output_path(struct gsc_ctx
*ctx
)
224 struct gsc_dev
*dev
= ctx
->gsc_dev
;
226 u32 cfg
= readl(dev
->regs
+ GSC_OUT_CON
);
227 cfg
&= ~GSC_OUT_PATH_MASK
;
229 if (ctx
->out_path
== GSC_DMA
)
230 cfg
|= GSC_OUT_PATH_MEMORY
;
232 cfg
|= GSC_OUT_PATH_LOCAL
;
234 writel(cfg
, dev
->regs
+ GSC_OUT_CON
);
237 void gsc_hw_set_out_size(struct gsc_ctx
*ctx
)
239 struct gsc_dev
*dev
= ctx
->gsc_dev
;
240 struct gsc_frame
*frame
= &ctx
->d_frame
;
243 /* Set output original size */
244 if (ctx
->out_path
== GSC_DMA
) {
245 cfg
= GSC_DSTIMG_OFFSET_X(frame
->crop
.left
);
246 cfg
|= GSC_DSTIMG_OFFSET_Y(frame
->crop
.top
);
247 writel(cfg
, dev
->regs
+ GSC_DSTIMG_OFFSET
);
249 cfg
= GSC_DSTIMG_WIDTH(frame
->f_width
);
250 cfg
|= GSC_DSTIMG_HEIGHT(frame
->f_height
);
251 writel(cfg
, dev
->regs
+ GSC_DSTIMG_SIZE
);
254 /* Set output scaled size */
255 if (ctx
->gsc_ctrls
.rotate
->val
== 90 ||
256 ctx
->gsc_ctrls
.rotate
->val
== 270) {
257 cfg
= GSC_SCALED_WIDTH(frame
->crop
.height
);
258 cfg
|= GSC_SCALED_HEIGHT(frame
->crop
.width
);
260 cfg
= GSC_SCALED_WIDTH(frame
->crop
.width
);
261 cfg
|= GSC_SCALED_HEIGHT(frame
->crop
.height
);
263 writel(cfg
, dev
->regs
+ GSC_SCALED_SIZE
);
266 void gsc_hw_set_out_image_rgb(struct gsc_ctx
*ctx
)
268 struct gsc_dev
*dev
= ctx
->gsc_dev
;
269 struct gsc_frame
*frame
= &ctx
->d_frame
;
272 cfg
= readl(dev
->regs
+ GSC_OUT_CON
);
273 if (frame
->colorspace
== V4L2_COLORSPACE_REC709
)
274 cfg
|= GSC_OUT_RGB_HD_WIDE
;
276 cfg
|= GSC_OUT_RGB_SD_WIDE
;
278 if (frame
->fmt
->pixelformat
== V4L2_PIX_FMT_RGB565X
)
279 cfg
|= GSC_OUT_RGB565
;
280 else if (frame
->fmt
->pixelformat
== V4L2_PIX_FMT_RGB32
)
281 cfg
|= GSC_OUT_XRGB8888
;
283 writel(cfg
, dev
->regs
+ GSC_OUT_CON
);
286 void gsc_hw_set_out_image_format(struct gsc_ctx
*ctx
)
288 struct gsc_dev
*dev
= ctx
->gsc_dev
;
289 struct gsc_frame
*frame
= &ctx
->d_frame
;
293 cfg
= readl(dev
->regs
+ GSC_OUT_CON
);
294 cfg
&= ~(GSC_OUT_RGB_TYPE_MASK
| GSC_OUT_YUV422_1P_ORDER_MASK
|
295 GSC_OUT_CHROMA_ORDER_MASK
| GSC_OUT_FORMAT_MASK
|
296 GSC_OUT_TILE_TYPE_MASK
| GSC_OUT_TILE_MODE
);
297 writel(cfg
, dev
->regs
+ GSC_OUT_CON
);
299 if (is_rgb(frame
->fmt
->color
)) {
300 gsc_hw_set_out_image_rgb(ctx
);
304 if (ctx
->out_path
!= GSC_DMA
) {
305 cfg
|= GSC_OUT_YUV444
;
309 for (i
= 0; i
< frame
->fmt
->num_planes
; i
++)
310 depth
+= frame
->fmt
->depth
[i
];
312 switch (frame
->fmt
->num_comp
) {
314 cfg
|= GSC_OUT_YUV422_1P
;
315 if (frame
->fmt
->yorder
== GSC_LSB_Y
)
316 cfg
|= GSC_OUT_YUV422_1P_ORDER_LSB_Y
;
318 cfg
|= GSC_OUT_YUV422_1P_OEDER_LSB_C
;
319 if (frame
->fmt
->corder
== GSC_CBCR
)
320 cfg
|= GSC_OUT_CHROMA_ORDER_CBCR
;
322 cfg
|= GSC_OUT_CHROMA_ORDER_CRCB
;
326 cfg
|= GSC_OUT_YUV420_2P
;
328 cfg
|= GSC_OUT_YUV422_2P
;
329 if (frame
->fmt
->corder
== GSC_CBCR
)
330 cfg
|= GSC_OUT_CHROMA_ORDER_CBCR
;
332 cfg
|= GSC_OUT_CHROMA_ORDER_CRCB
;
335 cfg
|= GSC_OUT_YUV420_3P
;
339 if (is_tiled(frame
->fmt
))
340 cfg
|= GSC_OUT_TILE_C_16x8
| GSC_OUT_TILE_MODE
;
343 writel(cfg
, dev
->regs
+ GSC_OUT_CON
);
346 void gsc_hw_set_prescaler(struct gsc_ctx
*ctx
)
348 struct gsc_dev
*dev
= ctx
->gsc_dev
;
349 struct gsc_scaler
*sc
= &ctx
->scaler
;
352 cfg
= GSC_PRESC_SHFACTOR(sc
->pre_shfactor
);
353 cfg
|= GSC_PRESC_H_RATIO(sc
->pre_hratio
);
354 cfg
|= GSC_PRESC_V_RATIO(sc
->pre_vratio
);
355 writel(cfg
, dev
->regs
+ GSC_PRE_SCALE_RATIO
);
358 void gsc_hw_set_mainscaler(struct gsc_ctx
*ctx
)
360 struct gsc_dev
*dev
= ctx
->gsc_dev
;
361 struct gsc_scaler
*sc
= &ctx
->scaler
;
364 cfg
= GSC_MAIN_H_RATIO_VALUE(sc
->main_hratio
);
365 writel(cfg
, dev
->regs
+ GSC_MAIN_H_RATIO
);
367 cfg
= GSC_MAIN_V_RATIO_VALUE(sc
->main_vratio
);
368 writel(cfg
, dev
->regs
+ GSC_MAIN_V_RATIO
);
371 void gsc_hw_set_rotation(struct gsc_ctx
*ctx
)
373 struct gsc_dev
*dev
= ctx
->gsc_dev
;
376 cfg
= readl(dev
->regs
+ GSC_IN_CON
);
377 cfg
&= ~GSC_IN_ROT_MASK
;
379 switch (ctx
->gsc_ctrls
.rotate
->val
) {
381 cfg
|= GSC_IN_ROT_270
;
384 cfg
|= GSC_IN_ROT_180
;
387 if (ctx
->gsc_ctrls
.hflip
->val
)
388 cfg
|= GSC_IN_ROT_90_XFLIP
;
389 else if (ctx
->gsc_ctrls
.vflip
->val
)
390 cfg
|= GSC_IN_ROT_90_YFLIP
;
392 cfg
|= GSC_IN_ROT_90
;
395 if (ctx
->gsc_ctrls
.hflip
->val
)
396 cfg
|= GSC_IN_ROT_XFLIP
;
397 else if (ctx
->gsc_ctrls
.vflip
->val
)
398 cfg
|= GSC_IN_ROT_YFLIP
;
401 writel(cfg
, dev
->regs
+ GSC_IN_CON
);
404 void gsc_hw_set_global_alpha(struct gsc_ctx
*ctx
)
406 struct gsc_dev
*dev
= ctx
->gsc_dev
;
407 struct gsc_frame
*frame
= &ctx
->d_frame
;
410 if (!is_rgb(frame
->fmt
->color
)) {
411 pr_debug("Not a RGB format");
415 cfg
= readl(dev
->regs
+ GSC_OUT_CON
);
416 cfg
&= ~GSC_OUT_GLOBAL_ALPHA_MASK
;
418 cfg
|= GSC_OUT_GLOBAL_ALPHA(ctx
->gsc_ctrls
.global_alpha
->val
);
419 writel(cfg
, dev
->regs
+ GSC_OUT_CON
);
422 void gsc_hw_set_sfr_update(struct gsc_ctx
*ctx
)
424 struct gsc_dev
*dev
= ctx
->gsc_dev
;
427 cfg
= readl(dev
->regs
+ GSC_ENABLE
);
428 cfg
|= GSC_ENABLE_SFR_UPDATE
;
429 writel(cfg
, dev
->regs
+ GSC_ENABLE
);