diff options
52 files changed, 1004 insertions, 373 deletions
diff --git a/Documentation/DocBook/gpu.tmpl b/Documentation/DocBook/gpu.tmpl index fe6b36a2fd98..1692c4dd5487 100644 --- a/Documentation/DocBook/gpu.tmpl +++ b/Documentation/DocBook/gpu.tmpl @@ -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> diff --git a/Documentation/devicetree/bindings/display/brcm,bcm-vc4.txt b/Documentation/devicetree/bindings/display/brcm,bcm-vc4.txt index 56a961aa5061..9f97df4d5152 100644 --- a/Documentation/devicetree/bindings/display/brcm,bcm-vc4.txt +++ b/Documentation/devicetree/bindings/display/brcm,bcm-vc4.txt @@ -35,6 +35,12 @@ Optional properties for HDMI: as an interrupt/status bit in the HDMI controller itself). See bindings/pinctrl/brcm,bcm2835-gpio.txt +Required properties for V3D: +- compatible: Should be "brcm,bcm2835-v3d" +- reg: Physical base address and length of the V3D's registers +- interrupts: The interrupt number + See bindings/interrupt-controller/brcm,bcm2835-armctrl-ic.txt + Example: pixelvalve@7e807000 { compatible = "brcm,bcm2835-pixelvalve2"; @@ -60,6 +66,12 @@ hdmi: hdmi@7e902000 { clock-names = "pixel", "hdmi"; }; +v3d: v3d@7ec00000 { + compatible = "brcm,bcm2835-v3d"; + reg = <0x7ec00000 0x1000>; + interrupts = <1 10>; +}; + vc4: gpu { compatible = "brcm,bcm2835-vc4"; }; diff --git a/Documentation/devicetree/bindings/display/panel/lg,lp120up1.txt b/Documentation/devicetree/bindings/display/panel/lg,lp120up1.txt new file mode 100644 index 000000000000..8c5de692c55c --- /dev/null +++ b/Documentation/devicetree/bindings/display/panel/lg,lp120up1.txt @@ -0,0 +1,7 @@ +LG 12.0" (1920x1280 pixels) TFT LCD panel + +Required properties: +- compatible: should be "lg,lp120up1" + +This binding is compatible with the simple-panel binding, which is specified +in simple-panel.txt in this directory. diff --git a/Documentation/devicetree/bindings/display/panel/urt,umsh-8596md.txt b/Documentation/devicetree/bindings/display/panel/urt,umsh-8596md.txt new file mode 100644 index 000000000000..088a6cea5015 --- /dev/null +++ b/Documentation/devicetree/bindings/display/panel/urt,umsh-8596md.txt @@ -0,0 +1,16 @@ +United Radiant Technology UMSH-8596MD-xT 7.0" WVGA TFT LCD panel + +Supported are LVDS versions (-11T, -19T) and parallel ones +(-T, -1T, -7T, -20T). + +Required properties: +- compatible: should be one of: + "urt,umsh-8596md-t", + "urt,umsh-8596md-1t", + "urt,umsh-8596md-7t", + "urt,umsh-8596md-11t", + "urt,umsh-8596md-19t", + "urt,umsh-8596md-20t". + +This binding is compatible with the simple-panel binding, which is specified +in simple-panel.txt in this directory. diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt index 72e2c5a2b327..1bcef7300b37 100644 --- a/Documentation/devicetree/bindings/vendor-prefixes.txt +++ b/Documentation/devicetree/bindings/vendor-prefixes.txt @@ -240,6 +240,7 @@ tplink TP-LINK Technologies Co., Ltd. tronfy Tronfy truly Truly Semiconductors Limited upisemi uPI Semiconductor Corp. +urt United Radiant Technology Corporation usi Universal Scientific Industrial Co., Ltd. v3 V3 Semiconductor variscite Variscite Ltd. diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_dbgdev.c b/drivers/gpu/drm/amd/amdkfd/kfd_dbgdev.c index c34c393e9aea..d5e19b5fbbfb 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_dbgdev.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_dbgdev.c @@ -513,7 +513,7 @@ static int dbgdev_wave_control_set_registers( union SQ_CMD_BITS *in_reg_sq_cmd, union GRBM_GFX_INDEX_BITS *in_reg_gfx_index) { - int status; + int status = 0; union SQ_CMD_BITS reg_sq_cmd; union GRBM_GFX_INDEX_BITS reg_gfx_index; struct HsaDbgWaveMsgAMDGen2 *pMsg; diff --git a/drivers/gpu/drm/ast/ast_mode.c b/drivers/gpu/drm/ast/ast_mode.c index f221e2dc1b0d..a965e7e8ad6e 100644 --- a/drivers/gpu/drm/ast/ast_mode.c +++ b/drivers/gpu/drm/ast/ast_mode.c @@ -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, diff --git a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c index 9863291a9a54..58c4f785cf84 100644 --- a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c +++ b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c @@ -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 @@ fail: atmel_hlcdc_crtc_destroy(&crtc->base); return ret; } - diff --git a/drivers/gpu/drm/bochs/bochs_kms.c b/drivers/gpu/drm/bochs/bochs_kms.c index 317c27f2a50b..96926f09e0c9 100644 --- a/drivers/gpu/drm/bochs/bochs_kms.c +++ b/drivers/gpu/drm/bochs/bochs_kms.c @@ -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, diff --git a/drivers/gpu/drm/cirrus/cirrus_mode.c b/drivers/gpu/drm/cirrus/cirrus_mode.c index 432ce9440e09..d3d8d7bfcc57 100644 --- a/drivers/gpu/drm/cirrus/cirrus_mode.c +++ b/drivers/gpu/drm/cirrus/cirrus_mode.c @@ -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, diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c index 092620c6ff32..a2596eb803fc 100644 --- a/drivers/gpu/drm/drm_atomic.c +++ b/drivers/gpu/drm/drm_atomic.c @@ -28,6 +28,7 @@ #include <drm/drmP.h> #include <drm/drm_atomic.h> +#include <drm/drm_mode.h> #include <drm/drm_plane_helper.h> /** @@ -376,6 +377,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 * @state: the state object to update with the new property value @@ -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 diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c index 4da4f2a49078..2bb90faa0ee2 100644 --- a/drivers/gpu/drm/drm_atomic_helper.c +++ b/drivers/gpu/drm/drm_atomic_helper.c @@ -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; + } + + encoder_mask |= 1 << drm_encoder_index(new_encoder); + } } - return true; -} + if (!encoder_mask) + return 0; -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; + /* + * 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; - WARN_ON(!drm_modeset_is_locked(&config->connection_mutex)); + if (drm_atomic_get_existing_connector_state(state, connector)) + continue; - drm_for_each_connector(connector, dev) { - if (connector->state->best_encoder != encoder) + encoder = connector->state->best_encoder; + if (!encoder || !(encoder_mask & (1 << drm_encoder_index(encoder)))) continue; - return connector->state->crtc; + 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; + } + + 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 NULL; + 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)); - - 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); - - crtc_state->connectors_changed = true; + for_each_connector_in_state(state, connector, connector_state, i) { + struct drm_crtc *encoder_crtc; - list_for_each_entry(connector, &config->connector_list, head) { - if (connector->state->best_encoder != encoder) + if (connector_state->best_encoder != encoder) continue; - DRM_DEBUG_ATOMIC("Stealing encoder from [CONNECTOR:%d:%s]\n", - connector->base.id, - connector->name); + encoder_crtc = connector->state->crtc; - 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; + 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); set_best_encoder(state, connector_state, NULL); - } - return 0; + crtc_state = drm_atomic_get_existing_crtc_state(state, encoder_crtc); + crtc_state->connectors_changed = true; + + return; + } } 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); - if (ret) - return ret; - } + /* 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; } + } - 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; - } - } + /* 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); + + ret = drm_atomic_set_crtc_for_connector(conn_state, + set->crtc); + if (ret) + return ret; } 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); diff --git a/drivers/gpu/drm/drm_bridge.c b/drivers/gpu/drm/drm_bridge.c index bd93453afa61..b3654404abd0 100644 --- a/drivers/gpu/drm/drm_bridge.c +++ b/drivers/gpu/drm/drm_bridge.c @@ -186,7 +186,8 @@ void drm_bridge_disable(struct drm_bridge *bridge) drm_bridge_disable(bridge->next); - bridge->funcs->disable(bridge); + if (bridge->funcs->disable) + bridge->funcs->disable(bridge); } EXPORT_SYMBOL(drm_bridge_disable); @@ -206,7 +207,8 @@ void drm_bridge_post_disable(struct drm_bridge *bridge) if (!bridge) return; - bridge->funcs->post_disable(bridge); + if (bridge->funcs->post_disable) + bridge->funcs->post_disable(bridge); drm_bridge_post_disable(bridge->next); } @@ -256,7 +258,8 @@ void drm_bridge_pre_enable(struct drm_bridge *bridge) drm_bridge_pre_enable(bridge->next); - bridge->funcs->pre_enable(bridge); + if (bridge->funcs->pre_enable) + bridge->funcs->pre_enable(bridge); } EXPORT_SYMBOL(drm_bridge_pre_enable); @@ -276,7 +279,8 @@ void drm_bridge_enable(struct drm_bridge *bridge) if (!bridge) return; - bridge->funcs->enable(bridge); + if (bridge->funcs->enable) + bridge->funcs->enable(bridge); drm_bridge_enable(bridge->next); } diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index 84514001dcef..e08f962288d9 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -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; } diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c index 7539eea4ccbc..79555d2b1b87 100644 --- a/drivers/gpu/drm/drm_crtc_helper.c +++ b/drivers/gpu/drm/drm_crtc_helper.c @@ -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); diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index fdb1eb014586..414d7f61aa05 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -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); diff --git a/drivers/gpu/drm/drm_mipi_dsi.c b/drivers/gpu/drm/drm_mipi_dsi.c index 6e6a9c58d404..f5d80839a90c 100644 --- a/drivers/gpu/drm/drm_mipi_dsi.c +++ b/drivers/gpu/drm/drm_mipi_dsi.c @@ -47,7 +47,17 @@ static int mipi_dsi_device_match(struct device *dev, struct device_driver *drv) { - return of_driver_match_device(dev, drv); + struct mipi_dsi_device *dsi = to_mipi_dsi_device(dev); + + /* attempt OF style match */ + if (of_driver_match_device(dev, drv)) + return 1; + + /* compare DSI device and driver names */ + if (!strcmp(dsi->name, drv->name)) + return 1; + + return 0; } static const struct dev_pm_ops mipi_dsi_device_pm_ops = { @@ -129,14 +139,20 @@ static int mipi_dsi_device_add(struct mipi_dsi_device *dsi) return device_add(&dsi->dev); } +#if IS_ENABLED(CONFIG_OF) static struct mipi_dsi_device * of_mipi_dsi_device_add(struct mipi_dsi_host *host, struct device_node *node) { - struct mipi_dsi_device *dsi; struct device *dev = host->dev; + struct mipi_dsi_device_info info = { }; int ret; u32 reg; + if (of_modalias_node(node, info.type, sizeof(info.type)) < 0) { + dev_err(dev, "modalias failure on %s\n", node->full_name); + return ERR_PTR(-EINVAL); + } + ret = of_property_read_u32(node, "reg", ®); if (ret) { dev_err(dev, "device node %s has no valid reg property: %d\n", @@ -144,32 +160,111 @@ of_mipi_dsi_device_add(struct mipi_dsi_host *host, struct device_node *node) return ERR_PTR(-EINVAL); } - if (reg > 3) { - dev_err(dev, "device node %s has invalid reg property: %u\n", - node->full_name, reg); + info.channel = reg; + info.node = of_node_get(node); + + return mipi_dsi_device_register_full(host, &info); +} +#else +static struct mipi_dsi_device * +of_mipi_dsi_device_add(struct mipi_dsi_host *host, struct device_node *node) +{ + return ERR_PTR(-ENODEV); +} +#endif + +/** + * mipi_dsi_device_register_full - create a MIPI DSI device + * @host: DSI host to which this device is connected + * @info: pointer to template containing DSI device information + * + * Create a MIPI DSI device by using the device information provided by + * mipi_dsi_device_info template + * + * Returns: + * A pointer to the newly created MIPI DSI device, or, a pointer encoded + * with an error + */ +struct mipi_dsi_device * +mipi_dsi_device_register_full(struct mipi_dsi_host *host, + const struct mipi_dsi_device_info *info) +{ + struct mipi_dsi_device *dsi; + struct device *dev = host->dev; + int ret; + + if (!info) { + dev_err(dev, "invalid mipi_dsi_device_info pointer\n"); + return ERR_PTR(-EINVAL); + } + + if (info->channel > 3) { + dev_err(dev, "invalid virtual channel: %u\n", info->channel); return ERR_PTR(-EINVAL); } dsi = mipi_dsi_device_alloc(host); if (IS_ERR(dsi)) { - dev_err(dev, "failed to allocate DSI device %s: %ld\n", - node->full_name, PTR_ERR(dsi)); + dev_err(dev, "failed to allocate DSI device %ld\n", + PTR_ERR(dsi)); return dsi; } - dsi->dev.of_node = of_node_get(node); - dsi->channel = reg; + dsi->dev.of_node = info->node; + dsi->channel = info->channel; + strlcpy(dsi->name, info->type, sizeof(dsi->name)); ret = mipi_dsi_device_add(dsi); if (ret) { - dev_err(dev, "failed to add DSI device %s: %d\n", - node->full_name, ret); + dev_err(dev, "failed to add DSI device %d\n", ret); kfree(dsi); return ERR_PTR(ret); } return dsi; } +EXPORT_SYMBOL(mipi_dsi_device_register_full); + +/** + * mipi_dsi_device_unregister - unregister MIPI DSI device + * @dsi: DSI peripheral device + */ +void mipi_dsi_device_unregister(struct mipi_dsi_device *dsi) +{ + device_unregister(&dsi->dev); +} +EXPORT_SYMBOL(mipi_dsi_device_unregister); + +static DEFINE_MUTEX(host_lock); +static LIST_HEAD(host_list); + +/** + * of_find_mipi_dsi_host_by_node() - find the MIPI DSI host matching a + * device tree node + * @node: device tree node + * + * Returns: + * A pointer to the MIPI DSI host corresponding to @node or NULL if no + * such device exists (or has not been registered yet). + */ +struct mipi_dsi_host *of_find_mipi_dsi_host_by_node(struct device_node *node) +{ + struct mipi_dsi_host *host; + + mutex_lock(&host_lock); + + list_for_each_entry(host, &host_list, list) { + if (host->dev->of_node == node) { + mutex_unlock(&host_lock); + return host; + } + } + + mutex_unlock(&host_lock); + + return NULL; +} +EXPORT_SYMBOL(of_find_mipi_dsi_host_by_node); int mipi_dsi_host_register(struct mipi_dsi_host *host) { @@ -182,6 +277,10 @@ int mipi_dsi_host_register(struct mipi_dsi_host *host) of_mipi_dsi_device_add(host, node); } + mutex_lock(&host_lock); + list_add_tail(&host->list, &host_list); + mutex_unlock(&host_lock); + return 0; } EXPORT_SYMBOL(mipi_dsi_host_register); @@ -190,7 +289,7 @@ static int mipi_dsi_remove_device_fn(struct device *dev, void *priv) { struct mipi_dsi_device *dsi = to_mipi_dsi_device(dev); - device_unregister(&dsi->dev); + mipi_dsi_device_unregister(dsi); return 0; } @@ -198,6 +297,10 @@ static int mipi_dsi_remove_device_fn(struct device *dev, void *priv) void mipi_dsi_host_unregister(struct mipi_dsi_host *host) { device_for_each_child(host->dev, NULL, mipi_dsi_remove_device_fn); + + mutex_lock(&host_lock); + list_del_init(&host->list); + mutex_unlock(&host_lock); } EXPORT_SYMBOL(mipi_dsi_host_unregister); diff --git a/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_crtc.c b/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_crtc.c index 7574db2da413..4ed7798533f9 100644 --- a/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_crtc.c +++ b/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_crtc.c @@ -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, }; diff --git a/drivers/gpu/drm/gma500/cdv_intel_display.c b/drivers/gpu/drm/gma500/cdv_intel_display.c index 6126546295e9..17db4b4749d5 100644 --- a/drivers/gpu/drm/gma500/cdv_intel_display.c +++ b/drivers/gpu/drm/gma500/cdv_intel_display.c @@ -116,7 +116,7 @@ static const struct gma_limit_t cdv_intel_limits[] = { .p1 = {.min = 1, .max = 10}, .p2 = {.dot_limit = 225000, .p2_slow = 10, .p2_fast = 10}, .find_pll = cdv_intel_find_dp_pll, - } + } }; #define _wait_for(COND, MS, W) ({ \ @@ -245,7 +245,7 @@ cdv_dpll_set_clock_cdv(struct drm_device *dev, struct drm_crtc *crtc, /* We don't know what the other fields of these regs are, so * leave them in place. */ - /* + /* * The BIT 14:13 of 0x8010/0x8030 is used to select the ref clk * for the pipe A/B. Display spec 1.06 has wrong definition. * Correct definition is like below: @@ -256,7 +256,7 @@ cdv_dpll_set_clock_cdv(struct drm_device *dev, struct drm_crtc *crtc, * * if DPLLA sets 01 and DPLLB sets 02, both use clk from DPLLA * - */ + */ ret = cdv_sb_read(dev, ref_sfr, &ref_value); if (ret) return ret; @@ -646,7 +646,7 @@ static int cdv_intel_crtc_mode_set(struct drm_crtc *crtc, * for DP/eDP. When using SSC clock, the ref clk is 100MHz.Otherwise * it will be 27MHz. From the VBIOS code it seems that the pipe A choose * 27MHz for DP/eDP while the Pipe B chooses the 100MHz. - */ + */ if (pipe == 0) refclk = 27000; else @@ -659,7 +659,7 @@ static int cdv_intel_crtc_mode_set(struct drm_crtc *crtc, } drm_mode_debug_printmodeline(adjusted_mode); - + limit = gma_crtc->clock_funcs->limit(crtc, refclk); ok = limit->find_pll(limit, crtc, adjusted_mode->clock, refclk, @@ -721,7 +721,7 @@ static int cdv_intel_crtc_mode_set(struct drm_crtc *crtc, pipeconf |= PIPE_6BPC; } else pipeconf |= PIPE_8BPC; - + /* Set up the display plane register */ dspcntr = DISPPLANE_GAMMA_ENABLE; @@ -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, diff --git a/drivers/gpu/drm/gma500/gma_display.c b/drivers/gpu/drm/gma500/gma_display.c index 927082148d4d..5bf765de2517 100644 --- a/drivers/gpu/drm/gma500/gma_display.c +++ b/drivers/gpu/drm/gma500/gma_display.c @@ -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; diff --git a/drivers/gpu/drm/gma500/gma_display.h b/drivers/gpu/drm/gma500/gma_display.h index 78b9f986a6e5..b2491c65f053 100644 --- a/drivers/gpu/drm/gma500/gma_display.h +++ b/drivers/gpu/drm/gma500/gma_display.h @@ -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); diff --git a/drivers/gpu/drm/gma500/mdfld_intel_display.c b/drivers/gpu/drm/gma500/mdfld_intel_display.c index acd38344b302..92e3f93ee682 100644 --- a/drivers/gpu/drm/gma500/mdfld_intel_display.c +++ b/drivers/gpu/drm/gma500/mdfld_intel_display.c @@ -1026,10 +1026,8 @@ mrst_crtc_mode_set_exit: 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, }; - diff --git a/drivers/gpu/drm/gma500/oaktrail_crtc.c b/drivers/gpu/drm/gma500/oaktrail_crtc.c index 1048f0c7c6ce..da9fd34b9550 100644 --- a/drivers/gpu/drm/gma500/oaktrail_crtc.c +++ b/drivers/gpu/drm/gma500/oaktrail_crtc.c @@ -657,7 +657,6 @@ pipe_set_base_exit: 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, diff --git a/drivers/gpu/drm/gma500/psb_intel_display.c b/drivers/gpu/drm/gma500/psb_intel_display.c index dcdbc37e55e1..398015be87e4 100644 --- a/drivers/gpu/drm/gma500/psb_intel_display.c +++ b/drivers/gpu/drm/gma500/psb_intel_display.c @@ -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, diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 8b7b8b64b008..6e0d8283daa6 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -10542,7 +10542,8 @@ found: goto fail; } - if (drm_atomic_commit(state)) { + ret = drm_atomic_commit(state); + if (ret) { DRM_DEBUG_KMS("failed to set mode on load-detect pipe\n"); goto fail; } diff --git a/drivers/gpu/drm/mgag200/mgag200_mode.c b/drivers/gpu/drm/mgag200/mgag200_mode.c index af8b4c19cf15..14e64e08909e 100644 --- a/drivers/gpu/drm/mgag200/mgag200_mode.c +++ b/drivers/gpu/drm/mgag200/mgag200_mode.c @@ -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, diff --git a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_crtc.c b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_crtc.c index c77e3d4e2c5c..e233acf52334 100644 --- a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_crtc.c +++ b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_crtc.c @@ -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, diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c index a064d9712234..9673b9520b6a 100644 --- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c +++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c @@ -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, diff --git a/drivers/gpu/drm/nouveau/dispnv04/crtc.c b/drivers/gpu/drm/nouveau/dispnv04/crtc.c index 6f04397d43a7..55ccbf006b5e 100644 --- a/drivers/gpu/drm/nouveau/dispnv04/crtc.c +++ b/drivers/gpu/drm/nouveau/dispnv04/crtc.c @@ -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, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/pm/nv40.c b/drivers/gpu/drm/nouveau/nvkm/engine/pm/nv40.c index 4bef72a9d106..3fda594700e0 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/pm/nv40.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/pm/nv40.c @@ -59,9 +59,11 @@ static void nv40_perfctr_next(struct nvkm_pm *pm, struct nvkm_perfdom *dom) { struct nvkm_device *device = pm->engine.subdev.device; - if (pm->sequence != pm->sequence) { + struct nv40_pm *nv40pm = container_of(pm, struct nv40_pm, base); + + if (nv40pm->sequence != pm->sequence) { nvkm_wr32(device, 0x400084, 0x00000020); - pm->sequence = pm->sequence; + nv40pm->sequence = pm->sequence; } } diff --git a/drivers/gpu/drm/omapdrm/displays/connector-dvi.c b/drivers/gpu/drm/omapdrm/displays/connector-dvi.c index 3fd5a0b4d4cf..747f26a55e43 100644 --- a/drivers/gpu/drm/omapdrm/displays/connector-dvi.c +++ b/drivers/gpu/drm/omapdrm/displays/connector-dvi.c @@ -279,7 +279,7 @@ static int dvic_probe(struct platform_device *pdev) platform_set_drvdata(pdev, ddata); - if (pdev->dev.of_node) + if (!pdev->dev.of_node) return -ENODEV; r = dvic_probe_of(pdev); diff --git a/drivers/gpu/drm/omapdrm/displays/panel-dsi-cm.c b/drivers/gpu/drm/omapdrm/displays/panel-dsi-cm.c index ae7dd625e19f..36485c2137ce 100644 --- a/drivers/gpu/drm/omapdrm/displays/panel-dsi-cm.c +++ b/drivers/gpu/drm/omapdrm/displays/panel-dsi-cm.c @@ -1180,7 +1180,7 @@ static int dsicm_probe(struct platform_device *pdev) platform_set_drvdata(pdev, ddata); ddata->pdev = pdev; - if (pdev->dev.of_node) + if (!pdev->dev.of_node) return -ENODEV; r = dsicm_probe_of(pdev); diff --git a/drivers/gpu/drm/omapdrm/omap_crtc.c b/drivers/gpu/drm/omapdrm/omap_crtc.c index 04097dab8589..075f2bb44867 100644 --- a/drivers/gpu/drm/omapdrm/omap_crtc.c +++ b/drivers/gpu/drm/omapdrm/omap_crtc.c @@ -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, diff --git a/drivers/gpu/drm/panel/panel-simple.c b/drivers/gpu/drm/panel/panel-simple.c index 2164c999052c..ceb20486dacf 100644 --- a/drivers/gpu/drm/panel/panel-simple.c +++ b/drivers/gpu/drm/panel/panel-simple.c @@ -847,6 +847,7 @@ static const struct drm_display_mode innolux_g121x1_l03_mode = { .vsync_end = 768 + 38 + 1, .vtotal = 768 + 38 + 1 + 0, .vrefresh = 60, + .flags = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC, }; static const struct panel_desc innolux_g121x1_l03 = { @@ -982,6 +983,29 @@ static const struct panel_desc lg_lb070wv8 = { .bus_format = MEDIA_BUS_FMT_RGB888_1X7X4_SPWG, }; +static const struct drm_display_mode lg_lp120up1_mode = { + .clock = 162300, + .hdisplay = 1920, + .hsync_start = 1920 + 40, + .hsync_end = 1920 + 40 + 40, + .htotal = 1920 + 40 + 40+ 80, + .vdisplay = 1280, + .vsync_start = 1280 + 4, + .vsync_end = 1280 + 4 + 4, + .vtotal = 1280 + 4 + 4 + 12, + .vrefresh = 60, +}; + +static const struct panel_desc lg_lp120up1 = { + .modes = &lg_lp120up1_mode, + .num_modes = 1, + .bpc = 8, + .size = { + .width = 267, + .height = 183, + }, +}; + static const struct drm_display_mode lg_lp129qe_mode = { .clock = 285250, .hdisplay = 2560, @@ -1177,6 +1201,42 @@ static const struct panel_desc shelly_sca07010_bfn_lnn = { .bus_format = MEDIA_BUS_FMT_RGB666_1X18, }; +static const struct display_timing urt_umsh_8596md_timing = { + .pixelclock = { 33260000, 33260000, 33260000 }, + .hactive = { 800, 800, 800 }, + .hfront_porch = { 41, 41, 41 }, + .hback_porch = { 216 - 128, 216 - 128, 216 - 128 }, + .hsync_len = { 71, 128, 128 }, + .vactive = { 480, 480, 480 }, + .vfront_porch = { 10, 10, 10 }, + .vback_porch = { 35 - 2, 35 - 2, 35 - 2 }, + .vsync_len = { 2, 2, 2 }, + .flags = DISPLAY_FLAGS_DE_HIGH | DISPLAY_FLAGS_PIXDATA_NEGEDGE | + DISPLAY_FLAGS_HSYNC_LOW | DISPLAY_FLAGS_VSYNC_LOW, +}; + +static const struct panel_desc urt_umsh_8596md_lvds = { + .timings = &urt_umsh_8596md_timing, + .num_timings = 1, + .bpc = 6, + .size = { + .width = 152, + .height = 91, + }, + .bus_format = MEDIA_BUS_FMT_RGB666_1X7X3_SPWG, +}; + +static const struct panel_desc urt_umsh_8596md_parallel = { + .timings = &urt_umsh_8596md_timing, + .num_timings = 1, + .bpc = 6, + .size = { + .width = 152, + .height = 91, + }, + .bus_format = MEDIA_BUS_FMT_RGB666_1X18, +}; + static const struct of_device_id platform_of_match[] = { { .compatible = "ampire,am800480r3tmqwa1h", @@ -1257,6 +1317,9 @@ static const struct of_device_id platform_of_match[] = { .compatible = "lg,lb070wv8", .data = &lg_lb070wv8, }, { + .compatible = "lg,lp120up1", + .data = &lg_lp120up1, + }, { .compatible = "lg,lp129qe", .data = &lg_lp129qe, }, { @@ -1281,6 +1344,24 @@ static const struct of_device_id platform_of_match[] = { .compatible = "shelly,sca07010-bfn-lnn", .data = &shelly_sca07010_bfn_lnn, }, { + .compatible = "urt,umsh-8596md-t", + .data = &urt_umsh_8596md_parallel, + }, { + .compatible = "urt,umsh-8596md-1t", + .data = &urt_umsh_8596md_parallel, + }, { + .compatible = "urt,umsh-8596md-7t", + .data = &urt_umsh_8596md_parallel, + }, { + .compatible = "urt,umsh-8596md-11t", + .data = &urt_umsh_8596md_lvds, + }, { + .compatible = "urt,umsh-8596md-19t", + .data = &urt_umsh_8596md_lvds, + }, { + .compatible = "urt,umsh-8596md-20t", + .data = &urt_umsh_8596md_parallel, + }, { /* sentinel */ } }; diff --git a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c index 51e9e8ce551a..d9f06cc361fa 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c +++ b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c @@ -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, diff --git a/drivers/gpu/drm/shmobile/shmob_drm_crtc.c b/drivers/gpu/drm/shmobile/shmob_drm_crtc.c index 27342fd76e90..88643ab160bf 100644 --- a/drivers/gpu/drm/shmobile/shmob_drm_crtc.c +++ b/drivers/gpu/drm/shmobile/shmob_drm_crtc.c @@ -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, diff --git a/drivers/gpu/drm/sti/sti_crtc.c b/drivers/gpu/drm/sti/sti_crtc.c index de11c7cfb02f..e04deedabd4a 100644 --- a/drivers/gpu/drm/sti/sti_crtc.c +++ b/drivers/gpu/drm/sti/sti_crtc.c @@ -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, diff --git a/drivers/gpu/drm/udl/udl_modeset.c b/drivers/gpu/drm/udl/udl_modeset.c index 160ef2a08b89..b87afee44995 100644 --- a/drivers/gpu/drm/udl/udl_modeset.c +++ b/drivers/gpu/drm/udl/udl_modeset.c @@ -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, diff --git a/drivers/gpu/drm/vc4/vc4_bo.c b/drivers/gpu/drm/vc4/vc4_bo.c index 22278bcfc60e..ac8eafea6361 100644 --- a/drivers/gpu/drm/vc4/vc4_bo.c +++ b/drivers/gpu/drm/vc4/vc4_bo.c @@ -499,11 +499,12 @@ vc4_create_shader_bo_ioctl(struct drm_device *dev, void *data, if (IS_ERR(bo)) return PTR_ERR(bo); - ret = copy_from_user(bo->base.vaddr, + if (copy_from_user(bo->base.vaddr, (void __user *)(uintptr_t)args->data, - args->size); - if (ret != 0) + args->size)) { + ret = -EFAULT; goto fail; + } /* Clear the rest of the memory from allocating from the BO * cache. */ diff --git a/drivers/gpu/drm/vc4/vc4_drv.h b/drivers/gpu/drm/vc4/vc4_drv.h index f53fe6cd72be..fa2ad15d4f62 100644 --- a/drivers/gpu/drm/vc4/vc4_drv.h +++ b/drivers/gpu/drm/vc4/vc4_drv.h @@ -52,7 +52,7 @@ struct vc4_dev { /* Protects bo_cache and the BO stats. */ struct mutex bo_lock; - /* Sequence number for the last job queued in job_list. + /* Sequence number for the last job queued in bin_job_list. * Starts at 0 (no jobs emitted). */ uint64_t emit_seqno; @@ -62,11 +62,19 @@ struct vc4_dev { */ uint64_t finished_seqno; - /* List of all struct vc4_exec_info for jobs to be executed. - * The first job in the list is the one currently programmed - * into ct0ca/ct1ca for execution. + /* List of all struct vc4_exec_info for jobs to be executed in + * the binner. The first job in the list is the one currently + * programmed into ct0ca for execution. */ - struct list_head job_list; + struct list_head bin_job_list; + + /* List of all struct vc4_exec_info for jobs that have + * completed binning and are ready for rendering. The first + * job in the list is the one currently programmed into ct1ca + * for execution. + */ + struct list_head render_job_list; + /* List of the finished vc4_exec_infos waiting to be freed by * job_done_work. */ @@ -296,11 +304,20 @@ struct vc4_exec_info { }; static inline struct vc4_exec_info * -vc4_first_job(struct vc4_dev *vc4) +vc4_first_bin_job(struct vc4_dev *vc4) +{ + if (list_empty(&vc4->bin_job_list)) + return NULL; + return list_first_entry(&vc4->bin_job_list, struct vc4_exec_info, head); +} + +static inline struct vc4_exec_info * +vc4_first_render_job(struct vc4_dev *vc4) { - if (list_empty(&vc4->job_list)) + if (list_empty(&vc4->render_job_list)) return NULL; - return list_first_entry(&vc4->job_list, struct vc4_exec_info, head); + return list_first_entry(&vc4->render_job_list, + struct vc4_exec_info, head); } /** @@ -414,7 +431,9 @@ int vc4_wait_seqno_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); int vc4_wait_bo_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); -void vc4_submit_next_job(struct drm_device *dev); +void vc4_submit_next_bin_job(struct drm_device *dev); +void vc4_submit_next_render_job(struct drm_device *dev); +void vc4_move_job_to_render(struct drm_device *dev, struct vc4_exec_info *exec); int vc4_wait_for_seqno(struct drm_device *dev, uint64_t seqno, uint64_t timeout_ns, bool interruptible); void vc4_job_handle_completed(struct vc4_dev *vc4); diff --git a/drivers/gpu/drm/vc4/vc4_gem.c b/drivers/gpu/drm/vc4/vc4_gem.c index 202aa1544acc..8d4384f8b78d 100644 --- a/drivers/gpu/drm/vc4/vc4_gem.c +++ b/drivers/gpu/drm/vc4/vc4_gem.c @@ -141,10 +141,10 @@ vc4_save_hang_state(struct drm_device *dev) struct vc4_dev *vc4 = to_vc4_dev(dev); struct drm_vc4_get_hang_state *state; struct vc4_hang_state *kernel_state; - struct vc4_exec_info *exec; + struct vc4_exec_info *exec[2]; struct vc4_bo *bo; unsigned long irqflags; - unsigned int i, unref_list_count; + unsigned int i, j, unref_list_count, prev_idx; kernel_state = kcalloc(1, sizeof(*kernel_state), GFP_KERNEL); if (!kernel_state) @@ -153,37 +153,55 @@ vc4_save_hang_state(struct drm_device *dev) state = &kernel_state->user_state; spin_lock_irqsave(&vc4->job_lock, irqflags); - exec = vc4_first_job(vc4); - if (!exec) { + exec[0] = vc4_first_bin_job(vc4); + exec[1] = vc4_first_render_job(vc4); + if (!exec[0] && !exec[1]) { spin_unlock_irqrestore(&vc4->job_lock, irqflags); return; } - unref_list_count = 0; - list_for_each_entry(bo, &exec->unref_list, unref_head) - unref_list_count++; + /* Get the bos from both binner and renderer into hang state. */ + state->bo_count = 0; + for (i = 0; i < 2; i++) { + if (!exec[i]) + continue; + + unref_list_count = 0; + list_for_each_entry(bo, &exec[i]->unref_list, unref_head) + unref_list_count++; + state->bo_count += exec[i]->bo_count + unref_list_count; + } + + kernel_state->bo = kcalloc(state->bo_count, + sizeof(*kernel_state->bo), GFP_ATOMIC); - state->bo_count = exec->bo_count + unref_list_count; - kernel_state->bo = kcalloc(state->bo_count, sizeof(*kernel_state->bo), - GFP_ATOMIC); if (!kernel_state->bo) { spin_unlock_irqrestore(&vc4->job_lock, irqflags); return; } - for (i = 0; i < exec->bo_count; i++) { - drm_gem_object_reference(&exec->bo[i]->base); - kernel_state->bo[i] = &exec->bo[i]->base; - } + prev_idx = 0; + for (i = 0; i < 2; i++) { + if (!exec[i]) + continue; - list_for_each_entry(bo, &exec->unref_list, unref_head) { - drm_gem_object_reference(&bo->base.base); - kernel_state->bo[i] = &bo->base.base; - i++; + for (j = 0; j < exec[i]->bo_count; j++) { + drm_gem_object_reference(&exec[i]->bo[j]->base); + kernel_state->bo[j + prev_idx] = &exec[i]->bo[j]->base; + } + + list_for_each_entry(bo, &exec[i]->unref_list, unref_head) { + drm_gem_object_reference(&bo->base.base); + kernel_state->bo[j + prev_idx] = &bo->base.base; + j++; + } + prev_idx = j + 1; } - state->start_bin = exec->ct0ca; - state->start_render = exec->ct1ca; + if (exec[0]) + state->start_bin = exec[0]->ct0ca; + if (exec[1]) + state->start_render = exec[1]->ct1ca; spin_unlock_irqrestore(&vc4->job_lock, irqflags); @@ -267,13 +285,15 @@ vc4_hangcheck_elapsed(unsigned long data) struct vc4_dev *vc4 = to_vc4_dev(dev); uint32_t ct0ca, ct1ca; unsigned long irqflags; - struct vc4_exec_info *exec; + struct vc4_exec_info *bin_exec, *render_exec; spin_lock_irqsave(&vc4->job_lock, irqflags); - exec = vc4_first_job(vc4); + + bin_exec = vc4_first_bin_job(vc4); + render_exec = vc4_first_render_job(vc4); /* If idle, we can stop watching for hangs. */ - if (!exec) { + if (!bin_exec && !render_exec) { spin_unlock_irqrestore(&vc4->job_lock, irqflags); return; } @@ -284,9 +304,12 @@ vc4_hangcheck_elapsed(unsigned long data) /* If we've made any progress in execution, rearm the timer * and wait. */ - if (ct0ca != exec->last_ct0ca || ct1ca != exec->last_ct1ca) { - exec->last_ct0ca = ct0ca; - exec->last_ct1ca = ct1ca; + if ((bin_exec && ct0ca != bin_exec->last_ct0ca) || + (render_exec && ct1ca != render_exec->last_ct1ca)) { + if (bin_exec) + bin_exec->last_ct0ca = ct0ca; + if (render_exec) + render_exec->last_ct1ca = ct1ca; spin_unlock_irqrestore(&vc4->job_lock, irqflags); vc4_queue_hangcheck(dev); return; @@ -386,11 +409,13 @@ vc4_flush_caches(struct drm_device *dev) * The job_lock should be held during this. */ void -vc4_submit_next_job(struct drm_device *dev) +vc4_submit_next_bin_job(struct drm_device *dev) { struct vc4_dev *vc4 = to_vc4_dev(dev); - struct vc4_exec_info *exec = vc4_first_job(vc4); + struct vc4_exec_info *exec; +again: + exec = vc4_first_bin_job(vc4); if (!exec) return; @@ -400,11 +425,40 @@ vc4_submit_next_job(struct drm_device *dev) V3D_WRITE(V3D_BPOA, 0); V3D_WRITE(V3D_BPOS, 0); - if (exec->ct0ca != exec->ct0ea) + /* Either put the job in the binner if it uses the binner, or + * immediately move it to the to-be-rendered queue. + */ + if (exec->ct0ca != exec->ct0ea) { submit_cl(dev, 0, exec->ct0ca, exec->ct0ea); + } else { + vc4_move_job_to_render(dev, exec); + goto again; + } +} + +void +vc4_submit_next_render_job(struct drm_device *dev) +{ + struct vc4_dev *vc4 = to_vc4_dev(dev); + struct vc4_exec_info *exec = vc4_first_render_job(vc4); + + if (!exec) + return; + submit_cl(dev, 1, exec->ct1ca, exec->ct1ea); } +void +vc4_move_job_to_render(struct drm_device *dev, struct vc4_exec_info *exec) +{ + struct vc4_dev *vc4 = to_vc4_dev(dev); + bool was_empty = list_empty(&vc4->render_job_list); + + list_move_tail(&exec->head, &vc4->render_job_list); + if (was_empty) + vc4_submit_next_render_job(dev); +} + static void vc4_update_bo_seqnos(struct vc4_exec_info *exec, uint64_t seqno) { @@ -443,14 +497,14 @@ vc4_queue_submit(struct drm_device *dev, struct vc4_exec_info *exec) exec->seqno = seqno; vc4_update_bo_seqnos(exec, seqno); - list_add_tail(&exec->head, &vc4->job_list); + list_add_tail(&exec->head, &vc4->bin_job_list); /* If no job was executing, kick ours off. Otherwise, it'll - * get started when the previous job's frame done interrupt + * get started when the previous job's flush done interrupt * occurs. */ - if (vc4_first_job(vc4) == exec) { - vc4_submit_next_job(dev); + if (vc4_first_bin_job(vc4) == exec) { + vc4_submit_next_bin_job(dev); vc4_queue_hangcheck(dev); } @@ -859,7 +913,8 @@ vc4_gem_init(struct drm_device *dev) { struct vc4_dev *vc4 = to_vc4_dev(dev); - INIT_LIST_HEAD(&vc4->job_list); + INIT_LIST_HEAD(&vc4->bin_job_list); + INIT_LIST_HEAD(&vc4->render_job_list); INIT_LIST_HEAD(&vc4->job_done_list); INIT_LIST_HEAD(&vc4->seqno_cb_list); spin_lock_init(&vc4->job_lock); diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c index 56272ca98ab7..d8b864925fd3 100644 --- a/drivers/gpu/drm/vc4/vc4_hdmi.c +++ b/drivers/gpu/drm/vc4/vc4_hdmi.c @@ -47,6 +47,7 @@ struct vc4_hdmi { void __iomem *hdmicore_regs; void __iomem *hd_regs; int hpd_gpio; + bool hpd_active_low; struct clk *pixel_clock; struct clk *hsm_clock; @@ -166,7 +167,8 @@ vc4_hdmi_connector_detect(struct drm_connector *connector, bool force) struct vc4_dev *vc4 = to_vc4_dev(dev); if (vc4->hdmi->hpd_gpio) { - if (gpio_get_value(vc4->hdmi->hpd_gpio)) + if (gpio_get_value_cansleep(vc4->hdmi->hpd_gpio) ^ + vc4->hdmi->hpd_active_low) return connector_status_connected; else return connector_status_disconnected; @@ -517,11 +519,17 @@ static int vc4_hdmi_bind(struct device *dev, struct device *master, void *data) * we'll use the HDMI core's register. */ if (of_find_property(dev->of_node, "hpd-gpios", &value)) { - hdmi->hpd_gpio = of_get_named_gpio(dev->of_node, "hpd-gpios", 0); + enum of_gpio_flags hpd_gpio_flags; + + hdmi->hpd_gpio = of_get_named_gpio_flags(dev->of_node, + "hpd-gpios", 0, + &hpd_gpio_flags); if (hdmi->hpd_gpio < 0) { ret = hdmi->hpd_gpio; goto err_unprepare_hsm; } + + hdmi->hpd_active_low = hpd_gpio_flags & OF_GPIO_ACTIVE_LOW; } vc4->hdmi = hdmi; diff --git a/drivers/gpu/drm/vc4/vc4_irq.c b/drivers/gpu/drm/vc4/vc4_irq.c index 78a21357fb2d..b0104a346a74 100644 --- a/drivers/gpu/drm/vc4/vc4_irq.c +++ b/drivers/gpu/drm/vc4/vc4_irq.c @@ -30,6 +30,10 @@ * disables that specific interrupt, and 0s written are ignored * (reading either one returns the set of enabled interrupts). * + * When we take a binning flush done interrupt, we need to submit the + * next frame for binning and move the finished frame to the render + * thread. + * * When we take a render frame interrupt, we need to wake the * processes waiting for some frame to be done, and get the next frame * submitted ASAP (so the hardware doesn't sit idle when there's work @@ -44,6 +48,7 @@ #include "vc4_regs.h" #define V3D_DRIVER_IRQS (V3D_INT_OUTOMEM | \ + V3D_INT_FLDONE | \ V3D_INT_FRDONE) DECLARE_WAIT_QUEUE_HEAD(render_wait); @@ -77,7 +82,7 @@ vc4_overflow_mem_work(struct work_struct *work) unsigned long irqflags; spin_lock_irqsave(&vc4->job_lock, irqflags); - current_exec = vc4_first_job(vc4); + current_exec = vc4_first_bin_job(vc4); if (current_exec) { vc4->overflow_mem->seqno = vc4->finished_seqno + 1; list_add_tail(&vc4->overflow_mem->unref_head, @@ -98,17 +103,43 @@ vc4_overflow_mem_work(struct work_struct *work) } static void -vc4_irq_finish_job(struct drm_device *dev) +vc4_irq_finish_bin_job(struct drm_device *dev) +{ + struct vc4_dev *vc4 = to_vc4_dev(dev); + struct vc4_exec_info *exec = vc4_first_bin_job(vc4); + + if (!exec) + return; + + vc4_move_job_to_render(dev, exec); + vc4_submit_next_bin_job(dev); +} + +static void +vc4_cancel_bin_job(struct drm_device *dev) +{ + struct vc4_dev *vc4 = to_vc4_dev(dev); + struct vc4_exec_info *exec = vc4_first_bin_job(vc4); + + if (!exec) + return; + + list_move_tail(&exec->head, &vc4->bin_job_list); + vc4_submit_next_bin_job(dev); +} + +static void +vc4_irq_finish_render_job(struct drm_device *dev) { struct vc4_dev *vc4 = to_vc4_dev(dev); - struct vc4_exec_info *exec = vc4_first_job(vc4); + struct vc4_exec_info *exec = vc4_first_render_job(vc4); if (!exec) return; vc4->finished_seqno++; list_move_tail(&exec->head, &vc4->job_done_list); - vc4_submit_next_job(dev); + vc4_submit_next_render_job(dev); wake_up_all(&vc4->job_wait_queue); schedule_work(&vc4->job_done_work); @@ -125,9 +156,10 @@ vc4_irq(int irq, void *arg) barrier(); intctl = V3D_READ(V3D_INTCTL); - /* Acknowledge the interrupts we're handling here. The render - * frame done interrupt will be cleared, while OUTOMEM will - * stay high until the underlying cause is cleared. + /* Acknowledge the interrupts we're handling here. The binner + * last flush / render frame done interrupt will be cleared, + * while OUTOMEM will stay high until the underlying cause is + * cleared. */ V3D_WRITE(V3D_INTCTL, intctl); @@ -138,9 +170,16 @@ vc4_irq(int irq, void *arg) status = IRQ_HANDLED; } + if (intctl & V3D_INT_FLDONE) { + spin_lock(&vc4->job_lock); + vc4_irq_finish_bin_job(dev); + spin_unlock(&vc4->job_lock); + status = IRQ_HANDLED; + } + if (intctl & V3D_INT_FRDONE) { spin_lock(&vc4->job_lock); - vc4_irq_finish_job(dev); + vc4_irq_finish_render_job(dev); spin_unlock(&vc4->job_lock); status = IRQ_HANDLED; } @@ -205,6 +244,7 @@ void vc4_irq_reset(struct drm_device *dev) V3D_WRITE(V3D_INTENA, V3D_DRIVER_IRQS); spin_lock_irqsave(&vc4->job_lock, irqflags); - vc4_irq_finish_job(dev); + vc4_cancel_bin_job(dev); + vc4_irq_finish_render_job(dev); spin_unlock_irqrestore(&vc4->job_lock, irqflags); } diff --git a/drivers/gpu/drm/vc4/vc4_v3d.c b/drivers/gpu/drm/vc4/vc4_v3d.c index 31de5d17bc85..e6d3c6028341 100644 --- a/drivers/gpu/drm/vc4/vc4_v3d.c +++ b/drivers/gpu/drm/vc4/vc4_v3d.c @@ -268,6 +268,7 @@ static int vc4_v3d_dev_remove(struct platform_device *pdev) } static const struct of_device_id vc4_v3d_dt_match[] = { + { .compatible = "brcm,bcm2835-v3d" }, { .compatible = "brcm,vc4-v3d" }, {} }; diff --git a/drivers/gpu/drm/virtio/virtgpu_display.c b/drivers/gpu/drm/virtio/virtgpu_display.c index 429aa311685a..4854dac87e24 100644 --- a/drivers/gpu/drm/virtio/virtgpu_display.c +++ b/drivers/gpu/drm/virtio/virtgpu_display.c @@ -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, }; diff --git a/drivers/gpu/host1x/bus.c b/drivers/gpu/host1x/bus.c index dd2dbb9746ce..c27858ae0552 100644 --- a/drivers/gpu/host1x/bus.c +++ b/drivers/gpu/host1x/bus.c @@ -83,8 +83,10 @@ static int host1x_device_parse_dt(struct host1x_device *device, if (of_match_node(driver->subdevs, np) && of_device_is_available(np)) { err = host1x_subdev_add(device, np); - if (err < 0) + if (err < 0) { + of_node_put(np); return err; + } } } diff --git a/drivers/gpu/host1x/job.c b/drivers/gpu/host1x/job.c index 63bd63f3c7df..1919aab88c3f 100644 --- a/drivers/gpu/host1x/job.c +++ b/drivers/gpu/host1x/job.c @@ -225,7 +225,7 @@ unpin: return 0; } -static unsigned int do_relocs(struct host1x_job *job, struct host1x_bo *cmdbuf) +static int do_relocs(struct host1x_job *job, struct host1x_bo *cmdbuf) { int i = 0; u32 last_page = ~0; diff --git a/include/drm/drm_atomic_helper.h b/include/drm/drm_atomic_helper.h index fe5efada9d68..9054598c9a7a 100644 --- a/include/drm/drm_atomic_helper.h +++ b/include/drm/drm_atomic_helper.h @@ -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 diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h index 7fad193dc645..e0170bf80bb0 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h @@ -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; @@ -1584,6 +1597,8 @@ struct drm_bridge_funcs { * * The bridge can assume that the display pipe (i.e. clocks and timing * signals) feeding it is still running when this callback is called. + * + * The disable callback is optional. */ void (*disable)(struct drm_bridge *bridge); @@ -1600,6 +1615,8 @@ struct drm_bridge_funcs { * The bridge must assume that the display pipe (i.e. clocks and timing * singals) feeding it is no longer running when this callback is * called. + * + * The post_disable callback is optional. */ void (*post_disable)(struct drm_bridge *bridge); @@ -1628,6 +1645,8 @@ struct drm_bridge_funcs { * will not yet be running when this callback is called. The bridge must * not enable the display link feeding the next bridge in the chain (if * there is one) when this callback is called. + * + * The pre_enable callback is optional. */ void (*pre_enable)(struct drm_bridge *bridge); @@ -1645,6 +1664,8 @@ struct drm_bridge_funcs { * signals) feeding it is running when this callback is called. This * callback must enable the display link feeding the next bridge in the * chain if there is one. + * + * The enable callback is optional. */ void (*enable)(struct drm_bridge *bridge); }; @@ -1677,6 +1698,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 +1712,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 +2049,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 +2160,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 +2593,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) \ diff --git a/include/drm/drm_crtc_helper.h b/include/drm/drm_crtc_helper.h index 4b37afa2b73b..97fa894d4ee2 100644 --- a/include/drm/drm_crtc_helper.h +++ b/include/drm/drm_crtc_helper.h @@ -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); diff --git a/include/drm/drm_mipi_dsi.h b/include/drm/drm_mipi_dsi.h index 1b3b1f8c8cdf..7a9840f8b38e 100644 --- a/include/drm/drm_mipi_dsi.h +++ b/include/drm/drm_mipi_dsi.h @@ -96,14 +96,17 @@ struct mipi_dsi_host_ops { * struct mipi_dsi_host - DSI host device * @dev: driver model device node for this DSI host * @ops: DSI host operations + * @list: list management */ struct mipi_dsi_host { struct device *dev; const struct mipi_dsi_host_ops *ops; + struct list_head list; }; int mipi_dsi_host_register(struct mipi_dsi_host *host); void mipi_dsi_host_unregister(struct mipi_dsi_host *host); +struct mipi_dsi_host *of_find_mipi_dsi_host_by_node(struct device_node *node); /* DSI mode flags */ @@ -139,10 +142,28 @@ enum mipi_dsi_pixel_format { MIPI_DSI_FMT_RGB565, }; +#define DSI_DEV_NAME_SIZE 20 + +/** + * struct mipi_dsi_device_info - template for creating a mipi_dsi_device + * @type: DSI peripheral chip type + * @channel: DSI virtual channel assigned to peripheral + * @node: pointer to OF device node or NULL + * + * This is populated and passed to mipi_dsi_device_new to create a new + * DSI device + */ +struct mipi_dsi_device_info { + char type[DSI_DEV_NAME_SIZE]; + u32 channel; + struct device_node *node; +}; + /** * struct mipi_dsi_device - DSI peripheral device * @host: DSI host for this peripheral * @dev: driver model device node for this peripheral + * @name: DSI peripheral chip type * @channel: virtual channel assigned to the peripheral * @format: pixel format for video mode * @lanes: number of active data lanes @@ -152,6 +173,7 @@ struct mipi_dsi_device { struct mipi_dsi_host *host; struct device dev; + char name[DSI_DEV_NAME_SIZE]; unsigned int channel; unsigned int lanes; enum mipi_dsi_pixel_format format; @@ -188,6 +210,10 @@ static inline int mipi_dsi_pixel_format_to_bpp(enum mipi_dsi_pixel_format fmt) return -EINVAL; } +struct mipi_dsi_device * +mipi_dsi_device_register_full(struct mipi_dsi_host *host, + const struct mipi_dsi_device_info *info); +void mipi_dsi_device_unregister(struct mipi_dsi_device *dsi); struct mipi_dsi_device *of_find_mipi_dsi_device_by_node(struct device_node *np); int mipi_dsi_attach(struct mipi_dsi_device *dsi); int mipi_dsi_detach(struct mipi_dsi_device *dsi); diff --git a/include/uapi/drm/drm_mode.h b/include/uapi/drm/drm_mode.h index 50adb46204c2..c0217434d28d 100644 --- a/include/uapi/drm/drm_mode.h +++ b/include/uapi/drm/drm_mode.h @@ -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) |