mirror of https://gitee.com/openkylin/linux.git
Merge tag 'drm-misc-next-2017-06-02' of git://anongit.freedesktop.org/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 ...
This commit is contained in:
commit
55f5b0bf51
|
@ -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.
|
||||
IRQ Helper Library
|
||||
~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Managed IRQ Registration
|
||||
''''''''''''''''''''''''
|
||||
.. kernel-doc:: drivers/gpu/drm/drm_irq.c
|
||||
:doc: irq helpers
|
||||
|
||||
: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.
|
||||
.. kernel-doc:: drivers/gpu/drm/drm_irq.c
|
||||
:export:
|
||||
|
||||
Memory Manager Initialization
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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
|
||||
=================
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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:
|
||||
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
@ -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);
|
||||
|
|
|
@ -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)
|
||||
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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)
|
||||
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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"
|
||||
|
||||
/**
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -26,7 +26,11 @@
|
|||
* implementation details and are not exported to drivers.
|
||||
*/
|
||||
|
||||
#include <drm/drm_connector.h>
|
||||
#include <drm/drm_crtc.h>
|
||||
#include <drm/drm_dp_helper.h>
|
||||
#include <drm/drm_encoder.h>
|
||||
#include <drm/drm_modes.h>
|
||||
|
||||
/* drm_fb_helper.c */
|
||||
#ifdef CONFIG_DRM_FBDEV_EMULATION
|
||||
|
@ -63,3 +67,11 @@ static inline void drm_dp_aux_unregister_devnode(struct drm_dp_aux *aux)
|
|||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
/* drm_probe_helper.c */
|
||||
enum drm_mode_status drm_crtc_mode_valid(struct drm_crtc *crtc,
|
||||
const struct drm_display_mode *mode);
|
||||
enum drm_mode_status drm_encoder_mode_valid(struct drm_encoder *encoder,
|
||||
const struct drm_display_mode *mode);
|
||||
enum drm_mode_status drm_connector_mode_valid(struct drm_connector *connector,
|
||||
struct drm_display_mode *mode);
|
||||
|
|
|
@ -2836,16 +2836,15 @@ static void drm_dp_mst_dump_mstb(struct seq_file *m,
|
|||
static bool dump_dp_payload_table(struct drm_dp_mst_topology_mgr *mgr,
|
||||
char *buf)
|
||||
{
|
||||
int ret;
|
||||
int i;
|
||||
for (i = 0; i < 4; i++) {
|
||||
ret = drm_dp_dpcd_read(mgr->aux, DP_PAYLOAD_TABLE_UPDATE_STATUS + (i * 16), &buf[i * 16], 16);
|
||||
if (ret != 16)
|
||||
break;
|
||||
|
||||
for (i = 0; i < 64; i += 16) {
|
||||
if (drm_dp_dpcd_read(mgr->aux,
|
||||
DP_PAYLOAD_TABLE_UPDATE_STATUS + i,
|
||||
&buf[i], 16) != 16)
|
||||
return false;
|
||||
}
|
||||
if (i == 4)
|
||||
return true;
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
static void fetch_monitor_name(struct drm_dp_mst_topology_mgr *mgr,
|
||||
|
@ -2909,42 +2908,24 @@ void drm_dp_mst_dump_topology(struct seq_file *m,
|
|||
mutex_lock(&mgr->lock);
|
||||
if (mgr->mst_primary) {
|
||||
u8 buf[64];
|
||||
bool bret;
|
||||
int ret;
|
||||
|
||||
ret = drm_dp_dpcd_read(mgr->aux, DP_DPCD_REV, buf, DP_RECEIVER_CAP_SIZE);
|
||||
seq_printf(m, "dpcd: ");
|
||||
for (i = 0; i < DP_RECEIVER_CAP_SIZE; i++)
|
||||
seq_printf(m, "%02x ", buf[i]);
|
||||
seq_printf(m, "\n");
|
||||
seq_printf(m, "dpcd: %*ph\n", DP_RECEIVER_CAP_SIZE, buf);
|
||||
ret = drm_dp_dpcd_read(mgr->aux, DP_FAUX_CAP, buf, 2);
|
||||
seq_printf(m, "faux/mst: ");
|
||||
for (i = 0; i < 2; i++)
|
||||
seq_printf(m, "%02x ", buf[i]);
|
||||
seq_printf(m, "\n");
|
||||
seq_printf(m, "faux/mst: %*ph\n", 2, buf);
|
||||
ret = drm_dp_dpcd_read(mgr->aux, DP_MSTM_CTRL, buf, 1);
|
||||
seq_printf(m, "mst ctrl: ");
|
||||
for (i = 0; i < 1; i++)
|
||||
seq_printf(m, "%02x ", buf[i]);
|
||||
seq_printf(m, "\n");
|
||||
seq_printf(m, "mst ctrl: %*ph\n", 1, buf);
|
||||
|
||||
/* dump the standard OUI branch header */
|
||||
ret = drm_dp_dpcd_read(mgr->aux, DP_BRANCH_OUI, buf, DP_BRANCH_OUI_HEADER_SIZE);
|
||||
seq_printf(m, "branch oui: ");
|
||||
for (i = 0; i < 0x3; i++)
|
||||
seq_printf(m, "%02x", buf[i]);
|
||||
seq_printf(m, " devid: ");
|
||||
seq_printf(m, "branch oui: %*phN devid: ", 3, buf);
|
||||
for (i = 0x3; i < 0x8 && buf[i]; i++)
|
||||
seq_printf(m, "%c", buf[i]);
|
||||
|
||||
seq_printf(m, " revision: hw: %x.%x sw: %x.%x", buf[0x9] >> 4, buf[0x9] & 0xf, buf[0xa], buf[0xb]);
|
||||
seq_printf(m, "\n");
|
||||
bret = dump_dp_payload_table(mgr, buf);
|
||||
if (bret == true) {
|
||||
seq_printf(m, "payload table: ");
|
||||
for (i = 0; i < 63; i++)
|
||||
seq_printf(m, "%02x ", buf[i]);
|
||||
seq_printf(m, "\n");
|
||||
}
|
||||
seq_printf(m, " revision: hw: %x.%x sw: %x.%x\n",
|
||||
buf[0x9] >> 4, buf[0x9] & 0xf, buf[0xa], buf[0xb]);
|
||||
if (dump_dp_payload_table(mgr, buf))
|
||||
seq_printf(m, "payload table: %*ph\n", 63, buf);
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -53,8 +53,9 @@ int drm_name_info(struct seq_file *m, void *data);
|
|||
int drm_clients_info(struct seq_file *m, void* data);
|
||||
int drm_gem_name_info(struct seq_file *m, void *data);
|
||||
|
||||
/* drm_irq.c */
|
||||
/* drm_vblank.c */
|
||||
extern unsigned int drm_timestamp_monotonic;
|
||||
void drm_vblank_disable_and_save(struct drm_device *dev, unsigned int pipe);
|
||||
|
||||
/* IOCTLS */
|
||||
int drm_wait_vblank(struct drm_device *dev, void *data,
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -38,6 +38,9 @@
|
|||
#include <drm/drm_crtc_helper.h>
|
||||
#include <drm/drm_fb_helper.h>
|
||||
#include <drm/drm_edid.h>
|
||||
#include <drm/drm_modeset_helper_vtables.h>
|
||||
|
||||
#include "drm_crtc_helper_internal.h"
|
||||
|
||||
/**
|
||||
* DOC: output probing helper overview
|
||||
|
@ -80,6 +83,61 @@ drm_mode_validate_flag(const struct drm_display_mode *mode,
|
|||
return MODE_OK;
|
||||
}
|
||||
|
||||
static enum drm_mode_status
|
||||
drm_mode_validate_pipeline(struct drm_display_mode *mode,
|
||||
struct drm_connector *connector)
|
||||
{
|
||||
struct drm_device *dev = connector->dev;
|
||||
uint32_t *ids = connector->encoder_ids;
|
||||
enum drm_mode_status ret = MODE_OK;
|
||||
unsigned int i;
|
||||
|
||||
/* Step 1: Validate against connector */
|
||||
ret = drm_connector_mode_valid(connector, mode);
|
||||
if (ret != MODE_OK)
|
||||
return ret;
|
||||
|
||||
/* Step 2: Validate against encoders and crtcs */
|
||||
for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) {
|
||||
struct drm_encoder *encoder = drm_encoder_find(dev, ids[i]);
|
||||
struct drm_crtc *crtc;
|
||||
|
||||
if (!encoder)
|
||||
continue;
|
||||
|
||||
ret = drm_encoder_mode_valid(encoder, mode);
|
||||
if (ret != MODE_OK) {
|
||||
/* No point in continuing for crtc check as this encoder
|
||||
* will not accept the mode anyway. If all encoders
|
||||
* reject the mode then, at exit, ret will not be
|
||||
* MODE_OK. */
|
||||
continue;
|
||||
}
|
||||
|
||||
ret = drm_bridge_mode_valid(encoder->bridge, mode);
|
||||
if (ret != MODE_OK) {
|
||||
/* There is also no point in continuing for crtc check
|
||||
* here. */
|
||||
continue;
|
||||
}
|
||||
|
||||
drm_for_each_crtc(crtc, dev) {
|
||||
if (!drm_encoder_crtc_ok(encoder, crtc))
|
||||
continue;
|
||||
|
||||
ret = drm_crtc_mode_valid(crtc, mode);
|
||||
if (ret == MODE_OK) {
|
||||
/* If we get to this point there is at least
|
||||
* one combination of encoder+crtc that works
|
||||
* for this mode. Lets return now. */
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int drm_helper_probe_add_cmdline_mode(struct drm_connector *connector)
|
||||
{
|
||||
struct drm_cmdline_mode *cmdline_mode;
|
||||
|
@ -113,6 +171,41 @@ static int drm_helper_probe_add_cmdline_mode(struct drm_connector *connector)
|
|||
return 1;
|
||||
}
|
||||
|
||||
enum drm_mode_status drm_crtc_mode_valid(struct drm_crtc *crtc,
|
||||
const struct drm_display_mode *mode)
|
||||
{
|
||||
const struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private;
|
||||
|
||||
if (!crtc_funcs || !crtc_funcs->mode_valid)
|
||||
return MODE_OK;
|
||||
|
||||
return crtc_funcs->mode_valid(crtc, mode);
|
||||
}
|
||||
|
||||
enum drm_mode_status drm_encoder_mode_valid(struct drm_encoder *encoder,
|
||||
const struct drm_display_mode *mode)
|
||||
{
|
||||
const struct drm_encoder_helper_funcs *encoder_funcs =
|
||||
encoder->helper_private;
|
||||
|
||||
if (!encoder_funcs || !encoder_funcs->mode_valid)
|
||||
return MODE_OK;
|
||||
|
||||
return encoder_funcs->mode_valid(encoder, mode);
|
||||
}
|
||||
|
||||
enum drm_mode_status drm_connector_mode_valid(struct drm_connector *connector,
|
||||
struct drm_display_mode *mode)
|
||||
{
|
||||
const struct drm_connector_helper_funcs *connector_funcs =
|
||||
connector->helper_private;
|
||||
|
||||
if (!connector_funcs || !connector_funcs->mode_valid)
|
||||
return MODE_OK;
|
||||
|
||||
return connector_funcs->mode_valid(connector, mode);
|
||||
}
|
||||
|
||||
#define DRM_OUTPUT_POLL_PERIOD (10*HZ)
|
||||
/**
|
||||
* drm_kms_helper_poll_enable - re-enable output polling.
|
||||
|
@ -284,7 +377,11 @@ EXPORT_SYMBOL(drm_helper_probe_detect);
|
|||
* - drm_mode_validate_flag() checks the modes against basic connector
|
||||
* capabilities (interlace_allowed,doublescan_allowed,stereo_allowed)
|
||||
* - the optional &drm_connector_helper_funcs.mode_valid helper can perform
|
||||
* driver and/or hardware specific checks
|
||||
* driver and/or sink specific checks
|
||||
* - the optional &drm_crtc_helper_funcs.mode_valid,
|
||||
* &drm_bridge_funcs.mode_valid and &drm_encoder_helper_funcs.mode_valid
|
||||
* helpers can perform driver and/or source specific checks which are also
|
||||
* enforced by the modeset/atomic helpers
|
||||
*
|
||||
* 5. Any mode whose status is not OK is pruned from the connector's modes list,
|
||||
* accompanied by a debug message indicating the reason for the mode's
|
||||
|
@ -428,9 +525,9 @@ int drm_helper_probe_single_connector_modes(struct drm_connector *connector,
|
|||
if (mode->status == MODE_OK)
|
||||
mode->status = drm_mode_validate_flag(mode, mode_flags);
|
||||
|
||||
if (mode->status == MODE_OK && connector_funcs->mode_valid)
|
||||
mode->status = connector_funcs->mode_valid(connector,
|
||||
mode);
|
||||
if (mode->status == MODE_OK)
|
||||
mode->status = drm_mode_validate_pipeline(mode,
|
||||
connector);
|
||||
}
|
||||
|
||||
prune:
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -171,12 +171,13 @@ static int exynos_drm_suspend(struct device *dev)
|
|||
{
|
||||
struct drm_device *drm_dev = dev_get_drvdata(dev);
|
||||
struct drm_connector *connector;
|
||||
struct drm_connector_list_iter conn_iter;
|
||||
|
||||
if (pm_runtime_suspended(dev) || !drm_dev)
|
||||
return 0;
|
||||
|
||||
drm_modeset_lock_all(drm_dev);
|
||||
drm_for_each_connector(connector, drm_dev) {
|
||||
drm_connector_list_iter_begin(drm_dev, &conn_iter);
|
||||
drm_for_each_connector_iter(connector, &conn_iter) {
|
||||
int old_dpms = connector->dpms;
|
||||
|
||||
if (connector->funcs->dpms)
|
||||
|
@ -185,7 +186,7 @@ static int exynos_drm_suspend(struct device *dev)
|
|||
/* Set the old mode back to the connector for resume */
|
||||
connector->dpms = old_dpms;
|
||||
}
|
||||
drm_modeset_unlock_all(drm_dev);
|
||||
drm_connector_list_iter_end(&conn_iter);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -194,12 +195,13 @@ static int exynos_drm_resume(struct device *dev)
|
|||
{
|
||||
struct drm_device *drm_dev = dev_get_drvdata(dev);
|
||||
struct drm_connector *connector;
|
||||
struct drm_connector_list_iter conn_iter;
|
||||
|
||||
if (pm_runtime_suspended(dev) || !drm_dev)
|
||||
return 0;
|
||||
|
||||
drm_modeset_lock_all(drm_dev);
|
||||
drm_for_each_connector(connector, drm_dev) {
|
||||
drm_connector_list_iter_begin(drm_dev, &conn_iter);
|
||||
drm_for_each_connector_iter(connector, &conn_iter) {
|
||||
if (connector->funcs->dpms) {
|
||||
int dpms = connector->dpms;
|
||||
|
||||
|
@ -207,7 +209,7 @@ static int exynos_drm_resume(struct device *dev)
|
|||
connector->funcs->dpms(connector, dpms);
|
||||
}
|
||||
}
|
||||
drm_modeset_unlock_all(drm_dev);
|
||||
drm_connector_list_iter_end(&conn_iter);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -376,7 +378,7 @@ static int exynos_drm_bind(struct device *dev)
|
|||
/* Probe non kms sub drivers and virtual display driver. */
|
||||
ret = exynos_drm_device_subdrv_probe(drm);
|
||||
if (ret)
|
||||
goto err_cleanup_vblank;
|
||||
goto err_unbind_all;
|
||||
|
||||
drm_mode_config_reset(drm);
|
||||
|
||||
|
@ -407,8 +409,6 @@ static int exynos_drm_bind(struct device *dev)
|
|||
exynos_drm_fbdev_fini(drm);
|
||||
drm_kms_helper_poll_fini(drm);
|
||||
exynos_drm_device_subdrv_remove(drm);
|
||||
err_cleanup_vblank:
|
||||
drm_vblank_cleanup(drm);
|
||||
err_unbind_all:
|
||||
component_unbind_all(drm->dev, drm);
|
||||
err_mode_config_cleanup:
|
||||
|
|
|
@ -11400,6 +11400,7 @@ static bool check_digital_port_conflicts(struct drm_atomic_state *state)
|
|||
{
|
||||
struct drm_device *dev = state->dev;
|
||||
struct drm_connector *connector;
|
||||
struct drm_connector_list_iter conn_iter;
|
||||
unsigned int used_ports = 0;
|
||||
unsigned int used_mst_ports = 0;
|
||||
|
||||
|
@ -11408,7 +11409,8 @@ static bool check_digital_port_conflicts(struct drm_atomic_state *state)
|
|||
* list to detect the problem on ddi platforms
|
||||
* where there's just one encoder per digital port.
|
||||
*/
|
||||
drm_for_each_connector(connector, dev) {
|
||||
drm_connector_list_iter_begin(dev, &conn_iter);
|
||||
drm_for_each_connector_iter(connector, &conn_iter) {
|
||||
struct drm_connector_state *connector_state;
|
||||
struct intel_encoder *encoder;
|
||||
|
||||
|
@ -11447,6 +11449,7 @@ static bool check_digital_port_conflicts(struct drm_atomic_state *state)
|
|||
break;
|
||||
}
|
||||
}
|
||||
drm_connector_list_iter_end(&conn_iter);
|
||||
|
||||
/* can't mix MST and SST/HDMI on the same port */
|
||||
if (used_ports & used_mst_ports)
|
||||
|
|
|
@ -278,7 +278,7 @@ static int imx_drm_bind(struct device *dev)
|
|||
/* Now try and bind all our sub-components */
|
||||
ret = component_bind_all(dev, drm);
|
||||
if (ret)
|
||||
goto err_vblank;
|
||||
goto err_kms;
|
||||
|
||||
drm_mode_config_reset(drm);
|
||||
|
||||
|
@ -316,8 +316,6 @@ static int imx_drm_bind(struct device *dev)
|
|||
err_unbind:
|
||||
#endif
|
||||
component_unbind_all(drm->dev, drm);
|
||||
err_vblank:
|
||||
drm_vblank_cleanup(drm);
|
||||
err_kms:
|
||||
drm_mode_config_cleanup(drm);
|
||||
err_unref:
|
||||
|
|
|
@ -221,6 +221,7 @@ static int mtk_crtc_ddp_hw_init(struct mtk_drm_crtc *mtk_crtc)
|
|||
struct drm_crtc *crtc = &mtk_crtc->base;
|
||||
struct drm_connector *connector;
|
||||
struct drm_encoder *encoder;
|
||||
struct drm_connector_list_iter conn_iter;
|
||||
unsigned int width, height, vrefresh, bpc = MTK_MAX_BPC;
|
||||
int ret;
|
||||
int i;
|
||||
|
@ -237,13 +238,15 @@ static int mtk_crtc_ddp_hw_init(struct mtk_drm_crtc *mtk_crtc)
|
|||
if (encoder->crtc != crtc)
|
||||
continue;
|
||||
|
||||
drm_for_each_connector(connector, crtc->dev) {
|
||||
drm_connector_list_iter_begin(crtc->dev, &conn_iter);
|
||||
drm_for_each_connector_iter(connector, &conn_iter) {
|
||||
if (connector->encoder != encoder)
|
||||
continue;
|
||||
if (connector->display_info.bpc != 0 &&
|
||||
bpc > connector->display_info.bpc)
|
||||
bpc = connector->display_info.bpc;
|
||||
}
|
||||
drm_connector_list_iter_end(&conn_iter);
|
||||
}
|
||||
|
||||
ret = pm_runtime_get_sync(crtc->dev->dev);
|
||||
|
|
|
@ -285,7 +285,6 @@ static void meson_drv_unbind(struct device *dev)
|
|||
drm_kms_helper_poll_fini(drm);
|
||||
drm_fbdev_cma_fini(priv->fbdev);
|
||||
drm_mode_config_cleanup(drm);
|
||||
drm_vblank_cleanup(drm);
|
||||
drm_dev_unref(drm);
|
||||
|
||||
}
|
||||
|
|
|
@ -2872,17 +2872,20 @@ nv50_msto_enable(struct drm_encoder *encoder)
|
|||
struct nv50_mstc *mstc = NULL;
|
||||
struct nv50_mstm *mstm = NULL;
|
||||
struct drm_connector *connector;
|
||||
struct drm_connector_list_iter conn_iter;
|
||||
u8 proto, depth;
|
||||
int slots;
|
||||
bool r;
|
||||
|
||||
drm_for_each_connector(connector, encoder->dev) {
|
||||
drm_connector_list_iter_begin(encoder->dev, &conn_iter);
|
||||
drm_for_each_connector_iter(connector, &conn_iter) {
|
||||
if (connector->state->best_encoder == &msto->encoder) {
|
||||
mstc = nv50_mstc(connector);
|
||||
mstm = mstc->mstm;
|
||||
break;
|
||||
}
|
||||
}
|
||||
drm_connector_list_iter_end(&conn_iter);
|
||||
|
||||
if (WARN_ON(!mstc))
|
||||
return;
|
||||
|
|
|
@ -6,6 +6,7 @@ config DRM_PL111
|
|||
select DRM_KMS_HELPER
|
||||
select DRM_KMS_CMA_HELPER
|
||||
select DRM_GEM_CMA_HELPER
|
||||
select DRM_PANEL
|
||||
select VT_HW_CONSOLE_BINDING if FRAMEBUFFER_CONSOLE
|
||||
help
|
||||
Choose this option for DRM support for the PL111 CLCD controller.
|
||||
|
|
|
@ -179,7 +179,6 @@ static struct drm_driver pl111_drm_driver = {
|
|||
#endif
|
||||
};
|
||||
|
||||
#ifdef CONFIG_ARM_AMBA
|
||||
static int pl111_amba_probe(struct amba_device *amba_dev,
|
||||
const struct amba_id *id)
|
||||
{
|
||||
|
@ -252,7 +251,7 @@ static struct amba_id pl111_id_table[] = {
|
|||
{0, 0},
|
||||
};
|
||||
|
||||
static struct amba_driver pl111_amba_driver = {
|
||||
static struct amba_driver pl111_amba_driver __maybe_unused = {
|
||||
.drv = {
|
||||
.name = "drm-clcd-pl111",
|
||||
},
|
||||
|
@ -261,8 +260,9 @@ static struct amba_driver pl111_amba_driver = {
|
|||
.id_table = pl111_id_table,
|
||||
};
|
||||
|
||||
#ifdef CONFIG_ARM_AMBA
|
||||
module_amba_driver(pl111_amba_driver);
|
||||
#endif /* CONFIG_ARM_AMBA */
|
||||
#endif
|
||||
|
||||
MODULE_DESCRIPTION(DRIVER_DESC);
|
||||
MODULE_AUTHOR("ARM Ltd.");
|
||||
|
|
|
@ -1118,16 +1118,17 @@ static void vop_crtc_destroy_state(struct drm_crtc *crtc,
|
|||
#ifdef CONFIG_DRM_ANALOGIX_DP
|
||||
static struct drm_connector *vop_get_edp_connector(struct vop *vop)
|
||||
{
|
||||
struct drm_crtc *crtc = &vop->crtc;
|
||||
struct drm_connector *connector;
|
||||
struct drm_connector_list_iter conn_iter;
|
||||
|
||||
mutex_lock(&crtc->dev->mode_config.mutex);
|
||||
drm_for_each_connector(connector, crtc->dev)
|
||||
drm_connector_list_iter_begin(vop->drm_dev, &conn_iter);
|
||||
drm_for_each_connector_iter(connector, &conn_iter) {
|
||||
if (connector->connector_type == DRM_MODE_CONNECTOR_eDP) {
|
||||
mutex_unlock(&crtc->dev->mode_config.mutex);
|
||||
drm_connector_list_iter_end(&conn_iter);
|
||||
return connector;
|
||||
}
|
||||
mutex_unlock(&crtc->dev->mode_config.mutex);
|
||||
}
|
||||
drm_connector_list_iter_end(&conn_iter);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
|
|
@ -1144,8 +1144,6 @@ void ltdc_unload(struct drm_device *ddev)
|
|||
|
||||
DRM_DEBUG_DRIVER("\n");
|
||||
|
||||
drm_vblank_cleanup(ddev);
|
||||
|
||||
if (ldev->panel)
|
||||
drm_panel_detach(ldev->panel);
|
||||
|
||||
|
|
|
@ -138,7 +138,6 @@ static int sun4i_drv_bind(struct device *dev)
|
|||
sun4i_framebuffer_free(drm);
|
||||
cleanup_mode_config:
|
||||
drm_mode_config_cleanup(drm);
|
||||
drm_vblank_cleanup(drm);
|
||||
free_mem_region:
|
||||
of_reserved_mem_device_release(dev);
|
||||
free_drm:
|
||||
|
@ -154,7 +153,6 @@ static void sun4i_drv_unbind(struct device *dev)
|
|||
drm_kms_helper_poll_fini(drm);
|
||||
sun4i_framebuffer_free(drm);
|
||||
drm_mode_config_cleanup(drm);
|
||||
drm_vblank_cleanup(drm);
|
||||
of_reserved_mem_device_release(dev);
|
||||
drm_dev_unref(drm);
|
||||
}
|
||||
|
|
|
@ -914,7 +914,7 @@ static int mipi_dbi_debugfs_command_show(struct seq_file *m, void *unused)
|
|||
{
|
||||
struct mipi_dbi *mipi = m->private;
|
||||
u8 cmd, val[4];
|
||||
size_t len, i;
|
||||
size_t len;
|
||||
int ret;
|
||||
|
||||
for (cmd = 0; cmd < 255; cmd++) {
|
||||
|
@ -943,10 +943,7 @@ static int mipi_dbi_debugfs_command_show(struct seq_file *m, void *unused)
|
|||
seq_puts(m, "XX\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
for (i = 0; i < len; i++)
|
||||
seq_printf(m, "%02x", val[i]);
|
||||
seq_puts(m, "\n");
|
||||
seq_printf(m, "%*phN\n", (int)len, val);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -345,12 +345,16 @@ static u32 vc4_get_fifo_full_level(u32 format)
|
|||
static struct drm_encoder *vc4_get_crtc_encoder(struct drm_crtc *crtc)
|
||||
{
|
||||
struct drm_connector *connector;
|
||||
struct drm_connector_list_iter conn_iter;
|
||||
|
||||
drm_for_each_connector(connector, crtc->dev) {
|
||||
drm_connector_list_iter_begin(crtc->dev, &conn_iter);
|
||||
drm_for_each_connector_iter(connector, &conn_iter) {
|
||||
if (connector->state->crtc == crtc) {
|
||||
drm_connector_list_iter_end(&conn_iter);
|
||||
return connector->encoder;
|
||||
}
|
||||
}
|
||||
drm_connector_list_iter_end(&conn_iter);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
|
|
@ -532,7 +532,7 @@ int vc4_queue_seqno_cb(struct drm_device *dev,
|
|||
extern struct platform_driver vc4_hdmi_driver;
|
||||
int vc4_hdmi_debugfs_regs(struct seq_file *m, void *unused);
|
||||
|
||||
/* vc4_hdmi.c */
|
||||
/* vc4_vec.c */
|
||||
extern struct platform_driver vc4_vec_driver;
|
||||
int vc4_vec_debugfs_regs(struct seq_file *m, void *unused);
|
||||
|
||||
|
|
|
@ -401,6 +401,7 @@ static int vc4_v3d_bind(struct device *dev, struct device *master, void *data)
|
|||
return ret;
|
||||
}
|
||||
|
||||
pm_runtime_set_active(dev);
|
||||
pm_runtime_use_autosuspend(dev);
|
||||
pm_runtime_set_autosuspend_delay(dev, 40); /* a little over 2 frames. */
|
||||
pm_runtime_enable(dev);
|
||||
|
|
|
@ -56,7 +56,6 @@ int drm_virtio_init(struct drm_driver *driver, struct virtio_device *vdev)
|
|||
dev = drm_dev_alloc(driver, &vdev->dev);
|
||||
if (IS_ERR(dev))
|
||||
return PTR_ERR(dev);
|
||||
dev->virtdev = vdev;
|
||||
vdev->priv = dev;
|
||||
|
||||
if (strcmp(vdev->dev.parent->bus->name, "pci") == 0) {
|
||||
|
|
|
@ -138,7 +138,7 @@ int virtio_gpu_driver_load(struct drm_device *dev, unsigned long flags)
|
|||
u32 num_scanouts, num_capsets;
|
||||
int ret;
|
||||
|
||||
if (!virtio_has_feature(dev->virtdev, VIRTIO_F_VERSION_1))
|
||||
if (!virtio_has_feature(dev_to_virtio(dev->dev), VIRTIO_F_VERSION_1))
|
||||
return -ENODEV;
|
||||
|
||||
vgdev = kzalloc(sizeof(struct virtio_gpu_device), GFP_KERNEL);
|
||||
|
@ -147,7 +147,7 @@ int virtio_gpu_driver_load(struct drm_device *dev, unsigned long flags)
|
|||
|
||||
vgdev->ddev = dev;
|
||||
dev->dev_private = vgdev;
|
||||
vgdev->vdev = dev->virtdev;
|
||||
vgdev->vdev = dev_to_virtio(dev->dev);
|
||||
vgdev->dev = dev->dev;
|
||||
|
||||
spin_lock_init(&vgdev->display_info_lock);
|
||||
|
|
|
@ -80,6 +80,9 @@
|
|||
#include <drm/drm_debugfs.h>
|
||||
#include <drm/drm_ioctl.h>
|
||||
#include <drm/drm_sysfs.h>
|
||||
#include <drm/drm_vblank.h>
|
||||
#include <drm/drm_irq.h>
|
||||
|
||||
|
||||
struct module;
|
||||
|
||||
|
@ -292,23 +295,6 @@ struct pci_controller;
|
|||
/* Format strings and argument splitters to simplify printing
|
||||
* various "complex" objects
|
||||
*/
|
||||
#define DRM_MODE_FMT "%d:\"%s\" %d %d %d %d %d %d %d %d %d %d 0x%x 0x%x"
|
||||
#define DRM_MODE_ARG(m) \
|
||||
(m)->base.id, (m)->name, (m)->vrefresh, (m)->clock, \
|
||||
(m)->hdisplay, (m)->hsync_start, (m)->hsync_end, (m)->htotal, \
|
||||
(m)->vdisplay, (m)->vsync_start, (m)->vsync_end, (m)->vtotal, \
|
||||
(m)->type, (m)->flags
|
||||
|
||||
#define DRM_RECT_FMT "%dx%d%+d%+d"
|
||||
#define DRM_RECT_ARG(r) drm_rect_width(r), drm_rect_height(r), (r)->x1, (r)->y1
|
||||
|
||||
/* for rect's in fixed-point format: */
|
||||
#define DRM_RECT_FP_FMT "%d.%06ux%d.%06u%+d.%06u%+d.%06u"
|
||||
#define DRM_RECT_FP_ARG(r) \
|
||||
drm_rect_width(r) >> 16, ((drm_rect_width(r) & 0xffff) * 15625) >> 10, \
|
||||
drm_rect_height(r) >> 16, ((drm_rect_height(r) & 0xffff) * 15625) >> 10, \
|
||||
(r)->x1 >> 16, (((r)->x1 & 0xffff) * 15625) >> 10, \
|
||||
(r)->y1 >> 16, (((r)->y1 & 0xffff) * 15625) >> 10
|
||||
|
||||
/*@}*/
|
||||
|
||||
|
@ -391,8 +377,13 @@ struct drm_device {
|
|||
int last_context; /**< Last current context */
|
||||
/*@} */
|
||||
|
||||
/** \name VBLANK IRQ support */
|
||||
/*@{ */
|
||||
/**
|
||||
* @irq_enabled:
|
||||
*
|
||||
* Indicates that interrupt handling is enabled, specifically vblank
|
||||
* handling. Drivers which don't use drm_irq_install() need to set this
|
||||
* to true manually.
|
||||
*/
|
||||
bool irq_enabled;
|
||||
int irq;
|
||||
|
||||
|
@ -429,8 +420,6 @@ struct drm_device {
|
|||
struct pci_controller *hose;
|
||||
#endif
|
||||
|
||||
struct virtio_device *virtdev;
|
||||
|
||||
struct drm_sg_mem *sg; /**< Scatter gather memory */
|
||||
unsigned int num_crtcs; /**< Number of CRTCs on this device */
|
||||
|
||||
|
@ -466,8 +455,6 @@ static inline bool drm_drv_uses_atomic_modeset(struct drm_device *dev)
|
|||
return dev->mode_config.funcs->atomic_commit != NULL;
|
||||
}
|
||||
|
||||
#include <drm/drm_irq.h>
|
||||
|
||||
#define DRM_SWITCH_POWER_ON 0
|
||||
#define DRM_SWITCH_POWER_OFF 1
|
||||
#define DRM_SWITCH_POWER_CHANGING 2
|
||||
|
|
|
@ -520,7 +520,7 @@ __drm_atomic_get_current_plane_state(struct drm_atomic_state *state,
|
|||
|
||||
int __must_check
|
||||
drm_atomic_set_mode_for_crtc(struct drm_crtc_state *state,
|
||||
struct drm_display_mode *mode);
|
||||
const struct drm_display_mode *mode);
|
||||
int __must_check
|
||||
drm_atomic_set_mode_prop_for_crtc(struct drm_crtc_state *state,
|
||||
struct drm_property_blob *blob);
|
||||
|
|
|
@ -253,6 +253,8 @@ int drm_bridge_attach(struct drm_encoder *encoder, struct drm_bridge *bridge,
|
|||
bool drm_bridge_mode_fixup(struct drm_bridge *bridge,
|
||||
const struct drm_display_mode *mode,
|
||||
struct drm_display_mode *adjusted_mode);
|
||||
enum drm_mode_status drm_bridge_mode_valid(struct drm_bridge *bridge,
|
||||
const struct drm_display_mode *mode);
|
||||
void drm_bridge_disable(struct drm_bridge *bridge);
|
||||
void drm_bridge_post_disable(struct drm_bridge *bridge);
|
||||
void drm_bridge_mode_set(struct drm_bridge *bridge,
|
||||
|
|
|
@ -1009,21 +1009,6 @@ struct drm_tile_group *drm_mode_get_tile_group(struct drm_device *dev,
|
|||
void drm_mode_put_tile_group(struct drm_device *dev,
|
||||
struct drm_tile_group *tg);
|
||||
|
||||
/**
|
||||
* drm_for_each_connector - iterate over all connectors
|
||||
* @connector: the loop cursor
|
||||
* @dev: the DRM device
|
||||
*
|
||||
* Iterate over all connectors of @dev.
|
||||
*
|
||||
* WARNING:
|
||||
*
|
||||
* This iterator is not safe against hotadd/removal of connectors and is
|
||||
* deprecated. Use drm_for_each_connector_iter() instead.
|
||||
*/
|
||||
#define drm_for_each_connector(connector, dev) \
|
||||
list_for_each_entry(connector, &(dev)->mode_config.connector_list, head)
|
||||
|
||||
/**
|
||||
* struct drm_connector_list_iter - connector_list iterator
|
||||
*
|
||||
|
|
|
@ -214,7 +214,9 @@ struct drm_crtc_state {
|
|||
* atomic commit. In that case the event can be send out any time
|
||||
* after the hardware has stopped scanning out the current
|
||||
* framebuffers. It should contain the timestamp and counter for the
|
||||
* last vblank before the display pipeline was shut off.
|
||||
* last vblank before the display pipeline was shut off. The simplest
|
||||
* way to achieve that is calling drm_crtc_send_vblank_event()
|
||||
* somewhen after drm_crtc_vblank_off() has been called.
|
||||
*
|
||||
* - For a CRTC which is enabled at the end of the commit (even when it
|
||||
* undergoes an full modeset) the vblank timestamp and counter must
|
||||
|
|
|
@ -327,11 +327,40 @@ struct drm_driver {
|
|||
struct timeval *vblank_time,
|
||||
bool in_vblank_irq);
|
||||
|
||||
/* these have to be filled in */
|
||||
|
||||
/**
|
||||
* @irq_handler:
|
||||
*
|
||||
* Interrupt handler called when using drm_irq_install(). Not used by
|
||||
* drivers which implement their own interrupt handling.
|
||||
*/
|
||||
irqreturn_t(*irq_handler) (int irq, void *arg);
|
||||
|
||||
/**
|
||||
* @irq_preinstall:
|
||||
*
|
||||
* Optional callback used by drm_irq_install() which is called before
|
||||
* the interrupt handler is registered. This should be used to clear out
|
||||
* any pending interrupts (from e.g. firmware based drives) and reset
|
||||
* the interrupt handling registers.
|
||||
*/
|
||||
void (*irq_preinstall) (struct drm_device *dev);
|
||||
|
||||
/**
|
||||
* @irq_postinstall:
|
||||
*
|
||||
* Optional callback used by drm_irq_install() which is called after
|
||||
* the interrupt handler is registered. This should be used to enable
|
||||
* interrupt generation in the hardware.
|
||||
*/
|
||||
int (*irq_postinstall) (struct drm_device *dev);
|
||||
|
||||
/**
|
||||
* @irq_uninstall:
|
||||
*
|
||||
* Optional callback used by drm_irq_uninstall() which is called before
|
||||
* the interrupt handler is unregistered. This should be used to disable
|
||||
* interrupt generation in the hardware.
|
||||
*/
|
||||
void (*irq_uninstall) (struct drm_device *dev);
|
||||
|
||||
/**
|
||||
|
|
|
@ -40,6 +40,7 @@
|
|||
struct dma_fence;
|
||||
struct drm_file;
|
||||
struct drm_device;
|
||||
struct device;
|
||||
|
||||
/*
|
||||
* FIXME: Not sure we want to have drm_minor here in the end, but to avoid
|
||||
|
|
|
@ -24,165 +24,9 @@
|
|||
#ifndef _DRM_IRQ_H_
|
||||
#define _DRM_IRQ_H_
|
||||
|
||||
#include <linux/seqlock.h>
|
||||
|
||||
/**
|
||||
* struct drm_pending_vblank_event - pending vblank event tracking
|
||||
*/
|
||||
struct drm_pending_vblank_event {
|
||||
/**
|
||||
* @base: Base structure for tracking pending DRM events.
|
||||
*/
|
||||
struct drm_pending_event base;
|
||||
/**
|
||||
* @pipe: drm_crtc_index() of the &drm_crtc this event is for.
|
||||
*/
|
||||
unsigned int pipe;
|
||||
/**
|
||||
* @event: Actual event which will be sent to userspace.
|
||||
*/
|
||||
struct drm_event_vblank event;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct drm_vblank_crtc - vblank tracking for a CRTC
|
||||
*
|
||||
* This structure tracks the vblank state for one CRTC.
|
||||
*
|
||||
* Note that for historical reasons - the vblank handling code is still shared
|
||||
* with legacy/non-kms drivers - this is a free-standing structure not directly
|
||||
* connected to &struct drm_crtc. But all public interface functions are taking
|
||||
* a &struct drm_crtc to hide this implementation detail.
|
||||
*/
|
||||
struct drm_vblank_crtc {
|
||||
/**
|
||||
* @dev: Pointer to the &drm_device.
|
||||
*/
|
||||
struct drm_device *dev;
|
||||
/**
|
||||
* @queue: Wait queue for vblank waiters.
|
||||
*/
|
||||
wait_queue_head_t queue; /**< VBLANK wait queue */
|
||||
/**
|
||||
* @disable_timer: Disable timer for the delayed vblank disabling
|
||||
* hysteresis logic. Vblank disabling is controlled through the
|
||||
* drm_vblank_offdelay module option and the setting of the
|
||||
* &drm_device.max_vblank_count value.
|
||||
*/
|
||||
struct timer_list disable_timer;
|
||||
|
||||
/**
|
||||
* @seqlock: Protect vblank count and time.
|
||||
*/
|
||||
seqlock_t seqlock; /* protects vblank count and time */
|
||||
|
||||
/**
|
||||
* @count: Current software vblank counter.
|
||||
*/
|
||||
u32 count;
|
||||
/**
|
||||
* @time: Vblank timestamp corresponding to @count.
|
||||
*/
|
||||
struct timeval time;
|
||||
|
||||
/**
|
||||
* @refcount: Number of users/waiters of the vblank interrupt. Only when
|
||||
* this refcount reaches 0 can the hardware interrupt be disabled using
|
||||
* @disable_timer.
|
||||
*/
|
||||
atomic_t refcount; /* number of users of vblank interruptsper crtc */
|
||||
/**
|
||||
* @last: Protected by &drm_device.vbl_lock, used for wraparound handling.
|
||||
*/
|
||||
u32 last;
|
||||
/**
|
||||
* @inmodeset: Tracks whether the vblank is disabled due to a modeset.
|
||||
* For legacy driver bit 2 additionally tracks whether an additional
|
||||
* temporary vblank reference has been acquired to paper over the
|
||||
* hardware counter resetting/jumping. KMS drivers should instead just
|
||||
* call drm_crtc_vblank_off() and drm_crtc_vblank_on(), which explicitly
|
||||
* save and restore the vblank count.
|
||||
*/
|
||||
unsigned int inmodeset; /* Display driver is setting mode */
|
||||
/**
|
||||
* @pipe: drm_crtc_index() of the &drm_crtc corresponding to this
|
||||
* structure.
|
||||
*/
|
||||
unsigned int pipe;
|
||||
/**
|
||||
* @framedur_ns: Frame/Field duration in ns, used by
|
||||
* drm_calc_vbltimestamp_from_scanoutpos() and computed by
|
||||
* drm_calc_timestamping_constants().
|
||||
*/
|
||||
int framedur_ns;
|
||||
/**
|
||||
* @linedur_ns: Line duration in ns, used by
|
||||
* drm_calc_vbltimestamp_from_scanoutpos() and computed by
|
||||
* drm_calc_timestamping_constants().
|
||||
*/
|
||||
int linedur_ns;
|
||||
|
||||
/**
|
||||
* @hwmode:
|
||||
*
|
||||
* Cache of the current hardware display mode. Only valid when @enabled
|
||||
* is set. This is used by helpers like
|
||||
* drm_calc_vbltimestamp_from_scanoutpos(). We can't just access the
|
||||
* hardware mode by e.g. looking at &drm_crtc_state.adjusted_mode,
|
||||
* because that one is really hard to get from interrupt context.
|
||||
*/
|
||||
struct drm_display_mode hwmode;
|
||||
|
||||
/**
|
||||
* @enabled: Tracks the enabling state of the corresponding &drm_crtc to
|
||||
* avoid double-disabling and hence corrupting saved state. Needed by
|
||||
* drivers not using atomic KMS, since those might go through their CRTC
|
||||
* disabling functions multiple times.
|
||||
*/
|
||||
bool enabled;
|
||||
};
|
||||
struct drm_device;
|
||||
|
||||
int drm_irq_install(struct drm_device *dev, int irq);
|
||||
int drm_irq_uninstall(struct drm_device *dev);
|
||||
|
||||
int drm_vblank_init(struct drm_device *dev, unsigned int num_crtcs);
|
||||
u32 drm_crtc_vblank_count(struct drm_crtc *crtc);
|
||||
u32 drm_crtc_vblank_count_and_time(struct drm_crtc *crtc,
|
||||
struct timeval *vblanktime);
|
||||
void drm_crtc_send_vblank_event(struct drm_crtc *crtc,
|
||||
struct drm_pending_vblank_event *e);
|
||||
void drm_crtc_arm_vblank_event(struct drm_crtc *crtc,
|
||||
struct drm_pending_vblank_event *e);
|
||||
bool drm_handle_vblank(struct drm_device *dev, unsigned int pipe);
|
||||
bool drm_crtc_handle_vblank(struct drm_crtc *crtc);
|
||||
int drm_crtc_vblank_get(struct drm_crtc *crtc);
|
||||
void drm_crtc_vblank_put(struct drm_crtc *crtc);
|
||||
void drm_wait_one_vblank(struct drm_device *dev, unsigned int pipe);
|
||||
void drm_crtc_wait_one_vblank(struct drm_crtc *crtc);
|
||||
void drm_crtc_vblank_off(struct drm_crtc *crtc);
|
||||
void drm_crtc_vblank_reset(struct drm_crtc *crtc);
|
||||
void drm_crtc_vblank_on(struct drm_crtc *crtc);
|
||||
void drm_vblank_cleanup(struct drm_device *dev);
|
||||
u32 drm_accurate_vblank_count(struct drm_crtc *crtc);
|
||||
|
||||
bool drm_calc_vbltimestamp_from_scanoutpos(struct drm_device *dev,
|
||||
unsigned int pipe, int *max_error,
|
||||
struct timeval *vblank_time,
|
||||
bool in_vblank_irq);
|
||||
void drm_calc_timestamping_constants(struct drm_crtc *crtc,
|
||||
const struct drm_display_mode *mode);
|
||||
|
||||
/**
|
||||
* drm_crtc_vblank_waitqueue - get vblank waitqueue for the CRTC
|
||||
* @crtc: which CRTC's vblank waitqueue to retrieve
|
||||
*
|
||||
* This function returns a pointer to the vblank waitqueue for the CRTC.
|
||||
* Drivers can use this to implement vblank waits using wait_event() and related
|
||||
* functions.
|
||||
*/
|
||||
static inline wait_queue_head_t *drm_crtc_vblank_waitqueue(struct drm_crtc *crtc)
|
||||
{
|
||||
return &crtc->dev->vblank[drm_crtc_index(crtc)].queue;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -197,6 +197,8 @@ enum drm_mode_status {
|
|||
* there's the hardware timings, which are corrected for interlacing,
|
||||
* double-clocking and similar things. They are provided as a convenience, and
|
||||
* can be appropriately computed using drm_mode_set_crtcinfo().
|
||||
*
|
||||
* For printing you can use %DRM_MODE_FMT and DRM_MODE_ARG().
|
||||
*/
|
||||
struct drm_display_mode {
|
||||
/**
|
||||
|
@ -407,6 +409,21 @@ struct drm_display_mode {
|
|||
enum hdmi_picture_aspect picture_aspect_ratio;
|
||||
};
|
||||
|
||||
/**
|
||||
* DRM_MODE_FMT - printf string for &struct drm_display_mode
|
||||
*/
|
||||
#define DRM_MODE_FMT "%d:\"%s\" %d %d %d %d %d %d %d %d %d %d 0x%x 0x%x"
|
||||
|
||||
/**
|
||||
* DRM_MODE_ARG - printf arguments for &struct drm_display_mode
|
||||
* @m: display mode
|
||||
*/
|
||||
#define DRM_MODE_ARG(m) \
|
||||
(m)->base.id, (m)->name, (m)->vrefresh, (m)->clock, \
|
||||
(m)->hdisplay, (m)->hsync_start, (m)->hsync_end, (m)->htotal, \
|
||||
(m)->vdisplay, (m)->vsync_start, (m)->vsync_end, (m)->vtotal, \
|
||||
(m)->type, (m)->flags
|
||||
|
||||
#define obj_to_mode(x) container_of(x, struct drm_display_mode, base)
|
||||
|
||||
/**
|
||||
|
|
|
@ -6,19 +6,7 @@
|
|||
#include <linux/interrupt.h> /* For task queue support */
|
||||
#include <linux/sched/signal.h>
|
||||
#include <linux/delay.h>
|
||||
|
||||
#ifndef readq
|
||||
static inline u64 readq(void __iomem *reg)
|
||||
{
|
||||
return ((u64) readl(reg)) | (((u64) readl(reg + 4UL)) << 32);
|
||||
}
|
||||
|
||||
static inline void writeq(u64 val, void __iomem *reg)
|
||||
{
|
||||
writel(val & 0xffffffff, reg);
|
||||
writel(val >> 32, reg + 0x4UL);
|
||||
}
|
||||
#endif
|
||||
#include <linux/io-64-nonatomic-lo-hi.h>
|
||||
|
||||
/** Current process ID */
|
||||
#define DRM_CURRENTPID task_pid_nr(current)
|
||||
|
|
|
@ -59,6 +59,8 @@ struct drm_device;
|
|||
struct drm_gem_object;
|
||||
struct drm_file;
|
||||
|
||||
struct device;
|
||||
|
||||
struct dma_buf *drm_gem_prime_export(struct drm_device *dev,
|
||||
struct drm_gem_object *obj,
|
||||
int flags);
|
||||
|
|
|
@ -42,6 +42,33 @@ struct drm_rect {
|
|||
int x1, y1, x2, y2;
|
||||
};
|
||||
|
||||
/**
|
||||
* DRM_RECT_FMT - printf string for &struct drm_rect
|
||||
*/
|
||||
#define DRM_RECT_FMT "%dx%d%+d%+d"
|
||||
/**
|
||||
* DRM_RECT_ARG - printf arguments for &struct drm_rect
|
||||
* @r: rectangle struct
|
||||
*/
|
||||
#define DRM_RECT_ARG(r) drm_rect_width(r), drm_rect_height(r), (r)->x1, (r)->y1
|
||||
|
||||
/**
|
||||
* DRM_RECT_FP_FMT - printf string for &struct drm_rect in 16.16 fixed point
|
||||
*/
|
||||
#define DRM_RECT_FP_FMT "%d.%06ux%d.%06u%+d.%06u%+d.%06u"
|
||||
/**
|
||||
* DRM_RECT_FP_ARG - printf arguments for &struct drm_rect in 16.16 fixed point
|
||||
* @r: rectangle struct
|
||||
*
|
||||
* This is useful for e.g. printing plane source rectangles, which are in 16.16
|
||||
* fixed point.
|
||||
*/
|
||||
#define DRM_RECT_FP_ARG(r) \
|
||||
drm_rect_width(r) >> 16, ((drm_rect_width(r) & 0xffff) * 15625) >> 10, \
|
||||
drm_rect_height(r) >> 16, ((drm_rect_height(r) & 0xffff) * 15625) >> 10, \
|
||||
(r)->x1 >> 16, (((r)->x1 & 0xffff) * 15625) >> 10, \
|
||||
(r)->y1 >> 16, (((r)->y1 & 0xffff) * 15625) >> 10
|
||||
|
||||
/**
|
||||
* drm_rect_adjust_size - adjust the size of the rectangle
|
||||
* @r: rectangle to be adjusted
|
||||
|
|
|
@ -0,0 +1,181 @@
|
|||
/*
|
||||
* Copyright 2016 Intel Corp.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the next
|
||||
* paragraph) shall be included in all copies or substantial portions of the
|
||||
* Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef _DRM_VBLANK_H_
|
||||
#define _DRM_VBLANK_H_
|
||||
|
||||
#include <linux/seqlock.h>
|
||||
#include <linux/idr.h>
|
||||
#include <linux/poll.h>
|
||||
|
||||
#include <drm/drm_file.h>
|
||||
#include <drm/drm_modes.h>
|
||||
#include <uapi/drm/drm.h>
|
||||
|
||||
struct drm_device;
|
||||
struct drm_crtc;
|
||||
|
||||
/**
|
||||
* struct drm_pending_vblank_event - pending vblank event tracking
|
||||
*/
|
||||
struct drm_pending_vblank_event {
|
||||
/**
|
||||
* @base: Base structure for tracking pending DRM events.
|
||||
*/
|
||||
struct drm_pending_event base;
|
||||
/**
|
||||
* @pipe: drm_crtc_index() of the &drm_crtc this event is for.
|
||||
*/
|
||||
unsigned int pipe;
|
||||
/**
|
||||
* @event: Actual event which will be sent to userspace.
|
||||
*/
|
||||
struct drm_event_vblank event;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct drm_vblank_crtc - vblank tracking for a CRTC
|
||||
*
|
||||
* This structure tracks the vblank state for one CRTC.
|
||||
*
|
||||
* Note that for historical reasons - the vblank handling code is still shared
|
||||
* with legacy/non-kms drivers - this is a free-standing structure not directly
|
||||
* connected to &struct drm_crtc. But all public interface functions are taking
|
||||
* a &struct drm_crtc to hide this implementation detail.
|
||||
*/
|
||||
struct drm_vblank_crtc {
|
||||
/**
|
||||
* @dev: Pointer to the &drm_device.
|
||||
*/
|
||||
struct drm_device *dev;
|
||||
/**
|
||||
* @queue: Wait queue for vblank waiters.
|
||||
*/
|
||||
wait_queue_head_t queue; /**< VBLANK wait queue */
|
||||
/**
|
||||
* @disable_timer: Disable timer for the delayed vblank disabling
|
||||
* hysteresis logic. Vblank disabling is controlled through the
|
||||
* drm_vblank_offdelay module option and the setting of the
|
||||
* &drm_device.max_vblank_count value.
|
||||
*/
|
||||
struct timer_list disable_timer;
|
||||
|
||||
/**
|
||||
* @seqlock: Protect vblank count and time.
|
||||
*/
|
||||
seqlock_t seqlock; /* protects vblank count and time */
|
||||
|
||||
/**
|
||||
* @count: Current software vblank counter.
|
||||
*/
|
||||
u32 count;
|
||||
/**
|
||||
* @time: Vblank timestamp corresponding to @count.
|
||||
*/
|
||||
struct timeval time;
|
||||
|
||||
/**
|
||||
* @refcount: Number of users/waiters of the vblank interrupt. Only when
|
||||
* this refcount reaches 0 can the hardware interrupt be disabled using
|
||||
* @disable_timer.
|
||||
*/
|
||||
atomic_t refcount; /* number of users of vblank interruptsper crtc */
|
||||
/**
|
||||
* @last: Protected by &drm_device.vbl_lock, used for wraparound handling.
|
||||
*/
|
||||
u32 last;
|
||||
/**
|
||||
* @inmodeset: Tracks whether the vblank is disabled due to a modeset.
|
||||
* For legacy driver bit 2 additionally tracks whether an additional
|
||||
* temporary vblank reference has been acquired to paper over the
|
||||
* hardware counter resetting/jumping. KMS drivers should instead just
|
||||
* call drm_crtc_vblank_off() and drm_crtc_vblank_on(), which explicitly
|
||||
* save and restore the vblank count.
|
||||
*/
|
||||
unsigned int inmodeset; /* Display driver is setting mode */
|
||||
/**
|
||||
* @pipe: drm_crtc_index() of the &drm_crtc corresponding to this
|
||||
* structure.
|
||||
*/
|
||||
unsigned int pipe;
|
||||
/**
|
||||
* @framedur_ns: Frame/Field duration in ns, used by
|
||||
* drm_calc_vbltimestamp_from_scanoutpos() and computed by
|
||||
* drm_calc_timestamping_constants().
|
||||
*/
|
||||
int framedur_ns;
|
||||
/**
|
||||
* @linedur_ns: Line duration in ns, used by
|
||||
* drm_calc_vbltimestamp_from_scanoutpos() and computed by
|
||||
* drm_calc_timestamping_constants().
|
||||
*/
|
||||
int linedur_ns;
|
||||
|
||||
/**
|
||||
* @hwmode:
|
||||
*
|
||||
* Cache of the current hardware display mode. Only valid when @enabled
|
||||
* is set. This is used by helpers like
|
||||
* drm_calc_vbltimestamp_from_scanoutpos(). We can't just access the
|
||||
* hardware mode by e.g. looking at &drm_crtc_state.adjusted_mode,
|
||||
* because that one is really hard to get from interrupt context.
|
||||
*/
|
||||
struct drm_display_mode hwmode;
|
||||
|
||||
/**
|
||||
* @enabled: Tracks the enabling state of the corresponding &drm_crtc to
|
||||
* avoid double-disabling and hence corrupting saved state. Needed by
|
||||
* drivers not using atomic KMS, since those might go through their CRTC
|
||||
* disabling functions multiple times.
|
||||
*/
|
||||
bool enabled;
|
||||
};
|
||||
|
||||
int drm_vblank_init(struct drm_device *dev, unsigned int num_crtcs);
|
||||
u32 drm_crtc_vblank_count(struct drm_crtc *crtc);
|
||||
u32 drm_crtc_vblank_count_and_time(struct drm_crtc *crtc,
|
||||
struct timeval *vblanktime);
|
||||
void drm_crtc_send_vblank_event(struct drm_crtc *crtc,
|
||||
struct drm_pending_vblank_event *e);
|
||||
void drm_crtc_arm_vblank_event(struct drm_crtc *crtc,
|
||||
struct drm_pending_vblank_event *e);
|
||||
bool drm_handle_vblank(struct drm_device *dev, unsigned int pipe);
|
||||
bool drm_crtc_handle_vblank(struct drm_crtc *crtc);
|
||||
int drm_crtc_vblank_get(struct drm_crtc *crtc);
|
||||
void drm_crtc_vblank_put(struct drm_crtc *crtc);
|
||||
void drm_wait_one_vblank(struct drm_device *dev, unsigned int pipe);
|
||||
void drm_crtc_wait_one_vblank(struct drm_crtc *crtc);
|
||||
void drm_crtc_vblank_off(struct drm_crtc *crtc);
|
||||
void drm_crtc_vblank_reset(struct drm_crtc *crtc);
|
||||
void drm_crtc_vblank_on(struct drm_crtc *crtc);
|
||||
void drm_vblank_cleanup(struct drm_device *dev);
|
||||
u32 drm_accurate_vblank_count(struct drm_crtc *crtc);
|
||||
|
||||
bool drm_calc_vbltimestamp_from_scanoutpos(struct drm_device *dev,
|
||||
unsigned int pipe, int *max_error,
|
||||
struct timeval *vblank_time,
|
||||
bool in_vblank_irq);
|
||||
void drm_calc_timestamping_constants(struct drm_crtc *crtc,
|
||||
const struct drm_display_mode *mode);
|
||||
wait_queue_head_t *drm_crtc_vblank_waitqueue(struct drm_crtc *crtc);
|
||||
#endif
|
Loading…
Reference in New Issue