Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

drm/sun4i: Add basic support for DE3

Display Engine 3 is an upgrade of DE2 with new features like support for
10 bit color formats and support for AFBC.

Most of DE2 code works with DE3, except some small details.

Implement basic support for DE3. Support for 10 bit colort formats and
AFBC, among others missing features, will be added later.

Signed-off-by: Jernej Skrabec <jernej.skrabec@siol.net>
Signed-off-by: Maxime Ripard <maxime.ripard@bootlin.com>
Link: https://patchwork.freedesktop.org/patch/260238/

authored by

Jernej Skrabec and committed by
Maxime Ripard
c50519e6 97eb57fe

+201 -16
+83
drivers/gpu/drm/sun4i/sun8i_csc.c
··· 34 34 0x000004A8, 0x00000000, 0x00000813, 0xFFFBAC4A, 35 35 }; 36 36 37 + /* 38 + * DE3 has a bit different CSC units. Factors are in two's complement format. 39 + * First three factors in a row are multiplication factors which have 17 bits 40 + * for fractional part. Fourth value in a row is comprised of two factors. 41 + * Upper 16 bits represents difference, which is subtracted from the input 42 + * value before multiplication and lower 16 bits represents constant, which 43 + * is addes at the end. 44 + * 45 + * x' = c00 * (x + d0) + c01 * (y + d1) + c02 * (z + d2) + const0 46 + * y' = c10 * (x + d0) + c11 * (y + d1) + c12 * (z + d2) + const1 47 + * z' = c20 * (x + d0) + c21 * (y + d1) + c22 * (z + d2) + const2 48 + * 49 + * Please note that above formula is true only for Blender CSC. Other DE3 CSC 50 + * units takes only positive value for difference. From what can be deducted 51 + * from BSP driver code, those units probably automatically assume that 52 + * difference has to be subtracted. 53 + * 54 + * Layout of factors in table: 55 + * c00 c01 c02 [d0 const0] 56 + * c10 c11 c12 [d1 const1] 57 + * c20 c21 c22 [d2 const2] 58 + */ 59 + 60 + static const u32 yuv2rgb_de3[] = { 61 + 0x0002542a, 0x00000000, 0x0003312a, 0xffc00000, 62 + 0x0002542a, 0xffff376b, 0xfffe5fc3, 0xfe000000, 63 + 0x0002542a, 0x000408d3, 0x00000000, 0xfe000000, 64 + }; 65 + 66 + static const u32 yvu2rgb_de3[] = { 67 + 0x0002542a, 0x0003312a, 0x00000000, 0xffc00000, 68 + 0x0002542a, 0xfffe5fc3, 0xffff376b, 0xfe000000, 69 + 0x0002542a, 0x00000000, 0x000408d3, 0xfe000000, 70 + }; 71 + 37 72 static void sun8i_csc_set_coefficients(struct regmap *map, u32 base, 38 73 enum sun8i_csc_mode mode) 39 74 { ··· 96 61 } 97 62 } 98 63 64 + static void sun8i_de3_ccsc_set_coefficients(struct regmap *map, int layer, 65 + enum sun8i_csc_mode mode) 66 + { 67 + const u32 *table; 68 + u32 base_reg; 69 + 70 + switch (mode) { 71 + case SUN8I_CSC_MODE_YUV2RGB: 72 + table = yuv2rgb_de3; 73 + break; 74 + case SUN8I_CSC_MODE_YVU2RGB: 75 + table = yvu2rgb_de3; 76 + break; 77 + default: 78 + DRM_WARN("Wrong CSC mode specified.\n"); 79 + return; 80 + } 81 + 82 + base_reg = SUN50I_MIXER_BLEND_CSC_COEFF(DE3_BLD_BASE, layer, 0, 0); 83 + regmap_bulk_write(map, base_reg, table, 12); 84 + } 85 + 99 86 static void sun8i_csc_enable(struct regmap *map, u32 base, bool enable) 100 87 { 101 88 u32 val; ··· 130 73 regmap_update_bits(map, SUN8I_CSC_CTRL(base), SUN8I_CSC_CTRL_EN, val); 131 74 } 132 75 76 + static void sun8i_de3_ccsc_enable(struct regmap *map, int layer, bool enable) 77 + { 78 + u32 val, mask; 79 + 80 + mask = SUN50I_MIXER_BLEND_CSC_CTL_EN(layer); 81 + 82 + if (enable) 83 + val = mask; 84 + else 85 + val = 0; 86 + 87 + regmap_update_bits(map, SUN50I_MIXER_BLEND_CSC_CTL(DE3_BLD_BASE), 88 + mask, val); 89 + } 90 + 133 91 void sun8i_csc_set_ccsc_coefficients(struct sun8i_mixer *mixer, int layer, 134 92 enum sun8i_csc_mode mode) 135 93 { 136 94 u32 base; 95 + 96 + if (mixer->cfg->is_de3) { 97 + sun8i_de3_ccsc_set_coefficients(mixer->engine.regs, 98 + layer, mode); 99 + return; 100 + } 137 101 138 102 base = ccsc_base[mixer->cfg->ccsc][layer]; 139 103 ··· 164 86 void sun8i_csc_enable_ccsc(struct sun8i_mixer *mixer, int layer, bool enable) 165 87 { 166 88 u32 base; 89 + 90 + if (mixer->cfg->is_de3) { 91 + sun8i_de3_ccsc_enable(mixer->engine.regs, layer, enable); 92 + return; 93 + } 167 94 168 95 base = ccsc_base[mixer->cfg->ccsc][layer]; 169 96
+26 -11
drivers/gpu/drm/sun4i/sun8i_mixer.c
··· 459 459 460 460 base = sun8i_blender_base(mixer); 461 461 462 - /* Reset the registers */ 463 - for (i = 0; i < DE2_MIXER_UNIT_SIZE; i += 4) 464 - regmap_write(mixer->engine.regs, i, 0); 462 + /* Reset registers and disable unused sub-engines */ 463 + if (mixer->cfg->is_de3) { 464 + for (i = 0; i < DE3_MIXER_UNIT_SIZE; i += 4) 465 + regmap_write(mixer->engine.regs, i, 0); 465 466 466 - /* Disable unused sub-engines */ 467 - regmap_write(mixer->engine.regs, SUN8I_MIXER_FCE_EN, 0); 468 - regmap_write(mixer->engine.regs, SUN8I_MIXER_BWS_EN, 0); 469 - regmap_write(mixer->engine.regs, SUN8I_MIXER_LTI_EN, 0); 470 - regmap_write(mixer->engine.regs, SUN8I_MIXER_PEAK_EN, 0); 471 - regmap_write(mixer->engine.regs, SUN8I_MIXER_ASE_EN, 0); 472 - regmap_write(mixer->engine.regs, SUN8I_MIXER_FCC_EN, 0); 473 - regmap_write(mixer->engine.regs, SUN8I_MIXER_DCSC_EN, 0); 467 + regmap_write(mixer->engine.regs, SUN50I_MIXER_FCE_EN, 0); 468 + regmap_write(mixer->engine.regs, SUN50I_MIXER_PEAK_EN, 0); 469 + regmap_write(mixer->engine.regs, SUN50I_MIXER_LCTI_EN, 0); 470 + regmap_write(mixer->engine.regs, SUN50I_MIXER_BLS_EN, 0); 471 + regmap_write(mixer->engine.regs, SUN50I_MIXER_FCC_EN, 0); 472 + regmap_write(mixer->engine.regs, SUN50I_MIXER_DNS_EN, 0); 473 + regmap_write(mixer->engine.regs, SUN50I_MIXER_DRC_EN, 0); 474 + regmap_write(mixer->engine.regs, SUN50I_MIXER_FMT_EN, 0); 475 + regmap_write(mixer->engine.regs, SUN50I_MIXER_CDC0_EN, 0); 476 + regmap_write(mixer->engine.regs, SUN50I_MIXER_CDC1_EN, 0); 477 + } else { 478 + for (i = 0; i < DE2_MIXER_UNIT_SIZE; i += 4) 479 + regmap_write(mixer->engine.regs, i, 0); 480 + 481 + regmap_write(mixer->engine.regs, SUN8I_MIXER_FCE_EN, 0); 482 + regmap_write(mixer->engine.regs, SUN8I_MIXER_BWS_EN, 0); 483 + regmap_write(mixer->engine.regs, SUN8I_MIXER_LTI_EN, 0); 484 + regmap_write(mixer->engine.regs, SUN8I_MIXER_PEAK_EN, 0); 485 + regmap_write(mixer->engine.regs, SUN8I_MIXER_ASE_EN, 0); 486 + regmap_write(mixer->engine.regs, SUN8I_MIXER_FCC_EN, 0); 487 + regmap_write(mixer->engine.regs, SUN8I_MIXER_DCSC_EN, 0); 488 + } 474 489 475 490 /* Enable the mixer */ 476 491 regmap_write(mixer->engine.regs, SUN8I_MIXER_GLOBAL_CTL,
+32 -2
drivers/gpu/drm/sun4i/sun8i_mixer.h
··· 30 30 #define SUN8I_MIXER_GLOBAL_DBUFF_ENABLE BIT(0) 31 31 32 32 #define DE2_MIXER_UNIT_SIZE 0x6000 33 + #define DE3_MIXER_UNIT_SIZE 0x3000 33 34 34 35 #define DE2_BLD_BASE 0x1000 35 36 #define DE2_CH_BASE 0x2000 36 37 #define DE2_CH_SIZE 0x1000 38 + 39 + #define DE3_BLD_BASE 0x0800 40 + #define DE3_CH_BASE 0x1000 41 + #define DE3_CH_SIZE 0x0800 37 42 38 43 #define SUN8I_MIXER_BLEND_PIPE_CTL(base) ((base) + 0) 39 44 #define SUN8I_MIXER_BLEND_ATTR_FCOLOR(base, x) ((base) + 0x4 + 0x10 * (x)) ··· 54 49 #define SUN8I_MIXER_BLEND_CK_MAX(base, x) ((base) + 0xc0 + 0x04 * (x)) 55 50 #define SUN8I_MIXER_BLEND_CK_MIN(base, x) ((base) + 0xe0 + 0x04 * (x)) 56 51 #define SUN8I_MIXER_BLEND_OUTCTL(base) ((base) + 0xfc) 52 + #define SUN50I_MIXER_BLEND_CSC_CTL(base) ((base) + 0x100) 53 + #define SUN50I_MIXER_BLEND_CSC_COEFF(base, layer, x, y) \ 54 + ((base) + 0x110 + (layer) * 0x30 + (x) * 0x10 + 4 * (y)) 55 + #define SUN50I_MIXER_BLEND_CSC_CONST(base, layer, i) \ 56 + ((base) + 0x110 + (layer) * 0x30 + (i) * 0x10 + 0x0c) 57 57 58 58 #define SUN8I_MIXER_BLEND_PIPE_CTL_EN_MSK GENMASK(12, 8) 59 59 #define SUN8I_MIXER_BLEND_PIPE_CTL_EN(pipe) BIT(8 + pipe) 60 60 #define SUN8I_MIXER_BLEND_PIPE_CTL_FC_EN(pipe) BIT(pipe) 61 + 61 62 /* colors are always in AARRGGBB format */ 62 63 #define SUN8I_MIXER_BLEND_COLOR_BLACK 0xff000000 63 64 /* The following numbers are some still unknown magic numbers */ ··· 73 62 #define SUN8I_MIXER_BLEND_ROUTE_PIPE_SHIFT(n) ((n) << 2) 74 63 75 64 #define SUN8I_MIXER_BLEND_OUTCTL_INTERLACED BIT(1) 65 + 66 + #define SUN50I_MIXER_BLEND_CSC_CTL_EN(ch) BIT(ch) 67 + #define SUN50I_MIXER_BLEND_CSC_CONST_VAL(d, c) (((d) << 16) | ((c) & 0xffff)) 76 68 77 69 #define SUN8I_MIXER_FBFMT_ARGB8888 0 78 70 #define SUN8I_MIXER_FBFMT_ABGR8888 1 ··· 126 112 #define SUN8I_MIXER_FCC_EN 0xaa000 127 113 #define SUN8I_MIXER_DCSC_EN 0xb0000 128 114 115 + #define SUN50I_MIXER_FCE_EN 0x70000 116 + #define SUN50I_MIXER_PEAK_EN 0x70800 117 + #define SUN50I_MIXER_LCTI_EN 0x71000 118 + #define SUN50I_MIXER_BLS_EN 0x71800 119 + #define SUN50I_MIXER_FCC_EN 0x72000 120 + #define SUN50I_MIXER_DNS_EN 0x80000 121 + #define SUN50I_MIXER_DRC_EN 0xa0000 122 + #define SUN50I_MIXER_FMT_EN 0xa8000 123 + #define SUN50I_MIXER_CDC0_EN 0xd0000 124 + #define SUN50I_MIXER_CDC1_EN 0xd8000 125 + 129 126 struct de2_fmt_info { 130 127 u32 drm_fmt; 131 128 u32 de2_fmt; ··· 158 133 * are invalid. 159 134 * @mod_rate: module clock rate that needs to be set in order to have 160 135 * a functional block. 136 + * @is_de3: true, if this is next gen display engine 3.0, false otherwise. 161 137 */ 162 138 struct sun8i_mixer_cfg { 163 139 int vi_num; ··· 166 140 int scaler_mask; 167 141 int ccsc; 168 142 unsigned long mod_rate; 143 + unsigned int is_de3 : 1; 169 144 }; 170 145 171 146 struct sun8i_mixer { ··· 189 162 static inline u32 190 163 sun8i_blender_base(struct sun8i_mixer *mixer) 191 164 { 192 - return DE2_BLD_BASE; 165 + return mixer->cfg->is_de3 ? DE3_BLD_BASE : DE2_BLD_BASE; 193 166 } 194 167 195 168 static inline u32 196 169 sun8i_channel_base(struct sun8i_mixer *mixer, int channel) 197 170 { 198 - return DE2_CH_BASE + channel * DE2_CH_SIZE; 171 + if (mixer->cfg->is_de3) 172 + return DE3_CH_BASE + channel * DE3_CH_SIZE; 173 + else 174 + return DE2_CH_BASE + channel * DE2_CH_SIZE; 199 175 } 200 176 201 177 const struct de2_fmt_info *sun8i_mixer_format_info(u32 format);
+8 -2
drivers/gpu/drm/sun4i/sun8i_ui_scaler.c
··· 93 93 { 94 94 int vi_num = mixer->cfg->vi_num; 95 95 96 - return DE2_VI_SCALER_UNIT_BASE + DE2_VI_SCALER_UNIT_SIZE * vi_num + 97 - DE2_UI_SCALER_UNIT_SIZE * (channel - vi_num); 96 + if (mixer->cfg->is_de3) 97 + return DE3_VI_SCALER_UNIT_BASE + 98 + DE3_VI_SCALER_UNIT_SIZE * vi_num + 99 + DE3_UI_SCALER_UNIT_SIZE * (channel - vi_num); 100 + else 101 + return DE2_VI_SCALER_UNIT_BASE + 102 + DE2_VI_SCALER_UNIT_SIZE * vi_num + 103 + DE2_UI_SCALER_UNIT_SIZE * (channel - vi_num); 98 104 } 99 105 100 106 static int sun8i_ui_scaler_coef_index(unsigned int step)
+1
drivers/gpu/drm/sun4i/sun8i_ui_scaler.h
··· 12 12 #include "sun8i_mixer.h" 13 13 14 14 #define DE2_UI_SCALER_UNIT_SIZE 0x10000 15 + #define DE3_UI_SCALER_UNIT_SIZE 0x08000 15 16 16 17 /* this two macros assumes 16 fractional bits which is standard in DRM */ 17 18 #define SUN8I_UI_SCALER_SCALE_MIN 1
+8
drivers/gpu/drm/sun4i/sun8i_vi_layer.c
··· 202 202 SUN8I_MIXER_CHAN_VI_LAYER_ATTR(ch_base, overlay), 203 203 SUN8I_MIXER_CHAN_VI_LAYER_ATTR_RGB_MODE, val); 204 204 205 + /* It seems that YUV formats use global alpha setting. */ 206 + if (mixer->cfg->is_de3) 207 + regmap_update_bits(mixer->engine.regs, 208 + SUN8I_MIXER_CHAN_VI_LAYER_ATTR(ch_base, 209 + overlay), 210 + SUN50I_MIXER_CHAN_VI_LAYER_ATTR_ALPHA_MASK, 211 + SUN50I_MIXER_CHAN_VI_LAYER_ATTR_ALPHA(0xff)); 212 + 205 213 return 0; 206 214 } 207 215
+2
drivers/gpu/drm/sun4i/sun8i_vi_layer.h
··· 30 30 #define SUN8I_MIXER_CHAN_VI_LAYER_ATTR_RGB_MODE BIT(15) 31 31 #define SUN8I_MIXER_CHAN_VI_LAYER_ATTR_FBFMT_OFFSET 8 32 32 #define SUN8I_MIXER_CHAN_VI_LAYER_ATTR_FBFMT_MASK GENMASK(12, 8) 33 + #define SUN50I_MIXER_CHAN_VI_LAYER_ATTR_ALPHA_MASK GENMASK(31, 24) 34 + #define SUN50I_MIXER_CHAN_VI_LAYER_ATTR_ALPHA(x) ((x) << 24) 33 35 34 36 struct sun8i_mixer; 35 37
+18 -1
drivers/gpu/drm/sun4i/sun8i_vi_scaler.c
··· 835 835 836 836 static u32 sun8i_vi_scaler_base(struct sun8i_mixer *mixer, int channel) 837 837 { 838 - return DE2_VI_SCALER_UNIT_BASE + DE2_VI_SCALER_UNIT_SIZE * channel; 838 + if (mixer->cfg->is_de3) 839 + return DE3_VI_SCALER_UNIT_BASE + 840 + DE3_VI_SCALER_UNIT_SIZE * channel; 841 + else 842 + return DE2_VI_SCALER_UNIT_BASE + 843 + DE2_VI_SCALER_UNIT_SIZE * channel; 839 844 } 840 845 841 846 static int sun8i_vi_scaler_coef_index(unsigned int step) ··· 954 949 } else { 955 950 chphase = hphase; 956 951 cvphase = vphase; 952 + } 953 + 954 + if (mixer->cfg->is_de3) { 955 + u32 val; 956 + 957 + if (format->hsub == 1 && format->vsub == 1) 958 + val = SUN50I_SCALER_VSU_SCALE_MODE_UI; 959 + else 960 + val = SUN50I_SCALER_VSU_SCALE_MODE_NORMAL; 961 + 962 + regmap_write(mixer->engine.regs, 963 + SUN50I_SCALER_VSU_SCALE_MODE(base), val); 957 964 } 958 965 959 966 regmap_write(mixer->engine.regs,
+23
drivers/gpu/drm/sun4i/sun8i_vi_scaler.h
··· 15 15 #define DE2_VI_SCALER_UNIT_BASE 0x20000 16 16 #define DE2_VI_SCALER_UNIT_SIZE 0x20000 17 17 18 + #define DE3_VI_SCALER_UNIT_BASE 0x20000 19 + #define DE3_VI_SCALER_UNIT_SIZE 0x08000 20 + 18 21 /* this two macros assumes 16 fractional bits which is standard in DRM */ 19 22 #define SUN8I_VI_SCALER_SCALE_MIN 1 20 23 #define SUN8I_VI_SCALER_SCALE_MAX ((1UL << 20) - 1) ··· 28 25 #define SUN8I_VI_SCALER_SIZE(w, h) (((h) - 1) << 16 | ((w) - 1)) 29 26 30 27 #define SUN8I_SCALER_VSU_CTRL(base) ((base) + 0x0) 28 + #define SUN50I_SCALER_VSU_SCALE_MODE(base) ((base) + 0x10) 29 + #define SUN50I_SCALER_VSU_DIR_THR(base) ((base) + 0x20) 30 + #define SUN50I_SCALER_VSU_EDGE_THR(base) ((base) + 0x24) 31 + #define SUN50I_SCALER_VSU_EDSCL_CTRL(base) ((base) + 0x28) 32 + #define SUN50I_SCALER_VSU_ANGLE_THR(base) ((base) + 0x2c) 31 33 #define SUN8I_SCALER_VSU_OUTSIZE(base) ((base) + 0x40) 32 34 #define SUN8I_SCALER_VSU_YINSIZE(base) ((base) + 0x80) 33 35 #define SUN8I_SCALER_VSU_YHSTEP(base) ((base) + 0x88) ··· 53 45 54 46 #define SUN8I_SCALER_VSU_CTRL_EN BIT(0) 55 47 #define SUN8I_SCALER_VSU_CTRL_COEFF_RDY BIT(4) 48 + 49 + #define SUN50I_SCALER_VSU_SUB_ZERO_DIR_THR(x) (((x) << 24) & 0xFF) 50 + #define SUN50I_SCALER_VSU_ZERO_DIR_THR(x) (((x) << 16) & 0xFF) 51 + #define SUN50I_SCALER_VSU_HORZ_DIR_THR(x) (((x) << 8) & 0xFF) 52 + #define SUN50I_SCALER_VSU_VERT_DIR_THR(x) ((x) & 0xFF) 53 + 54 + #define SUN50I_SCALER_VSU_SCALE_MODE_UI 0 55 + #define SUN50I_SCALER_VSU_SCALE_MODE_NORMAL 1 56 + #define SUN50I_SCALER_VSU_SCALE_MODE_ED_SCALE 2 57 + 58 + #define SUN50I_SCALER_VSU_EDGE_SHIFT(x) (((x) << 16) & 0xF) 59 + #define SUN50I_SCALER_VSU_EDGE_OFFSET(x) ((x) & 0xFF) 60 + 61 + #define SUN50I_SCALER_VSU_ANGLE_SHIFT(x) (((x) << 16) & 0xF) 62 + #define SUN50I_SCALER_VSU_ANGLE_OFFSET(x) ((x) & 0xFF) 56 63 57 64 void sun8i_vi_scaler_enable(struct sun8i_mixer *mixer, int layer, bool enable); 58 65 void sun8i_vi_scaler_setup(struct sun8i_mixer *mixer, int layer,