Commit 55f5b0bf authored by Dave Airlie's avatar Dave Airlie

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
  ...
parents 562ff059 7f696942
......@@ -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
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
......
......@@ -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,
......
This diff is collapsed.
......@@ -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:
......
This diff is collapsed.
......@@ -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
......
/*
* 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
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment