diff options
Diffstat (limited to 'drivers/gpu/drm/sun4i')
-rw-r--r-- | drivers/gpu/drm/sun4i/sun4i_tcon.c | 46 | ||||
-rw-r--r-- | drivers/gpu/drm/sun4i/sun4i_tcon.h | 7 | ||||
-rw-r--r-- | drivers/gpu/drm/sun4i/sun8i_csc.c | 109 | ||||
-rw-r--r-- | drivers/gpu/drm/sun4i/sun8i_dw_hdmi.c | 10 | ||||
-rw-r--r-- | drivers/gpu/drm/sun4i/sun8i_dw_hdmi.h | 1 | ||||
-rw-r--r-- | drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c | 26 | ||||
-rw-r--r-- | drivers/gpu/drm/sun4i/sun8i_mixer.h | 6 | ||||
-rw-r--r-- | drivers/gpu/drm/sun4i/sun8i_vi_layer.c | 2 |
8 files changed, 94 insertions, 113 deletions
diff --git a/drivers/gpu/drm/sun4i/sun4i_tcon.c b/drivers/gpu/drm/sun4i/sun4i_tcon.c index eaaf5d70e352..9f06dec0fc61 100644 --- a/drivers/gpu/drm/sun4i/sun4i_tcon.c +++ b/drivers/gpu/drm/sun4i/sun4i_tcon.c @@ -569,30 +569,13 @@ static void sun4i_tcon0_mode_set_rgb(struct sun4i_tcon *tcon, if (info->bus_flags & DRM_BUS_FLAG_DE_LOW) val |= SUN4I_TCON0_IO_POL_DE_NEGATIVE; - /* - * On A20 and similar SoCs, the only way to achieve Positive Edge - * (Rising Edge), is setting dclk clock phase to 2/3(240°). - * By default TCON works in Negative Edge(Falling Edge), - * this is why phase is set to 0 in that case. - * Unfortunately there's no way to logically invert dclk through - * IO_POL register. - * The only acceptable way to work, triple checked with scope, - * is using clock phase set to 0° for Negative Edge and set to 240° - * for Positive Edge. - * On A33 and similar SoCs there would be a 90° phase option, - * but it divides also dclk by 2. - * Following code is a way to avoid quirks all around TCON - * and DOTCLOCK drivers. - */ - if (info->bus_flags & DRM_BUS_FLAG_PIXDATA_DRIVE_POSEDGE) - clk_set_phase(tcon->dclk, 240); - if (info->bus_flags & DRM_BUS_FLAG_PIXDATA_DRIVE_NEGEDGE) - clk_set_phase(tcon->dclk, 0); + val |= SUN4I_TCON0_IO_POL_DCLK_DRIVE_NEGEDGE; regmap_update_bits(tcon->regs, SUN4I_TCON0_IO_POL_REG, SUN4I_TCON0_IO_POL_HSYNC_POSITIVE | SUN4I_TCON0_IO_POL_VSYNC_POSITIVE | + SUN4I_TCON0_IO_POL_DCLK_DRIVE_NEGEDGE | SUN4I_TCON0_IO_POL_DE_NEGATIVE, val); @@ -689,6 +672,30 @@ static void sun4i_tcon1_mode_set(struct sun4i_tcon *tcon, SUN4I_TCON1_BASIC5_V_SYNC(vsync) | SUN4I_TCON1_BASIC5_H_SYNC(hsync)); + /* Setup the polarity of multiple signals */ + if (tcon->quirks->polarity_in_ch0) { + val = 0; + + if (mode->flags & DRM_MODE_FLAG_PHSYNC) + val |= SUN4I_TCON0_IO_POL_HSYNC_POSITIVE; + + if (mode->flags & DRM_MODE_FLAG_PVSYNC) + val |= SUN4I_TCON0_IO_POL_VSYNC_POSITIVE; + + regmap_write(tcon->regs, SUN4I_TCON0_IO_POL_REG, val); + } else { + /* according to vendor driver, this bit must be always set */ + val = SUN4I_TCON1_IO_POL_UNKNOWN; + + if (mode->flags & DRM_MODE_FLAG_PHSYNC) + val |= SUN4I_TCON1_IO_POL_HSYNC_POSITIVE; + + if (mode->flags & DRM_MODE_FLAG_PVSYNC) + val |= SUN4I_TCON1_IO_POL_VSYNC_POSITIVE; + + regmap_write(tcon->regs, SUN4I_TCON1_IO_POL_REG, val); + } + /* Map output pins to channel 1 */ regmap_update_bits(tcon->regs, SUN4I_TCON_GCTL_REG, SUN4I_TCON_GCTL_IOMAP_MASK, @@ -1517,6 +1524,7 @@ static const struct sun4i_tcon_quirks sun8i_a83t_tv_quirks = { static const struct sun4i_tcon_quirks sun8i_r40_tv_quirks = { .has_channel_1 = true, + .polarity_in_ch0 = true, .set_mux = sun8i_r40_tcon_tv_set_mux, }; diff --git a/drivers/gpu/drm/sun4i/sun4i_tcon.h b/drivers/gpu/drm/sun4i/sun4i_tcon.h index cfbf4e6c1679..e624f6977eb8 100644 --- a/drivers/gpu/drm/sun4i/sun4i_tcon.h +++ b/drivers/gpu/drm/sun4i/sun4i_tcon.h @@ -113,6 +113,7 @@ #define SUN4I_TCON0_IO_POL_REG 0x88 #define SUN4I_TCON0_IO_POL_DCLK_PHASE(phase) ((phase & 3) << 28) #define SUN4I_TCON0_IO_POL_DE_NEGATIVE BIT(27) +#define SUN4I_TCON0_IO_POL_DCLK_DRIVE_NEGEDGE BIT(26) #define SUN4I_TCON0_IO_POL_HSYNC_POSITIVE BIT(25) #define SUN4I_TCON0_IO_POL_VSYNC_POSITIVE BIT(24) @@ -153,6 +154,11 @@ #define SUN4I_TCON1_BASIC5_V_SYNC(height) (((height) - 1) & 0x3ff) #define SUN4I_TCON1_IO_POL_REG 0xf0 +/* there is no documentation about this bit */ +#define SUN4I_TCON1_IO_POL_UNKNOWN BIT(26) +#define SUN4I_TCON1_IO_POL_HSYNC_POSITIVE BIT(25) +#define SUN4I_TCON1_IO_POL_VSYNC_POSITIVE BIT(24) + #define SUN4I_TCON1_IO_TRI_REG 0xf4 #define SUN4I_TCON_ECC_FIFO_REG 0xf8 @@ -235,6 +241,7 @@ struct sun4i_tcon_quirks { bool needs_de_be_mux; /* sun6i needs mux to select backend */ bool needs_edp_reset; /* a80 edp reset needed for tcon0 access */ bool supports_lvds; /* Does the TCON support an LVDS output? */ + bool polarity_in_ch0; /* some tcon1 channels have polarity bits in tcon0 pol register */ u8 dclk_min_div; /* minimum divider for TCON0 DCLK */ /* callback to handle tcon muxing options */ diff --git a/drivers/gpu/drm/sun4i/sun8i_csc.c b/drivers/gpu/drm/sun4i/sun8i_csc.c index 781955dd4995..9bd62de0c288 100644 --- a/drivers/gpu/drm/sun4i/sun8i_csc.c +++ b/drivers/gpu/drm/sun4i/sun8i_csc.c @@ -46,33 +46,6 @@ static const u32 yuv2rgb[2][2][12] = { }, }; -static const u32 yvu2rgb[2][2][12] = { - [DRM_COLOR_YCBCR_LIMITED_RANGE] = { - [DRM_COLOR_YCBCR_BT601] = { - 0x000004A8, 0x00000662, 0x00000000, 0xFFFC8451, - 0x000004A8, 0xFFFFFCC0, 0xFFFFFE6F, 0x00021E4D, - 0x000004A8, 0x00000000, 0x00000811, 0xFFFBACA9, - }, - [DRM_COLOR_YCBCR_BT709] = { - 0x000004A8, 0x0000072B, 0x00000000, 0xFFFC1F99, - 0x000004A8, 0xFFFFFDDF, 0xFFFFFF26, 0x00013383, - 0x000004A8, 0x00000000, 0x00000873, 0xFFFB7BEF, - } - }, - [DRM_COLOR_YCBCR_FULL_RANGE] = { - [DRM_COLOR_YCBCR_BT601] = { - 0x00000400, 0x0000059B, 0x00000000, 0xFFFD322E, - 0x00000400, 0xFFFFFD25, 0xFFFFFEA0, 0x00021DD5, - 0x00000400, 0x00000000, 0x00000716, 0xFFFC74BD, - }, - [DRM_COLOR_YCBCR_BT709] = { - 0x00000400, 0x0000064C, 0x00000000, 0xFFFCD9B4, - 0x00000400, 0xFFFFFE21, 0xFFFFFF41, 0x00014F96, - 0x00000400, 0x00000000, 0x0000076C, 0xFFFC49EF, - } - }, -}; - /* * DE3 has a bit different CSC units. Factors are in two's complement format. * First three factors in a row are multiplication factors which have 17 bits @@ -96,7 +69,7 @@ static const u32 yvu2rgb[2][2][12] = { * c20 c21 c22 [d2 const2] */ -static const u32 yuv2rgb_de3[2][2][12] = { +static const u32 yuv2rgb_de3[2][3][12] = { [DRM_COLOR_YCBCR_LIMITED_RANGE] = { [DRM_COLOR_YCBCR_BT601] = { 0x0002542A, 0x00000000, 0x0003312A, 0xFFC00000, @@ -107,6 +80,11 @@ static const u32 yuv2rgb_de3[2][2][12] = { 0x0002542A, 0x00000000, 0x000395E2, 0xFFC00000, 0x0002542A, 0xFFFF92D2, 0xFFFEEF27, 0xFE000000, 0x0002542A, 0x0004398C, 0x00000000, 0xFE000000, + }, + [DRM_COLOR_YCBCR_BT2020] = { + 0x0002542A, 0x00000000, 0x00035B7B, 0xFFC00000, + 0x0002542A, 0xFFFFA017, 0xFFFEB2FC, 0xFE000000, + 0x0002542A, 0x00044896, 0x00000000, 0xFE000000, } }, [DRM_COLOR_YCBCR_FULL_RANGE] = { @@ -119,33 +97,11 @@ static const u32 yuv2rgb_de3[2][2][12] = { 0x00020000, 0x00000000, 0x0003264C, 0x00000000, 0x00020000, 0xFFFFA018, 0xFFFF1053, 0xFE000000, 0x00020000, 0x0003B611, 0x00000000, 0xFE000000, - } - }, -}; - -static const u32 yvu2rgb_de3[2][2][12] = { - [DRM_COLOR_YCBCR_LIMITED_RANGE] = { - [DRM_COLOR_YCBCR_BT601] = { - 0x0002542A, 0x0003312A, 0x00000000, 0xFFC00000, - 0x0002542A, 0xFFFE5FC3, 0xFFFF376B, 0xFE000000, - 0x0002542A, 0x00000000, 0x000408D2, 0xFE000000, }, - [DRM_COLOR_YCBCR_BT709] = { - 0x0002542A, 0x000395E2, 0x00000000, 0xFFC00000, - 0x0002542A, 0xFFFEEF27, 0xFFFF92D2, 0xFE000000, - 0x0002542A, 0x00000000, 0x0004398C, 0xFE000000, - } - }, - [DRM_COLOR_YCBCR_FULL_RANGE] = { - [DRM_COLOR_YCBCR_BT601] = { - 0x00020000, 0x0002CDD2, 0x00000000, 0x00000000, - 0x00020000, 0xFFFE925D, 0xFFFF4FCE, 0xFE000000, - 0x00020000, 0x00000000, 0x00038B43, 0xFE000000, - }, - [DRM_COLOR_YCBCR_BT709] = { - 0x00020000, 0x0003264C, 0x00000000, 0x00000000, - 0x00020000, 0xFFFF1053, 0xFFFFA018, 0xFE000000, - 0x00020000, 0x00000000, 0x0003B611, 0xFE000000, + [DRM_COLOR_YCBCR_BT2020] = { + 0x00020000, 0x00000000, 0x0002F2FE, 0x00000000, + 0x00020000, 0xFFFFABC0, 0xFFFEDB78, 0xFE000000, + 0x00020000, 0x0003C346, 0x00000000, 0xFE000000, } }, }; @@ -157,21 +113,30 @@ static void sun8i_csc_set_coefficients(struct regmap *map, u32 base, { const u32 *table; u32 base_reg; + int i; + + table = yuv2rgb[range][encoding]; switch (mode) { case SUN8I_CSC_MODE_YUV2RGB: - table = yuv2rgb[range][encoding]; + base_reg = SUN8I_CSC_COEFF(base, 0); + regmap_bulk_write(map, base_reg, table, 12); break; case SUN8I_CSC_MODE_YVU2RGB: - table = yvu2rgb[range][encoding]; + for (i = 0; i < 12; i++) { + if ((i & 3) == 1) + base_reg = SUN8I_CSC_COEFF(base, i + 1); + else if ((i & 3) == 2) + base_reg = SUN8I_CSC_COEFF(base, i - 1); + else + base_reg = SUN8I_CSC_COEFF(base, i); + regmap_write(map, base_reg, table[i]); + } break; default: DRM_WARN("Wrong CSC mode specified.\n"); return; } - - base_reg = SUN8I_CSC_COEFF(base, 0); - regmap_bulk_write(map, base_reg, table, 12); } static void sun8i_de3_ccsc_set_coefficients(struct regmap *map, int layer, @@ -180,22 +145,36 @@ static void sun8i_de3_ccsc_set_coefficients(struct regmap *map, int layer, enum drm_color_range range) { const u32 *table; - u32 base_reg; + u32 addr; + int i; + + table = yuv2rgb_de3[range][encoding]; switch (mode) { case SUN8I_CSC_MODE_YUV2RGB: - table = yuv2rgb_de3[range][encoding]; + addr = SUN50I_MIXER_BLEND_CSC_COEFF(DE3_BLD_BASE, layer, 0); + regmap_bulk_write(map, addr, table, 12); break; case SUN8I_CSC_MODE_YVU2RGB: - table = yvu2rgb_de3[range][encoding]; + for (i = 0; i < 12; i++) { + if ((i & 3) == 1) + addr = SUN50I_MIXER_BLEND_CSC_COEFF(DE3_BLD_BASE, + layer, + i + 1); + else if ((i & 3) == 2) + addr = SUN50I_MIXER_BLEND_CSC_COEFF(DE3_BLD_BASE, + layer, + i - 1); + else + addr = SUN50I_MIXER_BLEND_CSC_COEFF(DE3_BLD_BASE, + layer, i); + regmap_write(map, addr, table[i]); + } break; default: DRM_WARN("Wrong CSC mode specified.\n"); return; } - - base_reg = SUN50I_MIXER_BLEND_CSC_COEFF(DE3_BLD_BASE, layer, 0, 0); - regmap_bulk_write(map, base_reg, table, 12); } static void sun8i_csc_enable(struct regmap *map, u32 base, bool enable) diff --git a/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.c b/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.c index 92add2cef2e7..bbdfd5e26ec8 100644 --- a/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.c +++ b/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.c @@ -21,8 +21,7 @@ static void sun8i_dw_hdmi_encoder_mode_set(struct drm_encoder *encoder, { struct sun8i_dw_hdmi *hdmi = encoder_to_sun8i_dw_hdmi(encoder); - if (hdmi->quirks->set_rate) - clk_set_rate(hdmi->clk_tmds, mode->crtc_clock * 1000); + clk_set_rate(hdmi->clk_tmds, mode->crtc_clock * 1000); } static const struct drm_encoder_helper_funcs @@ -48,11 +47,9 @@ sun8i_dw_hdmi_mode_valid_h6(struct dw_hdmi *hdmi, void *data, { /* * Controller support maximum of 594 MHz, which correlates to - * 4K@60Hz 4:4:4 or RGB. However, for frequencies greater than - * 340 MHz scrambling has to be enabled. Because scrambling is - * not yet implemented, just limit to 340 MHz for now. + * 4K@60Hz 4:4:4 or RGB. */ - if (mode->clock > 340000) + if (mode->clock > 594000) return MODE_CLOCK_HIGH; return MODE_OK; @@ -295,7 +292,6 @@ static int sun8i_dw_hdmi_remove(struct platform_device *pdev) static const struct sun8i_dw_hdmi_quirks sun8i_a83t_quirks = { .mode_valid = sun8i_dw_hdmi_mode_valid_a83t, - .set_rate = true, }; static const struct sun8i_dw_hdmi_quirks sun50i_h6_quirks = { diff --git a/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.h b/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.h index d983746fa194..d4b55af0592f 100644 --- a/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.h +++ b/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.h @@ -179,7 +179,6 @@ struct sun8i_dw_hdmi_quirks { enum drm_mode_status (*mode_valid)(struct dw_hdmi *hdmi, void *data, const struct drm_display_info *info, const struct drm_display_mode *mode); - unsigned int set_rate : 1; unsigned int use_drm_infoframe : 1; }; diff --git a/drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c b/drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c index 35c2133724e2..9994edf67509 100644 --- a/drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c +++ b/drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c @@ -104,29 +104,21 @@ static const struct dw_hdmi_mpll_config sun50i_h6_mpll_cfg[] = { static const struct dw_hdmi_curr_ctrl sun50i_h6_cur_ctr[] = { /* pixelclk bpp8 bpp10 bpp12 */ - { 25175000, { 0x0000, 0x0000, 0x0000 }, }, { 27000000, { 0x0012, 0x0000, 0x0000 }, }, - { 59400000, { 0x0008, 0x0008, 0x0008 }, }, - { 72000000, { 0x0008, 0x0008, 0x001b }, }, - { 74250000, { 0x0013, 0x0013, 0x0013 }, }, - { 90000000, { 0x0008, 0x001a, 0x001b }, }, - { 118800000, { 0x001b, 0x001a, 0x001b }, }, - { 144000000, { 0x001b, 0x001a, 0x0034 }, }, - { 180000000, { 0x001b, 0x0033, 0x0034 }, }, - { 216000000, { 0x0036, 0x0033, 0x0034 }, }, - { 237600000, { 0x0036, 0x0033, 0x001b }, }, - { 288000000, { 0x0036, 0x001b, 0x001b }, }, - { 297000000, { 0x0019, 0x001b, 0x0019 }, }, - { 330000000, { 0x0036, 0x001b, 0x001b }, }, - { 594000000, { 0x003f, 0x001b, 0x001b }, }, + { 74250000, { 0x0013, 0x001a, 0x001b }, }, + { 148500000, { 0x0019, 0x0033, 0x0034 }, }, + { 297000000, { 0x0019, 0x001b, 0x001b }, }, + { 594000000, { 0x0010, 0x001b, 0x001b }, }, { ~0UL, { 0x0000, 0x0000, 0x0000 }, } }; static const struct dw_hdmi_phy_config sun50i_h6_phy_config[] = { /*pixelclk symbol term vlev*/ - { 74250000, 0x8009, 0x0004, 0x0232}, - { 148500000, 0x8029, 0x0004, 0x0273}, - { 594000000, 0x8039, 0x0004, 0x014a}, + { 27000000, 0x8009, 0x0007, 0x02b0 }, + { 74250000, 0x8009, 0x0006, 0x022d }, + { 148500000, 0x8029, 0x0006, 0x0270 }, + { 297000000, 0x8039, 0x0005, 0x01ab }, + { 594000000, 0x8029, 0x0000, 0x008a }, { ~0UL, 0x0000, 0x0000, 0x0000} }; diff --git a/drivers/gpu/drm/sun4i/sun8i_mixer.h b/drivers/gpu/drm/sun4i/sun8i_mixer.h index 7576b523fdbb..145833a9d82d 100644 --- a/drivers/gpu/drm/sun4i/sun8i_mixer.h +++ b/drivers/gpu/drm/sun4i/sun8i_mixer.h @@ -50,10 +50,8 @@ #define SUN8I_MIXER_BLEND_CK_MIN(base, x) ((base) + 0xe0 + 0x04 * (x)) #define SUN8I_MIXER_BLEND_OUTCTL(base) ((base) + 0xfc) #define SUN50I_MIXER_BLEND_CSC_CTL(base) ((base) + 0x100) -#define SUN50I_MIXER_BLEND_CSC_COEFF(base, layer, x, y) \ - ((base) + 0x110 + (layer) * 0x30 + (x) * 0x10 + 4 * (y)) -#define SUN50I_MIXER_BLEND_CSC_CONST(base, layer, i) \ - ((base) + 0x110 + (layer) * 0x30 + (i) * 0x10 + 0x0c) +#define SUN50I_MIXER_BLEND_CSC_COEFF(base, layer, x) \ + ((base) + 0x110 + (layer) * 0x30 + (x) * 4) #define SUN8I_MIXER_BLEND_PIPE_CTL_EN_MSK GENMASK(12, 8) #define SUN8I_MIXER_BLEND_PIPE_CTL_EN(pipe) BIT(8 + pipe) diff --git a/drivers/gpu/drm/sun4i/sun8i_vi_layer.c b/drivers/gpu/drm/sun4i/sun8i_vi_layer.c index 76393fc976fe..8cc294a9969d 100644 --- a/drivers/gpu/drm/sun4i/sun8i_vi_layer.c +++ b/drivers/gpu/drm/sun4i/sun8i_vi_layer.c @@ -543,6 +543,8 @@ struct sun8i_vi_layer *sun8i_vi_layer_init_one(struct drm_device *drm, supported_encodings = BIT(DRM_COLOR_YCBCR_BT601) | BIT(DRM_COLOR_YCBCR_BT709); + if (mixer->cfg->is_de3) + supported_encodings |= BIT(DRM_COLOR_YCBCR_BT2020); supported_ranges = BIT(DRM_COLOR_YCBCR_LIMITED_RANGE) | BIT(DRM_COLOR_YCBCR_FULL_RANGE); |