mirror of
https://github.com/torvalds/linux.git
synced 2024-12-23 03:11:46 +00:00
drm/vmwgfx: Add and connect CRTC helper functions
Atomic mode set requires us to refactor existing vmw_stdu_crtc_set_config code into sections that check the validity of the new mode, and sections that actually program the hardware state. vmw_du_crtc_atomic_check() takes CRTC-related checking code. In a later patch, vmw_du_primary_plane_atomic_check() will take framebuffer-related checking code. These helpers won't be called until we flip on the atomic support flag or set drm_crtc_funcs->set_config to using the atomic helper. v2: * The state->num_connector is actually the total number of potential connectors, not just the one associated with the display unit. The proper one to check is ->connector_mask. * Add the check to only allow plane state to be the same as crtc state (Thanks to mlankhorst) * Make sure to turn on SVGA mode before using VRAM. SVGA mode is disabled in master_drop if dbdev is not running. v3: * Moved dot clock override to crtc_atomic_check Signed-off-by: Sinclair Yeh <syeh@vmware.com> Signed-off-by: Thomas Hellstrom <thellstrom@vmware.com> Reviewed-by: Thomas Hellstrom <thellstrom@vmware.com> Acked-by: Daniel Vetter <daniel@ffwll.ch>
This commit is contained in:
parent
d7721ca711
commit
06ec41909e
@ -390,6 +390,61 @@ void vmw_du_primary_plane_destroy(struct drm_plane *plane)
|
||||
}
|
||||
|
||||
|
||||
int vmw_du_crtc_atomic_check(struct drm_crtc *crtc,
|
||||
struct drm_crtc_state *new_state)
|
||||
{
|
||||
struct vmw_display_unit *du = vmw_crtc_to_du(new_state->crtc);
|
||||
int connector_mask = 1 << drm_connector_index(&du->connector);
|
||||
bool has_primary = new_state->plane_mask &
|
||||
BIT(drm_plane_index(crtc->primary));
|
||||
|
||||
/* We always want to have an active plane with an active CRTC */
|
||||
if (has_primary != new_state->enable)
|
||||
return -EINVAL;
|
||||
|
||||
|
||||
if (new_state->connector_mask != connector_mask &&
|
||||
new_state->connector_mask != 0) {
|
||||
DRM_ERROR("Invalid connectors configuration\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Our virtual device does not have a dot clock, so use the logical
|
||||
* clock value as the dot clock.
|
||||
*/
|
||||
if (new_state->mode.crtc_clock == 0)
|
||||
new_state->adjusted_mode.crtc_clock = new_state->mode.clock;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void vmw_du_crtc_atomic_begin(struct drm_crtc *crtc,
|
||||
struct drm_crtc_state *old_crtc_state)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void vmw_du_crtc_atomic_flush(struct drm_crtc *crtc,
|
||||
struct drm_crtc_state *old_crtc_state)
|
||||
{
|
||||
struct drm_pending_vblank_event *event = crtc->state->event;
|
||||
|
||||
if (event) {
|
||||
crtc->state->event = NULL;
|
||||
|
||||
spin_lock_irq(&crtc->dev->event_lock);
|
||||
if (drm_crtc_vblank_get(crtc) == 0)
|
||||
drm_crtc_arm_vblank_event(crtc, event);
|
||||
else
|
||||
drm_crtc_send_vblank_event(crtc, event);
|
||||
spin_unlock_irq(&crtc->dev->event_lock);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* vmw_du_crtc_duplicate_state - duplicate crtc state
|
||||
* @crtc: DRM crtc
|
||||
|
@ -161,6 +161,7 @@ struct vmw_crtc_state {
|
||||
* @surf Display surface for STDU
|
||||
* @dmabuf display dmabuf for SOU
|
||||
* @content_fb_type Used by STDU.
|
||||
* @dmabuf_size Size of the dmabuf, used by Screen Object Display Unit
|
||||
* @pinned pin count for STDU display surface
|
||||
*/
|
||||
struct vmw_plane_state {
|
||||
@ -169,6 +170,7 @@ struct vmw_plane_state {
|
||||
struct vmw_dma_buffer *dmabuf;
|
||||
|
||||
int content_fb_type;
|
||||
unsigned long dmabuf_size;
|
||||
|
||||
int pinned;
|
||||
};
|
||||
@ -342,10 +344,17 @@ int vmw_du_cursor_plane_update(struct drm_plane *plane,
|
||||
uint32_t src_x, uint32_t src_y,
|
||||
uint32_t src_w, uint32_t src_h);
|
||||
|
||||
/* Atomic Helpers */
|
||||
void vmw_du_plane_reset(struct drm_plane *plane);
|
||||
struct drm_plane_state *vmw_du_plane_duplicate_state(struct drm_plane *plane);
|
||||
void vmw_du_plane_destroy_state(struct drm_plane *plane,
|
||||
struct drm_plane_state *state);
|
||||
int vmw_du_crtc_atomic_check(struct drm_crtc *crtc,
|
||||
struct drm_crtc_state *state);
|
||||
void vmw_du_crtc_atomic_begin(struct drm_crtc *crtc,
|
||||
struct drm_crtc_state *old_crtc_state);
|
||||
void vmw_du_crtc_atomic_flush(struct drm_crtc *crtc,
|
||||
struct drm_crtc_state *old_crtc_state);
|
||||
void vmw_du_crtc_reset(struct drm_crtc *crtc);
|
||||
struct drm_crtc_state *vmw_du_crtc_duplicate_state(struct drm_crtc *crtc);
|
||||
void vmw_du_crtc_destroy_state(struct drm_crtc *crtc,
|
||||
|
@ -167,6 +167,7 @@ static int vmw_ldu_add_active(struct vmw_private *vmw_priv,
|
||||
if (vfb != ld->fb) {
|
||||
if (ld->fb && ld->fb->unpin)
|
||||
ld->fb->unpin(ld->fb);
|
||||
vmw_svga_enable(vmw_priv);
|
||||
if (vfb->pin)
|
||||
vfb->pin(vfb);
|
||||
ld->fb = vfb;
|
||||
@ -190,6 +191,68 @@ static int vmw_ldu_add_active(struct vmw_private *vmw_priv,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* vmw_ldu_crtc_mode_set_nofb - Enable svga
|
||||
*
|
||||
* @crtc: CRTC associated with the new screen
|
||||
*
|
||||
* For LDU, just enable the svga
|
||||
*/
|
||||
static void vmw_ldu_crtc_mode_set_nofb(struct drm_crtc *crtc)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* vmw_ldu_crtc_helper_prepare - Noop
|
||||
*
|
||||
* @crtc: CRTC associated with the new screen
|
||||
*
|
||||
* Prepares the CRTC for a mode set, but we don't need to do anything here.
|
||||
*
|
||||
*/
|
||||
static void vmw_ldu_crtc_helper_prepare(struct drm_crtc *crtc)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* vmw_ldu_crtc_helper_commit - Noop
|
||||
*
|
||||
* @crtc: CRTC associated with the new screen
|
||||
*
|
||||
* This is called after a mode set has been completed. Here's
|
||||
* usually a good place to call vmw_ldu_add_active/vmw_ldu_del_active
|
||||
* but since for LDU the display plane is closely tied to the
|
||||
* CRTC, it makes more sense to do those at plane update time.
|
||||
*/
|
||||
static void vmw_ldu_crtc_helper_commit(struct drm_crtc *crtc)
|
||||
{
|
||||
struct vmw_private *dev_priv;
|
||||
struct vmw_legacy_display_unit *ldu;
|
||||
struct vmw_framebuffer *vfb;
|
||||
struct drm_framebuffer *fb;
|
||||
|
||||
|
||||
ldu = vmw_crtc_to_ldu(crtc);
|
||||
dev_priv = vmw_priv(crtc->dev);
|
||||
fb = crtc->primary->fb;
|
||||
|
||||
vfb = (fb) ? vmw_framebuffer_to_vfb(fb) : NULL;
|
||||
|
||||
if (vfb)
|
||||
vmw_ldu_add_active(dev_priv, ldu, vfb);
|
||||
else
|
||||
vmw_ldu_del_active(dev_priv, ldu);
|
||||
}
|
||||
|
||||
/**
|
||||
* vmw_ldu_crtc_helper_disable - Turns off CRTC
|
||||
*
|
||||
* @crtc: CRTC to be turned off
|
||||
*/
|
||||
static void vmw_ldu_crtc_helper_disable(struct drm_crtc *crtc)
|
||||
{
|
||||
}
|
||||
|
||||
static int vmw_ldu_crtc_set_config(struct drm_mode_set *set)
|
||||
{
|
||||
struct vmw_private *dev_priv;
|
||||
@ -346,6 +409,20 @@ static const struct drm_plane_funcs vmw_ldu_cursor_funcs = {
|
||||
.atomic_destroy_state = vmw_du_plane_destroy_state,
|
||||
};
|
||||
|
||||
/*
|
||||
* Atomic Helpers
|
||||
*/
|
||||
static const struct drm_crtc_helper_funcs vmw_ldu_crtc_helper_funcs = {
|
||||
.prepare = vmw_ldu_crtc_helper_prepare,
|
||||
.commit = vmw_ldu_crtc_helper_commit,
|
||||
.disable = vmw_ldu_crtc_helper_disable,
|
||||
.mode_set = drm_helper_crtc_mode_set,
|
||||
.mode_set_nofb = vmw_ldu_crtc_mode_set_nofb,
|
||||
.atomic_check = vmw_du_crtc_atomic_check,
|
||||
.atomic_begin = vmw_du_crtc_atomic_begin,
|
||||
.atomic_flush = vmw_du_crtc_atomic_flush,
|
||||
};
|
||||
|
||||
|
||||
static int vmw_ldu_init(struct vmw_private *dev_priv, unsigned unit)
|
||||
{
|
||||
@ -445,6 +522,8 @@ static int vmw_ldu_init(struct vmw_private *dev_priv, unsigned unit)
|
||||
goto err_free_unregister;
|
||||
}
|
||||
|
||||
drm_crtc_helper_add(crtc, &vmw_ldu_crtc_helper_funcs);
|
||||
|
||||
drm_mode_crtc_set_gamma_size(crtc, 256);
|
||||
|
||||
drm_object_attach_property(&connector->base,
|
||||
|
@ -250,6 +250,109 @@ static int vmw_sou_backing_alloc(struct vmw_private *dev_priv,
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* vmw_sou_crtc_mode_set_nofb - Create new screen
|
||||
*
|
||||
* @crtc: CRTC associated with the new screen
|
||||
*
|
||||
* This function creates/destroys a screen. This function cannot fail, so if
|
||||
* somehow we run into a failure, just do the best we can to get out.
|
||||
*/
|
||||
static void vmw_sou_crtc_mode_set_nofb(struct drm_crtc *crtc)
|
||||
{
|
||||
struct vmw_private *dev_priv;
|
||||
struct vmw_screen_object_unit *sou;
|
||||
struct vmw_framebuffer *vfb;
|
||||
struct drm_framebuffer *fb;
|
||||
struct drm_plane_state *ps;
|
||||
struct vmw_plane_state *vps;
|
||||
int ret;
|
||||
|
||||
|
||||
sou = vmw_crtc_to_sou(crtc);
|
||||
dev_priv = vmw_priv(crtc->dev);
|
||||
ps = crtc->primary->state;
|
||||
fb = ps->fb;
|
||||
vps = vmw_plane_state_to_vps(ps);
|
||||
|
||||
vfb = (fb) ? vmw_framebuffer_to_vfb(fb) : NULL;
|
||||
|
||||
if (sou->defined) {
|
||||
ret = vmw_sou_fifo_destroy(dev_priv, sou);
|
||||
if (ret) {
|
||||
DRM_ERROR("Failed to destroy Screen Object\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (vfb) {
|
||||
sou->buffer = vps->dmabuf;
|
||||
sou->buffer_size = vps->dmabuf_size;
|
||||
|
||||
ret = vmw_sou_fifo_create(dev_priv, sou, crtc->x, crtc->y,
|
||||
&crtc->mode);
|
||||
if (ret)
|
||||
DRM_ERROR("Failed to define Screen Object %dx%d\n",
|
||||
crtc->x, crtc->y);
|
||||
|
||||
vmw_kms_add_active(dev_priv, &sou->base, vfb);
|
||||
} else {
|
||||
sou->buffer = NULL;
|
||||
sou->buffer_size = 0;
|
||||
|
||||
vmw_kms_del_active(dev_priv, &sou->base);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* vmw_sou_crtc_helper_prepare - Noop
|
||||
*
|
||||
* @crtc: CRTC associated with the new screen
|
||||
*
|
||||
* Prepares the CRTC for a mode set, but we don't need to do anything here.
|
||||
*/
|
||||
static void vmw_sou_crtc_helper_prepare(struct drm_crtc *crtc)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* vmw_sou_crtc_helper_commit - Noop
|
||||
*
|
||||
* @crtc: CRTC associated with the new screen
|
||||
*
|
||||
* This is called after a mode set has been completed.
|
||||
*/
|
||||
static void vmw_sou_crtc_helper_commit(struct drm_crtc *crtc)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* vmw_sou_crtc_helper_disable - Turns off CRTC
|
||||
*
|
||||
* @crtc: CRTC to be turned off
|
||||
*/
|
||||
static void vmw_sou_crtc_helper_disable(struct drm_crtc *crtc)
|
||||
{
|
||||
struct vmw_private *dev_priv;
|
||||
struct vmw_screen_object_unit *sou;
|
||||
int ret;
|
||||
|
||||
|
||||
if (!crtc) {
|
||||
DRM_ERROR("CRTC is NULL\n");
|
||||
return;
|
||||
}
|
||||
|
||||
sou = vmw_crtc_to_sou(crtc);
|
||||
dev_priv = vmw_priv(crtc->dev);
|
||||
|
||||
if (sou->defined) {
|
||||
ret = vmw_sou_fifo_destroy(dev_priv, sou);
|
||||
if (ret)
|
||||
DRM_ERROR("Failed to destroy Screen Object\n");
|
||||
}
|
||||
}
|
||||
|
||||
static int vmw_sou_crtc_set_config(struct drm_mode_set *set)
|
||||
{
|
||||
struct vmw_private *dev_priv;
|
||||
@ -527,6 +630,20 @@ static const struct drm_plane_funcs vmw_sou_cursor_funcs = {
|
||||
.atomic_destroy_state = vmw_du_plane_destroy_state,
|
||||
};
|
||||
|
||||
/*
|
||||
* Atomic Helpers
|
||||
*/
|
||||
static const struct drm_crtc_helper_funcs vmw_sou_crtc_helper_funcs = {
|
||||
.prepare = vmw_sou_crtc_helper_prepare,
|
||||
.commit = vmw_sou_crtc_helper_commit,
|
||||
.disable = vmw_sou_crtc_helper_disable,
|
||||
.mode_set = drm_helper_crtc_mode_set,
|
||||
.mode_set_nofb = vmw_sou_crtc_mode_set_nofb,
|
||||
.atomic_check = vmw_du_crtc_atomic_check,
|
||||
.atomic_begin = vmw_du_crtc_atomic_begin,
|
||||
.atomic_flush = vmw_du_crtc_atomic_flush,
|
||||
};
|
||||
|
||||
|
||||
static int vmw_sou_init(struct vmw_private *dev_priv, unsigned unit)
|
||||
{
|
||||
@ -626,6 +743,8 @@ static int vmw_sou_init(struct vmw_private *dev_priv, unsigned unit)
|
||||
goto err_free_unregister;
|
||||
}
|
||||
|
||||
drm_crtc_helper_add(crtc, &vmw_sou_crtc_helper_funcs);
|
||||
|
||||
drm_mode_crtc_set_gamma_size(crtc, 256);
|
||||
|
||||
drm_object_attach_property(&connector->base,
|
||||
|
@ -500,6 +500,106 @@ out_srf_unref:
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* vmw_stdu_crtc_mode_set_nofb - Updates screen target size
|
||||
*
|
||||
* @crtc: CRTC associated with the screen target
|
||||
*
|
||||
* This function defines/destroys a screen target
|
||||
*
|
||||
*/
|
||||
static void vmw_stdu_crtc_mode_set_nofb(struct drm_crtc *crtc)
|
||||
{
|
||||
struct vmw_private *dev_priv;
|
||||
struct vmw_screen_target_display_unit *stdu;
|
||||
int ret;
|
||||
|
||||
|
||||
stdu = vmw_crtc_to_stdu(crtc);
|
||||
dev_priv = vmw_priv(crtc->dev);
|
||||
|
||||
if (stdu->defined) {
|
||||
ret = vmw_stdu_bind_st(dev_priv, stdu, NULL);
|
||||
if (ret)
|
||||
DRM_ERROR("Failed to blank CRTC\n");
|
||||
|
||||
(void) vmw_stdu_update_st(dev_priv, stdu);
|
||||
|
||||
ret = vmw_stdu_destroy_st(dev_priv, stdu);
|
||||
if (ret)
|
||||
DRM_ERROR("Failed to destroy Screen Target\n");
|
||||
|
||||
stdu->content_fb_type = SAME_AS_DISPLAY;
|
||||
}
|
||||
|
||||
if (!crtc->state->enable)
|
||||
return;
|
||||
|
||||
vmw_svga_enable(dev_priv);
|
||||
ret = vmw_stdu_define_st(dev_priv, stdu, &crtc->mode, crtc->x, crtc->y);
|
||||
|
||||
if (ret)
|
||||
DRM_ERROR("Failed to define Screen Target of size %dx%d\n",
|
||||
crtc->x, crtc->y);
|
||||
}
|
||||
|
||||
|
||||
static void vmw_stdu_crtc_helper_prepare(struct drm_crtc *crtc)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
static void vmw_stdu_crtc_helper_commit(struct drm_crtc *crtc)
|
||||
{
|
||||
struct vmw_private *dev_priv;
|
||||
struct vmw_screen_target_display_unit *stdu;
|
||||
struct vmw_framebuffer *vfb;
|
||||
struct drm_framebuffer *fb;
|
||||
|
||||
|
||||
stdu = vmw_crtc_to_stdu(crtc);
|
||||
dev_priv = vmw_priv(crtc->dev);
|
||||
fb = crtc->primary->fb;
|
||||
|
||||
vfb = (fb) ? vmw_framebuffer_to_vfb(fb) : NULL;
|
||||
|
||||
if (vfb)
|
||||
vmw_kms_add_active(dev_priv, &stdu->base, vfb);
|
||||
else
|
||||
vmw_kms_del_active(dev_priv, &stdu->base);
|
||||
}
|
||||
|
||||
static void vmw_stdu_crtc_helper_disable(struct drm_crtc *crtc)
|
||||
{
|
||||
struct vmw_private *dev_priv;
|
||||
struct vmw_screen_target_display_unit *stdu;
|
||||
int ret;
|
||||
|
||||
|
||||
if (!crtc) {
|
||||
DRM_ERROR("CRTC is NULL\n");
|
||||
return;
|
||||
}
|
||||
|
||||
stdu = vmw_crtc_to_stdu(crtc);
|
||||
dev_priv = vmw_priv(crtc->dev);
|
||||
|
||||
if (stdu->defined) {
|
||||
ret = vmw_stdu_bind_st(dev_priv, stdu, NULL);
|
||||
if (ret)
|
||||
DRM_ERROR("Failed to blank CRTC\n");
|
||||
|
||||
(void) vmw_stdu_update_st(dev_priv, stdu);
|
||||
|
||||
ret = vmw_stdu_destroy_st(dev_priv, stdu);
|
||||
if (ret)
|
||||
DRM_ERROR("Failed to destroy Screen Target\n");
|
||||
|
||||
stdu->content_fb_type = SAME_AS_DISPLAY;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* vmw_stdu_crtc_set_config - Sets a mode
|
||||
*
|
||||
@ -1113,6 +1213,21 @@ static const struct drm_plane_funcs vmw_stdu_cursor_funcs = {
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* Atomic Helpers
|
||||
*/
|
||||
static const struct drm_crtc_helper_funcs vmw_stdu_crtc_helper_funcs = {
|
||||
.prepare = vmw_stdu_crtc_helper_prepare,
|
||||
.commit = vmw_stdu_crtc_helper_commit,
|
||||
.disable = vmw_stdu_crtc_helper_disable,
|
||||
.mode_set = drm_helper_crtc_mode_set,
|
||||
.mode_set_nofb = vmw_stdu_crtc_mode_set_nofb,
|
||||
.atomic_check = vmw_du_crtc_atomic_check,
|
||||
.atomic_begin = vmw_du_crtc_atomic_begin,
|
||||
.atomic_flush = vmw_du_crtc_atomic_flush,
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* vmw_stdu_init - Sets up a Screen Target Display Unit
|
||||
*
|
||||
@ -1219,6 +1334,8 @@ static int vmw_stdu_init(struct vmw_private *dev_priv, unsigned unit)
|
||||
goto err_free_unregister;
|
||||
}
|
||||
|
||||
drm_crtc_helper_add(crtc, &vmw_stdu_crtc_helper_funcs);
|
||||
|
||||
drm_mode_crtc_set_gamma_size(crtc, 256);
|
||||
|
||||
drm_object_attach_property(&connector->base,
|
||||
|
Loading…
Reference in New Issue
Block a user