Skip to content

Commit

Permalink
Merge tag 'drm-misc-next-2017-06-02' of git://anongit.freedesktop.org…
Browse files Browse the repository at this point in the history
…/git/drm-misc into drm-next

Core Changes:
- Stop proliferation of drm_vblank_cleanup by adding to the docs and deleting
  boilerplate (Daniel)
- Roll out and use mode_valid hooks across crtc/encoder/bridge (Jose)
- Add drm_vblank.[hc] to isolate vblank code from optional irq helpers (Daniel)

Driver Changes:
- Replace drm_for_each_connector with drm_for_each_connector_iter (Gustavo)
- A couple misc driver fixes

Cc: Gustavo Padovan <gustavo.padovan@collabora.com>
Cc: Jose Abreu <Jose.Abreu@synopsys.com>
Cc: Daniel Vetter <daniel.vetter@intel.com>

* tag 'drm-misc-next-2017-06-02' of git://anongit.freedesktop.org/git/drm-misc: (34 commits)
  drm/vc4: Mark the device as active when enabling runtime PM.
  drm: remove writeq/readq function definitions
  drm/atmel-hlcdc: Use crtc->mode_valid() callback
  drm/exynos: Drop drm_vblank_cleanup
  drm/hdlcd|mali: Drop drm_vblank_cleanup
  drm/doc: Polish irq helper documentation
  drm: Extract drm_vblank.[hc]
  drm/vc4: Fix comment in vc4_drv.h
  drm/pl111: fix warnings without CONFIG_ARM_AMBA
  drm/atomic: Consitfy mode parameter to drm_atomic_set_mode_for_crtc()
  drm/arcgpu: Drop drm_vblank_cleanup
  drm/atmel: Drop drm_vblank_cleanup
  drm/imx: Drop drm_vblank_cleanup
  drm/meson: Drop drm_vblank_cleanup
  drm/stm: Drop drm_vblank_cleanup
  drm/sun4i: Drop drm_vblank_cleanup
  drm: better document how to send out the crtc disable event
  drm: Use vsnprintf extension %ph
  drm/doc: move printf helpers out of drmP.h
  drm/pl111: select DRM_PANEL
  ...
  • Loading branch information
Dave Airlie committed Jun 6, 2017
2 parents 562ff05 + 7f69694 commit 55f5b0b
Show file tree
Hide file tree
Showing 50 changed files with 2,278 additions and 1,987 deletions.
63 changes: 9 additions & 54 deletions Documentation/gpu/drm-internals.rst
Original file line number Diff line number Diff line change
Expand Up @@ -149,60 +149,15 @@ Device Instance and Driver Handling
Driver Load
-----------

IRQ Registration
~~~~~~~~~~~~~~~~

The DRM core tries to facilitate IRQ handler registration and
unregistration by providing :c:func:`drm_irq_install()` and
:c:func:`drm_irq_uninstall()` functions. Those functions only
support a single interrupt per device, devices that use more than one
IRQs need to be handled manually.

Managed IRQ Registration
''''''''''''''''''''''''

:c:func:`drm_irq_install()` starts by calling the irq_preinstall
driver operation. The operation is optional and must make sure that the
interrupt will not get fired by clearing all pending interrupt flags or
disabling the interrupt.

The passed-in IRQ will then be requested by a call to
:c:func:`request_irq()`. If the DRIVER_IRQ_SHARED driver feature
flag is set, a shared (IRQF_SHARED) IRQ handler will be requested.

The IRQ handler function must be provided as the mandatory irq_handler
driver operation. It will get passed directly to
:c:func:`request_irq()` and thus has the same prototype as all IRQ
handlers. It will get called with a pointer to the DRM device as the
second argument.

Finally the function calls the optional irq_postinstall driver
operation. The operation usually enables interrupts (excluding the
vblank interrupt, which is enabled separately), but drivers may choose
to enable/disable interrupts at a different time.

