1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * Copyright (c) 2011 - 2012 Samsung Electronics Co., Ltd.
4 * http://www.samsung.com
6 * Samsung EXYNOS5 SoC series G-Scaler driver
10 #include <linux/delay.h>
14 void gsc_hw_set_sw_reset(struct gsc_dev
*dev
)
16 writel(GSC_SW_RESET_SRESET
, dev
->regs
+ GSC_SW_RESET
);
19 int gsc_wait_reset(struct gsc_dev
*dev
)
21 unsigned long end
= jiffies
+ msecs_to_jiffies(50);
24 while (time_before(jiffies
, end
)) {
25 cfg
= readl(dev
->regs
+ GSC_SW_RESET
);
34 void gsc_hw_set_frm_done_irq_mask(struct gsc_dev
*dev
, bool mask
)
38 cfg
= readl(dev
->regs
+ GSC_IRQ
);
40 cfg
|= GSC_IRQ_FRMDONE_MASK
;
42 cfg
&= ~GSC_IRQ_FRMDONE_MASK
;
43 writel(cfg
, dev
->regs
+ GSC_IRQ
);
46 void gsc_hw_set_gsc_irq_enable(struct gsc_dev
*dev
, bool mask
)
50 cfg
= readl(dev
->regs
+ GSC_IRQ
);
52 cfg
|= GSC_IRQ_ENABLE
;
54 cfg
&= ~GSC_IRQ_ENABLE
;
55 writel(cfg
, dev
->regs
+ GSC_IRQ
);
58 void gsc_hw_set_input_buf_masking(struct gsc_dev
*dev
, u32 shift
,
61 u32 cfg
= readl(dev
->regs
+ GSC_IN_BASE_ADDR_Y_MASK
);
62 u32 mask
= 1 << shift
;
65 cfg
|= enable
<< shift
;
67 writel(cfg
, dev
->regs
+ GSC_IN_BASE_ADDR_Y_MASK
);
68 writel(cfg
, dev
->regs
+ GSC_IN_BASE_ADDR_CB_MASK
);
69 writel(cfg
, dev
->regs
+ GSC_IN_BASE_ADDR_CR_MASK
);
72 void gsc_hw_set_output_buf_masking(struct gsc_dev
*dev
, u32 shift
,
75 u32 cfg
= readl(dev
->regs
+ GSC_OUT_BASE_ADDR_Y_MASK
);
76 u32 mask
= 1 << shift
;
79 cfg
|= enable
<< shift
;
81 writel(cfg
, dev
->regs
+ GSC_OUT_BASE_ADDR_Y_MASK
);
82 writel(cfg
, dev
->regs
+ GSC_OUT_BASE_ADDR_CB_MASK
);
83 writel(cfg
, dev
->regs
+ GSC_OUT_BASE_ADDR_CR_MASK
);
86 void gsc_hw_set_input_addr(struct gsc_dev
*dev
, struct gsc_addr
*addr
,
89 pr_debug("src_buf[%d]: %pad, cb: %pad, cr: %pad", index
,
90 &addr
->y
, &addr
->cb
, &addr
->cr
);
91 writel(addr
->y
, dev
->regs
+ GSC_IN_BASE_ADDR_Y(index
));
92 writel(addr
->cb
, dev
->regs
+ GSC_IN_BASE_ADDR_CB(index
));
93 writel(addr
->cr
, dev
->regs
+ GSC_IN_BASE_ADDR_CR(index
));
97 void gsc_hw_set_output_addr(struct gsc_dev
*dev
,
98 struct gsc_addr
*addr
, int index
)
100 pr_debug("dst_buf[%d]: %pad, cb: %pad, cr: %pad",
101 index
, &addr
->y
, &addr
->cb
, &addr
->cr
);
102 writel(addr
->y
, dev
->regs
+ GSC_OUT_BASE_ADDR_Y(index
));
103 writel(addr
->cb
, dev
->regs
+ GSC_OUT_BASE_ADDR_CB(index
));
104 writel(addr
->cr
, dev
->regs
+ GSC_OUT_BASE_ADDR_CR(index
));
107 void gsc_hw_set_input_path(struct gsc_ctx
*ctx
)
109 struct gsc_dev
*dev
= ctx
->gsc_dev
;
111 u32 cfg
= readl(dev
->regs
+ GSC_IN_CON
);
112 cfg
&= ~(GSC_IN_PATH_MASK
| GSC_IN_LOCAL_SEL_MASK
);
114 if (ctx
->in_path
== GSC_DMA
)
115 cfg
|= GSC_IN_PATH_MEMORY
;
117 writel(cfg
, dev
->regs
+ GSC_IN_CON
);
120 void gsc_hw_set_in_size(struct gsc_ctx
*ctx
)
122 struct gsc_dev
*dev
= ctx
->gsc_dev
;
123 struct gsc_frame
*frame
= &ctx
->s_frame
;
126 /* Set input pixel offset */
127 cfg
= GSC_SRCIMG_OFFSET_X(frame
->crop
.left
);
128 cfg
|= GSC_SRCIMG_OFFSET_Y(frame
->crop
.top
);
129 writel(cfg
, dev
->regs
+ GSC_SRCIMG_OFFSET
);
131 /* Set input original size */
132 cfg
= GSC_SRCIMG_WIDTH(frame
->f_width
);
133 cfg
|= GSC_SRCIMG_HEIGHT(frame
->f_height
);
134 writel(cfg
, dev
->regs
+ GSC_SRCIMG_SIZE
);
136 /* Set input cropped size */
137 cfg
= GSC_CROPPED_WIDTH(frame
->crop
.width
);
138 cfg
|= GSC_CROPPED_HEIGHT(frame
->crop
.height
);
139 writel(cfg
, dev
->regs
+ GSC_CROPPED_SIZE
);
142 void gsc_hw_set_in_image_rgb(struct gsc_ctx
*ctx
)
144 struct gsc_dev
*dev
= ctx
->gsc_dev
;
145 struct gsc_frame
*frame
= &ctx
->s_frame
;
148 cfg
= readl(dev
->regs
+ GSC_IN_CON
);
149 if (frame
->colorspace
== V4L2_COLORSPACE_REC709
)
150 cfg
|= GSC_IN_RGB_HD_WIDE
;
152 cfg
|= GSC_IN_RGB_SD_WIDE
;
154 if (frame
->fmt
->pixelformat
== V4L2_PIX_FMT_RGB565X
)
155 cfg
|= GSC_IN_RGB565
;
156 else if (frame
->fmt
->pixelformat
== V4L2_PIX_FMT_RGB32
)
157 cfg
|= GSC_IN_XRGB8888
;
159 writel(cfg
, dev
->regs
+ GSC_IN_CON
);
162 void gsc_hw_set_in_image_format(struct gsc_ctx
*ctx
)
164 struct gsc_dev
*dev
= ctx
->gsc_dev
;
165 struct gsc_frame
*frame
= &ctx
->s_frame
;
169 cfg
= readl(dev
->regs
+ GSC_IN_CON
);
170 cfg
&= ~(GSC_IN_RGB_TYPE_MASK
| GSC_IN_YUV422_1P_ORDER_MASK
|
171 GSC_IN_CHROMA_ORDER_MASK
| GSC_IN_FORMAT_MASK
|
172 GSC_IN_TILE_TYPE_MASK
| GSC_IN_TILE_MODE
);
173 writel(cfg
, dev
->regs
+ GSC_IN_CON
);
175 if (is_rgb(frame
->fmt
->color
)) {
176 gsc_hw_set_in_image_rgb(ctx
);
179 for (i
= 0; i
< frame
->fmt
->num_planes
; i
++)
180 depth
+= frame
->fmt
->depth
[i
];
182 switch (frame
->fmt
->num_comp
) {
184 cfg
|= GSC_IN_YUV422_1P
;
185 if (frame
->fmt
->yorder
== GSC_LSB_Y
)
186 cfg
|= GSC_IN_YUV422_1P_ORDER_LSB_Y
;
188 cfg
|= GSC_IN_YUV422_1P_OEDER_LSB_C
;
189 if (frame
->fmt
->corder
== GSC_CBCR
)
190 cfg
|= GSC_IN_CHROMA_ORDER_CBCR
;
192 cfg
|= GSC_IN_CHROMA_ORDER_CRCB
;
196 cfg
|= GSC_IN_YUV420_2P
;
198 cfg
|= GSC_IN_YUV422_2P
;
199 if (frame
->fmt
->corder
== GSC_CBCR
)
200 cfg
|= GSC_IN_CHROMA_ORDER_CBCR
;
202 cfg
|= GSC_IN_CHROMA_ORDER_CRCB
;
206 cfg
|= GSC_IN_YUV420_3P
;
208 cfg
|= GSC_IN_YUV422_3P
;
212 if (is_tiled(frame
->fmt
))
213 cfg
|= GSC_IN_TILE_C_16x8
| GSC_IN_TILE_MODE
;
215 writel(cfg
, dev
->regs
+ GSC_IN_CON
);
218 void gsc_hw_set_output_path(struct gsc_ctx
*ctx
)
220 struct gsc_dev
*dev
= ctx
->gsc_dev
;
222 u32 cfg
= readl(dev
->regs
+ GSC_OUT_CON
);
223 cfg
&= ~GSC_OUT_PATH_MASK
;
225 if (ctx
->out_path
== GSC_DMA
)
226 cfg
|= GSC_OUT_PATH_MEMORY
;
228 cfg
|= GSC_OUT_PATH_LOCAL
;
230 writel(cfg
, dev
->regs
+ GSC_OUT_CON
);
233 void gsc_hw_set_out_size(struct gsc_ctx
*ctx
)
235 struct gsc_dev
*dev
= ctx
->gsc_dev
;
236 struct gsc_frame
*frame
= &ctx
->d_frame
;
239 /* Set output original size */
240 if (ctx
->out_path
== GSC_DMA
) {
241 cfg
= GSC_DSTIMG_OFFSET_X(frame
->crop
.left
);
242 cfg
|= GSC_DSTIMG_OFFSET_Y(frame
->crop
.top
);
243 writel(cfg
, dev
->regs
+ GSC_DSTIMG_OFFSET
);
245 cfg
= GSC_DSTIMG_WIDTH(frame
->f_width
);
246 cfg
|= GSC_DSTIMG_HEIGHT(frame
->f_height
);
247 writel(cfg
, dev
->regs
+ GSC_DSTIMG_SIZE
);
250 /* Set output scaled size */
251 if (ctx
->gsc_ctrls
.rotate
->val
== 90 ||
252 ctx
->gsc_ctrls
.rotate
->val
== 270) {
253 cfg
= GSC_SCALED_WIDTH(frame
->crop
.height
);
254 cfg
|= GSC_SCALED_HEIGHT(frame
->crop
.width
);
256 cfg
= GSC_SCALED_WIDTH(frame
->crop
.width
);
257 cfg
|= GSC_SCALED_HEIGHT(frame
->crop
.height
);
259 writel(cfg
, dev
->regs
+ GSC_SCALED_SIZE
);
262 void gsc_hw_set_out_image_rgb(struct gsc_ctx
*ctx
)
264 struct gsc_dev
*dev
= ctx
->gsc_dev
;
265 struct gsc_frame
*frame
= &ctx
->d_frame
;
268 cfg
= readl(dev
->regs
+ GSC_OUT_CON
);
269 if (frame
->colorspace
== V4L2_COLORSPACE_REC709
)
270 cfg
|= GSC_OUT_RGB_HD_WIDE
;
272 cfg
|= GSC_OUT_RGB_SD_WIDE
;
274 if (frame
->fmt
->pixelformat
== V4L2_PIX_FMT_RGB565X
)
275 cfg
|= GSC_OUT_RGB565
;
276 else if (frame
->fmt
->pixelformat
== V4L2_PIX_FMT_RGB32
)
277 cfg
|= GSC_OUT_XRGB8888
;
279 writel(cfg
, dev
->regs
+ GSC_OUT_CON
);
282 void gsc_hw_set_out_image_format(struct gsc_ctx
*ctx
)
284 struct gsc_dev
*dev
= ctx
->gsc_dev
;
285 struct gsc_frame
*frame
= &ctx
->d_frame
;
289 cfg
= readl(dev
->regs
+ GSC_OUT_CON
);
290 cfg
&= ~(GSC_OUT_RGB_TYPE_MASK
| GSC_OUT_YUV422_1P_ORDER_MASK
|
291 GSC_OUT_CHROMA_ORDER_MASK
| GSC_OUT_FORMAT_MASK
|
292 GSC_OUT_TILE_TYPE_MASK
| GSC_OUT_TILE_MODE
);
293 writel(cfg
, dev
->regs
+ GSC_OUT_CON
);
295 if (is_rgb(frame
->fmt
->color
)) {
296 gsc_hw_set_out_image_rgb(ctx
);
300 if (ctx
->out_path
!= GSC_DMA
) {
301 cfg
|= GSC_OUT_YUV444
;
305 for (i
= 0; i
< frame
->fmt
->num_planes
; i
++)
306 depth
+= frame
->fmt
->depth
[i
];
308 switch (frame
->fmt
->num_comp
) {
310 cfg
|= GSC_OUT_YUV422_1P
;
311 if (frame
->fmt
->yorder
== GSC_LSB_Y
)
312 cfg
|= GSC_OUT_YUV422_1P_ORDER_LSB_Y
;
314 cfg
|= GSC_OUT_YUV422_1P_OEDER_LSB_C
;
315 if (frame
->fmt
->corder
== GSC_CBCR
)
316 cfg
|= GSC_OUT_CHROMA_ORDER_CBCR
;
318 cfg
|= GSC_OUT_CHROMA_ORDER_CRCB
;
322 cfg
|= GSC_OUT_YUV420_2P
;
324 cfg
|= GSC_OUT_YUV422_2P
;
325 if (frame
->fmt
->corder
== GSC_CBCR
)
326 cfg
|= GSC_OUT_CHROMA_ORDER_CBCR
;
328 cfg
|= GSC_OUT_CHROMA_ORDER_CRCB
;
331 cfg
|= GSC_OUT_YUV420_3P
;
335 if (is_tiled(frame
->fmt
))
336 cfg
|= GSC_OUT_TILE_C_16x8
| GSC_OUT_TILE_MODE
;
339 writel(cfg
, dev
->regs
+ GSC_OUT_CON
);
342 void gsc_hw_set_prescaler(struct gsc_ctx
*ctx
)
344 struct gsc_dev
*dev
= ctx
->gsc_dev
;
345 struct gsc_scaler
*sc
= &ctx
->scaler
;
348 cfg
= GSC_PRESC_SHFACTOR(sc
->pre_shfactor
);
349 cfg
|= GSC_PRESC_H_RATIO(sc
->pre_hratio
);
350 cfg
|= GSC_PRESC_V_RATIO(sc
->pre_vratio
);
351 writel(cfg
, dev
->regs
+ GSC_PRE_SCALE_RATIO
);
354 void gsc_hw_set_mainscaler(struct gsc_ctx
*ctx
)
356 struct gsc_dev
*dev
= ctx
->gsc_dev
;
357 struct gsc_scaler
*sc
= &ctx
->scaler
;
360 cfg
= GSC_MAIN_H_RATIO_VALUE(sc
->main_hratio
);
361 writel(cfg
, dev
->regs
+ GSC_MAIN_H_RATIO
);
363 cfg
= GSC_MAIN_V_RATIO_VALUE(sc
->main_vratio
);
364 writel(cfg
, dev
->regs
+ GSC_MAIN_V_RATIO
);
367 void gsc_hw_set_rotation(struct gsc_ctx
*ctx
)
369 struct gsc_dev
*dev
= ctx
->gsc_dev
;
372 cfg
= readl(dev
->regs
+ GSC_IN_CON
);
373 cfg
&= ~GSC_IN_ROT_MASK
;
375 switch (ctx
->gsc_ctrls
.rotate
->val
) {
377 cfg
|= GSC_IN_ROT_270
;
380 cfg
|= GSC_IN_ROT_180
;
383 if (ctx
->gsc_ctrls
.hflip
->val
)
384 cfg
|= GSC_IN_ROT_90_XFLIP
;
385 else if (ctx
->gsc_ctrls
.vflip
->val
)
386 cfg
|= GSC_IN_ROT_90_YFLIP
;
388 cfg
|= GSC_IN_ROT_90
;
391 if (ctx
->gsc_ctrls
.hflip
->val
)
392 cfg
|= GSC_IN_ROT_XFLIP
;
393 else if (ctx
->gsc_ctrls
.vflip
->val
)
394 cfg
|= GSC_IN_ROT_YFLIP
;
397 writel(cfg
, dev
->regs
+ GSC_IN_CON
);
400 void gsc_hw_set_global_alpha(struct gsc_ctx
*ctx
)
402 struct gsc_dev
*dev
= ctx
->gsc_dev
;
403 struct gsc_frame
*frame
= &ctx
->d_frame
;
406 if (!is_rgb(frame
->fmt
->color
)) {
407 pr_debug("Not a RGB format");
411 cfg
= readl(dev
->regs
+ GSC_OUT_CON
);
412 cfg
&= ~GSC_OUT_GLOBAL_ALPHA_MASK
;
414 cfg
|= GSC_OUT_GLOBAL_ALPHA(ctx
->gsc_ctrls
.global_alpha
->val
);
415 writel(cfg
, dev
->regs
+ GSC_OUT_CON
);
418 void gsc_hw_set_sfr_update(struct gsc_ctx
*ctx
)
420 struct gsc_dev
*dev
= ctx
->gsc_dev
;
423 cfg
= readl(dev
->regs
+ GSC_ENABLE
);
424 cfg
|= GSC_ENABLE_SFR_UPDATE
;
425 writel(cfg
, dev
->regs
+ GSC_ENABLE
);