Skip to content

Commit

Permalink
drm/vc4: txp: Turn the TXP into a CRTC of its own
Browse files Browse the repository at this point in the history
The TXP so far has been leveraging the PixelValve infrastructure in the
driver, that was really two things: the interaction with DRM's CRTC
concept, the setup of the underlying pixelvalve and the setup of the shared
HVS, the pixelvalve part being irrelevant to the TXP since it accesses the
HVS directly.

Now that we have a clear separation between the three parts, we can
represent the TXP as a CRTC of its own, leveraging the common CRTC and HVS
code, but leaving aside the pixelvalve setup.

Signed-off-by: Maxime Ripard <maxime@cerno.tech>
Reviewed-by: Eric Anholt <eric@anholt.net>
Link: https://patchwork.freedesktop.org/patch/msgid/20f387f881b57f3474fa42d94cfd8bc1b7b80595.1591882579.git-series.maxime@cerno.tech
  • Loading branch information
mripard committed Jul 7, 2020
1 parent e25a21a commit 39fcb28
Show file tree
Hide file tree
Showing 2 changed files with 99 additions and 20 deletions.
19 changes: 0 additions & 19 deletions drivers/gpu/drm/vc4/vc4_crtc.c
Original file line number Diff line number Diff line change
Expand Up @@ -474,17 +474,6 @@ static int vc4_crtc_atomic_check(struct drm_crtc *crtc,
if (conn_state->crtc != crtc)
continue;

/* The writeback connector is implemented using the transposer
* block which is directly taking its data from the HVS FIFO.
*/
if (conn->connector_type == DRM_MODE_CONNECTOR_WRITEBACK) {
state->no_vblank = true;
vc4_state->feed_txp = true;
} else {
state->no_vblank = false;
vc4_state->feed_txp = false;
}

vc4_state->margins.left = conn_state->tv.margins.left;
vc4_state->margins.right = conn_state->tv.margins.right;
vc4_state->margins.top = conn_state->tv.margins.top;
Expand Down Expand Up @@ -826,7 +815,6 @@ static void vc4_set_crtc_possible_masks(struct drm_device *drm,
struct drm_crtc *crtc)
{
struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc);
const struct vc4_crtc_data *crtc_data = vc4_crtc_to_vc4_crtc_data(vc4_crtc);
const struct vc4_pv_data *pv_data = vc4_crtc_to_vc4_pv_data(vc4_crtc);
const enum vc4_encoder_type *encoder_types = pv_data->encoder_types;
struct drm_encoder *encoder;
Expand All @@ -835,13 +823,6 @@ static void vc4_set_crtc_possible_masks(struct drm_device *drm,
struct vc4_encoder *vc4_encoder;
int i;

/* HVS FIFO2 can feed the TXP IP. */
if (crtc_data->hvs_channel == 2 &&
encoder->encoder_type == DRM_MODE_ENCODER_VIRTUAL) {
encoder->possible_crtcs |= drm_crtc_mask(crtc);
continue;
}

vc4_encoder = to_vc4_encoder(encoder);
for (i = 0; i < ARRAY_SIZE(pv_data->encoder_types); i++) {
if (vc4_encoder->type == encoder_types[i]) {
Expand Down
100 changes: 99 additions & 1 deletion drivers/gpu/drm/vc4/vc4_txp.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#include <drm/drm_fourcc.h>
#include <drm/drm_panel.h>
#include <drm/drm_probe_helper.h>
#include <drm/drm_vblank.h>
#include <drm/drm_writeback.h>

#include "vc4_drv.h"
Expand Down Expand Up @@ -145,6 +146,8 @@
#define TXP_WRITE(offset, val) writel(val, txp->regs + (offset))

struct vc4_txp {
struct vc4_crtc base;

struct platform_device *pdev;

struct drm_writeback_connector connector;
Expand Down Expand Up @@ -362,23 +365,105 @@ static const struct drm_encoder_helper_funcs vc4_txp_encoder_helper_funcs = {
.disable = vc4_txp_encoder_disable,
};

static int vc4_txp_enable_vblank(struct drm_crtc *crtc)
{
return 0;
}

static void vc4_txp_disable_vblank(struct drm_crtc *crtc) {}

static const struct drm_crtc_funcs vc4_txp_crtc_funcs = {
.set_config = drm_atomic_helper_set_config,
.destroy = vc4_crtc_destroy,
.page_flip = vc4_page_flip,
.reset = vc4_crtc_reset,
.atomic_duplicate_state = vc4_crtc_duplicate_state,
.atomic_destroy_state = vc4_crtc_destroy_state,
.gamma_set = drm_atomic_helper_legacy_gamma_set,
.enable_vblank = vc4_txp_enable_vblank,
.disable_vblank = vc4_txp_disable_vblank,
};

static int vc4_txp_atomic_check(struct drm_crtc *crtc,
struct drm_crtc_state *state)
{
struct vc4_crtc_state *vc4_state = to_vc4_crtc_state(state);
int ret;

ret = vc4_hvs_atomic_check(crtc, state);
if (ret)
return ret;

state->no_vblank = true;
vc4_state->feed_txp = true;

return 0;
}

static void vc4_txp_atomic_enable(struct drm_crtc *crtc,
struct drm_crtc_state *old_state)
{
drm_crtc_vblank_on(crtc);
vc4_hvs_atomic_enable(crtc, old_state);
}

static void vc4_txp_atomic_disable(struct drm_crtc *crtc,
struct drm_crtc_state *old_state)
{
struct drm_device *dev = crtc->dev;

/* Disable vblank irq handling before crtc is disabled. */
drm_crtc_vblank_off(crtc);

vc4_hvs_atomic_disable(crtc, old_state);

/*
* Make sure we issue a vblank event after disabling the CRTC if
* someone was waiting it.
*/
if (crtc->state->event) {
unsigned long flags;

spin_lock_irqsave(&dev->event_lock, flags);
drm_crtc_send_vblank_event(crtc, crtc->state->event);
crtc->state->event = NULL;
spin_unlock_irqrestore(&dev->event_lock, flags);
}
}

static const struct drm_crtc_helper_funcs vc4_txp_crtc_helper_funcs = {
.atomic_check = vc4_txp_atomic_check,
.atomic_flush = vc4_hvs_atomic_flush,
.atomic_enable = vc4_txp_atomic_enable,
.atomic_disable = vc4_txp_atomic_disable,
.mode_set_nofb = vc4_hvs_mode_set_nofb,
};

static irqreturn_t vc4_txp_interrupt(int irq, void *data)
{
struct vc4_txp *txp = data;
struct vc4_crtc *vc4_crtc = &txp->base;

TXP_WRITE(TXP_DST_CTRL, TXP_READ(TXP_DST_CTRL) & ~TXP_EI);
vc4_crtc_handle_vblank(to_vc4_crtc(txp->connector.base.state->crtc));
vc4_crtc_handle_vblank(vc4_crtc);
drm_writeback_signal_completion(&txp->connector, 0);

return IRQ_HANDLED;
}

static const struct vc4_crtc_data vc4_txp_crtc_data = {
.hvs_channel = 2,
};

static int vc4_txp_bind(struct device *dev, struct device *master, void *data)
{
struct platform_device *pdev = to_platform_device(dev);
struct drm_device *drm = dev_get_drvdata(master);
struct vc4_dev *vc4 = to_vc4_dev(drm);
struct vc4_crtc *vc4_crtc;
struct vc4_txp *txp;
struct drm_crtc *crtc;
struct drm_encoder *encoder;
int ret, irq;

irq = platform_get_irq(pdev, 0);
Expand All @@ -388,6 +473,11 @@ static int vc4_txp_bind(struct device *dev, struct device *master, void *data)
txp = devm_kzalloc(dev, sizeof(*txp), GFP_KERNEL);
if (!txp)
return -ENOMEM;
vc4_crtc = &txp->base;
crtc = &vc4_crtc->base;

vc4_crtc->pdev = pdev;
vc4_crtc->data = &vc4_txp_crtc_data;

txp->pdev = pdev;

Expand All @@ -407,6 +497,14 @@ static int vc4_txp_bind(struct device *dev, struct device *master, void *data)
if (ret)
return ret;

ret = vc4_crtc_init(drm, vc4_crtc,
&vc4_txp_crtc_funcs, &vc4_txp_crtc_helper_funcs);
if (ret)
return ret;

encoder = &txp->connector.encoder;
encoder->possible_crtcs |= drm_crtc_mask(crtc);

ret = devm_request_irq(dev, irq, vc4_txp_interrupt, 0,
dev_name(dev), txp);
if (ret)
Expand Down

0 comments on commit 39fcb28

Please sign in to comment.