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 }
427