Commit 1a4be38a authored by Dave Airlie's avatar Dave Airlie

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

* tag 'topic/drm-misc-2016-03-14' of git://anongit.freedesktop.org/drm-intel: (27 commits)
  drm: atomic helper: do not unreference error pointer
  drm/edid: Extract SADs properly from multiple audio data blocks
  drm: fix blob pointer check
  drm: introduce pipe color correction properties
  drm/atomic: Clean up update_connector_routing.
  drm/atomic: Clean up steal_encoder, v2.
  drm/atomic: Handle encoder assignment conflicts in a separate check, v3.
  drm/atomic: Handle encoder stealing from set_config better.
  drm/atomic: Always call steal_encoder, v2.
  drm/ast: removed optional dummy crtc mode_fixup function.
  drm/bochs: removed optional dummy crtc mode_fixup function.
  drm/fsl-dcu: removed optional dummy crtc mode_fixup function.
  drm/virtio: removed optional dummy crtc mode_fixup function.
  drm/nouveau/dispnv04: removed optional dummy crtc mode_fixup function.
  drm/atmel-hlcdc: remove optional dummy crtc mode_fixup function.
  drm/sti: removed optional dummy crtc mode_fixup function.
  drm/shmobile: removed optional dummy crtc mode_fixup function.
  drm/msm/mdp: removed optional dummy crtc mode_fixup function.
  drm/omapdrm: removed optional dummy crtc mode_fixup function.
  drm/rcar-du: removed optional dummy crtc mode_fixup function.
  ...
parents c51e034f c1f415c9
......@@ -1816,7 +1816,7 @@ void intel_crt_init(struct drm_device *dev)
<td valign="top" >Description/Restrictions</td>
</tr>
<tr>
<td rowspan="37" valign="top" >DRM</td>
<td rowspan="42" valign="top" >DRM</td>
<td valign="top" >Generic</td>
<td valign="top" >“rotation”</td>
<td valign="top" >BITMASK</td>
......@@ -2068,7 +2068,7 @@ void intel_crt_init(struct drm_device *dev)
<td valign="top" >property to suggest an Y offset for a connector</td>
</tr>
<tr>
<td rowspan="3" valign="top" >Optional</td>
<td rowspan="8" valign="top" >Optional</td>
<td valign="top" >“scaling mode”</td>
<td valign="top" >ENUM</td>
<td valign="top" >{ "None", "Full", "Center", "Full aspect" }</td>
......@@ -2092,6 +2092,61 @@ void intel_crt_init(struct drm_device *dev)
<td valign="top" >TBD</td>
</tr>
<tr>
<td valign="top" >“DEGAMMA_LUT”</td>
<td valign="top" >BLOB</td>
<td valign="top" >0</td>
<td valign="top" >CRTC</td>
<td valign="top" >DRM property to set the degamma lookup table
(LUT) mapping pixel data from the framebuffer before it is
given to the transformation matrix. The data is an interpreted
as an array of struct drm_color_lut elements. Hardware might
choose not to use the full precision of the LUT elements nor
use all the elements of the LUT (for example the hardware
might choose to interpolate between LUT[0] and LUT[4]). </td>
</tr>
<tr>
<td valign="top" >“DEGAMMA_LUT_SIZE”</td>
<td valign="top" >RANGE | IMMUTABLE</td>
<td valign="top" >Min=0, Max=UINT_MAX</td>
<td valign="top" >CRTC</td>
<td valign="top" >DRM property to gives the size of the lookup
table to be set on the DEGAMMA_LUT property (the size depends
on the underlying hardware).</td>
</tr>
<tr>
<td valign="top" >“CTM”</td>
<td valign="top" >BLOB</td>
<td valign="top" >0</td>
<td valign="top" >CRTC</td>
<td valign="top" >DRM property to set the current
transformation matrix (CTM) apply to pixel data after the
lookup through the degamma LUT and before the lookup through
the gamma LUT. The data is an interpreted as a struct
drm_color_ctm.</td>
</tr>
<tr>
<td valign="top" >“GAMMA_LUT”</td>
<td valign="top" >BLOB</td>
<td valign="top" >0</td>
<td valign="top" >CRTC</td>
<td valign="top" >DRM property to set the gamma lookup table
(LUT) mapping pixel data after to the transformation matrix to
data sent to the connector. The data is an interpreted as an
array of struct drm_color_lut elements. Hardware might choose
not to use the full precision of the LUT elements nor use all
the elements of the LUT (for example the hardware might choose
to interpolate between LUT[0] and LUT[4]).</td>
</tr>
<tr>
<td valign="top" >“GAMMA_LUT_SIZE”</td>
<td valign="top" >RANGE | IMMUTABLE</td>
<td valign="top" >Min=0, Max=UINT_MAX</td>
<td valign="top" >CRTC</td>
<td valign="top" >DRM property to gives the size of the lookup
table to be set on the GAMMA_LUT property (the size depends on
the underlying hardware).</td>
</tr>
<tr>
<td rowspan="20" valign="top" >i915</td>
<td rowspan="2" valign="top" >Generic</td>
<td valign="top" >"Broadcast RGB"</td>
......
......@@ -497,13 +497,6 @@ static void ast_crtc_dpms(struct drm_crtc *crtc, int mode)
}
}
static bool ast_crtc_mode_fixup(struct drm_crtc *crtc,
const struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode)
{
return true;
}
/* ast is different - we will force move buffers out of VRAM */
static int ast_crtc_do_set_base(struct drm_crtc *crtc,
struct drm_framebuffer *fb,
......@@ -617,7 +610,6 @@ static void ast_crtc_commit(struct drm_crtc *crtc)
static const struct drm_crtc_helper_funcs ast_crtc_helper_funcs = {
.dpms = ast_crtc_dpms,
.mode_fixup = ast_crtc_mode_fixup,
.mode_set = ast_crtc_mode_set,
.mode_set_base = ast_crtc_mode_set_base,
.disable = ast_crtc_disable,
......
......@@ -121,13 +121,6 @@ static void atmel_hlcdc_crtc_mode_set_nofb(struct drm_crtc *c)
cfg);
}
static bool atmel_hlcdc_crtc_mode_fixup(struct drm_crtc *crtc,
const struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode)
{
return true;
}
static void atmel_hlcdc_crtc_disable(struct drm_crtc *c)
{
struct drm_device *dev = c->dev;
......@@ -261,7 +254,6 @@ static void atmel_hlcdc_crtc_atomic_flush(struct drm_crtc *crtc,
}
static const struct drm_crtc_helper_funcs lcdc_crtc_helper_funcs = {
.mode_fixup = atmel_hlcdc_crtc_mode_fixup,
.mode_set = drm_helper_crtc_mode_set,
.mode_set_nofb = atmel_hlcdc_crtc_mode_set_nofb,
.mode_set_base = drm_helper_crtc_mode_set_base,
......@@ -349,4 +341,3 @@ int atmel_hlcdc_crtc_create(struct drm_device *dev)
atmel_hlcdc_crtc_destroy(&crtc->base);
return ret;
}
......@@ -30,13 +30,6 @@ static void bochs_crtc_dpms(struct drm_crtc *crtc, int mode)
}
}
static bool bochs_crtc_mode_fixup(struct drm_crtc *crtc,
const struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode)
{
return true;
}
static int bochs_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
struct drm_framebuffer *old_fb)
{
......@@ -135,7 +128,6 @@ static const struct drm_crtc_funcs bochs_crtc_funcs = {
static const struct drm_crtc_helper_funcs bochs_helper_funcs = {
.dpms = bochs_crtc_dpms,
.mode_fixup = bochs_crtc_mode_fixup,
.mode_set = bochs_crtc_mode_set,
.mode_set_base = bochs_crtc_mode_set_base,
.prepare = bochs_crtc_prepare,
......
......@@ -91,18 +91,6 @@ static void cirrus_crtc_dpms(struct drm_crtc *crtc, int mode)
WREG_GFX(0xe, gr0e);
}
/*
* The core passes the desired mode to the CRTC code to see whether any
* CRTC-specific modifications need to be made to it. We're in a position
* to just pass that straight through, so this does nothing
*/
static bool cirrus_crtc_mode_fixup(struct drm_crtc *crtc,
const struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode)
{
return true;
}
static void cirrus_set_start_address(struct drm_crtc *crtc, unsigned offset)
{
struct cirrus_device *cdev = crtc->dev->dev_private;
......@@ -372,7 +360,6 @@ static const struct drm_crtc_funcs cirrus_crtc_funcs = {
static const struct drm_crtc_helper_funcs cirrus_helper_funcs = {
.dpms = cirrus_crtc_dpms,
.mode_fixup = cirrus_crtc_mode_fixup,
.mode_set = cirrus_crtc_mode_set,
.mode_set_base = cirrus_crtc_mode_set_base,
.prepare = cirrus_crtc_prepare,
......
......@@ -28,6 +28,7 @@
#include <drm/drmP.h>
#include <drm/drm_atomic.h>
#include <drm/drm_mode.h>
#include <drm/drm_plane_helper.h>
/**
......@@ -375,6 +376,59 @@ int drm_atomic_set_mode_prop_for_crtc(struct drm_crtc_state *state,
}
EXPORT_SYMBOL(drm_atomic_set_mode_prop_for_crtc);
/**
* drm_atomic_replace_property_blob - replace a blob property
* @blob: a pointer to the member blob to be replaced
* @new_blob: the new blob to replace with
* @expected_size: the expected size of the new blob
* @replaced: whether the blob has been replaced
*
* RETURNS:
* Zero on success, error code on failure
*/
static void
drm_atomic_replace_property_blob(struct drm_property_blob **blob,
struct drm_property_blob *new_blob,
bool *replaced)
{
struct drm_property_blob *old_blob = *blob;
if (old_blob == new_blob)
return;
if (old_blob)
drm_property_unreference_blob(old_blob);
if (new_blob)
drm_property_reference_blob(new_blob);
*blob = new_blob;
*replaced = true;
return;
}
static int
drm_atomic_replace_property_blob_from_id(struct drm_crtc *crtc,
struct drm_property_blob **blob,
uint64_t blob_id,
ssize_t expected_size,
bool *replaced)
{
struct drm_device *dev = crtc->dev;
struct drm_property_blob *new_blob = NULL;
if (blob_id != 0) {
new_blob = drm_property_lookup_blob(dev, blob_id);
if (new_blob == NULL)
return -EINVAL;
if (expected_size > 0 && expected_size != new_blob->length)
return -EINVAL;
}
drm_atomic_replace_property_blob(blob, new_blob, replaced);
return 0;
}
/**
* drm_atomic_crtc_set_property - set property on CRTC
* @crtc: the drm CRTC to set a property on
......@@ -397,6 +451,7 @@ int drm_atomic_crtc_set_property(struct drm_crtc *crtc,
{
struct drm_device *dev = crtc->dev;
struct drm_mode_config *config = &dev->mode_config;
bool replaced = false;
int ret;
if (property == config->prop_active)
......@@ -407,8 +462,31 @@ int drm_atomic_crtc_set_property(struct drm_crtc *crtc,
ret = drm_atomic_set_mode_prop_for_crtc(state, mode);
drm_property_unreference_blob(mode);
return ret;
}
else if (crtc->funcs->atomic_set_property)
} else if (property == config->degamma_lut_property) {
ret = drm_atomic_replace_property_blob_from_id(crtc,
&state->degamma_lut,
val,
-1,
&replaced);
state->color_mgmt_changed = replaced;
return ret;
} else if (property == config->ctm_property) {
ret = drm_atomic_replace_property_blob_from_id(crtc,
&state->ctm,
val,
sizeof(struct drm_color_ctm),
&replaced);
state->color_mgmt_changed = replaced;
return ret;
} else if (property == config->gamma_lut_property) {
ret = drm_atomic_replace_property_blob_from_id(crtc,
&state->gamma_lut,
val,
-1,
&replaced);
state->color_mgmt_changed = replaced;
return ret;
} else if (crtc->funcs->atomic_set_property)
return crtc->funcs->atomic_set_property(crtc, state, property, val);
else
return -EINVAL;
......@@ -444,6 +522,12 @@ drm_atomic_crtc_get_property(struct drm_crtc *crtc,
*val = state->active;
else if (property == config->prop_mode_id)
*val = (state->mode_blob) ? state->mode_blob->base.id : 0;
else if (property == config->degamma_lut_property)
*val = (state->degamma_lut) ? state->degamma_lut->base.id : 0;
else if (property == config->ctm_property)
*val = (state->ctm) ? state->ctm->base.id : 0;
else if (property == config->gamma_lut_property)
*val = (state->gamma_lut) ? state->gamma_lut->base.id : 0;
else if (crtc->funcs->atomic_get_property)
return crtc->funcs->atomic_get_property(crtc, state, property, val);
else
......
......@@ -86,43 +86,104 @@ drm_atomic_helper_plane_changed(struct drm_atomic_state *state,
}
}
static bool
check_pending_encoder_assignment(struct drm_atomic_state *state,
struct drm_encoder *new_encoder)
static int handle_conflicting_encoders(struct drm_atomic_state *state,
bool disable_conflicting_encoders)
{
struct drm_connector *connector;
struct drm_connector_state *conn_state;
int i;
struct drm_connector *connector;
struct drm_encoder *encoder;
unsigned encoder_mask = 0;
int i, ret;
/*
* First loop, find all newly assigned encoders from the connectors
* part of the state. If the same encoder is assigned to multiple
* connectors bail out.
*/
for_each_connector_in_state(state, connector, conn_state, i) {
if (conn_state->best_encoder != new_encoder)
const struct drm_connector_helper_funcs *funcs = connector->helper_private;
struct drm_encoder *new_encoder;
if (!conn_state->crtc)
continue;
/* encoder already assigned and we're trying to re-steal it! */
if (connector->state->best_encoder != conn_state->best_encoder)
return false;
if (funcs->atomic_best_encoder)
new_encoder = funcs->atomic_best_encoder(connector, conn_state);
else
new_encoder = funcs->best_encoder(connector);
if (new_encoder) {
if (encoder_mask & (1 << drm_encoder_index(new_encoder))) {
DRM_DEBUG_ATOMIC("[ENCODER:%d:%s] on [CONNECTOR:%d:%s] already assigned\n",
new_encoder->base.id, new_encoder->name,
connector->base.id, connector->name);
return -EINVAL;
}
return true;
}
encoder_mask |= 1 << drm_encoder_index(new_encoder);
}
}
static struct drm_crtc *
get_current_crtc_for_encoder(struct drm_device *dev,
struct drm_encoder *encoder)
{
struct drm_mode_config *config = &dev->mode_config;
struct drm_connector *connector;
if (!encoder_mask)
return 0;
WARN_ON(!drm_modeset_is_locked(&config->connection_mutex));
/*
* Second loop, iterate over all connectors not part of the state.
*
* If a conflicting encoder is found and disable_conflicting_encoders
* is not set, an error is returned. Userspace can provide a solution
* through the atomic ioctl.
*
* If the flag is set conflicting connectors are removed from the crtc
* and the crtc is disabled if no encoder is left. This preserves
* compatibility with the legacy set_config behavior.
*/
drm_for_each_connector(connector, state->dev) {
struct drm_crtc_state *crtc_state;
drm_for_each_connector(connector, dev) {
if (connector->state->best_encoder != encoder)
if (drm_atomic_get_existing_connector_state(state, connector))
continue;
return connector->state->crtc;
encoder = connector->state->best_encoder;
if (!encoder || !(encoder_mask & (1 << drm_encoder_index(encoder))))
continue;
if (!disable_conflicting_encoders) {
DRM_DEBUG_ATOMIC("[ENCODER:%d:%s] in use on [CRTC:%d:%s] by [CONNECTOR:%d:%s]\n",
encoder->base.id, encoder->name,
connector->state->crtc->base.id,
connector->state->crtc->name,
connector->base.id, connector->name);
return -EINVAL;
}
return NULL;
conn_state = drm_atomic_get_connector_state(state, connector);
if (IS_ERR(conn_state))
return PTR_ERR(conn_state);
DRM_DEBUG_ATOMIC("[ENCODER:%d:%s] in use on [CRTC:%d:%s], disabling [CONNECTOR:%d:%s]\n",
encoder->base.id, encoder->name,
conn_state->crtc->base.id, conn_state->crtc->name,
connector->base.id, connector->name);
crtc_state = drm_atomic_get_existing_crtc_state(state, conn_state->crtc);
ret = drm_atomic_set_crtc_for_connector(conn_state, NULL);
if (ret)
return ret;
if (!crtc_state->connector_mask) {
ret = drm_atomic_set_mode_prop_for_crtc(crtc_state,
NULL);
if (ret < 0)
return ret;
crtc_state->active = false;
}
}
return 0;
}
static void
......@@ -166,70 +227,44 @@ set_best_encoder(struct drm_atomic_state *state,
conn_state->best_encoder = encoder;
}
static int
static void
steal_encoder(struct drm_atomic_state *state,
struct drm_encoder *encoder,
struct drm_crtc *encoder_crtc)
struct drm_encoder *encoder)
{
struct drm_mode_config *config = &state->dev->mode_config;
struct drm_crtc_state *crtc_state;
struct drm_connector *connector;
struct drm_connector_state *connector_state;
int i;
/*
* We can only steal an encoder coming from a connector, which means we
* must already hold the connection_mutex.
*/
WARN_ON(!drm_modeset_is_locked(&config->connection_mutex));
for_each_connector_in_state(state, connector, connector_state, i) {
struct drm_crtc *encoder_crtc;
if (connector_state->best_encoder != encoder)
continue;
encoder_crtc = connector->state->crtc;
DRM_DEBUG_ATOMIC("[ENCODER:%d:%s] in use on [CRTC:%d:%s], stealing it\n",
encoder->base.id, encoder->name,
encoder_crtc->base.id, encoder_crtc->name);
crtc_state = drm_atomic_get_crtc_state(state, encoder_crtc);
if (IS_ERR(crtc_state))
return PTR_ERR(crtc_state);
set_best_encoder(state, connector_state, NULL);
crtc_state = drm_atomic_get_existing_crtc_state(state, encoder_crtc);
crtc_state->connectors_changed = true;
list_for_each_entry(connector, &config->connector_list, head) {
if (connector->state->best_encoder != encoder)
continue;
DRM_DEBUG_ATOMIC("Stealing encoder from [CONNECTOR:%d:%s]\n",
connector->base.id,
connector->name);
connector_state = drm_atomic_get_connector_state(state,
connector);
if (IS_ERR(connector_state))
return PTR_ERR(connector_state);
if (connector_state->best_encoder != encoder)
continue;
set_best_encoder(state, connector_state, NULL);
return;
}
return 0;
}
static int
update_connector_routing(struct drm_atomic_state *state, int conn_idx)
update_connector_routing(struct drm_atomic_state *state,
struct drm_connector *connector,
struct drm_connector_state *connector_state)
{
const struct drm_connector_helper_funcs *funcs;
struct drm_encoder *new_encoder;
struct drm_crtc *encoder_crtc;
struct drm_connector *connector;
struct drm_connector_state *connector_state;
struct drm_crtc_state *crtc_state;
int idx, ret;
connector = state->connectors[conn_idx];
connector_state = state->connector_states[conn_idx];
if (!connector)
return 0;
DRM_DEBUG_ATOMIC("Updating routing for [CONNECTOR:%d:%s]\n",
connector->base.id,
......@@ -237,16 +272,12 @@ update_connector_routing(struct drm_atomic_state *state, int conn_idx)
if (connector->state->crtc != connector_state->crtc) {
if (connector->state->crtc) {
idx = drm_crtc_index(connector->state->crtc);
crtc_state = state->crtc_states[idx];
crtc_state = drm_atomic_get_existing_crtc_state(state, connector->state->crtc);
crtc_state->connectors_changed = true;
}
if (connector_state->crtc) {
idx = drm_crtc_index(connector_state->crtc);
crtc_state = state->crtc_states[idx];
crtc_state = drm_atomic_get_existing_crtc_state(state, connector_state->crtc);
crtc_state->connectors_changed = true;
}
}
......@@ -298,34 +329,11 @@ update_connector_routing(struct drm_atomic_state *state, int conn_idx)
return 0;
}
if (!check_pending_encoder_assignment(state, new_encoder)) {
DRM_DEBUG_ATOMIC("Encoder for [CONNECTOR:%d:%s] already assigned\n",
connector->base.id,
connector->name);
return -EINVAL;
}
encoder_crtc = get_current_crtc_for_encoder(state->dev,
new_encoder);
if (encoder_crtc) {
ret = steal_encoder(state, new_encoder, encoder_crtc);
if (ret) {
DRM_DEBUG_ATOMIC("Encoder stealing failed for [CONNECTOR:%d:%s]\n",
connector->base.id,
connector->name);
return ret;
}
}
if (WARN_ON(!connector_state->crtc))
return -EINVAL;
steal_encoder(state, new_encoder);
set_best_encoder(state, connector_state, new_encoder);
idx = drm_crtc_index(connector_state->crtc);
crtc_state = state->crtc_states[idx];
crtc_state = drm_atomic_get_existing_crtc_state(state, connector_state->crtc);
crtc_state->connectors_changed = true;
DRM_DEBUG_ATOMIC("[CONNECTOR:%d:%s] using [ENCODER:%d:%s] on [CRTC:%d:%s]\n",
......@@ -488,13 +496,18 @@ drm_atomic_helper_check_modeset(struct drm_device *dev,
}
}
ret = handle_conflicting_encoders(state, state->legacy_set_config);
if (ret)
return ret;
for_each_connector_in_state(state, connector, connector_state, i) {
/*
* This only sets crtc->mode_changed for routing changes,
* drivers must set crtc->mode_changed themselves when connector
* properties need to be updated.
*/
ret = update_connector_routing(state, i);
ret = update_connector_routing(state, connector,
connector_state);
if (ret)
return ret;
}
......@@ -1761,28 +1774,18 @@ static int update_output_state(struct drm_atomic_state *state,
struct drm_crtc_state *crtc_state;
struct drm_connector *connector;
struct drm_connector_state *conn_state;
int ret, i, j;
int ret, i;
ret = drm_modeset_lock(&dev->mode_config.connection_mutex,
state->acquire_ctx);
if (ret)
return ret;
/* First grab all affected connector/crtc states. */
for (i = 0; i < set->num_connectors; i++) {
conn_state = drm_atomic_get_connector_state(state,
set->connectors[i]);
if (IS_ERR(conn_state))
return PTR_ERR(conn_state);
}
for_each_crtc_in_state(state, crtc, crtc_state, i) {
ret = drm_atomic_add_affected_connectors(state, crtc);
/* First disable all connectors on the target crtc. */
ret = drm_atomic_add_affected_connectors(state, set->crtc);
if (ret)
return ret;
}
/* Then recompute connector->crtc links and crtc enabling state. */
for_each_connector_in_state(state, connector, conn_state, i) {
if (conn_state->crtc == set->crtc) {
ret = drm_atomic_set_crtc_for_connector(conn_state,
......@@ -1790,16 +1793,19 @@ static int update_output_state(struct drm_atomic_state *state,
if (ret)
return ret;
}
}
/* Then set all connectors from set->connectors on the target crtc */
for (i = 0; i < set->num_connectors; i++) {
conn_state = drm_atomic_get_connector_state(state,
set->connectors[i]);
if (IS_ERR(conn_state))
return PTR_ERR(conn_state);
for (j = 0; j < set->num_connectors; j++) {
if (set->connectors[j] == connector) {
ret = drm_atomic_set_crtc_for_connector(conn_state,
set->crtc);
if (ret)
return ret;
break;
}
}
}
for_each_crtc_in_state(state, crtc, crtc_state, i) {
......@@ -1842,6 +1848,7 @@ int drm_atomic_helper_set_config(struct drm_mode_set *set)
if (!state)
return -ENOMEM;
state->legacy_set_config = true;
state->acquire_ctx = drm_modeset_legacy_acquire_ctx(crtc);
retry:
ret = __drm_atomic_helper_set_config(set, state);
......@@ -2488,8 +2495,12 @@ EXPORT_SYMBOL(drm_atomic_helper_connector_dpms);
*/
void drm_atomic_helper_crtc_reset(struct drm_crtc *crtc)
{
if (crtc->state)
if (crtc->state) {
drm_property_unreference_blob(crtc->state->mode_blob);
drm_property_unreference_blob(crtc->state->degamma_lut);
drm_property_unreference_blob(crtc->state->ctm);
drm_property_unreference_blob(crtc->state->gamma_lut);
}
kfree(crtc->state);
crtc->state = kzalloc(sizeof(*crtc->state), GFP_KERNEL);
......@@ -2513,10 +2524,17 @@ void __drm_atomic_helper_crtc_duplicate_state(struct drm_crtc *crtc,
if (state->mode_blob)
drm_property_reference_blob(state->mode_blob);
if (state->degamma_lut)
drm_property_reference_blob(state->degamma_lut);
if (state->ctm)
drm_property_reference_blob(state->ctm);
if (state->gamma_lut)
drm_property_reference_blob(state->gamma_lut);
state->mode_changed = false;
state->active_changed = false;
state->planes_changed = false;
state->connectors_changed = false;
state->color_mgmt_changed = false;
state->event = NULL;
}
EXPORT_SYMBOL(__drm_atomic_helper_crtc_duplicate_state);
......@@ -2557,6 +2575,9 @@ void __drm_atomic_helper_crtc_destroy_state(struct drm_crtc *crtc,
struct drm_crtc_state *state)
{
drm_property_unreference_blob(state->mode_blob);
drm_property_unreference_blob(state->degamma_lut);
drm_property_unreference_blob(state->ctm);
drm_property_unreference_blob(state->gamma_lut);
}
EXPORT_SYMBOL(__drm_atomic_helper_crtc_destroy_state);
......@@ -2870,3 +2891,98 @@ void drm_atomic_helper_connector_destroy_state(struct drm_connector *connector,
kfree(state);
}
EXPORT_SYMBOL(drm_atomic_helper_connector_destroy_state);
/**
* drm_atomic_helper_legacy_gamma_set - set the legacy gamma correction table
* @crtc: CRTC object
* @red: red correction table
* @green: green correction table
* @blue: green correction table
* @start:
* @size: size of the tables
*
* Implements support for legacy gamma correction table for drivers
* that support color management through the DEGAMMA_LUT/GAMMA_LUT
* properties.
*/
void drm_atomic_helper_legacy_gamma_set(struct drm_crtc *crtc,
u16 *red, u16 *green, u16 *blue,
uint32_t start, uint32_t size)
{
struct drm_device *dev = crtc->dev;
struct drm_mode_config *config = &dev->mode_config;
struct drm_atomic_state *state;
struct drm_crtc_state *crtc_state;
struct drm_property_blob *blob = NULL;
struct drm_color_lut *blob_data;
int i, ret = 0;
state = drm_atomic_state_alloc(crtc->dev);
if (!state)
return;
blob = drm_property_create_blob(dev,
sizeof(struct drm_color_lut) * size,
NULL);
if (IS_ERR(blob)) {
ret = PTR_ERR(blob);
blob = NULL;
goto fail;
}
/* Prepare GAMMA_LUT with the legacy values. */
blob_data = (struct drm_color_lut *) blob->data;
for (i = 0; i < size; i++) {
blob_data[i].red = red[i];
blob_data[i].green = green[i];
blob_data[i].blue = blue[i];
}
state->acquire_ctx = crtc->dev->mode_config.acquire_ctx;
retry:
crtc_state = drm_atomic_get_crtc_state(state, crtc);
if (IS_ERR(crtc_state)) {
ret = PTR_ERR(crtc_state);
goto fail;
}
/* Reset DEGAMMA_LUT and CTM properties. */
ret = drm_atomic_crtc_set_property(crtc, crtc_state,
config->degamma_lut_property, 0);
if (ret)
goto fail;
ret = drm_atomic_crtc_set_property(crtc, crtc_state,
config->ctm_property, 0);
if (ret)
goto fail;
ret = drm_atomic_crtc_set_property(crtc, crtc_state,
config->gamma_lut_property, blob->base.id);
if (ret)
goto fail;
ret = drm_atomic_commit(state);
if (ret)
goto fail;
/* Driver takes ownership of state on successful commit. */
drm_property_unreference_blob(blob);
return;
fail:
if (ret == -EDEADLK)
goto backoff;
drm_atomic_state_free(state);
drm_property_unreference_blob(blob);
return;
backoff:
drm_atomic_state_clear(state);
drm_atomic_legacy_backoff(state);
goto retry;
}
EXPORT_SYMBOL(drm_atomic_helper_legacy_gamma_set);
......@@ -430,9 +430,7 @@ EXPORT_SYMBOL(drm_framebuffer_init);
static void __drm_framebuffer_unregister(struct drm_device *dev,
struct drm_framebuffer *fb)
{
mutex_lock(&dev->mode_config.idr_mutex);
idr_remove(&dev->mode_config.crtc_idr, fb->base.id);
mutex_unlock(&dev->mode_config.idr_mutex);
drm_mode_object_put(dev, &fb->base);
fb->base.id = 0;
}
......@@ -1554,6 +1552,41 @@ static int drm_mode_create_standard_properties(struct drm_device *dev)
return -ENOMEM;
dev->mode_config.prop_mode_id = prop;
prop = drm_property_create(dev,
DRM_MODE_PROP_BLOB,
"DEGAMMA_LUT", 0);
if (!prop)
return -ENOMEM;
dev->mode_config.degamma_lut_property = prop;
prop = drm_property_create_range(dev,
DRM_MODE_PROP_IMMUTABLE,
"DEGAMMA_LUT_SIZE", 0, UINT_MAX);
if (!prop)
return -ENOMEM;
dev->mode_config.degamma_lut_size_property = prop;
prop = drm_property_create(dev,
DRM_MODE_PROP_BLOB,
"CTM", 0);
if (!prop)
return -ENOMEM;
dev->mode_config.ctm_property = prop;
prop = drm_property_create(dev,
DRM_MODE_PROP_BLOB,
"GAMMA_LUT", 0);
if (!prop)
return -ENOMEM;
dev->mode_config.gamma_lut_property = prop;
prop = drm_property_create_range(dev,
DRM_MODE_PROP_IMMUTABLE,
"GAMMA_LUT_SIZE", 0, UINT_MAX);
if (!prop)
return -ENOMEM;
dev->mode_config.gamma_lut_size_property = prop;
return 0;
}
......
......@@ -1075,3 +1075,36 @@ int drm_helper_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
return drm_plane_helper_commit(plane, plane_state, old_fb);
}
EXPORT_SYMBOL(drm_helper_crtc_mode_set_base);
/**
* drm_helper_crtc_enable_color_mgmt - enable color management properties
* @crtc: DRM CRTC
* @degamma_lut_size: the size of the degamma lut (before CSC)
* @gamma_lut_size: the size of the gamma lut (after CSC)
*
* This function lets the driver enable the color correction properties on a
* CRTC. This includes 3 degamma, csc and gamma properties that userspace can
* set and 2 size properties to inform the userspace of the lut sizes.
*/
void drm_helper_crtc_enable_color_mgmt(struct drm_crtc *crtc,
int degamma_lut_size,
int gamma_lut_size)
{
struct drm_device *dev = crtc->dev;
struct drm_mode_config *config = &dev->mode_config;
drm_object_attach_property(&crtc->base,
config->degamma_lut_property, 0);
drm_object_attach_property(&crtc->base,
config->ctm_property, 0);
drm_object_attach_property(&crtc->base,
config->gamma_lut_property, 0);
drm_object_attach_property(&crtc->base,
config->degamma_lut_size_property,
degamma_lut_size);
drm_object_attach_property(&crtc->base,
config->gamma_lut_size_property,
gamma_lut_size);
}
EXPORT_SYMBOL(drm_helper_crtc_enable_color_mgmt);
......@@ -3308,7 +3308,7 @@ void drm_edid_to_eld(struct drm_connector *connector, struct edid *edid)
u8 *cea;
u8 *name;
u8 *db;
int sad_count = 0;
int total_sad_count = 0;
int mnl;
int dbl;
......@@ -3322,6 +3322,7 @@ void drm_edid_to_eld(struct drm_connector *connector, struct edid *edid)
name = NULL;
drm_for_each_detailed_block((u8 *)edid, monitor_name, &name);
/* max: 13 bytes EDID, 16 bytes ELD */
for (mnl = 0; name && mnl < 13; mnl++) {
if (name[mnl] == 0x0a)
break;
......@@ -3350,11 +3351,15 @@ void drm_edid_to_eld(struct drm_connector *connector, struct edid *edid)
dbl = cea_db_payload_len(db);
switch (cea_db_tag(db)) {
int sad_count;
case AUDIO_BLOCK:
/* Audio Data Block, contains SADs */
sad_count = dbl / 3;
if (dbl >= 1)
memcpy(eld + 20 + mnl, &db[1], dbl);
sad_count = min(dbl / 3, 15 - total_sad_count);
if (sad_count >= 1)
memcpy(eld + 20 + mnl + total_sad_count * 3,
&db[1], sad_count * 3);
total_sad_count += sad_count;
break;
case SPEAKER_BLOCK:
/* Speaker Allocation Data Block */
......@@ -3371,13 +3376,13 @@ void drm_edid_to_eld(struct drm_connector *connector, struct edid *edid)
}
}
}
eld[5] |= sad_count << 4;
eld[5] |= total_sad_count << 4;
eld[DRM_ELD_BASELINE_ELD_LEN] =
DIV_ROUND_UP(drm_eld_calc_baseline_block_size(eld), 4);
DRM_DEBUG_KMS("ELD size %d, SAD count %d\n",
drm_eld_size(eld), sad_count);
drm_eld_size(eld), total_sad_count);
}
EXPORT_SYMBOL(drm_edid_to_eld);
......
......@@ -62,13 +62,6 @@ static void fsl_dcu_drm_crtc_enable(struct drm_crtc *crtc)
DCU_UPDATE_MODE_READREG);
}
static bool fsl_dcu_drm_crtc_mode_fixup(struct drm_crtc *crtc,
const struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode)
{
return true;
}
static void fsl_dcu_drm_crtc_mode_set_nofb(struct drm_crtc *crtc)
{
struct drm_device *dev = crtc->dev;
......@@ -127,7 +120,6 @@ static const struct drm_crtc_helper_funcs fsl_dcu_drm_crtc_helper_funcs = {
.atomic_flush = fsl_dcu_drm_crtc_atomic_flush,
.disable = fsl_dcu_drm_disable_crtc,
.enable = fsl_dcu_drm_crtc_enable,
.mode_fixup = fsl_dcu_drm_crtc_mode_fixup,
.mode_set_nofb = fsl_dcu_drm_crtc_mode_set_nofb,
};
......
......@@ -974,7 +974,6 @@ struct drm_display_mode *cdv_intel_crtc_mode_get(struct drm_device *dev,
const struct drm_crtc_helper_funcs cdv_intel_helper_funcs = {
.dpms = gma_crtc_dpms,
.mode_fixup = gma_crtc_mode_fixup,
.mode_set = cdv_intel_crtc_mode_set,
.mode_set_base = gma_pipe_set_base,
.prepare = gma_crtc_prepare,
......
......@@ -478,13 +478,6 @@ int gma_crtc_cursor_move(struct drm_crtc *crtc, int x, int y)
return 0;
}
bool gma_crtc_mode_fixup(struct drm_crtc *crtc,
const struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode)
{
return true;
}
void gma_crtc_prepare(struct drm_crtc *crtc)
{
const struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private;
......
......@@ -75,9 +75,6 @@ extern void gma_crtc_load_lut(struct drm_crtc *crtc);
extern void gma_crtc_gamma_set(struct drm_crtc *crtc, u16 *red, u16 *green,
u16 *blue, u32 start, u32 size);
extern void gma_crtc_dpms(struct drm_crtc *crtc, int mode);
extern bool gma_crtc_mode_fixup(struct drm_crtc *crtc,
const struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode);
extern void gma_crtc_prepare(struct drm_crtc *crtc);
extern void gma_crtc_commit(struct drm_crtc *crtc);
extern void gma_crtc_disable(struct drm_crtc *crtc);
......
......@@ -1026,10 +1026,8 @@ static int mdfld_crtc_mode_set(struct drm_crtc *crtc,
const struct drm_crtc_helper_funcs mdfld_helper_funcs = {
.dpms = mdfld_crtc_dpms,
.mode_fixup = gma_crtc_mode_fixup,
.mode_set = mdfld_crtc_mode_set,
.mode_set_base = mdfld__intel_pipe_set_base,
.prepare = gma_crtc_prepare,
.commit = gma_crtc_commit,
};
......@@ -657,7 +657,6 @@ static int oaktrail_pipe_set_base(struct drm_crtc *crtc,
const struct drm_crtc_helper_funcs oaktrail_helper_funcs = {
.dpms = oaktrail_crtc_dpms,
.mode_fixup = gma_crtc_mode_fixup,
.mode_set = oaktrail_crtc_mode_set,
.mode_set_base = oaktrail_pipe_set_base,
.prepare = gma_crtc_prepare,
......
......@@ -430,7 +430,6 @@ struct drm_display_mode *psb_intel_crtc_mode_get(struct drm_device *dev,
const struct drm_crtc_helper_funcs psb_intel_helper_funcs = {
.dpms = gma_crtc_dpms,
.mode_fixup = gma_crtc_mode_fixup,
.mode_set = psb_intel_crtc_mode_set,
.mode_set_base = gma_pipe_set_base,
.prepare = gma_crtc_prepare,
......
......@@ -92,18 +92,6 @@ static inline void mga_wait_busy(struct mga_device *mdev)
} while ((status & 0x01) && time_before(jiffies, timeout));
}
/*
* The core passes the desired mode to the CRTC code to see whether any
* CRTC-specific modifications need to be made to it. We're in a position
* to just pass that straight through, so this does nothing
*/
static bool mga_crtc_mode_fixup(struct drm_crtc *crtc,
const struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode)
{
return true;
}
#define P_ARRAY_SIZE 9
static int mga_g200se_set_plls(struct mga_device *mdev, long clock)
......@@ -1410,7 +1398,6 @@ static const struct drm_crtc_funcs mga_crtc_funcs = {
static const struct drm_crtc_helper_funcs mga_helper_funcs = {
.disable = mga_crtc_disable,
.dpms = mga_crtc_dpms,
.mode_fixup = mga_crtc_mode_fixup,
.mode_set = mga_crtc_mode_set,
.mode_set_base = mga_crtc_mode_set_base,
.prepare = mga_crtc_prepare,
......
......@@ -147,13 +147,6 @@ static void mdp4_crtc_destroy(struct drm_crtc *crtc)
kfree(mdp4_crtc);
}
static bool mdp4_crtc_mode_fixup(struct drm_crtc *crtc,
const struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode)
{
return true;
}
/* statically (for now) map planes to mixer stage (z-order): */
static const int idxs[] = {
[VG1] = 1,
......@@ -501,7 +494,6 @@ static const struct drm_crtc_funcs mdp4_crtc_funcs = {
};
static const struct drm_crtc_helper_funcs mdp4_crtc_helper_funcs = {
.mode_fixup = mdp4_crtc_mode_fixup,
.mode_set_nofb = mdp4_crtc_mode_set_nofb,
.disable = mdp4_crtc_disable,
.enable = mdp4_crtc_enable,
......
......@@ -185,13 +185,6 @@ static void mdp5_crtc_destroy(struct drm_crtc *crtc)
kfree(mdp5_crtc);
}
static bool mdp5_crtc_mode_fixup(struct drm_crtc *crtc,
const struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode)
{
return true;
}
/*
* blend_setup() - blend all the planes of a CRTC
*
......@@ -627,7 +620,6 @@ static const struct drm_crtc_funcs mdp5_crtc_funcs = {
};
static const struct drm_crtc_helper_funcs mdp5_crtc_helper_funcs = {
.mode_fixup = mdp5_crtc_mode_fixup,
.mode_set_nofb = mdp5_crtc_mode_set_nofb,
.disable = mdp5_crtc_disable,
.enable = mdp5_crtc_enable,
......
......@@ -227,13 +227,6 @@ nv_crtc_dpms(struct drm_crtc *crtc, int mode)
NVWriteVgaCrtc(dev, nv_crtc->index, NV_CIO_CRE_RPC1_INDEX, crtc1A);
}
static bool
nv_crtc_mode_fixup(struct drm_crtc *crtc, const struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode)
{
return true;
}
static void
nv_crtc_mode_set_vga(struct drm_crtc *crtc, struct drm_display_mode *mode)
{
......@@ -1093,7 +1086,6 @@ static const struct drm_crtc_helper_funcs nv04_crtc_helper_funcs = {
.dpms = nv_crtc_dpms,
.prepare = nv_crtc_prepare,
.commit = nv_crtc_commit,
.mode_fixup = nv_crtc_mode_fixup,
.mode_set = nv_crtc_mode_set,
.mode_set_base = nv04_crtc_mode_set_base,
.mode_set_base_atomic = nv04_crtc_mode_set_base_atomic,
......
......@@ -332,13 +332,6 @@ static void omap_crtc_destroy(struct drm_crtc *crtc)
kfree(omap_crtc);
}
static bool omap_crtc_mode_fixup(struct drm_crtc *crtc,
const struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode)
{
return true;
}
static void omap_crtc_enable(struct drm_crtc *crtc)
{
struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
......@@ -475,7 +468,6 @@ static const struct drm_crtc_funcs omap_crtc_funcs = {
};
static const struct drm_crtc_helper_funcs omap_crtc_helper_funcs = {
.mode_fixup = omap_crtc_mode_fixup,
.mode_set_nofb = omap_crtc_mode_set_nofb,
.disable = omap_crtc_disable,
.enable = omap_crtc_enable,
......
......@@ -491,14 +491,6 @@ static void rcar_du_crtc_disable(struct drm_crtc *crtc)
rcrtc->outputs = 0;
}
static bool rcar_du_crtc_mode_fixup(struct drm_crtc *crtc,
const struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode)
{
/* TODO Fixup modes */
return true;
}
static void rcar_du_crtc_atomic_begin(struct drm_crtc *crtc,
struct drm_crtc_state *old_crtc_state)
{
......@@ -531,7 +523,6 @@ static void rcar_du_crtc_atomic_flush(struct drm_crtc *crtc,
}
static const struct drm_crtc_helper_funcs crtc_helper_funcs = {
.mode_fixup = rcar_du_crtc_mode_fixup,
.disable = rcar_du_crtc_disable,
.enable = rcar_du_crtc_enable,
.atomic_begin = rcar_du_crtc_atomic_begin,
......
......@@ -359,13 +359,6 @@ static void shmob_drm_crtc_dpms(struct drm_crtc *crtc, int mode)
scrtc->dpms = mode;
}
static bool shmob_drm_crtc_mode_fixup(struct drm_crtc *crtc,
const struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode)
{
return true;
}
static void shmob_drm_crtc_mode_prepare(struct drm_crtc *crtc)
{
shmob_drm_crtc_dpms(crtc, DRM_MODE_DPMS_OFF);
......@@ -431,7 +424,6 @@ static int shmob_drm_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
static const struct drm_crtc_helper_funcs crtc_helper_funcs = {
.dpms = shmob_drm_crtc_dpms,
.mode_fixup = shmob_drm_crtc_mode_fixup,
.prepare = shmob_drm_crtc_mode_prepare,
.commit = shmob_drm_crtc_mode_commit,
.mode_set = shmob_drm_crtc_mode_set,
......
......@@ -51,14 +51,6 @@ static void sti_crtc_disabling(struct drm_crtc *crtc)
mixer->status = STI_MIXER_DISABLING;
}
static bool sti_crtc_mode_fixup(struct drm_crtc *crtc,
const struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode)
{
/* accept the provided drm_display_mode, do not fix it up */
return true;
}
static int
sti_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *mode)
{
......@@ -229,7 +221,6 @@ static void sti_crtc_atomic_flush(struct drm_crtc *crtc,
static const struct drm_crtc_helper_funcs sti_crtc_helper_funcs = {
.enable = sti_crtc_enable,
.disable = sti_crtc_disabling,
.mode_fixup = sti_crtc_mode_fixup,
.mode_set = drm_helper_crtc_mode_set,
.mode_set_nofb = sti_crtc_mode_set_nofb,
.mode_set_base = drm_helper_crtc_mode_set_base,
......
......@@ -279,14 +279,6 @@ static void udl_crtc_dpms(struct drm_crtc *crtc, int mode)
}
static bool udl_crtc_mode_fixup(struct drm_crtc *crtc,
const struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode)
{
return true;
}
#if 0
static int
udl_pipe_set_base_atomic(struct drm_crtc *crtc, struct drm_framebuffer *fb,
......@@ -402,7 +394,6 @@ static void udl_crtc_commit(struct drm_crtc *crtc)
static const struct drm_crtc_helper_funcs udl_helper_funcs = {
.dpms = udl_crtc_dpms,
.mode_fixup = udl_crtc_mode_fixup,
.mode_set = udl_crtc_mode_set,
.prepare = udl_crtc_prepare,
.commit = udl_crtc_commit,
......
......@@ -237,13 +237,6 @@ virtio_gpu_framebuffer_init(struct drm_device *dev,
return 0;
}
static bool virtio_gpu_crtc_mode_fixup(struct drm_crtc *crtc,
const struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode)
{
return true;
}
static void virtio_gpu_crtc_mode_set_nofb(struct drm_crtc *crtc)
{
struct drm_device *dev = crtc->dev;
......@@ -277,7 +270,6 @@ static int virtio_gpu_crtc_atomic_check(struct drm_crtc *crtc,
static const struct drm_crtc_helper_funcs virtio_gpu_crtc_helper_funcs = {
.enable = virtio_gpu_crtc_enable,
.disable = virtio_gpu_crtc_disable,
.mode_fixup = virtio_gpu_crtc_mode_fixup,
.mode_set_nofb = virtio_gpu_crtc_mode_set_nofb,
.atomic_check = virtio_gpu_crtc_atomic_check,
};
......
......@@ -146,6 +146,9 @@ __drm_atomic_helper_connector_destroy_state(struct drm_connector *connector,
struct drm_connector_state *state);
void drm_atomic_helper_connector_destroy_state(struct drm_connector *connector,
struct drm_connector_state *state);
void drm_atomic_helper_legacy_gamma_set(struct drm_crtc *crtc,
u16 *red, u16 *green, u16 *blue,
uint32_t start, uint32_t size);
/**
* drm_atomic_crtc_for_each_plane - iterate over planes currently attached to CRTC
......
......@@ -305,6 +305,8 @@ struct drm_plane_helper_funcs;
* @mode_changed: crtc_state->mode or crtc_state->enable has been changed
* @active_changed: crtc_state->active has been toggled.
* @connectors_changed: connectors to this crtc have been updated
* @color_mgmt_changed: color management properties have changed (degamma or
* gamma LUT or CSC matrix)
* @plane_mask: bitmask of (1 << drm_plane_index(plane)) of attached planes
* @connector_mask: bitmask of (1 << drm_connector_index(connector)) of attached connectors
* @encoder_mask: bitmask of (1 << drm_encoder_index(encoder)) of attached encoders
......@@ -312,6 +314,11 @@ struct drm_plane_helper_funcs;
* update to ensure framebuffer cleanup isn't done too early
* @adjusted_mode: for use by helpers and drivers to compute adjusted mode timings
* @mode: current mode timings
* @degamma_lut: Lookup table for converting framebuffer pixel data
* before apply the conversion matrix
* @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
......@@ -333,6 +340,7 @@ struct drm_crtc_state {
bool mode_changed : 1;
bool active_changed : 1;
bool connectors_changed : 1;
bool color_mgmt_changed : 1;
/* attached planes bitmask:
* WARNING: transitional helpers do not maintain plane_mask so
......@@ -355,6 +363,11 @@ struct drm_crtc_state {
/* blob property to expose current mode to atomic userspace */
struct drm_property_blob *mode_blob;
/* blob property to expose color management to userspace */
struct drm_property_blob *degamma_lut;
struct drm_property_blob *ctm;
struct drm_property_blob *gamma_lut;
struct drm_pending_vblank_event *event;
struct drm_atomic_state *state;
......@@ -757,7 +770,7 @@ struct drm_crtc {
int x, y;
const struct drm_crtc_funcs *funcs;
/* CRTC gamma size for reporting to userspace */
/* Legacy FB CRTC gamma size for reporting to userspace */
uint32_t gamma_size;
uint16_t *gamma_store;
......@@ -1677,6 +1690,7 @@ struct drm_bridge {
* @dev: parent DRM device
* @allow_modeset: allow full modeset
* @legacy_cursor_update: hint to enforce legacy cursor IOCTL semantics
* @legacy_set_config: Disable conflicting encoders instead of failing with -EINVAL.
* @planes: pointer to array of plane pointers
* @plane_states: pointer to array of plane states pointers
* @crtcs: pointer to array of CRTC pointers
......@@ -1690,6 +1704,7 @@ struct drm_atomic_state {
struct drm_device *dev;
bool allow_modeset : 1;
bool legacy_cursor_update : 1;
bool legacy_set_config : 1;
struct drm_plane **planes;
struct drm_plane_state **plane_states;
struct drm_crtc **crtcs;
......@@ -2026,6 +2041,15 @@ struct drm_mode_config_funcs {
* @property_blob_list: list of all the blob property objects
* @blob_lock: mutex for blob property allocation and management
* @*_property: core property tracking
* @degamma_lut_property: LUT used to convert the framebuffer's colors to linear
* gamma
* @degamma_lut_size_property: size of the degamma LUT as supported by the
* driver (read-only)
* @ctm_property: Matrix used to convert colors after the lookup in the
* degamma LUT
* @gamma_lut_property: LUT used to convert the colors, after the CSC matrix, to
* the gamma space of the connected screen (read-only)
* @gamma_lut_size_property: size of the gamma LUT as supported by the driver
* @preferred_depth: preferred RBG pixel depth, used by fb helpers
* @prefer_shadow: hint to userspace to prefer shadow-fb rendering
* @async_page_flip: does this device support async flips on the primary plane?
......@@ -2128,6 +2152,13 @@ struct drm_mode_config {
struct drm_property *aspect_ratio_property;
struct drm_property *dirty_info_property;
/* Optional color correction properties */
struct drm_property *degamma_lut_property;
struct drm_property *degamma_lut_size_property;
struct drm_property *ctm_property;
struct drm_property *gamma_lut_property;
struct drm_property *gamma_lut_size_property;
/* properties for virtual machine layout */
struct drm_property *suggested_x_property;
struct drm_property *suggested_y_property;
......@@ -2554,6 +2585,21 @@ static inline struct drm_property *drm_property_find(struct drm_device *dev,
return mo ? obj_to_property(mo) : NULL;
}
/*
* Extract a degamma/gamma LUT value provided by user and round it to the
* precision supported by the hardware.
*/
static inline uint32_t drm_color_lut_extract(uint32_t user_input,
uint32_t bit_precision)
{
uint32_t val = user_input + (1 << (16 - bit_precision - 1));
uint32_t max = 0xffff >> (16 - bit_precision);
val >>= 16 - bit_precision;
return clamp_val(val, 0, max);
}
/* Plane list iterator for legacy (overlay only) planes. */
#define drm_for_each_legacy_plane(plane, dev) \
list_for_each_entry(plane, &(dev)->mode_config.plane_list, head) \
......
......@@ -48,6 +48,9 @@ extern bool drm_crtc_helper_set_mode(struct drm_crtc *crtc,
struct drm_display_mode *mode,
int x, int y,
struct drm_framebuffer *old_fb);
extern void drm_helper_crtc_enable_color_mgmt(struct drm_crtc *crtc,
int degamma_lut_size,
int gamma_lut_size);
extern bool drm_helper_crtc_in_use(struct drm_crtc *crtc);
extern bool drm_helper_encoder_in_use(struct drm_encoder *encoder);
......
......@@ -487,6 +487,21 @@ struct drm_mode_crtc_lut {
__u64 blue;
};
struct drm_color_ctm {
/* Conversion matrix in S31.32 format. */
__s64 matrix[9];
};
struct drm_color_lut {
/*
* Data is U0.16 fixed point format.
*/
__u16 red;
__u16 green;
__u16 blue;
__u16 reserved;
};
#define DRM_MODE_PAGE_FLIP_EVENT 0x01
#define DRM_MODE_PAGE_FLIP_ASYNC 0x02
#define DRM_MODE_PAGE_FLIP_FLAGS (DRM_MODE_PAGE_FLIP_EVENT|DRM_MODE_PAGE_FLIP_ASYNC)
......
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