Browse Source

Update vc4_txp.c

Fix the core dump error for GUI under qortal's mempow crunch.
main
balloonatic 2 years ago committed by GitHub
parent
commit
5d221765c0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 64
      drivers/gpu/drm/vc4/vc4_txp.c

64
drivers/gpu/drm/vc4/vc4_txp.c

@ -1,10 +1,11 @@
// SPDX-License-Identifier: GPL-2.0 // SPDX-License-Identifier: GPL-2.0
/* /*
* Copyright © 2018 Broadcom * Copyright (C) 2018 Broadcom
* * Copyright (C) 2022 Qortal Project
* Authors: * Authors:
* Eric Anholt <eric@anholt.net> * Eric Anholt <eric@anholt.net>
* Boris Brezillon <boris.brezillon@bootlin.com> * Boris Brezillon <boris.brezillon@bootlin.com>
* Scare Crowe <dmax@crowetic.com>
*/ */
#include <linux/clk.h> #include <linux/clk.h>
@ -15,6 +16,7 @@
#include <drm/drm_atomic.h> #include <drm/drm_atomic.h>
#include <drm/drm_atomic_helper.h> #include <drm/drm_atomic_helper.h>
#include <drm/drm_drv.h>
#include <drm/drm_edid.h> #include <drm/drm_edid.h>
#include <drm/drm_fb_cma_helper.h> #include <drm/drm_fb_cma_helper.h>
#include <drm/drm_fourcc.h> #include <drm/drm_fourcc.h>
@ -154,7 +156,6 @@ struct vc4_txp {
struct drm_writeback_connector connector; struct drm_writeback_connector connector;
void __iomem *regs; void __iomem *regs;
struct debugfs_regset32 regset;
}; };
static inline struct vc4_txp *encoder_to_vc4_txp(struct drm_encoder *encoder) static inline struct vc4_txp *encoder_to_vc4_txp(struct drm_encoder *encoder)
@ -275,6 +276,7 @@ static int vc4_txp_connector_atomic_check(struct drm_connector *conn,
static void vc4_txp_connector_atomic_commit(struct drm_connector *conn, static void vc4_txp_connector_atomic_commit(struct drm_connector *conn,
struct drm_atomic_state *state) struct drm_atomic_state *state)
{ {
struct drm_device *drm = conn->dev;
struct drm_connector_state *conn_state = drm_atomic_get_new_connector_state(state, struct drm_connector_state *conn_state = drm_atomic_get_new_connector_state(state,
conn); conn);
struct vc4_txp *txp = connector_to_vc4_txp(conn); struct vc4_txp *txp = connector_to_vc4_txp(conn);
@ -282,6 +284,7 @@ static void vc4_txp_connector_atomic_commit(struct drm_connector *conn,
struct drm_display_mode *mode; struct drm_display_mode *mode;
struct drm_framebuffer *fb; struct drm_framebuffer *fb;
u32 ctrl; u32 ctrl;
int idx;
int i; int i;
if (WARN_ON(!conn_state->writeback_job)) if (WARN_ON(!conn_state->writeback_job))
@ -305,8 +308,15 @@ static void vc4_txp_connector_atomic_commit(struct drm_connector *conn,
if (fb->format->has_alpha) if (fb->format->has_alpha)
ctrl |= TXP_ALPHA_ENABLE; ctrl |= TXP_ALPHA_ENABLE;
else else
/*
* If TXP_ALPHA_ENABLE isn't set and TXP_ALPHA_INVERT is, the
* hardware will force the output padding to be 0xff.
*/
ctrl |= TXP_ALPHA_INVERT; ctrl |= TXP_ALPHA_INVERT;
if (!drm_dev_enter(drm, &idx))
return;
gem = drm_fb_cma_get_gem_obj(fb, 0); gem = drm_fb_cma_get_gem_obj(fb, 0);
TXP_WRITE(TXP_DST_PTR, gem->paddr + fb->offsets[0]); TXP_WRITE(TXP_DST_PTR, gem->paddr + fb->offsets[0]);
TXP_WRITE(TXP_DST_PITCH, fb->pitches[0]); TXP_WRITE(TXP_DST_PITCH, fb->pitches[0]);
@ -317,6 +327,8 @@ static void vc4_txp_connector_atomic_commit(struct drm_connector *conn,
TXP_WRITE(TXP_DST_CTRL, ctrl); TXP_WRITE(TXP_DST_CTRL, ctrl);
drm_writeback_queue_job(&txp->connector, conn_state); drm_writeback_queue_job(&txp->connector, conn_state);
drm_dev_exit(idx);
} }
static const struct drm_connector_helper_funcs vc4_txp_connector_helper_funcs = { static const struct drm_connector_helper_funcs vc4_txp_connector_helper_funcs = {
@ -332,16 +344,10 @@ vc4_txp_connector_detect(struct drm_connector *connector, bool force)
return connector_status_connected; return connector_status_connected;
} }
static void vc4_txp_connector_destroy(struct drm_connector *connector)
{
drm_connector_unregister(connector);
drm_connector_cleanup(connector);
}
static const struct drm_connector_funcs vc4_txp_connector_funcs = { static const struct drm_connector_funcs vc4_txp_connector_funcs = {
.detect = vc4_txp_connector_detect, .detect = vc4_txp_connector_detect,
.fill_modes = drm_helper_probe_single_connector_modes, .fill_modes = drm_helper_probe_single_connector_modes,
.destroy = vc4_txp_connector_destroy, .destroy = drm_connector_cleanup,
.reset = drm_atomic_helper_connector_reset, .reset = drm_atomic_helper_connector_reset,
.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
.atomic_destroy_state = drm_atomic_helper_connector_destroy_state, .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
@ -349,7 +355,12 @@ static const struct drm_connector_funcs vc4_txp_connector_funcs = {
static void vc4_txp_encoder_disable(struct drm_encoder *encoder) static void vc4_txp_encoder_disable(struct drm_encoder *encoder)
{ {
struct drm_device *drm = encoder->dev;
struct vc4_txp *txp = encoder_to_vc4_txp(encoder); struct vc4_txp *txp = encoder_to_vc4_txp(encoder);
int idx;
if (!drm_dev_enter(drm, &idx))
return;
if (TXP_READ(TXP_DST_CTRL) & TXP_BUSY) { if (TXP_READ(TXP_DST_CTRL) & TXP_BUSY) {
unsigned long timeout = jiffies + msecs_to_jiffies(1000); unsigned long timeout = jiffies + msecs_to_jiffies(1000);
@ -364,6 +375,8 @@ static void vc4_txp_encoder_disable(struct drm_encoder *encoder)
} }
TXP_WRITE(TXP_DST_CTRL, TXP_POWERDOWN); TXP_WRITE(TXP_DST_CTRL, TXP_POWERDOWN);
drm_dev_exit(idx);
} }
static const struct drm_encoder_helper_funcs vc4_txp_encoder_helper_funcs = { static const struct drm_encoder_helper_funcs vc4_txp_encoder_helper_funcs = {
@ -379,13 +392,13 @@ static void vc4_txp_disable_vblank(struct drm_crtc *crtc) {}
static const struct drm_crtc_funcs vc4_txp_crtc_funcs = { static const struct drm_crtc_funcs vc4_txp_crtc_funcs = {
.set_config = drm_atomic_helper_set_config, .set_config = drm_atomic_helper_set_config,
.destroy = vc4_crtc_destroy,
.page_flip = vc4_page_flip, .page_flip = vc4_page_flip,
.reset = vc4_crtc_reset, .reset = vc4_crtc_reset,
.atomic_duplicate_state = vc4_crtc_duplicate_state, .atomic_duplicate_state = vc4_crtc_duplicate_state,
.atomic_destroy_state = vc4_crtc_destroy_state, .atomic_destroy_state = vc4_crtc_destroy_state,
.enable_vblank = vc4_txp_enable_vblank, .enable_vblank = vc4_txp_enable_vblank,
.disable_vblank = vc4_txp_disable_vblank, .disable_vblank = vc4_txp_disable_vblank,
.late_register = vc4_crtc_late_register,
}; };
static int vc4_txp_atomic_check(struct drm_crtc *crtc, static int vc4_txp_atomic_check(struct drm_crtc *crtc,
@ -448,6 +461,16 @@ static irqreturn_t vc4_txp_interrupt(int irq, void *data)
struct vc4_txp *txp = data; struct vc4_txp *txp = data;
struct vc4_crtc *vc4_crtc = &txp->base; struct vc4_crtc *vc4_crtc = &txp->base;
/*
* We don't need to protect the register access using
* drm_dev_enter() there because the interrupt handler lifetime
* is tied to the device itself, and not to the DRM device.
*
* So when the device will be gone, one of the first thing we
* will be doing will be to unregister the interrupt handler,
* and then unregister the DRM device. drm_dev_enter() would
* thus always succeed if we are here.
*/
TXP_WRITE(TXP_DST_CTRL, TXP_READ(TXP_DST_CTRL) & ~TXP_EI); TXP_WRITE(TXP_DST_CTRL, TXP_READ(TXP_DST_CTRL) & ~TXP_EI);
vc4_crtc_handle_vblank(vc4_crtc); vc4_crtc_handle_vblank(vc4_crtc);
drm_writeback_signal_completion(&txp->connector, 0); drm_writeback_signal_completion(&txp->connector, 0);
@ -456,6 +479,7 @@ static irqreturn_t vc4_txp_interrupt(int irq, void *data)
} }
static const struct vc4_crtc_data vc4_txp_crtc_data = { static const struct vc4_crtc_data vc4_txp_crtc_data = {
.debugfs_name = "txp_regs",
.hvs_available_channels = BIT(2), .hvs_available_channels = BIT(2),
.hvs_output = 2, .hvs_output = 2,
}; };
@ -464,7 +488,6 @@ static int vc4_txp_bind(struct device *dev, struct device *master, void *data)
{ {
struct platform_device *pdev = to_platform_device(dev); struct platform_device *pdev = to_platform_device(dev);
struct drm_device *drm = dev_get_drvdata(master); struct drm_device *drm = dev_get_drvdata(master);
struct vc4_dev *vc4 = to_vc4_dev(drm);
struct vc4_crtc *vc4_crtc; struct vc4_crtc *vc4_crtc;
struct vc4_txp *txp; struct vc4_txp *txp;
struct drm_crtc *crtc; struct drm_crtc *crtc;
@ -475,7 +498,7 @@ static int vc4_txp_bind(struct device *dev, struct device *master, void *data)
if (irq < 0) if (irq < 0)
return irq; return irq;
txp = devm_kzalloc(dev, sizeof(*txp), GFP_KERNEL); txp = drmm_kzalloc(drm, sizeof(*txp), GFP_KERNEL);
if (!txp) if (!txp)
return -ENOMEM; return -ENOMEM;
vc4_crtc = &txp->base; vc4_crtc = &txp->base;
@ -490,9 +513,9 @@ static int vc4_txp_bind(struct device *dev, struct device *master, void *data)
txp->regs = vc4_ioremap_regs(pdev, 0); txp->regs = vc4_ioremap_regs(pdev, 0);
if (IS_ERR(txp->regs)) if (IS_ERR(txp->regs))
return PTR_ERR(txp->regs); return PTR_ERR(txp->regs);
txp->regset.base = txp->regs; vc4_crtc->regset.base = txp->regs;
txp->regset.regs = txp_regs; vc4_crtc->regset.regs = txp_regs;
txp->regset.nregs = ARRAY_SIZE(txp_regs); vc4_crtc->regset.nregs = ARRAY_SIZE(txp_regs);
drm_connector_helper_add(&txp->connector.base, drm_connector_helper_add(&txp->connector.base,
&vc4_txp_connector_helper_funcs); &vc4_txp_connector_helper_funcs);
@ -517,9 +540,6 @@ static int vc4_txp_bind(struct device *dev, struct device *master, void *data)
return ret; return ret;
dev_set_drvdata(dev, txp); dev_set_drvdata(dev, txp);
vc4->txp = txp;
vc4_debugfs_add_regset32(drm, "txp_regs", &txp->regset);
return 0; return 0;
} }
@ -527,13 +547,9 @@ static int vc4_txp_bind(struct device *dev, struct device *master, void *data)
static void vc4_txp_unbind(struct device *dev, struct device *master, static void vc4_txp_unbind(struct device *dev, struct device *master,
void *data) void *data)
{ {
struct drm_device *drm = dev_get_drvdata(master);
struct vc4_dev *vc4 = to_vc4_dev(drm);
struct vc4_txp *txp = dev_get_drvdata(dev); struct vc4_txp *txp = dev_get_drvdata(dev);
vc4_txp_connector_destroy(&txp->connector.base); drm_connector_cleanup(&txp->connector.base);
vc4->txp = NULL;
} }
static const struct component_ops vc4_txp_ops = { static const struct component_ops vc4_txp_ops = {

Loading…
Cancel
Save