File Index
Files and directories
Sign in
FILE

sun8i_csc.c

File preview with syntax highlighting.

linux-6.19.14/drivers/gpu/drm/sun4i/sun8i_csc.c C
  1// SPDX-License-Identifier: GPL-2.0-or-later
  2/*
  3 * Copyright (C) Jernej Skrabec <jernej.skrabec@siol.net>
  4 */
  5
  6#include <drm/drm_fourcc.h>
  7#include <drm/drm_framebuffer.h>
  8#include <drm/drm_plane.h>
  9#include <drm/drm_print.h>
 10
 11#include "sun8i_csc.h"
 12#include "sun8i_mixer.h"
 13
 14enum sun8i_csc_mode {
 15	SUN8I_CSC_MODE_OFF,
 16	SUN8I_CSC_MODE_YUV2RGB,
 17	SUN8I_CSC_MODE_YVU2RGB,
 18};
 19
 20static const u32 ccsc_base[][2] = {
 21	[CCSC_MIXER0_LAYOUT]	= {CCSC00_OFFSET, CCSC01_OFFSET},
 22	[CCSC_MIXER1_LAYOUT]	= {CCSC10_OFFSET, CCSC11_OFFSET},
 23	[CCSC_D1_MIXER0_LAYOUT]	= {CCSC00_OFFSET, CCSC01_D1_OFFSET},
 24};
 25
 26/*
 27 * Factors are in two's complement format, 10 bits for fractinal part.
 28 * First tree values in each line are multiplication factor and last
 29 * value is constant, which is added at the end.
 30 */
 31
 32static const u32 yuv2rgb[2][2][12] = {
 33	[DRM_COLOR_YCBCR_LIMITED_RANGE] = {
 34		[DRM_COLOR_YCBCR_BT601] = {
 35			0x000004A8, 0x00000000, 0x00000662, 0xFFFC8451,
 36			0x000004A8, 0xFFFFFE6F, 0xFFFFFCC0, 0x00021E4D,
 37			0x000004A8, 0x00000811, 0x00000000, 0xFFFBACA9,
 38		},
 39		[DRM_COLOR_YCBCR_BT709] = {
 40			0x000004A8, 0x00000000, 0x0000072B, 0xFFFC1F99,
 41			0x000004A8, 0xFFFFFF26, 0xFFFFFDDF, 0x00013383,
 42			0x000004A8, 0x00000873, 0x00000000, 0xFFFB7BEF,
 43		}
 44	},
 45	[DRM_COLOR_YCBCR_FULL_RANGE] = {
 46		[DRM_COLOR_YCBCR_BT601] = {
 47			0x00000400, 0x00000000, 0x0000059B, 0xFFFD322E,
 48			0x00000400, 0xFFFFFEA0, 0xFFFFFD25, 0x00021DD5,
 49			0x00000400, 0x00000716, 0x00000000, 0xFFFC74BD,
 50		},
 51		[DRM_COLOR_YCBCR_BT709] = {
 52			0x00000400, 0x00000000, 0x0000064C, 0xFFFCD9B4,
 53			0x00000400, 0xFFFFFF41, 0xFFFFFE21, 0x00014F96,
 54			0x00000400, 0x0000076C, 0x00000000, 0xFFFC49EF,
 55		}
 56	},
 57};
 58
 59/*
 60 * DE3 has a bit different CSC units. Factors are in two's complement format.
 61 * First three factors in a row are multiplication factors which have 17 bits
 62 * for fractional part. Fourth value in a row is comprised of two factors.
 63 * Upper 16 bits represents difference, which is subtracted from the input
 64 * value before multiplication and lower 16 bits represents constant, which
 65 * is addes at the end.
 66 *
 67 * x' = c00 * (x + d0) + c01 * (y + d1) + c02 * (z + d2) + const0
 68 * y' = c10 * (x + d0) + c11 * (y + d1) + c12 * (z + d2) + const1
 69 * z' = c20 * (x + d0) + c21 * (y + d1) + c22 * (z + d2) + const2
 70 *
 71 * Please note that above formula is true only for Blender CSC. Other DE3 CSC
 72 * units takes only positive value for difference. From what can be deducted
 73 * from BSP driver code, those units probably automatically assume that
 74 * difference has to be subtracted.
 75 *
 76 * Layout of factors in table:
 77 * c00 c01 c02 [d0 const0]
 78 * c10 c11 c12 [d1 const1]
 79 * c20 c21 c22 [d2 const2]
 80 */
 81
 82static const u32 yuv2rgb_de3[2][3][12] = {
 83	[DRM_COLOR_YCBCR_LIMITED_RANGE] = {
 84		[DRM_COLOR_YCBCR_BT601] = {
 85			0x0002542A, 0x00000000, 0x0003312A, 0xFFC00000,
 86			0x0002542A, 0xFFFF376B, 0xFFFE5FC3, 0xFE000000,
 87			0x0002542A, 0x000408D2, 0x00000000, 0xFE000000,
 88		},
 89		[DRM_COLOR_YCBCR_BT709] = {
 90			0x0002542A, 0x00000000, 0x000395E2, 0xFFC00000,
 91			0x0002542A, 0xFFFF92D2, 0xFFFEEF27, 0xFE000000,
 92			0x0002542A, 0x0004398C, 0x00000000, 0xFE000000,
 93		},
 94		[DRM_COLOR_YCBCR_BT2020] = {
 95			0x0002542A, 0x00000000, 0x00035B7B, 0xFFC00000,
 96			0x0002542A, 0xFFFFA017, 0xFFFEB2FC, 0xFE000000,
 97			0x0002542A, 0x00044896, 0x00000000, 0xFE000000,
 98		}
 99	},
100	[DRM_COLOR_YCBCR_FULL_RANGE] = {
101		[DRM_COLOR_YCBCR_BT601] = {
102			0x00020000, 0x00000000, 0x0002CDD2, 0x00000000,
103			0x00020000, 0xFFFF4FCE, 0xFFFE925D, 0xFE000000,
104			0x00020000, 0x00038B43, 0x00000000, 0xFE000000,
105		},
106		[DRM_COLOR_YCBCR_BT709] = {
107			0x00020000, 0x00000000, 0x0003264C, 0x00000000,
108			0x00020000, 0xFFFFA018, 0xFFFF1053, 0xFE000000,
109			0x00020000, 0x0003B611, 0x00000000, 0xFE000000,
110		},
111		[DRM_COLOR_YCBCR_BT2020] = {
112			0x00020000, 0x00000000, 0x0002F2FE, 0x00000000,
113			0x00020000, 0xFFFFABC0, 0xFFFEDB78, 0xFE000000,
114			0x00020000, 0x0003C346, 0x00000000, 0xFE000000,
115		}
116	},
117};
118
119static void sun8i_csc_setup(struct regmap *map, u32 base,
120			    enum sun8i_csc_mode mode,
121			    enum drm_color_encoding encoding,
122			    enum drm_color_range range)
123{
124	u32 base_reg, val;
125	const u32 *table;
126	int i;
127
128	table = yuv2rgb[range][encoding];
129
130	switch (mode) {
131	case SUN8I_CSC_MODE_OFF:
132		val = 0;
133		break;
134	case SUN8I_CSC_MODE_YUV2RGB:
135		val = SUN8I_CSC_CTRL_EN;
136		base_reg = SUN8I_CSC_COEFF(base, 0);
137		regmap_bulk_write(map, base_reg, table, 12);
138		break;
139	case SUN8I_CSC_MODE_YVU2RGB:
140		val = SUN8I_CSC_CTRL_EN;
141		for (i = 0; i < 12; i++) {
142			if ((i & 3) == 1)
143				base_reg = SUN8I_CSC_COEFF(base, i + 1);
144			else if ((i & 3) == 2)
145				base_reg = SUN8I_CSC_COEFF(base, i - 1);
146			else
147				base_reg = SUN8I_CSC_COEFF(base, i);
148			regmap_write(map, base_reg, table[i]);
149		}
150		break;
151	default:
152		val = 0;
153		DRM_WARN("Wrong CSC mode specified.\n");
154		return;
155	}
156
157	regmap_write(map, SUN8I_CSC_CTRL(base), val);
158}
159
160static void sun8i_de3_ccsc_setup(struct regmap *map, int layer,
161				 enum sun8i_csc_mode mode,
162				 enum drm_color_encoding encoding,
163				 enum drm_color_range range)
164{
165	u32 addr, val, mask;
166	const u32 *table;
167	int i;
168
169	mask = SUN50I_MIXER_BLEND_CSC_CTL_EN(layer);
170	table = yuv2rgb_de3[range][encoding];
171
172	switch (mode) {
173	case SUN8I_CSC_MODE_OFF:
174		val = 0;
175		break;
176	case SUN8I_CSC_MODE_YUV2RGB:
177		val = mask;
178		addr = SUN50I_MIXER_BLEND_CSC_COEFF(DE3_BLD_BASE, layer, 0);
179		regmap_bulk_write(map, addr, table, 12);
180		break;
181	case SUN8I_CSC_MODE_YVU2RGB:
182		val = mask;
183		for (i = 0; i < 12; i++) {
184			if ((i & 3) == 1)
185				addr = SUN50I_MIXER_BLEND_CSC_COEFF(DE3_BLD_BASE,
186								    layer,
187								    i + 1);
188			else if ((i & 3) == 2)
189				addr = SUN50I_MIXER_BLEND_CSC_COEFF(DE3_BLD_BASE,
190								    layer,
191								    i - 1);
192			else
193				addr = SUN50I_MIXER_BLEND_CSC_COEFF(DE3_BLD_BASE,
194								    layer, i);
195			regmap_write(map, addr, table[i]);
196		}
197		break;
198	default:
199		val = 0;
200		DRM_WARN("Wrong CSC mode specified.\n");
201		return;
202	}
203
204	regmap_update_bits(map, SUN50I_MIXER_BLEND_CSC_CTL(DE3_BLD_BASE),
205			   mask, val);
206}
207
208static u32 sun8i_csc_get_mode(struct drm_plane_state *state)
209{
210	const struct drm_format_info *format;
211
212	if (!state->crtc || !state->visible)
213		return SUN8I_CSC_MODE_OFF;
214
215	format = state->fb->format;
216	if (!format->is_yuv)
217		return SUN8I_CSC_MODE_OFF;
218
219	switch (format->format) {
220	case DRM_FORMAT_YVU411:
221	case DRM_FORMAT_YVU420:
222	case DRM_FORMAT_YVU422:
223	case DRM_FORMAT_YVU444:
224		return SUN8I_CSC_MODE_YVU2RGB;
225	default:
226		return SUN8I_CSC_MODE_YUV2RGB;
227	}
228}
229
230void sun8i_csc_config(struct sun8i_layer *layer,
231		      struct drm_plane_state *state)
232{
233	u32 mode = sun8i_csc_get_mode(state);
234	u32 base;
235
236	if (layer->cfg->de_type == SUN8I_MIXER_DE3) {
237		sun8i_de3_ccsc_setup(layer->regs, layer->channel,
238				     mode, state->color_encoding,
239				     state->color_range);
240		return;
241	}
242
243	base = ccsc_base[layer->cfg->ccsc][layer->channel];
244
245	sun8i_csc_setup(layer->regs, base,
246			mode, state->color_encoding,
247			state->color_range);
248}
~/ Read-only file preview.