Commit 9c704d14 authored by Dave Airlie's avatar Dave Airlie

Merge tag 'topic/drm-misc-2016-10-05' of git://anongit.freedesktop.org/drm-intel into drm-next

Another attempt, this time rebased and without the pipe crc patches:
- display_info cleanups from Ville
- make prime/gem lookups faster with rbtrees (Chris)
- misc stuff all over

* tag 'topic/drm-misc-2016-10-05' of git://anongit.freedesktop.org/drm-intel:
  drm/rockchip: analogix_dp: Refuse to enable PSR if panel doesn't support it
  drm/bridge: analogix_dp: Add analogix_dp_psr_supported
  drm/fb-helper: add DRM_FB_HELPER_DEFAULT_OPS for fb_ops
  drm: Document caveats around atomic event handling
  uapi: add missing install of sync_file.h
  drm: Simplify drm_printk to reduce object size quite a bit
  drm/i915: Account for sink max TMDS clock when checking the port clock
  drm/i915: Replace a bunch of connector->base.display_info with a local variable
  drm/edid: Move dvi_dual/max_tmds_clock parsing out from drm_edid_to_eld()
  drm/edid: Clear the old cea_rev when there's no CEA extension in the new EDID
  drm/edid: Reduce the number of times we parse the CEA extension block
  drm/edid: Don't pass around drm_display_info needlessly
  drm/edid: Move dvi_dual/max_tmds_clock to drm_display_info
  drm/edid: Make max_tmds_clock kHz instead of MHz
  drm/edid: Clear old dvi_dual/max_tmds_clock before parsing the new EDID
  drm/edid: Clear old audio latency values before parsing the new EDID
  drm: Convert prime dma-buf <-> handle to rbtree
  drm/mediatek: mark symbols static where possible
  drm/rockchip: mark symbols static where possible
  drm/rockchip: add missing header dependencies
parents a74feb65 0546d685
...@@ -168,12 +168,12 @@ int amdgpu_connector_get_monitor_bpc(struct drm_connector *connector) ...@@ -168,12 +168,12 @@ int amdgpu_connector_get_monitor_bpc(struct drm_connector *connector)
} }
/* Any defined maximum tmds clock limit we must not exceed? */ /* Any defined maximum tmds clock limit we must not exceed? */
if (connector->max_tmds_clock > 0) { if (connector->display_info.max_tmds_clock > 0) {
/* mode_clock is clock in kHz for mode to be modeset on this connector */ /* mode_clock is clock in kHz for mode to be modeset on this connector */
mode_clock = amdgpu_connector->pixelclock_for_modeset; mode_clock = amdgpu_connector->pixelclock_for_modeset;
/* Maximum allowable input clock in kHz */ /* Maximum allowable input clock in kHz */
max_tmds_clock = connector->max_tmds_clock * 1000; max_tmds_clock = connector->display_info.max_tmds_clock;
DRM_DEBUG("%s: hdmi mode dotclock %d kHz, max tmds input clock %d kHz.\n", DRM_DEBUG("%s: hdmi mode dotclock %d kHz, max tmds input clock %d kHz.\n",
connector->name, mode_clock, max_tmds_clock); connector->name, mode_clock, max_tmds_clock);
......
...@@ -98,6 +98,14 @@ static int analogix_dp_detect_hpd(struct analogix_dp_device *dp) ...@@ -98,6 +98,14 @@ static int analogix_dp_detect_hpd(struct analogix_dp_device *dp)
return 0; return 0;
} }
int analogix_dp_psr_supported(struct device *dev)
{
struct analogix_dp_device *dp = dev_get_drvdata(dev);
return dp->psr_support;
}
EXPORT_SYMBOL_GPL(analogix_dp_psr_supported);
int analogix_dp_enable_psr(struct device *dev) int analogix_dp_enable_psr(struct device *dev)
{ {
struct analogix_dp_device *dp = dev_get_drvdata(dev); struct analogix_dp_device *dp = dev_get_drvdata(dev);
......
...@@ -89,7 +89,6 @@ void drm_dev_printk(const struct device *dev, const char *level, ...@@ -89,7 +89,6 @@ void drm_dev_printk(const struct device *dev, const char *level,
EXPORT_SYMBOL(drm_dev_printk); EXPORT_SYMBOL(drm_dev_printk);
void drm_printk(const char *level, unsigned int category, void drm_printk(const char *level, unsigned int category,
const char *function_name, const char *prefix,
const char *format, ...) const char *format, ...)
{ {
struct va_format vaf; struct va_format vaf;
...@@ -102,7 +101,9 @@ void drm_printk(const char *level, unsigned int category, ...@@ -102,7 +101,9 @@ void drm_printk(const char *level, unsigned int category,
vaf.fmt = format; vaf.fmt = format;
vaf.va = &args; vaf.va = &args;
printk("%s" DRM_PRINTK_FMT, level, function_name, prefix, &vaf); printk("%s" "[" DRM_NAME ":%ps]%s %pV",
level, __builtin_return_address(0),
strcmp(level, KERN_ERR) == 0 ? " *ERROR*" : "", &vaf);
va_end(args); va_end(args);
} }
......
...@@ -3253,16 +3253,12 @@ static void fixup_detailed_cea_mode_clock(struct drm_display_mode *mode) ...@@ -3253,16 +3253,12 @@ static void fixup_detailed_cea_mode_clock(struct drm_display_mode *mode)
} }
static void static void
parse_hdmi_vsdb(struct drm_connector *connector, const u8 *db) drm_parse_hdmi_vsdb_audio(struct drm_connector *connector, const u8 *db)
{ {
u8 len = cea_db_payload_len(db); u8 len = cea_db_payload_len(db);
if (len >= 6) { if (len >= 6)
connector->eld[5] |= (db[6] >> 7) << 1; /* Supports_AI */ connector->eld[5] |= (db[6] >> 7) << 1; /* Supports_AI */
connector->dvi_dual = db[6] & 1;
}
if (len >= 7)
connector->max_tmds_clock = db[7] * 5;
if (len >= 8) { if (len >= 8) {
connector->latency_present[0] = db[8] >> 7; connector->latency_present[0] = db[8] >> 7;
connector->latency_present[1] = (db[8] >> 6) & 1; connector->latency_present[1] = (db[8] >> 6) & 1;
...@@ -3276,19 +3272,15 @@ parse_hdmi_vsdb(struct drm_connector *connector, const u8 *db) ...@@ -3276,19 +3272,15 @@ parse_hdmi_vsdb(struct drm_connector *connector, const u8 *db)
if (len >= 12) if (len >= 12)
connector->audio_latency[1] = db[12]; connector->audio_latency[1] = db[12];
DRM_DEBUG_KMS("HDMI: DVI dual %d, " DRM_DEBUG_KMS("HDMI: latency present %d %d, "
"max TMDS clock %d, " "video latency %d %d, "
"latency present %d %d, " "audio latency %d %d\n",
"video latency %d %d, " connector->latency_present[0],
"audio latency %d %d\n", connector->latency_present[1],
connector->dvi_dual, connector->video_latency[0],
connector->max_tmds_clock, connector->video_latency[1],
(int) connector->latency_present[0], connector->audio_latency[0],
(int) connector->latency_present[1], connector->audio_latency[1]);
connector->video_latency[0],
connector->video_latency[1],
connector->audio_latency[0],
connector->audio_latency[1]);
} }
static void static void
...@@ -3358,6 +3350,13 @@ void drm_edid_to_eld(struct drm_connector *connector, struct edid *edid) ...@@ -3358,6 +3350,13 @@ void drm_edid_to_eld(struct drm_connector *connector, struct edid *edid)
memset(eld, 0, sizeof(connector->eld)); memset(eld, 0, sizeof(connector->eld));
connector->latency_present[0] = false;
connector->latency_present[1] = false;
connector->video_latency[0] = 0;
connector->audio_latency[0] = 0;
connector->video_latency[1] = 0;
connector->audio_latency[1] = 0;
cea = drm_find_cea_extension(edid); cea = drm_find_cea_extension(edid);
if (!cea) { if (!cea) {
DRM_DEBUG_KMS("ELD: no CEA Extension found\n"); DRM_DEBUG_KMS("ELD: no CEA Extension found\n");
...@@ -3407,7 +3406,7 @@ void drm_edid_to_eld(struct drm_connector *connector, struct edid *edid) ...@@ -3407,7 +3406,7 @@ void drm_edid_to_eld(struct drm_connector *connector, struct edid *edid)
case VENDOR_BLOCK: case VENDOR_BLOCK:
/* HDMI Vendor-Specific Data Block */ /* HDMI Vendor-Specific Data Block */
if (cea_db_is_hdmi_vsdb(db)) if (cea_db_is_hdmi_vsdb(db))
parse_hdmi_vsdb(connector, db); drm_parse_hdmi_vsdb_audio(connector, db);
break; break;
default: default:
break; break;
...@@ -3721,105 +3720,127 @@ bool drm_rgb_quant_range_selectable(struct edid *edid) ...@@ -3721,105 +3720,127 @@ bool drm_rgb_quant_range_selectable(struct edid *edid)
} }
EXPORT_SYMBOL(drm_rgb_quant_range_selectable); EXPORT_SYMBOL(drm_rgb_quant_range_selectable);
/* static void drm_parse_hdmi_deep_color_info(struct drm_connector *connector,
* Parse the CEA extension according to CEA-861-B. const u8 *hdmi)
* Return true if HDMI deep color supported, false if not or unknown.
*/
static bool drm_assign_hdmi_deep_color_info(struct edid *edid,
struct drm_display_info *info,
struct drm_connector *connector)
{ {
u8 *edid_ext, *hdmi; struct drm_display_info *info = &connector->display_info;
int i;
int start_offset, end_offset;
unsigned int dc_bpc = 0; unsigned int dc_bpc = 0;
edid_ext = drm_find_cea_extension(edid); /* HDMI supports at least 8 bpc */
if (!edid_ext) info->bpc = 8;
return false;
if (cea_db_offsets(edid_ext, &start_offset, &end_offset)) if (cea_db_payload_len(hdmi) < 6)
return false; return;
if (hdmi[6] & DRM_EDID_HDMI_DC_30) {
dc_bpc = 10;
info->edid_hdmi_dc_modes |= DRM_EDID_HDMI_DC_30;
DRM_DEBUG("%s: HDMI sink does deep color 30.\n",
connector->name);
}
if (hdmi[6] & DRM_EDID_HDMI_DC_36) {
dc_bpc = 12;
info->edid_hdmi_dc_modes |= DRM_EDID_HDMI_DC_36;
DRM_DEBUG("%s: HDMI sink does deep color 36.\n",
connector->name);
}
if (hdmi[6] & DRM_EDID_HDMI_DC_48) {
dc_bpc = 16;
info->edid_hdmi_dc_modes |= DRM_EDID_HDMI_DC_48;
DRM_DEBUG("%s: HDMI sink does deep color 48.\n",
connector->name);
}
if (dc_bpc == 0) {
DRM_DEBUG("%s: No deep color support on this HDMI sink.\n",
connector->name);
return;
}
DRM_DEBUG("%s: Assigning HDMI sink color depth as %d bpc.\n",
connector->name, dc_bpc);
info->bpc = dc_bpc;
/* /*
* Because HDMI identifier is in Vendor Specific Block, * Deep color support mandates RGB444 support for all video
* search it from all data blocks of CEA extension. * modes and forbids YCRCB422 support for all video modes per
* HDMI 1.3 spec.
*/ */
for_each_cea_db(edid_ext, i, start_offset, end_offset) { info->color_formats = DRM_COLOR_FORMAT_RGB444;
if (cea_db_is_hdmi_vsdb(&edid_ext[i])) {
/* HDMI supports at least 8 bpc */
info->bpc = 8;
hdmi = &edid_ext[i];
if (cea_db_payload_len(hdmi) < 6)
return false;
if (hdmi[6] & DRM_EDID_HDMI_DC_30) {
dc_bpc = 10;
info->edid_hdmi_dc_modes |= DRM_EDID_HDMI_DC_30;
DRM_DEBUG("%s: HDMI sink does deep color 30.\n",
connector->name);
}
if (hdmi[6] & DRM_EDID_HDMI_DC_36) { /* YCRCB444 is optional according to spec. */
dc_bpc = 12; if (hdmi[6] & DRM_EDID_HDMI_DC_Y444) {
info->edid_hdmi_dc_modes |= DRM_EDID_HDMI_DC_36; info->color_formats |= DRM_COLOR_FORMAT_YCRCB444;
DRM_DEBUG("%s: HDMI sink does deep color 36.\n", DRM_DEBUG("%s: HDMI sink does YCRCB444 in deep color.\n",
connector->name); connector->name);
} }
if (hdmi[6] & DRM_EDID_HDMI_DC_48) { /*
dc_bpc = 16; * Spec says that if any deep color mode is supported at all,
info->edid_hdmi_dc_modes |= DRM_EDID_HDMI_DC_48; * then deep color 36 bit must be supported.
DRM_DEBUG("%s: HDMI sink does deep color 48.\n", */
connector->name); if (!(hdmi[6] & DRM_EDID_HDMI_DC_36)) {
} DRM_DEBUG("%s: HDMI sink should do DC_36, but does not!\n",
connector->name);
}
}
if (dc_bpc > 0) { static void
DRM_DEBUG("%s: Assigning HDMI sink color depth as %d bpc.\n", drm_parse_hdmi_vsdb_video(struct drm_connector *connector, const u8 *db)
connector->name, dc_bpc); {
info->bpc = dc_bpc; struct drm_display_info *info = &connector->display_info;
u8 len = cea_db_payload_len(db);
/*
* Deep color support mandates RGB444 support for all video
* modes and forbids YCRCB422 support for all video modes per
* HDMI 1.3 spec.
*/
info->color_formats = DRM_COLOR_FORMAT_RGB444;
/* YCRCB444 is optional according to spec. */
if (hdmi[6] & DRM_EDID_HDMI_DC_Y444) {
info->color_formats |= DRM_COLOR_FORMAT_YCRCB444;
DRM_DEBUG("%s: HDMI sink does YCRCB444 in deep color.\n",
connector->name);
}
/* if (len >= 6)
* Spec says that if any deep color mode is supported at all, info->dvi_dual = db[6] & 1;
* then deep color 36 bit must be supported. if (len >= 7)
*/ info->max_tmds_clock = db[7] * 5000;
if (!(hdmi[6] & DRM_EDID_HDMI_DC_36)) {
DRM_DEBUG("%s: HDMI sink should do DC_36, but does not!\n",
connector->name);
}
return true; DRM_DEBUG_KMS("HDMI: DVI dual %d, "
} "max TMDS clock %d kHz\n",
else { info->dvi_dual,
DRM_DEBUG("%s: No deep color support on this HDMI sink.\n", info->max_tmds_clock);
connector->name);
}
}
}
return false; drm_parse_hdmi_deep_color_info(connector, db);
} }
static void drm_add_display_info(struct edid *edid, static void drm_parse_cea_ext(struct drm_connector *connector,
struct drm_display_info *info, struct edid *edid)
struct drm_connector *connector)
{ {
u8 *edid_ext; struct drm_display_info *info = &connector->display_info;
const u8 *edid_ext;
int i, start, end;
edid_ext = drm_find_cea_extension(edid);
if (!edid_ext)
return;
info->cea_rev = edid_ext[1];
/* The existence of a CEA block should imply RGB support */
info->color_formats = DRM_COLOR_FORMAT_RGB444;
if (edid_ext[3] & EDID_CEA_YCRCB444)
info->color_formats |= DRM_COLOR_FORMAT_YCRCB444;
if (edid_ext[3] & EDID_CEA_YCRCB422)
info->color_formats |= DRM_COLOR_FORMAT_YCRCB422;
if (cea_db_offsets(edid_ext, &start, &end))
return;
for_each_cea_db(edid_ext, i, start, end) {
const u8 *db = &edid_ext[i];
if (cea_db_is_hdmi_vsdb(db))
drm_parse_hdmi_vsdb_video(connector, db);
}
}
static void drm_add_display_info(struct drm_connector *connector,
struct edid *edid)
{
struct drm_display_info *info = &connector->display_info;
info->width_mm = edid->width_cm * 10; info->width_mm = edid->width_cm * 10;
info->height_mm = edid->height_cm * 10; info->height_mm = edid->height_cm * 10;
...@@ -3827,6 +3848,9 @@ static void drm_add_display_info(struct edid *edid, ...@@ -3827,6 +3848,9 @@ static void drm_add_display_info(struct edid *edid,
/* driver figures it out in this case */ /* driver figures it out in this case */
info->bpc = 0; info->bpc = 0;
info->color_formats = 0; info->color_formats = 0;
info->cea_rev = 0;
info->max_tmds_clock = 0;
info->dvi_dual = false;
if (edid->revision < 3) if (edid->revision < 3)
return; return;
...@@ -3834,21 +3858,7 @@ static void drm_add_display_info(struct edid *edid, ...@@ -3834,21 +3858,7 @@ static void drm_add_display_info(struct edid *edid,
if (!(edid->input & DRM_EDID_INPUT_DIGITAL)) if (!(edid->input & DRM_EDID_INPUT_DIGITAL))
return; return;
/* Get data from CEA blocks if present */ drm_parse_cea_ext(connector, edid);
edid_ext = drm_find_cea_extension(edid);
if (edid_ext) {
info->cea_rev = edid_ext[1];
/* The existence of a CEA block should imply RGB support */
info->color_formats = DRM_COLOR_FORMAT_RGB444;
if (edid_ext[3] & EDID_CEA_YCRCB444)
info->color_formats |= DRM_COLOR_FORMAT_YCRCB444;
if (edid_ext[3] & EDID_CEA_YCRCB422)
info->color_formats |= DRM_COLOR_FORMAT_YCRCB422;
}
/* HDMI deep color modes supported? Assign to info, if so */
drm_assign_hdmi_deep_color_info(edid, info, connector);
/* /*
* Digital sink with "DFP 1.x compliant TMDS" according to EDID 1.3? * Digital sink with "DFP 1.x compliant TMDS" according to EDID 1.3?
...@@ -4084,7 +4094,7 @@ int drm_add_edid_modes(struct drm_connector *connector, struct edid *edid) ...@@ -4084,7 +4094,7 @@ int drm_add_edid_modes(struct drm_connector *connector, struct edid *edid)
if (quirks & (EDID_QUIRK_PREFER_LARGE_60 | EDID_QUIRK_PREFER_LARGE_75)) if (quirks & (EDID_QUIRK_PREFER_LARGE_60 | EDID_QUIRK_PREFER_LARGE_75))
edid_fixup_preferred(connector, quirks); edid_fixup_preferred(connector, quirks);
drm_add_display_info(edid, &connector->display_info, connector); drm_add_display_info(connector, edid);
if (quirks & EDID_QUIRK_FORCE_6BPC) if (quirks & EDID_QUIRK_FORCE_6BPC)
connector->display_info.bpc = 6; connector->display_info.bpc = 6;
......
...@@ -1008,6 +1008,31 @@ static void send_vblank_event(struct drm_device *dev, ...@@ -1008,6 +1008,31 @@ static void send_vblank_event(struct drm_device *dev,
* period. This helper function implements exactly the required vblank arming * period. This helper function implements exactly the required vblank arming
* behaviour. * behaviour.
* *
* NOTE: Drivers using this to send out the event in struct &drm_crtc_state
* as part of an atomic commit must ensure that the next vblank happens at
* exactly the same time as the atomic commit is committed to the hardware. This
* function itself does **not** protect again the next vblank interrupt racing
* with either this function call or the atomic commit operation. A possible
* sequence could be:
*
* 1. Driver commits new hardware state into vblank-synchronized registers.
* 2. A vblank happens, committing the hardware state. Also the corresponding
* vblank interrupt is fired off and fully processed by the interrupt
* handler.
* 3. The atomic commit operation proceeds to call drm_crtc_arm_vblank_event().
* 4. The event is only send out for the next vblank, which is wrong.
*
* An equivalent race can happen when the driver calls
* drm_crtc_arm_vblank_event() before writing out the new hardware state.
*
* The only way to make this work safely is to prevent the vblank from firing
* (and the hardware from committing anything else) until the entire atomic
* commit sequence has run to completion. If the hardware does not have such a
* feature (e.g. using a "go" bit), then it is unsafe to use this functions.
* Instead drivers need to manually send out the event from their interrupt
* handler by calling drm_crtc_send_vblank_event() and make sure that there's no
* possible race with the hardware committing the atomic update.
*
* Caller must hold event lock. Caller must also hold a vblank reference for * Caller must hold event lock. Caller must also hold a vblank reference for
* the event @e, which will be dropped when the next vblank arrives. * the event @e, which will be dropped when the next vblank arrives.
*/ */
...@@ -1030,8 +1055,11 @@ EXPORT_SYMBOL(drm_crtc_arm_vblank_event); ...@@ -1030,8 +1055,11 @@ EXPORT_SYMBOL(drm_crtc_arm_vblank_event);
* @crtc: the source CRTC of the vblank event * @crtc: the source CRTC of the vblank event
* @e: the event to send * @e: the event to send
* *
* Updates sequence # and timestamp on event, and sends it to userspace. * Updates sequence # and timestamp on event for the most recently processed
* Caller must hold event lock. * vblank, and sends it to userspace. Caller must hold event lock.
*
* See drm_crtc_arm_vblank_event() for a helper which can be used in certain
* situation, especially to send out events for atomic commit operations.
*/ */
void drm_crtc_send_vblank_event(struct drm_crtc *crtc, void drm_crtc_send_vblank_event(struct drm_crtc *crtc,
struct drm_pending_vblank_event *e) struct drm_pending_vblank_event *e)
......
...@@ -28,6 +28,7 @@ ...@@ -28,6 +28,7 @@
#include <linux/export.h> #include <linux/export.h>
#include <linux/dma-buf.h> #include <linux/dma-buf.h>
#include <linux/rbtree.h>
#include <drm/drmP.h> #include <drm/drmP.h>
#include <drm/drm_gem.h> #include <drm/drm_gem.h>
...@@ -61,9 +62,11 @@ ...@@ -61,9 +62,11 @@
*/ */
struct drm_prime_member { struct drm_prime_member {
struct list_head entry;
struct dma_buf *dma_buf; struct dma_buf *dma_buf;
uint32_t handle; uint32_t handle;
struct rb_node dmabuf_rb;
struct rb_node handle_rb;
}; };
struct drm_prime_attachment { struct drm_prime_attachment {
...@@ -75,6 +78,7 @@ static int drm_prime_add_buf_handle(struct drm_prime_file_private *prime_fpriv, ...@@ -75,6 +78,7 @@ static int drm_prime_add_buf_handle(struct drm_prime_file_private *prime_fpriv,
struct dma_buf *dma_buf, uint32_t handle) struct dma_buf *dma_buf, uint32_t handle)
{ {
struct drm_prime_member *member; struct drm_prime_member *member;
struct rb_node **p, *rb;
member = kmalloc(sizeof(*member), GFP_KERNEL); member = kmalloc(sizeof(*member), GFP_KERNEL);
if (!member) if (!member)
...@@ -83,18 +87,56 @@ static int drm_prime_add_buf_handle(struct drm_prime_file_private *prime_fpriv, ...@@ -83,18 +87,56 @@ static int drm_prime_add_buf_handle(struct drm_prime_file_private *prime_fpriv,
get_dma_buf(dma_buf); get_dma_buf(dma_buf);
member->dma_buf = dma_buf; member->dma_buf = dma_buf;
member->handle = handle; member->handle = handle;
list_add(&member->entry, &prime_fpriv->head);
rb = NULL;
p = &prime_fpriv->dmabufs.rb_node;
while (*p) {
struct drm_prime_member *pos;
rb = *p;
pos = rb_entry(rb, struct drm_prime_member, dmabuf_rb);
if (dma_buf > pos->dma_buf)
p = &rb->rb_right;
else
p = &rb->rb_left;
}
rb_link_node(&member->dmabuf_rb, rb, p);
rb_insert_color(&member->dmabuf_rb, &prime_fpriv->dmabufs);
rb = NULL;
p = &prime_fpriv->handles.rb_node;
while (*p) {
struct drm_prime_member *pos;
rb = *p;
pos = rb_entry(rb, struct drm_prime_member, handle_rb);
if (handle > pos->handle)
p = &rb->rb_right;
else
p = &rb->rb_left;
}
rb_link_node(&member->handle_rb, rb, p);
rb_insert_color(&member->handle_rb, &prime_fpriv->handles);
return 0; return 0;
} }
static struct dma_buf *drm_prime_lookup_buf_by_handle(struct drm_prime_file_private *prime_fpriv, static struct dma_buf *drm_prime_lookup_buf_by_handle(struct drm_prime_file_private *prime_fpriv,
uint32_t handle) uint32_t handle)
{ {
struct drm_prime_member *member; struct rb_node *rb;
rb = prime_fpriv->handles.rb_node;
while (rb) {
struct drm_prime_member *member;
list_for_each_entry(member, &prime_fpriv->head, entry) { member = rb_entry(rb, struct drm_prime_member, handle_rb);
if (member->handle == handle) if (member->handle == handle)
return member->dma_buf; return member->dma_buf;
else if (member->handle < handle)
rb = rb->rb_right;
else
rb = rb->rb_left;
} }
return NULL; return NULL;
...@@ -104,14 +146,23 @@ static int drm_prime_lookup_buf_handle(struct drm_prime_file_private *prime_fpri ...@@ -104,14 +146,23 @@ static int drm_prime_lookup_buf_handle(struct drm_prime_file_private *prime_fpri
struct dma_buf *dma_buf, struct dma_buf *dma_buf,
uint32_t *handle) uint32_t *handle)
{ {
struct drm_prime_member *member; struct rb_node *rb;
rb = prime_fpriv->dmabufs.rb_node;
while (rb) {
struct drm_prime_member *member;
list_for_each_entry(member, &prime_fpriv->head, entry) { member = rb_entry(rb, struct drm_prime_member, dmabuf_rb);
if (member->dma_buf == dma_buf) { if (member->dma_buf == dma_buf) {
*handle = member->handle; *handle = member->handle;
return 0; return 0;
} else if (member->dma_buf < dma_buf) {
rb = rb->rb_right;
} else {
rb = rb->rb_left;
} }
} }
return -ENOENT; return -ENOENT;
} }
...@@ -166,13 +217,24 @@ static void drm_gem_map_detach(struct dma_buf *dma_buf, ...@@ -166,13 +217,24 @@ static void drm_gem_map_detach(struct dma_buf *dma_buf,
void drm_prime_remove_buf_handle_locked(struct drm_prime_file_private *prime_fpriv, void drm_prime_remove_buf_handle_locked(struct drm_prime_file_private *prime_fpriv,
struct dma_buf *dma_buf) struct dma_buf *dma_buf)
{ {
struct drm_prime_member *member, *safe; struct rb_node *rb;
list_for_each_entry_safe(member, safe, &prime_fpriv->head, entry) { rb = prime_fpriv->dmabufs.rb_node;
while (rb) {
struct drm_prime_member *member;
member = rb_entry(rb, struct drm_prime_member, dmabuf_rb);
if (member->dma_buf == dma_buf) { if (member->dma_buf == dma_buf) {
rb_erase(&member->handle_rb, &prime_fpriv->handles);
rb_erase(&member->dmabuf_rb, &prime_fpriv->dmabufs);
dma_buf_put(dma_buf); dma_buf_put(dma_buf);
list_del(&member->entry);
kfree(member); kfree(member);
return;
} else if (member->dma_buf < dma_buf) {
rb = rb->rb_right;
} else {
rb = rb->rb_left;
} }
} }
} }
...@@ -759,12 +821,13 @@ EXPORT_SYMBOL(drm_prime_gem_destroy); ...@@ -759,12 +821,13 @@ EXPORT_SYMBOL(drm_prime_gem_destroy);
void drm_prime_init_file_private(struct drm_prime_file_private *prime_fpriv) void drm_prime_init_file_private(struct drm_prime_file_private *prime_fpriv)
{ {
INIT_LIST_HEAD(&prime_fpriv->head);
mutex_init(&prime_fpriv->lock); mutex_init(&prime_fpriv->lock);
prime_fpriv->dmabufs = RB_ROOT;
prime_fpriv->handles = RB_ROOT;
} }
void drm_prime_destroy_file_private(struct drm_prime_file_private *prime_fpriv) void drm_prime_destroy_file_private(struct drm_prime_file_private *prime_fpriv)
{ {
/* by now drm_gem_release should've made sure the list is empty */ /* by now drm_gem_release should've made sure the list is empty */
WARN_ON(!list_empty(&prime_fpriv->head)); WARN_ON(!RB_EMPTY_ROOT(&prime_fpriv->dmabufs));
} }
...@@ -12654,22 +12654,22 @@ static void ...@@ -12654,22 +12654,22 @@ static void
connected_sink_compute_bpp(struct intel_connector *connector, connected_sink_compute_bpp(struct intel_connector *connector,
struct intel_crtc_state *pipe_config) struct intel_crtc_state *pipe_config)
{ {
const struct drm_display_info *info = &connector->base.display_info;
int bpp = pipe_config->pipe_bpp; int bpp = pipe_config->pipe_bpp;
DRM_DEBUG_KMS("[CONNECTOR:%d:%s] checking for sink bpp constrains\n", DRM_DEBUG_KMS("[CONNECTOR:%d:%s] checking for sink bpp constrains\n",
connector->base.base.id, connector->base.base.id,
connector->base.name); connector->base.name);
/* Don't use an invalid EDID bpc value */ /* Don't use an invalid EDID bpc value */
if (connector->base.display_info.bpc && if (info->bpc != 0 && info->bpc * 3 < bpp) {
connector->base.display_info.bpc * 3 < bpp) {
DRM_DEBUG_KMS("clamping display bpp (was %d) to EDID reported max of %d\n", DRM_DEBUG_KMS("clamping display bpp (was %d) to EDID reported max of %d\n",
bpp, connector->base.display_info.bpc*3); bpp, info->bpc * 3);
pipe_config->pipe_bpp = connector->base.display_info.bpc*3; pipe_config->pipe_bpp = info->bpc * 3;
} }
/* Clamp bpp to 8 on screens without EDID 1.4 */ /* Clamp bpp to 8 on screens without EDID 1.4 */
if (connector->base.display_info.bpc == 0 && bpp > 24) { if (info->bpc == 0 && bpp > 24) {
DRM_DEBUG_KMS("clamping display bpp (was %d) to default limit of 24\n", DRM_DEBUG_KMS("clamping display bpp (was %d) to default limit of 24\n",
bpp); bpp);
pipe_config->pipe_bpp = 24; pipe_config->pipe_bpp = 24;
......
...@@ -1220,10 +1220,17 @@ static int hdmi_port_clock_limit(struct intel_hdmi *hdmi, ...@@ -1220,10 +1220,17 @@ static int hdmi_port_clock_limit(struct intel_hdmi *hdmi,
int max_tmds_clock = intel_hdmi_source_max_tmds_clock(to_i915(dev)); int max_tmds_clock = intel_hdmi_source_max_tmds_clock(to_i915(dev));
if (respect_downstream_limits) { if (respect_downstream_limits) {
struct intel_connector *connector = hdmi->attached_connector;
const struct drm_display_info *info = &connector->base.display_info;
if (hdmi->dp_dual_mode.max_tmds_clock) if (hdmi->dp_dual_mode.max_tmds_clock)
max_tmds_clock = min(max_tmds_clock, max_tmds_clock = min(max_tmds_clock,
hdmi->dp_dual_mode.max_tmds_clock); hdmi->dp_dual_mode.max_tmds_clock);
if (!hdmi->has_hdmi_sink)
if (info->max_tmds_clock)
max_tmds_clock = min(max_tmds_clock,
info->max_tmds_clock);
else if (!hdmi->has_hdmi_sink)
max_tmds_clock = min(max_tmds_clock, 165000); max_tmds_clock = min(max_tmds_clock, 165000);
} }
......
...@@ -1086,20 +1086,20 @@ static int mtk_hdmi_output_init(struct mtk_hdmi *hdmi) ...@@ -1086,20 +1086,20 @@ static int mtk_hdmi_output_init(struct mtk_hdmi *hdmi)
return 0; return 0;
} }
void mtk_hdmi_audio_enable(struct mtk_hdmi *hdmi) static void mtk_hdmi_audio_enable(struct mtk_hdmi *hdmi)
{ {
mtk_hdmi_aud_enable_packet(hdmi, true); mtk_hdmi_aud_enable_packet(hdmi, true);
hdmi->audio_enable = true; hdmi->audio_enable = true;
} }
void mtk_hdmi_audio_disable(struct mtk_hdmi *hdmi) static void mtk_hdmi_audio_disable(struct mtk_hdmi *hdmi)
{ {
mtk_hdmi_aud_enable_packet(hdmi, false); mtk_hdmi_aud_enable_packet(hdmi, false);
hdmi->audio_enable = false; hdmi->audio_enable = false;
} }
int mtk_hdmi_audio_set_param(struct mtk_hdmi *hdmi, static int mtk_hdmi_audio_set_param(struct mtk_hdmi *hdmi,
struct hdmi_audio_param *param) struct hdmi_audio_param *param)
{ {
if (!hdmi->audio_enable) { if (!hdmi->audio_enable) {
dev_err(hdmi->dev, "hdmi audio is in disable state!\n"); dev_err(hdmi->dev, "hdmi audio is in disable state!\n");
...@@ -1624,7 +1624,8 @@ static void mtk_hdmi_audio_shutdown(struct device *dev, void *data) ...@@ -1624,7 +1624,8 @@ static void mtk_hdmi_audio_shutdown(struct device *dev, void *data)
mtk_hdmi_audio_disable(hdmi); mtk_hdmi_audio_disable(hdmi);
} }
int mtk_hdmi_audio_digital_mute(struct device *dev, void *data, bool enable) static int
mtk_hdmi_audio_digital_mute(struct device *dev, void *data, bool enable)
{ {
struct mtk_hdmi *hdmi = dev_get_drvdata(dev); struct mtk_hdmi *hdmi = dev_get_drvdata(dev);
......
...@@ -198,12 +198,12 @@ int radeon_get_monitor_bpc(struct drm_connector *connector) ...@@ -198,12 +198,12 @@ int radeon_get_monitor_bpc(struct drm_connector *connector)
} }
/* Any defined maximum tmds clock limit we must not exceed? */ /* Any defined maximum tmds clock limit we must not exceed? */
if (connector->max_tmds_clock > 0) { if (connector->display_info.max_tmds_clock > 0) {
/* mode_clock is clock in kHz for mode to be modeset on this connector */ /* mode_clock is clock in kHz for mode to be modeset on this connector */
mode_clock = radeon_connector->pixelclock_for_modeset; mode_clock = radeon_connector->pixelclock_for_modeset;
/* Maximum allowable input clock in kHz */ /* Maximum allowable input clock in kHz */
max_tmds_clock = connector->max_tmds_clock * 1000; max_tmds_clock = connector->display_info.max_tmds_clock;
DRM_DEBUG("%s: hdmi mode dotclock %d kHz, max tmds input clock %d kHz.\n", DRM_DEBUG("%s: hdmi mode dotclock %d kHz, max tmds input clock %d kHz.\n",
connector->name, mode_clock, max_tmds_clock); connector->name, mode_clock, max_tmds_clock);
......
...@@ -85,6 +85,9 @@ static void analogix_dp_psr_set(struct drm_encoder *encoder, bool enabled) ...@@ -85,6 +85,9 @@ static void analogix_dp_psr_set(struct drm_encoder *encoder, bool enabled)
struct rockchip_dp_device *dp = to_dp(encoder); struct rockchip_dp_device *dp = to_dp(encoder);
unsigned long flags; unsigned long flags;
if (!analogix_dp_psr_supported(dp->dev))
return;
dev_dbg(dp->dev, "%s PSR...\n", enabled ? "Entry" : "Exit"); dev_dbg(dp->dev, "%s PSR...\n", enabled ? "Entry" : "Exit");
spin_lock_irqsave(&dp->psr_lock, flags); spin_lock_irqsave(&dp->psr_lock, flags);
......
...@@ -309,7 +309,7 @@ static struct drm_driver rockchip_drm_driver = { ...@@ -309,7 +309,7 @@ static struct drm_driver rockchip_drm_driver = {
}; };
#ifdef CONFIG_PM_SLEEP #ifdef CONFIG_PM_SLEEP
void rockchip_drm_fb_suspend(struct drm_device *drm) static void rockchip_drm_fb_suspend(struct drm_device *drm)
{ {
struct rockchip_drm_private *priv = drm->dev_private; struct rockchip_drm_private *priv = drm->dev_private;
...@@ -318,7 +318,7 @@ void rockchip_drm_fb_suspend(struct drm_device *drm) ...@@ -318,7 +318,7 @@ void rockchip_drm_fb_suspend(struct drm_device *drm)
console_unlock(); console_unlock();
} }
void rockchip_drm_fb_resume(struct drm_device *drm) static void rockchip_drm_fb_resume(struct drm_device *drm)
{ {
struct rockchip_drm_private *priv = drm->dev_private; struct rockchip_drm_private *priv = drm->dev_private;
......
...@@ -20,6 +20,7 @@ ...@@ -20,6 +20,7 @@
#include "rockchip_drm_drv.h" #include "rockchip_drm_drv.h"
#include "rockchip_drm_gem.h" #include "rockchip_drm_gem.h"
#include "rockchip_drm_fb.h" #include "rockchip_drm_fb.h"
#include "rockchip_drm_fbdev.h"
#define PREFERRED_BPP 32 #define PREFERRED_BPP 32
#define to_drm_private(x) \ #define to_drm_private(x) \
......
...@@ -38,6 +38,7 @@ struct analogix_dp_plat_data { ...@@ -38,6 +38,7 @@ struct analogix_dp_plat_data {
struct drm_connector *); struct drm_connector *);
}; };
int analogix_dp_psr_supported(struct device *dev);
int analogix_dp_enable_psr(struct device *dev); int analogix_dp_enable_psr(struct device *dev);
int analogix_dp_disable_psr(struct device *dev); int analogix_dp_disable_psr(struct device *dev);
......
...@@ -51,6 +51,7 @@ ...@@ -51,6 +51,7 @@
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/poll.h> #include <linux/poll.h>
#include <linux/ratelimit.h> #include <linux/ratelimit.h>
#include <linux/rbtree.h>
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/types.h> #include <linux/types.h>
...@@ -140,9 +141,8 @@ void drm_dev_printk(const struct device *dev, const char *level, ...@@ -140,9 +141,8 @@ void drm_dev_printk(const struct device *dev, const char *level,
unsigned int category, const char *function_name, unsigned int category, const char *function_name,
const char *prefix, const char *format, ...); const char *prefix, const char *format, ...);
extern __printf(5, 6) extern __printf(3, 4)
void drm_printk(const char *level, unsigned int category, void drm_printk(const char *level, unsigned int category,
const char *function_name, const char *prefix,
const char *format, ...); const char *format, ...);
/***********************************************************************/ /***********************************************************************/
...@@ -198,8 +198,7 @@ void drm_printk(const char *level, unsigned int category, ...@@ -198,8 +198,7 @@ void drm_printk(const char *level, unsigned int category,
drm_dev_printk(dev, KERN_ERR, DRM_UT_NONE, __func__, " *ERROR*",\ drm_dev_printk(dev, KERN_ERR, DRM_UT_NONE, __func__, " *ERROR*",\
fmt, ##__VA_ARGS__) fmt, ##__VA_ARGS__)
#define DRM_ERROR(fmt, ...) \ #define DRM_ERROR(fmt, ...) \
drm_printk(KERN_ERR, DRM_UT_NONE, __func__, " *ERROR*", fmt, \ drm_printk(KERN_ERR, DRM_UT_NONE, fmt, ##__VA_ARGS__)
##__VA_ARGS__)
/** /**
* Rate limited error output. Like DRM_ERROR() but won't flood the log. * Rate limited error output. Like DRM_ERROR() but won't flood the log.
...@@ -241,38 +240,38 @@ void drm_printk(const char *level, unsigned int category, ...@@ -241,38 +240,38 @@ void drm_printk(const char *level, unsigned int category,
#define DRM_DEV_DEBUG(dev, fmt, args...) \ #define DRM_DEV_DEBUG(dev, fmt, args...) \
drm_dev_printk(dev, KERN_DEBUG, DRM_UT_CORE, __func__, "", fmt, \ drm_dev_printk(dev, KERN_DEBUG, DRM_UT_CORE, __func__, "", fmt, \
##args) ##args)
#define DRM_DEBUG(fmt, args...) \ #define DRM_DEBUG(fmt, ...) \
drm_printk(KERN_DEBUG, DRM_UT_CORE, __func__, "", fmt, ##args) drm_printk(KERN_DEBUG, DRM_UT_CORE, fmt, ##__VA_ARGS__)
#define DRM_DEV_DEBUG_DRIVER(dev, fmt, args...) \ #define DRM_DEV_DEBUG_DRIVER(dev, fmt, args...) \
drm_dev_printk(dev, KERN_DEBUG, DRM_UT_DRIVER, __func__, "", \ drm_dev_printk(dev, KERN_DEBUG, DRM_UT_DRIVER, __func__, "", \
fmt, ##args) fmt, ##args)
#define DRM_DEBUG_DRIVER(fmt, args...) \ #define DRM_DEBUG_DRIVER(fmt, ...) \
drm_printk(KERN_DEBUG, DRM_UT_DRIVER, __func__, "", fmt, ##args) drm_printk(KERN_DEBUG, DRM_UT_DRIVER, fmt, ##__VA_ARGS__)
#define DRM_DEV_DEBUG_KMS(dev, fmt, args...) \ #define DRM_DEV_DEBUG_KMS(dev, fmt, args...) \
drm_dev_printk(dev, KERN_DEBUG, DRM_UT_KMS, __func__, "", fmt, \ drm_dev_printk(dev, KERN_DEBUG, DRM_UT_KMS, __func__, "", fmt, \
##args) ##args)
#define DRM_DEBUG_KMS(fmt, args...) \ #define DRM_DEBUG_KMS(fmt, ...) \
drm_printk(KERN_DEBUG, DRM_UT_KMS, __func__, "", fmt, ##args) drm_printk(KERN_DEBUG, DRM_UT_KMS, fmt, ##__VA_ARGS__)
#define DRM_DEV_DEBUG_PRIME(dev, fmt, args...) \ #define DRM_DEV_DEBUG_PRIME(dev, fmt, args...) \
drm_dev_printk(dev, KERN_DEBUG, DRM_UT_PRIME, __func__, "", \ drm_dev_printk(dev, KERN_DEBUG, DRM_UT_PRIME, __func__, "", \
fmt, ##args) fmt, ##args)
#define DRM_DEBUG_PRIME(fmt, args...) \ #define DRM_DEBUG_PRIME(fmt, ...) \
drm_printk(KERN_DEBUG, DRM_UT_PRIME, __func__, "", fmt, ##args) drm_printk(KERN_DEBUG, DRM_UT_PRIME, fmt, ##__VA_ARGS__)
#define DRM_DEV_DEBUG_ATOMIC(dev, fmt, args...) \ #define DRM_DEV_DEBUG_ATOMIC(dev, fmt, args...) \
drm_dev_printk(dev, KERN_DEBUG, DRM_UT_ATOMIC, __func__, "", \ drm_dev_printk(dev, KERN_DEBUG, DRM_UT_ATOMIC, __func__, "", \
fmt, ##args) fmt, ##args)
#define DRM_DEBUG_ATOMIC(fmt, args...) \ #define DRM_DEBUG_ATOMIC(fmt, ...) \
drm_printk(KERN_DEBUG, DRM_UT_ATOMIC, __func__, "", fmt, ##args) drm_printk(KERN_DEBUG, DRM_UT_ATOMIC, fmt, ##__VA_ARGS__)
#define DRM_DEV_DEBUG_VBL(dev, fmt, args...) \ #define DRM_DEV_DEBUG_VBL(dev, fmt, args...) \
drm_dev_printk(dev, KERN_DEBUG, DRM_UT_VBL, __func__, "", fmt, \ drm_dev_printk(dev, KERN_DEBUG, DRM_UT_VBL, __func__, "", fmt, \
##args) ##args)
#define DRM_DEBUG_VBL(fmt, args...) \ #define DRM_DEBUG_VBL(fmt, ...) \
drm_printk(KERN_DEBUG, DRM_UT_VBL, __func__, "", fmt, ##args) drm_printk(KERN_DEBUG, DRM_UT_VBL, fmt, ##__VA_ARGS__)
#define _DRM_DEV_DEFINE_DEBUG_RATELIMITED(dev, level, fmt, args...) \ #define _DRM_DEV_DEFINE_DEBUG_RATELIMITED(dev, level, fmt, args...) \
({ \ ({ \
...@@ -371,10 +370,10 @@ struct drm_pending_event { ...@@ -371,10 +370,10 @@ struct drm_pending_event {
we deliver the event, for tracing only */ we deliver the event, for tracing only */
}; };
/* initial implementaton using a linked list - todo hashtab */
struct drm_prime_file_private { struct drm_prime_file_private {
struct list_head head;
struct mutex lock; struct mutex lock;
struct rb_root dmabufs;
struct rb_root handles;
}; };
/** File private data */ /** File private data */
......
...@@ -166,6 +166,17 @@ struct drm_display_info { ...@@ -166,6 +166,17 @@ struct drm_display_info {
*/ */
u32 bus_flags; u32 bus_flags;
/**
* @max_tmds_clock: Maximum TMDS clock rate supported by the
* sink in kHz. 0 means undefined.
*/
int max_tmds_clock;
/**
* @dvi_dual: Dual-link DVI sink?
*/
bool dvi_dual;
/** /**
* @edid_hdmi_dc_modes: Mask of supported hdmi deep color modes. Even * @edid_hdmi_dc_modes: Mask of supported hdmi deep color modes. Even
* more stuff redundant with @bus_formats. * more stuff redundant with @bus_formats.
...@@ -515,8 +526,6 @@ struct drm_cmdline_mode { ...@@ -515,8 +526,6 @@ struct drm_cmdline_mode {
* @encoder_ids: valid encoders for this connector * @encoder_ids: valid encoders for this connector
* @encoder: encoder driving this connector, if any * @encoder: encoder driving this connector, if any
* @eld: EDID-like data, if present * @eld: EDID-like data, if present
* @dvi_dual: dual link DVI, if found
* @max_tmds_clock: max clock rate, if found
* @latency_present: AV delay info from ELD, if found * @latency_present: AV delay info from ELD, if found
* @video_latency: video latency info from ELD, if found * @video_latency: video latency info from ELD, if found
* @audio_latency: audio latency info from ELD, if found * @audio_latency: audio latency info from ELD, if found
...@@ -650,8 +659,6 @@ struct drm_connector { ...@@ -650,8 +659,6 @@ struct drm_connector {
#define MAX_ELD_BYTES 128 #define MAX_ELD_BYTES 128
/* EDID bits */ /* EDID bits */
uint8_t eld[MAX_ELD_BYTES]; uint8_t eld[MAX_ELD_BYTES];
bool dvi_dual;
int max_tmds_clock; /* in MHz */
bool latency_present[2]; bool latency_present[2];
int video_latency[2]; /* [0]: progressive, [1]: interlaced */ int video_latency[2]; /* [0]: progressive, [1]: interlaced */
int audio_latency[2]; int audio_latency[2];
......
...@@ -109,8 +109,6 @@ struct drm_plane_helper_funcs; ...@@ -109,8 +109,6 @@ struct drm_plane_helper_funcs;
* @ctm: Transformation matrix * @ctm: Transformation matrix
* @gamma_lut: Lookup table for converting pixel data after the * @gamma_lut: Lookup table for converting pixel data after the
* conversion matrix * conversion matrix
* @event: optional pointer to a DRM event to signal upon completion of the
* state update
* @state: backpointer to global drm_atomic_state * @state: backpointer to global drm_atomic_state
* *
* Note that the distinction between @enable and @active is rather subtile: * Note that the distinction between @enable and @active is rather subtile:
...@@ -159,6 +157,46 @@ struct drm_crtc_state { ...@@ -159,6 +157,46 @@ struct drm_crtc_state {
struct drm_property_blob *ctm; struct drm_property_blob *ctm;
struct drm_property_blob *gamma_lut; struct drm_property_blob *gamma_lut;
/**
* @event:
*
* Optional pointer to a DRM event to signal upon completion of the
* state update. The driver must send out the event when the atomic
* commit operation completes. There are two cases:
*
* - The event is for a CRTC which is being disabled through this
* atomic commit. In that case the event can be send out any time
* after the hardware has stopped scanning out the current
* framebuffers. It should contain the timestamp and counter for the
* last vblank before the display pipeline was shut off.
*
* - For a CRTC which is enabled at the end of the commit (even when it
* undergoes an full modeset) the vblank timestamp and counter must
* be for the vblank right before the first frame that scans out the
* new set of buffers. Again the event can only be sent out after the
* hardware has stopped scanning out the old buffers.
*
* - Events for disabled CRTCs are not allowed, and drivers can ignore
* that case.
*
* This can be handled by the drm_crtc_send_vblank_event() function,
* which the driver should call on the provided event upon completion of
* the atomic commit. Note that if the driver supports vblank signalling
* and timestamping the vblank counters and timestamps must agree with
* the ones returned from page flip events. With the current vblank
* helper infrastructure this can be achieved by holding a vblank
* reference while the page flip is pending, acquired through
* drm_crtc_vblank_get() and released with drm_crtc_vblank_put().
* Drivers are free to implement their own vblank counter and timestamp
* tracking though, e.g. if they have accurate timestamp registers in
* hardware.
*
* For hardware which supports some means to synchronize vblank
* interrupt delivery with committing display state there's also
* drm_crtc_arm_vblank_event(). See the documentation of that function
* for a detailed discussion of the constraints it needs to be used
* safely.
*/
struct drm_pending_vblank_event *event; struct drm_pending_vblank_event *event;
struct drm_atomic_state *state; struct drm_atomic_state *state;
...@@ -835,17 +873,9 @@ struct drm_mode_config_funcs { ...@@ -835,17 +873,9 @@ struct drm_mode_config_funcs {
* CRTC index supplied in &drm_event to userspace. * CRTC index supplied in &drm_event to userspace.
* *
* The drm core will supply a struct &drm_event in the event * The drm core will supply a struct &drm_event in the event
* member of each CRTC's &drm_crtc_state structure. This can be handled by the * member of each CRTC's &drm_crtc_state structure. See the
* drm_crtc_send_vblank_event() function, which the driver should call on * documentation for &drm_crtc_state for more details about the precise
* the provided event upon completion of the atomic commit. Note that if * semantics of this event.
* the driver supports vblank signalling and timestamping the vblank
* counters and timestamps must agree with the ones returned from page
* flip events. With the current vblank helper infrastructure this can
* be achieved by holding a vblank reference while the page flip is
* pending, acquired through drm_crtc_vblank_get() and released with
* drm_crtc_vblank_put(). Drivers are free to implement their own vblank
* counter and timestamp tracking though, e.g. if they have accurate
* timestamp registers in hardware.
* *
* NOTE: * NOTE:
* *
......
...@@ -217,6 +217,19 @@ struct drm_fb_helper { ...@@ -217,6 +217,19 @@ struct drm_fb_helper {
bool delayed_hotplug; bool delayed_hotplug;
}; };
/**
* @DRM_FB_HELPER_DEFAULT_OPS:
*
* Helper define to register default implementations of drm_fb_helper
* functions. To be used in struct fb_ops of drm drivers.
*/
#define DRM_FB_HELPER_DEFAULT_OPS \
.fb_check_var = drm_fb_helper_check_var, \
.fb_set_par = drm_fb_helper_set_par, \
.fb_setcmap = drm_fb_helper_setcmap, \
.fb_blank = drm_fb_helper_blank, \
.fb_pan_display = drm_fb_helper_pan_display
#ifdef CONFIG_DRM_FBDEV_EMULATION #ifdef CONFIG_DRM_FBDEV_EMULATION
void drm_fb_helper_prepare(struct drm_device *dev, struct drm_fb_helper *helper, void drm_fb_helper_prepare(struct drm_device *dev, struct drm_fb_helper *helper,
const struct drm_fb_helper_funcs *funcs); const struct drm_fb_helper_funcs *funcs);
......
...@@ -396,6 +396,7 @@ header-y += string.h ...@@ -396,6 +396,7 @@ header-y += string.h
header-y += suspend_ioctls.h header-y += suspend_ioctls.h
header-y += swab.h header-y += swab.h
header-y += synclink.h header-y += synclink.h
header-y += sync_file.h
header-y += sysctl.h header-y += sysctl.h
header-y += sysinfo.h header-y += sysinfo.h
header-y += target_core_user.h header-y += target_core_user.h
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment