GNU Linux-libre 6.7.9-gnu
[releases.git] / drivers / media / platform / samsung / exynos-gsc / gsc-regs.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * Copyright (c) 2011 - 2012 Samsung Electronics Co., Ltd.
4  *              http://www.samsung.com
5  *
6  * Samsung EXYNOS5 SoC series G-Scaler driver
7  */
8
9 #include <linux/io.h>
10 #include <linux/delay.h>
11
12 #include "gsc-core.h"
13
14 void gsc_hw_set_sw_reset(struct gsc_dev *dev)
15 {
16         writel(GSC_SW_RESET_SRESET, dev->regs + GSC_SW_RESET);
17 }
18
19 int gsc_wait_reset(struct gsc_dev *dev)
20 {
21         unsigned long end = jiffies + msecs_to_jiffies(50);
22         u32 cfg;
23
24         while (time_before(jiffies, end)) {
25                 cfg = readl(dev->regs + GSC_SW_RESET);
26                 if (!cfg)
27                         return 0;
28                 usleep_range(10, 20);
29         }
30
31         return -EBUSY;
32 }
33
34 void gsc_hw_set_frm_done_irq_mask(struct gsc_dev *dev, bool mask)
35 {
36         u32 cfg;
37
38         cfg = readl(dev->regs + GSC_IRQ);
39         if (mask)
40                 cfg |= GSC_IRQ_FRMDONE_MASK;
41         else
42                 cfg &= ~GSC_IRQ_FRMDONE_MASK;
43         writel(cfg, dev->regs + GSC_IRQ);
44 }
45
46 void gsc_hw_set_gsc_irq_enable(struct gsc_dev *dev, bool mask)
47 {
48         u32 cfg;
49
50         cfg = readl(dev->regs + GSC_IRQ);
51         if (mask)
52                 cfg |= GSC_IRQ_ENABLE;
53         else
54                 cfg &= ~GSC_IRQ_ENABLE;
55         writel(cfg, dev->regs + GSC_IRQ);
56 }
57
58 void gsc_hw_set_input_buf_masking(struct gsc_dev *dev, u32 shift,
59                                 bool enable)
60 {
61         u32 cfg = readl(dev->regs + GSC_IN_BASE_ADDR_Y_MASK);
62         u32 mask = 1 << shift;
63
64         cfg &= ~mask;
65         cfg |= enable << shift;
66
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);
70 }
71
72 void gsc_hw_set_output_buf_masking(struct gsc_dev *dev, u32 shift,
73                                 bool enable)
74 {
75         u32 cfg = readl(dev->regs + GSC_OUT_BASE_ADDR_Y_MASK);
76         u32 mask = 1 << shift;
77
78         cfg &= ~mask;
79         cfg |= enable << shift;
80
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);
84 }
85
86 void gsc_hw_set_input_addr(struct gsc_dev *dev, struct gsc_addr *addr,
87                                 int index)
88 {
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));
94
95 }
96
97 void gsc_hw_set_output_addr(struct gsc_dev *dev,
98                              struct gsc_addr *addr, int index)
99 {
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));
105 }
106
107 void gsc_hw_set_input_path(struct gsc_ctx *ctx)
108 {
109         struct gsc_dev *dev = ctx->gsc_dev;
110
111         u32 cfg = readl(dev->regs + GSC_IN_CON);
112         cfg &= ~(GSC_IN_PATH_MASK | GSC_IN_LOCAL_SEL_MASK);
113
114         if (ctx->in_path == GSC_DMA)
115                 cfg |= GSC_IN_PATH_MEMORY;
116
117         writel(cfg, dev->regs + GSC_IN_CON);
118 }
119
120 void gsc_hw_set_in_size(struct gsc_ctx *ctx)
121 {
122         struct gsc_dev *dev = ctx->gsc_dev;
123         struct gsc_frame *frame = &ctx->s_frame;
124         u32 cfg;
125
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);
130
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);
135
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);
140 }
141
142 void gsc_hw_set_in_image_rgb(struct gsc_ctx *ctx)
143 {
144         struct gsc_dev *dev = ctx->gsc_dev;
145         struct gsc_frame *frame = &ctx->s_frame;
146         u32 cfg;
147
148         cfg = readl(dev->regs + GSC_IN_CON);
149         if (frame->colorspace == V4L2_COLORSPACE_REC709)
150                 cfg |= GSC_IN_RGB_HD_WIDE;
151         else
152                 cfg |= GSC_IN_RGB_SD_WIDE;
153
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;
158
159         writel(cfg, dev->regs + GSC_IN_CON);
160 }
161
162 void gsc_hw_set_in_image_format(struct gsc_ctx *ctx)
163 {
164         struct gsc_dev *dev = ctx->gsc_dev;
165         struct gsc_frame *frame = &ctx->s_frame;
166         u32 i, depth = 0;
167         u32 cfg;
168
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);
174
175         if (is_rgb(frame->fmt->color)) {
176                 gsc_hw_set_in_image_rgb(ctx);
177                 return;
178         }
179         for (i = 0; i < frame->fmt->num_planes; i++)
180                 depth += frame->fmt->depth[i];
181
182         switch (frame->fmt->num_comp) {
183         case 1:
184                 cfg |= GSC_IN_YUV422_1P;
185                 if (frame->fmt->yorder == GSC_LSB_Y)
186                         cfg |= GSC_IN_YUV422_1P_ORDER_LSB_Y;
187                 else
188                         cfg |= GSC_IN_YUV422_1P_OEDER_LSB_C;
189                 if (frame->fmt->corder == GSC_CBCR)
190                         cfg |= GSC_IN_CHROMA_ORDER_CBCR;
191                 else
192                         cfg |= GSC_IN_CHROMA_ORDER_CRCB;
193                 break;
194         case 2:
195                 if (depth == 12)
196                         cfg |= GSC_IN_YUV420_2P;
197                 else
198                         cfg |= GSC_IN_YUV422_2P;
199                 if (frame->fmt->corder == GSC_CBCR)
200                         cfg |= GSC_IN_CHROMA_ORDER_CBCR;
201                 else
202                         cfg |= GSC_IN_CHROMA_ORDER_CRCB;
203                 break;
204         case 3:
205                 if (depth == 12)
206                         cfg |= GSC_IN_YUV420_3P;
207                 else
208                         cfg |= GSC_IN_YUV422_3P;
209                 break;
210         }
211
212         if (is_tiled(frame->fmt))
213                 cfg |= GSC_IN_TILE_C_16x8 | GSC_IN_TILE_MODE;
214
215         writel(cfg, dev->regs + GSC_IN_CON);
216 }
217
218 void gsc_hw_set_output_path(struct gsc_ctx *ctx)
219 {
220         struct gsc_dev *dev = ctx->gsc_dev;
221
222         u32 cfg = readl(dev->regs + GSC_OUT_CON);
223         cfg &= ~GSC_OUT_PATH_MASK;
224
225         if (ctx->out_path == GSC_DMA)
226                 cfg |= GSC_OUT_PATH_MEMORY;
227         else
228                 cfg |= GSC_OUT_PATH_LOCAL;
229
230         writel(cfg, dev->regs + GSC_OUT_CON);
231 }
232
233 void gsc_hw_set_out_size(struct gsc_ctx *ctx)
234 {
235         struct gsc_dev *dev = ctx->gsc_dev;
236         struct gsc_frame *frame = &ctx->d_frame;
237         u32 cfg;
238
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);
244
245                 cfg = GSC_DSTIMG_WIDTH(frame->f_width);
246                 cfg |= GSC_DSTIMG_HEIGHT(frame->f_height);
247                 writel(cfg, dev->regs + GSC_DSTIMG_SIZE);
248         }
249
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);
255         } else {
256                 cfg = GSC_SCALED_WIDTH(frame->crop.width);
257                 cfg |= GSC_SCALED_HEIGHT(frame->crop.height);
258         }
259         writel(cfg, dev->regs + GSC_SCALED_SIZE);
260 }
261
262 void gsc_hw_set_out_image_rgb(struct gsc_ctx *ctx)
263 {
264         struct gsc_dev *dev = ctx->gsc_dev;
265         struct gsc_frame *frame = &ctx->d_frame;
266         u32 cfg;
267
268         cfg = readl(dev->regs + GSC_OUT_CON);
269         if (frame->colorspace == V4L2_COLORSPACE_REC709)
270                 cfg |= GSC_OUT_RGB_HD_WIDE;
271         else
272                 cfg |= GSC_OUT_RGB_SD_WIDE;
273
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;
278
279         writel(cfg, dev->regs + GSC_OUT_CON);
280 }
281
282 void gsc_hw_set_out_image_format(struct gsc_ctx *ctx)
283 {
284         struct gsc_dev *dev = ctx->gsc_dev;
285         struct gsc_frame *frame = &ctx->d_frame;
286         u32 i, depth = 0;
287         u32 cfg;
288
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);
294
295         if (is_rgb(frame->fmt->color)) {
296                 gsc_hw_set_out_image_rgb(ctx);
297                 return;
298         }
299
300         if (ctx->out_path != GSC_DMA) {
301                 cfg |= GSC_OUT_YUV444;
302                 goto end_set;
303         }
304
305         for (i = 0; i < frame->fmt->num_planes; i++)
306                 depth += frame->fmt->depth[i];
307
308         switch (frame->fmt->num_comp) {
309         case 1:
310                 cfg |= GSC_OUT_YUV422_1P;
311                 if (frame->fmt->yorder == GSC_LSB_Y)
312                         cfg |= GSC_OUT_YUV422_1P_ORDER_LSB_Y;
313                 else
314                         cfg |= GSC_OUT_YUV422_1P_OEDER_LSB_C;
315                 if (frame->fmt->corder == GSC_CBCR)
316                         cfg |= GSC_OUT_CHROMA_ORDER_CBCR;
317                 else
318                         cfg |= GSC_OUT_CHROMA_ORDER_CRCB;
319                 break;
320         case 2:
321                 if (depth == 12)
322                         cfg |= GSC_OUT_YUV420_2P;
323                 else
324                         cfg |= GSC_OUT_YUV422_2P;
325                 if (frame->fmt->corder == GSC_CBCR)
326                         cfg |= GSC_OUT_CHROMA_ORDER_CBCR;
327                 else
328                         cfg |= GSC_OUT_CHROMA_ORDER_CRCB;
329                 break;
330         case 3:
331                 cfg |= GSC_OUT_YUV420_3P;
332                 break;
333         }
334
335         if (is_tiled(frame->fmt))
336                 cfg |= GSC_OUT_TILE_C_16x8 | GSC_OUT_TILE_MODE;
337
338 end_set:
339         writel(cfg, dev->regs + GSC_OUT_CON);
340 }
341
342 void gsc_hw_set_prescaler(struct gsc_ctx *ctx)
343 {
344         struct gsc_dev *dev = ctx->gsc_dev;
345         struct gsc_scaler *sc = &ctx->scaler;
346         u32 cfg;
347
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);
352 }
353
354 void gsc_hw_set_mainscaler(struct gsc_ctx *ctx)
355 {
356         struct gsc_dev *dev = ctx->gsc_dev;
357         struct gsc_scaler *sc = &ctx->scaler;
358         u32 cfg;
359
360         cfg = GSC_MAIN_H_RATIO_VALUE(sc->main_hratio);
361         writel(cfg, dev->regs + GSC_MAIN_H_RATIO);
362
363         cfg = GSC_MAIN_V_RATIO_VALUE(sc->main_vratio);
364         writel(cfg, dev->regs + GSC_MAIN_V_RATIO);
365 }
366
367 void gsc_hw_set_rotation(struct gsc_ctx *ctx)
368 {
369         struct gsc_dev *dev = ctx->gsc_dev;
370         u32 cfg;
371
372         cfg = readl(dev->regs + GSC_IN_CON);
373         cfg &= ~GSC_IN_ROT_MASK;
374
375         switch (ctx->gsc_ctrls.rotate->val) {
376         case 270:
377                 cfg |= GSC_IN_ROT_270;
378                 break;
379         case 180:
380                 cfg |= GSC_IN_ROT_180;
381                 break;
382         case 90:
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;
387                 else
388                         cfg |= GSC_IN_ROT_90;
389                 break;
390         case 0:
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;
395         }
396
397         writel(cfg, dev->regs + GSC_IN_CON);
398 }
399
400 void gsc_hw_set_global_alpha(struct gsc_ctx *ctx)
401 {
402         struct gsc_dev *dev = ctx->gsc_dev;
403         struct gsc_frame *frame = &ctx->d_frame;
404         u32 cfg;
405
406         if (!is_rgb(frame->fmt->color)) {
407                 pr_debug("Not a RGB format");
408                 return;
409         }
410
411         cfg = readl(dev->regs + GSC_OUT_CON);
412         cfg &= ~GSC_OUT_GLOBAL_ALPHA_MASK;
413
414         cfg |= GSC_OUT_GLOBAL_ALPHA(ctx->gsc_ctrls.global_alpha->val);
415         writel(cfg, dev->regs + GSC_OUT_CON);
416 }
417
418 void gsc_hw_set_sfr_update(struct gsc_ctx *ctx)
419 {
420         struct gsc_dev *dev = ctx->gsc_dev;
421         u32 cfg;
422
423         cfg = readl(dev->regs + GSC_ENABLE);
424         cfg |= GSC_ENABLE_SFR_UPDATE;
425         writel(cfg, dev->regs + GSC_ENABLE);
426 }