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)
}
/* 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 = amdgpu_connector->pixelclock_for_modeset;
/* 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",
connector->name, mode_clock, max_tmds_clock);
......
......@@ -98,6 +98,14 @@ static int analogix_dp_detect_hpd(struct analogix_dp_device *dp)
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)
{
struct analogix_dp_device *dp = dev_get_drvdata(dev);
......
......@@ -89,7 +89,6 @@ void drm_dev_printk(const struct device *dev, const char *level,
EXPORT_SYMBOL(drm_dev_printk);
void drm_printk(const char *level, unsigned int category,
const char *function_name, const char *prefix,
const char *format, ...)
{
struct va_format vaf;
......@@ -102,7 +101,9 @@ void drm_printk(const char *level, unsigned int category,
vaf.fmt = format;
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);
}
......
......@@ -3253,16 +3253,12 @@ static void fixup_detailed_cea_mode_clock(struct drm_display_mode *mode)
}
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);
if (len >= 6) {
if (len >= 6)
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) {
connector->latency_present[0] = db[8] >> 7;
connector->latency_present[1] = (db[8] >> 6) & 1;
......@@ -3276,15 +3272,11 @@ parse_hdmi_vsdb(struct drm_connector *connector, const u8 *db)
if (len >= 12)
connector->audio_latency[1] = db[12];
DRM_DEBUG_KMS("HDMI: DVI dual %d, "
"max TMDS clock %d, "
"latency present %d %d, "
DRM_DEBUG_KMS("HDMI: latency present %d %d, "
"video latency %d %d, "
"audio latency %d %d\n",
connector->dvi_dual,
connector->max_tmds_clock,
(int) connector->latency_present[0],
(int) connector->latency_present[1],
connector->latency_present[0],
connector->latency_present[1],
connector->video_latency[0],
connector->video_latency[1],
connector->audio_latency[0],
......@@ -3358,6 +3350,13 @@ void drm_edid_to_eld(struct drm_connector *connector, struct edid *edid)
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);
if (!cea) {
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)
case VENDOR_BLOCK:
/* HDMI Vendor-Specific Data Block */
if (cea_db_is_hdmi_vsdb(db))
parse_hdmi_vsdb(connector, db);
drm_parse_hdmi_vsdb_audio(connector, db);
break;
default:
break;
......@@ -3721,38 +3720,17 @@ bool drm_rgb_quant_range_selectable(struct edid *edid)
}
EXPORT_SYMBOL(drm_rgb_quant_range_selectable);
/*
* Parse the CEA extension according to CEA-861-B.
* 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)
static void drm_parse_hdmi_deep_color_info(struct drm_connector *connector,
const u8 *hdmi)
{
u8 *edid_ext, *hdmi;
int i;
int start_offset, end_offset;
struct drm_display_info *info = &connector->display_info;
unsigned int dc_bpc = 0;
edid_ext = drm_find_cea_extension(edid);
if (!edid_ext)
return false;
if (cea_db_offsets(edid_ext, &start_offset, &end_offset))
return false;
/*
* Because HDMI identifier is in Vendor Specific Block,
* search it from all data blocks of CEA extension.
*/
for_each_cea_db(edid_ext, i, start_offset, end_offset) {
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;
return;
if (hdmi[6] & DRM_EDID_HDMI_DC_30) {
dc_bpc = 10;
......@@ -3775,7 +3753,12 @@ static bool drm_assign_hdmi_deep_color_info(struct edid *edid,
connector->name);
}
if (dc_bpc > 0) {
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;
......@@ -3802,41 +3785,38 @@ static bool drm_assign_hdmi_deep_color_info(struct edid *edid,
DRM_DEBUG("%s: HDMI sink should do DC_36, but does not!\n",
connector->name);
}
return true;
}
else {
DRM_DEBUG("%s: No deep color support on this HDMI sink.\n",
connector->name);
}
}
}
return false;
}
static void drm_add_display_info(struct edid *edid,
struct drm_display_info *info,
struct drm_connector *connector)
static void
drm_parse_hdmi_vsdb_video(struct drm_connector *connector, const u8 *db)
{
u8 *edid_ext;
struct drm_display_info *info = &connector->display_info;
u8 len = cea_db_payload_len(db);
info->width_mm = edid->width_cm * 10;
info->height_mm = edid->height_cm * 10;
if (len >= 6)
info->dvi_dual = db[6] & 1;
if (len >= 7)
info->max_tmds_clock = db[7] * 5000;
/* driver figures it out in this case */
info->bpc = 0;
info->color_formats = 0;
DRM_DEBUG_KMS("HDMI: DVI dual %d, "
"max TMDS clock %d kHz\n",
info->dvi_dual,
info->max_tmds_clock);
if (edid->revision < 3)
return;
drm_parse_hdmi_deep_color_info(connector, db);
}
if (!(edid->input & DRM_EDID_INPUT_DIGITAL))
return;
static void drm_parse_cea_ext(struct drm_connector *connector,
struct edid *edid)
{
struct drm_display_info *info = &connector->display_info;
const u8 *edid_ext;
int i, start, end;
/* Get data from CEA blocks if present */
edid_ext = drm_find_cea_extension(edid);
if (edid_ext) {
if (!edid_ext)
return;
info->cea_rev = edid_ext[1];
/* The existence of a CEA block should imply RGB support */
......@@ -3845,10 +3825,40 @@ static void drm_add_display_info(struct edid *edid,
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->height_mm = edid->height_cm * 10;
/* driver figures it out in this case */
info->bpc = 0;
info->color_formats = 0;
info->cea_rev = 0;
info->max_tmds_clock = 0;
info->dvi_dual = false;
if (edid->revision < 3)
return;
if (!(edid->input & DRM_EDID_INPUT_DIGITAL))
return;
/* HDMI deep color modes supported? Assign to info, if so */
drm_assign_hdmi_deep_color_info(edid, info, connector);
drm_parse_cea_ext(connector, edid);
/*
* 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)
if (quirks & (EDID_QUIRK_PREFER_LARGE_60 | EDID_QUIRK_PREFER_LARGE_75))
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)
connector->display_info.bpc = 6;
......
......@@ -1008,6 +1008,31 @@ static void send_vblank_event(struct drm_device *dev,
* period. This helper function implements exactly the required vblank arming
* 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
* the event @e, which will be dropped when the next vblank arrives.
*/
......@@ -1030,8 +1055,11 @@ EXPORT_SYMBOL(drm_crtc_arm_vblank_event);
* @crtc: the source CRTC of the vblank event
* @e: the event to send
*
* Updates sequence # and timestamp on event, and sends it to userspace.
* Caller must hold event lock.
* Updates sequence # and timestamp on event for the most recently processed
* 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,
struct drm_pending_vblank_event *e)
......
......@@ -28,6 +28,7 @@
#include <linux/export.h>
#include <linux/dma-buf.h>
#include <linux/rbtree.h>
#include <drm/drmP.h>
#include <drm/drm_gem.h>
......@@ -61,9 +62,11 @@
*/
struct drm_prime_member {
struct list_head entry;
struct dma_buf *dma_buf;
uint32_t handle;
struct rb_node dmabuf_rb;
struct rb_node handle_rb;
};
struct drm_prime_attachment {
......@@ -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 drm_prime_member *member;
struct rb_node **p, *rb;
member = kmalloc(sizeof(*member), GFP_KERNEL);
if (!member)
......@@ -83,18 +87,56 @@ static int drm_prime_add_buf_handle(struct drm_prime_file_private *prime_fpriv,
get_dma_buf(dma_buf);
member->dma_buf = dma_buf;
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;
}
static struct dma_buf *drm_prime_lookup_buf_by_handle(struct drm_prime_file_private *prime_fpriv,
uint32_t handle)
{
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)
return member->dma_buf;
else if (member->handle < handle)
rb = rb->rb_right;
else
rb = rb->rb_left;
}
return NULL;
......@@ -104,14 +146,23 @@ static int drm_prime_lookup_buf_handle(struct drm_prime_file_private *prime_fpri
struct dma_buf *dma_buf,
uint32_t *handle)
{
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) {
*handle = member->handle;
return 0;
} else if (member->dma_buf < dma_buf) {
rb = rb->rb_right;
} else {
rb = rb->rb_left;
}
}
return -ENOENT;
}
......@@ -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,
struct dma_buf *dma_buf)
{
struct drm_prime_member *member, *safe;
struct rb_node *rb;
rb = prime_fpriv->dmabufs.rb_node;
while (rb) {
struct drm_prime_member *member;
list_for_each_entry_safe(member, safe, &prime_fpriv->head, entry) {
member = rb_entry(rb, struct drm_prime_member, dmabuf_rb);
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);
list_del(&member->entry);
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);
void drm_prime_init_file_private(struct drm_prime_file_private *prime_fpriv)
{
INIT_LIST_HEAD(&prime_fpriv->head);
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)
{
/* 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,6 +12654,7 @@ static void
connected_sink_compute_bpp(struct intel_connector *connector,
struct intel_crtc_state *pipe_config)
{
const struct drm_display_info *info = &connector->base.display_info;
int bpp = pipe_config->pipe_bpp;
DRM_DEBUG_KMS("[CONNECTOR:%d:%s] checking for sink bpp constrains\n",
......@@ -12661,15 +12662,14 @@ connected_sink_compute_bpp(struct intel_connector *connector,
connector->base.name);
/* Don't use an invalid EDID bpc value */
if (connector->base.display_info.bpc &&
connector->base.display_info.bpc * 3 < bpp) {
if (info->bpc != 0 && info->bpc * 3 < bpp) {
DRM_DEBUG_KMS("clamping display bpp (was %d) to EDID reported max of %d\n",
bpp, connector->base.display_info.bpc*3);
pipe_config->pipe_bpp = connector->base.display_info.bpc*3;
bpp, info->bpc * 3);
pipe_config->pipe_bpp = info->bpc * 3;
}
/* 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",
bpp);
pipe_config->pipe_bpp = 24;
......
......@@ -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));
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)
max_tmds_clock = min(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);
}
......
......@@ -1086,19 +1086,19 @@ static int mtk_hdmi_output_init(struct mtk_hdmi *hdmi)
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);
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);
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)
{
if (!hdmi->audio_enable) {
......@@ -1624,7 +1624,8 @@ static void mtk_hdmi_audio_shutdown(struct device *dev, void *data)
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);
......
......@@ -198,12 +198,12 @@ int radeon_get_monitor_bpc(struct drm_connector *connector)
}
/* 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 = radeon_connector->pixelclock_for_modeset;
/* 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",
connector->name, mode_clock, max_tmds_clock);
......
......@@ -85,6 +85,9 @@ static void analogix_dp_psr_set(struct drm_encoder *encoder, bool enabled)
struct rockchip_dp_device *dp = to_dp(encoder);
unsigned long flags;
if (!analogix_dp_psr_supported(dp->dev))
return;
dev_dbg(dp->dev, "%s PSR...\n", enabled ? "Entry" : "Exit");
spin_lock_irqsave(&dp->psr_lock, flags);
......
......@@ -309,7 +309,7 @@ static struct drm_driver rockchip_drm_driver = {
};
#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;
......@@ -318,7 +318,7 @@ void rockchip_drm_fb_suspend(struct drm_device *drm)
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;
......
......@@ -20,6 +20,7 @@
#include "rockchip_drm_drv.h"
#include "rockchip_drm_gem.h"
#include "rockchip_drm_fb.h"
#include "rockchip_drm_fbdev.h"
#define PREFERRED_BPP 32
#define to_drm_private(x) \
......
......@@ -38,6 +38,7 @@ struct analogix_dp_plat_data {
struct drm_connector *);
};
int analogix_dp_psr_supported(struct device *dev);
int analogix_dp_enable_psr(struct device *dev);
int analogix_dp_disable_psr(struct device *dev);
......
......@@ -51,6 +51,7 @@
#include <linux/platform_device.h>
#include <linux/poll.h>
#include <linux/ratelimit.h>
#include <linux/rbtree.h>
#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/types.h>
......@@ -140,9 +141,8 @@ void drm_dev_printk(const struct device *dev, const char *level,
unsigned int category, const char *function_name,
const char *prefix, const char *format, ...);
extern __printf(5, 6)
extern __printf(3, 4)
void drm_printk(const char *level, unsigned int category,
const char *function_name, const char *prefix,
const char *format, ...);
/***********************************************************************/
......@@ -198,8 +198,7 @@ void drm_printk(const char *level, unsigned int category,
drm_dev_printk(dev, KERN_ERR, DRM_UT_NONE, __func__, " *ERROR*",\
fmt, ##__VA_ARGS__)
#define DRM_ERROR(fmt, ...) \
drm_printk(KERN_ERR, DRM_UT_NONE, __func__, " *ERROR*", fmt, \
##__VA_ARGS__)
drm_printk(KERN_ERR, DRM_UT_NONE, fmt, ##__VA_ARGS__)
/**
* 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,
#define DRM_DEV_DEBUG(dev, fmt, args...) \
drm_dev_printk(dev, KERN_DEBUG, DRM_UT_CORE, __func__, "", fmt, \
##args)
#define DRM_DEBUG(fmt, args...) \
drm_printk(KERN_DEBUG, DRM_UT_CORE, __func__, "", fmt, ##args)
#define DRM_DEBUG(fmt, ...) \
drm_printk(KERN_DEBUG, DRM_UT_CORE, fmt, ##__VA_ARGS__)
#define DRM_DEV_DEBUG_DRIVER(dev, fmt, args...) \
drm_dev_printk(dev, KERN_DEBUG, DRM_UT_DRIVER, __func__, "", \
fmt, ##args)
#define DRM_DEBUG_DRIVER(fmt, args...) \
drm_printk(KERN_DEBUG, DRM_UT_DRIVER, __func__, "", fmt, ##args)
#define DRM_DEBUG_DRIVER(fmt, ...) \
drm_printk(KERN_DEBUG, DRM_UT_DRIVER, fmt, ##__VA_ARGS__)
#define DRM_DEV_DEBUG_KMS(dev, fmt, args...) \
drm_dev_printk(dev, KERN_DEBUG, DRM_UT_KMS, __func__, "", fmt, \
##args)
#define DRM_DEBUG_KMS(fmt, args...) \
drm_printk(KERN_DEBUG, DRM_UT_KMS, __func__, "", fmt, ##args)
#define DRM_DEBUG_KMS(fmt, ...) \
drm_printk(KERN_DEBUG, DRM_UT_KMS, fmt, ##__VA_ARGS__)
#define DRM_DEV_DEBUG_PRIME(dev, fmt, args...) \
drm_dev_printk(dev, KERN_DEBUG, DRM_UT_PRIME, __func__, "", \
fmt, ##args)
#define DRM_DEBUG_PRIME(fmt, args...) \
drm_printk(KERN_DEBUG, DRM_UT_PRIME, __func__, "", fmt, ##args)
#define DRM_DEBUG_PRIME(fmt, ...) \
drm_printk(KERN_DEBUG, DRM_UT_PRIME, fmt, ##__VA_ARGS__)
#define DRM_DEV_DEBUG_ATOMIC(dev, fmt, args...) \
drm_dev_printk(dev, KERN_DEBUG, DRM_UT_ATOMIC, __func__, "", \
fmt, ##args)
#define DRM_DEBUG_ATOMIC(fmt, args...) \
drm_printk(KERN_DEBUG, DRM_UT_ATOMIC, __func__, "", fmt, ##args)
#define DRM_DEBUG_ATOMIC(fmt, ...) \
drm_printk(KERN_DEBUG, DRM_UT_ATOMIC, fmt, ##__VA_ARGS__)
#define DRM_DEV_DEBUG_VBL(dev, fmt, args...) \
drm_dev_printk(dev, KERN_DEBUG, DRM_UT_VBL, __func__, "", fmt, \
##args)
#define DRM_DEBUG_VBL(fmt, args...) \
drm_printk(KERN_DEBUG, DRM_UT_VBL, __func__, "", fmt, ##args)
#define DRM_DEBUG_VBL(fmt, ...) \
drm_printk(KERN_DEBUG, DRM_UT_VBL, fmt, ##__VA_ARGS__)
#define _DRM_DEV_DEFINE_DEBUG_RATELIMITED(dev, level, fmt, args...) \
({ \
......@@ -371,10 +370,10 @@ struct drm_pending_event {
we deliver the event, for tracing only */
};
/* initial implementaton using a linked list - todo hashtab */
struct drm_prime_file_private {
struct list_head head;
struct mutex lock;
struct rb_root dmabufs;
struct rb_root handles;
};
/** File private data */
......
......@@ -166,6 +166,17 @@ struct drm_display_info {
*/
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
* more stuff redundant with @bus_formats.
......@@ -515,8 +526,6 @@ struct drm_cmdline_mode {
* @encoder_ids: valid encoders for this connector
* @encoder: encoder driving this connector, if any
* @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
* @video_latency: video latency info from ELD, if found
* @audio_latency: audio latency info from ELD, if found
......@@ -650,8 +659,6 @@ struct drm_connector {
#define MAX_ELD_BYTES 128
/* EDID bits */
uint8_t eld[MAX_ELD_BYTES];
bool dvi_dual;
int max_tmds_clock; /* in MHz */
bool latency_present[2];
int video_latency[2]; /* [0]: progressive, [1]: interlaced */
int audio_latency[2];
......
......@@ -109,8 +109,6 @@ struct drm_plane_helper_funcs;
* @ctm: Transformation matrix
* @gamma_lut: Lookup table for converting pixel data after the
* conversion matrix
* @event: optional pointer to a DRM event to signal upon completion of the
* state update
* @state: backpointer to global drm_atomic_state
*
* Note that the distinction between @enable and @active is rather subtile:
......@@ -159,6 +157,46 @@ struct drm_crtc_state {
struct drm_property_blob *ctm;
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_atomic_state *state;
......@@ -835,17 +873,9 @@ struct drm_mode_config_funcs {
* CRTC index supplied in &drm_event to userspace.
*
* 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
* 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.
* member of each CRTC's &drm_crtc_state structure. See the
* documentation for &drm_crtc_state for more details about the precise
* semantics of this event.
*
* NOTE:
*
......
......@@ -217,6 +217,19 @@ struct drm_fb_helper {
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
void drm_fb_helper_prepare(struct drm_device *dev, struct drm_fb_helper *helper,
const struct drm_fb_helper_funcs *funcs);
......
......@@ -396,6 +396,7 @@ header-y += string.h
header-y += suspend_ioctls.h
header-y += swab.h
header-y += synclink.h
header-y += sync_file.h
header-y += sysctl.h
header-y += sysinfo.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