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
14void gsc_hw_set_sw_reset(struct gsc_dev *dev)
15{
16	writel(GSC_SW_RESET_SRESET, dev->regs + GSC_SW_RESET);
17}
18
19int 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
34void 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
46void 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
58void 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
72void 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
86void 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
97void 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
107void 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
120void 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
142void 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
162void 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
218void 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
233void 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
262void 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
282void 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
338end_set:
339	writel(cfg, dev->regs + GSC_OUT_CON);
340}
341
342void 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
354void 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
367void 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
400void 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
418void 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