:c:func:`drm_irq_uninstall()` is similarly used to uninstall an
IRQ handler. It starts by waking up all processes waiting on a vblank
interrupt to make sure they don't hang, and then calls the optional
irq_uninstall driver operation. The operation must disable all hardware
interrupts. Finally the function frees the IRQ by calling
:c:func:`free_irq()`.

Manual IRQ Registration
'''''''''''''''''''''''

Drivers that require multiple interrupt handlers can't use the managed
IRQ registration functions. In that case IRQs must be registered and
unregistered manually (usually with the :c:func:`request_irq()` and
:c:func:`free_irq()` functions, or their :c:func:`devm_request_irq()` and
:c:func:`devm_free_irq()` equivalents).

When manually registering IRQs, drivers must not set the
DRIVER_HAVE_IRQ driver feature flag, and must not provide the
irq_handler driver operation. They must set the :c:type:`struct
drm_device <drm_device>` irq_enabled field to 1 upon
registration of the IRQs, and clear it to 0 after unregistering the
IRQs.

IRQ Helper Library
~~~~~~~~~~~~~~~~~~

.. kernel-doc:: drivers/gpu/drm/drm_irq.c
:doc: irq helpers

.. kernel-doc:: drivers/gpu/drm/drm_irq.c
:export:

Memory Manager Initialization
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Expand Down
4 changes: 2 additions & 2 deletions Documentation/gpu/drm-kms.rst
Original file line number Diff line number Diff line change
Expand Up @@ -612,8 +612,8 @@ operation handler.
Vertical Blanking and Interrupt Handling Functions Reference
------------------------------------------------------------

.. kernel-doc:: include/drm/drm_irq.h
.. kernel-doc:: include/drm/drm_vblank.h
:internal:

.. kernel-doc:: drivers/gpu/drm/drm_irq.c
.. kernel-doc:: drivers/gpu/drm/drm_vblank.c
:export:
13 changes: 0 additions & 13 deletions Documentation/gpu/todo.rst
Original file line number Diff line number Diff line change
Expand Up @@ -177,19 +177,6 @@ following drivers still use ``struct_mutex``: ``msm``, ``omapdrm`` and

Contact: Daniel Vetter, respective driver maintainers

Switch to drm_connector_list_iter for any connector_list walking
----------------------------------------------------------------

Connectors can be hotplugged, and we now have a special list of helpers to walk
the connector_list in a race-free fashion, without incurring deadlocks on
mutexes and other fun stuff.

Unfortunately most drivers are not converted yet. At least all those supporting
DP MST hotplug should be converted, since for those drivers the difference
matters. See drm_for_each_connector_iter() vs. drm_for_each_connector().

Contact: Daniel Vetter

Core refactorings
=================

Expand Down
2 changes: 1 addition & 1 deletion drivers/gpu/drm/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ drm-y := drm_auth.o drm_bufs.o drm_cache.o \
drm_framebuffer.o drm_connector.o drm_blend.o \
drm_encoder.o drm_mode_object.o drm_property.o \
drm_plane.o drm_color_mgmt.o drm_print.o \
drm_dumb_buffers.o drm_mode_config.o
drm_dumb_buffers.o drm_mode_config.o drm_vblank.o

drm-$(CONFIG_DRM_LIB_RANDOM) += lib/drm_random.o
drm-$(CONFIG_DRM_VM) += drm_vm.o
Expand Down
1 change: 0 additions & 1 deletion drivers/gpu/drm/arc/arcpgu_drv.c
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,6 @@ static int arcpgu_unload(struct drm_device *drm)
arcpgu->fbdev = NULL;
}
drm_kms_helper_poll_fini(drm);
drm_vblank_cleanup(drm);
drm_mode_config_cleanup(drm);

return 0;
Expand Down
2 changes: 0 additions & 2 deletions drivers/gpu/drm/arm/hdlcd_drv.c
Original file line number Diff line number Diff line change
Expand Up @@ -340,7 +340,6 @@ static int hdlcd_drm_bind(struct device *dev)
}
err_fbdev:
drm_kms_helper_poll_fini(drm);
drm_vblank_cleanup(drm);
err_vblank:
pm_runtime_disable(drm->dev);
err_pm_active:
Expand Down Expand Up @@ -368,7 +367,6 @@ static void hdlcd_drm_unbind(struct device *dev)
}
drm_kms_helper_poll_fini(drm);
component_unbind_all(dev, drm);
drm_vblank_cleanup(drm);
pm_runtime_get_sync(drm->dev);
drm_irq_uninstall(drm);
pm_runtime_put_sync(drm->dev);
Expand Down
2 changes: 0 additions & 2 deletions drivers/gpu/drm/arm/malidp_drv.c
Original file line number Diff line number Diff line change
Expand Up @@ -652,7 +652,6 @@ static int malidp_bind(struct device *dev)
drm_kms_helper_poll_fini(drm);
fbdev_fail:
pm_runtime_get_sync(dev);
drm_vblank_cleanup(drm);
vblank_fail:
malidp_se_irq_fini(drm);
malidp_de_irq_fini(drm);
Expand Down Expand Up @@ -692,7 +691,6 @@ static void malidp_unbind(struct device *dev)
}
drm_kms_helper_poll_fini(drm);
pm_runtime_get_sync(dev);
drm_vblank_cleanup(drm);
malidp_se_irq_fini(drm);
malidp_de_irq_fini(drm);
component_unbind_all(dev, drm);
Expand Down
10 changes: 5 additions & 5 deletions drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c
Original file line number Diff line number Diff line change
Expand Up @@ -140,13 +140,13 @@ static void atmel_hlcdc_crtc_mode_set_nofb(struct drm_crtc *c)
cfg);
}

static bool atmel_hlcdc_crtc_mode_fixup(struct drm_crtc *c,
const struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode)
static enum drm_mode_status
atmel_hlcdc_crtc_mode_valid(struct drm_crtc *c,
const struct drm_display_mode *mode)
{
struct atmel_hlcdc_crtc *crtc = drm_crtc_to_atmel_hlcdc_crtc(c);

return atmel_hlcdc_dc_mode_valid(crtc->dc, adjusted_mode) == MODE_OK;
return atmel_hlcdc_dc_mode_valid(crtc->dc, mode);
}

static void atmel_hlcdc_crtc_disable(struct drm_crtc *c)
Expand Down Expand Up @@ -315,7 +315,7 @@ 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_valid = atmel_hlcdc_crtc_mode_valid,
.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,
Expand Down
6 changes: 3 additions & 3 deletions drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c
Original file line number Diff line number Diff line change
Expand Up @@ -375,8 +375,9 @@ static const struct of_device_id atmel_hlcdc_of_match[] = {
};
MODULE_DEVICE_TABLE(of, atmel_hlcdc_of_match);

int atmel_hlcdc_dc_mode_valid(struct atmel_hlcdc_dc *dc,
struct drm_display_mode *mode)
enum drm_mode_status
atmel_hlcdc_dc_mode_valid(struct atmel_hlcdc_dc *dc,
const struct drm_display_mode *mode)
{
int vfront_porch = mode->vsync_start - mode->vdisplay;
int vback_porch = mode->vtotal - mode->vsync_end;
Expand Down Expand Up @@ -678,7 +679,6 @@ static void atmel_hlcdc_dc_unload(struct drm_device *dev)
flush_workqueue(dc->wq);
drm_kms_helper_poll_fini(dev);
drm_mode_config_cleanup(dev);
drm_vblank_cleanup(dev);

pm_runtime_get_sync(dev->dev);
drm_irq_uninstall(dev);
Expand Down
5 changes: 3 additions & 2 deletions drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.h
Original file line number Diff line number Diff line change
Expand Up @@ -422,8 +422,9 @@ static inline void atmel_hlcdc_layer_init(struct atmel_hlcdc_layer *layer,
layer->regmap = regmap;
}

int atmel_hlcdc_dc_mode_valid(struct atmel_hlcdc_dc *dc,
struct drm_display_mode *mode);
enum drm_mode_status
atmel_hlcdc_dc_mode_valid(struct atmel_hlcdc_dc *dc,
const struct drm_display_mode *mode);

int atmel_hlcdc_create_planes(struct drm_device *dev);
void atmel_hlcdc_plane_irq(struct atmel_hlcdc_plane *plane);
Expand Down
14 changes: 7 additions & 7 deletions drivers/gpu/drm/bridge/analogix-anx78xx.c
Original file line number Diff line number Diff line change
Expand Up @@ -1061,18 +1061,18 @@ static int anx78xx_bridge_attach(struct drm_bridge *bridge)
return 0;
}

static bool anx78xx_bridge_mode_fixup(struct drm_bridge *bridge,
const struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode)
static enum drm_mode_status
anx78xx_bridge_mode_valid(struct drm_bridge *bridge,
const struct drm_display_mode *mode)
{
if (mode->flags & DRM_MODE_FLAG_INTERLACE)
return false;
return MODE_NO_INTERLACE;

/* Max 1200p at 5.4 Ghz, one lane */
if (mode->clock > 154000)
return false;
return MODE_CLOCK_HIGH;

return true;
return MODE_OK;
}

static void anx78xx_bridge_disable(struct drm_bridge *bridge)
Expand Down Expand Up @@ -1129,7 +1129,7 @@ static void anx78xx_bridge_enable(struct drm_bridge *bridge)

static const struct drm_bridge_funcs anx78xx_bridge_funcs = {
.attach = anx78xx_bridge_attach,
.mode_fixup = anx78xx_bridge_mode_fixup,
.mode_valid = anx78xx_bridge_mode_valid,
.disable = anx78xx_bridge_disable,
.mode_set = anx78xx_bridge_mode_set,
.enable = anx78xx_bridge_enable,
Expand Down
2 changes: 1 addition & 1 deletion drivers/gpu/drm/drm_atomic.c
Original file line number Diff line number Diff line change
Expand Up @@ -328,7 +328,7 @@ static s32 __user *get_out_fence_for_crtc(struct drm_atomic_state *state,
* Zero on success, error code on failure. Cannot return -EDEADLK.
*/
int drm_atomic_set_mode_for_crtc(struct drm_crtc_state *state,
struct drm_display_mode *mode)
const struct drm_display_mode *mode)
{
struct drm_mode_modeinfo umode;

Expand Down
76 changes: 73 additions & 3 deletions drivers/gpu/drm/drm_atomic_helper.c
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
#include <drm/drm_atomic_helper.h>
#include <linux/dma-fence.h>

#include "drm_crtc_helper_internal.h"
#include "drm_crtc_internal.h"

/**
Expand Down Expand Up @@ -452,6 +453,69 @@ mode_fixup(struct drm_atomic_state *state)
return 0;
}

static enum drm_mode_status mode_valid_path(struct drm_connector *connector,
struct drm_encoder *encoder,
struct drm_crtc *crtc,
struct drm_display_mode *mode)
{
enum drm_mode_status ret;

ret = drm_encoder_mode_valid(encoder, mode);
if (ret != MODE_OK) {
DRM_DEBUG_ATOMIC("[ENCODER:%d:%s] mode_valid() failed\n",
encoder->base.id, encoder->name);
return ret;
}

ret = drm_bridge_mode_valid(encoder->bridge, mode);
if (ret != MODE_OK) {
DRM_DEBUG_ATOMIC("[BRIDGE] mode_valid() failed\n");
return ret;
}

ret = drm_crtc_mode_valid(crtc, mode);
if (ret != MODE_OK) {
DRM_DEBUG_ATOMIC("[CRTC:%d:%s] mode_valid() failed\n",
crtc->base.id, crtc->name);
return ret;
}

return ret;
}

static int
mode_valid(struct drm_atomic_state *state)
{
struct drm_connector_state *conn_state;
struct drm_connector *connector;
int i;

for_each_new_connector_in_state(state, connector, conn_state, i) {
struct drm_encoder *encoder = conn_state->best_encoder;
struct drm_crtc *crtc = conn_state->crtc;
struct drm_crtc_state *crtc_state;
enum drm_mode_status mode_status;
struct drm_display_mode *mode;

if (!crtc || !encoder)
continue;

crtc_state = drm_atomic_get_new_crtc_state(state, crtc);
if (!crtc_state)
continue;
if (!crtc_state->mode_changed && !crtc_state->connectors_changed)
continue;

mode = &crtc_state->mode;

mode_status = mode_valid_path(connector, encoder, crtc, mode);
if (mode_status != MODE_OK)
return -EINVAL;
}

return 0;
}

/**
* drm_atomic_helper_check_modeset - validate state object for modeset changes
* @dev: DRM device
Expand All @@ -466,13 +530,15 @@ mode_fixup(struct drm_atomic_state *state)
* 2. &drm_connector_helper_funcs.atomic_check to validate the connector state.
* 3. If it's determined a modeset is needed then all connectors on the affected crtc
* crtc are added and &drm_connector_helper_funcs.atomic_check is run on them.
* 4. &drm_bridge_funcs.mode_fixup is called on all encoder bridges.
* 5. &drm_encoder_helper_funcs.atomic_check is called to validate any encoder state.
* 4. &drm_encoder_helper_funcs.mode_valid, &drm_bridge_funcs.mode_valid and
* &drm_crtc_helper_funcs.mode_valid are called on the affected components.
* 5. &drm_bridge_funcs.mode_fixup is called on all encoder bridges.
* 6. &drm_encoder_helper_funcs.atomic_check is called to validate any encoder state.
* This function is only called when the encoder will be part of a configured crtc,
* it must not be used for implementing connector property validation.
* If this function is NULL, &drm_atomic_encoder_helper_funcs.mode_fixup is called
* instead.
* 6. &drm_crtc_helper_funcs.mode_fixup is called last, to fix up the mode with crtc constraints.
* 7. &drm_crtc_helper_funcs.mode_fixup is called last, to fix up the mode with crtc constraints.
*
* &drm_crtc_state.mode_changed is set when the input mode is changed.
* &drm_crtc_state.connectors_changed is set when a connector is added or
Expand Down Expand Up @@ -617,6 +683,10 @@ drm_atomic_helper_check_modeset(struct drm_device *dev,
return ret;
}

ret = mode_valid(state);
if (ret)
return ret;

return mode_fixup(state);
}
EXPORT_SYMBOL(drm_atomic_helper_check_modeset);
Expand Down
33 changes: 33 additions & 0 deletions drivers/gpu/drm/drm_bridge.c
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,39 @@ bool drm_bridge_mode_fixup(struct drm_bridge *bridge,
}
EXPORT_SYMBOL(drm_bridge_mode_fixup);

/**
* drm_bridge_mode_valid - validate the mode against all bridges in the
* encoder chain.
* @bridge: bridge control structure
* @mode: desired mode to be validated
*
* Calls &drm_bridge_funcs.mode_valid for all the bridges in the encoder
* chain, starting from the first bridge to the last. If at least one bridge
* does not accept the mode the function returns the error code.
*
* Note: the bridge passed should be the one closest to the encoder.
*
* RETURNS:
* MODE_OK on success, drm_mode_status Enum error code on failure
*/
enum drm_mode_status drm_bridge_mode_valid(struct drm_bridge *bridge,
const struct drm_display_mode *mode)
{
enum drm_mode_status ret = MODE_OK;

if (!bridge)
return ret;

if (bridge->funcs->mode_valid)
ret = bridge->funcs->mode_valid(bridge, mode);

if (ret != MODE_OK)
return ret;

return drm_bridge_mode_valid(bridge->next, mode);
}
EXPORT_SYMBOL(drm_bridge_mode_valid);

/**
* drm_bridge_disable - disables all bridges in the encoder chain
* @bridge: bridge control structure
Expand Down
Loading

0 comments on commit 55f5b0b

Please sign in to comment.