Skip to content

Fix for the cursor corruption with KMS (again) #4895

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions arch/arm/boot/dts/bcm2711.dtsi
Original file line number Diff line number Diff line change
Expand Up @@ -290,6 +290,7 @@

hvs: hvs@7e400000 {
compatible = "brcm,bcm2711-hvs";
reg = <0x7e400000 0x8000>;
interrupts = <GIC_SPI 97 IRQ_TYPE_LEVEL_HIGH>;
};

Expand Down
24 changes: 12 additions & 12 deletions drivers/gpu/drm/vc4/vc4_crtc.c
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ static const struct debugfs_reg32 crtc_regs[] = {
static unsigned int
vc4_crtc_get_cob_allocation(struct vc4_dev *vc4, unsigned int channel)
{
struct vc4_hvs *hvs = vc4->hvs;
u32 dispbase = HVS_READ(SCALER_DISPBASEX(channel));
/* Top/base are supposed to be 4-pixel aligned, but the
* Raspberry Pi firmware fills the low bits (which are
Expand All @@ -89,6 +90,7 @@ static bool vc4_crtc_get_scanout_position(struct drm_crtc *crtc,
{
struct drm_device *dev = crtc->dev;
struct vc4_dev *vc4 = to_vc4_dev(dev);
struct vc4_hvs *hvs = vc4->hvs;
struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc);
struct vc4_crtc_state *vc4_crtc_state = to_vc4_crtc_state(crtc->state);
unsigned int cob_size;
Expand Down Expand Up @@ -123,7 +125,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(hvs, vc4_crtc_state->assigned_channel) % 2)
*hpos += mode->crtc_htotal / 2;
}

Expand Down Expand Up @@ -449,6 +451,7 @@ static void vc4_crtc_config_pv(struct drm_crtc *crtc, struct drm_encoder *encode
static void require_hvs_enabled(struct drm_device *dev)
{
struct vc4_dev *vc4 = to_vc4_dev(dev);
struct vc4_hvs *hvs = vc4->hvs;

WARN_ON_ONCE((HVS_READ(SCALER_DISPCTRL) & SCALER_DISPCTRL_ENABLE) !=
SCALER_DISPCTRL_ENABLE);
Expand All @@ -462,6 +465,7 @@ static int vc4_crtc_disable(struct drm_crtc *crtc,
struct vc4_encoder *vc4_encoder = to_vc4_encoder(encoder);
struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc);
struct drm_device *dev = crtc->dev;
struct vc4_dev *vc4 = to_vc4_dev(dev);
int ret;

CRTC_WRITE(PV_V_CONTROL,
Expand Down Expand Up @@ -491,7 +495,7 @@ static int vc4_crtc_disable(struct drm_crtc *crtc,
vc4_encoder->post_crtc_disable(encoder, state);

vc4_crtc_pixelvalve_reset(crtc);
vc4_hvs_stop_channel(dev, channel);
vc4_hvs_stop_channel(vc4->hvs, channel);

if (vc4_encoder && vc4_encoder->post_crtc_powerdown)
vc4_encoder->post_crtc_powerdown(encoder, state);
Expand All @@ -517,6 +521,7 @@ static struct drm_encoder *vc4_crtc_get_encoder_by_type(struct drm_crtc *crtc,
int vc4_crtc_disable_at_boot(struct drm_crtc *crtc)
{
struct drm_device *drm = crtc->dev;
struct vc4_dev *vc4 = to_vc4_dev(drm);
struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc);
enum vc4_encoder_type encoder_type;
const struct vc4_pv_data *pv_data;
Expand All @@ -538,7 +543,7 @@ int vc4_crtc_disable_at_boot(struct drm_crtc *crtc)
if (!(CRTC_READ(PV_V_CONTROL) & PV_VCONTROL_VIDEN))
return 0;

channel = vc4_hvs_get_fifo_from_output(drm, vc4_crtc->data->hvs_output);
channel = vc4_hvs_get_fifo_from_output(vc4->hvs, vc4_crtc->data->hvs_output);
if (channel < 0)
return 0;

Expand Down Expand Up @@ -752,6 +757,7 @@ static void vc4_crtc_handle_page_flip(struct vc4_crtc *vc4_crtc)
struct drm_crtc *crtc = &vc4_crtc->base;
struct drm_device *dev = crtc->dev;
struct vc4_dev *vc4 = to_vc4_dev(dev);
struct vc4_hvs *hvs = vc4->hvs;
u32 chan = vc4_crtc->current_hvs_channel;
unsigned long flags;

Expand All @@ -770,7 +776,7 @@ static void vc4_crtc_handle_page_flip(struct vc4_crtc *vc4_crtc)
* the CRTC and encoder already reconfigured, leading to
* underruns. This can be seen when reconfiguring the CRTC.
*/
vc4_hvs_unmask_underrun(dev, chan);
vc4_hvs_unmask_underrun(hvs, chan);
}
spin_unlock(&vc4_crtc->irq_lock);
spin_unlock_irqrestore(&dev->event_lock, flags);
Expand Down Expand Up @@ -951,14 +957,8 @@ void vc4_crtc_destroy_state(struct drm_crtc *crtc,
struct vc4_dev *vc4 = to_vc4_dev(crtc->dev);
struct vc4_crtc_state *vc4_state = to_vc4_crtc_state(state);

if (drm_mm_node_allocated(&vc4_state->mm)) {
unsigned long flags;

spin_lock_irqsave(&vc4->hvs->mm_lock, flags);
drm_mm_remove_node(&vc4_state->mm);
spin_unlock_irqrestore(&vc4->hvs->mm_lock, flags);

}
vc4_hvs_mark_dlist_entry_stale(vc4->hvs, vc4_state->mm);
vc4_state->mm = NULL;

drm_atomic_helper_crtc_destroy_state(crtc, state);
}
Expand Down
48 changes: 22 additions & 26 deletions drivers/gpu/drm/vc4/vc4_drv.h
Original file line number Diff line number Diff line change
Expand Up @@ -335,20 +335,15 @@ struct vc4_hvs {
struct drm_mm lbm_mm;
spinlock_t mm_lock;

struct list_head stale_dlist_entries;
struct work_struct free_dlist_work;

struct drm_mm_node mitchell_netravali_filter;

struct debugfs_regset32 regset;

/* HVS version 5 flag, therefore requires updated dlist structures */
bool hvs5;

spinlock_t hw_dlist_lock;
struct {
unsigned int start;
unsigned int size;
u32 shadow[2048];
bool pending;
} fifo[3];
};

struct vc4_plane {
Expand Down Expand Up @@ -389,11 +384,6 @@ struct vc4_plane_state {
*/
u32 __iomem *hw_dlist;

/* Offset where the plane's dlist was last stored in the
* shadow dlist bucket at vc4_crtc_atomic_flush() time.
*/
unsigned int dlist_offset;

/* Clipped coordinates of the plane on the display. */
int crtc_x, crtc_y, crtc_w, crtc_h;
/* Clipped area being scanned from in the FB. */
Expand Down Expand Up @@ -586,10 +576,16 @@ struct drm_connector *vc4_get_crtc_connector(struct drm_crtc *crtc,
struct drm_encoder *vc4_get_crtc_encoder(struct drm_crtc *crtc,
struct drm_crtc_state *state);

struct vc4_hvs_dlist_allocation {
struct list_head node;
struct drm_mm_node mm_node;
unsigned int channel;
u8 target_frame_count;
};

struct vc4_crtc_state {
struct drm_crtc_state base;
/* Dlist area for this CRTC configuration. */
struct drm_mm_node mm;
struct vc4_hvs_dlist_allocation *mm;
bool txp_armed;
unsigned int assigned_channel;

Expand All @@ -616,8 +612,8 @@ to_vc4_crtc_state(struct drm_crtc_state *crtc_state)

#define V3D_READ(offset) readl(vc4->v3d->regs + offset)
#define V3D_WRITE(offset, val) writel(val, vc4->v3d->regs + offset)
#define HVS_READ(offset) readl(vc4->hvs->regs + offset)
#define HVS_WRITE(offset, val) writel(val, vc4->hvs->regs + offset)
#define HVS_READ(offset) readl(hvs->regs + offset)
#define HVS_WRITE(offset, val) writel(val, hvs->regs + offset)

#define VC4_REG32(reg) { .name = #reg, .offset = reg }

Expand Down Expand Up @@ -978,16 +974,19 @@ void vc4_irq_reset(struct drm_device *dev);

/* vc4_hvs.c */
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);
void vc4_hvs_stop_channel(struct vc4_hvs *hvs, unsigned int output);
int vc4_hvs_get_fifo_from_output(struct vc4_hvs *hvs, unsigned int output);
u8 vc4_hvs_get_fifo_frame_count(struct vc4_hvs *hvs, unsigned int fifo);
void vc4_hvs_mark_dlist_entry_stale(struct vc4_hvs *hvs,
struct vc4_hvs_dlist_allocation *alloc);
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);
void vc4_hvs_atomic_disable(struct drm_crtc *crtc, struct drm_atomic_state *state);
void vc4_hvs_atomic_flush(struct drm_crtc *crtc, struct drm_atomic_state *state);
void vc4_hvs_dump_state(struct drm_device *dev);
void vc4_hvs_unmask_underrun(struct drm_device *dev, int channel);
void vc4_hvs_mask_underrun(struct drm_device *dev, int channel);
void vc4_hvs_dump_state(struct vc4_hvs *hvs);
void vc4_hvs_unmask_underrun(struct vc4_hvs *hvs, int channel);
void vc4_hvs_mask_underrun(struct vc4_hvs *hvs, int channel);

/* vc4_kms.c */
int vc4_kms_load(struct drm_device *dev);
Expand All @@ -996,10 +995,7 @@ int vc4_kms_load(struct drm_device *dev);
struct drm_plane *vc4_plane_init(struct drm_device *dev,
enum drm_plane_type type);
int vc4_plane_create_additional_planes(struct drm_device *dev);
u32 vc4_plane_write_dlist(struct vc4_hvs *hvs,
struct vc4_crtc_state *vc4_crtc_state,
struct vc4_plane_state *vc4_plane_state,
unsigned dlist_offset);
u32 vc4_plane_write_dlist(struct drm_plane *plane, u32 __iomem *dlist);
u32 vc4_plane_dlist_size(const struct drm_plane_state *state);
void vc4_plane_async_set_fb(struct drm_plane *plane,
struct drm_framebuffer *fb);
Expand Down
Loading