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