mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-09-14 06:35:12 +00:00
drm: xlnx: zynqmp_dpsub: Move CRTC handling to zynqmp_kms.c
Decouple the CRTC handling from the display controller programming by moving the corresponding code from zynqmp_disp.c to zynqmp_kms.c. This prepares for using the DPSUB with a live video input, without creating a DRM CRTC in the DPSUB driver. Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
This commit is contained in:
parent
76c8eeb72d
commit
83a956d3c3
5 changed files with 232 additions and 235 deletions
|
@ -11,27 +11,21 @@
|
|||
|
||||
#include <drm/drm_atomic.h>
|
||||
#include <drm/drm_atomic_helper.h>
|
||||
#include <drm/drm_atomic_uapi.h>
|
||||
#include <drm/drm_blend.h>
|
||||
#include <drm/drm_crtc.h>
|
||||
#include <drm/drm_device.h>
|
||||
#include <drm/drm_fb_dma_helper.h>
|
||||
#include <drm/drm_fourcc.h>
|
||||
#include <drm/drm_framebuffer.h>
|
||||
#include <drm/drm_managed.h>
|
||||
#include <drm/drm_plane.h>
|
||||
#include <drm/drm_vblank.h>
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/dma/xilinx_dpdma.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/dmaengine.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/spinlock.h>
|
||||
|
||||
#include "zynqmp_disp.h"
|
||||
#include "zynqmp_disp_regs.h"
|
||||
|
@ -88,16 +82,6 @@ struct zynqmp_disp_format {
|
|||
const u32 *sf;
|
||||
};
|
||||
|
||||
/**
|
||||
* enum zynqmp_disp_layer_id - Layer identifier
|
||||
* @ZYNQMP_DISP_LAYER_VID: Video layer
|
||||
* @ZYNQMP_DISP_LAYER_GFX: Graphics layer
|
||||
*/
|
||||
enum zynqmp_disp_layer_id {
|
||||
ZYNQMP_DISP_LAYER_VID,
|
||||
ZYNQMP_DISP_LAYER_GFX
|
||||
};
|
||||
|
||||
/**
|
||||
* enum zynqmp_disp_layer_mode - Layer mode
|
||||
* @ZYNQMP_DISP_LAYER_NONLIVE: non-live (memory) mode
|
||||
|
@ -143,7 +127,7 @@ struct zynqmp_disp_layer_info {
|
|||
* @mode: Current operation mode
|
||||
*/
|
||||
struct zynqmp_disp_layer {
|
||||
enum zynqmp_disp_layer_id id;
|
||||
enum zynqmp_dpsub_layer_id id;
|
||||
struct zynqmp_disp *disp;
|
||||
const struct zynqmp_disp_layer_info *info;
|
||||
|
||||
|
@ -398,12 +382,12 @@ static void zynqmp_disp_avbuf_write(struct zynqmp_disp *disp, int reg, u32 val)
|
|||
|
||||
static bool zynqmp_disp_layer_is_gfx(const struct zynqmp_disp_layer *layer)
|
||||
{
|
||||
return layer->id == ZYNQMP_DISP_LAYER_GFX;
|
||||
return layer->id == ZYNQMP_DPSUB_LAYER_GFX;
|
||||
}
|
||||
|
||||
static bool zynqmp_disp_layer_is_video(const struct zynqmp_disp_layer *layer)
|
||||
{
|
||||
return layer->id == ZYNQMP_DISP_LAYER_VID;
|
||||
return layer->id == ZYNQMP_DPSUB_LAYER_VID;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -882,35 +866,6 @@ static void zynqmp_disp_audio_disable(struct zynqmp_disp *disp)
|
|||
ZYNQMP_DISP_AUD_SOFT_RESET_AUD_SRST);
|
||||
}
|
||||
|
||||
/* -----------------------------------------------------------------------------
|
||||
* ZynqMP Display external functions for zynqmp_dp
|
||||
*/
|
||||
|
||||
/**
|
||||
* zynqmp_disp_handle_vblank - Handle the vblank event
|
||||
* @disp: Display controller
|
||||
*
|
||||
* This function handles the vblank interrupt, and sends an event to
|
||||
* CRTC object. This will be called by the DP vblank interrupt handler.
|
||||
*/
|
||||
void zynqmp_disp_handle_vblank(struct zynqmp_disp *disp)
|
||||
{
|
||||
struct drm_crtc *crtc = &disp->dpsub->crtc;
|
||||
|
||||
drm_crtc_handle_vblank(crtc);
|
||||
}
|
||||
|
||||
/**
|
||||
* zynqmp_disp_get_crtc_mask - Return the CRTC bit mask
|
||||
* @disp: Display controller
|
||||
*
|
||||
* Return: the crtc mask of the zyqnmp_disp CRTC.
|
||||
*/
|
||||
uint32_t zynqmp_disp_get_crtc_mask(struct zynqmp_disp *disp)
|
||||
{
|
||||
return drm_crtc_mask(&disp->dpsub->crtc);
|
||||
}
|
||||
|
||||
/* -----------------------------------------------------------------------------
|
||||
* ZynqMP Display Layer & DRM Plane
|
||||
*/
|
||||
|
@ -1110,7 +1065,7 @@ zynqmp_disp_plane_atomic_check(struct drm_plane *plane,
|
|||
false, false);
|
||||
}
|
||||
|
||||
static void
|
||||
void
|
||||
zynqmp_disp_plane_atomic_disable(struct drm_plane *plane,
|
||||
struct drm_atomic_state *state)
|
||||
{
|
||||
|
@ -1300,12 +1255,12 @@ static int zynqmp_disp_layer_request_dma(struct zynqmp_disp *disp,
|
|||
static int zynqmp_disp_create_layers(struct zynqmp_disp *disp)
|
||||
{
|
||||
static const struct zynqmp_disp_layer_info layer_info[] = {
|
||||
[ZYNQMP_DISP_LAYER_VID] = {
|
||||
[ZYNQMP_DPSUB_LAYER_VID] = {
|
||||
.formats = avbuf_vid_fmts,
|
||||
.num_formats = ARRAY_SIZE(avbuf_vid_fmts),
|
||||
.num_channels = 3,
|
||||
},
|
||||
[ZYNQMP_DISP_LAYER_GFX] = {
|
||||
[ZYNQMP_DPSUB_LAYER_GFX] = {
|
||||
.formats = avbuf_gfx_fmts,
|
||||
.num_formats = ARRAY_SIZE(avbuf_gfx_fmts),
|
||||
.num_channels = 1,
|
||||
|
@ -1335,14 +1290,14 @@ static int zynqmp_disp_create_layers(struct zynqmp_disp *disp)
|
|||
}
|
||||
|
||||
/* -----------------------------------------------------------------------------
|
||||
* ZynqMP Display & DRM CRTC
|
||||
* ZynqMP Display
|
||||
*/
|
||||
|
||||
/**
|
||||
* zynqmp_disp_enable - Enable the display controller
|
||||
* @disp: Display controller
|
||||
*/
|
||||
static void zynqmp_disp_enable(struct zynqmp_disp *disp)
|
||||
void zynqmp_disp_enable(struct zynqmp_disp *disp)
|
||||
{
|
||||
zynqmp_disp_blend_set_output_format(disp, ZYNQMP_DPSUB_FORMAT_RGB);
|
||||
zynqmp_disp_blend_set_bg_color(disp, 0, 0, 0);
|
||||
|
@ -1362,7 +1317,7 @@ static void zynqmp_disp_enable(struct zynqmp_disp *disp)
|
|||
* zynqmp_disp_disable - Disable the display controller
|
||||
* @disp: Display controller
|
||||
*/
|
||||
static void zynqmp_disp_disable(struct zynqmp_disp *disp)
|
||||
void zynqmp_disp_disable(struct zynqmp_disp *disp)
|
||||
{
|
||||
zynqmp_disp_audio_disable(disp);
|
||||
|
||||
|
@ -1371,8 +1326,15 @@ static void zynqmp_disp_disable(struct zynqmp_disp *disp)
|
|||
zynqmp_disp_avbuf_disable(disp);
|
||||
}
|
||||
|
||||
static int zynqmp_disp_setup_clock(struct zynqmp_disp *disp,
|
||||
unsigned long mode_clock)
|
||||
/**
|
||||
* zynqmp_disp_setup_clock - Configure the display controller pixel clock rate
|
||||
* @disp: Display controller
|
||||
* @mode_clock: The pixel clock rate, in Hz
|
||||
*
|
||||
* Return: 0 on success, or a negative error clock otherwise
|
||||
*/
|
||||
int zynqmp_disp_setup_clock(struct zynqmp_disp *disp,
|
||||
unsigned long mode_clock)
|
||||
{
|
||||
unsigned long rate;
|
||||
long diff;
|
||||
|
@ -1398,186 +1360,13 @@ static int zynqmp_disp_setup_clock(struct zynqmp_disp *disp,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static inline struct zynqmp_disp *crtc_to_disp(struct drm_crtc *crtc)
|
||||
{
|
||||
return container_of(crtc, struct zynqmp_dpsub, crtc)->disp;
|
||||
}
|
||||
|
||||
static void
|
||||
zynqmp_disp_crtc_atomic_enable(struct drm_crtc *crtc,
|
||||
struct drm_atomic_state *state)
|
||||
{
|
||||
struct zynqmp_disp *disp = crtc_to_disp(crtc);
|
||||
struct drm_display_mode *adjusted_mode = &crtc->state->adjusted_mode;
|
||||
int ret, vrefresh;
|
||||
|
||||
pm_runtime_get_sync(disp->dev);
|
||||
|
||||
zynqmp_disp_setup_clock(disp, adjusted_mode->clock * 1000);
|
||||
|
||||
ret = clk_prepare_enable(disp->dpsub->vid_clk);
|
||||
if (ret) {
|
||||
dev_err(disp->dev, "failed to enable the video clock\n");
|
||||
pm_runtime_put_sync(disp->dev);
|
||||
return;
|
||||
}
|
||||
|
||||
zynqmp_disp_enable(disp);
|
||||
|
||||
/* Delay of 3 vblank intervals for timing gen to be stable */
|
||||
vrefresh = (adjusted_mode->clock * 1000) /
|
||||
(adjusted_mode->vtotal * adjusted_mode->htotal);
|
||||
msleep(3 * 1000 / vrefresh);
|
||||
}
|
||||
|
||||
static void
|
||||
zynqmp_disp_crtc_atomic_disable(struct drm_crtc *crtc,
|
||||
struct drm_atomic_state *state)
|
||||
{
|
||||
struct zynqmp_disp *disp = crtc_to_disp(crtc);
|
||||
struct drm_plane_state *old_plane_state;
|
||||
|
||||
/*
|
||||
* Disable the plane if active. The old plane state can be NULL in the
|
||||
* .shutdown() path if the plane is already disabled, skip
|
||||
* zynqmp_disp_plane_atomic_disable() in that case.
|
||||
*/
|
||||
old_plane_state = drm_atomic_get_old_plane_state(state, crtc->primary);
|
||||
if (old_plane_state)
|
||||
zynqmp_disp_plane_atomic_disable(crtc->primary, state);
|
||||
|
||||
zynqmp_disp_disable(disp);
|
||||
|
||||
drm_crtc_vblank_off(crtc);
|
||||
|
||||
spin_lock_irq(&crtc->dev->event_lock);
|
||||
if (crtc->state->event) {
|
||||
drm_crtc_send_vblank_event(crtc, crtc->state->event);
|
||||
crtc->state->event = NULL;
|
||||
}
|
||||
spin_unlock_irq(&crtc->dev->event_lock);
|
||||
|
||||
clk_disable_unprepare(disp->dpsub->vid_clk);
|
||||
pm_runtime_put_sync(disp->dev);
|
||||
}
|
||||
|
||||
static int zynqmp_disp_crtc_atomic_check(struct drm_crtc *crtc,
|
||||
struct drm_atomic_state *state)
|
||||
{
|
||||
return drm_atomic_add_affected_planes(state, crtc);
|
||||
}
|
||||
|
||||
static void
|
||||
zynqmp_disp_crtc_atomic_begin(struct drm_crtc *crtc,
|
||||
struct drm_atomic_state *state)
|
||||
{
|
||||
drm_crtc_vblank_on(crtc);
|
||||
}
|
||||
|
||||
static void
|
||||
zynqmp_disp_crtc_atomic_flush(struct drm_crtc *crtc,
|
||||
struct drm_atomic_state *state)
|
||||
{
|
||||
if (crtc->state->event) {
|
||||
struct drm_pending_vblank_event *event;
|
||||
|
||||
/* Consume the flip_done event from atomic helper. */
|
||||
event = crtc->state->event;
|
||||
crtc->state->event = NULL;
|
||||
|
||||
event->pipe = drm_crtc_index(crtc);
|
||||
|
||||
WARN_ON(drm_crtc_vblank_get(crtc) != 0);
|
||||
|
||||
spin_lock_irq(&crtc->dev->event_lock);
|
||||
drm_crtc_arm_vblank_event(crtc, event);
|
||||
spin_unlock_irq(&crtc->dev->event_lock);
|
||||
}
|
||||
}
|
||||
|
||||
static const struct drm_crtc_helper_funcs zynqmp_disp_crtc_helper_funcs = {
|
||||
.atomic_enable = zynqmp_disp_crtc_atomic_enable,
|
||||
.atomic_disable = zynqmp_disp_crtc_atomic_disable,
|
||||
.atomic_check = zynqmp_disp_crtc_atomic_check,
|
||||
.atomic_begin = zynqmp_disp_crtc_atomic_begin,
|
||||
.atomic_flush = zynqmp_disp_crtc_atomic_flush,
|
||||
};
|
||||
|
||||
static int zynqmp_disp_crtc_enable_vblank(struct drm_crtc *crtc)
|
||||
{
|
||||
struct zynqmp_disp *disp = crtc_to_disp(crtc);
|
||||
|
||||
zynqmp_dp_enable_vblank(disp->dpsub->dp);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void zynqmp_disp_crtc_disable_vblank(struct drm_crtc *crtc)
|
||||
{
|
||||
struct zynqmp_disp *disp = crtc_to_disp(crtc);
|
||||
|
||||
zynqmp_dp_disable_vblank(disp->dpsub->dp);
|
||||
}
|
||||
|
||||
static const struct drm_crtc_funcs zynqmp_disp_crtc_funcs = {
|
||||
.destroy = drm_crtc_cleanup,
|
||||
.set_config = drm_atomic_helper_set_config,
|
||||
.page_flip = drm_atomic_helper_page_flip,
|
||||
.reset = drm_atomic_helper_crtc_reset,
|
||||
.atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state,
|
||||
.atomic_destroy_state = drm_atomic_helper_crtc_destroy_state,
|
||||
.enable_vblank = zynqmp_disp_crtc_enable_vblank,
|
||||
.disable_vblank = zynqmp_disp_crtc_disable_vblank,
|
||||
};
|
||||
|
||||
static int zynqmp_disp_create_crtc(struct zynqmp_disp *disp)
|
||||
{
|
||||
struct drm_plane *plane = &disp->dpsub->planes[ZYNQMP_DISP_LAYER_GFX];
|
||||
struct drm_crtc *crtc = &disp->dpsub->crtc;
|
||||
int ret;
|
||||
|
||||
ret = drm_crtc_init_with_planes(disp->drm, crtc, plane,
|
||||
NULL, &zynqmp_disp_crtc_funcs, NULL);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
drm_crtc_helper_add(crtc, &zynqmp_disp_crtc_helper_funcs);
|
||||
|
||||
/* Start with vertical blanking interrupt reporting disabled. */
|
||||
drm_crtc_vblank_off(crtc);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void zynqmp_disp_map_crtc_to_plane(struct zynqmp_disp *disp)
|
||||
{
|
||||
u32 possible_crtcs = drm_crtc_mask(&disp->dpsub->crtc);
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(disp->layers); i++)
|
||||
disp->dpsub->planes[i].possible_crtcs = possible_crtcs;
|
||||
}
|
||||
|
||||
/* -----------------------------------------------------------------------------
|
||||
* Initialization & Cleanup
|
||||
*/
|
||||
|
||||
int zynqmp_disp_drm_init(struct zynqmp_dpsub *dpsub)
|
||||
{
|
||||
struct zynqmp_disp *disp = dpsub->disp;
|
||||
int ret;
|
||||
|
||||
ret = zynqmp_disp_create_planes(disp);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = zynqmp_disp_create_crtc(disp);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
zynqmp_disp_map_crtc_to_plane(disp);
|
||||
|
||||
return 0;
|
||||
return zynqmp_disp_create_planes(dpsub->disp);
|
||||
}
|
||||
|
||||
int zynqmp_disp_probe(struct zynqmp_dpsub *dpsub, struct drm_device *drm)
|
||||
|
@ -1617,7 +1406,7 @@ int zynqmp_disp_probe(struct zynqmp_dpsub *dpsub, struct drm_device *drm)
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
layer = &disp->layers[ZYNQMP_DISP_LAYER_VID];
|
||||
layer = &disp->layers[ZYNQMP_DPSUB_LAYER_VID];
|
||||
dpsub->dma_align = 1 << layer->dmas[0].chan->device->copy_align;
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -25,13 +25,30 @@
|
|||
#define ZYNQMP_DISP_MAX_DMA_BIT 44
|
||||
|
||||
struct device;
|
||||
struct drm_atomic_state;
|
||||
struct drm_device;
|
||||
struct drm_plane;
|
||||
struct platform_device;
|
||||
struct zynqmp_disp;
|
||||
struct zynqmp_dpsub;
|
||||
|
||||
void zynqmp_disp_handle_vblank(struct zynqmp_disp *disp);
|
||||
uint32_t zynqmp_disp_get_crtc_mask(struct zynqmp_disp *disp);
|
||||
/**
|
||||
* enum zynqmp_dpsub_layer_id - Layer identifier
|
||||
* @ZYNQMP_DPSUB_LAYER_VID: Video layer
|
||||
* @ZYNQMP_DPSUB_LAYER_GFX: Graphics layer
|
||||
*/
|
||||
enum zynqmp_dpsub_layer_id {
|
||||
ZYNQMP_DPSUB_LAYER_VID,
|
||||
ZYNQMP_DPSUB_LAYER_GFX,
|
||||
};
|
||||
|
||||
void zynqmp_disp_enable(struct zynqmp_disp *disp);
|
||||
void zynqmp_disp_disable(struct zynqmp_disp *disp);
|
||||
int zynqmp_disp_setup_clock(struct zynqmp_disp *disp,
|
||||
unsigned long mode_clock);
|
||||
|
||||
void zynqmp_disp_plane_atomic_disable(struct drm_plane *plane,
|
||||
struct drm_atomic_state *state);
|
||||
|
||||
int zynqmp_disp_drm_init(struct zynqmp_dpsub *dpsub);
|
||||
int zynqmp_disp_probe(struct zynqmp_dpsub *dpsub, struct drm_device *drm);
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
#include "zynqmp_disp.h"
|
||||
#include "zynqmp_dp.h"
|
||||
#include "zynqmp_dpsub.h"
|
||||
#include "zynqmp_kms.h"
|
||||
|
||||
static uint zynqmp_dp_aux_timeout_ms = 50;
|
||||
module_param_named(aux_timeout_ms, zynqmp_dp_aux_timeout_ms, uint, 0444);
|
||||
|
@ -1560,7 +1561,7 @@ static irqreturn_t zynqmp_dp_irq_handler(int irq, void *data)
|
|||
zynqmp_dp_write(dp, ZYNQMP_DP_INT_STATUS, status);
|
||||
|
||||
if (status & ZYNQMP_DP_INT_VBLANK_START)
|
||||
zynqmp_disp_handle_vblank(dp->dpsub->disp);
|
||||
zynqmp_dpsub_handle_vblank(dp->dpsub);
|
||||
|
||||
if (status & ZYNQMP_DP_INT_HPD_EVENT)
|
||||
schedule_delayed_work(&dp->hpd_work, 0);
|
||||
|
|
|
@ -9,17 +9,199 @@
|
|||
* - Laurent Pinchart <laurent.pinchart@ideasonboard.com>
|
||||
*/
|
||||
|
||||
#include <drm/drm_atomic.h>
|
||||
#include <drm/drm_atomic_helper.h>
|
||||
#include <drm/drm_bridge.h>
|
||||
#include <drm/drm_bridge_connector.h>
|
||||
#include <drm/drm_connector.h>
|
||||
#include <drm/drm_crtc.h>
|
||||
#include <drm/drm_encoder.h>
|
||||
#include <drm/drm_plane.h>
|
||||
#include <drm/drm_simple_kms_helper.h>
|
||||
#include <drm/drm_vblank.h>
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/spinlock.h>
|
||||
|
||||
#include "zynqmp_disp.h"
|
||||
#include "zynqmp_dp.h"
|
||||
#include "zynqmp_dpsub.h"
|
||||
#include "zynqmp_kms.h"
|
||||
|
||||
/* -----------------------------------------------------------------------------
|
||||
* DRM CRTC
|
||||
*/
|
||||
|
||||
static inline struct zynqmp_dpsub *crtc_to_dpsub(struct drm_crtc *crtc)
|
||||
{
|
||||
return container_of(crtc, struct zynqmp_dpsub, crtc);
|
||||
}
|
||||
|
||||
static void zynqmp_dpsub_crtc_atomic_enable(struct drm_crtc *crtc,
|
||||
struct drm_atomic_state *state)
|
||||
{
|
||||
struct zynqmp_dpsub *dpsub = crtc_to_dpsub(crtc);
|
||||
struct drm_display_mode *adjusted_mode = &crtc->state->adjusted_mode;
|
||||
int ret, vrefresh;
|
||||
|
||||
pm_runtime_get_sync(dpsub->dev);
|
||||
|
||||
zynqmp_disp_setup_clock(dpsub->disp, adjusted_mode->clock * 1000);
|
||||
|
||||
ret = clk_prepare_enable(dpsub->vid_clk);
|
||||
if (ret) {
|
||||
dev_err(dpsub->dev, "failed to enable a pixel clock\n");
|
||||
pm_runtime_put_sync(dpsub->dev);
|
||||
return;
|
||||
}
|
||||
|
||||
zynqmp_disp_enable(dpsub->disp);
|
||||
|
||||
/* Delay of 3 vblank intervals for timing gen to be stable */
|
||||
vrefresh = (adjusted_mode->clock * 1000) /
|
||||
(adjusted_mode->vtotal * adjusted_mode->htotal);
|
||||
msleep(3 * 1000 / vrefresh);
|
||||
}
|
||||
|
||||
static void zynqmp_dpsub_crtc_atomic_disable(struct drm_crtc *crtc,
|
||||
struct drm_atomic_state *state)
|
||||
{
|
||||
struct zynqmp_dpsub *dpsub = crtc_to_dpsub(crtc);
|
||||
struct drm_plane_state *old_plane_state;
|
||||
|
||||
/*
|
||||
* Disable the plane if active. The old plane state can be NULL in the
|
||||
* .shutdown() path if the plane is already disabled, skip
|
||||
* zynqmp_disp_plane_atomic_disable() in that case.
|
||||
*/
|
||||
old_plane_state = drm_atomic_get_old_plane_state(state, crtc->primary);
|
||||
if (old_plane_state)
|
||||
zynqmp_disp_plane_atomic_disable(crtc->primary, state);
|
||||
|
||||
zynqmp_disp_disable(dpsub->disp);
|
||||
|
||||
drm_crtc_vblank_off(crtc);
|
||||
|
||||
spin_lock_irq(&crtc->dev->event_lock);
|
||||
if (crtc->state->event) {
|
||||
drm_crtc_send_vblank_event(crtc, crtc->state->event);
|
||||
crtc->state->event = NULL;
|
||||
}
|
||||
spin_unlock_irq(&crtc->dev->event_lock);
|
||||
|
||||
clk_disable_unprepare(dpsub->vid_clk);
|
||||
pm_runtime_put_sync(dpsub->dev);
|
||||
}
|
||||
|
||||
static int zynqmp_dpsub_crtc_atomic_check(struct drm_crtc *crtc,
|
||||
struct drm_atomic_state *state)
|
||||
{
|
||||
return drm_atomic_add_affected_planes(state, crtc);
|
||||
}
|
||||
|
||||
static void zynqmp_dpsub_crtc_atomic_begin(struct drm_crtc *crtc,
|
||||
struct drm_atomic_state *state)
|
||||
{
|
||||
drm_crtc_vblank_on(crtc);
|
||||
}
|
||||
|
||||
static void zynqmp_dpsub_crtc_atomic_flush(struct drm_crtc *crtc,
|
||||
struct drm_atomic_state *state)
|
||||
{
|
||||
if (crtc->state->event) {
|
||||
struct drm_pending_vblank_event *event;
|
||||
|
||||
/* Consume the flip_done event from atomic helper. */
|
||||
event = crtc->state->event;
|
||||
crtc->state->event = NULL;
|
||||
|
||||
event->pipe = drm_crtc_index(crtc);
|
||||
|
||||
WARN_ON(drm_crtc_vblank_get(crtc) != 0);
|
||||
|
||||
spin_lock_irq(&crtc->dev->event_lock);
|
||||
drm_crtc_arm_vblank_event(crtc, event);
|
||||
spin_unlock_irq(&crtc->dev->event_lock);
|
||||
}
|
||||
}
|
||||
|
||||
static const struct drm_crtc_helper_funcs zynqmp_dpsub_crtc_helper_funcs = {
|
||||
.atomic_enable = zynqmp_dpsub_crtc_atomic_enable,
|
||||
.atomic_disable = zynqmp_dpsub_crtc_atomic_disable,
|
||||
.atomic_check = zynqmp_dpsub_crtc_atomic_check,
|
||||
.atomic_begin = zynqmp_dpsub_crtc_atomic_begin,
|
||||
.atomic_flush = zynqmp_dpsub_crtc_atomic_flush,
|
||||
};
|
||||
|
||||
static int zynqmp_dpsub_crtc_enable_vblank(struct drm_crtc *crtc)
|
||||
{
|
||||
struct zynqmp_dpsub *dpsub = crtc_to_dpsub(crtc);
|
||||
|
||||
zynqmp_dp_enable_vblank(dpsub->dp);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void zynqmp_dpsub_crtc_disable_vblank(struct drm_crtc *crtc)
|
||||
{
|
||||
struct zynqmp_dpsub *dpsub = crtc_to_dpsub(crtc);
|
||||
|
||||
zynqmp_dp_disable_vblank(dpsub->dp);
|
||||
}
|
||||
|
||||
static const struct drm_crtc_funcs zynqmp_dpsub_crtc_funcs = {
|
||||
.destroy = drm_crtc_cleanup,
|
||||
.set_config = drm_atomic_helper_set_config,
|
||||
.page_flip = drm_atomic_helper_page_flip,
|
||||
.reset = drm_atomic_helper_crtc_reset,
|
||||
.atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state,
|
||||
.atomic_destroy_state = drm_atomic_helper_crtc_destroy_state,
|
||||
.enable_vblank = zynqmp_dpsub_crtc_enable_vblank,
|
||||
.disable_vblank = zynqmp_dpsub_crtc_disable_vblank,
|
||||
};
|
||||
|
||||
static int zynqmp_dpsub_create_crtc(struct zynqmp_dpsub *dpsub)
|
||||
{
|
||||
struct drm_plane *plane = &dpsub->planes[ZYNQMP_DPSUB_LAYER_GFX];
|
||||
struct drm_crtc *crtc = &dpsub->crtc;
|
||||
int ret;
|
||||
|
||||
ret = drm_crtc_init_with_planes(&dpsub->drm, crtc, plane,
|
||||
NULL, &zynqmp_dpsub_crtc_funcs, NULL);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
drm_crtc_helper_add(crtc, &zynqmp_dpsub_crtc_helper_funcs);
|
||||
|
||||
/* Start with vertical blanking interrupt reporting disabled. */
|
||||
drm_crtc_vblank_off(crtc);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void zynqmp_dpsub_map_crtc_to_plane(struct zynqmp_dpsub *dpsub)
|
||||
{
|
||||
u32 possible_crtcs = drm_crtc_mask(&dpsub->crtc);
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(dpsub->planes); i++)
|
||||
dpsub->planes[i].possible_crtcs = possible_crtcs;
|
||||
}
|
||||
|
||||
/**
|
||||
* zynqmp_dpsub_handle_vblank - Handle the vblank event
|
||||
* @dpsub: DisplayPort subsystem
|
||||
*
|
||||
* This function handles the vblank interrupt, and sends an event to
|
||||
* CRTC object. This will be called by the DP vblank interrupt handler.
|
||||
*/
|
||||
void zynqmp_dpsub_handle_vblank(struct zynqmp_dpsub *dpsub)
|
||||
{
|
||||
drm_crtc_handle_vblank(&dpsub->crtc);
|
||||
}
|
||||
|
||||
/* -----------------------------------------------------------------------------
|
||||
* Initialization
|
||||
*/
|
||||
|
@ -38,12 +220,18 @@ int zynqmp_dpsub_kms_init(struct zynqmp_dpsub *dpsub)
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = zynqmp_dpsub_create_crtc(dpsub);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
zynqmp_dpsub_map_crtc_to_plane(dpsub);
|
||||
|
||||
ret = zynqmp_dp_drm_init(dpsub);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Create the encoder and attach the bridge. */
|
||||
encoder->possible_crtcs |= zynqmp_disp_get_crtc_mask(dpsub->disp);
|
||||
encoder->possible_crtcs |= drm_crtc_mask(&dpsub->crtc);
|
||||
drm_simple_encoder_init(&dpsub->drm, encoder, DRM_MODE_ENCODER_NONE);
|
||||
|
||||
ret = drm_bridge_attach(encoder, dpsub->bridge, NULL,
|
||||
|
|
|
@ -14,6 +14,8 @@
|
|||
|
||||
struct zynqmp_dpsub;
|
||||
|
||||
void zynqmp_dpsub_handle_vblank(struct zynqmp_dpsub *dpsub);
|
||||
|
||||
int zynqmp_dpsub_kms_init(struct zynqmp_dpsub *dpsub);
|
||||
|
||||
#endif /* _ZYNQMP_KMS_H_ */
|
||||
|
|
Loading…
Reference in a new issue