You've already forked linux-apfs
mirror of
https://github.com/linux-apfs/linux-apfs.git
synced 2026-05-01 15:00:59 -07:00
Merge branch 'drm/next/atomic' of git://linuxtv.org/pinchartl/fbdev into drm-next
rcar-du atomic modesetting support * 'drm/next/atomic' of git://linuxtv.org/pinchartl/fbdev: (32 commits) drm: rcar-du: Fix race condition in hardware plane allocator drm: rcar-du: Move group locking inside rcar_du_crtc_update_planes() drm: rcar-du: Move plane commit code from CRTC start to CRTC resume drm: rcar-du: Move plane format to plane state drm: rcar-du: Remove unneeded rcar_du_crtc plane field drm: rcar-du: Replace plane crtc and enabled fields by plane state drm: rcar-du: Rework plane setup code drm: rcar-du: Switch plane set_property to atomic helpers drm: rcar-du: Switch page flip to atomic helpers drm: rcar-du: Implement asynchronous commit support drm: rcar-du: Replace encoder mode_fixup with atomic_check drm: rcar-du: Switch connector DPMS to atomic helpers drm: rcar-du: Switch mode config to atomic helpers drm: rcar-du: Switch plane update to atomic helpers drm: rcar-du: Rework CRTC enable/disable for atomic updates drm: rcar-du: Rework HDMI encoder enable/disable for atomic updates drm: rcar-du: Rework encoder enable/disable for atomic updates drm: rcar-du: Replace LVDS encoder DPMS by enable/disable drm: rcar-du: Remove private copy of plane size and position drm: rcar-du: Wire up atomic state object scaffolding ...
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -15,12 +15,12 @@
|
||||
#define __RCAR_DU_CRTC_H__
|
||||
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/wait.h>
|
||||
|
||||
#include <drm/drmP.h>
|
||||
#include <drm/drm_crtc.h>
|
||||
|
||||
struct rcar_du_group;
|
||||
struct rcar_du_plane;
|
||||
|
||||
struct rcar_du_crtc {
|
||||
struct drm_crtc crtc;
|
||||
@@ -32,11 +32,12 @@ struct rcar_du_crtc {
|
||||
bool started;
|
||||
|
||||
struct drm_pending_vblank_event *event;
|
||||
wait_queue_head_t flip_wait;
|
||||
|
||||
unsigned int outputs;
|
||||
int dpms;
|
||||
bool enabled;
|
||||
|
||||
struct rcar_du_group *group;
|
||||
struct rcar_du_plane *plane;
|
||||
};
|
||||
|
||||
#define to_rcar_crtc(c) container_of(c, struct rcar_du_crtc, crtc)
|
||||
@@ -59,6 +60,5 @@ void rcar_du_crtc_resume(struct rcar_du_crtc *rcrtc);
|
||||
|
||||
void rcar_du_crtc_route_output(struct drm_crtc *crtc,
|
||||
enum rcar_du_output output);
|
||||
void rcar_du_crtc_update_planes(struct drm_crtc *crtc);
|
||||
|
||||
#endif /* __RCAR_DU_CRTC_H__ */
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/pm.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/wait.h>
|
||||
|
||||
#include <drm/drmP.h>
|
||||
#include <drm/drm_crtc_helper.h>
|
||||
@@ -163,6 +164,8 @@ static int rcar_du_load(struct drm_device *dev, unsigned long flags)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
init_waitqueue_head(&rcdu->commit.wait);
|
||||
|
||||
rcdu->dev = &pdev->dev;
|
||||
rcdu->info = np ? of_match_device(rcar_du_of_table, rcdu->dev)->data
|
||||
: (void *)platform_get_device_id(pdev)->driver_data;
|
||||
@@ -175,6 +178,15 @@ static int rcar_du_load(struct drm_device *dev, unsigned long flags)
|
||||
if (IS_ERR(rcdu->mmio))
|
||||
return PTR_ERR(rcdu->mmio);
|
||||
|
||||
/* Initialize vertical blanking interrupts handling. Start with vblank
|
||||
* disabled for all CRTCs.
|
||||
*/
|
||||
ret = drm_vblank_init(dev, (1 << rcdu->info->num_crtcs) - 1);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "failed to initialize vblank\n");
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* DRM/KMS objects */
|
||||
ret = rcar_du_modeset_init(rcdu);
|
||||
if (ret < 0) {
|
||||
@@ -182,13 +194,6 @@ static int rcar_du_load(struct drm_device *dev, unsigned long flags)
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* vblank handling */
|
||||
ret = drm_vblank_init(dev, (1 << rcdu->num_crtcs) - 1);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "failed to initialize vblank\n");
|
||||
goto done;
|
||||
}
|
||||
|
||||
dev->irq_enabled = 1;
|
||||
|
||||
platform_set_drvdata(pdev, rcdu);
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
#define __RCAR_DU_DRV_H__
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/wait.h>
|
||||
|
||||
#include "rcar_du_crtc.h"
|
||||
#include "rcar_du_group.h"
|
||||
@@ -64,6 +65,10 @@ struct rcar_du_device_info {
|
||||
unsigned int num_lvds;
|
||||
};
|
||||
|
||||
#define RCAR_DU_MAX_CRTCS 3
|
||||
#define RCAR_DU_MAX_GROUPS DIV_ROUND_UP(RCAR_DU_MAX_CRTCS, 2)
|
||||
#define RCAR_DU_MAX_LVDS 2
|
||||
|
||||
struct rcar_du_device {
|
||||
struct device *dev;
|
||||
const struct rcar_du_device_info *info;
|
||||
@@ -73,13 +78,18 @@ struct rcar_du_device {
|
||||
struct drm_device *ddev;
|
||||
struct drm_fbdev_cma *fbdev;
|
||||
|
||||
struct rcar_du_crtc crtcs[3];
|
||||
struct rcar_du_crtc crtcs[RCAR_DU_MAX_CRTCS];
|
||||
unsigned int num_crtcs;
|
||||
|
||||
struct rcar_du_group groups[2];
|
||||
struct rcar_du_group groups[RCAR_DU_MAX_GROUPS];
|
||||
|
||||
unsigned int dpad0_source;
|
||||
struct rcar_du_lvdsenc *lvds[2];
|
||||
struct rcar_du_lvdsenc *lvds[RCAR_DU_MAX_LVDS];
|
||||
|
||||
struct {
|
||||
wait_queue_head_t wait;
|
||||
u32 pending;
|
||||
} commit;
|
||||
};
|
||||
|
||||
static inline bool rcar_du_has(struct rcar_du_device *rcdu,
|
||||
|
||||
@@ -42,46 +42,40 @@ rcar_du_connector_best_encoder(struct drm_connector *connector)
|
||||
* Encoder
|
||||
*/
|
||||
|
||||
static void rcar_du_encoder_dpms(struct drm_encoder *encoder, int mode)
|
||||
static void rcar_du_encoder_disable(struct drm_encoder *encoder)
|
||||
{
|
||||
struct rcar_du_encoder *renc = to_rcar_encoder(encoder);
|
||||
|
||||
if (mode != DRM_MODE_DPMS_ON)
|
||||
mode = DRM_MODE_DPMS_OFF;
|
||||
|
||||
if (renc->lvds)
|
||||
rcar_du_lvdsenc_dpms(renc->lvds, encoder->crtc, mode);
|
||||
rcar_du_lvdsenc_enable(renc->lvds, encoder->crtc, false);
|
||||
}
|
||||
|
||||
static bool rcar_du_encoder_mode_fixup(struct drm_encoder *encoder,
|
||||
const struct drm_display_mode *mode,
|
||||
struct drm_display_mode *adjusted_mode)
|
||||
static void rcar_du_encoder_enable(struct drm_encoder *encoder)
|
||||
{
|
||||
struct rcar_du_encoder *renc = to_rcar_encoder(encoder);
|
||||
|
||||
if (renc->lvds)
|
||||
rcar_du_lvdsenc_enable(renc->lvds, encoder->crtc, true);
|
||||
}
|
||||
|
||||
static int rcar_du_encoder_atomic_check(struct drm_encoder *encoder,
|
||||
struct drm_crtc_state *crtc_state,
|
||||
struct drm_connector_state *conn_state)
|
||||
{
|
||||
struct rcar_du_encoder *renc = to_rcar_encoder(encoder);
|
||||
struct drm_display_mode *adjusted_mode = &crtc_state->adjusted_mode;
|
||||
const struct drm_display_mode *mode = &crtc_state->mode;
|
||||
const struct drm_display_mode *panel_mode;
|
||||
struct drm_connector *connector = conn_state->connector;
|
||||
struct drm_device *dev = encoder->dev;
|
||||
struct drm_connector *connector;
|
||||
bool found = false;
|
||||
|
||||
/* DAC encoders have currently no restriction on the mode. */
|
||||
if (encoder->encoder_type == DRM_MODE_ENCODER_DAC)
|
||||
return true;
|
||||
|
||||
list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
|
||||
if (connector->encoder == encoder) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
dev_dbg(dev->dev, "mode_fixup: no connector found\n");
|
||||
return false;
|
||||
}
|
||||
return 0;
|
||||
|
||||
if (list_empty(&connector->modes)) {
|
||||
dev_dbg(dev->dev, "mode_fixup: empty modes list\n");
|
||||
return false;
|
||||
dev_dbg(dev->dev, "encoder: empty modes list\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
panel_mode = list_first_entry(&connector->modes,
|
||||
@@ -90,7 +84,7 @@ static bool rcar_du_encoder_mode_fixup(struct drm_encoder *encoder,
|
||||
/* We're not allowed to modify the resolution. */
|
||||
if (mode->hdisplay != panel_mode->hdisplay ||
|
||||
mode->vdisplay != panel_mode->vdisplay)
|
||||
return false;
|
||||
return -EINVAL;
|
||||
|
||||
/* The flat panel mode is fixed, just copy it to the adjusted mode. */
|
||||
drm_mode_copy(adjusted_mode, panel_mode);
|
||||
@@ -102,25 +96,7 @@ static bool rcar_du_encoder_mode_fixup(struct drm_encoder *encoder,
|
||||
adjusted_mode->clock = clamp(adjusted_mode->clock,
|
||||
30000, 150000);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void rcar_du_encoder_mode_prepare(struct drm_encoder *encoder)
|
||||
{
|
||||
struct rcar_du_encoder *renc = to_rcar_encoder(encoder);
|
||||
|
||||
if (renc->lvds)
|
||||
rcar_du_lvdsenc_dpms(renc->lvds, encoder->crtc,
|
||||
DRM_MODE_DPMS_OFF);
|
||||
}
|
||||
|
||||
static void rcar_du_encoder_mode_commit(struct drm_encoder *encoder)
|
||||
{
|
||||
struct rcar_du_encoder *renc = to_rcar_encoder(encoder);
|
||||
|
||||
if (renc->lvds)
|
||||
rcar_du_lvdsenc_dpms(renc->lvds, encoder->crtc,
|
||||
DRM_MODE_DPMS_ON);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void rcar_du_encoder_mode_set(struct drm_encoder *encoder,
|
||||
@@ -133,11 +109,10 @@ static void rcar_du_encoder_mode_set(struct drm_encoder *encoder,
|
||||
}
|
||||
|
||||
static const struct drm_encoder_helper_funcs encoder_helper_funcs = {
|
||||
.dpms = rcar_du_encoder_dpms,
|
||||
.mode_fixup = rcar_du_encoder_mode_fixup,
|
||||
.prepare = rcar_du_encoder_mode_prepare,
|
||||
.commit = rcar_du_encoder_mode_commit,
|
||||
.mode_set = rcar_du_encoder_mode_set,
|
||||
.disable = rcar_du_encoder_disable,
|
||||
.enable = rcar_du_encoder_enable,
|
||||
.atomic_check = rcar_du_encoder_atomic_check,
|
||||
};
|
||||
|
||||
static const struct drm_encoder_funcs encoder_funcs = {
|
||||
|
||||
@@ -14,6 +14,8 @@
|
||||
#ifndef __RCAR_DU_GROUP_H__
|
||||
#define __RCAR_DU_GROUP_H__
|
||||
|
||||
#include <linux/mutex.h>
|
||||
|
||||
#include "rcar_du_plane.h"
|
||||
|
||||
struct rcar_du_device;
|
||||
@@ -25,6 +27,7 @@ struct rcar_du_device;
|
||||
* @index: group index
|
||||
* @use_count: number of users of the group (rcar_du_group_(get|put))
|
||||
* @used_crtcs: number of CRTCs currently in use
|
||||
* @lock: protects the DPTSR register
|
||||
* @planes: planes handled by the group
|
||||
*/
|
||||
struct rcar_du_group {
|
||||
@@ -35,6 +38,8 @@ struct rcar_du_group {
|
||||
unsigned int use_count;
|
||||
unsigned int used_crtcs;
|
||||
|
||||
struct mutex lock;
|
||||
|
||||
struct rcar_du_planes planes;
|
||||
};
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
*/
|
||||
|
||||
#include <drm/drmP.h>
|
||||
#include <drm/drm_atomic_helper.h>
|
||||
#include <drm/drm_crtc.h>
|
||||
#include <drm/drm_crtc_helper.h>
|
||||
#include <drm/drm_encoder_slave.h>
|
||||
@@ -74,10 +75,13 @@ rcar_du_hdmi_connector_detect(struct drm_connector *connector, bool force)
|
||||
}
|
||||
|
||||
static const struct drm_connector_funcs connector_funcs = {
|
||||
.dpms = drm_helper_connector_dpms,
|
||||
.dpms = drm_atomic_helper_connector_dpms,
|
||||
.reset = drm_atomic_helper_connector_reset,
|
||||
.detect = rcar_du_hdmi_connector_detect,
|
||||
.fill_modes = drm_helper_probe_single_connector_modes,
|
||||
.destroy = rcar_du_hdmi_connector_destroy,
|
||||
.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
|
||||
.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
|
||||
};
|
||||
|
||||
int rcar_du_hdmi_connector_init(struct rcar_du_device *rcdu,
|
||||
@@ -108,7 +112,7 @@ int rcar_du_hdmi_connector_init(struct rcar_du_device *rcdu,
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
drm_helper_connector_dpms(connector, DRM_MODE_DPMS_OFF);
|
||||
connector->dpms = DRM_MODE_DPMS_OFF;
|
||||
drm_object_property_set_value(&connector->base,
|
||||
rcdu->ddev->mode_config.dpms_property, DRM_MODE_DPMS_OFF);
|
||||
|
||||
@@ -116,7 +120,6 @@ int rcar_du_hdmi_connector_init(struct rcar_du_device *rcdu,
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
connector->encoder = encoder;
|
||||
rcon->encoder = renc;
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -26,42 +26,51 @@
|
||||
struct rcar_du_hdmienc {
|
||||
struct rcar_du_encoder *renc;
|
||||
struct device *dev;
|
||||
int dpms;
|
||||
bool enabled;
|
||||
};
|
||||
|
||||
#define to_rcar_hdmienc(e) (to_rcar_encoder(e)->hdmi)
|
||||
#define to_slave_funcs(e) (to_rcar_encoder(e)->slave.slave_funcs)
|
||||
|
||||
static void rcar_du_hdmienc_dpms(struct drm_encoder *encoder, int mode)
|
||||
static void rcar_du_hdmienc_disable(struct drm_encoder *encoder)
|
||||
{
|
||||
struct rcar_du_hdmienc *hdmienc = to_rcar_hdmienc(encoder);
|
||||
struct drm_encoder_slave_funcs *sfuncs = to_slave_funcs(encoder);
|
||||
|
||||
if (mode != DRM_MODE_DPMS_ON)
|
||||
mode = DRM_MODE_DPMS_OFF;
|
||||
|
||||
if (hdmienc->dpms == mode)
|
||||
return;
|
||||
|
||||
if (mode == DRM_MODE_DPMS_ON && hdmienc->renc->lvds)
|
||||
rcar_du_lvdsenc_dpms(hdmienc->renc->lvds, encoder->crtc, mode);
|
||||
|
||||
if (sfuncs->dpms)
|
||||
sfuncs->dpms(encoder, mode);
|
||||
sfuncs->dpms(encoder, DRM_MODE_DPMS_OFF);
|
||||
|
||||
if (mode != DRM_MODE_DPMS_ON && hdmienc->renc->lvds)
|
||||
rcar_du_lvdsenc_dpms(hdmienc->renc->lvds, encoder->crtc, mode);
|
||||
if (hdmienc->renc->lvds)
|
||||
rcar_du_lvdsenc_enable(hdmienc->renc->lvds, encoder->crtc,
|
||||
false);
|
||||
|
||||
hdmienc->dpms = mode;
|
||||
hdmienc->enabled = false;
|
||||
}
|
||||
|
||||
static bool rcar_du_hdmienc_mode_fixup(struct drm_encoder *encoder,
|
||||
const struct drm_display_mode *mode,
|
||||
struct drm_display_mode *adjusted_mode)
|
||||
static void rcar_du_hdmienc_enable(struct drm_encoder *encoder)
|
||||
{
|
||||
struct rcar_du_hdmienc *hdmienc = to_rcar_hdmienc(encoder);
|
||||
struct drm_encoder_slave_funcs *sfuncs = to_slave_funcs(encoder);
|
||||
|
||||
if (hdmienc->renc->lvds)
|
||||
rcar_du_lvdsenc_enable(hdmienc->renc->lvds, encoder->crtc,
|
||||
true);
|
||||
|
||||
if (sfuncs->dpms)
|
||||
sfuncs->dpms(encoder, DRM_MODE_DPMS_ON);
|
||||
|
||||
hdmienc->enabled = true;
|
||||
}
|
||||
|
||||
static int rcar_du_hdmienc_atomic_check(struct drm_encoder *encoder,
|
||||
struct drm_crtc_state *crtc_state,
|
||||
struct drm_connector_state *conn_state)
|
||||
{
|
||||
struct rcar_du_hdmienc *hdmienc = to_rcar_hdmienc(encoder);
|
||||
struct drm_encoder_slave_funcs *sfuncs = to_slave_funcs(encoder);
|
||||
struct drm_display_mode *adjusted_mode = &crtc_state->adjusted_mode;
|
||||
const struct drm_display_mode *mode = &crtc_state->mode;
|
||||
|
||||
/* The internal LVDS encoder has a clock frequency operating range of
|
||||
* 30MHz to 150MHz. Clamp the clock accordingly.
|
||||
*/
|
||||
@@ -70,19 +79,9 @@ static bool rcar_du_hdmienc_mode_fixup(struct drm_encoder *encoder,
|
||||
30000, 150000);
|
||||
|
||||
if (sfuncs->mode_fixup == NULL)
|
||||
return true;
|
||||
return 0;
|
||||
|
||||
return sfuncs->mode_fixup(encoder, mode, adjusted_mode);
|
||||
}
|
||||
|
||||
static void rcar_du_hdmienc_mode_prepare(struct drm_encoder *encoder)
|
||||
{
|
||||
rcar_du_hdmienc_dpms(encoder, DRM_MODE_DPMS_OFF);
|
||||
}
|
||||
|
||||
static void rcar_du_hdmienc_mode_commit(struct drm_encoder *encoder)
|
||||
{
|
||||
rcar_du_hdmienc_dpms(encoder, DRM_MODE_DPMS_ON);
|
||||
return sfuncs->mode_fixup(encoder, mode, adjusted_mode) ? 0 : -EINVAL;
|
||||
}
|
||||
|
||||
static void rcar_du_hdmienc_mode_set(struct drm_encoder *encoder,
|
||||
@@ -99,18 +98,18 @@ static void rcar_du_hdmienc_mode_set(struct drm_encoder *encoder,
|
||||
}
|
||||
|
||||
static const struct drm_encoder_helper_funcs encoder_helper_funcs = {
|
||||
.dpms = rcar_du_hdmienc_dpms,
|
||||
.mode_fixup = rcar_du_hdmienc_mode_fixup,
|
||||
.prepare = rcar_du_hdmienc_mode_prepare,
|
||||
.commit = rcar_du_hdmienc_mode_commit,
|
||||
.mode_set = rcar_du_hdmienc_mode_set,
|
||||
.disable = rcar_du_hdmienc_disable,
|
||||
.enable = rcar_du_hdmienc_enable,
|
||||
.atomic_check = rcar_du_hdmienc_atomic_check,
|
||||
};
|
||||
|
||||
static void rcar_du_hdmienc_cleanup(struct drm_encoder *encoder)
|
||||
{
|
||||
struct rcar_du_hdmienc *hdmienc = to_rcar_hdmienc(encoder);
|
||||
|
||||
rcar_du_hdmienc_dpms(encoder, DRM_MODE_DPMS_OFF);
|
||||
if (hdmienc->enabled)
|
||||
rcar_du_hdmienc_disable(encoder);
|
||||
|
||||
drm_encoder_cleanup(encoder);
|
||||
put_device(hdmienc->dev);
|
||||
|
||||
@@ -12,12 +12,15 @@
|
||||
*/
|
||||
|
||||
#include <drm/drmP.h>
|
||||
#include <drm/drm_atomic.h>
|
||||
#include <drm/drm_atomic_helper.h>
|
||||
#include <drm/drm_crtc.h>
|
||||
#include <drm/drm_crtc_helper.h>
|
||||
#include <drm/drm_fb_cma_helper.h>
|
||||
#include <drm/drm_gem_cma_helper.h>
|
||||
|
||||
#include <linux/of_graph.h>
|
||||
#include <linux/wait.h>
|
||||
|
||||
#include "rcar_du_crtc.h"
|
||||
#include "rcar_du_drv.h"
|
||||
@@ -185,9 +188,309 @@ static void rcar_du_output_poll_changed(struct drm_device *dev)
|
||||
drm_fbdev_cma_hotplug_event(rcdu->fbdev);
|
||||
}
|
||||
|
||||
/* -----------------------------------------------------------------------------
|
||||
* Atomic Check and Update
|
||||
*/
|
||||
|
||||
/*
|
||||
* Atomic hardware plane allocator
|
||||
*
|
||||
* The hardware plane allocator is solely based on the atomic plane states
|
||||
* without keeping any external state to avoid races between .atomic_check()
|
||||
* and .atomic_commit().
|
||||
*
|
||||
* The core idea is to avoid using a free planes bitmask that would need to be
|
||||
* shared between check and commit handlers with a collective knowledge based on
|
||||
* the allocated hardware plane(s) for each KMS plane. The allocator then loops
|
||||
* over all plane states to compute the free planes bitmask, allocates hardware
|
||||
* planes based on that bitmask, and stores the result back in the plane states.
|
||||
*
|
||||
* For this to work we need to access the current state of planes not touched by
|
||||
* the atomic update. To ensure that it won't be modified, we need to lock all
|
||||
* planes using drm_atomic_get_plane_state(). This effectively serializes atomic
|
||||
* updates from .atomic_check() up to completion (when swapping the states if
|
||||
* the check step has succeeded) or rollback (when freeing the states if the
|
||||
* check step has failed).
|
||||
*
|
||||
* Allocation is performed in the .atomic_check() handler and applied
|
||||
* automatically when the core swaps the old and new states.
|
||||
*/
|
||||
|
||||
static bool rcar_du_plane_needs_realloc(struct rcar_du_plane *plane,
|
||||
struct rcar_du_plane_state *state)
|
||||
{
|
||||
const struct rcar_du_format_info *cur_format;
|
||||
|
||||
cur_format = to_rcar_du_plane_state(plane->plane.state)->format;
|
||||
|
||||
/* Lowering the number of planes doesn't strictly require reallocation
|
||||
* as the extra hardware plane will be freed when committing, but doing
|
||||
* so could lead to more fragmentation.
|
||||
*/
|
||||
return !cur_format || cur_format->planes != state->format->planes;
|
||||
}
|
||||
|
||||
static unsigned int rcar_du_plane_hwmask(struct rcar_du_plane_state *state)
|
||||
{
|
||||
unsigned int mask;
|
||||
|
||||
if (state->hwindex == -1)
|
||||
return 0;
|
||||
|
||||
mask = 1 << state->hwindex;
|
||||
if (state->format->planes == 2)
|
||||
mask |= 1 << ((state->hwindex + 1) % 8);
|
||||
|
||||
return mask;
|
||||
}
|
||||
|
||||
static int rcar_du_plane_hwalloc(unsigned int num_planes, unsigned int free)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < RCAR_DU_NUM_HW_PLANES; ++i) {
|
||||
if (!(free & (1 << i)))
|
||||
continue;
|
||||
|
||||
if (num_planes == 1 || free & (1 << ((i + 1) % 8)))
|
||||
break;
|
||||
}
|
||||
|
||||
return i == RCAR_DU_NUM_HW_PLANES ? -EBUSY : i;
|
||||
}
|
||||
|
||||
static int rcar_du_atomic_check(struct drm_device *dev,
|
||||
struct drm_atomic_state *state)
|
||||
{
|
||||
struct rcar_du_device *rcdu = dev->dev_private;
|
||||
unsigned int group_freed_planes[RCAR_DU_MAX_GROUPS] = { 0, };
|
||||
unsigned int group_free_planes[RCAR_DU_MAX_GROUPS] = { 0, };
|
||||
bool needs_realloc = false;
|
||||
unsigned int groups = 0;
|
||||
unsigned int i;
|
||||
int ret;
|
||||
|
||||
ret = drm_atomic_helper_check(dev, state);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* Check if hardware planes need to be reallocated. */
|
||||
for (i = 0; i < dev->mode_config.num_total_plane; ++i) {
|
||||
struct rcar_du_plane_state *plane_state;
|
||||
struct rcar_du_plane *plane;
|
||||
unsigned int index;
|
||||
|
||||
if (!state->planes[i])
|
||||
continue;
|
||||
|
||||
plane = to_rcar_plane(state->planes[i]);
|
||||
plane_state = to_rcar_du_plane_state(state->plane_states[i]);
|
||||
|
||||
/* If the plane is being disabled we don't need to go through
|
||||
* the full reallocation procedure. Just mark the hardware
|
||||
* plane(s) as freed.
|
||||
*/
|
||||
if (!plane_state->format) {
|
||||
index = plane - plane->group->planes.planes;
|
||||
group_freed_planes[plane->group->index] |= 1 << index;
|
||||
plane_state->hwindex = -1;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* If the plane needs to be reallocated mark it as such, and
|
||||
* mark the hardware plane(s) as free.
|
||||
*/
|
||||
if (rcar_du_plane_needs_realloc(plane, plane_state)) {
|
||||
groups |= 1 << plane->group->index;
|
||||
needs_realloc = true;
|
||||
|
||||
index = plane - plane->group->planes.planes;
|
||||
group_freed_planes[plane->group->index] |= 1 << index;
|
||||
plane_state->hwindex = -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (!needs_realloc)
|
||||
return 0;
|
||||
|
||||
/* Grab all plane states for the groups that need reallocation to ensure
|
||||
* locking and avoid racy updates. This serializes the update operation,
|
||||
* but there's not much we can do about it as that's the hardware
|
||||
* design.
|
||||
*
|
||||
* Compute the used planes mask for each group at the same time to avoid
|
||||
* looping over the planes separately later.
|
||||
*/
|
||||
while (groups) {
|
||||
unsigned int index = ffs(groups) - 1;
|
||||
struct rcar_du_group *group = &rcdu->groups[index];
|
||||
unsigned int used_planes = 0;
|
||||
|
||||
for (i = 0; i < RCAR_DU_NUM_KMS_PLANES; ++i) {
|
||||
struct rcar_du_plane *plane = &group->planes.planes[i];
|
||||
struct rcar_du_plane_state *plane_state;
|
||||
struct drm_plane_state *s;
|
||||
|
||||
s = drm_atomic_get_plane_state(state, &plane->plane);
|
||||
if (IS_ERR(s))
|
||||
return PTR_ERR(s);
|
||||
|
||||
/* If the plane has been freed in the above loop its
|
||||
* hardware planes must not be added to the used planes
|
||||
* bitmask. However, the current state doesn't reflect
|
||||
* the free state yet, as we've modified the new state
|
||||
* above. Use the local freed planes list to check for
|
||||
* that condition instead.
|
||||
*/
|
||||
if (group_freed_planes[index] & (1 << i))
|
||||
continue;
|
||||
|
||||
plane_state = to_rcar_du_plane_state(plane->plane.state);
|
||||
used_planes |= rcar_du_plane_hwmask(plane_state);
|
||||
}
|
||||
|
||||
group_free_planes[index] = 0xff & ~used_planes;
|
||||
groups &= ~(1 << index);
|
||||
}
|
||||
|
||||
/* Reallocate hardware planes for each plane that needs it. */
|
||||
for (i = 0; i < dev->mode_config.num_total_plane; ++i) {
|
||||
struct rcar_du_plane_state *plane_state;
|
||||
struct rcar_du_plane *plane;
|
||||
int idx;
|
||||
|
||||
if (!state->planes[i])
|
||||
continue;
|
||||
|
||||
plane = to_rcar_plane(state->planes[i]);
|
||||
plane_state = to_rcar_du_plane_state(state->plane_states[i]);
|
||||
|
||||
/* Skip planes that are being disabled or don't need to be
|
||||
* reallocated.
|
||||
*/
|
||||
if (!plane_state->format ||
|
||||
!rcar_du_plane_needs_realloc(plane, plane_state))
|
||||
continue;
|
||||
|
||||
idx = rcar_du_plane_hwalloc(plane_state->format->planes,
|
||||
group_free_planes[plane->group->index]);
|
||||
if (idx < 0) {
|
||||
dev_dbg(rcdu->dev, "%s: no available hardware plane\n",
|
||||
__func__);
|
||||
return idx;
|
||||
}
|
||||
|
||||
plane_state->hwindex = idx;
|
||||
|
||||
group_free_planes[plane->group->index] &=
|
||||
~rcar_du_plane_hwmask(plane_state);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct rcar_du_commit {
|
||||
struct work_struct work;
|
||||
struct drm_device *dev;
|
||||
struct drm_atomic_state *state;
|
||||
u32 crtcs;
|
||||
};
|
||||
|
||||
static void rcar_du_atomic_complete(struct rcar_du_commit *commit)
|
||||
{
|
||||
struct drm_device *dev = commit->dev;
|
||||
struct rcar_du_device *rcdu = dev->dev_private;
|
||||
struct drm_atomic_state *old_state = commit->state;
|
||||
|
||||
/* Apply the atomic update. */
|
||||
drm_atomic_helper_commit_modeset_disables(dev, old_state);
|
||||
drm_atomic_helper_commit_modeset_enables(dev, old_state);
|
||||
drm_atomic_helper_commit_planes(dev, old_state);
|
||||
|
||||
drm_atomic_helper_wait_for_vblanks(dev, old_state);
|
||||
|
||||
drm_atomic_helper_cleanup_planes(dev, old_state);
|
||||
|
||||
drm_atomic_state_free(old_state);
|
||||
|
||||
/* Complete the commit, wake up any waiter. */
|
||||
spin_lock(&rcdu->commit.wait.lock);
|
||||
rcdu->commit.pending &= ~commit->crtcs;
|
||||
wake_up_all_locked(&rcdu->commit.wait);
|
||||
spin_unlock(&rcdu->commit.wait.lock);
|
||||
|
||||
kfree(commit);
|
||||
}
|
||||
|
||||
static void rcar_du_atomic_work(struct work_struct *work)
|
||||
{
|
||||
struct rcar_du_commit *commit =
|
||||
container_of(work, struct rcar_du_commit, work);
|
||||
|
||||
rcar_du_atomic_complete(commit);
|
||||
}
|
||||
|
||||
static int rcar_du_atomic_commit(struct drm_device *dev,
|
||||
struct drm_atomic_state *state, bool async)
|
||||
{
|
||||
struct rcar_du_device *rcdu = dev->dev_private;
|
||||
struct rcar_du_commit *commit;
|
||||
unsigned int i;
|
||||
int ret;
|
||||
|
||||
ret = drm_atomic_helper_prepare_planes(dev, state);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Allocate the commit object. */
|
||||
commit = kzalloc(sizeof(*commit), GFP_KERNEL);
|
||||
if (commit == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
INIT_WORK(&commit->work, rcar_du_atomic_work);
|
||||
commit->dev = dev;
|
||||
commit->state = state;
|
||||
|
||||
/* Wait until all affected CRTCs have completed previous commits and
|
||||
* mark them as pending.
|
||||
*/
|
||||
for (i = 0; i < dev->mode_config.num_crtc; ++i) {
|
||||
if (state->crtcs[i])
|
||||
commit->crtcs |= 1 << drm_crtc_index(state->crtcs[i]);
|
||||
}
|
||||
|
||||
spin_lock(&rcdu->commit.wait.lock);
|
||||
ret = wait_event_interruptible_locked(rcdu->commit.wait,
|
||||
!(rcdu->commit.pending & commit->crtcs));
|
||||
if (ret == 0)
|
||||
rcdu->commit.pending |= commit->crtcs;
|
||||
spin_unlock(&rcdu->commit.wait.lock);
|
||||
|
||||
if (ret) {
|
||||
kfree(commit);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Swap the state, this is the point of no return. */
|
||||
drm_atomic_helper_swap_state(dev, state);
|
||||
|
||||
if (async)
|
||||
schedule_work(&commit->work);
|
||||
else
|
||||
rcar_du_atomic_complete(commit);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* -----------------------------------------------------------------------------
|
||||
* Initialization
|
||||
*/
|
||||
|
||||
static const struct drm_mode_config_funcs rcar_du_mode_config_funcs = {
|
||||
.fb_create = rcar_du_fb_create,
|
||||
.output_poll_changed = rcar_du_output_poll_changed,
|
||||
.atomic_check = rcar_du_atomic_check,
|
||||
.atomic_commit = rcar_du_atomic_commit,
|
||||
};
|
||||
|
||||
static int rcar_du_encoders_init_one(struct rcar_du_device *rcdu,
|
||||
@@ -392,6 +695,8 @@ int rcar_du_modeset_init(struct rcar_du_device *rcdu)
|
||||
for (i = 0; i < num_groups; ++i) {
|
||||
struct rcar_du_group *rgrp = &rcdu->groups[i];
|
||||
|
||||
mutex_init(&rgrp->lock);
|
||||
|
||||
rgrp->dev = rcdu;
|
||||
rgrp->mmio_offset = mmio_offsets[i];
|
||||
rgrp->index = i;
|
||||
@@ -439,27 +744,21 @@ int rcar_du_modeset_init(struct rcar_du_device *rcdu)
|
||||
encoder->possible_clones = (1 << num_encoders) - 1;
|
||||
}
|
||||
|
||||
/* Now that the CRTCs have been initialized register the planes. */
|
||||
for (i = 0; i < num_groups; ++i) {
|
||||
ret = rcar_du_planes_register(&rcdu->groups[i]);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
drm_mode_config_reset(dev);
|
||||
|
||||
drm_kms_helper_poll_init(dev);
|
||||
|
||||
drm_helper_disable_unused_functions(dev);
|
||||
if (dev->mode_config.num_connector) {
|
||||
fbdev = drm_fbdev_cma_init(dev, 32, dev->mode_config.num_crtc,
|
||||
dev->mode_config.num_connector);
|
||||
if (IS_ERR(fbdev))
|
||||
return PTR_ERR(fbdev);
|
||||
|
||||
fbdev = drm_fbdev_cma_init(dev, 32, dev->mode_config.num_crtc,
|
||||
dev->mode_config.num_connector);
|
||||
if (IS_ERR(fbdev))
|
||||
return PTR_ERR(fbdev);
|
||||
|
||||
#ifndef CONFIG_FRAMEBUFFER_CONSOLE
|
||||
drm_fbdev_cma_restore_mode(fbdev);
|
||||
#endif
|
||||
|
||||
rcdu->fbdev = fbdev;
|
||||
rcdu->fbdev = fbdev;
|
||||
} else {
|
||||
dev_info(rcdu->dev,
|
||||
"no connector found, disabling fbdev emulation\n");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
*/
|
||||
|
||||
#include <drm/drmP.h>
|
||||
#include <drm/drm_atomic_helper.h>
|
||||
#include <drm/drm_crtc.h>
|
||||
#include <drm/drm_crtc_helper.h>
|
||||
|
||||
@@ -74,10 +75,13 @@ rcar_du_lvds_connector_detect(struct drm_connector *connector, bool force)
|
||||
}
|
||||
|
||||
static const struct drm_connector_funcs connector_funcs = {
|
||||
.dpms = drm_helper_connector_dpms,
|
||||
.dpms = drm_atomic_helper_connector_dpms,
|
||||
.reset = drm_atomic_helper_connector_reset,
|
||||
.detect = rcar_du_lvds_connector_detect,
|
||||
.fill_modes = drm_helper_probe_single_connector_modes,
|
||||
.destroy = rcar_du_lvds_connector_destroy,
|
||||
.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
|
||||
.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
|
||||
};
|
||||
|
||||
int rcar_du_lvds_connector_init(struct rcar_du_device *rcdu,
|
||||
@@ -117,7 +121,7 @@ int rcar_du_lvds_connector_init(struct rcar_du_device *rcdu,
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
drm_helper_connector_dpms(connector, DRM_MODE_DPMS_OFF);
|
||||
connector->dpms = DRM_MODE_DPMS_OFF;
|
||||
drm_object_property_set_value(&connector->base,
|
||||
rcdu->ddev->mode_config.dpms_property, DRM_MODE_DPMS_OFF);
|
||||
|
||||
@@ -125,7 +129,6 @@ int rcar_du_lvds_connector_init(struct rcar_du_device *rcdu,
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
connector->encoder = encoder;
|
||||
lvdscon->connector.encoder = renc;
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -28,7 +28,7 @@ struct rcar_du_lvdsenc {
|
||||
unsigned int index;
|
||||
void __iomem *mmio;
|
||||
struct clk *clock;
|
||||
int dpms;
|
||||
bool enabled;
|
||||
|
||||
enum rcar_lvds_input input;
|
||||
};
|
||||
@@ -48,7 +48,7 @@ static int rcar_du_lvdsenc_start(struct rcar_du_lvdsenc *lvds,
|
||||
u32 pllcr;
|
||||
int ret;
|
||||
|
||||
if (lvds->dpms == DRM_MODE_DPMS_ON)
|
||||
if (lvds->enabled)
|
||||
return 0;
|
||||
|
||||
ret = clk_prepare_enable(lvds->clock);
|
||||
@@ -110,13 +110,13 @@ static int rcar_du_lvdsenc_start(struct rcar_du_lvdsenc *lvds,
|
||||
lvdcr0 |= LVDCR0_LVRES;
|
||||
rcar_lvds_write(lvds, LVDCR0, lvdcr0);
|
||||
|
||||
lvds->dpms = DRM_MODE_DPMS_ON;
|
||||
lvds->enabled = true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void rcar_du_lvdsenc_stop(struct rcar_du_lvdsenc *lvds)
|
||||
{
|
||||
if (lvds->dpms == DRM_MODE_DPMS_OFF)
|
||||
if (!lvds->enabled)
|
||||
return;
|
||||
|
||||
rcar_lvds_write(lvds, LVDCR0, 0);
|
||||
@@ -124,13 +124,13 @@ static void rcar_du_lvdsenc_stop(struct rcar_du_lvdsenc *lvds)
|
||||
|
||||
clk_disable_unprepare(lvds->clock);
|
||||
|
||||
lvds->dpms = DRM_MODE_DPMS_OFF;
|
||||
lvds->enabled = false;
|
||||
}
|
||||
|
||||
int rcar_du_lvdsenc_dpms(struct rcar_du_lvdsenc *lvds,
|
||||
struct drm_crtc *crtc, int mode)
|
||||
int rcar_du_lvdsenc_enable(struct rcar_du_lvdsenc *lvds, struct drm_crtc *crtc,
|
||||
bool enable)
|
||||
{
|
||||
if (mode == DRM_MODE_DPMS_OFF) {
|
||||
if (!enable) {
|
||||
rcar_du_lvdsenc_stop(lvds);
|
||||
return 0;
|
||||
} else if (crtc) {
|
||||
@@ -179,7 +179,7 @@ int rcar_du_lvdsenc_init(struct rcar_du_device *rcdu)
|
||||
lvds->dev = rcdu;
|
||||
lvds->index = i;
|
||||
lvds->input = i ? RCAR_LVDS_INPUT_DU1 : RCAR_LVDS_INPUT_DU0;
|
||||
lvds->dpms = DRM_MODE_DPMS_OFF;
|
||||
lvds->enabled = false;
|
||||
|
||||
ret = rcar_du_lvdsenc_get_resources(lvds, pdev);
|
||||
if (ret < 0)
|
||||
|
||||
@@ -28,15 +28,15 @@ enum rcar_lvds_input {
|
||||
|
||||
#if IS_ENABLED(CONFIG_DRM_RCAR_LVDS)
|
||||
int rcar_du_lvdsenc_init(struct rcar_du_device *rcdu);
|
||||
int rcar_du_lvdsenc_dpms(struct rcar_du_lvdsenc *lvds,
|
||||
struct drm_crtc *crtc, int mode);
|
||||
int rcar_du_lvdsenc_enable(struct rcar_du_lvdsenc *lvds,
|
||||
struct drm_crtc *crtc, bool enable);
|
||||
#else
|
||||
static inline int rcar_du_lvdsenc_init(struct rcar_du_device *rcdu)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
static inline int rcar_du_lvdsenc_dpms(struct rcar_du_lvdsenc *lvds,
|
||||
struct drm_crtc *crtc, int mode)
|
||||
static inline int rcar_du_lvdsenc_enable(struct rcar_du_lvdsenc *lvds,
|
||||
struct drm_crtc *crtc, bool enable)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -14,68 +14,57 @@
|
||||
#ifndef __RCAR_DU_PLANE_H__
|
||||
#define __RCAR_DU_PLANE_H__
|
||||
|
||||
#include <linux/mutex.h>
|
||||
|
||||
#include <drm/drmP.h>
|
||||
#include <drm/drm_crtc.h>
|
||||
|
||||
struct rcar_du_format_info;
|
||||
struct rcar_du_group;
|
||||
|
||||
/* The RCAR DU has 8 hardware planes, shared between KMS planes and CRTCs. As
|
||||
* using KMS planes requires at least one of the CRTCs being enabled, no more
|
||||
* than 7 KMS planes can be available. We thus create 7 KMS planes and
|
||||
* 9 software planes (one for each KMS planes and one for each CRTC).
|
||||
/* The RCAR DU has 8 hardware planes, shared between primary and overlay planes.
|
||||
* As using overlay planes requires at least one of the CRTCs being enabled, no
|
||||
* more than 7 overlay planes can be available. We thus create 1 primary plane
|
||||
* per CRTC and 7 overlay planes, for a total of up to 9 KMS planes.
|
||||
*/
|
||||
|
||||
#define RCAR_DU_NUM_KMS_PLANES 7
|
||||
#define RCAR_DU_NUM_KMS_PLANES 9
|
||||
#define RCAR_DU_NUM_HW_PLANES 8
|
||||
#define RCAR_DU_NUM_SW_PLANES 9
|
||||
|
||||
struct rcar_du_plane {
|
||||
struct drm_plane plane;
|
||||
struct rcar_du_group *group;
|
||||
struct drm_crtc *crtc;
|
||||
|
||||
bool enabled;
|
||||
|
||||
int hwindex; /* 0-based, -1 means unused */
|
||||
unsigned int alpha;
|
||||
unsigned int colorkey;
|
||||
unsigned int zpos;
|
||||
|
||||
const struct rcar_du_format_info *format;
|
||||
|
||||
unsigned long dma[2];
|
||||
unsigned int pitch;
|
||||
|
||||
unsigned int width;
|
||||
unsigned int height;
|
||||
|
||||
unsigned int src_x;
|
||||
unsigned int src_y;
|
||||
unsigned int dst_x;
|
||||
unsigned int dst_y;
|
||||
};
|
||||
|
||||
static inline struct rcar_du_plane *to_rcar_plane(struct drm_plane *plane)
|
||||
{
|
||||
return container_of(plane, struct rcar_du_plane, plane);
|
||||
}
|
||||
|
||||
struct rcar_du_planes {
|
||||
struct rcar_du_plane planes[RCAR_DU_NUM_SW_PLANES];
|
||||
unsigned int free;
|
||||
struct mutex lock;
|
||||
struct rcar_du_plane planes[RCAR_DU_NUM_KMS_PLANES];
|
||||
|
||||
struct drm_property *alpha;
|
||||
struct drm_property *colorkey;
|
||||
struct drm_property *zpos;
|
||||
};
|
||||
|
||||
struct rcar_du_plane_state {
|
||||
struct drm_plane_state state;
|
||||
|
||||
const struct rcar_du_format_info *format;
|
||||
int hwindex; /* 0-based, -1 means unused */
|
||||
|
||||
unsigned int alpha;
|
||||
unsigned int colorkey;
|
||||
unsigned int zpos;
|
||||
};
|
||||
|
||||
static inline struct rcar_du_plane_state *
|
||||
to_rcar_du_plane_state(struct drm_plane_state *state)
|
||||
{
|
||||
return container_of(state, struct rcar_du_plane_state, state);
|
||||
}
|
||||
|
||||
int rcar_du_planes_init(struct rcar_du_group *rgrp);
|
||||
int rcar_du_planes_register(struct rcar_du_group *rgrp);
|
||||
|
||||
void rcar_du_plane_setup(struct rcar_du_plane *plane);
|
||||
void rcar_du_plane_update_base(struct rcar_du_plane *plane);
|
||||
void rcar_du_plane_compute_base(struct rcar_du_plane *plane,
|
||||
struct drm_framebuffer *fb);
|
||||
int rcar_du_plane_reserve(struct rcar_du_plane *plane,
|
||||
const struct rcar_du_format_info *format);
|
||||
void rcar_du_plane_release(struct rcar_du_plane *plane);
|
||||
|
||||
#endif /* __RCAR_DU_PLANE_H__ */
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
*/
|
||||
|
||||
#include <drm/drmP.h>
|
||||
#include <drm/drm_atomic_helper.h>
|
||||
#include <drm/drm_crtc.h>
|
||||
#include <drm/drm_crtc_helper.h>
|
||||
|
||||
@@ -43,10 +44,13 @@ rcar_du_vga_connector_detect(struct drm_connector *connector, bool force)
|
||||
}
|
||||
|
||||
static const struct drm_connector_funcs connector_funcs = {
|
||||
.dpms = drm_helper_connector_dpms,
|
||||
.dpms = drm_atomic_helper_connector_dpms,
|
||||
.reset = drm_atomic_helper_connector_reset,
|
||||
.detect = rcar_du_vga_connector_detect,
|
||||
.fill_modes = drm_helper_probe_single_connector_modes,
|
||||
.destroy = rcar_du_vga_connector_destroy,
|
||||
.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
|
||||
.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
|
||||
};
|
||||
|
||||
int rcar_du_vga_connector_init(struct rcar_du_device *rcdu,
|
||||
@@ -76,7 +80,7 @@ int rcar_du_vga_connector_init(struct rcar_du_device *rcdu,
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
drm_helper_connector_dpms(connector, DRM_MODE_DPMS_OFF);
|
||||
connector->dpms = DRM_MODE_DPMS_OFF;
|
||||
drm_object_property_set_value(&connector->base,
|
||||
rcdu->ddev->mode_config.dpms_property, DRM_MODE_DPMS_OFF);
|
||||
|
||||
@@ -84,7 +88,6 @@ int rcar_du_vga_connector_init(struct rcar_du_device *rcdu,
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
connector->encoder = encoder;
|
||||
rcon->encoder = renc;
|
||||
|
||||
return 0;
|
||||
|
||||
Reference in New Issue
Block a user