Commit b51cd7ad authored by Maxime Ripard's avatar Maxime Ripard

drm/vc4: hvs: Fix frame count register readout

In order to get the field currently being output, the driver has been
using the display FIFO frame count in the HVS, reading a 6-bit field at
the offset 12 in the DISPSTATx register.

While that field is indeed at that location for the FIFO 1 and 2, the
one for the FIFO0 is actually in the DISPSTAT1 register, at the offset
18.

Fixes: e538092c ("drm/vc4: Enable precise vblank timestamping for interlaced modes.")
Signed-off-by: default avatarMaxime Ripard <maxime@cerno.tech>
Acked-by: default avatarThomas Zimmermann <tzimmermann@suse.de>
Link: https://lore.kernel.org/r/20220331143744.777652-3-maxime@cerno.tech
parent 748acfc9
......@@ -123,7 +123,7 @@ static bool vc4_crtc_get_scanout_position(struct drm_crtc *crtc,
*vpos /= 2;
/* Use hpos to correct for field offset in interlaced mode. */
if (VC4_GET_FIELD(val, SCALER_DISPSTATX_FRAME_COUNT) % 2)
if (vc4_hvs_get_fifo_frame_count(dev, vc4_crtc_state->assigned_channel) % 2)
*hpos += mode->crtc_htotal / 2;
}
......
......@@ -935,6 +935,7 @@ void vc4_irq_reset(struct drm_device *dev);
extern struct platform_driver vc4_hvs_driver;
void vc4_hvs_stop_channel(struct drm_device *dev, unsigned int output);
int vc4_hvs_get_fifo_from_output(struct drm_device *dev, unsigned int output);
u8 vc4_hvs_get_fifo_frame_count(struct drm_device *dev, unsigned int fifo);
int vc4_hvs_atomic_check(struct drm_crtc *crtc, struct drm_atomic_state *state);
void vc4_hvs_atomic_begin(struct drm_crtc *crtc, struct drm_atomic_state *state);
void vc4_hvs_atomic_enable(struct drm_crtc *crtc, struct drm_atomic_state *state);
......
......@@ -197,6 +197,29 @@ static void vc4_hvs_update_gamma_lut(struct drm_crtc *crtc)
vc4_hvs_lut_load(crtc);
}
u8 vc4_hvs_get_fifo_frame_count(struct drm_device *dev, unsigned int fifo)
{
struct vc4_dev *vc4 = to_vc4_dev(dev);
u8 field = 0;
switch (fifo) {
case 0:
field = VC4_GET_FIELD(HVS_READ(SCALER_DISPSTAT1),
SCALER_DISPSTAT1_FRCNT0);
break;
case 1:
field = VC4_GET_FIELD(HVS_READ(SCALER_DISPSTAT1),
SCALER_DISPSTAT1_FRCNT1);
break;
case 2:
field = VC4_GET_FIELD(HVS_READ(SCALER_DISPSTAT2),
SCALER_DISPSTAT2_FRCNT2);
break;
}
return field;
}
int vc4_hvs_get_fifo_from_output(struct drm_device *dev, unsigned int output)
{
struct vc4_dev *vc4 = to_vc4_dev(dev);
......
......@@ -379,8 +379,6 @@
# define SCALER_DISPSTATX_MODE_EOF 3
# define SCALER_DISPSTATX_FULL BIT(29)
# define SCALER_DISPSTATX_EMPTY BIT(28)
# define SCALER_DISPSTATX_FRAME_COUNT_MASK VC4_MASK(17, 12)
# define SCALER_DISPSTATX_FRAME_COUNT_SHIFT 12
# define SCALER_DISPSTATX_LINE_MASK VC4_MASK(11, 0)
# define SCALER_DISPSTATX_LINE_SHIFT 0
......@@ -403,9 +401,15 @@
(x) * (SCALER_DISPBKGND1 - \
SCALER_DISPBKGND0))
#define SCALER_DISPSTAT1 0x00000058
# define SCALER_DISPSTAT1_FRCNT0_MASK VC4_MASK(23, 18)
# define SCALER_DISPSTAT1_FRCNT0_SHIFT 18
# define SCALER_DISPSTAT1_FRCNT1_MASK VC4_MASK(17, 12)
# define SCALER_DISPSTAT1_FRCNT1_SHIFT 12
#define SCALER_DISPSTATX(x) (SCALER_DISPSTAT0 + \
(x) * (SCALER_DISPSTAT1 - \
SCALER_DISPSTAT0))
#define SCALER_DISPBASE1 0x0000005c
#define SCALER_DISPBASEX(x) (SCALER_DISPBASE0 + \
(x) * (SCALER_DISPBASE1 - \
......@@ -415,7 +419,11 @@
(x) * (SCALER_DISPCTRL1 - \
SCALER_DISPCTRL0))
#define SCALER_DISPBKGND2 0x00000064
#define SCALER_DISPSTAT2 0x00000068
# define SCALER_DISPSTAT2_FRCNT2_MASK VC4_MASK(17, 12)
# define SCALER_DISPSTAT2_FRCNT2_SHIFT 12
#define SCALER_DISPBASE2 0x0000006c
#define SCALER_DISPALPHA2 0x00000070
#define SCALER_GAMADDR 0x00000078
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment