blob: 6f5b5a486cf361f8c52f74db5bc5e62e94a31491 [file] [log] [blame]
Sungchun Kang199854a2012-07-31 10:44:03 -03001/*
2 * Copyright (c) 2011 - 2012 Samsung Electronics Co., Ltd.
3 * http://www.samsung.com
4 *
5 * Samsung EXYNOS5 SoC series G-Scaler driver
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 as published
9 * by the Free Software Foundation, either version 2 of the License,
10 * or (at your option) any later version.
11 */
12
13#include <linux/io.h>
14#include <linux/delay.h>
15#include <mach/map.h>
16
17#include "gsc-core.h"
18
19void gsc_hw_set_sw_reset(struct gsc_dev *dev)
20{
21 writel(GSC_SW_RESET_SRESET, dev->regs + GSC_SW_RESET);
22}
23
24int gsc_wait_reset(struct gsc_dev *dev)
25{
26 unsigned long end = jiffies + msecs_to_jiffies(50);
27 u32 cfg;
28
29 while (time_before(jiffies, end)) {
30 cfg = readl(dev->regs + GSC_SW_RESET);
31 if (!cfg)
32 return 0;
33 usleep_range(10, 20);
34 }
35
36 return -EBUSY;
37}
38
39void gsc_hw_set_frm_done_irq_mask(struct gsc_dev *dev, bool mask)
40{
41 u32 cfg;
42
43 cfg = readl(dev->regs + GSC_IRQ);
44 if (mask)
45 cfg |= GSC_IRQ_FRMDONE_MASK;
46 else
47 cfg &= ~GSC_IRQ_FRMDONE_MASK;
48 writel(cfg, dev->regs + GSC_IRQ);
49}
50
51void gsc_hw_set_gsc_irq_enable(struct gsc_dev *dev, bool mask)
52{
53 u32 cfg;
54
55 cfg = readl(dev->regs + GSC_IRQ);
56 if (mask)
57 cfg |= GSC_IRQ_ENABLE;
58 else
59 cfg &= ~GSC_IRQ_ENABLE;
60 writel(cfg, dev->regs + GSC_IRQ);
61}
62
63void gsc_hw_set_input_buf_masking(struct gsc_dev *dev, u32 shift,
64 bool enable)
65{
66 u32 cfg = readl(dev->regs + GSC_IN_BASE_ADDR_Y_MASK);
67 u32 mask = 1 << shift;
68
69 cfg &= ~mask;
70 cfg |= enable << shift;
71
72 writel(cfg, dev->regs + GSC_IN_BASE_ADDR_Y_MASK);
73 writel(cfg, dev->regs + GSC_IN_BASE_ADDR_CB_MASK);
74 writel(cfg, dev->regs + GSC_IN_BASE_ADDR_CR_MASK);
75}
76
77void gsc_hw_set_output_buf_masking(struct gsc_dev *dev, u32 shift,
78 bool enable)
79{
80 u32 cfg = readl(dev->regs + GSC_OUT_BASE_ADDR_Y_MASK);
81 u32 mask = 1 << shift;
82
83 cfg &= ~mask;
84 cfg |= enable << shift;
85
86 writel(cfg, dev->regs + GSC_OUT_BASE_ADDR_Y_MASK);
87 writel(cfg, dev->regs + GSC_OUT_BASE_ADDR_CB_MASK);
88 writel(cfg, dev->regs + GSC_OUT_BASE_ADDR_CR_MASK);
89}
90
91void gsc_hw_set_input_addr(struct gsc_dev *dev, struct gsc_addr *addr,
92 int index)
93{
94 pr_debug("src_buf[%d]: 0x%X, cb: 0x%X, cr: 0x%X", index,
95 addr->y, addr->cb, addr->cr);
96 writel(addr->y, dev->regs + GSC_IN_BASE_ADDR_Y(index));
97 writel(addr->cb, dev->regs + GSC_IN_BASE_ADDR_CB(index));
98 writel(addr->cr, dev->regs + GSC_IN_BASE_ADDR_CR(index));
99
100}
101
102void gsc_hw_set_output_addr(struct gsc_dev *dev,
103 struct gsc_addr *addr, int index)
104{
105 pr_debug("dst_buf[%d]: 0x%X, cb: 0x%X, cr: 0x%X",
106 index, addr->y, addr->cb, addr->cr);
107 writel(addr->y, dev->regs + GSC_OUT_BASE_ADDR_Y(index));
108 writel(addr->cb, dev->regs + GSC_OUT_BASE_ADDR_CB(index));
109 writel(addr->cr, dev->regs + GSC_OUT_BASE_ADDR_CR(index));
110}
111
112void gsc_hw_set_input_path(struct gsc_ctx *ctx)
113{
114 struct gsc_dev *dev = ctx->gsc_dev;
115
116 u32 cfg = readl(dev->regs + GSC_IN_CON);
117 cfg &= ~(GSC_IN_PATH_MASK | GSC_IN_LOCAL_SEL_MASK);
118
119 if (ctx->in_path == GSC_DMA)
120 cfg |= GSC_IN_PATH_MEMORY;
121
122 writel(cfg, dev->regs + GSC_IN_CON);
123}
124
125void gsc_hw_set_in_size(struct gsc_ctx *ctx)
126{
127 struct gsc_dev *dev = ctx->gsc_dev;
128 struct gsc_frame *frame = &ctx->s_frame;
129 u32 cfg;
130
131 /* Set input pixel offset */
132 cfg = GSC_SRCIMG_OFFSET_X(frame->crop.left);
133 cfg |= GSC_SRCIMG_OFFSET_Y(frame->crop.top);
134 writel(cfg, dev->regs + GSC_SRCIMG_OFFSET);
135
136 /* Set input original size */
137 cfg = GSC_SRCIMG_WIDTH(frame->f_width);
138 cfg |= GSC_SRCIMG_HEIGHT(frame->f_height);
139 writel(cfg, dev->regs + GSC_SRCIMG_SIZE);
140
141 /* Set input cropped size */
142 cfg = GSC_CROPPED_WIDTH(frame->crop.width);
143 cfg |= GSC_CROPPED_HEIGHT(frame->crop.height);
144 writel(cfg, dev->regs + GSC_CROPPED_SIZE);
145}
146
147void gsc_hw_set_in_image_rgb(struct gsc_ctx *ctx)
148{
149 struct gsc_dev *dev = ctx->gsc_dev;
150 struct gsc_frame *frame = &ctx->s_frame;
151 u32 cfg;
152
153 cfg = readl(dev->regs + GSC_IN_CON);
154 if (frame->colorspace == V4L2_COLORSPACE_REC709)
155 cfg |= GSC_IN_RGB_HD_WIDE;
156 else
157 cfg |= GSC_IN_RGB_SD_WIDE;
158
159 if (frame->fmt->pixelformat == V4L2_PIX_FMT_RGB565X)
160 cfg |= GSC_IN_RGB565;
161 else if (frame->fmt->pixelformat == V4L2_PIX_FMT_RGB32)
162 cfg |= GSC_IN_XRGB8888;
163
164 writel(cfg, dev->regs + GSC_IN_CON);
165}
166
167void gsc_hw_set_in_image_format(struct gsc_ctx *ctx)
168{
169 struct gsc_dev *dev = ctx->gsc_dev;
170 struct gsc_frame *frame = &ctx->s_frame;
171 u32 i, depth = 0;
172 u32 cfg;
173
174 cfg = readl(dev->regs + GSC_IN_CON);
175 cfg &= ~(GSC_IN_RGB_TYPE_MASK | GSC_IN_YUV422_1P_ORDER_MASK |
176 GSC_IN_CHROMA_ORDER_MASK | GSC_IN_FORMAT_MASK |
177 GSC_IN_TILE_TYPE_MASK | GSC_IN_TILE_MODE);
178 writel(cfg, dev->regs + GSC_IN_CON);
179
180 if (is_rgb(frame->fmt->color)) {
181 gsc_hw_set_in_image_rgb(ctx);
182 return;
183 }
184 for (i = 0; i < frame->fmt->num_planes; i++)
185 depth += frame->fmt->depth[i];
186
187 switch (frame->fmt->num_comp) {
188 case 1:
189 cfg |= GSC_IN_YUV422_1P;
190 if (frame->fmt->yorder == GSC_LSB_Y)
191 cfg |= GSC_IN_YUV422_1P_ORDER_LSB_Y;
192 else
193 cfg |= GSC_IN_YUV422_1P_OEDER_LSB_C;
194 if (frame->fmt->corder == GSC_CBCR)
195 cfg |= GSC_IN_CHROMA_ORDER_CBCR;
196 else
197 cfg |= GSC_IN_CHROMA_ORDER_CRCB;
198 break;
199 case 2:
200 if (depth == 12)
201 cfg |= GSC_IN_YUV420_2P;
202 else
203 cfg |= GSC_IN_YUV422_2P;
204 if (frame->fmt->corder == GSC_CBCR)
205 cfg |= GSC_IN_CHROMA_ORDER_CBCR;
206 else
207 cfg |= GSC_IN_CHROMA_ORDER_CRCB;
208 break;
209 case 3:
210 if (depth == 12)
211 cfg |= GSC_IN_YUV420_3P;
212 else
213 cfg |= GSC_IN_YUV422_3P;
214 break;
Peter Senna Tschudinc2c1b412012-09-28 05:37:22 -0300215 }
Sungchun Kang199854a2012-07-31 10:44:03 -0300216
Shaik Ameer Bashaaecede42012-11-07 03:37:07 -0300217 if (is_tiled(frame->fmt))
218 cfg |= GSC_IN_TILE_C_16x8 | GSC_IN_TILE_MODE;
219
Sungchun Kang199854a2012-07-31 10:44:03 -0300220 writel(cfg, dev->regs + GSC_IN_CON);
221}
222
223void gsc_hw_set_output_path(struct gsc_ctx *ctx)
224{
225 struct gsc_dev *dev = ctx->gsc_dev;
226
227 u32 cfg = readl(dev->regs + GSC_OUT_CON);
228 cfg &= ~GSC_OUT_PATH_MASK;
229
230 if (ctx->out_path == GSC_DMA)
231 cfg |= GSC_OUT_PATH_MEMORY;
232 else
233 cfg |= GSC_OUT_PATH_LOCAL;
234
235 writel(cfg, dev->regs + GSC_OUT_CON);
236}
237
238void gsc_hw_set_out_size(struct gsc_ctx *ctx)
239{
240 struct gsc_dev *dev = ctx->gsc_dev;
241 struct gsc_frame *frame = &ctx->d_frame;
242 u32 cfg;
243
244 /* Set output original size */
245 if (ctx->out_path == GSC_DMA) {
246 cfg = GSC_DSTIMG_OFFSET_X(frame->crop.left);
247 cfg |= GSC_DSTIMG_OFFSET_Y(frame->crop.top);
248 writel(cfg, dev->regs + GSC_DSTIMG_OFFSET);
249
250 cfg = GSC_DSTIMG_WIDTH(frame->f_width);
251 cfg |= GSC_DSTIMG_HEIGHT(frame->f_height);
252 writel(cfg, dev->regs + GSC_DSTIMG_SIZE);
253 }
254
255 /* Set output scaled size */
256 if (ctx->gsc_ctrls.rotate->val == 90 ||
257 ctx->gsc_ctrls.rotate->val == 270) {
258 cfg = GSC_SCALED_WIDTH(frame->crop.height);
259 cfg |= GSC_SCALED_HEIGHT(frame->crop.width);
260 } else {
261 cfg = GSC_SCALED_WIDTH(frame->crop.width);
262 cfg |= GSC_SCALED_HEIGHT(frame->crop.height);
263 }
264 writel(cfg, dev->regs + GSC_SCALED_SIZE);
265}
266
267void gsc_hw_set_out_image_rgb(struct gsc_ctx *ctx)
268{
269 struct gsc_dev *dev = ctx->gsc_dev;
270 struct gsc_frame *frame = &ctx->d_frame;
271 u32 cfg;
272
273 cfg = readl(dev->regs + GSC_OUT_CON);
274 if (frame->colorspace == V4L2_COLORSPACE_REC709)
275 cfg |= GSC_OUT_RGB_HD_WIDE;
276 else
277 cfg |= GSC_OUT_RGB_SD_WIDE;
278
279 if (frame->fmt->pixelformat == V4L2_PIX_FMT_RGB565X)
280 cfg |= GSC_OUT_RGB565;
281 else if (frame->fmt->pixelformat == V4L2_PIX_FMT_RGB32)
282 cfg |= GSC_OUT_XRGB8888;
283
284 writel(cfg, dev->regs + GSC_OUT_CON);
285}
286
287void gsc_hw_set_out_image_format(struct gsc_ctx *ctx)
288{
289 struct gsc_dev *dev = ctx->gsc_dev;
290 struct gsc_frame *frame = &ctx->d_frame;
291 u32 i, depth = 0;
292 u32 cfg;
293
294 cfg = readl(dev->regs + GSC_OUT_CON);
295 cfg &= ~(GSC_OUT_RGB_TYPE_MASK | GSC_OUT_YUV422_1P_ORDER_MASK |
296 GSC_OUT_CHROMA_ORDER_MASK | GSC_OUT_FORMAT_MASK |
297 GSC_OUT_TILE_TYPE_MASK | GSC_OUT_TILE_MODE);
298 writel(cfg, dev->regs + GSC_OUT_CON);
299
300 if (is_rgb(frame->fmt->color)) {
301 gsc_hw_set_out_image_rgb(ctx);
302 return;
303 }
304
305 if (ctx->out_path != GSC_DMA) {
306 cfg |= GSC_OUT_YUV444;
307 goto end_set;
308 }
309
310 for (i = 0; i < frame->fmt->num_planes; i++)
311 depth += frame->fmt->depth[i];
312
313 switch (frame->fmt->num_comp) {
314 case 1:
315 cfg |= GSC_OUT_YUV422_1P;
316 if (frame->fmt->yorder == GSC_LSB_Y)
317 cfg |= GSC_OUT_YUV422_1P_ORDER_LSB_Y;
318 else
319 cfg |= GSC_OUT_YUV422_1P_OEDER_LSB_C;
320 if (frame->fmt->corder == GSC_CBCR)
321 cfg |= GSC_OUT_CHROMA_ORDER_CBCR;
322 else
323 cfg |= GSC_OUT_CHROMA_ORDER_CRCB;
324 break;
325 case 2:
326 if (depth == 12)
327 cfg |= GSC_OUT_YUV420_2P;
328 else
329 cfg |= GSC_OUT_YUV422_2P;
330 if (frame->fmt->corder == GSC_CBCR)
331 cfg |= GSC_OUT_CHROMA_ORDER_CBCR;
332 else
333 cfg |= GSC_OUT_CHROMA_ORDER_CRCB;
334 break;
335 case 3:
336 cfg |= GSC_OUT_YUV420_3P;
337 break;
Peter Senna Tschudinc2c1b412012-09-28 05:37:22 -0300338 }
Sungchun Kang199854a2012-07-31 10:44:03 -0300339
Shaik Ameer Bashaaecede42012-11-07 03:37:07 -0300340 if (is_tiled(frame->fmt))
341 cfg |= GSC_OUT_TILE_C_16x8 | GSC_OUT_TILE_MODE;
342
Sungchun Kang199854a2012-07-31 10:44:03 -0300343end_set:
344 writel(cfg, dev->regs + GSC_OUT_CON);
345}
346
347void gsc_hw_set_prescaler(struct gsc_ctx *ctx)
348{
349 struct gsc_dev *dev = ctx->gsc_dev;
350 struct gsc_scaler *sc = &ctx->scaler;
351 u32 cfg;
352
353 cfg = GSC_PRESC_SHFACTOR(sc->pre_shfactor);
354 cfg |= GSC_PRESC_H_RATIO(sc->pre_hratio);
355 cfg |= GSC_PRESC_V_RATIO(sc->pre_vratio);
356 writel(cfg, dev->regs + GSC_PRE_SCALE_RATIO);
357}
358
359void gsc_hw_set_mainscaler(struct gsc_ctx *ctx)
360{
361 struct gsc_dev *dev = ctx->gsc_dev;
362 struct gsc_scaler *sc = &ctx->scaler;
363 u32 cfg;
364
365 cfg = GSC_MAIN_H_RATIO_VALUE(sc->main_hratio);
366 writel(cfg, dev->regs + GSC_MAIN_H_RATIO);
367
368 cfg = GSC_MAIN_V_RATIO_VALUE(sc->main_vratio);
369 writel(cfg, dev->regs + GSC_MAIN_V_RATIO);
370}
371
372void gsc_hw_set_rotation(struct gsc_ctx *ctx)
373{
374 struct gsc_dev *dev = ctx->gsc_dev;
375 u32 cfg;
376
377 cfg = readl(dev->regs + GSC_IN_CON);
378 cfg &= ~GSC_IN_ROT_MASK;
379
380 switch (ctx->gsc_ctrls.rotate->val) {
381 case 270:
382 cfg |= GSC_IN_ROT_270;
383 break;
384 case 180:
385 cfg |= GSC_IN_ROT_180;
386 break;
387 case 90:
388 if (ctx->gsc_ctrls.hflip->val)
389 cfg |= GSC_IN_ROT_90_XFLIP;
390 else if (ctx->gsc_ctrls.vflip->val)
391 cfg |= GSC_IN_ROT_90_YFLIP;
392 else
393 cfg |= GSC_IN_ROT_90;
394 break;
395 case 0:
396 if (ctx->gsc_ctrls.hflip->val)
397 cfg |= GSC_IN_ROT_XFLIP;
398 else if (ctx->gsc_ctrls.vflip->val)
399 cfg |= GSC_IN_ROT_YFLIP;
400 }
401
402 writel(cfg, dev->regs + GSC_IN_CON);
403}
404
405void gsc_hw_set_global_alpha(struct gsc_ctx *ctx)
406{
407 struct gsc_dev *dev = ctx->gsc_dev;
408 struct gsc_frame *frame = &ctx->d_frame;
409 u32 cfg;
410
411 if (!is_rgb(frame->fmt->color)) {
412 pr_debug("Not a RGB format");
413 return;
414 }
415
416 cfg = readl(dev->regs + GSC_OUT_CON);
417 cfg &= ~GSC_OUT_GLOBAL_ALPHA_MASK;
418
419 cfg |= GSC_OUT_GLOBAL_ALPHA(ctx->gsc_ctrls.global_alpha->val);
420 writel(cfg, dev->regs + GSC_OUT_CON);
421}
422
423void gsc_hw_set_sfr_update(struct gsc_ctx *ctx)
424{
425 struct gsc_dev *dev = ctx->gsc_dev;
426 u32 cfg;
427
428 cfg = readl(dev->regs + GSC_ENABLE);
429 cfg |= GSC_ENABLE_SFR_UPDATE;
430 writel(cfg, dev->regs + GSC_ENABLE);
431}