mirror of
https://github.com/raspberrypi/linux.git
synced 2025-12-06 01:49:46 +00:00
drm/vc4: crtc: Support odd horizontal timings on BCM2712
BCM2711 runs pixelvalve at two pixels per clock cycle which results in an unfortunate limitation that odd horizontal timings are not possible. This is apparent on the standard DMT mode of 1366x768@60 which cannot be driven with correct timing. BCM2712 defaults to the same behaviour, but has a mode to support odd timings. While internally it still runs at two pixels per clock, setting the PV_VCONTROL_ODD_TIMING bit makes it appear externally to behave as it is one pixel per clock. Switching to this mode fixes 1366x768@60 mode, and other custom resultions with odd horizontal timings. Signed-off-by: Dom Cobley <popcornmix@gmail.com> drm/vc4: Disable the 2pixel/clock odd timings workaround for interlaced Whilst BCM2712 does fix using odd horizontal timings, it doesn't work with interlaced modes. Drop the workaround for interlaced modes and revert to the same behaviour as BCM2711. https://github.com/raspberrypi/linux/issues/6281 Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
This commit is contained in:
@@ -378,7 +378,9 @@ static void vc4_crtc_config_pv(struct drm_crtc *crtc, struct drm_encoder *encode
|
||||
bool is_dsi1 = vc4_encoder->type == VC4_ENCODER_TYPE_DSI1;
|
||||
bool is_vec = vc4_encoder->type == VC4_ENCODER_TYPE_VEC;
|
||||
u32 format = is_dsi1 ? PV_CONTROL_FORMAT_DSIV_24 : PV_CONTROL_FORMAT_24;
|
||||
u8 ppc = pv_data->pixels_per_clock;
|
||||
u8 ppc = (mode->flags & DRM_MODE_FLAG_INTERLACE) ?
|
||||
pv_data->pixels_per_clock_int :
|
||||
pv_data->pixels_per_clock;
|
||||
|
||||
u16 vert_bp = mode->crtc_vtotal - mode->crtc_vsync_end;
|
||||
u16 vert_sync = mode->crtc_vsync_end - mode->crtc_vsync_start;
|
||||
@@ -399,12 +401,6 @@ static void vc4_crtc_config_pv(struct drm_crtc *crtc, struct drm_encoder *encode
|
||||
|
||||
vc4_crtc_pixelvalve_reset(crtc);
|
||||
|
||||
/*
|
||||
* NOTE: The BCM2712 has a H_OTE (Horizontal Odd Timing Enable)
|
||||
* bit that, when set, will allow to specify the timings in
|
||||
* pixels instead of cycles, thus allowing to specify odd
|
||||
* timings.
|
||||
*/
|
||||
CRTC_WRITE(PV_HORZA,
|
||||
VC4_SET_FIELD((mode->htotal - mode->hsync_end) * pixel_rep / ppc,
|
||||
PV_HORZA_HBP) |
|
||||
@@ -449,6 +445,8 @@ static void vc4_crtc_config_pv(struct drm_crtc *crtc, struct drm_encoder *encode
|
||||
*/
|
||||
CRTC_WRITE(PV_V_CONTROL,
|
||||
PV_VCONTROL_CONTINUOUS |
|
||||
(vc4->gen >= VC4_GEN_6 && ppc == 1 ?
|
||||
PV_VCONTROL_ODD_TIMING : 0) |
|
||||
(is_dsi ? PV_VCONTROL_DSI : 0) |
|
||||
PV_VCONTROL_INTERLACE |
|
||||
(odd_field_first
|
||||
@@ -460,6 +458,8 @@ static void vc4_crtc_config_pv(struct drm_crtc *crtc, struct drm_encoder *encode
|
||||
} else {
|
||||
CRTC_WRITE(PV_V_CONTROL,
|
||||
PV_VCONTROL_CONTINUOUS |
|
||||
(vc4->gen >= VC4_GEN_6 && ppc == 1 ?
|
||||
PV_VCONTROL_ODD_TIMING : 0) |
|
||||
(is_dsi ? PV_VCONTROL_DSI : 0));
|
||||
CRTC_WRITE(PV_VSYNCD_EVEN, 0);
|
||||
}
|
||||
@@ -1217,6 +1217,7 @@ const struct vc4_pv_data bcm2835_pv0_data = {
|
||||
},
|
||||
.fifo_depth = 64,
|
||||
.pixels_per_clock = 1,
|
||||
.pixels_per_clock_int = 1,
|
||||
.encoder_types = {
|
||||
[PV_CONTROL_CLK_SELECT_DSI] = VC4_ENCODER_TYPE_DSI0,
|
||||
[PV_CONTROL_CLK_SELECT_DPI_SMI_HDMI] = VC4_ENCODER_TYPE_DPI,
|
||||
@@ -1232,6 +1233,7 @@ const struct vc4_pv_data bcm2835_pv1_data = {
|
||||
},
|
||||
.fifo_depth = 64,
|
||||
.pixels_per_clock = 1,
|
||||
.pixels_per_clock_int = 1,
|
||||
.encoder_types = {
|
||||
[PV_CONTROL_CLK_SELECT_DSI] = VC4_ENCODER_TYPE_DSI1,
|
||||
[PV_CONTROL_CLK_SELECT_DPI_SMI_HDMI] = VC4_ENCODER_TYPE_SMI,
|
||||
@@ -1247,6 +1249,7 @@ const struct vc4_pv_data bcm2835_pv2_data = {
|
||||
},
|
||||
.fifo_depth = 64,
|
||||
.pixels_per_clock = 1,
|
||||
.pixels_per_clock_int = 1,
|
||||
.encoder_types = {
|
||||
[PV_CONTROL_CLK_SELECT_DPI_SMI_HDMI] = VC4_ENCODER_TYPE_HDMI0,
|
||||
[PV_CONTROL_CLK_SELECT_VEC] = VC4_ENCODER_TYPE_VEC,
|
||||
@@ -1262,6 +1265,7 @@ const struct vc4_pv_data bcm2711_pv0_data = {
|
||||
},
|
||||
.fifo_depth = 64,
|
||||
.pixels_per_clock = 1,
|
||||
.pixels_per_clock_int = 1,
|
||||
.encoder_types = {
|
||||
[0] = VC4_ENCODER_TYPE_DSI0,
|
||||
[1] = VC4_ENCODER_TYPE_DPI,
|
||||
@@ -1277,6 +1281,7 @@ const struct vc4_pv_data bcm2711_pv1_data = {
|
||||
},
|
||||
.fifo_depth = 64,
|
||||
.pixels_per_clock = 1,
|
||||
.pixels_per_clock_int = 1,
|
||||
.encoder_types = {
|
||||
[0] = VC4_ENCODER_TYPE_DSI1,
|
||||
[1] = VC4_ENCODER_TYPE_SMI,
|
||||
@@ -1292,6 +1297,7 @@ const struct vc4_pv_data bcm2711_pv2_data = {
|
||||
},
|
||||
.fifo_depth = 256,
|
||||
.pixels_per_clock = 2,
|
||||
.pixels_per_clock_int = 2,
|
||||
.encoder_types = {
|
||||
[0] = VC4_ENCODER_TYPE_HDMI0,
|
||||
},
|
||||
@@ -1306,6 +1312,7 @@ const struct vc4_pv_data bcm2711_pv3_data = {
|
||||
},
|
||||
.fifo_depth = 64,
|
||||
.pixels_per_clock = 1,
|
||||
.pixels_per_clock_int = 1,
|
||||
.encoder_types = {
|
||||
[PV_CONTROL_CLK_SELECT_VEC] = VC4_ENCODER_TYPE_VEC,
|
||||
},
|
||||
@@ -1320,6 +1327,7 @@ const struct vc4_pv_data bcm2711_pv4_data = {
|
||||
},
|
||||
.fifo_depth = 64,
|
||||
.pixels_per_clock = 2,
|
||||
.pixels_per_clock_int = 2,
|
||||
.encoder_types = {
|
||||
[0] = VC4_ENCODER_TYPE_HDMI1,
|
||||
},
|
||||
@@ -1332,7 +1340,8 @@ const struct vc4_pv_data bcm2712_pv0_data = {
|
||||
.hvs_output = 0,
|
||||
},
|
||||
.fifo_depth = 64,
|
||||
.pixels_per_clock = 2,
|
||||
.pixels_per_clock = 1,
|
||||
.pixels_per_clock_int = 2,
|
||||
.encoder_types = {
|
||||
[0] = VC4_ENCODER_TYPE_HDMI0,
|
||||
},
|
||||
@@ -1345,7 +1354,8 @@ const struct vc4_pv_data bcm2712_pv1_data = {
|
||||
.hvs_output = 1,
|
||||
},
|
||||
.fifo_depth = 64,
|
||||
.pixels_per_clock = 2,
|
||||
.pixels_per_clock = 1,
|
||||
.pixels_per_clock_int = 2,
|
||||
.encoder_types = {
|
||||
[0] = VC4_ENCODER_TYPE_HDMI1,
|
||||
},
|
||||
|
||||
@@ -568,6 +568,8 @@ struct vc4_pv_data {
|
||||
|
||||
/* Number of pixels output per clock period */
|
||||
u8 pixels_per_clock;
|
||||
/* Number of pixels output per clock period when in an interlaced mode */
|
||||
u8 pixels_per_clock_int;
|
||||
|
||||
enum vc4_encoder_type encoder_types[4];
|
||||
};
|
||||
|
||||
@@ -1730,7 +1730,9 @@ static int vc4_hdmi_encoder_atomic_check(struct drm_encoder *encoder,
|
||||
unsigned long long tmds_char_rate = mode->clock * 1000;
|
||||
unsigned long long tmds_bit_rate;
|
||||
|
||||
if (vc4_hdmi->variant->unsupported_odd_h_timings) {
|
||||
if (vc4_hdmi->variant->unsupported_odd_h_timings ||
|
||||
(vc4_hdmi->variant->unsupported_int_odd_h_timings &&
|
||||
(mode->flags & DRM_MODE_FLAG_INTERLACE))) {
|
||||
if (mode->flags & DRM_MODE_FLAG_DBLCLK) {
|
||||
/* Only try to fixup DBLCLK modes to get 480i and 576i
|
||||
* working.
|
||||
@@ -3386,6 +3388,7 @@ static const struct vc4_hdmi_variant bcm2711_hdmi0_variant = {
|
||||
PHY_LANE_CK,
|
||||
},
|
||||
.unsupported_odd_h_timings = true,
|
||||
.unsupported_int_odd_h_timings = true,
|
||||
.external_irq_controller = true,
|
||||
|
||||
.init_resources = vc5_hdmi_init_resources,
|
||||
@@ -3415,6 +3418,7 @@ static const struct vc4_hdmi_variant bcm2711_hdmi1_variant = {
|
||||
PHY_LANE_2,
|
||||
},
|
||||
.unsupported_odd_h_timings = true,
|
||||
.unsupported_int_odd_h_timings = true,
|
||||
.external_irq_controller = true,
|
||||
|
||||
.init_resources = vc5_hdmi_init_resources,
|
||||
@@ -3443,7 +3447,8 @@ static const struct vc4_hdmi_variant bcm2712_hdmi0_variant = {
|
||||
PHY_LANE_2,
|
||||
PHY_LANE_CK,
|
||||
},
|
||||
.unsupported_odd_h_timings = true,
|
||||
.unsupported_odd_h_timings = false,
|
||||
.unsupported_int_odd_h_timings = true,
|
||||
.external_irq_controller = true,
|
||||
|
||||
.init_resources = vc5_hdmi_init_resources,
|
||||
@@ -3470,7 +3475,8 @@ static const struct vc4_hdmi_variant bcm2712_hdmi1_variant = {
|
||||
PHY_LANE_2,
|
||||
PHY_LANE_CK,
|
||||
},
|
||||
.unsupported_odd_h_timings = true,
|
||||
.unsupported_odd_h_timings = false,
|
||||
.unsupported_int_odd_h_timings = true,
|
||||
.external_irq_controller = true,
|
||||
|
||||
.init_resources = vc5_hdmi_init_resources,
|
||||
|
||||
@@ -46,6 +46,10 @@ struct vc4_hdmi_variant {
|
||||
|
||||
/* The BCM2711 cannot deal with odd horizontal pixel timings */
|
||||
bool unsupported_odd_h_timings;
|
||||
/* The BCM2712 can handle odd horizontal pixel timings, but not in
|
||||
* interlaced modes
|
||||
*/
|
||||
bool unsupported_int_odd_h_timings;
|
||||
|
||||
/*
|
||||
* The BCM2711 CEC/hotplug IRQ controller is shared between the
|
||||
|
||||
@@ -155,6 +155,7 @@
|
||||
# define PV_CONTROL_EN BIT(0)
|
||||
|
||||
#define PV_V_CONTROL 0x04
|
||||
# define PV_VCONTROL_ODD_TIMING BIT(29)
|
||||
# define PV_VCONTROL_ODD_DELAY_MASK VC4_MASK(22, 6)
|
||||
# define PV_VCONTROL_ODD_DELAY_SHIFT 6
|
||||
# define PV_VCONTROL_ODD_FIRST BIT(5)
|
||||
|
||||
Reference in New Issue
Block a user