diff options
Diffstat (limited to 'include/drm')
66 files changed, 1918 insertions, 1278 deletions
diff --git a/include/drm/amd_asic_type.h b/include/drm/amd_asic_type.h index bcc2bcf32886..b1230e33d506 100644 --- a/include/drm/amd_asic_type.h +++ b/include/drm/amd_asic_type.h @@ -27,30 +27,36 @@ */ enum amd_asic_type { CHIP_TAHITI = 0, - CHIP_PITCAIRN, - CHIP_VERDE, - CHIP_OLAND, - CHIP_HAINAN, - CHIP_BONAIRE, - CHIP_KAVERI, - CHIP_KABINI, - CHIP_HAWAII, - CHIP_MULLINS, - CHIP_TOPAZ, - CHIP_TONGA, - CHIP_FIJI, - CHIP_CARRIZO, - CHIP_STONEY, - CHIP_POLARIS10, - CHIP_POLARIS11, - CHIP_POLARIS12, - CHIP_VEGAM, - CHIP_VEGA10, - CHIP_VEGA12, - CHIP_VEGA20, - CHIP_RAVEN, - CHIP_NAVI10, + CHIP_PITCAIRN, /* 1 */ + CHIP_VERDE, /* 2 */ + CHIP_OLAND, /* 3 */ + CHIP_HAINAN, /* 4 */ + CHIP_BONAIRE, /* 5 */ + CHIP_KAVERI, /* 6 */ + CHIP_KABINI, /* 7 */ + CHIP_HAWAII, /* 8 */ + CHIP_MULLINS, /* 9 */ + CHIP_TOPAZ, /* 10 */ + CHIP_TONGA, /* 11 */ + CHIP_FIJI, /* 12 */ + CHIP_CARRIZO, /* 13 */ + CHIP_STONEY, /* 14 */ + CHIP_POLARIS10, /* 15 */ + CHIP_POLARIS11, /* 16 */ + CHIP_POLARIS12, /* 17 */ + CHIP_VEGAM, /* 18 */ + CHIP_VEGA10, /* 19 */ + CHIP_VEGA12, /* 20 */ + CHIP_VEGA20, /* 21 */ + CHIP_RAVEN, /* 22 */ + CHIP_ARCTURUS, /* 23 */ + CHIP_RENOIR, /* 24 */ + CHIP_NAVI10, /* 25 */ + CHIP_NAVI14, /* 26 */ + CHIP_NAVI12, /* 27 */ CHIP_LAST, }; +extern const char *amdgpu_asic_name[]; + #endif /*__AMD_ASIC_TYPE_H__ */ diff --git a/include/drm/ati_pcigart.h b/include/drm/ati_pcigart.h deleted file mode 100644 index a728a1364e66..000000000000 --- a/include/drm/ati_pcigart.h +++ /dev/null @@ -1,31 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#ifndef DRM_ATI_PCIGART_H -#define DRM_ATI_PCIGART_H - -#include <drm/drm_legacy.h> - -/* location of GART table */ -#define DRM_ATI_GART_MAIN 1 -#define DRM_ATI_GART_FB 2 - -#define DRM_ATI_GART_PCI 1 -#define DRM_ATI_GART_PCIE 2 -#define DRM_ATI_GART_IGP 3 - -struct drm_ati_pcigart_info { - int gart_table_location; - int gart_reg_if; - void *addr; - dma_addr_t bus_addr; - dma_addr_t table_mask; - struct drm_dma_handle *table_handle; - struct drm_local_map mapping; - int table_size; -}; - -extern int drm_ati_pcigart_init(struct drm_device *dev, - struct drm_ati_pcigart_info * gart_info); -extern int drm_ati_pcigart_cleanup(struct drm_device *dev, - struct drm_ati_pcigart_info * gart_info); - -#endif diff --git a/include/drm/bridge/analogix_dp.h b/include/drm/bridge/analogix_dp.h index e56046cf4d04..7aa2f93da49c 100644 --- a/include/drm/bridge/analogix_dp.h +++ b/include/drm/bridge/analogix_dp.h @@ -38,10 +38,6 @@ struct analogix_dp_plat_data { struct drm_connector *); }; -int analogix_dp_psr_enabled(struct analogix_dp_device *dp); -int analogix_dp_enable_psr(struct analogix_dp_device *dp); -int analogix_dp_disable_psr(struct analogix_dp_device *dp); - int analogix_dp_resume(struct analogix_dp_device *dp); int analogix_dp_suspend(struct analogix_dp_device *dp); diff --git a/include/drm/bridge/dw_hdmi.h b/include/drm/bridge/dw_hdmi.h index c402364aec0d..9d4d5cc47969 100644 --- a/include/drm/bridge/dw_hdmi.h +++ b/include/drm/bridge/dw_hdmi.h @@ -6,6 +6,8 @@ #ifndef __DW_HDMI__ #define __DW_HDMI__ +#include <sound/hdmi-codec.h> + struct drm_connector; struct drm_display_mode; struct drm_encoder; @@ -126,6 +128,7 @@ struct dw_hdmi_plat_data { const struct drm_display_mode *mode); unsigned long input_bus_format; unsigned long input_bus_encoding; + bool use_drm_infoframe; /* Vendor PHY support */ const struct dw_hdmi_phy_ops *phy_ops; @@ -154,7 +157,12 @@ void dw_hdmi_resume(struct dw_hdmi *hdmi); void dw_hdmi_setup_rx_sense(struct dw_hdmi *hdmi, bool hpd, bool rx_sense); +int dw_hdmi_set_plugged_cb(struct dw_hdmi *hdmi, hdmi_codec_plugged_cb fn, + struct device *codec_dev); void dw_hdmi_set_sample_rate(struct dw_hdmi *hdmi, unsigned int rate); +void dw_hdmi_set_channel_count(struct dw_hdmi *hdmi, unsigned int cnt); +void dw_hdmi_set_channel_status(struct dw_hdmi *hdmi, u8 *channel_status); +void dw_hdmi_set_channel_allocation(struct dw_hdmi *hdmi, unsigned int ca); void dw_hdmi_audio_enable(struct dw_hdmi *hdmi); void dw_hdmi_audio_disable(struct dw_hdmi *hdmi); void dw_hdmi_set_high_tmds_clock_ratio(struct dw_hdmi *hdmi); diff --git a/include/drm/bridge/dw_mipi_dsi.h b/include/drm/bridge/dw_mipi_dsi.h index 94cc64a342e1..b0e390b3288e 100644 --- a/include/drm/bridge/dw_mipi_dsi.h +++ b/include/drm/bridge/dw_mipi_dsi.h @@ -19,6 +19,13 @@ struct dw_mipi_dsi; struct mipi_dsi_device; struct platform_device; +struct dw_mipi_dsi_dphy_timing { + u16 data_hs2lp; + u16 data_lp2hs; + u16 clk_hs2lp; + u16 clk_lp2hs; +}; + struct dw_mipi_dsi_phy_ops { int (*init)(void *priv_data); void (*power_on)(void *priv_data); @@ -27,6 +34,8 @@ struct dw_mipi_dsi_phy_ops { const struct drm_display_mode *mode, unsigned long mode_flags, u32 lanes, u32 format, unsigned int *lane_mbps); + int (*get_timing)(void *priv_data, unsigned int lane_mbps, + struct dw_mipi_dsi_dphy_timing *timing); }; struct dw_mipi_dsi_host_ops { diff --git a/include/drm/drmP.h b/include/drm/drmP.h deleted file mode 100644 index 94aae87b1138..000000000000 --- a/include/drm/drmP.h +++ /dev/null @@ -1,103 +0,0 @@ -/* - * Internal Header for the Direct Rendering Manager - * - * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. - * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. - * Copyright (c) 2009-2010, Code Aurora Forum. - * All rights reserved. - * - * Author: Rickard E. (Rik) Faith <faith@valinux.com> - * Author: Gareth Hughes <gareth@valinux.com> - * - * 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_P_H_ -#define _DRM_P_H_ - -#include <linux/agp_backend.h> -#include <linux/cdev.h> -#include <linux/dma-mapping.h> -#include <linux/file.h> -#include <linux/fs.h> -#include <linux/highmem.h> -#include <linux/idr.h> -#include <linux/init.h> -#include <linux/io.h> -#include <linux/jiffies.h> -#include <linux/kernel.h> -#include <linux/kref.h> -#include <linux/miscdevice.h> -#include <linux/mm.h> -#include <linux/mutex.h> -#include <linux/platform_device.h> -#include <linux/poll.h> -#include <linux/ratelimit.h> -#include <linux/sched.h> -#include <linux/slab.h> -#include <linux/types.h> -#include <linux/vmalloc.h> -#include <linux/workqueue.h> -#include <linux/dma-fence.h> -#include <linux/module.h> -#include <linux/mman.h> -#include <asm/pgalloc.h> -#include <linux/uaccess.h> - -#include <uapi/drm/drm.h> -#include <uapi/drm/drm_mode.h> - -#include <drm/drm_agpsupport.h> -#include <drm/drm_crtc.h> -#include <drm/drm_fourcc.h> -#include <drm/drm_hashtab.h> -#include <drm/drm_mm.h> -#include <drm/drm_os_linux.h> -#include <drm/drm_sarea.h> -#include <drm/drm_drv.h> -#include <drm/drm_prime.h> -#include <drm/drm_print.h> -#include <drm/drm_pci.h> -#include <drm/drm_file.h> -#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> -#include <drm/drm_device.h> - -struct module; - -struct device_node; -struct videomode; -struct reservation_object; -struct dma_buf_attachment; - -struct pci_dev; -struct pci_controller; - -/* - * NOTE: drmP.h is obsolete - do NOT add anything to this file - * - * Do not include drmP.h in new files. - * Work is ongoing to remove drmP.h includes from existing files - */ - -#endif diff --git a/include/drm/drm_agpsupport.h b/include/drm/drm_agpsupport.h index b05e462276d5..664e120b93e6 100644 --- a/include/drm/drm_agpsupport.h +++ b/include/drm/drm_agpsupport.h @@ -31,11 +31,6 @@ struct drm_agp_head { void drm_free_agp(struct agp_memory * handle, int pages); int drm_bind_agp(struct agp_memory * handle, unsigned int start); int drm_unbind_agp(struct agp_memory * handle); -struct agp_memory *drm_agp_bind_pages(struct drm_device *dev, - struct page **pages, - unsigned long num_pages, - uint32_t gtt_offset, - uint32_t type); struct drm_agp_head *drm_agp_init(struct drm_device *dev); void drm_legacy_agp_clear(struct drm_device *dev); @@ -80,15 +75,6 @@ static inline int drm_unbind_agp(struct agp_memory * handle) return -ENODEV; } -static inline struct agp_memory *drm_agp_bind_pages(struct drm_device *dev, - struct page **pages, - unsigned long num_pages, - uint32_t gtt_offset, - uint32_t type) -{ - return NULL; -} - static inline struct drm_agp_head *drm_agp_init(struct drm_device *dev) { return NULL; diff --git a/include/drm/drm_atomic.h b/include/drm/drm_atomic.h index 927e1205d7aa..951dfb15c27b 100644 --- a/include/drm/drm_atomic.h +++ b/include/drm/drm_atomic.h @@ -35,7 +35,7 @@ * struct drm_crtc_commit - track modeset commits on a CRTC * * This structure is used to track pending modeset changes and atomic commit on - * a per-CRTC basis. Since updating the list should never block this structure + * a per-CRTC basis. Since updating the list should never block, this structure * is reference counted to allow waiters to safely wait on an event to complete, * without holding any locks. * @@ -60,8 +60,8 @@ * wait for flip_done <---- * clean up atomic state * - * The important bit to know is that cleanup_done is the terminal event, but the - * ordering between flip_done and hw_done is entirely up to the specific driver + * The important bit to know is that &cleanup_done is the terminal event, but the + * ordering between &flip_done and &hw_done is entirely up to the specific driver * and modeset state change. * * For an implementation of how to use this look at @@ -92,6 +92,9 @@ struct drm_crtc_commit { * commit is sent to userspace, or when an out-fence is singalled. Note * that for most hardware, in most cases this happens after @hw_done is * signalled. + * + * Completion of this stage is signalled implicitly by calling + * drm_crtc_send_vblank_event() on &drm_crtc_state.event. */ struct completion flip_done; @@ -107,6 +110,9 @@ struct drm_crtc_commit { * Note that this does not need to include separately reference-counted * resources like backing storage buffer pinning, or runtime pm * management. + * + * Drivers should call drm_atomic_helper_commit_hw_done() to signal + * completion of this stage. */ struct completion hw_done; @@ -118,6 +124,9 @@ struct drm_crtc_commit { * a vblank wait completed it might be a bit later. This completion is * useful to throttle updates and avoid hardware updates getting ahead * of the buffer cleanup too much. + * + * Drivers should call drm_atomic_helper_commit_cleanup_done() to signal + * completion of this stage. */ struct completion cleanup_done; @@ -354,7 +363,7 @@ struct drm_atomic_state { * When a connector or plane is not bound to any CRTC, it's still important * to preserve linearity to prevent the atomic states from being freed to early. * - * This commit (if set) is not bound to any crtc, but will be completed when + * This commit (if set) is not bound to any CRTC, but will be completed when * drm_atomic_helper_commit_hw_done() is called. */ struct drm_crtc_commit *fake_commit; @@ -467,12 +476,12 @@ drm_atomic_get_new_connector_for_encoder(struct drm_atomic_state *state, struct drm_encoder *encoder); /** - * drm_atomic_get_existing_crtc_state - get crtc state, if it exists + * drm_atomic_get_existing_crtc_state - get CRTC state, if it exists * @state: global atomic state object - * @crtc: crtc to grab + * @crtc: CRTC to grab * - * This function returns the crtc state for the given crtc, or NULL - * if the crtc is not part of the global atomic state. + * This function returns the CRTC state for the given CRTC, or NULL + * if the CRTC is not part of the global atomic state. * * This function is deprecated, @drm_atomic_get_old_crtc_state or * @drm_atomic_get_new_crtc_state should be used instead. @@ -485,12 +494,12 @@ drm_atomic_get_existing_crtc_state(struct drm_atomic_state *state, } /** - * drm_atomic_get_old_crtc_state - get old crtc state, if it exists + * drm_atomic_get_old_crtc_state - get old CRTC state, if it exists * @state: global atomic state object - * @crtc: crtc to grab + * @crtc: CRTC to grab * - * This function returns the old crtc state for the given crtc, or - * NULL if the crtc is not part of the global atomic state. + * This function returns the old CRTC state for the given CRTC, or + * NULL if the CRTC is not part of the global atomic state. */ static inline struct drm_crtc_state * drm_atomic_get_old_crtc_state(struct drm_atomic_state *state, @@ -499,12 +508,12 @@ drm_atomic_get_old_crtc_state(struct drm_atomic_state *state, return state->crtcs[drm_crtc_index(crtc)].old_state; } /** - * drm_atomic_get_new_crtc_state - get new crtc state, if it exists + * drm_atomic_get_new_crtc_state - get new CRTC state, if it exists * @state: global atomic state object - * @crtc: crtc to grab + * @crtc: CRTC to grab * - * This function returns the new crtc state for the given crtc, or - * NULL if the crtc is not part of the global atomic state. + * This function returns the new CRTC state for the given CRTC, or + * NULL if the CRTC is not part of the global atomic state. */ static inline struct drm_crtc_state * drm_atomic_get_new_crtc_state(struct drm_atomic_state *state, @@ -693,6 +702,7 @@ void drm_state_dump(struct drm_device *dev, struct drm_printer *p); (__i)++) \ for_each_if ((__state)->connectors[__i].ptr && \ ((connector) = (__state)->connectors[__i].ptr, \ + (void)(connector) /* Only to avoid unused-but-set-variable warning */, \ (old_connector_state) = (__state)->connectors[__i].old_state, \ (new_connector_state) = (__state)->connectors[__i].new_state, 1)) @@ -714,6 +724,7 @@ void drm_state_dump(struct drm_device *dev, struct drm_printer *p); (__i)++) \ for_each_if ((__state)->connectors[__i].ptr && \ ((connector) = (__state)->connectors[__i].ptr, \ + (void)(connector) /* Only to avoid unused-but-set-variable warning */, \ (old_connector_state) = (__state)->connectors[__i].old_state, 1)) /** @@ -734,7 +745,9 @@ void drm_state_dump(struct drm_device *dev, struct drm_printer *p); (__i)++) \ for_each_if ((__state)->connectors[__i].ptr && \ ((connector) = (__state)->connectors[__i].ptr, \ - (new_connector_state) = (__state)->connectors[__i].new_state, 1)) + (void)(connector) /* Only to avoid unused-but-set-variable warning */, \ + (new_connector_state) = (__state)->connectors[__i].new_state, \ + (void)(new_connector_state) /* Only to avoid unused-but-set-variable warning */, 1)) /** * for_each_oldnew_crtc_in_state - iterate over all CRTCs in an atomic update @@ -754,7 +767,9 @@ void drm_state_dump(struct drm_device *dev, struct drm_printer *p); (__i)++) \ for_each_if ((__state)->crtcs[__i].ptr && \ ((crtc) = (__state)->crtcs[__i].ptr, \ + (void)(crtc) /* Only to avoid unused-but-set-variable warning */, \ (old_crtc_state) = (__state)->crtcs[__i].old_state, \ + (void)(old_crtc_state) /* Only to avoid unused-but-set-variable warning */, \ (new_crtc_state) = (__state)->crtcs[__i].new_state, 1)) /** @@ -793,7 +808,9 @@ void drm_state_dump(struct drm_device *dev, struct drm_printer *p); (__i)++) \ for_each_if ((__state)->crtcs[__i].ptr && \ ((crtc) = (__state)->crtcs[__i].ptr, \ - (new_crtc_state) = (__state)->crtcs[__i].new_state, 1)) + (void)(crtc) /* Only to avoid unused-but-set-variable warning */, \ + (new_crtc_state) = (__state)->crtcs[__i].new_state, \ + (void)(new_crtc_state) /* Only to avoid unused-but-set-variable warning */, 1)) /** * for_each_oldnew_plane_in_state - iterate over all planes in an atomic update @@ -813,6 +830,7 @@ void drm_state_dump(struct drm_device *dev, struct drm_printer *p); (__i)++) \ for_each_if ((__state)->planes[__i].ptr && \ ((plane) = (__state)->planes[__i].ptr, \ + (void)(plane) /* Only to avoid unused-but-set-variable warning */, \ (old_plane_state) = (__state)->planes[__i].old_state,\ (new_plane_state) = (__state)->planes[__i].new_state, 1)) @@ -873,7 +891,9 @@ void drm_state_dump(struct drm_device *dev, struct drm_printer *p); (__i)++) \ for_each_if ((__state)->planes[__i].ptr && \ ((plane) = (__state)->planes[__i].ptr, \ - (new_plane_state) = (__state)->planes[__i].new_state, 1)) + (void)(plane) /* Only to avoid unused-but-set-variable warning */, \ + (new_plane_state) = (__state)->planes[__i].new_state, \ + (void)(new_plane_state) /* Only to avoid unused-but-set-variable warning */, 1)) /** * for_each_oldnew_private_obj_in_state - iterate over all private objects in an atomic update @@ -958,11 +978,11 @@ drm_atomic_crtc_needs_modeset(const struct drm_crtc_state *state) } /** - * drm_atomic_crtc_effectively_active - compute whether crtc is actually active + * drm_atomic_crtc_effectively_active - compute whether CRTC is actually active * @state: &drm_crtc_state for the CRTC * * When in self refresh mode, the crtc_state->active value will be false, since - * the crtc is off. However in some cases we're interested in whether the crtc + * the CRTC is off. However in some cases we're interested in whether the CRTC * is active, or effectively active (ie: it's connected to an active display). * In these cases, use this function instead of just checking active. */ diff --git a/include/drm/drm_atomic_helper.h b/include/drm/drm_atomic_helper.h index bf4e07141d81..9db3cac48f4f 100644 --- a/include/drm/drm_atomic_helper.h +++ b/include/drm/drm_atomic_helper.h @@ -152,7 +152,7 @@ int drm_atomic_helper_legacy_gamma_set(struct drm_crtc *crtc, /** * drm_atomic_crtc_for_each_plane - iterate over planes currently attached to CRTC * @plane: the loop cursor - * @crtc: the crtc whose planes are iterated + * @crtc: the CRTC whose planes are iterated * * This iterates over the current state, useful (for example) when applying * atomic state after it has been checked and swapped. To iterate over the @@ -166,7 +166,7 @@ int drm_atomic_helper_legacy_gamma_set(struct drm_crtc *crtc, /** * drm_crtc_atomic_state_for_each_plane - iterate over attached planes in new state * @plane: the loop cursor - * @crtc_state: the incoming crtc-state + * @crtc_state: the incoming CRTC state * * Similar to drm_crtc_for_each_plane(), but iterates the planes that will be * attached if the specified state is applied. Useful during for example @@ -180,7 +180,7 @@ int drm_atomic_helper_legacy_gamma_set(struct drm_crtc *crtc, * drm_crtc_atomic_state_for_each_plane_state - iterate over attached planes in new state * @plane: the loop cursor * @plane_state: loop cursor for the plane's state, must be const - * @crtc_state: the incoming crtc-state + * @crtc_state: the incoming CRTC state * * Similar to drm_crtc_for_each_plane(), but iterates the planes that will be * attached if the specified state is applied. Useful during for example @@ -189,7 +189,7 @@ int drm_atomic_helper_legacy_gamma_set(struct drm_crtc *crtc, * * Compared to just drm_atomic_crtc_state_for_each_plane() this also fills in a * const plane_state. This is useful when a driver just wants to peek at other - * active planes on this crtc, but does not need to change it. + * active planes on this CRTC, but does not need to change it. */ #define drm_atomic_crtc_state_for_each_plane_state(plane, plane_state, crtc_state) \ drm_for_each_plane_mask(plane, (crtc_state)->state->dev, (crtc_state)->plane_mask) \ diff --git a/include/drm/drm_atomic_state_helper.h b/include/drm/drm_atomic_state_helper.h index e4577cc11689..8171dea4cc22 100644 --- a/include/drm/drm_atomic_state_helper.h +++ b/include/drm/drm_atomic_state_helper.h @@ -37,6 +37,8 @@ struct drm_private_state; struct drm_modeset_acquire_ctx; struct drm_device; +void __drm_atomic_helper_crtc_state_reset(struct drm_crtc_state *state, + struct drm_crtc *crtc); void __drm_atomic_helper_crtc_reset(struct drm_crtc *crtc, struct drm_crtc_state *state); void drm_atomic_helper_crtc_reset(struct drm_crtc *crtc); @@ -48,6 +50,8 @@ void __drm_atomic_helper_crtc_destroy_state(struct drm_crtc_state *state); void drm_atomic_helper_crtc_destroy_state(struct drm_crtc *crtc, struct drm_crtc_state *state); +void __drm_atomic_helper_plane_state_reset(struct drm_plane_state *state, + struct drm_plane *plane); void __drm_atomic_helper_plane_reset(struct drm_plane *plane, struct drm_plane_state *state); void drm_atomic_helper_plane_reset(struct drm_plane *plane); @@ -59,6 +63,8 @@ void __drm_atomic_helper_plane_destroy_state(struct drm_plane_state *state); void drm_atomic_helper_plane_destroy_state(struct drm_plane *plane, struct drm_plane_state *state); +void __drm_atomic_helper_connector_state_reset(struct drm_connector_state *conn_state, + struct drm_connector *connector); void __drm_atomic_helper_connector_reset(struct drm_connector *connector, struct drm_connector_state *conn_state); void drm_atomic_helper_connector_reset(struct drm_connector *connector); diff --git a/include/drm/drm_bridge.h b/include/drm/drm_bridge.h index 7616f6562fe4..694e153a7531 100644 --- a/include/drm/drm_bridge.h +++ b/include/drm/drm_bridge.h @@ -25,6 +25,7 @@ #include <linux/list.h> #include <linux/ctype.h> +#include <drm/drm_encoder.h> #include <drm/drm_mode_object.h> #include <drm/drm_modes.h> @@ -42,7 +43,7 @@ struct drm_bridge_funcs { * This callback is invoked whenever our bridge is being attached to a * &drm_encoder. * - * The attach callback is optional. + * The @attach callback is optional. * * RETURNS: * @@ -56,7 +57,7 @@ struct drm_bridge_funcs { * This callback is invoked whenever our bridge is being detached from a * &drm_encoder. * - * The detach callback is optional. + * The @detach callback is optional. */ void (*detach)(struct drm_bridge *bridge); @@ -76,7 +77,7 @@ struct drm_bridge_funcs { * atomic helpers to validate modes supplied by userspace in * drm_atomic_helper_check_modeset(). * - * This function is optional. + * The @mode_valid callback is optional. * * NOTE: * @@ -108,7 +109,7 @@ struct drm_bridge_funcs { * this function passes all other callbacks must succeed for this * configuration. * - * The mode_fixup callback is optional. + * The @mode_fixup callback is optional. * * NOTE: * @@ -146,7 +147,7 @@ struct drm_bridge_funcs { * The bridge can assume that the display pipe (i.e. clocks and timing * signals) feeding it is still running when this callback is called. * - * The disable callback is optional. + * The @disable callback is optional. */ void (*disable)(struct drm_bridge *bridge); @@ -165,7 +166,7 @@ struct drm_bridge_funcs { * singals) feeding it is no longer running when this callback is * called. * - * The post_disable callback is optional. + * The @post_disable callback is optional. */ void (*post_disable)(struct drm_bridge *bridge); @@ -214,7 +215,7 @@ struct drm_bridge_funcs { * not enable the display link feeding the next bridge in the chain (if * there is one) when this callback is called. * - * The pre_enable callback is optional. + * The @pre_enable callback is optional. */ void (*pre_enable)(struct drm_bridge *bridge); @@ -234,7 +235,7 @@ struct drm_bridge_funcs { * callback must enable the display link feeding the next bridge in the * chain if there is one. * - * The enable callback is optional. + * The @enable callback is optional. */ void (*enable)(struct drm_bridge *bridge); @@ -254,14 +255,15 @@ struct drm_bridge_funcs { * there is one) when this callback is called. * * Note that this function will only be invoked in the context of an - * atomic commit. It will not be invoked from &drm_bridge_pre_enable. It - * would be prudent to also provide an implementation of @pre_enable if - * you are expecting driver calls into &drm_bridge_pre_enable. + * atomic commit. It will not be invoked from + * &drm_bridge_chain_pre_enable. It would be prudent to also provide an + * implementation of @pre_enable if you are expecting driver calls into + * &drm_bridge_chain_pre_enable. * * The @atomic_pre_enable callback is optional. */ void (*atomic_pre_enable)(struct drm_bridge *bridge, - struct drm_atomic_state *state); + struct drm_atomic_state *old_state); /** * @atomic_enable: @@ -279,14 +281,14 @@ struct drm_bridge_funcs { * chain if there is one. * * Note that this function will only be invoked in the context of an - * atomic commit. It will not be invoked from &drm_bridge_enable. It - * would be prudent to also provide an implementation of @enable if - * you are expecting driver calls into &drm_bridge_enable. + * atomic commit. It will not be invoked from &drm_bridge_chain_enable. + * It would be prudent to also provide an implementation of @enable if + * you are expecting driver calls into &drm_bridge_chain_enable. * - * The enable callback is optional. + * The @atomic_enable callback is optional. */ void (*atomic_enable)(struct drm_bridge *bridge, - struct drm_atomic_state *state); + struct drm_atomic_state *old_state); /** * @atomic_disable: * @@ -301,14 +303,15 @@ struct drm_bridge_funcs { * signals) feeding it is still running when this callback is called. * * Note that this function will only be invoked in the context of an - * atomic commit. It will not be invoked from &drm_bridge_disable. It - * would be prudent to also provide an implementation of @disable if - * you are expecting driver calls into &drm_bridge_disable. + * atomic commit. It will not be invoked from + * &drm_bridge_chain_disable. It would be prudent to also provide an + * implementation of @disable if you are expecting driver calls into + * &drm_bridge_chain_disable. * - * The disable callback is optional. + * The @atomic_disable callback is optional. */ void (*atomic_disable)(struct drm_bridge *bridge, - struct drm_atomic_state *state); + struct drm_atomic_state *old_state); /** * @atomic_post_disable: @@ -325,15 +328,16 @@ struct drm_bridge_funcs { * called. * * Note that this function will only be invoked in the context of an - * atomic commit. It will not be invoked from &drm_bridge_post_disable. + * atomic commit. It will not be invoked from + * &drm_bridge_chain_post_disable. * It would be prudent to also provide an implementation of * @post_disable if you are expecting driver calls into - * &drm_bridge_post_disable. + * &drm_bridge_chain_post_disable. * - * The post_disable callback is optional. + * The @atomic_post_disable callback is optional. */ void (*atomic_post_disable)(struct drm_bridge *bridge, - struct drm_atomic_state *state); + struct drm_atomic_state *old_state); }; /** @@ -380,8 +384,8 @@ struct drm_bridge { struct drm_device *dev; /** @encoder: encoder to which this bridge is connected */ struct drm_encoder *encoder; - /** @next: the next bridge in the encoder chain */ - struct drm_bridge *next; + /** @chain_node: used to form a bridge chain */ + struct list_head chain_node; #ifdef CONFIG_OF /** @of_node: device node pointer to the bridge */ struct device_node *of_node; @@ -406,35 +410,98 @@ struct drm_bridge *of_drm_find_bridge(struct device_node *np); int drm_bridge_attach(struct drm_encoder *encoder, struct drm_bridge *bridge, struct drm_bridge *previous); -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, - const struct drm_display_mode *mode, - const struct drm_display_mode *adjusted_mode); -void drm_bridge_pre_enable(struct drm_bridge *bridge); -void drm_bridge_enable(struct drm_bridge *bridge); +/** + * drm_bridge_get_next_bridge() - Get the next bridge in the chain + * @bridge: bridge object + * + * RETURNS: + * the next bridge in the chain after @bridge, or NULL if @bridge is the last. + */ +static inline struct drm_bridge * +drm_bridge_get_next_bridge(struct drm_bridge *bridge) +{ + if (list_is_last(&bridge->chain_node, &bridge->encoder->bridge_chain)) + return NULL; + + return list_next_entry(bridge, chain_node); +} + +/** + * drm_bridge_get_prev_bridge() - Get the previous bridge in the chain + * @bridge: bridge object + * + * RETURNS: + * the previous bridge in the chain, or NULL if @bridge is the first. + */ +static inline struct drm_bridge * +drm_bridge_get_prev_bridge(struct drm_bridge *bridge) +{ + if (list_is_first(&bridge->chain_node, &bridge->encoder->bridge_chain)) + return NULL; + + return list_prev_entry(bridge, chain_node); +} + +/** + * drm_bridge_chain_get_first_bridge() - Get the first bridge in the chain + * @encoder: encoder object + * + * RETURNS: + * the first bridge in the chain, or NULL if @encoder has no bridge attached + * to it. + */ +static inline struct drm_bridge * +drm_bridge_chain_get_first_bridge(struct drm_encoder *encoder) +{ + return list_first_entry_or_null(&encoder->bridge_chain, + struct drm_bridge, chain_node); +} + +/** + * drm_for_each_bridge_in_chain() - Iterate over all bridges present in a chain + * @encoder: the encoder to iterate bridges on + * @bridge: a bridge pointer updated to point to the current bridge at each + * iteration + * + * Iterate over all bridges present in the bridge chain attached to @encoder. + */ +#define drm_for_each_bridge_in_chain(encoder, bridge) \ + list_for_each_entry(bridge, &(encoder)->bridge_chain, chain_node) + +bool drm_bridge_chain_mode_fixup(struct drm_bridge *bridge, + const struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode); +enum drm_mode_status +drm_bridge_chain_mode_valid(struct drm_bridge *bridge, + const struct drm_display_mode *mode); +void drm_bridge_chain_disable(struct drm_bridge *bridge); +void drm_bridge_chain_post_disable(struct drm_bridge *bridge); +void drm_bridge_chain_mode_set(struct drm_bridge *bridge, + const struct drm_display_mode *mode, + const struct drm_display_mode *adjusted_mode); +void drm_bridge_chain_pre_enable(struct drm_bridge *bridge); +void drm_bridge_chain_enable(struct drm_bridge *bridge); -void drm_atomic_bridge_disable(struct drm_bridge *bridge, - struct drm_atomic_state *state); -void drm_atomic_bridge_post_disable(struct drm_bridge *bridge, +void drm_atomic_bridge_chain_disable(struct drm_bridge *bridge, + struct drm_atomic_state *state); +void drm_atomic_bridge_chain_post_disable(struct drm_bridge *bridge, + struct drm_atomic_state *state); +void drm_atomic_bridge_chain_pre_enable(struct drm_bridge *bridge, + struct drm_atomic_state *state); +void drm_atomic_bridge_chain_enable(struct drm_bridge *bridge, struct drm_atomic_state *state); -void drm_atomic_bridge_pre_enable(struct drm_bridge *bridge, - struct drm_atomic_state *state); -void drm_atomic_bridge_enable(struct drm_bridge *bridge, - struct drm_atomic_state *state); #ifdef CONFIG_DRM_PANEL_BRIDGE -struct drm_bridge *drm_panel_bridge_add(struct drm_panel *panel, - u32 connector_type); +struct drm_bridge *drm_panel_bridge_add(struct drm_panel *panel); +struct drm_bridge *drm_panel_bridge_add_typed(struct drm_panel *panel, + u32 connector_type); void drm_panel_bridge_remove(struct drm_bridge *bridge); struct drm_bridge *devm_drm_panel_bridge_add(struct device *dev, - struct drm_panel *panel, - u32 connector_type); + struct drm_panel *panel); +struct drm_bridge *devm_drm_panel_bridge_add_typed(struct device *dev, + struct drm_panel *panel, + u32 connector_type); +struct drm_connector *drm_panel_bridge_connector(struct drm_bridge *bridge); #endif #endif diff --git a/include/drm/drm_cache.h b/include/drm/drm_cache.h index 987ff16b9420..e9ad4863d915 100644 --- a/include/drm/drm_cache.h +++ b/include/drm/drm_cache.h @@ -45,7 +45,7 @@ static inline bool drm_arch_can_wc_memory(void) { #if defined(CONFIG_PPC) && !defined(CONFIG_NOT_COHERENT_CACHE) return false; -#elif defined(CONFIG_MIPS) && defined(CONFIG_CPU_LOONGSON3) +#elif defined(CONFIG_MIPS) && defined(CONFIG_CPU_LOONGSON64) return false; #elif defined(CONFIG_ARM) || defined(CONFIG_ARM64) /* diff --git a/include/drm/drm_color_mgmt.h b/include/drm/drm_color_mgmt.h index d1c662d92ab7..81c298488b0c 100644 --- a/include/drm/drm_color_mgmt.h +++ b/include/drm/drm_color_mgmt.h @@ -29,7 +29,30 @@ struct drm_crtc; struct drm_plane; -uint32_t drm_color_lut_extract(uint32_t user_input, uint32_t bit_precision); +/** + * drm_color_lut_extract - clamp and round LUT entries + * @user_input: input value + * @bit_precision: number of bits the hw LUT supports + * + * Extract a degamma/gamma LUT value provided by user (in the form of + * &drm_color_lut entries) and round it to the precision supported by the + * hardware. + */ +static inline u32 drm_color_lut_extract(u32 user_input, int bit_precision) +{ + u32 val = user_input; + u32 max = 0xffff >> (16 - bit_precision); + + /* Round only if we're not using full precision. */ + if (bit_precision < 16) { + val += 1UL << (16 - bit_precision - 1); + val >>= 16 - bit_precision; + } + + return clamp_val(val, 0, max); +} + +u64 drm_color_ctm_s31_32_to_qm_n(u64 user_input, u32 m, u32 n); void drm_crtc_enable_color_mgmt(struct drm_crtc *crtc, uint degamma_lut_size, diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h index ca745d9feaf5..221910948b37 100644 --- a/include/drm/drm_connector.h +++ b/include/drm/drm_connector.h @@ -41,6 +41,7 @@ struct drm_property; struct drm_property_blob; struct drm_printer; struct edid; +struct i2c_adapter; enum drm_connector_force { DRM_FORCE_UNSPECIFIED, @@ -187,19 +188,19 @@ struct drm_hdmi_info { /** * @y420_vdb_modes: bitmap of modes which can support ycbcr420 - * output only (not normal RGB/YCBCR444/422 outputs). There are total - * 107 VICs defined by CEA-861-F spec, so the size is 128 bits to map - * upto 128 VICs; + * output only (not normal RGB/YCBCR444/422 outputs). The max VIC + * defined by the CEA-861-G spec is 219, so the size is 256 bits to map + * up to 256 VICs. */ - unsigned long y420_vdb_modes[BITS_TO_LONGS(128)]; + unsigned long y420_vdb_modes[BITS_TO_LONGS(256)]; /** * @y420_cmdb_modes: bitmap of modes which can support ycbcr420 - * output also, along with normal HDMI outputs. There are total 107 - * VICs defined by CEA-861-F spec, so the size is 128 bits to map upto - * 128 VICs; + * output also, along with normal HDMI outputs. The max VIC defined by + * the CEA-861-G spec is 219, so the size is 256 bits to map up to 256 + * VICs. */ - unsigned long y420_cmdb_modes[BITS_TO_LONGS(128)]; + unsigned long y420_cmdb_modes[BITS_TO_LONGS(256)]; /** @y420_cmdb_map: bitmap of SVD index, to extraxt vcb modes */ u64 y420_cmdb_map; @@ -280,6 +281,10 @@ enum drm_panel_orientation { /* Additional Colorimetry extension added as part of CTA 861.G */ #define DRM_MODE_COLORIMETRY_DCI_P3_RGB_D65 11 #define DRM_MODE_COLORIMETRY_DCI_P3_RGB_THEATER 12 +/* Additional Colorimetry Options added for DP 1.4a VSC Colorimetry Format */ +#define DRM_MODE_COLORIMETRY_RGB_WIDE_FIXED 13 +#define DRM_MODE_COLORIMETRY_RGB_WIDE_FLOAT 14 +#define DRM_MODE_COLORIMETRY_BT601_YCC 15 /** * enum drm_bus_flags - bus_flags info for &drm_display_info @@ -323,6 +328,8 @@ enum drm_panel_orientation { * edge of the pixel clock * @DRM_BUS_FLAG_SYNC_SAMPLE_NEGEDGE: Sync signals are sampled on the falling * edge of the pixel clock + * @DRM_BUS_FLAG_SHARP_SIGNALS: Set if the Sharp-specific signals + * (SPL, CLS, PS, REV) must be used */ enum drm_bus_flags { DRM_BUS_FLAG_DE_LOW = BIT(0), @@ -341,6 +348,7 @@ enum drm_bus_flags { DRM_BUS_FLAG_SYNC_DRIVE_NEGEDGE = DRM_BUS_FLAG_SYNC_NEGEDGE, DRM_BUS_FLAG_SYNC_SAMPLE_POSEDGE = DRM_BUS_FLAG_SYNC_NEGEDGE, DRM_BUS_FLAG_SYNC_SAMPLE_NEGEDGE = DRM_BUS_FLAG_SYNC_POSEDGE, + DRM_BUS_FLAG_SHARP_SIGNALS = BIT(8), }; /** @@ -539,8 +547,8 @@ struct drm_connector_state { * * This is also used in the atomic helpers to map encoders to their * current and previous connectors, see - * &drm_atomic_get_old_connector_for_encoder() and - * &drm_atomic_get_new_connector_for_encoder(). + * drm_atomic_get_old_connector_for_encoder() and + * drm_atomic_get_new_connector_for_encoder(). * * NOTE: Atomic drivers must fill this out (either themselves or through * helpers), for otherwise the GETCONNECTOR and GETENCODER IOCTLs will @@ -599,6 +607,12 @@ struct drm_connector_state { unsigned int content_type; /** + * @hdcp_content_type: Connector property to pass the type of + * protected content. This is most commonly used for HDCP. + */ + unsigned int hdcp_content_type; + + /** * @scaling_mode: Connector property to control the * upscaling, mostly used for built-in panels. */ @@ -1056,6 +1070,14 @@ struct drm_cmdline_mode { unsigned int rotation_reflection; /** + * @panel_orientation: + * + * drm-connector "panel orientation" property override value, + * DRM_MODE_PANEL_ORIENTATION_UNKNOWN if not set. + */ + enum drm_panel_orientation panel_orientation; + + /** * @tv_margins: TV margins to apply to the mode. */ struct drm_connector_tv_margins tv_margins; @@ -1278,12 +1300,12 @@ struct drm_connector { /** @override_edid: has the EDID been overwritten through debugfs for testing? */ bool override_edid; -#define DRM_CONNECTOR_MAX_ENCODER 3 /** - * @encoder_ids: Valid encoders for this connector. Please only use - * drm_connector_for_each_possible_encoder() to enumerate these. + * @possible_encoders: Bit mask of encoders that can drive this + * connector, drm_encoder_index() determines the index into the bitfield + * and the bits are set with drm_connector_attach_encoder(). */ - uint32_t encoder_ids[DRM_CONNECTOR_MAX_ENCODER]; + u32 possible_encoders; /** * @encoder: Currently bound encoder driving this connector, if any. @@ -1308,6 +1330,18 @@ struct drm_connector { * [0]: progressive, [1]: interlaced */ int audio_latency[2]; + + /** + * @ddc: associated ddc adapter. + * A connector usually has its associated ddc adapter. If a driver uses + * this field, then an appropriate symbolic link is created in connector + * sysfs directory to make it easy for the user to tell which i2c + * adapter is for a particular display. + * + * The field should be set by calling drm_connector_init_with_ddc(). + */ + struct i2c_adapter *ddc; + /** * @null_edid_counter: track sinks that give us all zeros for the EDID. * Needed to workaround some HW bugs where we get all 0s @@ -1396,6 +1430,11 @@ int drm_connector_init(struct drm_device *dev, struct drm_connector *connector, const struct drm_connector_funcs *funcs, int connector_type); +int drm_connector_init_with_ddc(struct drm_device *dev, + struct drm_connector *connector, + const struct drm_connector_funcs *funcs, + int connector_type, + struct i2c_adapter *ddc); void drm_connector_attach_edid_property(struct drm_connector *connector); int drm_connector_register(struct drm_connector *connector); void drm_connector_unregister(struct drm_connector *connector); @@ -1481,6 +1520,7 @@ const char *drm_get_dvi_i_select_name(int val); const char *drm_get_tv_subconnector_name(int val); const char *drm_get_tv_select_name(int val); const char *drm_get_content_protection_name(int val); +const char *drm_get_hdcp_content_type_name(int val); int drm_mode_create_dvi_i_properties(struct drm_device *dev); int drm_mode_create_tv_margin_properties(struct drm_device *dev); @@ -1495,7 +1535,8 @@ int drm_connector_attach_scaling_mode_property(struct drm_connector *connector, int drm_connector_attach_vrr_capable_property( struct drm_connector *connector); int drm_mode_create_aspect_ratio_property(struct drm_device *dev); -int drm_mode_create_colorspace_property(struct drm_connector *connector); +int drm_mode_create_hdmi_colorspace_property(struct drm_connector *connector); +int drm_mode_create_dp_colorspace_property(struct drm_connector *connector); int drm_mode_create_content_type_property(struct drm_device *dev); void drm_hdmi_avi_infoframe_content_type(struct hdmi_avi_infoframe *frame, const struct drm_connector_state *conn_state); @@ -1580,13 +1621,9 @@ bool drm_connector_has_possible_encoder(struct drm_connector *connector, * drm_connector_for_each_possible_encoder - iterate connector's possible encoders * @connector: &struct drm_connector pointer * @encoder: &struct drm_encoder pointer used as cursor - * @__i: int iteration cursor, for macro-internal use */ -#define drm_connector_for_each_possible_encoder(connector, encoder, __i) \ - for ((__i) = 0; (__i) < ARRAY_SIZE((connector)->encoder_ids) && \ - (connector)->encoder_ids[(__i)] != 0; (__i)++) \ - for_each_if((encoder) = \ - drm_encoder_find((connector)->dev, NULL, \ - (connector)->encoder_ids[(__i)])) \ +#define drm_connector_for_each_possible_encoder(connector, encoder) \ + drm_for_each_encoder_mask(encoder, (connector)->dev, \ + (connector)->possible_encoders) #endif diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h index 128d8b210621..5e9b15a0e8c5 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h @@ -41,7 +41,6 @@ #include <drm/drm_connector.h> #include <drm/drm_device.h> #include <drm/drm_property.h> -#include <drm/drm_bridge.h> #include <drm/drm_edid.h> #include <drm/drm_plane.h> #include <drm/drm_blend.h> @@ -285,12 +284,12 @@ struct drm_crtc_state { u32 target_vblank; /** - * @pageflip_flags: + * @async_flip: * - * DRM_MODE_PAGE_FLIP_* flags, as passed to the page flip ioctl. - * Zero in any other case. + * This is set when DRM_MODE_PAGE_FLIP_ASYNC is set in the legacy + * PAGE_FLIP IOCTL. It's not wired up for the atomic IOCTL itself yet. */ - u32 pageflip_flags; + bool async_flip; /** * @vrr_enabled: @@ -756,6 +755,9 @@ struct drm_crtc_funcs { * provided from the configured source. Drivers must accept an "auto" * source name that will select a default source for this CRTC. * + * This may trigger an atomic modeset commit if necessary, to enable CRC + * generation. + * * Note that "auto" can depend upon the current modeset configuration, * e.g. it could pick an encoder or output specific CRC sampling point. * @@ -767,6 +769,7 @@ struct drm_crtc_funcs { * 0 on success or a negative error code on failure. */ int (*set_crc_source)(struct drm_crtc *crtc, const char *source); + /** * @verify_crc_source: * @@ -1104,7 +1107,7 @@ struct drm_crtc { /** * @self_refresh_data: Holds the state for the self refresh helpers * - * Initialized via drm_self_refresh_helper_register(). + * Initialized via drm_self_refresh_helper_init(). */ struct drm_self_refresh_data *self_refresh_data; }; diff --git a/include/drm/drm_dp_helper.h b/include/drm/drm_dp_helper.h index 397896b5b21a..bc04467f7c3a 100644 --- a/include/drm/drm_dp_helper.h +++ b/include/drm/drm_dp_helper.h @@ -23,9 +23,9 @@ #ifndef _DRM_DP_HELPER_H_ #define _DRM_DP_HELPER_H_ -#include <linux/types.h> -#include <linux/i2c.h> #include <linux/delay.h> +#include <linux/i2c.h> +#include <linux/types.h> /* * Unless otherwise noted, all values are from the DP 1.1a spec. Note that @@ -42,6 +42,48 @@ * 1.2 formally includes both eDP and DPI definitions. */ +/* MSA (Main Stream Attribute) MISC bits (as MISC1<<8|MISC0) */ +#define DP_MSA_MISC_SYNC_CLOCK (1 << 0) +#define DP_MSA_MISC_INTERLACE_VTOTAL_EVEN (1 << 8) +#define DP_MSA_MISC_STEREO_NO_3D (0 << 9) +#define DP_MSA_MISC_STEREO_PROG_RIGHT_EYE (1 << 9) +#define DP_MSA_MISC_STEREO_PROG_LEFT_EYE (3 << 9) +/* bits per component for non-RAW */ +#define DP_MSA_MISC_6_BPC (0 << 5) +#define DP_MSA_MISC_8_BPC (1 << 5) +#define DP_MSA_MISC_10_BPC (2 << 5) +#define DP_MSA_MISC_12_BPC (3 << 5) +#define DP_MSA_MISC_16_BPC (4 << 5) +/* bits per component for RAW */ +#define DP_MSA_MISC_RAW_6_BPC (1 << 5) +#define DP_MSA_MISC_RAW_7_BPC (2 << 5) +#define DP_MSA_MISC_RAW_8_BPC (3 << 5) +#define DP_MSA_MISC_RAW_10_BPC (4 << 5) +#define DP_MSA_MISC_RAW_12_BPC (5 << 5) +#define DP_MSA_MISC_RAW_14_BPC (6 << 5) +#define DP_MSA_MISC_RAW_16_BPC (7 << 5) +/* pixel encoding/colorimetry format */ +#define _DP_MSA_MISC_COLOR(misc1_7, misc0_21, misc0_3, misc0_4) \ + ((misc1_7) << 15 | (misc0_4) << 4 | (misc0_3) << 3 | ((misc0_21) << 1)) +#define DP_MSA_MISC_COLOR_RGB _DP_MSA_MISC_COLOR(0, 0, 0, 0) +#define DP_MSA_MISC_COLOR_CEA_RGB _DP_MSA_MISC_COLOR(0, 0, 1, 0) +#define DP_MSA_MISC_COLOR_RGB_WIDE_FIXED _DP_MSA_MISC_COLOR(0, 3, 0, 0) +#define DP_MSA_MISC_COLOR_RGB_WIDE_FLOAT _DP_MSA_MISC_COLOR(0, 3, 0, 1) +#define DP_MSA_MISC_COLOR_Y_ONLY _DP_MSA_MISC_COLOR(1, 0, 0, 0) +#define DP_MSA_MISC_COLOR_RAW _DP_MSA_MISC_COLOR(1, 1, 0, 0) +#define DP_MSA_MISC_COLOR_YCBCR_422_BT601 _DP_MSA_MISC_COLOR(0, 1, 1, 0) +#define DP_MSA_MISC_COLOR_YCBCR_422_BT709 _DP_MSA_MISC_COLOR(0, 1, 1, 1) +#define DP_MSA_MISC_COLOR_YCBCR_444_BT601 _DP_MSA_MISC_COLOR(0, 2, 1, 0) +#define DP_MSA_MISC_COLOR_YCBCR_444_BT709 _DP_MSA_MISC_COLOR(0, 2, 1, 1) +#define DP_MSA_MISC_COLOR_XVYCC_422_BT601 _DP_MSA_MISC_COLOR(0, 1, 0, 0) +#define DP_MSA_MISC_COLOR_XVYCC_422_BT709 _DP_MSA_MISC_COLOR(0, 1, 0, 1) +#define DP_MSA_MISC_COLOR_XVYCC_444_BT601 _DP_MSA_MISC_COLOR(0, 2, 0, 0) +#define DP_MSA_MISC_COLOR_XVYCC_444_BT709 _DP_MSA_MISC_COLOR(0, 2, 0, 1) +#define DP_MSA_MISC_COLOR_OPRGB _DP_MSA_MISC_COLOR(0, 0, 1, 1) +#define DP_MSA_MISC_COLOR_DCI_P3 _DP_MSA_MISC_COLOR(0, 3, 1, 0) +#define DP_MSA_MISC_COLOR_COLOR_PROFILE _DP_MSA_MISC_COLOR(0, 3, 1, 1) +#define DP_MSA_MISC_COLOR_VSC_SDP (1 << 14) + #define DP_AUX_MAX_PAYLOAD_BYTES 16 #define DP_AUX_I2C_WRITE 0x0 @@ -95,6 +137,7 @@ # define DP_DETAILED_CAP_INFO_AVAILABLE (1 << 4) /* DPI */ #define DP_MAIN_LINK_CHANNEL_CODING 0x006 +# define DP_CAP_ANSI_8B10B (1 << 0) #define DP_DOWN_STREAM_PORT_COUNT 0x007 # define DP_PORT_COUNT_MASK 0x0f @@ -264,7 +307,7 @@ # define DP_DSC_THROUGHPUT_MODE_0_900 (12 << 0) # define DP_DSC_THROUGHPUT_MODE_0_950 (13 << 0) # define DP_DSC_THROUGHPUT_MODE_0_1000 (14 << 0) -# define DP_DSC_THROUGHPUT_MODE_0_170 (15 << 4) +# define DP_DSC_THROUGHPUT_MODE_0_170 (15 << 0) /* 1.4a */ # define DP_DSC_THROUGHPUT_MODE_1_MASK (0xf << 4) # define DP_DSC_THROUGHPUT_MODE_1_SHIFT 4 # define DP_DSC_THROUGHPUT_MODE_1_UPSUPPORTED 0 @@ -562,6 +605,14 @@ # define DP_ADJUST_PRE_EMPHASIS_LANE1_SHIFT 6 #define DP_ADJUST_REQUEST_POST_CURSOR2 0x20c +# define DP_ADJUST_POST_CURSOR2_LANE0_MASK 0x03 +# define DP_ADJUST_POST_CURSOR2_LANE0_SHIFT 0 +# define DP_ADJUST_POST_CURSOR2_LANE1_MASK 0x0c +# define DP_ADJUST_POST_CURSOR2_LANE1_SHIFT 2 +# define DP_ADJUST_POST_CURSOR2_LANE2_MASK 0x30 +# define DP_ADJUST_POST_CURSOR2_LANE2_SHIFT 4 +# define DP_ADJUST_POST_CURSOR2_LANE3_MASK 0xc0 +# define DP_ADJUST_POST_CURSOR2_LANE3_SHIFT 6 #define DP_TEST_REQUEST 0x218 # define DP_TEST_LINK_TRAINING (1 << 0) @@ -966,6 +1017,38 @@ #define DP_HDCP_2_2_REG_STREAM_TYPE_OFFSET 0x69494 #define DP_HDCP_2_2_REG_DBG_OFFSET 0x69518 +/* Link Training (LT)-tunable PHY Repeaters */ +#define DP_LT_TUNABLE_PHY_REPEATER_FIELD_DATA_STRUCTURE_REV 0xf0000 /* 1.3 */ +#define DP_MAX_LINK_RATE_PHY_REPEATER 0xf0001 /* 1.4a */ +#define DP_PHY_REPEATER_CNT 0xf0002 /* 1.3 */ +#define DP_PHY_REPEATER_MODE 0xf0003 /* 1.3 */ +#define DP_MAX_LANE_COUNT_PHY_REPEATER 0xf0004 /* 1.4a */ +#define DP_Repeater_FEC_CAPABILITY 0xf0004 /* 1.4 */ +#define DP_PHY_REPEATER_EXTENDED_WAIT_TIMEOUT 0xf0005 /* 1.4a */ +#define DP_TRAINING_PATTERN_SET_PHY_REPEATER1 0xf0010 /* 1.3 */ +#define DP_TRAINING_LANE0_SET_PHY_REPEATER1 0xf0011 /* 1.3 */ +#define DP_TRAINING_LANE1_SET_PHY_REPEATER1 0xf0012 /* 1.3 */ +#define DP_TRAINING_LANE2_SET_PHY_REPEATER1 0xf0013 /* 1.3 */ +#define DP_TRAINING_LANE3_SET_PHY_REPEATER1 0xf0014 /* 1.3 */ +#define DP_TRAINING_AUX_RD_INTERVAL_PHY_REPEATER1 0xf0020 /* 1.4a */ +#define DP_TRANSMITTER_CAPABILITY_PHY_REPEATER1 0xf0021 /* 1.4a */ +#define DP_LANE0_1_STATUS_PHY_REPEATER1 0xf0030 /* 1.3 */ +#define DP_LANE2_3_STATUS_PHY_REPEATER1 0xf0031 /* 1.3 */ +#define DP_LANE_ALIGN_STATUS_UPDATED_PHY_REPEATER1 0xf0032 /* 1.3 */ +#define DP_ADJUST_REQUEST_LANE0_1_PHY_REPEATER1 0xf0033 /* 1.3 */ +#define DP_ADJUST_REQUEST_LANE2_3_PHY_REPEATER1 0xf0034 /* 1.3 */ +#define DP_SYMBOL_ERROR_COUNT_LANE0_PHY_REPEATER1 0xf0035 /* 1.3 */ +#define DP_SYMBOL_ERROR_COUNT_LANE1_PHY_REPEATER1 0xf0037 /* 1.3 */ +#define DP_SYMBOL_ERROR_COUNT_LANE2_PHY_REPEATER1 0xf0039 /* 1.3 */ +#define DP_SYMBOL_ERROR_COUNT_LANE3_PHY_REPEATER1 0xf003b /* 1.3 */ +#define DP_FEC_STATUS_PHY_REPEATER1 0xf0290 /* 1.4 */ +#define DP_FEC_ERROR_COUNT_PHY_REPEATER1 0xf0291 /* 1.4 */ +#define DP_FEC_CAPABILITY_PHY_REPEATER1 0xf0294 /* 1.4a */ + +/* Repeater modes */ +#define DP_PHY_REPEATER_MODE_TRANSPARENT 0x55 /* 1.3 */ +#define DP_PHY_REPEATER_MODE_NON_TRANSPARENT 0xaa /* 1.3 */ + /* DP HDCP message start offsets in DPCD address space */ #define DP_HDCP_2_2_AKE_INIT_OFFSET DP_HDCP_2_2_REG_RTX_OFFSET #define DP_HDCP_2_2_AKE_SEND_CERT_OFFSET DP_HDCP_2_2_REG_CERT_RX_OFFSET @@ -1049,6 +1132,8 @@ u8 drm_dp_get_adjust_request_voltage(const u8 link_status[DP_LINK_STATUS_SIZE], int lane); u8 drm_dp_get_adjust_request_pre_emphasis(const u8 link_status[DP_LINK_STATUS_SIZE], int lane); +u8 drm_dp_get_adjust_request_post_cursor(const u8 link_status[DP_LINK_STATUS_SIZE], + unsigned int lane); #define DP_BRANCH_OUI_HEADER_SIZE 0xc #define DP_RECEIVER_CAP_SIZE 0xf @@ -1144,6 +1229,13 @@ drm_dp_enhanced_frame_cap(const u8 dpcd[DP_RECEIVER_CAP_SIZE]) } static inline bool +drm_dp_fast_training_cap(const u8 dpcd[DP_RECEIVER_CAP_SIZE]) +{ + return dpcd[DP_DPCD_REV] >= 0x11 && + (dpcd[DP_MAX_DOWNSPREAD] & DP_NO_AUX_HANDSHAKE_LINK_TRAINING); +} + +static inline bool drm_dp_tps3_supported(const u8 dpcd[DP_RECEIVER_CAP_SIZE]) { return dpcd[DP_DPCD_REV] >= 0x12 && @@ -1208,6 +1300,19 @@ drm_dp_sink_supports_fec(const u8 fec_capable) return fec_capable & DP_FEC_CAPABLE; } +static inline bool +drm_dp_channel_coding_supported(const u8 dpcd[DP_RECEIVER_CAP_SIZE]) +{ + return dpcd[DP_MAIN_LINK_CHANNEL_CODING] & DP_CAP_ANSI_8B10B; +} + +static inline bool +drm_dp_alternate_scrambler_reset_cap(const u8 dpcd[DP_RECEIVER_CAP_SIZE]) +{ + return dpcd[DP_EDP_CONFIGURATION_CAP] & + DP_ALTERNATE_SCRAMBLER_RESET_CAP; +} + /* * DisplayPort AUX channel */ @@ -1230,20 +1335,19 @@ struct drm_dp_aux_msg { struct cec_adapter; struct edid; +struct drm_connector; /** * struct drm_dp_aux_cec - DisplayPort CEC-Tunneling-over-AUX * @lock: mutex protecting this struct * @adap: the CEC adapter for CEC-Tunneling-over-AUX support. - * @name: name of the CEC adapter - * @parent: parent device of the CEC adapter + * @connector: the connector this CEC adapter is associated with * @unregister_work: unregister the CEC adapter */ struct drm_dp_aux_cec { struct mutex lock; struct cec_adapter *adap; - const char *name; - struct device *parent; + struct drm_connector *connector; struct delayed_work unregister_work; }; @@ -1309,6 +1413,10 @@ struct drm_dp_aux { * @cec: struct containing fields used for CEC-Tunneling-over-AUX. */ struct drm_dp_aux_cec cec; + /** + * @is_remote: Is this AUX CH actually using sideband messaging. + */ + bool is_remote; }; ssize_t drm_dp_dpcd_read(struct drm_dp_aux *aux, unsigned int offset, @@ -1349,22 +1457,6 @@ static inline ssize_t drm_dp_dpcd_writeb(struct drm_dp_aux *aux, int drm_dp_dpcd_read_link_status(struct drm_dp_aux *aux, u8 status[DP_LINK_STATUS_SIZE]); -/* - * DisplayPort link - */ -#define DP_LINK_CAP_ENHANCED_FRAMING (1 << 0) - -struct drm_dp_link { - unsigned char revision; - unsigned int rate; - unsigned int num_lanes; - unsigned long capabilities; -}; - -int drm_dp_link_probe(struct drm_dp_aux *aux, struct drm_dp_link *link); -int drm_dp_link_power_up(struct drm_dp_aux *aux, struct drm_dp_link *link); -int drm_dp_link_power_down(struct drm_dp_aux *aux, struct drm_dp_link *link); -int drm_dp_link_configure(struct drm_dp_aux *aux, struct drm_dp_link *link); int drm_dp_downstream_max_clock(const u8 dpcd[DP_RECEIVER_CAP_SIZE], const u8 port_cap[4]); int drm_dp_downstream_max_bpc(const u8 dpcd[DP_RECEIVER_CAP_SIZE], @@ -1373,6 +1465,7 @@ int drm_dp_downstream_id(struct drm_dp_aux *aux, char id[6]); void drm_dp_downstream_debug(struct seq_file *m, const u8 dpcd[DP_RECEIVER_CAP_SIZE], const u8 port_cap[4], struct drm_dp_aux *aux); +void drm_dp_remote_aux_init(struct drm_dp_aux *aux); void drm_dp_aux_init(struct drm_dp_aux *aux); int drm_dp_aux_register(struct drm_dp_aux *aux); void drm_dp_aux_unregister(struct drm_dp_aux *aux); @@ -1430,6 +1523,13 @@ enum drm_dp_quirk { * The driver should ignore SINK_COUNT during detection. */ DP_DPCD_QUIRK_NO_SINK_COUNT, + /** + * @DP_DPCD_QUIRK_DSC_WITHOUT_VIRTUAL_DPCD: + * + * The device supports MST DSC despite not supporting Virtual DPCD. + * The DSC caps can be read from the physical aux instead. + */ + DP_DPCD_QUIRK_DSC_WITHOUT_VIRTUAL_DPCD, }; /** @@ -1447,8 +1547,8 @@ drm_dp_has_quirk(const struct drm_dp_desc *desc, enum drm_dp_quirk quirk) #ifdef CONFIG_DRM_DP_CEC void drm_dp_cec_irq(struct drm_dp_aux *aux); -void drm_dp_cec_register_connector(struct drm_dp_aux *aux, const char *name, - struct device *parent); +void drm_dp_cec_register_connector(struct drm_dp_aux *aux, + struct drm_connector *connector); void drm_dp_cec_unregister_connector(struct drm_dp_aux *aux); void drm_dp_cec_set_edid(struct drm_dp_aux *aux, const struct edid *edid); void drm_dp_cec_unset_edid(struct drm_dp_aux *aux); @@ -1457,9 +1557,9 @@ static inline void drm_dp_cec_irq(struct drm_dp_aux *aux) { } -static inline void drm_dp_cec_register_connector(struct drm_dp_aux *aux, - const char *name, - struct device *parent) +static inline void +drm_dp_cec_register_connector(struct drm_dp_aux *aux, + struct drm_connector *connector) { } diff --git a/include/drm/drm_dp_mst_helper.h b/include/drm/drm_dp_mst_helper.h index 8c97a5f92c47..bcb39da9adb4 100644 --- a/include/drm/drm_dp_mst_helper.h +++ b/include/drm/drm_dp_mst_helper.h @@ -26,6 +26,26 @@ #include <drm/drm_dp_helper.h> #include <drm/drm_atomic.h> +#if IS_ENABLED(CONFIG_DRM_DEBUG_DP_MST_TOPOLOGY_REFS) +#include <linux/stackdepot.h> +#include <linux/timekeeping.h> + +enum drm_dp_mst_topology_ref_type { + DRM_DP_MST_TOPOLOGY_REF_GET, + DRM_DP_MST_TOPOLOGY_REF_PUT, +}; + +struct drm_dp_mst_topology_ref_history { + struct drm_dp_mst_topology_ref_entry { + enum drm_dp_mst_topology_ref_type type; + int count; + ktime_t ts_nsec; + depot_stack_handle_t backtrace; + } *entries; + int len; +}; +#endif /* IS_ENABLED(CONFIG_DRM_DEBUG_DP_MST_TOPOLOGY_REFS) */ + struct drm_dp_mst_branch; /** @@ -45,21 +65,31 @@ struct drm_dp_vcpi { /** * struct drm_dp_mst_port - MST port * @port_num: port number - * @input: if this port is an input port. - * @mcs: message capability status - DP 1.2 spec. - * @ddps: DisplayPort Device Plug Status - DP 1.2 - * @pdt: Peer Device Type - * @ldps: Legacy Device Plug Status - * @dpcd_rev: DPCD revision of device on this port - * @num_sdp_streams: Number of simultaneous streams - * @num_sdp_stream_sinks: Number of stream sinks - * @available_pbn: Available bandwidth for this port. + * @input: if this port is an input port. Protected by + * &drm_dp_mst_topology_mgr.base.lock. + * @mcs: message capability status - DP 1.2 spec. Protected by + * &drm_dp_mst_topology_mgr.base.lock. + * @ddps: DisplayPort Device Plug Status - DP 1.2. Protected by + * &drm_dp_mst_topology_mgr.base.lock. + * @pdt: Peer Device Type. Protected by + * &drm_dp_mst_topology_mgr.base.lock. + * @ldps: Legacy Device Plug Status. Protected by + * &drm_dp_mst_topology_mgr.base.lock. + * @dpcd_rev: DPCD revision of device on this port. Protected by + * &drm_dp_mst_topology_mgr.base.lock. + * @num_sdp_streams: Number of simultaneous streams. Protected by + * &drm_dp_mst_topology_mgr.base.lock. + * @num_sdp_stream_sinks: Number of stream sinks. Protected by + * &drm_dp_mst_topology_mgr.base.lock. + * @available_pbn: Available bandwidth for this port. Protected by + * &drm_dp_mst_topology_mgr.base.lock. * @next: link to next port on this branch device - * @mstb: branch device attach below this port - * @aux: i2c aux transport to talk to device connected to this port. + * @aux: i2c aux transport to talk to device connected to this port, protected + * by &drm_dp_mst_topology_mgr.base.lock. * @parent: branch device parent of this port * @vcpi: Virtual Channel Payload info for this port. - * @connector: DRM connector this port is connected to. + * @connector: DRM connector this port is connected to. Protected by + * &drm_dp_mst_topology_mgr.base.lock. * @mgr: topology manager this port lives under. * * This structure represents an MST port endpoint on a device somewhere @@ -79,6 +109,14 @@ struct drm_dp_mst_port { */ struct kref malloc_kref; +#if IS_ENABLED(CONFIG_DRM_DEBUG_DP_MST_TOPOLOGY_REFS) + /** + * @topology_ref_history: A history of each topology + * reference/dereference. See CONFIG_DRM_DEBUG_DP_MST_TOPOLOGY_REFS. + */ + struct drm_dp_mst_topology_ref_history topology_ref_history; +#endif + u8 port_num; bool input; bool mcs; @@ -90,7 +128,17 @@ struct drm_dp_mst_port { u8 num_sdp_stream_sinks; uint16_t available_pbn; struct list_head next; - struct drm_dp_mst_branch *mstb; /* pointer to an mstb if this port has one */ + /** + * @mstb: the branch device connected to this port, if there is one. + * This should be considered protected for reading by + * &drm_dp_mst_topology_mgr.lock. There are two exceptions to this: + * &drm_dp_mst_topology_mgr.up_req_work and + * &drm_dp_mst_topology_mgr.work, which do not grab + * &drm_dp_mst_topology_mgr.lock during reads but are the only + * updaters of this list and are protected from writing concurrently + * by &drm_dp_mst_topology_mgr.probe_lock. + */ + struct drm_dp_mst_branch *mstb; struct drm_dp_aux aux; /* i2c bus for this port? */ struct drm_dp_mst_branch *parent; @@ -108,6 +156,8 @@ struct drm_dp_mst_port { * audio-capable. */ bool has_audio; + + bool fec_capable; }; /** @@ -116,7 +166,6 @@ struct drm_dp_mst_port { * @lct: Link count total to talk to this branch device. * @num_ports: number of ports on the branch. * @msg_slots: one bit per transmitted msg slot. - * @ports: linked list of ports on this branch. * @port_parent: pointer to the port parent, NULL if toplevel. * @mgr: topology manager for this branch device. * @tx_slots: transmission slots for this device. @@ -143,11 +192,35 @@ struct drm_dp_mst_branch { */ struct kref malloc_kref; +#if IS_ENABLED(CONFIG_DRM_DEBUG_DP_MST_TOPOLOGY_REFS) + /** + * @topology_ref_history: A history of each topology + * reference/dereference. See CONFIG_DRM_DEBUG_DP_MST_TOPOLOGY_REFS. + */ + struct drm_dp_mst_topology_ref_history topology_ref_history; +#endif + + /** + * @destroy_next: linked-list entry used by + * drm_dp_delayed_destroy_work() + */ + struct list_head destroy_next; + u8 rad[8]; u8 lct; int num_ports; int msg_slots; + /** + * @ports: the list of ports on this branch device. This should be + * considered protected for reading by &drm_dp_mst_topology_mgr.lock. + * There are two exceptions to this: + * &drm_dp_mst_topology_mgr.up_req_work and + * &drm_dp_mst_topology_mgr.work, which do not grab + * &drm_dp_mst_topology_mgr.lock during reads but are the only + * updaters of this list and are protected from updating the list + * concurrently by @drm_dp_mst_topology_mgr.probe_lock + */ struct list_head ports; /* list of tx ops queue for this port */ @@ -287,7 +360,7 @@ struct drm_dp_remote_dpcd_write { struct drm_dp_remote_i2c_read { u8 num_transactions; u8 port_number; - struct { + struct drm_dp_remote_i2c_read_tx { u8 i2c_dev_id; u8 num_bytes; u8 *bytes; @@ -312,6 +385,7 @@ struct drm_dp_port_number_req { struct drm_dp_enum_path_resources_ack_reply { u8 port_number; + bool fec_capable; u16 full_payload_bw_number; u16 avail_payload_bw_number; }; @@ -334,7 +408,7 @@ struct drm_dp_resource_status_notify { struct drm_dp_query_payload_ack_reply { u8 port_number; - u8 allocated_pbn; + u16 allocated_pbn; }; struct drm_dp_sideband_msg_req_body { @@ -428,6 +502,8 @@ struct drm_dp_payload { struct drm_dp_vcpi_allocation { struct drm_dp_mst_port *port; int vcpi; + int pbn; + bool dsc_enabled; struct list_head next; }; @@ -481,28 +557,39 @@ struct drm_dp_mst_topology_mgr { int conn_base_id; /** - * @down_rep_recv: Message receiver state for down replies. This and - * @up_req_recv are only ever access from the work item, which is - * serialised. + * @down_rep_recv: Message receiver state for down replies. */ struct drm_dp_sideband_msg_rx down_rep_recv; /** - * @up_req_recv: Message receiver state for up requests. This and - * @down_rep_recv are only ever access from the work item, which is - * serialised. + * @up_req_recv: Message receiver state for up requests. */ struct drm_dp_sideband_msg_rx up_req_recv; /** - * @lock: protects mst state, primary, dpcd. + * @lock: protects @mst_state, @mst_primary, @dpcd, and + * @payload_id_table_cleared. */ struct mutex lock; /** + * @probe_lock: Prevents @work and @up_req_work, the only writers of + * &drm_dp_mst_port.mstb and &drm_dp_mst_branch.ports, from racing + * while they update the topology. + */ + struct mutex probe_lock; + + /** * @mst_state: If this manager is enabled for an MST capable port. False * if no MST sink/branch devices is connected. */ - bool mst_state; + bool mst_state : 1; + + /** + * @payload_id_table_cleared: Whether or not we've cleared the payload + * ID table for @mst_primary. Protected by @lock. + */ + bool payload_id_table_cleared : 1; + /** * @mst_primary: Pointer to the primary/first branch device. */ @@ -531,6 +618,12 @@ struct drm_dp_mst_topology_mgr { * &drm_dp_sideband_msg_tx.state once they are queued */ struct mutex qlock; + + /** + * @is_waiting_for_dwn_reply: indicate whether is waiting for down reply + */ + bool is_waiting_for_dwn_reply; + /** * @tx_msg_downq: List of pending down replies. */ @@ -575,18 +668,49 @@ struct drm_dp_mst_topology_mgr { struct work_struct tx_work; /** - * @destroy_connector_list: List of to be destroyed connectors. + * @destroy_port_list: List of to be destroyed connectors. + */ + struct list_head destroy_port_list; + /** + * @destroy_branch_device_list: List of to be destroyed branch + * devices. + */ + struct list_head destroy_branch_device_list; + /** + * @delayed_destroy_lock: Protects @destroy_port_list and + * @destroy_branch_device_list. + */ + struct mutex delayed_destroy_lock; + /** + * @delayed_destroy_work: Work item to destroy MST port and branch + * devices, needed to avoid locking inversion. + */ + struct work_struct delayed_destroy_work; + + /** + * @up_req_list: List of pending up requests from the topology that + * need to be processed, in chronological order. */ - struct list_head destroy_connector_list; + struct list_head up_req_list; /** - * @destroy_connector_lock: Protects @connector_list. + * @up_req_lock: Protects @up_req_list */ - struct mutex destroy_connector_lock; + struct mutex up_req_lock; /** - * @destroy_connector_work: Work item to destroy connectors. Needed to - * avoid locking inversion. + * @up_req_work: Work item to process up requests received from the + * topology. Needed to avoid blocking hotplug handling and sideband + * transmissions. */ - struct work_struct destroy_connector_work; + struct work_struct up_req_work; + +#if IS_ENABLED(CONFIG_DRM_DEBUG_DP_MST_TOPOLOGY_REFS) + /** + * @topology_ref_history_lock: protects + * &drm_dp_mst_port.topology_ref_history and + * &drm_dp_mst_branch.topology_ref_history. + */ + struct mutex topology_ref_history_lock; +#endif }; int drm_dp_mst_topology_mgr_init(struct drm_dp_mst_topology_mgr *mgr, @@ -603,15 +727,18 @@ int drm_dp_mst_topology_mgr_set_mst(struct drm_dp_mst_topology_mgr *mgr, bool ms int drm_dp_mst_hpd_irq(struct drm_dp_mst_topology_mgr *mgr, u8 *esi, bool *handled); -enum drm_connector_status drm_dp_mst_detect_port(struct drm_connector *connector, struct drm_dp_mst_topology_mgr *mgr, struct drm_dp_mst_port *port); +int +drm_dp_mst_detect_port(struct drm_connector *connector, + struct drm_modeset_acquire_ctx *ctx, + struct drm_dp_mst_topology_mgr *mgr, + struct drm_dp_mst_port *port); bool drm_dp_mst_port_has_audio(struct drm_dp_mst_topology_mgr *mgr, struct drm_dp_mst_port *port); struct edid *drm_dp_mst_get_edid(struct drm_connector *connector, struct drm_dp_mst_topology_mgr *mgr, struct drm_dp_mst_port *port); -int drm_dp_calc_pbn_mode(int clock, int bpp); - +int drm_dp_calc_pbn_mode(int clock, int bpp, bool dsc); bool drm_dp_mst_allocate_vcpi(struct drm_dp_mst_topology_mgr *mgr, struct drm_dp_mst_port *port, int pbn, int slots); @@ -642,13 +769,33 @@ void drm_dp_mst_dump_topology(struct seq_file *m, void drm_dp_mst_topology_mgr_suspend(struct drm_dp_mst_topology_mgr *mgr); int __must_check -drm_dp_mst_topology_mgr_resume(struct drm_dp_mst_topology_mgr *mgr); +drm_dp_mst_topology_mgr_resume(struct drm_dp_mst_topology_mgr *mgr, + bool sync); + +ssize_t drm_dp_mst_dpcd_read(struct drm_dp_aux *aux, + unsigned int offset, void *buffer, size_t size); +ssize_t drm_dp_mst_dpcd_write(struct drm_dp_aux *aux, + unsigned int offset, void *buffer, size_t size); + +int drm_dp_mst_connector_late_register(struct drm_connector *connector, + struct drm_dp_mst_port *port); +void drm_dp_mst_connector_early_unregister(struct drm_connector *connector, + struct drm_dp_mst_port *port); + struct drm_dp_mst_topology_state *drm_atomic_get_mst_topology_state(struct drm_atomic_state *state, struct drm_dp_mst_topology_mgr *mgr); int __must_check drm_dp_atomic_find_vcpi_slots(struct drm_atomic_state *state, struct drm_dp_mst_topology_mgr *mgr, - struct drm_dp_mst_port *port, int pbn); + struct drm_dp_mst_port *port, int pbn, + int pbn_div); +int drm_dp_mst_atomic_enable_dsc(struct drm_atomic_state *state, + struct drm_dp_mst_port *port, + int pbn, int pbn_div, + bool enable); +int __must_check +drm_dp_mst_add_affected_dsc_crtcs(struct drm_atomic_state *state, + struct drm_dp_mst_topology_mgr *mgr); int __must_check drm_dp_atomic_release_vcpi_slots(struct drm_atomic_state *state, struct drm_dp_mst_topology_mgr *mgr, @@ -660,6 +807,8 @@ int __must_check drm_dp_mst_atomic_check(struct drm_atomic_state *state); void drm_dp_mst_get_port_malloc(struct drm_dp_mst_port *port); void drm_dp_mst_put_port_malloc(struct drm_dp_mst_port *port); +struct drm_dp_aux *drm_dp_mst_dsc_aux_for_port(struct drm_dp_mst_port *port); + extern const struct drm_private_state_funcs drm_dp_mst_topology_state_funcs; /** diff --git a/include/drm/drm_drv.h b/include/drm/drm_drv.h index 68ca736c548d..cf13470810a5 100644 --- a/include/drm/drm_drv.h +++ b/include/drm/drm_drv.h @@ -62,12 +62,6 @@ enum drm_driver_feature { */ DRIVER_MODESET = BIT(1), /** - * @DRIVER_PRIME: - * - * Driver implements DRM PRIME buffer sharing. - */ - DRIVER_PRIME = BIT(2), - /** * @DRIVER_RENDER: * * Driver supports dedicated render nodes. See also the :ref:`section on @@ -502,21 +496,25 @@ struct drm_driver { * @gem_free_object: deconstructor for drm_gem_objects * * This is deprecated and should not be used by new drivers. Use - * @gem_free_object_unlocked instead. + * &drm_gem_object_funcs.free instead. */ void (*gem_free_object) (struct drm_gem_object *obj); /** * @gem_free_object_unlocked: deconstructor for drm_gem_objects * - * This is for drivers which are not encumbered with &drm_device.struct_mutex - * legacy locking schemes. Use this hook instead of @gem_free_object. + * This is deprecated and should not be used by new drivers. Use + * &drm_gem_object_funcs.free instead. + * Compared to @gem_free_object this is not encumbered with + * &drm_device.struct_mutex legacy locking schemes. */ void (*gem_free_object_unlocked) (struct drm_gem_object *obj); /** * @gem_open_object: * + * This callback is deprecated in favour of &drm_gem_object_funcs.open. + * * Driver hook called upon gem handle creation */ int (*gem_open_object) (struct drm_gem_object *, struct drm_file *); @@ -524,6 +522,8 @@ struct drm_driver { /** * @gem_close_object: * + * This callback is deprecated in favour of &drm_gem_object_funcs.close. + * * Driver hook called upon gem handle release */ void (*gem_close_object) (struct drm_gem_object *, struct drm_file *); @@ -531,6 +531,9 @@ struct drm_driver { /** * @gem_print_info: * + * This callback is deprecated in favour of + * &drm_gem_object_funcs.print_info. + * * If driver subclasses struct &drm_gem_object, it can implement this * optional hook for printing additional driver specific info. * @@ -545,56 +548,108 @@ struct drm_driver { /** * @gem_create_object: constructor for gem objects * - * Hook for allocating the GEM object struct, for use by core - * helpers. + * Hook for allocating the GEM object struct, for use by the CMA and + * SHMEM GEM helpers. */ struct drm_gem_object *(*gem_create_object)(struct drm_device *dev, size_t size); - - /* prime: */ /** * @prime_handle_to_fd: * - * export handle -> fd (see drm_gem_prime_handle_to_fd() helper) + * Main PRIME export function. Should be implemented with + * drm_gem_prime_handle_to_fd() for GEM based drivers. + * + * For an in-depth discussion see :ref:`PRIME buffer sharing + * documentation <prime_buffer_sharing>`. */ int (*prime_handle_to_fd)(struct drm_device *dev, struct drm_file *file_priv, uint32_t handle, uint32_t flags, int *prime_fd); /** * @prime_fd_to_handle: * - * import fd -> handle (see drm_gem_prime_fd_to_handle() helper) + * Main PRIME import function. Should be implemented with + * drm_gem_prime_fd_to_handle() for GEM based drivers. + * + * For an in-depth discussion see :ref:`PRIME buffer sharing + * documentation <prime_buffer_sharing>`. */ int (*prime_fd_to_handle)(struct drm_device *dev, struct drm_file *file_priv, int prime_fd, uint32_t *handle); /** * @gem_prime_export: * - * export GEM -> dmabuf - * - * This defaults to drm_gem_prime_export() if not set. + * Export hook for GEM drivers. Deprecated in favour of + * &drm_gem_object_funcs.export. */ - struct dma_buf * (*gem_prime_export)(struct drm_device *dev, - struct drm_gem_object *obj, int flags); + struct dma_buf * (*gem_prime_export)(struct drm_gem_object *obj, + int flags); /** * @gem_prime_import: * - * import dmabuf -> GEM + * Import hook for GEM drivers. * * This defaults to drm_gem_prime_import() if not set. */ struct drm_gem_object * (*gem_prime_import)(struct drm_device *dev, struct dma_buf *dma_buf); + + /** + * @gem_prime_pin: + * + * Deprecated hook in favour of &drm_gem_object_funcs.pin. + */ int (*gem_prime_pin)(struct drm_gem_object *obj); + + /** + * @gem_prime_unpin: + * + * Deprecated hook in favour of &drm_gem_object_funcs.unpin. + */ void (*gem_prime_unpin)(struct drm_gem_object *obj); - struct reservation_object * (*gem_prime_res_obj)( - struct drm_gem_object *obj); + + + /** + * @gem_prime_get_sg_table: + * + * Deprecated hook in favour of &drm_gem_object_funcs.get_sg_table. + */ struct sg_table *(*gem_prime_get_sg_table)(struct drm_gem_object *obj); + + /** + * @gem_prime_import_sg_table: + * + * Optional hook used by the PRIME helper functions + * drm_gem_prime_import() respectively drm_gem_prime_import_dev(). + */ struct drm_gem_object *(*gem_prime_import_sg_table)( struct drm_device *dev, struct dma_buf_attachment *attach, struct sg_table *sgt); + /** + * @gem_prime_vmap: + * + * Deprecated vmap hook for GEM drivers. Please use + * &drm_gem_object_funcs.vmap instead. + */ void *(*gem_prime_vmap)(struct drm_gem_object *obj); + + /** + * @gem_prime_vunmap: + * + * Deprecated vunmap hook for GEM drivers. Please use + * &drm_gem_object_funcs.vunmap instead. + */ void (*gem_prime_vunmap)(struct drm_gem_object *obj, void *vaddr); + + /** + * @gem_prime_mmap: + * + * mmap hook for GEM drivers, used to implement dma-buf mmap in the + * PRIME helpers. + * + * FIXME: There's way too much duplication going on here, and also moved + * to &drm_gem_object_funcs. + */ int (*gem_prime_mmap)(struct drm_gem_object *obj, struct vm_area_struct *vma); @@ -662,6 +717,9 @@ struct drm_driver { /** * @gem_vm_ops: Driver private ops for this object + * + * For GEM drivers this is deprecated in favour of + * &drm_gem_object_funcs.vm_ops. */ const struct vm_operations_struct *gem_vm_ops; @@ -720,8 +778,6 @@ struct drm_driver { int dev_priv_size; }; -extern unsigned int drm_debug; - int drm_dev_init(struct drm_device *dev, struct drm_driver *driver, struct device *parent); diff --git a/include/drm/drm_edid.h b/include/drm/drm_edid.h index b9719418c3d2..f0b03d401c27 100644 --- a/include/drm/drm_edid.h +++ b/include/drm/drm_edid.h @@ -368,6 +368,10 @@ drm_hdmi_avi_infoframe_colorspace(struct hdmi_avi_infoframe *frame, const struct drm_connector_state *conn_state); void +drm_hdmi_avi_infoframe_bars(struct hdmi_avi_infoframe *frame, + const struct drm_connector_state *conn_state); + +void drm_hdmi_avi_infoframe_quant_range(struct hdmi_avi_infoframe *frame, struct drm_connector *connector, const struct drm_display_mode *mode, @@ -481,7 +485,6 @@ int drm_add_edid_modes(struct drm_connector *connector, struct edid *edid); int drm_add_override_edid_modes(struct drm_connector *connector); u8 drm_match_cea_mode(const struct drm_display_mode *to_match); -enum hdmi_picture_aspect drm_get_cea_aspect_ratio(const u8 video_code); bool drm_detect_hdmi_monitor(struct edid *edid); bool drm_detect_monitor_audio(struct edid *edid); enum hdmi_quantization_range diff --git a/include/drm/drm_encoder.h b/include/drm/drm_encoder.h index 70cfca03d812..5623994b6e9e 100644 --- a/include/drm/drm_encoder.h +++ b/include/drm/drm_encoder.h @@ -140,7 +140,7 @@ struct drm_encoder { * @possible_crtcs: Bitmask of potential CRTC bindings, using * drm_crtc_index() as the index into the bitfield. The driver must set * the bits for all &drm_crtc objects this encoder can be connected to - * before calling drm_encoder_init(). + * before calling drm_dev_register(). * * In reality almost every driver gets this wrong. * @@ -154,7 +154,7 @@ struct drm_encoder { * using drm_encoder_index() as the index into the bitfield. The driver * must set the bits for all &drm_encoder objects which can clone a * &drm_crtc together with this encoder before calling - * drm_encoder_init(). Drivers should set the bit representing the + * drm_dev_register(). Drivers should set the bit representing the * encoder itself, too. Cloning bits should be set such that when two * encoders can be used in a cloned configuration, they both should have * each another bits set. @@ -172,7 +172,12 @@ struct drm_encoder { * &drm_connector_state.crtc. */ struct drm_crtc *crtc; - struct drm_bridge *bridge; + + /** + * @bridge_chain: Bridges attached to this encoder. + */ + struct list_head bridge_chain; + const struct drm_encoder_funcs *funcs; const struct drm_encoder_helper_funcs *helper_private; }; @@ -198,7 +203,7 @@ static inline unsigned int drm_encoder_index(const struct drm_encoder *encoder) } /** - * drm_encoder_mask - find the mask of a registered ENCODER + * drm_encoder_mask - find the mask of a registered encoder * @encoder: encoder to find mask for * * Given a registered encoder, return the mask bit of that encoder for an diff --git a/include/drm/drm_fb_cma_helper.h b/include/drm/drm_fb_cma_helper.h index 4becb09975a4..795aea1d0a25 100644 --- a/include/drm/drm_fb_cma_helper.h +++ b/include/drm/drm_fb_cma_helper.h @@ -2,6 +2,8 @@ #ifndef __DRM_FB_CMA_HELPER_H__ #define __DRM_FB_CMA_HELPER_H__ +#include <linux/types.h> + struct drm_framebuffer; struct drm_plane_state; diff --git a/include/drm/drm_fb_helper.h b/include/drm/drm_fb_helper.h index c8a8ae2a678a..1c6633da0f91 100644 --- a/include/drm/drm_fb_helper.h +++ b/include/drm/drm_fb_helper.h @@ -231,11 +231,8 @@ void drm_fb_helper_fill_info(struct fb_info *info, struct drm_fb_helper *fb_helper, struct drm_fb_helper_surface_size *sizes); -void drm_fb_helper_unlink_fbi(struct drm_fb_helper *fb_helper); - void drm_fb_helper_deferred_io(struct fb_info *info, struct list_head *pagelist); -int drm_fb_helper_defio_init(struct drm_fb_helper *fb_helper); ssize_t drm_fb_helper_sys_read(struct fb_info *info, char __user *buf, size_t count, loff_t *ppos); @@ -270,18 +267,9 @@ int drm_fb_helper_initial_config(struct drm_fb_helper *fb_helper, int bpp_sel); int drm_fb_helper_debug_enter(struct fb_info *info); int drm_fb_helper_debug_leave(struct fb_info *info); -int drm_fb_helper_fbdev_setup(struct drm_device *dev, - struct drm_fb_helper *fb_helper, - const struct drm_fb_helper_funcs *funcs, - unsigned int preferred_bpp, - unsigned int max_conn_count); -void drm_fb_helper_fbdev_teardown(struct drm_device *dev); - void drm_fb_helper_lastclose(struct drm_device *dev); void drm_fb_helper_output_poll_changed(struct drm_device *dev); -int drm_fb_helper_generic_probe(struct drm_fb_helper *fb_helper, - struct drm_fb_helper_surface_size *sizes); int drm_fbdev_generic_setup(struct drm_device *dev, unsigned int preferred_bpp); #else static inline void drm_fb_helper_prepare(struct drm_device *dev, @@ -364,10 +352,6 @@ static inline int drm_fb_helper_ioctl(struct fb_info *info, unsigned int cmd, return 0; } -static inline void drm_fb_helper_unlink_fbi(struct drm_fb_helper *fb_helper) -{ -} - static inline void drm_fb_helper_deferred_io(struct fb_info *info, struct list_head *pagelist) { @@ -453,24 +437,6 @@ static inline int drm_fb_helper_debug_leave(struct fb_info *info) return 0; } -static inline int -drm_fb_helper_fbdev_setup(struct drm_device *dev, - struct drm_fb_helper *fb_helper, - const struct drm_fb_helper_funcs *funcs, - unsigned int preferred_bpp, - unsigned int max_conn_count) -{ - /* So drivers can use it to free the struct */ - dev->fb_helper = fb_helper; - - return 0; -} - -static inline void drm_fb_helper_fbdev_teardown(struct drm_device *dev) -{ - dev->fb_helper = NULL; -} - static inline void drm_fb_helper_lastclose(struct drm_device *dev) { } @@ -480,13 +446,6 @@ static inline void drm_fb_helper_output_poll_changed(struct drm_device *dev) } static inline int -drm_fb_helper_generic_probe(struct drm_fb_helper *fb_helper, - struct drm_fb_helper_surface_size *sizes) -{ - return 0; -} - -static inline int drm_fbdev_generic_setup(struct drm_device *dev, unsigned int preferred_bpp) { return 0; @@ -539,18 +498,16 @@ drm_fb_helper_remove_conflicting_framebuffers(struct apertures_struct *a, /** * drm_fb_helper_remove_conflicting_pci_framebuffers - remove firmware-configured framebuffers for PCI devices * @pdev: PCI device - * @resource_id: index of PCI BAR configuring framebuffer memory * @name: requesting driver name * * This function removes framebuffer devices (eg. initialized by firmware) - * using memory range configured for @pdev's BAR @resource_id. + * using memory range configured for any of @pdev's memory bars. * * The function assumes that PCI device with shadowed ROM drives a primary * display and so kicks out vga16fb. */ static inline int drm_fb_helper_remove_conflicting_pci_framebuffers(struct pci_dev *pdev, - int resource_id, const char *name) { int ret = 0; @@ -560,7 +517,7 @@ drm_fb_helper_remove_conflicting_pci_framebuffers(struct pci_dev *pdev, * otherwise the vga fbdev driver falls over. */ #if IS_REACHABLE(CONFIG_FB) - ret = remove_conflicting_pci_framebuffers(pdev, resource_id, name); + ret = remove_conflicting_pci_framebuffers(pdev, name); #endif if (ret == 0) ret = vga_remove_vgacon(pdev); diff --git a/include/drm/drm_file.h b/include/drm/drm_file.h index 67af60bb527a..8b099b347817 100644 --- a/include/drm/drm_file.h +++ b/include/drm/drm_file.h @@ -42,6 +42,7 @@ struct dma_fence; struct drm_file; struct drm_device; struct device; +struct file; /* * FIXME: Not sure we want to have drm_minor here in the end, but to avoid @@ -387,4 +388,6 @@ void drm_event_cancel_free(struct drm_device *dev, void drm_send_event_locked(struct drm_device *dev, struct drm_pending_event *e); void drm_send_event(struct drm_device *dev, struct drm_pending_event *e); +struct file *mock_drm_getfile(struct drm_minor *minor, unsigned int flags); + #endif /* _DRM_FILE_H_ */ diff --git a/include/drm/drm_fourcc.h b/include/drm/drm_fourcc.h index 306d1efeb5e0..156b122c0ad5 100644 --- a/include/drm/drm_fourcc.h +++ b/include/drm/drm_fourcc.h @@ -78,7 +78,7 @@ struct drm_format_info { * triplet @char_per_block, @block_w, @block_h for better * describing the pixel format. */ - u8 cpp[3]; + u8 cpp[4]; /** * @char_per_block: @@ -104,7 +104,7 @@ struct drm_format_info { * information from their drm_mode_config.get_format_info hook * if they want the core to be validating the pitch. */ - u8 char_per_block[3]; + u8 char_per_block[4]; }; /** @@ -113,7 +113,7 @@ struct drm_format_info { * Block width in pixels, this is intended to be accessed through * drm_format_info_block_width() */ - u8 block_w[3]; + u8 block_w[4]; /** * @block_h: @@ -121,7 +121,7 @@ struct drm_format_info { * Block height in pixels, this is intended to be accessed through * drm_format_info_block_height() */ - u8 block_h[3]; + u8 block_h[4]; /** @hsub: Horizontal chroma subsampling factor */ u8 hsub; diff --git a/include/drm/drm_gem.h b/include/drm/drm_gem.h index a9121fe66ea2..0b375069cd48 100644 --- a/include/drm/drm_gem.h +++ b/include/drm/drm_gem.h @@ -35,7 +35,7 @@ */ #include <linux/kref.h> -#include <linux/reservation.h> +#include <linux/dma-resv.h> #include <drm/drm_vma_manager.h> @@ -101,7 +101,7 @@ struct drm_gem_object_funcs { /** * @pin: * - * Pin backing buffer in memory. + * Pin backing buffer in memory. Used by the drm_gem_map_attach() helper. * * This callback is optional. */ @@ -110,7 +110,7 @@ struct drm_gem_object_funcs { /** * @unpin: * - * Unpin backing buffer. + * Unpin backing buffer. Used by the drm_gem_map_detach() helper. * * This callback is optional. */ @@ -120,16 +120,21 @@ struct drm_gem_object_funcs { * @get_sg_table: * * Returns a Scatter-Gather table representation of the buffer. - * Used when exporting a buffer. + * Used when exporting a buffer by the drm_gem_map_dma_buf() helper. + * Releasing is done by calling dma_unmap_sg_attrs() and sg_free_table() + * in drm_gem_unmap_buf(), therefore these helpers and this callback + * here cannot be used for sg tables pointing at driver private memory + * ranges. * - * This callback is mandatory if buffer export is supported. + * See also drm_prime_pages_to_sg(). */ struct sg_table *(*get_sg_table)(struct drm_gem_object *obj); /** * @vmap: * - * Returns a virtual address for the buffer. + * Returns a virtual address for the buffer. Used by the + * drm_gem_dmabuf_vmap() helper. * * This callback is optional. */ @@ -138,13 +143,27 @@ struct drm_gem_object_funcs { /** * @vunmap: * - * Releases the the address previously returned by @vmap. + * Releases the the address previously returned by @vmap. Used by the + * drm_gem_dmabuf_vunmap() helper. * * This callback is optional. */ void (*vunmap)(struct drm_gem_object *obj, void *vaddr); /** + * @mmap: + * + * Handle mmap() of the gem object, setup vma accordingly. + * + * This callback is optional. + * + * The callback is used by by both drm_gem_mmap_obj() and + * drm_gem_prime_mmap(). When @mmap is present @vm_ops is not + * used, the @mmap callback must set vma->vm_ops instead. + */ + int (*mmap)(struct drm_gem_object *obj, struct vm_area_struct *vma); + + /** * @vm_ops: * * Virtual memory operations used with mmap. @@ -270,7 +289,7 @@ struct drm_gem_object { * * Normally (@resv == &@_resv) except for imported GEM objects. */ - struct reservation_object *resv; + struct dma_resv *resv; /** * @_resv: @@ -279,7 +298,7 @@ struct drm_gem_object { * * This is unused for imported GEM objects. */ - struct reservation_object _resv; + struct dma_resv _resv; /** * @funcs: @@ -384,7 +403,7 @@ void drm_gem_put_pages(struct drm_gem_object *obj, struct page **pages, int drm_gem_objects_lookup(struct drm_file *filp, void __user *bo_handles, int count, struct drm_gem_object ***objs_out); struct drm_gem_object *drm_gem_object_lookup(struct drm_file *filp, u32 handle); -long drm_gem_reservation_object_wait(struct drm_file *filep, u32 handle, +long drm_gem_dma_resv_wait(struct drm_file *filep, u32 handle, bool wait_all, unsigned long timeout); int drm_gem_lock_reservations(struct drm_gem_object **objs, int count, struct ww_acquire_ctx *acquire_ctx); diff --git a/include/drm/drm_gem_framebuffer_helper.h b/include/drm/drm_gem_framebuffer_helper.h index 7f307e834eef..d9f13fd25b0a 100644 --- a/include/drm/drm_gem_framebuffer_helper.h +++ b/include/drm/drm_gem_framebuffer_helper.h @@ -33,11 +33,4 @@ int drm_gem_fb_prepare_fb(struct drm_plane *plane, struct drm_plane_state *state); int drm_gem_fb_simple_display_pipe_prepare_fb(struct drm_simple_display_pipe *pipe, struct drm_plane_state *plane_state); - -struct drm_framebuffer * -drm_gem_fbdev_fb_create(struct drm_device *dev, - struct drm_fb_helper_surface_size *sizes, - unsigned int pitch_align, struct drm_gem_object *obj, - const struct drm_framebuffer_funcs *funcs); - #endif diff --git a/include/drm/drm_gem_shmem_helper.h b/include/drm/drm_gem_shmem_helper.h index 038b6d313447..e34a7b7f848a 100644 --- a/include/drm/drm_gem_shmem_helper.h +++ b/include/drm/drm_gem_shmem_helper.h @@ -45,6 +45,22 @@ struct drm_gem_shmem_object { unsigned int pages_use_count; /** + * @madv: State for madvise + * + * 0 is active/inuse. + * A negative value is the object is purged. + * Positive values are driver specific and not used by the helpers. + */ + int madv; + + /** + * @madv_list: List entry for madvise tracking + * + * Typically used by drivers to track purgeable objects + */ + struct list_head madv_list; + + /** * @pages_mark_dirty_on_put: * * Mark pages as dirty when they are put. @@ -85,32 +101,6 @@ struct drm_gem_shmem_object { #define to_drm_gem_shmem_obj(obj) \ container_of(obj, struct drm_gem_shmem_object, base) -/** - * DEFINE_DRM_GEM_SHMEM_FOPS() - Macro to generate file operations for shmem drivers - * @name: name for the generated structure - * - * This macro autogenerates a suitable &struct file_operations for shmem based - * drivers, which can be assigned to &drm_driver.fops. Note that this structure - * cannot be shared between drivers, because it contains a reference to the - * current module using THIS_MODULE. - * - * Note that the declaration is already marked as static - if you need a - * non-static version of this you're probably doing it wrong and will break the - * THIS_MODULE reference by accident. - */ -#define DEFINE_DRM_GEM_SHMEM_FOPS(name) \ - static const struct file_operations name = {\ - .owner = THIS_MODULE,\ - .open = drm_open,\ - .release = drm_release,\ - .unlocked_ioctl = drm_ioctl,\ - .compat_ioctl = drm_compat_ioctl,\ - .poll = drm_poll,\ - .read = drm_read,\ - .llseek = noop_llseek,\ - .mmap = drm_gem_shmem_mmap, \ - } - struct drm_gem_shmem_object *drm_gem_shmem_create(struct drm_device *dev, size_t size); void drm_gem_shmem_free_object(struct drm_gem_object *obj); @@ -121,6 +111,18 @@ void drm_gem_shmem_unpin(struct drm_gem_object *obj); void *drm_gem_shmem_vmap(struct drm_gem_object *obj); void drm_gem_shmem_vunmap(struct drm_gem_object *obj, void *vaddr); +int drm_gem_shmem_madvise(struct drm_gem_object *obj, int madv); + +static inline bool drm_gem_shmem_is_purgeable(struct drm_gem_shmem_object *shmem) +{ + return (shmem->madv > 0) && + !shmem->vmap_use_count && shmem->sgt && + !shmem->base.dma_buf && !shmem->base.import_attach; +} + +void drm_gem_shmem_purge_locked(struct drm_gem_object *obj); +bool drm_gem_shmem_purge(struct drm_gem_object *obj); + struct drm_gem_shmem_object * drm_gem_shmem_create_with_handle(struct drm_file *file_priv, struct drm_device *dev, size_t size, @@ -128,9 +130,7 @@ drm_gem_shmem_create_with_handle(struct drm_file *file_priv, int drm_gem_shmem_dumb_create(struct drm_file *file, struct drm_device *dev, struct drm_mode_create_dumb *args); -int drm_gem_shmem_mmap(struct file *filp, struct vm_area_struct *vma); - -extern const struct vm_operations_struct drm_gem_shmem_vm_ops; +int drm_gem_shmem_mmap(struct drm_gem_object *obj, struct vm_area_struct *vma); void drm_gem_shmem_print_info(struct drm_printer *p, unsigned int indent, const struct drm_gem_object *obj); diff --git a/include/drm/drm_gem_ttm_helper.h b/include/drm/drm_gem_ttm_helper.h new file mode 100644 index 000000000000..118cef76f84f --- /dev/null +++ b/include/drm/drm_gem_ttm_helper.h @@ -0,0 +1,21 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#ifndef DRM_GEM_TTM_HELPER_H +#define DRM_GEM_TTM_HELPER_H + +#include <linux/kernel.h> + +#include <drm/drm_gem.h> +#include <drm/drm_device.h> +#include <drm/ttm/ttm_bo_api.h> +#include <drm/ttm/ttm_bo_driver.h> + +#define drm_gem_ttm_of_gem(gem_obj) \ + container_of(gem_obj, struct ttm_buffer_object, base) + +void drm_gem_ttm_print_info(struct drm_printer *p, unsigned int indent, + const struct drm_gem_object *gem); +int drm_gem_ttm_mmap(struct drm_gem_object *gem, + struct vm_area_struct *vma); + +#endif diff --git a/include/drm/drm_gem_vram_helper.h b/include/drm/drm_gem_vram_helper.h index 9581ea0a4f7e..573e9fd109bf 100644 --- a/include/drm/drm_gem_vram_helper.h +++ b/include/drm/drm_gem_vram_helper.h @@ -3,18 +3,25 @@ #ifndef DRM_GEM_VRAM_HELPER_H #define DRM_GEM_VRAM_HELPER_H +#include <drm/drm_file.h> #include <drm/drm_gem.h> +#include <drm/drm_ioctl.h> #include <drm/ttm/ttm_bo_api.h> +#include <drm/ttm/ttm_bo_driver.h> #include <drm/ttm/ttm_placement.h> + #include <linux/kernel.h> /* for container_of() */ struct drm_mode_create_dumb; -struct drm_vram_mm_funcs; +struct drm_plane; +struct drm_plane_state; +struct drm_simple_display_pipe; struct filp; struct vm_area_struct; #define DRM_GEM_VRAM_PL_FLAG_VRAM TTM_PL_FLAG_VRAM #define DRM_GEM_VRAM_PL_FLAG_SYSTEM TTM_PL_FLAG_SYSTEM +#define DRM_GEM_VRAM_PL_FLAG_TOPDOWN TTM_PL_FLAG_TOPDOWN /* * Buffer-object helpers @@ -34,12 +41,26 @@ struct vm_area_struct; * backed by VRAM. It can be used for simple framebuffer devices with * dedicated memory. The buffer object can be evicted to system memory if * video memory becomes scarce. + * + * GEM VRAM objects perform reference counting for pin and mapping + * operations. So a buffer object that has been pinned N times with + * drm_gem_vram_pin() must be unpinned N times with + * drm_gem_vram_unpin(). The same applies to pairs of + * drm_gem_vram_kmap() and drm_gem_vram_kunmap(), as well as pairs of + * drm_gem_vram_vmap() and drm_gem_vram_vunmap(). */ struct drm_gem_vram_object { - struct drm_gem_object gem; struct ttm_buffer_object bo; struct ttm_bo_kmap_obj kmap; + /** + * @kmap_use_count: + * + * Reference count on the virtual address. + * The address are un-mapped when the count reaches zero. + */ + unsigned int kmap_use_count; + /* Supported placements are %TTM_PL_VRAM and %TTM_PL_SYSTEM */ struct ttm_placement placement; struct ttm_place placements[2]; @@ -68,14 +89,12 @@ static inline struct drm_gem_vram_object *drm_gem_vram_of_bo( static inline struct drm_gem_vram_object *drm_gem_vram_of_gem( struct drm_gem_object *gem) { - return container_of(gem, struct drm_gem_vram_object, gem); + return container_of(gem, struct drm_gem_vram_object, bo.base); } struct drm_gem_vram_object *drm_gem_vram_create(struct drm_device *dev, - struct ttm_bo_device *bdev, size_t size, - unsigned long pg_align, - bool interruptible); + unsigned long pg_align); void drm_gem_vram_put(struct drm_gem_vram_object *gbo); u64 drm_gem_vram_mmap_offset(struct drm_gem_vram_object *gbo); s64 drm_gem_vram_offset(struct drm_gem_vram_object *gbo); @@ -84,31 +103,19 @@ int drm_gem_vram_unpin(struct drm_gem_vram_object *gbo); void *drm_gem_vram_kmap(struct drm_gem_vram_object *gbo, bool map, bool *is_iomem); void drm_gem_vram_kunmap(struct drm_gem_vram_object *gbo); +void *drm_gem_vram_vmap(struct drm_gem_vram_object *gbo); +void drm_gem_vram_vunmap(struct drm_gem_vram_object *gbo, void *vaddr); int drm_gem_vram_fill_create_dumb(struct drm_file *file, struct drm_device *dev, - struct ttm_bo_device *bdev, unsigned long pg_align, - bool interruptible, + unsigned long pitch_align, struct drm_mode_create_dumb *args); /* - * Helpers for struct ttm_bo_driver - */ - -void drm_gem_vram_bo_driver_evict_flags(struct ttm_buffer_object *bo, - struct ttm_placement *pl); - -int drm_gem_vram_bo_driver_verify_access(struct ttm_buffer_object *bo, - struct file *filp); - -extern const struct drm_vram_mm_funcs drm_gem_vram_mm_funcs; - -/* * Helpers for struct drm_driver */ -void drm_gem_vram_driver_gem_free_object_unlocked(struct drm_gem_object *gem); int drm_gem_vram_driver_dumb_create(struct drm_file *file, struct drm_device *dev, struct drm_mode_create_dumb *args); @@ -116,6 +123,28 @@ int drm_gem_vram_driver_dumb_mmap_offset(struct drm_file *file, struct drm_device *dev, uint32_t handle, uint64_t *offset); +/* + * Helpers for struct drm_plane_helper_funcs + */ +int +drm_gem_vram_plane_helper_prepare_fb(struct drm_plane *plane, + struct drm_plane_state *new_state); +void +drm_gem_vram_plane_helper_cleanup_fb(struct drm_plane *plane, + struct drm_plane_state *old_state); + +/* + * Helpers for struct drm_simple_display_pipe_funcs + */ + +int drm_gem_vram_simple_display_pipe_prepare_fb( + struct drm_simple_display_pipe *pipe, + struct drm_plane_state *new_state); + +void drm_gem_vram_simple_display_pipe_cleanup_fb( + struct drm_simple_display_pipe *pipe, + struct drm_plane_state *old_state); + /** * define DRM_GEM_VRAM_DRIVER - default callback functions for \ &struct drm_driver @@ -124,30 +153,56 @@ int drm_gem_vram_driver_dumb_mmap_offset(struct drm_file *file, * &struct drm_driver with default functions. */ #define DRM_GEM_VRAM_DRIVER \ - .gem_free_object_unlocked = \ - drm_gem_vram_driver_gem_free_object_unlocked, \ + .debugfs_init = drm_vram_mm_debugfs_init, \ .dumb_create = drm_gem_vram_driver_dumb_create, \ - .dumb_map_offset = drm_gem_vram_driver_dumb_mmap_offset + .dumb_map_offset = drm_gem_vram_driver_dumb_mmap_offset, \ + .gem_prime_mmap = drm_gem_prime_mmap + +/* + * VRAM memory manager + */ + +/** + * struct drm_vram_mm - An instance of VRAM MM + * @vram_base: Base address of the managed video memory + * @vram_size: Size of the managed video memory in bytes + * @bdev: The TTM BO device. + * @funcs: TTM BO functions + * + * The fields &struct drm_vram_mm.vram_base and + * &struct drm_vram_mm.vrm_size are managed by VRAM MM, but are + * available for public read access. Use the field + * &struct drm_vram_mm.bdev to access the TTM BO device. + */ +struct drm_vram_mm { + uint64_t vram_base; + size_t vram_size; + + struct ttm_bo_device bdev; +}; + +/** + * drm_vram_mm_of_bdev() - \ + Returns the container of type &struct ttm_bo_device for field bdev. + * @bdev: the TTM BO device + * + * Returns: + * The containing instance of &struct drm_vram_mm + */ +static inline struct drm_vram_mm *drm_vram_mm_of_bdev( + struct ttm_bo_device *bdev) +{ + return container_of(bdev, struct drm_vram_mm, bdev); +} + +int drm_vram_mm_debugfs_init(struct drm_minor *minor); /* - * PRIME helpers for struct drm_driver + * Helpers for integration with struct drm_device */ -int drm_gem_vram_driver_gem_prime_pin(struct drm_gem_object *obj); -void drm_gem_vram_driver_gem_prime_unpin(struct drm_gem_object *obj); -void *drm_gem_vram_driver_gem_prime_vmap(struct drm_gem_object *obj); -void drm_gem_vram_driver_gem_prime_vunmap(struct drm_gem_object *obj, - void *vaddr); -int drm_gem_vram_driver_gem_prime_mmap(struct drm_gem_object *obj, - struct vm_area_struct *vma); - -#define DRM_GEM_VRAM_DRIVER_PRIME \ - .gem_prime_export = drm_gem_prime_export, \ - .gem_prime_import = drm_gem_prime_import, \ - .gem_prime_pin = drm_gem_vram_driver_gem_prime_pin, \ - .gem_prime_unpin = drm_gem_vram_driver_gem_prime_unpin, \ - .gem_prime_vmap = drm_gem_vram_driver_gem_prime_vmap, \ - .gem_prime_vunmap = drm_gem_vram_driver_gem_prime_vunmap, \ - .gem_prime_mmap = drm_gem_vram_driver_gem_prime_mmap +struct drm_vram_mm *drm_vram_helper_alloc_mm( + struct drm_device *dev, uint64_t vram_base, size_t vram_size); +void drm_vram_helper_release_mm(struct drm_device *dev); #endif diff --git a/include/drm/drm_hdcp.h b/include/drm/drm_hdcp.h index 13771a496e2b..06a11202a097 100644 --- a/include/drm/drm_hdcp.h +++ b/include/drm/drm_hdcp.h @@ -291,5 +291,12 @@ struct drm_connector; bool drm_hdcp_check_ksvs_revoked(struct drm_device *dev, u8 *ksvs, u32 ksv_count); int drm_connector_attach_content_protection_property( - struct drm_connector *connector); + struct drm_connector *connector, bool hdcp_content_type); +void drm_hdcp_update_content_protection(struct drm_connector *connector, + u64 val); + +/* Content Type classification for HDCP2.2 vs others */ +#define DRM_MODE_HDCP_CONTENT_TYPE0 0 +#define DRM_MODE_HDCP_CONTENT_TYPE1 1 + #endif diff --git a/include/drm/drm_ioctl.h b/include/drm/drm_ioctl.h index fafb6f592c4b..10100a4bbe2a 100644 --- a/include/drm/drm_ioctl.h +++ b/include/drm/drm_ioctl.h @@ -114,6 +114,9 @@ enum drm_ioctl_flags { * Whether &drm_ioctl_desc.func should be called with the DRM BKL held * or not. Enforced as the default for all modern drivers, hence there * should never be a need to set this flag. + * + * Do not use anywhere else than for the VBLANK_WAIT IOCTL, which is the + * only legacy IOCTL which needs this. */ DRM_UNLOCKED = BIT(4), /** diff --git a/include/drm/drm_legacy.h b/include/drm/drm_legacy.h index 58dc0c04bf99..5745710453c8 100644 --- a/include/drm/drm_legacy.h +++ b/include/drm/drm_legacy.h @@ -38,7 +38,9 @@ #include <drm/drm_hashtab.h> struct drm_device; +struct drm_driver; struct file; +struct pci_driver; /* * Legacy Support for palateontologic DRM drivers @@ -188,8 +190,33 @@ do { \ void drm_legacy_idlelock_take(struct drm_lock_data *lock); void drm_legacy_idlelock_release(struct drm_lock_data *lock); -/* drm_pci.c dma alloc wrappers */ +/* drm_pci.c */ + +#ifdef CONFIG_PCI + void __drm_legacy_pci_free(struct drm_device *dev, drm_dma_handle_t * dmah); +int drm_legacy_pci_init(struct drm_driver *driver, struct pci_driver *pdriver); +void drm_legacy_pci_exit(struct drm_driver *driver, struct pci_driver *pdriver); + +#else + +static inline void __drm_legacy_pci_free(struct drm_device *dev, + drm_dma_handle_t *dmah) +{ +} + +static inline int drm_legacy_pci_init(struct drm_driver *driver, + struct pci_driver *pdriver) +{ + return -EINVAL; +} + +static inline void drm_legacy_pci_exit(struct drm_driver *driver, + struct pci_driver *pdriver) +{ +} + +#endif /* drm_memory.c */ void drm_legacy_ioremap(struct drm_local_map *map, struct drm_device *dev); diff --git a/include/drm/drm_mipi_dbi.h b/include/drm/drm_mipi_dbi.h new file mode 100644 index 000000000000..67c66f5ee591 --- /dev/null +++ b/include/drm/drm_mipi_dbi.h @@ -0,0 +1,188 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * MIPI Display Bus Interface (DBI) LCD controller support + * + * Copyright 2016 Noralf Trønnes + */ + +#ifndef __LINUX_MIPI_DBI_H +#define __LINUX_MIPI_DBI_H + +#include <linux/mutex.h> +#include <drm/drm_device.h> +#include <drm/drm_simple_kms_helper.h> + +struct drm_rect; +struct spi_device; +struct gpio_desc; +struct regulator; + +/** + * struct mipi_dbi - MIPI DBI interface + */ +struct mipi_dbi { + /** + * @cmdlock: Command lock + */ + struct mutex cmdlock; + + /** + * @command: Bus specific callback executing commands. + */ + int (*command)(struct mipi_dbi *dbi, u8 *cmd, u8 *param, size_t num); + + /** + * @read_commands: Array of read commands terminated by a zero entry. + * Reading is disabled if this is NULL. + */ + const u8 *read_commands; + + /** + * @swap_bytes: Swap bytes in buffer before transfer + */ + bool swap_bytes; + + /** + * @reset: Optional reset gpio + */ + struct gpio_desc *reset; + + /* Type C specific */ + + /** + * @spi: SPI device + */ + struct spi_device *spi; + + /** + * @dc: Optional D/C gpio. + */ + struct gpio_desc *dc; + + /** + * @tx_buf9: Buffer used for Option 1 9-bit conversion + */ + void *tx_buf9; + + /** + * @tx_buf9_len: Size of tx_buf9. + */ + size_t tx_buf9_len; +}; + +/** + * struct mipi_dbi_dev - MIPI DBI device + */ +struct mipi_dbi_dev { + /** + * @drm: DRM device + */ + struct drm_device drm; + + /** + * @pipe: Display pipe structure + */ + struct drm_simple_display_pipe pipe; + + /** + * @connector: Connector + */ + struct drm_connector connector; + + /** + * @mode: Fixed display mode + */ + struct drm_display_mode mode; + + /** + * @enabled: Pipeline is enabled + */ + bool enabled; + + /** + * @tx_buf: Buffer used for transfer (copy clip rect area) + */ + u16 *tx_buf; + + /** + * @rotation: initial rotation in degrees Counter Clock Wise + */ + unsigned int rotation; + + /** + * @backlight: backlight device (optional) + */ + struct backlight_device *backlight; + + /** + * @regulator: power regulator (optional) + */ + struct regulator *regulator; + + /** + * @dbi: MIPI DBI interface + */ + struct mipi_dbi dbi; +}; + +static inline struct mipi_dbi_dev *drm_to_mipi_dbi_dev(struct drm_device *drm) +{ + return container_of(drm, struct mipi_dbi_dev, drm); +} + +int mipi_dbi_spi_init(struct spi_device *spi, struct mipi_dbi *dbi, + struct gpio_desc *dc); +int mipi_dbi_dev_init_with_formats(struct mipi_dbi_dev *dbidev, + const struct drm_simple_display_pipe_funcs *funcs, + const uint32_t *formats, unsigned int format_count, + const struct drm_display_mode *mode, + unsigned int rotation, size_t tx_buf_size); +int mipi_dbi_dev_init(struct mipi_dbi_dev *dbidev, + const struct drm_simple_display_pipe_funcs *funcs, + const struct drm_display_mode *mode, unsigned int rotation); +void mipi_dbi_release(struct drm_device *drm); +void mipi_dbi_pipe_update(struct drm_simple_display_pipe *pipe, + struct drm_plane_state *old_state); +void mipi_dbi_enable_flush(struct mipi_dbi_dev *dbidev, + struct drm_crtc_state *crtc_state, + struct drm_plane_state *plan_state); +void mipi_dbi_pipe_disable(struct drm_simple_display_pipe *pipe); +void mipi_dbi_hw_reset(struct mipi_dbi *dbi); +bool mipi_dbi_display_is_on(struct mipi_dbi *dbi); +int mipi_dbi_poweron_reset(struct mipi_dbi_dev *dbidev); +int mipi_dbi_poweron_conditional_reset(struct mipi_dbi_dev *dbidev); + +u32 mipi_dbi_spi_cmd_max_speed(struct spi_device *spi, size_t len); +int mipi_dbi_spi_transfer(struct spi_device *spi, u32 speed_hz, + u8 bpw, const void *buf, size_t len); + +int mipi_dbi_command_read(struct mipi_dbi *dbi, u8 cmd, u8 *val); +int mipi_dbi_command_buf(struct mipi_dbi *dbi, u8 cmd, u8 *data, size_t len); +int mipi_dbi_command_stackbuf(struct mipi_dbi *dbi, u8 cmd, u8 *data, size_t len); +int mipi_dbi_buf_copy(void *dst, struct drm_framebuffer *fb, + struct drm_rect *clip, bool swap); +/** + * mipi_dbi_command - MIPI DCS command with optional parameter(s) + * @dbi: MIPI DBI structure + * @cmd: Command + * @seq...: Optional parameter(s) + * + * Send MIPI DCS command to the controller. Use mipi_dbi_command_read() for + * get/read. + * + * Returns: + * Zero on success, negative error code on failure. + */ +#define mipi_dbi_command(dbi, cmd, seq...) \ +({ \ + u8 d[] = { seq }; \ + mipi_dbi_command_stackbuf(dbi, cmd, d, ARRAY_SIZE(d)); \ +}) + +#ifdef CONFIG_DEBUG_FS +int mipi_dbi_debugfs_init(struct drm_minor *minor); +#else +#define mipi_dbi_debugfs_init NULL +#endif + +#endif /* __LINUX_MIPI_DBI_H */ diff --git a/include/drm/drm_mipi_dsi.h b/include/drm/drm_mipi_dsi.h index 13cf2ae59f6c..360e6377e84b 100644 --- a/include/drm/drm_mipi_dsi.h +++ b/include/drm/drm_mipi_dsi.h @@ -13,6 +13,7 @@ struct mipi_dsi_host; struct mipi_dsi_device; +struct drm_dsc_picture_parameter_set; /* request ACK from peripheral */ #define MIPI_DSI_MSG_REQ_ACK BIT(0) @@ -228,6 +229,9 @@ int mipi_dsi_shutdown_peripheral(struct mipi_dsi_device *dsi); int mipi_dsi_turn_on_peripheral(struct mipi_dsi_device *dsi); int mipi_dsi_set_maximum_return_packet_size(struct mipi_dsi_device *dsi, u16 value); +ssize_t mipi_dsi_compression_mode(struct mipi_dsi_device *dsi, bool enable); +ssize_t mipi_dsi_picture_parameter_set(struct mipi_dsi_device *dsi, + const struct drm_dsc_picture_parameter_set *pps); ssize_t mipi_dsi_generic_write(struct mipi_dsi_device *dsi, const void *payload, size_t size); diff --git a/include/drm/drm_mm.h b/include/drm/drm_mm.h index 2c3bbb43c7d1..d7939c054259 100644 --- a/include/drm/drm_mm.h +++ b/include/drm/drm_mm.h @@ -168,8 +168,9 @@ struct drm_mm_node { struct rb_node rb_hole_addr; u64 __subtree_last; u64 hole_size; - bool allocated : 1; - bool scanned_block : 1; + unsigned long flags; +#define DRM_MM_NODE_ALLOCATED_BIT 0 +#define DRM_MM_NODE_SCANNED_BIT 1 #ifdef CONFIG_DRM_DEBUG_MM depot_stack_handle_t stack; #endif @@ -253,7 +254,7 @@ struct drm_mm_scan { */ static inline bool drm_mm_node_allocated(const struct drm_mm_node *node) { - return node->allocated; + return test_bit(DRM_MM_NODE_ALLOCATED_BIT, &node->flags); } /** diff --git a/include/drm/drm_mode_config.h b/include/drm/drm_mode_config.h index f57eea0481e0..3bcbe30339f0 100644 --- a/include/drm/drm_mode_config.h +++ b/include/drm/drm_mode_config.h @@ -849,6 +849,12 @@ struct drm_mode_config { */ struct drm_property *content_protection_property; + /** + * @hdcp_content_type_property: DRM ENUM property for type of + * Protected Content. + */ + struct drm_property *hdcp_content_type_property; + /* dumb ioctl parameters */ uint32_t preferred_depth, prefer_shadow; diff --git a/include/drm/drm_modeset_helper_vtables.h b/include/drm/drm_modeset_helper_vtables.h index 6b18c8adfe9d..5a87f1bd7a3f 100644 --- a/include/drm/drm_modeset_helper_vtables.h +++ b/include/drm/drm_modeset_helper_vtables.h @@ -955,9 +955,8 @@ struct drm_connector_helper_funcs { * @atomic_best_encoder. * * You can leave this function to NULL if the connector is only - * attached to a single encoder and you are using the atomic helpers. - * In this case, the core will call drm_atomic_helper_best_encoder() - * for you. + * attached to a single encoder. In this case, the core will call + * drm_connector_get_single_encoder() for you. * * RETURNS: * @@ -977,7 +976,7 @@ struct drm_connector_helper_funcs { * * This function is used by drm_atomic_helper_check_modeset(). * If it is not implemented, the core will fallback to @best_encoder - * (or drm_atomic_helper_best_encoder() if @best_encoder is NULL). + * (or drm_connector_get_single_encoder() if @best_encoder is NULL). * * NOTE: * diff --git a/include/drm/drm_modeset_lock.h b/include/drm/drm_modeset_lock.h index 7b8841065b11..4fc9a43ac45a 100644 --- a/include/drm/drm_modeset_lock.h +++ b/include/drm/drm_modeset_lock.h @@ -114,6 +114,15 @@ static inline bool drm_modeset_is_locked(struct drm_modeset_lock *lock) return ww_mutex_is_locked(&lock->mutex); } +/** + * drm_modeset_lock_assert_held - equivalent to lockdep_assert_held() + * @lock: lock to check + */ +static inline void drm_modeset_lock_assert_held(struct drm_modeset_lock *lock) +{ + lockdep_assert_held(&lock->mutex.base); +} + int drm_modeset_lock(struct drm_modeset_lock *lock, struct drm_modeset_acquire_ctx *ctx); int __must_check drm_modeset_lock_single_interruptible(struct drm_modeset_lock *lock); diff --git a/include/drm/drm_of.h b/include/drm/drm_of.h index ead34ab5ca4e..b9b093add92e 100644 --- a/include/drm/drm_of.h +++ b/include/drm/drm_of.h @@ -16,6 +16,18 @@ struct drm_panel; struct drm_bridge; struct device_node; +/** + * enum drm_lvds_dual_link_pixels - Pixel order of an LVDS dual-link connection + * @DRM_LVDS_DUAL_LINK_EVEN_ODD_PIXELS: Even pixels are expected to be generated + * from the first port, odd pixels from the second port + * @DRM_LVDS_DUAL_LINK_ODD_EVEN_PIXELS: Odd pixels are expected to be generated + * from the first port, even pixels from the second port + */ +enum drm_lvds_dual_link_pixels { + DRM_LVDS_DUAL_LINK_EVEN_ODD_PIXELS = 0, + DRM_LVDS_DUAL_LINK_ODD_EVEN_PIXELS = 1, +}; + #ifdef CONFIG_OF uint32_t drm_of_crtc_port_mask(struct drm_device *dev, struct device_node *port); @@ -35,6 +47,8 @@ int drm_of_find_panel_or_bridge(const struct device_node *np, int port, int endpoint, struct drm_panel **panel, struct drm_bridge **bridge); +int drm_of_lvds_get_dual_link_pixel_order(const struct device_node *port1, + const struct device_node *port2); #else static inline uint32_t drm_of_crtc_port_mask(struct drm_device *dev, struct device_node *port) @@ -77,6 +91,13 @@ static inline int drm_of_find_panel_or_bridge(const struct device_node *np, { return -EINVAL; } + +static inline int +drm_of_lvds_get_dual_link_pixel_order(const struct device_node *port1, + const struct device_node *port2) +{ + return -EINVAL; +} #endif /* diff --git a/include/drm/drm_os_linux.h b/include/drm/drm_os_linux.h deleted file mode 100644 index ee8d61b64f29..000000000000 --- a/include/drm/drm_os_linux.h +++ /dev/null @@ -1,55 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/** - * \file drm_os_linux.h - * OS abstraction macros. - */ - -#include <linux/interrupt.h> /* For task queue support */ -#include <linux/sched/signal.h> -#include <linux/delay.h> -#include <linux/io-64-nonatomic-lo-hi.h> - -/** Current process ID */ -#define DRM_CURRENTPID task_pid_nr(current) -#define DRM_UDELAY(d) udelay(d) -/** Read a byte from a MMIO region */ -#define DRM_READ8(map, offset) readb(((void __iomem *)(map)->handle) + (offset)) -/** Read a word from a MMIO region */ -#define DRM_READ16(map, offset) readw(((void __iomem *)(map)->handle) + (offset)) -/** Read a dword from a MMIO region */ -#define DRM_READ32(map, offset) readl(((void __iomem *)(map)->handle) + (offset)) -/** Write a byte into a MMIO region */ -#define DRM_WRITE8(map, offset, val) writeb(val, ((void __iomem *)(map)->handle) + (offset)) -/** Write a word into a MMIO region */ -#define DRM_WRITE16(map, offset, val) writew(val, ((void __iomem *)(map)->handle) + (offset)) -/** Write a dword into a MMIO region */ -#define DRM_WRITE32(map, offset, val) writel(val, ((void __iomem *)(map)->handle) + (offset)) - -/** Read a qword from a MMIO region - be careful using these unless you really understand them */ -#define DRM_READ64(map, offset) readq(((void __iomem *)(map)->handle) + (offset)) -/** Write a qword into a MMIO region */ -#define DRM_WRITE64(map, offset, val) writeq(val, ((void __iomem *)(map)->handle) + (offset)) - -#define DRM_WAIT_ON( ret, queue, timeout, condition ) \ -do { \ - DECLARE_WAITQUEUE(entry, current); \ - unsigned long end = jiffies + (timeout); \ - add_wait_queue(&(queue), &entry); \ - \ - for (;;) { \ - __set_current_state(TASK_INTERRUPTIBLE); \ - if (condition) \ - break; \ - if (time_after_eq(jiffies, end)) { \ - ret = -EBUSY; \ - break; \ - } \ - schedule_timeout((HZ/100 > 1) ? HZ/100 : 1); \ - if (signal_pending(current)) { \ - ret = -EINTR; \ - break; \ - } \ - } \ - __set_current_state(TASK_RUNNING); \ - remove_wait_queue(&(queue), &entry); \ -} while (0) diff --git a/include/drm/drm_panel.h b/include/drm/drm_panel.h index 8c738c0e6e9f..121f7aabccd1 100644 --- a/include/drm/drm_panel.h +++ b/include/drm/drm_panel.h @@ -24,9 +24,11 @@ #ifndef __DRM_PANEL_H__ #define __DRM_PANEL_H__ +#include <linux/err.h> #include <linux/errno.h> #include <linux/list.h> +struct backlight_device; struct device_node; struct drm_connector; struct drm_device; @@ -35,14 +37,6 @@ struct display_timing; /** * struct drm_panel_funcs - perform operations on a given panel - * @disable: disable panel (turn off back light, etc.) - * @unprepare: turn off panel - * @prepare: turn on panel and perform set up - * @enable: enable panel (turn on back light, etc.) - * @get_modes: add modes to the connector that the panel is attached to and - * return the number of modes added - * @get_timings: copy display timings into the provided array and return - * the number of display timings available * * The .prepare() function is typically called before the display controller * starts to transmit video data. Panel drivers can use this to turn the panel @@ -66,134 +60,134 @@ struct display_timing; * * To save power when no video data is transmitted, a driver can power down * the panel. This is the job of the .unprepare() function. + * + * Backlight can be handled automatically if configured using + * drm_panel_of_backlight(). Then the driver does not need to implement the + * functionality to enable/disable backlight. */ struct drm_panel_funcs { - int (*disable)(struct drm_panel *panel); - int (*unprepare)(struct drm_panel *panel); + /** + * @prepare: + * + * Turn on panel and perform set up. + * + * This function is optional. + */ int (*prepare)(struct drm_panel *panel); + + /** + * @enable: + * + * Enable panel (turn on back light, etc.). + * + * This function is optional. + */ int (*enable)(struct drm_panel *panel); - int (*get_modes)(struct drm_panel *panel); + + /** + * @disable: + * + * Disable panel (turn off back light, etc.). + * + * This function is optional. + */ + int (*disable)(struct drm_panel *panel); + + /** + * @unprepare: + * + * Turn off panel. + * + * This function is optional. + */ + int (*unprepare)(struct drm_panel *panel); + + /** + * @get_modes: + * + * Add modes to the connector that the panel is attached to + * and returns the number of modes added. + * + * This function is mandatory. + */ + int (*get_modes)(struct drm_panel *panel, + struct drm_connector *connector); + + /** + * @get_timings: + * + * Copy display timings into the provided array and return + * the number of display timings available. + * + * This function is optional. + */ int (*get_timings)(struct drm_panel *panel, unsigned int num_timings, struct display_timing *timings); }; /** * struct drm_panel - DRM panel object - * @drm: DRM device owning the panel - * @connector: DRM connector that the panel is attached to - * @dev: parent device of the panel - * @link: link from panel device (supplier) to DRM device (consumer) - * @funcs: operations that can be performed on the panel - * @list: panel entry in registry */ struct drm_panel { - struct drm_device *drm; - struct drm_connector *connector; + /** + * @dev: + * + * Parent device of the panel. + */ struct device *dev; + /** + * @backlight: + * + * Backlight device, used to turn on backlight after the call + * to enable(), and to turn off backlight before the call to + * disable(). + * backlight is set by drm_panel_of_backlight() and drivers + * shall not assign it. + */ + struct backlight_device *backlight; + + /** + * @funcs: + * + * Operations that can be performed on the panel. + */ const struct drm_panel_funcs *funcs; + /** + * @connector_type: + * + * Type of the panel as a DRM_MODE_CONNECTOR_* value. This is used to + * initialise the drm_connector corresponding to the panel with the + * correct connector type. + */ + int connector_type; + + /** + * @list: + * + * Panel entry in registry. + */ struct list_head list; }; -/** - * drm_disable_unprepare - power off a panel - * @panel: DRM panel - * - * Calling this function will completely power off a panel (assert the panel's - * reset, turn off power supplies, ...). After this function has completed, it - * is usually no longer possible to communicate with the panel until another - * call to drm_panel_prepare(). - * - * Return: 0 on success or a negative error code on failure. - */ -static inline int drm_panel_unprepare(struct drm_panel *panel) -{ - if (panel && panel->funcs && panel->funcs->unprepare) - return panel->funcs->unprepare(panel); - - return panel ? -ENOSYS : -EINVAL; -} - -/** - * drm_panel_disable - disable a panel - * @panel: DRM panel - * - * This will typically turn off the panel's backlight or disable the display - * drivers. For smart panels it should still be possible to communicate with - * the integrated circuitry via any command bus after this call. - * - * Return: 0 on success or a negative error code on failure. - */ -static inline int drm_panel_disable(struct drm_panel *panel) -{ - if (panel && panel->funcs && panel->funcs->disable) - return panel->funcs->disable(panel); - - return panel ? -ENOSYS : -EINVAL; -} - -/** - * drm_panel_prepare - power on a panel - * @panel: DRM panel - * - * Calling this function will enable power and deassert any reset signals to - * the panel. After this has completed it is possible to communicate with any - * integrated circuitry via a command bus. - * - * Return: 0 on success or a negative error code on failure. - */ -static inline int drm_panel_prepare(struct drm_panel *panel) -{ - if (panel && panel->funcs && panel->funcs->prepare) - return panel->funcs->prepare(panel); - - return panel ? -ENOSYS : -EINVAL; -} - -/** - * drm_panel_enable - enable a panel - * @panel: DRM panel - * - * Calling this function will cause the panel display drivers to be turned on - * and the backlight to be enabled. Content will be visible on screen after - * this call completes. - * - * Return: 0 on success or a negative error code on failure. - */ -static inline int drm_panel_enable(struct drm_panel *panel) -{ - if (panel && panel->funcs && panel->funcs->enable) - return panel->funcs->enable(panel); - - return panel ? -ENOSYS : -EINVAL; -} - -/** - * drm_panel_get_modes - probe the available display modes of a panel - * @panel: DRM panel - * - * The modes probed from the panel are automatically added to the connector - * that the panel is attached to. - * - * Return: The number of modes available from the panel on success or a - * negative error code on failure. - */ -static inline int drm_panel_get_modes(struct drm_panel *panel) -{ - if (panel && panel->funcs && panel->funcs->get_modes) - return panel->funcs->get_modes(panel); - - return panel ? -ENOSYS : -EINVAL; -} - -void drm_panel_init(struct drm_panel *panel); +void drm_panel_init(struct drm_panel *panel, struct device *dev, + const struct drm_panel_funcs *funcs, + int connector_type); int drm_panel_add(struct drm_panel *panel); void drm_panel_remove(struct drm_panel *panel); int drm_panel_attach(struct drm_panel *panel, struct drm_connector *connector); -int drm_panel_detach(struct drm_panel *panel); +void drm_panel_detach(struct drm_panel *panel); + +int drm_panel_prepare(struct drm_panel *panel); +int drm_panel_unprepare(struct drm_panel *panel); + +int drm_panel_enable(struct drm_panel *panel); +int drm_panel_disable(struct drm_panel *panel); + +int drm_panel_get_modes(struct drm_panel *panel, struct drm_connector *connector); #if defined(CONFIG_OF) && defined(CONFIG_DRM_PANEL) struct drm_panel *of_drm_find_panel(const struct device_node *np); @@ -204,4 +198,13 @@ static inline struct drm_panel *of_drm_find_panel(const struct device_node *np) } #endif +#if IS_REACHABLE(CONFIG_BACKLIGHT_CLASS_DEVICE) +int drm_panel_of_backlight(struct drm_panel *panel); +#else +static inline int drm_panel_of_backlight(struct drm_panel *panel) +{ + return 0; +} +#endif + #endif diff --git a/include/drm/drm_pci.h b/include/drm/drm_pci.h index 8181e9e7cf1d..9031e217b506 100644 --- a/include/drm/drm_pci.h +++ b/include/drm/drm_pci.h @@ -39,23 +39,36 @@ struct drm_device; struct drm_driver; struct drm_master; +#ifdef CONFIG_PCI + struct drm_dma_handle *drm_pci_alloc(struct drm_device *dev, size_t size, size_t align); void drm_pci_free(struct drm_device *dev, struct drm_dma_handle * dmah); -int drm_legacy_pci_init(struct drm_driver *driver, struct pci_driver *pdriver); -void drm_legacy_pci_exit(struct drm_driver *driver, struct pci_driver *pdriver); -#ifdef CONFIG_PCI int drm_get_pci_dev(struct pci_dev *pdev, const struct pci_device_id *ent, struct drm_driver *driver); + #else + +static inline struct drm_dma_handle *drm_pci_alloc(struct drm_device *dev, + size_t size, size_t align) +{ + return NULL; +} + +static inline void drm_pci_free(struct drm_device *dev, + struct drm_dma_handle *dmah) +{ +} + static inline int drm_get_pci_dev(struct pci_dev *pdev, const struct pci_device_id *ent, struct drm_driver *driver) { return -ENOSYS; } + #endif #endif /* _DRM_PCI_H_ */ diff --git a/include/drm/drm_plane.h b/include/drm/drm_plane.h index cd5903ad33f7..3f396d94afe4 100644 --- a/include/drm/drm_plane.h +++ b/include/drm/drm_plane.h @@ -140,10 +140,11 @@ struct drm_plane_state { * @zpos: * Priority of the given plane on crtc (optional). * - * Note that multiple active planes on the same crtc can have an - * identical zpos value. The rule to solving the conflict is to compare - * the plane object IDs; the plane with a higher ID must be stacked on - * top of a plane with a lower ID. + * User-space may set mutable zpos properties so that multiple active + * planes on the same CRTC have identical zpos values. This is a + * user-space bug, but drivers can solve the conflict by comparing the + * plane object IDs; the plane with a higher ID is stacked on top of a + * plane with a lower ID. * * See drm_plane_create_zpos_property() and * drm_plane_create_zpos_immutable_property() for more details. @@ -183,8 +184,26 @@ struct drm_plane_state { */ struct drm_property_blob *fb_damage_clips; - /** @src: clipped source coordinates of the plane (in 16.16) */ - /** @dst: clipped destination coordinates of the plane */ + /** + * @src: + * + * source coordinates of the plane (in 16.16). + * + * When using drm_atomic_helper_check_plane_state(), + * the coordinates are clipped, but the driver may choose + * to use unclipped coordinates instead when the hardware + * performs the clipping automatically. + */ + /** + * @dst: + * + * clipped destination coordinates of the plane. + * + * When using drm_atomic_helper_check_plane_state(), + * the coordinates are clipped, but the driver may choose + * to use unclipped coordinates instead when the hardware + * performs the clipping automatically. + */ struct drm_rect src, dst; /** diff --git a/include/drm/drm_prime.h b/include/drm/drm_prime.h index b03731a3f079..9af7422b44cf 100644 --- a/include/drm/drm_prime.h +++ b/include/drm/drm_prime.h @@ -42,7 +42,6 @@ * This just contains the internal &struct dma_buf and handle caches for each * &struct drm_file used by the PRIME core code. */ - struct drm_prime_file_private { /* private: */ struct mutex lock; @@ -62,27 +61,18 @@ struct drm_device; struct drm_gem_object; struct drm_file; -struct device; +/* core prime functions */ +struct dma_buf *drm_gem_dmabuf_export(struct drm_device *dev, + struct dma_buf_export_info *exp_info); +void drm_gem_dmabuf_release(struct dma_buf *dma_buf); -struct dma_buf *drm_gem_prime_export(struct drm_device *dev, - struct drm_gem_object *obj, - int flags); +int drm_gem_prime_fd_to_handle(struct drm_device *dev, + struct drm_file *file_priv, int prime_fd, uint32_t *handle); int drm_gem_prime_handle_to_fd(struct drm_device *dev, struct drm_file *file_priv, uint32_t handle, uint32_t flags, int *prime_fd); -int drm_gem_prime_mmap(struct drm_gem_object *obj, struct vm_area_struct *vma); -struct drm_gem_object *drm_gem_prime_import(struct drm_device *dev, - struct dma_buf *dma_buf); -struct drm_gem_object *drm_gem_prime_import_dev(struct drm_device *dev, - struct dma_buf *dma_buf, - struct device *attach_dev); - -int drm_gem_prime_fd_to_handle(struct drm_device *dev, - struct drm_file *file_priv, int prime_fd, uint32_t *handle); -struct dma_buf *drm_gem_dmabuf_export(struct drm_device *dev, - struct dma_buf_export_info *exp_info); -void drm_gem_dmabuf_release(struct dma_buf *dma_buf); +/* helper functions for exporting */ int drm_gem_map_attach(struct dma_buf *dma_buf, struct dma_buf_attachment *attach); void drm_gem_map_detach(struct dma_buf *dma_buf, @@ -94,12 +84,25 @@ void drm_gem_unmap_dma_buf(struct dma_buf_attachment *attach, enum dma_data_direction dir); void *drm_gem_dmabuf_vmap(struct dma_buf *dma_buf); void drm_gem_dmabuf_vunmap(struct dma_buf *dma_buf, void *vaddr); + +int drm_gem_prime_mmap(struct drm_gem_object *obj, struct vm_area_struct *vma); int drm_gem_dmabuf_mmap(struct dma_buf *dma_buf, struct vm_area_struct *vma); -int drm_prime_sg_to_page_addr_arrays(struct sg_table *sgt, struct page **pages, - dma_addr_t *addrs, int max_pages); struct sg_table *drm_prime_pages_to_sg(struct page **pages, unsigned int nr_pages); +struct dma_buf *drm_gem_prime_export(struct drm_gem_object *obj, + int flags); + +/* helper functions for importing */ +struct drm_gem_object *drm_gem_prime_import_dev(struct drm_device *dev, + struct dma_buf *dma_buf, + struct device *attach_dev); +struct drm_gem_object *drm_gem_prime_import(struct drm_device *dev, + struct dma_buf *dma_buf); + void drm_prime_gem_destroy(struct drm_gem_object *obj, struct sg_table *sg); +int drm_prime_sg_to_page_addr_arrays(struct sg_table *sgt, struct page **pages, + dma_addr_t *addrs, int max_pages); + #endif /* __DRM_PRIME_H__ */ diff --git a/include/drm/drm_print.h b/include/drm/drm_print.h index a5d6f2f3e430..8f99d389792d 100644 --- a/include/drm/drm_print.h +++ b/include/drm/drm_print.h @@ -34,6 +34,9 @@ #include <drm/drm.h> +/* Do *not* use outside of drm_print.[ch]! */ +extern unsigned int __drm_debug; + /** * DOC: print * @@ -83,11 +86,14 @@ void __drm_printfn_seq_file(struct drm_printer *p, struct va_format *vaf); void __drm_puts_seq_file(struct drm_printer *p, const char *str); void __drm_printfn_info(struct drm_printer *p, struct va_format *vaf); void __drm_printfn_debug(struct drm_printer *p, struct va_format *vaf); +void __drm_printfn_err(struct drm_printer *p, struct va_format *vaf); __printf(2, 3) void drm_printf(struct drm_printer *p, const char *f, ...); void drm_puts(struct drm_printer *p, const char *str); void drm_print_regset32(struct drm_printer *p, struct debugfs_regset32 *regset); +void drm_print_bits(struct drm_printer *p, unsigned long value, + const char * const bits[], unsigned int nbits); __printf(2, 0) /** @@ -227,82 +233,106 @@ static inline struct drm_printer drm_debug_printer(const char *prefix) return p; } -/* - * The following categories are defined: +/** + * drm_err_printer - construct a &drm_printer that outputs to pr_err() + * @prefix: debug output prefix * - * CORE: Used in the generic drm code: drm_ioctl.c, drm_mm.c, drm_memory.c, ... - * This is the category used by the DRM_DEBUG() macro. + * RETURNS: + * The &drm_printer object + */ +static inline struct drm_printer drm_err_printer(const char *prefix) +{ + struct drm_printer p = { + .printfn = __drm_printfn_err, + .prefix = prefix + }; + return p; +} + +/** + * enum drm_debug_category - The DRM debug categories * - * DRIVER: Used in the vendor specific part of the driver: i915, radeon, ... - * This is the category used by the DRM_DEBUG_DRIVER() macro. + * Each of the DRM debug logging macros use a specific category, and the logging + * is filtered by the drm.debug module parameter. This enum specifies the values + * for the interface. * - * KMS: used in the modesetting code. - * This is the category used by the DRM_DEBUG_KMS() macro. + * Each DRM_DEBUG_<CATEGORY> macro logs to DRM_UT_<CATEGORY> category, except + * DRM_DEBUG() logs to DRM_UT_CORE. * - * PRIME: used in the prime code. - * This is the category used by the DRM_DEBUG_PRIME() macro. + * Enabling verbose debug messages is done through the drm.debug parameter, each + * category being enabled by a bit: * - * ATOMIC: used in the atomic code. - * This is the category used by the DRM_DEBUG_ATOMIC() macro. + * - drm.debug=0x1 will enable CORE messages + * - drm.debug=0x2 will enable DRIVER messages + * - drm.debug=0x3 will enable CORE and DRIVER messages + * - ... + * - drm.debug=0x1ff will enable all messages * - * VBL: used for verbose debug message in the vblank code - * This is the category used by the DRM_DEBUG_VBL() macro. + * An interesting feature is that it's possible to enable verbose logging at + * run-time by echoing the debug value in its sysfs node:: * - * Enabling verbose debug messages is done through the drm.debug parameter, - * each category being enabled by a bit. + * # echo 0xf > /sys/module/drm/parameters/debug * - * drm.debug=0x1 will enable CORE messages - * drm.debug=0x2 will enable DRIVER messages - * drm.debug=0x3 will enable CORE and DRIVER messages - * ... - * drm.debug=0x3f will enable all messages + */ +enum drm_debug_category { + /** + * @DRM_UT_CORE: Used in the generic drm code: drm_ioctl.c, drm_mm.c, + * drm_memory.c, ... + */ + DRM_UT_CORE = 0x01, + /** + * @DRM_UT_DRIVER: Used in the vendor specific part of the driver: i915, + * radeon, ... macro. + */ + DRM_UT_DRIVER = 0x02, + /** + * @DRM_UT_KMS: Used in the modesetting code. + */ + DRM_UT_KMS = 0x04, + /** + * @DRM_UT_PRIME: Used in the prime code. + */ + DRM_UT_PRIME = 0x08, + /** + * @DRM_UT_ATOMIC: Used in the atomic code. + */ + DRM_UT_ATOMIC = 0x10, + /** + * @DRM_UT_VBL: Used for verbose debug message in the vblank code. + */ + DRM_UT_VBL = 0x20, + /** + * @DRM_UT_STATE: Used for verbose atomic state debugging. + */ + DRM_UT_STATE = 0x40, + /** + * @DRM_UT_LEASE: Used in the lease code. + */ + DRM_UT_LEASE = 0x80, + /** + * @DRM_UT_DP: Used in the DP code. + */ + DRM_UT_DP = 0x100, +}; + +static inline bool drm_debug_enabled(enum drm_debug_category category) +{ + return unlikely(__drm_debug & category); +} + +/* + * struct device based logging * - * An interesting feature is that it's possible to enable verbose logging at - * run-time by echoing the debug value in its sysfs node: - * # echo 0xf > /sys/module/drm/parameters/debug + * Prefer drm_device based logging over device or prink based logging. */ -#define DRM_UT_NONE 0x00 -#define DRM_UT_CORE 0x01 -#define DRM_UT_DRIVER 0x02 -#define DRM_UT_KMS 0x04 -#define DRM_UT_PRIME 0x08 -#define DRM_UT_ATOMIC 0x10 -#define DRM_UT_VBL 0x20 -#define DRM_UT_STATE 0x40 -#define DRM_UT_LEASE 0x80 -#define DRM_UT_DP 0x100 __printf(3, 4) void drm_dev_printk(const struct device *dev, const char *level, const char *format, ...); __printf(3, 4) -void drm_dev_dbg(const struct device *dev, unsigned int category, +void drm_dev_dbg(const struct device *dev, enum drm_debug_category category, const char *format, ...); -__printf(2, 3) -void drm_dbg(unsigned int category, const char *format, ...); -__printf(1, 2) -void drm_err(const char *format, ...); - -/* Macros to make printk easier */ - -#define _DRM_PRINTK(once, level, fmt, ...) \ - printk##once(KERN_##level "[" DRM_NAME "] " fmt, ##__VA_ARGS__) - -#define DRM_INFO(fmt, ...) \ - _DRM_PRINTK(, INFO, fmt, ##__VA_ARGS__) -#define DRM_NOTE(fmt, ...) \ - _DRM_PRINTK(, NOTICE, fmt, ##__VA_ARGS__) -#define DRM_WARN(fmt, ...) \ - _DRM_PRINTK(, WARNING, fmt, ##__VA_ARGS__) - -#define DRM_INFO_ONCE(fmt, ...) \ - _DRM_PRINTK(_once, INFO, fmt, ##__VA_ARGS__) -#define DRM_NOTE_ONCE(fmt, ...) \ - _DRM_PRINTK(_once, NOTICE, fmt, ##__VA_ARGS__) -#define DRM_WARN_ONCE(fmt, ...) \ - _DRM_PRINTK(_once, WARNING, fmt, ##__VA_ARGS__) - /** * Error output. * @@ -311,8 +341,6 @@ void drm_err(const char *format, ...); */ #define DRM_DEV_ERROR(dev, fmt, ...) \ drm_dev_printk(dev, KERN_ERR, "*ERROR* " fmt, ##__VA_ARGS__) -#define DRM_ERROR(fmt, ...) \ - drm_err(fmt, ##__VA_ARGS__) /** * Rate limited error output. Like DRM_ERROR() but won't flood the log. @@ -329,10 +357,8 @@ void drm_err(const char *format, ...); if (__ratelimit(&_rs)) \ DRM_DEV_ERROR(dev, fmt, ##__VA_ARGS__); \ }) -#define DRM_ERROR_RATELIMITED(fmt, ...) \ - DRM_DEV_ERROR_RATELIMITED(NULL, fmt, ##__VA_ARGS__) -#define DRM_DEV_INFO(dev, fmt, ...) \ +#define DRM_DEV_INFO(dev, fmt, ...) \ drm_dev_printk(dev, KERN_INFO, fmt, ##__VA_ARGS__) #define DRM_DEV_INFO_ONCE(dev, fmt, ...) \ @@ -352,41 +378,18 @@ void drm_err(const char *format, ...); */ #define DRM_DEV_DEBUG(dev, fmt, ...) \ drm_dev_dbg(dev, DRM_UT_CORE, fmt, ##__VA_ARGS__) -#define DRM_DEBUG(fmt, ...) \ - drm_dbg(DRM_UT_CORE, fmt, ##__VA_ARGS__) - #define DRM_DEV_DEBUG_DRIVER(dev, fmt, ...) \ drm_dev_dbg(dev, DRM_UT_DRIVER, fmt, ##__VA_ARGS__) -#define DRM_DEBUG_DRIVER(fmt, ...) \ - drm_dbg(DRM_UT_DRIVER, fmt, ##__VA_ARGS__) - #define DRM_DEV_DEBUG_KMS(dev, fmt, ...) \ drm_dev_dbg(dev, DRM_UT_KMS, fmt, ##__VA_ARGS__) -#define DRM_DEBUG_KMS(fmt, ...) \ - drm_dbg(DRM_UT_KMS, fmt, ##__VA_ARGS__) - #define DRM_DEV_DEBUG_PRIME(dev, fmt, ...) \ drm_dev_dbg(dev, DRM_UT_PRIME, fmt, ##__VA_ARGS__) -#define DRM_DEBUG_PRIME(fmt, ...) \ - drm_dbg(DRM_UT_PRIME, fmt, ##__VA_ARGS__) - #define DRM_DEV_DEBUG_ATOMIC(dev, fmt, ...) \ drm_dev_dbg(dev, DRM_UT_ATOMIC, fmt, ##__VA_ARGS__) -#define DRM_DEBUG_ATOMIC(fmt, ...) \ - drm_dbg(DRM_UT_ATOMIC, fmt, ##__VA_ARGS__) - #define DRM_DEV_DEBUG_VBL(dev, fmt, ...) \ drm_dev_dbg(dev, DRM_UT_VBL, fmt, ##__VA_ARGS__) -#define DRM_DEBUG_VBL(fmt, ...) \ - drm_dbg(DRM_UT_VBL, fmt, ##__VA_ARGS__) - -#define DRM_DEBUG_LEASE(fmt, ...) \ - drm_dbg(DRM_UT_LEASE, fmt, ##__VA_ARGS__) - #define DRM_DEV_DEBUG_DP(dev, fmt, ...) \ drm_dev_dbg(dev, DRM_UT_DP, fmt, ## __VA_ARGS__) -#define DRM_DEBUG_DP(fmt, ...) \ - drm_dbg(DRM_UT_DP, fmt, ## __VA_ARGS__) #define _DRM_DEV_DEFINE_DEBUG_RATELIMITED(dev, category, fmt, ...) \ ({ \ @@ -406,24 +409,147 @@ void drm_err(const char *format, ...); #define DRM_DEV_DEBUG_RATELIMITED(dev, fmt, ...) \ _DEV_DRM_DEFINE_DEBUG_RATELIMITED(dev, DRM_UT_CORE, \ fmt, ##__VA_ARGS__) -#define DRM_DEBUG_RATELIMITED(fmt, ...) \ - DRM_DEV_DEBUG_RATELIMITED(NULL, fmt, ##__VA_ARGS__) - #define DRM_DEV_DEBUG_DRIVER_RATELIMITED(dev, fmt, ...) \ _DRM_DEV_DEFINE_DEBUG_RATELIMITED(dev, DRM_UT_DRIVER, \ fmt, ##__VA_ARGS__) -#define DRM_DEBUG_DRIVER_RATELIMITED(fmt, ...) \ - DRM_DEV_DEBUG_DRIVER_RATELIMITED(NULL, fmt, ##__VA_ARGS__) - #define DRM_DEV_DEBUG_KMS_RATELIMITED(dev, fmt, ...) \ _DRM_DEV_DEFINE_DEBUG_RATELIMITED(dev, DRM_UT_KMS, \ fmt, ##__VA_ARGS__) -#define DRM_DEBUG_KMS_RATELIMITED(fmt, ...) \ - DRM_DEV_DEBUG_KMS_RATELIMITED(NULL, fmt, ##__VA_ARGS__) - #define DRM_DEV_DEBUG_PRIME_RATELIMITED(dev, fmt, ...) \ _DRM_DEV_DEFINE_DEBUG_RATELIMITED(dev, DRM_UT_PRIME, \ fmt, ##__VA_ARGS__) + +/* + * struct drm_device based logging + * + * Prefer drm_device based logging over device or prink based logging. + */ + +/* Helper for struct drm_device based logging. */ +#define __drm_printk(drm, level, type, fmt, ...) \ + dev_##level##type((drm)->dev, "[drm] " fmt, ##__VA_ARGS__) + + +#define drm_info(drm, fmt, ...) \ + __drm_printk((drm), info,, fmt, ##__VA_ARGS__) + +#define drm_notice(drm, fmt, ...) \ + __drm_printk((drm), notice,, fmt, ##__VA_ARGS__) + +#define drm_warn(drm, fmt, ...) \ + __drm_printk((drm), warn,, fmt, ##__VA_ARGS__) + +#define drm_err(drm, fmt, ...) \ + __drm_printk((drm), err,, "*ERROR* " fmt, ##__VA_ARGS__) + + +#define drm_info_once(drm, fmt, ...) \ + __drm_printk((drm), info, _once, fmt, ##__VA_ARGS__) + +#define drm_notice_once(drm, fmt, ...) \ + __drm_printk((drm), notice, _once, fmt, ##__VA_ARGS__) + +#define drm_warn_once(drm, fmt, ...) \ + __drm_printk((drm), warn, _once, fmt, ##__VA_ARGS__) + +#define drm_err_once(drm, fmt, ...) \ + __drm_printk((drm), err, _once, "*ERROR* " fmt, ##__VA_ARGS__) + + +#define drm_err_ratelimited(drm, fmt, ...) \ + __drm_printk((drm), err, _ratelimited, "*ERROR* " fmt, ##__VA_ARGS__) + + +#define drm_dbg_core(drm, fmt, ...) \ + drm_dev_dbg((drm)->dev, DRM_UT_CORE, fmt, ##__VA_ARGS__) +#define drm_dbg(drm, fmt, ...) \ + drm_dev_dbg((drm)->dev, DRM_UT_DRIVER, fmt, ##__VA_ARGS__) +#define drm_dbg_kms(drm, fmt, ...) \ + drm_dev_dbg((drm)->dev, DRM_UT_KMS, fmt, ##__VA_ARGS__) +#define drm_dbg_prime(drm, fmt, ...) \ + drm_dev_dbg((drm)->dev, DRM_UT_PRIME, fmt, ##__VA_ARGS__) +#define drm_dbg_atomic(drm, fmt, ...) \ + drm_dev_dbg((drm)->dev, DRM_UT_ATOMIC, fmt, ##__VA_ARGS__) +#define drm_dbg_vbl(drm, fmt, ...) \ + drm_dev_dbg((drm)->dev, DRM_UT_VBL, fmt, ##__VA_ARGS__) +#define drm_dbg_state(drm, fmt, ...) \ + drm_dev_dbg((drm)->dev, DRM_UT_STATE, fmt, ##__VA_ARGS__) +#define drm_dbg_lease(drm, fmt, ...) \ + drm_dev_dbg((drm)->dev, DRM_UT_LEASE, fmt, ##__VA_ARGS__) +#define drm_dbg_dp(drm, fmt, ...) \ + drm_dev_dbg((drm)->dev, DRM_UT_DP, fmt, ##__VA_ARGS__) + + +/* + * printk based logging + * + * Prefer drm_device based logging over device or prink based logging. + */ + +__printf(2, 3) +void __drm_dbg(enum drm_debug_category category, const char *format, ...); +__printf(1, 2) +void __drm_err(const char *format, ...); + +/* Macros to make printk easier */ + +#define _DRM_PRINTK(once, level, fmt, ...) \ + printk##once(KERN_##level "[" DRM_NAME "] " fmt, ##__VA_ARGS__) + +#define DRM_INFO(fmt, ...) \ + _DRM_PRINTK(, INFO, fmt, ##__VA_ARGS__) +#define DRM_NOTE(fmt, ...) \ + _DRM_PRINTK(, NOTICE, fmt, ##__VA_ARGS__) +#define DRM_WARN(fmt, ...) \ + _DRM_PRINTK(, WARNING, fmt, ##__VA_ARGS__) + +#define DRM_INFO_ONCE(fmt, ...) \ + _DRM_PRINTK(_once, INFO, fmt, ##__VA_ARGS__) +#define DRM_NOTE_ONCE(fmt, ...) \ + _DRM_PRINTK(_once, NOTICE, fmt, ##__VA_ARGS__) +#define DRM_WARN_ONCE(fmt, ...) \ + _DRM_PRINTK(_once, WARNING, fmt, ##__VA_ARGS__) + +#define DRM_ERROR(fmt, ...) \ + __drm_err(fmt, ##__VA_ARGS__) + +#define DRM_ERROR_RATELIMITED(fmt, ...) \ + DRM_DEV_ERROR_RATELIMITED(NULL, fmt, ##__VA_ARGS__) + +#define DRM_DEBUG(fmt, ...) \ + __drm_dbg(DRM_UT_CORE, fmt, ##__VA_ARGS__) + +#define DRM_DEBUG_DRIVER(fmt, ...) \ + __drm_dbg(DRM_UT_DRIVER, fmt, ##__VA_ARGS__) + +#define DRM_DEBUG_KMS(fmt, ...) \ + __drm_dbg(DRM_UT_KMS, fmt, ##__VA_ARGS__) + +#define DRM_DEBUG_PRIME(fmt, ...) \ + __drm_dbg(DRM_UT_PRIME, fmt, ##__VA_ARGS__) + +#define DRM_DEBUG_ATOMIC(fmt, ...) \ + __drm_dbg(DRM_UT_ATOMIC, fmt, ##__VA_ARGS__) + +#define DRM_DEBUG_VBL(fmt, ...) \ + __drm_dbg(DRM_UT_VBL, fmt, ##__VA_ARGS__) + +#define DRM_DEBUG_LEASE(fmt, ...) \ + __drm_dbg(DRM_UT_LEASE, fmt, ##__VA_ARGS__) + +#define DRM_DEBUG_DP(fmt, ...) \ + __drm_dbg(DRM_UT_DP, fmt, ## __VA_ARGS__) + + +#define DRM_DEBUG_RATELIMITED(fmt, ...) \ + DRM_DEV_DEBUG_RATELIMITED(NULL, fmt, ##__VA_ARGS__) + +#define DRM_DEBUG_DRIVER_RATELIMITED(fmt, ...) \ + DRM_DEV_DEBUG_DRIVER_RATELIMITED(NULL, fmt, ##__VA_ARGS__) + +#define DRM_DEBUG_KMS_RATELIMITED(fmt, ...) \ + DRM_DEV_DEBUG_KMS_RATELIMITED(NULL, fmt, ##__VA_ARGS__) + #define DRM_DEBUG_PRIME_RATELIMITED(fmt, ...) \ DRM_DEV_DEBUG_PRIME_RATELIMITED(NULL, fmt, ##__VA_ARGS__) diff --git a/include/drm/drm_rect.h b/include/drm/drm_rect.h index 6195820aa5c5..57a3be9e53e4 100644 --- a/include/drm/drm_rect.h +++ b/include/drm/drm_rect.h @@ -24,6 +24,8 @@ #ifndef DRM_RECT_H #define DRM_RECT_H +#include <linux/types.h> + /** * DOC: rect utils * @@ -70,6 +72,23 @@ struct drm_rect { (r)->y1 >> 16, (((r)->y1 & 0xffff) * 15625) >> 10 /** + * drm_rect_init - initialize the rectangle from x/y/w/h + * @r: rectangle + * @x: x coordinate + * @y: y coordinate + * @width: width + * @height: height + */ +static inline void drm_rect_init(struct drm_rect *r, int x, int y, + int width, int height) +{ + r->x1 = x; + r->y1 = y; + r->x2 = x + width; + r->y2 = y + height; +} + +/** * drm_rect_adjust_size - adjust the size of the rectangle * @r: rectangle to be adjusted * @dw: horizontal adjustment @@ -107,6 +126,20 @@ static inline void drm_rect_translate(struct drm_rect *r, int dx, int dy) } /** + * drm_rect_translate_to - translate the rectangle to an absolute position + * @r: rectangle to be tranlated + * @x: horizontal position + * @y: vertical position + * + * Move rectangle @r to @x in the horizontal direction, + * and to @y in the vertical direction. + */ +static inline void drm_rect_translate_to(struct drm_rect *r, int x, int y) +{ + drm_rect_translate(r, x - r->x1, y - r->y1); +} + +/** * drm_rect_downscale - downscale a rectangle * @r: rectangle to be downscaled * @horz: horizontal downscale factor diff --git a/include/drm/drm_scdc_helper.h b/include/drm/drm_scdc_helper.h index f92eb2094d6b..6a483533aae4 100644 --- a/include/drm/drm_scdc_helper.h +++ b/include/drm/drm_scdc_helper.h @@ -50,9 +50,9 @@ #define SCDC_READ_REQUEST_ENABLE (1 << 0) #define SCDC_STATUS_FLAGS_0 0x40 -#define SCDC_CH2_LOCK (1 < 3) -#define SCDC_CH1_LOCK (1 < 2) -#define SCDC_CH0_LOCK (1 < 1) +#define SCDC_CH2_LOCK (1 << 3) +#define SCDC_CH1_LOCK (1 << 2) +#define SCDC_CH0_LOCK (1 << 1) #define SCDC_CH_LOCK_MASK (SCDC_CH2_LOCK | SCDC_CH1_LOCK | SCDC_CH0_LOCK) #define SCDC_CLOCK_DETECT (1 << 0) diff --git a/include/drm/drm_self_refresh_helper.h b/include/drm/drm_self_refresh_helper.h index 397a583ccca7..520235c20708 100644 --- a/include/drm/drm_self_refresh_helper.h +++ b/include/drm/drm_self_refresh_helper.h @@ -12,9 +12,10 @@ struct drm_atomic_state; struct drm_crtc; void drm_self_refresh_helper_alter_state(struct drm_atomic_state *state); +void drm_self_refresh_helper_update_avg_times(struct drm_atomic_state *state, + unsigned int commit_time_ms, + unsigned int new_self_refresh_mask); -int drm_self_refresh_helper_init(struct drm_crtc *crtc, - unsigned int entry_delay_ms); - +int drm_self_refresh_helper_init(struct drm_crtc *crtc); void drm_self_refresh_helper_cleanup(struct drm_crtc *crtc); #endif diff --git a/include/drm/drm_simple_kms_helper.h b/include/drm/drm_simple_kms_helper.h index 4d89cd0a60db..15afee9cf049 100644 --- a/include/drm/drm_simple_kms_helper.h +++ b/include/drm/drm_simple_kms_helper.h @@ -49,7 +49,7 @@ struct drm_simple_display_pipe_funcs { * * drm_mode_status Enum */ - enum drm_mode_status (*mode_valid)(struct drm_crtc *crtc, + enum drm_mode_status (*mode_valid)(struct drm_simple_display_pipe *pipe, const struct drm_display_mode *mode); /** diff --git a/include/drm/drm_sysfs.h b/include/drm/drm_sysfs.h index 4f311e836cdc..d454ef617b2c 100644 --- a/include/drm/drm_sysfs.h +++ b/include/drm/drm_sysfs.h @@ -4,10 +4,13 @@ struct drm_device; struct device; +struct drm_connector; +struct drm_property; int drm_class_device_register(struct device *dev); void drm_class_device_unregister(struct device *dev); void drm_sysfs_hotplug_event(struct drm_device *dev); - +void drm_sysfs_connector_status_event(struct drm_connector *connector, + struct drm_property *property); #endif diff --git a/include/drm/drm_util.h b/include/drm/drm_util.h index 07b8e9f04599..79952d8c4bba 100644 --- a/include/drm/drm_util.h +++ b/include/drm/drm_util.h @@ -41,7 +41,7 @@ * Use EXPORT_SYMBOL_FOR_TESTS_ONLY() for functions that shall * only be visible for drmselftests. */ -#if defined(CONFIG_DRM_DEBUG_SELFTEST_MODULE) +#if defined(CONFIG_DRM_EXPORT_FOR_TESTS) #define EXPORT_SYMBOL_FOR_TESTS_ONLY(x) EXPORT_SYMBOL(x) #else #define EXPORT_SYMBOL_FOR_TESTS_ONLY(x) diff --git a/include/drm/drm_vblank.h b/include/drm/drm_vblank.h index e528bb2f659d..c16c44052b3d 100644 --- a/include/drm/drm_vblank.h +++ b/include/drm/drm_vblank.h @@ -30,7 +30,6 @@ #include <drm/drm_file.h> #include <drm/drm_modes.h> -#include <uapi/drm/drm.h> struct drm_device; struct drm_crtc; @@ -110,9 +109,20 @@ struct drm_vblank_crtc { seqlock_t seqlock; /** - * @count: Current software vblank counter. + * @count: + * + * Current software vblank counter. + * + * Note that for a given vblank counter value drm_crtc_handle_vblank() + * and drm_crtc_vblank_count() or drm_crtc_vblank_count_and_time() + * provide a barrier: Any writes done before calling + * drm_crtc_handle_vblank() will be visible to callers of the later + * functions, iff the vblank count is the same or a later one. + * + * IMPORTANT: This guarantee requires barriers, therefor never access + * this field directly. Use drm_crtc_vblank_count() instead. */ - u64 count; + atomic64_t count; /** * @time: Vblank timestamp corresponding to @count. */ diff --git a/include/drm/drm_vram_mm_helper.h b/include/drm/drm_vram_mm_helper.h deleted file mode 100644 index a8ffd8599b08..000000000000 --- a/include/drm/drm_vram_mm_helper.h +++ /dev/null @@ -1,102 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ - -#ifndef DRM_VRAM_MM_HELPER_H -#define DRM_VRAM_MM_HELPER_H - -#include <drm/ttm/ttm_bo_driver.h> - -struct drm_device; - -/** - * struct drm_vram_mm_funcs - Callback functions for &struct drm_vram_mm - * @evict_flags: Provides an implementation for struct \ - &ttm_bo_driver.evict_flags - * @verify_access: Provides an implementation for \ - struct &ttm_bo_driver.verify_access - * - * These callback function integrate VRAM MM with TTM buffer objects. New - * functions can be added if necessary. - */ -struct drm_vram_mm_funcs { - void (*evict_flags)(struct ttm_buffer_object *bo, - struct ttm_placement *placement); - int (*verify_access)(struct ttm_buffer_object *bo, struct file *filp); -}; - -/** - * struct drm_vram_mm - An instance of VRAM MM - * @vram_base: Base address of the managed video memory - * @vram_size: Size of the managed video memory in bytes - * @bdev: The TTM BO device. - * @funcs: TTM BO functions - * - * The fields &struct drm_vram_mm.vram_base and - * &struct drm_vram_mm.vrm_size are managed by VRAM MM, but are - * available for public read access. Use the field - * &struct drm_vram_mm.bdev to access the TTM BO device. - */ -struct drm_vram_mm { - uint64_t vram_base; - size_t vram_size; - - struct ttm_bo_device bdev; - - const struct drm_vram_mm_funcs *funcs; -}; - -/** - * drm_vram_mm_of_bdev() - \ - Returns the container of type &struct ttm_bo_device for field bdev. - * @bdev: the TTM BO device - * - * Returns: - * The containing instance of &struct drm_vram_mm - */ -static inline struct drm_vram_mm *drm_vram_mm_of_bdev( - struct ttm_bo_device *bdev) -{ - return container_of(bdev, struct drm_vram_mm, bdev); -} - -int drm_vram_mm_init(struct drm_vram_mm *vmm, struct drm_device *dev, - uint64_t vram_base, size_t vram_size, - const struct drm_vram_mm_funcs *funcs); -void drm_vram_mm_cleanup(struct drm_vram_mm *vmm); - -int drm_vram_mm_mmap(struct file *filp, struct vm_area_struct *vma, - struct drm_vram_mm *vmm); - -/* - * Helpers for integration with struct drm_device - */ - -struct drm_vram_mm *drm_vram_helper_alloc_mm( - struct drm_device *dev, uint64_t vram_base, size_t vram_size, - const struct drm_vram_mm_funcs *funcs); -void drm_vram_helper_release_mm(struct drm_device *dev); - -/* - * Helpers for &struct file_operations - */ - -int drm_vram_mm_file_operations_mmap( - struct file *filp, struct vm_area_struct *vma); - -/** - * define DRM_VRAM_MM_FILE_OPERATIONS - default callback functions for \ - &struct file_operations - * - * Drivers that use VRAM MM can use this macro to initialize - * &struct file_operations with default functions. - */ -#define DRM_VRAM_MM_FILE_OPERATIONS \ - .llseek = no_llseek, \ - .read = drm_read, \ - .poll = drm_poll, \ - .unlocked_ioctl = drm_ioctl, \ - .compat_ioctl = drm_compat_ioctl, \ - .mmap = drm_vram_mm_file_operations_mmap, \ - .open = drm_open, \ - .release = drm_release \ - -#endif diff --git a/include/drm/gpu_scheduler.h b/include/drm/gpu_scheduler.h index 57b4121c750a..589be851f8a1 100644 --- a/include/drm/gpu_scheduler.h +++ b/include/drm/gpu_scheduler.h @@ -26,6 +26,7 @@ #include <drm/spsc_queue.h> #include <linux/dma-fence.h> +#include <linux/completion.h> #define MAX_WAIT_SCHED_ENTITY_Q_EMPTY msecs_to_jiffies(1000) @@ -51,9 +52,10 @@ enum drm_sched_priority { * @list: used to append this struct to the list of entities in the * runqueue. * @rq: runqueue on which this entity is currently scheduled. - * @rq_list: a list of run queues on which jobs from this entity can - * be scheduled - * @num_rq_list: number of run queues in the rq_list + * @sched_list: A list of schedulers (drm_gpu_schedulers). + * Jobs from this entity can be scheduled on any scheduler + * on this list. + * @num_sched_list: number of drm_gpu_schedulers in the sched_list. * @rq_lock: lock to modify the runqueue to which this entity belongs. * @job_queue: the list of jobs of this entity. * @fence_seq: a linearly increasing seqno incremented with each @@ -71,6 +73,7 @@ enum drm_sched_priority { * @last_scheduled: points to the finished fence of the last scheduled job. * @last_user: last group leader pushing a job into the entity. * @stopped: Marks the enity as removed from rq and destined for termination. + * @entity_idle: Signals when enityt is not in use * * Entities will emit jobs in order to their corresponding hardware * ring, and the scheduler will alternate between entities based on @@ -79,8 +82,9 @@ enum drm_sched_priority { struct drm_sched_entity { struct list_head list; struct drm_sched_rq *rq; - struct drm_sched_rq **rq_list; - unsigned int num_rq_list; + struct drm_gpu_scheduler **sched_list; + unsigned int num_sched_list; + enum drm_sched_priority priority; spinlock_t rq_lock; struct spsc_queue job_queue; @@ -94,6 +98,7 @@ struct drm_sched_entity { struct dma_fence *last_scheduled; struct task_struct *last_user; bool stopped; + struct completion entity_idle; }; /** @@ -257,7 +262,7 @@ struct drm_sched_backend_ops { * @job_list_lock: lock to protect the ring_mirror_list. * @hang_limit: once the hangs by a job crosses this limit then it is marked * guilty and it will be considered for scheduling further. - * @num_jobs: the number of jobs in queue in the scheduler + * @score: score to help loadbalancer pick a idle sched * @ready: marks if the underlying HW is ready to work * @free_guilty: A hit to time out handler to free the guilty job. * @@ -278,8 +283,8 @@ struct drm_gpu_scheduler { struct list_head ring_mirror_list; spinlock_t job_list_lock; int hang_limit; - atomic_t num_jobs; - bool ready; + atomic_t score; + bool ready; bool free_guilty; }; @@ -309,8 +314,9 @@ void drm_sched_rq_remove_entity(struct drm_sched_rq *rq, struct drm_sched_entity *entity); int drm_sched_entity_init(struct drm_sched_entity *entity, - struct drm_sched_rq **rq_list, - unsigned int num_rq_list, + enum drm_sched_priority priority, + struct drm_gpu_scheduler **sched_list, + unsigned int num_sched_list, atomic_t *guilty); long drm_sched_entity_flush(struct drm_sched_entity *entity, long timeout); void drm_sched_entity_fini(struct drm_sched_entity *entity); diff --git a/include/drm/i915_component.h b/include/drm/i915_component.h index dcb95bd9dee6..55c3b123581b 100644 --- a/include/drm/i915_component.h +++ b/include/drm/i915_component.h @@ -34,7 +34,7 @@ enum i915_component_type { /* MAX_PORT is the number of port * It must be sync with I915_MAX_PORTS defined i915_drv.h */ -#define MAX_PORTS 6 +#define MAX_PORTS 9 /** * struct i915_audio_component - Used for direct communication between i915 and hda drivers diff --git a/include/drm/i915_drm.h b/include/drm/i915_drm.h index 7523e9a7b6e2..6722005884db 100644 --- a/include/drm/i915_drm.h +++ b/include/drm/i915_drm.h @@ -30,11 +30,11 @@ #include <uapi/drm/i915_drm.h> /* For use by IPS driver */ -extern unsigned long i915_read_mch_val(void); -extern bool i915_gpu_raise(void); -extern bool i915_gpu_lower(void); -extern bool i915_gpu_busy(void); -extern bool i915_gpu_turbo_disable(void); +unsigned long i915_read_mch_val(void); +bool i915_gpu_raise(void); +bool i915_gpu_lower(void); +bool i915_gpu_busy(void); +bool i915_gpu_turbo_disable(void); /* Exported from arch/x86/kernel/early-quirks.c */ extern struct resource intel_graphics_stolen_res; @@ -100,19 +100,4 @@ extern struct resource intel_graphics_stolen_res; #define INTEL_GEN11_BSM_DW1 0xc4 #define INTEL_BSM_MASK (-(1u << 20)) -enum port { - PORT_NONE = -1, - - PORT_A = 0, - PORT_B, - PORT_C, - PORT_D, - PORT_E, - PORT_F, - - I915_MAX_PORTS -}; - -#define port_name(p) ((p) + 'A') - #endif /* _I915_DRM_H_ */ diff --git a/include/drm/i915_mei_hdcp_interface.h b/include/drm/i915_mei_hdcp_interface.h index 8c344255146a..4d48de8890ca 100644 --- a/include/drm/i915_mei_hdcp_interface.h +++ b/include/drm/i915_mei_hdcp_interface.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: (GPL-2.0+) */ /* - * Copyright © 2017-2018 Intel Corporation + * Copyright © 2017-2019 Intel Corporation * * Authors: * Ramalingam C <ramalingam.c@intel.com> @@ -42,9 +42,44 @@ enum hdcp_wired_protocol { HDCP_PROTOCOL_DP }; +enum mei_fw_ddi { + MEI_DDI_INVALID_PORT = 0x0, + + MEI_DDI_B = 1, + MEI_DDI_C, + MEI_DDI_D, + MEI_DDI_E, + MEI_DDI_F, + MEI_DDI_A = 7, + MEI_DDI_RANGE_END = MEI_DDI_A, +}; + +/** + * enum mei_fw_tc - ME Firmware defined index for transcoders + * @MEI_INVALID_TRANSCODER: Index for Invalid transcoder + * @MEI_TRANSCODER_EDP: Index for EDP Transcoder + * @MEI_TRANSCODER_DSI0: Index for DSI0 Transcoder + * @MEI_TRANSCODER_DSI1: Index for DSI1 Transcoder + * @MEI_TRANSCODER_A: Index for Transcoder A + * @MEI_TRANSCODER_B: Index for Transcoder B + * @MEI_TRANSCODER_C: Index for Transcoder C + * @MEI_TRANSCODER_D: Index for Transcoder D + */ +enum mei_fw_tc { + MEI_INVALID_TRANSCODER = 0x00, + MEI_TRANSCODER_EDP, + MEI_TRANSCODER_DSI0, + MEI_TRANSCODER_DSI1, + MEI_TRANSCODER_A = 0x10, + MEI_TRANSCODER_B, + MEI_TRANSCODER_C, + MEI_TRANSCODER_D +}; + /** * struct hdcp_port_data - intel specific HDCP port data - * @port: port index as per I915 + * @fw_ddi: ddi index as per ME FW + * @fw_tc: transcoder index as per ME FW * @port_type: HDCP port type as per ME FW classification * @protocol: HDCP adaptation as per ME FW * @k: No of streams transmitted on a port. Only on DP MST this is != 1 @@ -56,7 +91,8 @@ enum hdcp_wired_protocol { * streams */ struct hdcp_port_data { - enum port port; + enum mei_fw_ddi fw_ddi; + enum mei_fw_tc fw_tc; u8 port_type; u8 protocol; u16 k; diff --git a/include/drm/i915_pciids.h b/include/drm/i915_pciids.h index 6d60ea68c171..1d2c12219f44 100644 --- a/include/drm/i915_pciids.h +++ b/include/drm/i915_pciids.h @@ -446,27 +446,30 @@ /* CML GT1 */ #define INTEL_CML_GT1_IDS(info) \ - INTEL_VGA_DEVICE(0x9B21, info), \ - INTEL_VGA_DEVICE(0x9BAA, info), \ - INTEL_VGA_DEVICE(0x9BAB, info), \ - INTEL_VGA_DEVICE(0x9BAC, info), \ - INTEL_VGA_DEVICE(0x9BA0, info), \ INTEL_VGA_DEVICE(0x9BA5, info), \ INTEL_VGA_DEVICE(0x9BA8, info), \ INTEL_VGA_DEVICE(0x9BA4, info), \ INTEL_VGA_DEVICE(0x9BA2, info) +#define INTEL_CML_U_GT1_IDS(info) \ + INTEL_VGA_DEVICE(0x9B21, info), \ + INTEL_VGA_DEVICE(0x9BAA, info), \ + INTEL_VGA_DEVICE(0x9BAC, info) + /* CML GT2 */ #define INTEL_CML_GT2_IDS(info) \ - INTEL_VGA_DEVICE(0x9B41, info), \ - INTEL_VGA_DEVICE(0x9BCA, info), \ - INTEL_VGA_DEVICE(0x9BCB, info), \ - INTEL_VGA_DEVICE(0x9BCC, info), \ - INTEL_VGA_DEVICE(0x9BC0, info), \ INTEL_VGA_DEVICE(0x9BC5, info), \ INTEL_VGA_DEVICE(0x9BC8, info), \ INTEL_VGA_DEVICE(0x9BC4, info), \ - INTEL_VGA_DEVICE(0x9BC2, info) + INTEL_VGA_DEVICE(0x9BC2, info), \ + INTEL_VGA_DEVICE(0x9BC6, info), \ + INTEL_VGA_DEVICE(0x9BE6, info), \ + INTEL_VGA_DEVICE(0x9BF6, info) + +#define INTEL_CML_U_GT2_IDS(info) \ + INTEL_VGA_DEVICE(0x9B41, info), \ + INTEL_VGA_DEVICE(0x9BCA, info), \ + INTEL_VGA_DEVICE(0x9BCC, info) #define INTEL_KBL_IDS(info) \ INTEL_KBL_GT1_IDS(info), \ @@ -533,7 +536,9 @@ INTEL_WHL_U_GT3_IDS(info), \ INTEL_AML_CFL_GT2_IDS(info), \ INTEL_CML_GT1_IDS(info), \ - INTEL_CML_GT2_IDS(info) + INTEL_CML_GT2_IDS(info), \ + INTEL_CML_U_GT1_IDS(info), \ + INTEL_CML_U_GT2_IDS(info) /* CNL */ #define INTEL_CNL_PORT_F_IDS(info) \ @@ -568,18 +573,32 @@ INTEL_VGA_DEVICE(0x8A56, info), \ INTEL_VGA_DEVICE(0x8A71, info), \ INTEL_VGA_DEVICE(0x8A70, info), \ - INTEL_VGA_DEVICE(0x8A53, info) + INTEL_VGA_DEVICE(0x8A53, info), \ + INTEL_VGA_DEVICE(0x8A54, info) #define INTEL_ICL_11_IDS(info) \ INTEL_ICL_PORT_F_IDS(info), \ INTEL_VGA_DEVICE(0x8A51, info), \ INTEL_VGA_DEVICE(0x8A5D, info) -/* EHL */ +/* EHL/JSL */ #define INTEL_EHL_IDS(info) \ INTEL_VGA_DEVICE(0x4500, info), \ INTEL_VGA_DEVICE(0x4571, info), \ INTEL_VGA_DEVICE(0x4551, info), \ - INTEL_VGA_DEVICE(0x4541, info) + INTEL_VGA_DEVICE(0x4541, info), \ + INTEL_VGA_DEVICE(0x4E71, info), \ + INTEL_VGA_DEVICE(0x4E61, info), \ + INTEL_VGA_DEVICE(0x4E51, info) + +/* TGL */ +#define INTEL_TGL_12_IDS(info) \ + INTEL_VGA_DEVICE(0x9A49, info), \ + INTEL_VGA_DEVICE(0x9A40, info), \ + INTEL_VGA_DEVICE(0x9A59, info), \ + INTEL_VGA_DEVICE(0x9A60, info), \ + INTEL_VGA_DEVICE(0x9A68, info), \ + INTEL_VGA_DEVICE(0x9A70, info), \ + INTEL_VGA_DEVICE(0x9A78, info) #endif /* _I915_PCIIDS_H */ diff --git a/include/drm/task_barrier.h b/include/drm/task_barrier.h new file mode 100644 index 000000000000..087e3f649c52 --- /dev/null +++ b/include/drm/task_barrier.h @@ -0,0 +1,107 @@ +/* + * Copyright 2019 Advanced Micro Devices, Inc. + * + * 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 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 + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) 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. + * + */ +#include <linux/semaphore.h> +#include <linux/atomic.h> + +/* + * Reusable 2 PHASE task barrier (randevouz point) implementation for N tasks. + * Based on the Little book of sempahores - https://greenteapress.com/wp/semaphores/ + */ + + + +#ifndef DRM_TASK_BARRIER_H_ +#define DRM_TASK_BARRIER_H_ + +/* + * Represents an instance of a task barrier. + */ +struct task_barrier { + unsigned int n; + atomic_t count; + struct semaphore enter_turnstile; + struct semaphore exit_turnstile; +}; + +static inline void task_barrier_signal_turnstile(struct semaphore *turnstile, + unsigned int n) +{ + int i; + + for (i = 0 ; i < n; i++) + up(turnstile); +} + +static inline void task_barrier_init(struct task_barrier *tb) +{ + tb->n = 0; + atomic_set(&tb->count, 0); + sema_init(&tb->enter_turnstile, 0); + sema_init(&tb->exit_turnstile, 0); +} + +static inline void task_barrier_add_task(struct task_barrier *tb) +{ + tb->n++; +} + +static inline void task_barrier_rem_task(struct task_barrier *tb) +{ + tb->n--; +} + +/* + * Lines up all the threads BEFORE the critical point. + * + * When all thread passed this code the entry barrier is back to locked state. + */ +static inline void task_barrier_enter(struct task_barrier *tb) +{ + if (atomic_inc_return(&tb->count) == tb->n) + task_barrier_signal_turnstile(&tb->enter_turnstile, tb->n); + + down(&tb->enter_turnstile); +} + +/* + * Lines up all the threads AFTER the critical point. + * + * This function is used to avoid any one thread running ahead if the barrier is + * used repeatedly . + */ +static inline void task_barrier_exit(struct task_barrier *tb) +{ + if (atomic_dec_return(&tb->count) == 0) + task_barrier_signal_turnstile(&tb->exit_turnstile, tb->n); + + down(&tb->exit_turnstile); +} + +/* Convinieince function when nothing to be done in between entry and exit */ +static inline void task_barrier_full(struct task_barrier *tb) +{ + task_barrier_enter(tb); + task_barrier_exit(tb); +} + +#endif diff --git a/include/drm/tinydrm/mipi-dbi.h b/include/drm/tinydrm/mipi-dbi.h deleted file mode 100644 index 51fc667beef7..000000000000 --- a/include/drm/tinydrm/mipi-dbi.h +++ /dev/null @@ -1,117 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ -/* - * MIPI Display Bus Interface (DBI) LCD controller support - * - * Copyright 2016 Noralf Trønnes - */ - -#ifndef __LINUX_MIPI_DBI_H -#define __LINUX_MIPI_DBI_H - -#include <linux/mutex.h> -#include <drm/drm_device.h> -#include <drm/drm_simple_kms_helper.h> - -struct drm_rect; -struct spi_device; -struct gpio_desc; -struct regulator; - -/** - * struct mipi_dbi - MIPI DBI controller - * @spi: SPI device - * @enabled: Pipeline is enabled - * @cmdlock: Command lock - * @command: Bus specific callback executing commands. - * @read_commands: Array of read commands terminated by a zero entry. - * Reading is disabled if this is NULL. - * @dc: Optional D/C gpio. - * @tx_buf: Buffer used for transfer (copy clip rect area) - * @tx_buf9: Buffer used for Option 1 9-bit conversion - * @tx_buf9_len: Size of tx_buf9. - * @swap_bytes: Swap bytes in buffer before transfer - * @reset: Optional reset gpio - * @rotation: initial rotation in degrees Counter Clock Wise - * @backlight: backlight device (optional) - * @regulator: power regulator (optional) - */ -struct mipi_dbi { - /** - * @drm: DRM device - */ - struct drm_device drm; - - /** - * @pipe: Display pipe structure - */ - struct drm_simple_display_pipe pipe; - - struct spi_device *spi; - bool enabled; - struct mutex cmdlock; - int (*command)(struct mipi_dbi *mipi, u8 *cmd, u8 *param, size_t num); - const u8 *read_commands; - struct gpio_desc *dc; - u16 *tx_buf; - void *tx_buf9; - size_t tx_buf9_len; - bool swap_bytes; - struct gpio_desc *reset; - unsigned int rotation; - struct backlight_device *backlight; - struct regulator *regulator; -}; - -static inline struct mipi_dbi *drm_to_mipi_dbi(struct drm_device *drm) -{ - return container_of(drm, struct mipi_dbi, drm); -} - -int mipi_dbi_spi_init(struct spi_device *spi, struct mipi_dbi *mipi, - struct gpio_desc *dc); -int mipi_dbi_init(struct mipi_dbi *mipi, - const struct drm_simple_display_pipe_funcs *funcs, - const struct drm_display_mode *mode, unsigned int rotation); -void mipi_dbi_release(struct drm_device *drm); -void mipi_dbi_pipe_update(struct drm_simple_display_pipe *pipe, - struct drm_plane_state *old_state); -void mipi_dbi_enable_flush(struct mipi_dbi *mipi, - struct drm_crtc_state *crtc_state, - struct drm_plane_state *plan_state); -void mipi_dbi_pipe_disable(struct drm_simple_display_pipe *pipe); -void mipi_dbi_hw_reset(struct mipi_dbi *mipi); -bool mipi_dbi_display_is_on(struct mipi_dbi *mipi); -int mipi_dbi_poweron_reset(struct mipi_dbi *mipi); -int mipi_dbi_poweron_conditional_reset(struct mipi_dbi *mipi); -u32 mipi_dbi_spi_cmd_max_speed(struct spi_device *spi, size_t len); - -int mipi_dbi_command_read(struct mipi_dbi *mipi, u8 cmd, u8 *val); -int mipi_dbi_command_buf(struct mipi_dbi *mipi, u8 cmd, u8 *data, size_t len); -int mipi_dbi_command_stackbuf(struct mipi_dbi *mipi, u8 cmd, u8 *data, size_t len); -int mipi_dbi_buf_copy(void *dst, struct drm_framebuffer *fb, - struct drm_rect *clip, bool swap); -/** - * mipi_dbi_command - MIPI DCS command with optional parameter(s) - * @mipi: MIPI structure - * @cmd: Command - * @seq...: Optional parameter(s) - * - * Send MIPI DCS command to the controller. Use mipi_dbi_command_read() for - * get/read. - * - * Returns: - * Zero on success, negative error code on failure. - */ -#define mipi_dbi_command(mipi, cmd, seq...) \ -({ \ - u8 d[] = { seq }; \ - mipi_dbi_command_stackbuf(mipi, cmd, d, ARRAY_SIZE(d)); \ -}) - -#ifdef CONFIG_DEBUG_FS -int mipi_dbi_debugfs_init(struct drm_minor *minor); -#else -#define mipi_dbi_debugfs_init NULL -#endif - -#endif /* __LINUX_MIPI_DBI_H */ diff --git a/include/drm/tinydrm/tinydrm-helpers.h b/include/drm/tinydrm/tinydrm-helpers.h deleted file mode 100644 index f8bcadf48cb1..000000000000 --- a/include/drm/tinydrm/tinydrm-helpers.h +++ /dev/null @@ -1,75 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ -/* - * Copyright (C) 2016 Noralf Trønnes - */ - -#ifndef __LINUX_TINYDRM_HELPERS_H -#define __LINUX_TINYDRM_HELPERS_H - -struct backlight_device; -struct drm_device; -struct drm_display_mode; -struct drm_framebuffer; -struct drm_rect; -struct drm_simple_display_pipe; -struct drm_simple_display_pipe_funcs; -struct spi_transfer; -struct spi_message; -struct spi_device; -struct device; - -/** - * tinydrm_machine_little_endian - Machine is little endian - * - * Returns: - * true if *defined(__LITTLE_ENDIAN)*, false otherwise - */ -static inline bool tinydrm_machine_little_endian(void) -{ -#if defined(__LITTLE_ENDIAN) - return true; -#else - return false; -#endif -} - -int tinydrm_display_pipe_init(struct drm_device *drm, - struct drm_simple_display_pipe *pipe, - const struct drm_simple_display_pipe_funcs *funcs, - int connector_type, - const uint32_t *formats, - unsigned int format_count, - const struct drm_display_mode *mode, - unsigned int rotation); - -size_t tinydrm_spi_max_transfer_size(struct spi_device *spi, size_t max_len); -bool tinydrm_spi_bpw_supported(struct spi_device *spi, u8 bpw); -int tinydrm_spi_transfer(struct spi_device *spi, u32 speed_hz, - struct spi_transfer *header, u8 bpw, const void *buf, - size_t len); -void _tinydrm_dbg_spi_message(struct spi_device *spi, struct spi_message *m); - -#ifdef DEBUG -/** - * tinydrm_dbg_spi_message - Dump SPI message - * @spi: SPI device - * @m: SPI message - * - * Dumps info about the transfers in a SPI message including buffer content. - * DEBUG has to be defined for this function to be enabled alongside setting - * the DRM_UT_DRIVER bit of &drm_debug. - */ -static inline void tinydrm_dbg_spi_message(struct spi_device *spi, - struct spi_message *m) -{ - if (drm_debug & DRM_UT_DRIVER) - _tinydrm_dbg_spi_message(spi, m); -} -#else -static inline void tinydrm_dbg_spi_message(struct spi_device *spi, - struct spi_message *m) -{ -} -#endif /* DEBUG */ - -#endif /* __LINUX_TINYDRM_HELPERS_H */ diff --git a/include/drm/ttm/ttm_bo_api.h b/include/drm/ttm/ttm_bo_api.h index 49d9cdfc58f2..66ca49db9633 100644 --- a/include/drm/ttm/ttm_bo_api.h +++ b/include/drm/ttm/ttm_bo_api.h @@ -31,6 +31,7 @@ #ifndef _TTM_BO_API_H_ #define _TTM_BO_API_H_ +#include <drm/drm_gem.h> #include <drm/drm_hashtab.h> #include <drm/drm_vma_manager.h> #include <linux/kref.h> @@ -39,7 +40,7 @@ #include <linux/mutex.h> #include <linux/mm.h> #include <linux/bitmap.h> -#include <linux/reservation.h> +#include <linux/dma-resv.h> struct ttm_bo_global; @@ -127,6 +128,7 @@ struct ttm_tt; /** * struct ttm_buffer_object * + * @base: drm_gem_object superclass data. * @bdev: Pointer to the buffer object device structure. * @type: The bo type. * @destroy: Destruction function. If NULL, kfree is used. @@ -145,16 +147,13 @@ struct ttm_tt; * holds a pointer to a persistent shmem object. * @ttm: TTM structure holding system pages. * @evicted: Whether the object was evicted without user-space knowing. - * @cpu_writes: For synchronization. Number of cpu writers. * @lru: List head for the lru list. * @ddestroy: List head for the delayed destroy list. * @swap: List head for swap LRU list. * @moving: Fence set when BO is moving - * @vma_node: Address space manager node. * @offset: The current GPU offset, which can have different meanings * depending on the memory type. For SYSTEM type memory, it should be 0. * @cur_placement: Hint of current placement. - * @wu_mutex: Wait unreserved mutex. * * Base class for TTM buffer object, that deals with data placement and CPU * mappings. GPU mappings are really up to the driver, but for simpler GPUs @@ -169,6 +168,8 @@ struct ttm_tt; */ struct ttm_buffer_object { + struct drm_gem_object base; + /** * Members constant at init. */ @@ -196,12 +197,6 @@ struct ttm_buffer_object { bool evicted; /** - * Members protected by the bo::reserved lock only when written to. - */ - - atomic_t cpu_writers; - - /** * Members protected by the bdev::lru_lock. */ @@ -215,9 +210,6 @@ struct ttm_buffer_object { */ struct dma_fence *moving; - - struct drm_vma_offset_node vma_node; - unsigned priority; /** @@ -229,10 +221,6 @@ struct ttm_buffer_object { uint64_t offset; /* GPU address space is independent of CPU word size */ struct sg_table *sg; - - struct reservation_object *resv; - struct reservation_object ttm_resv; - struct mutex wu_mutex; }; /** @@ -275,7 +263,7 @@ struct ttm_bo_kmap_obj { struct ttm_operation_ctx { bool interruptible; bool no_wait_gpu; - struct reservation_object *resv; + struct dma_resv *resv; uint64_t bytes_moved; uint32_t flags; }; @@ -370,30 +358,6 @@ int ttm_bo_validate(struct ttm_buffer_object *bo, void ttm_bo_put(struct ttm_buffer_object *bo); /** - * ttm_bo_add_to_lru - * - * @bo: The buffer object. - * - * Add this bo to the relevant mem type lru and, if it's backed by - * system pages (ttms) to the swap list. - * This function must be called with struct ttm_bo_global::lru_lock held, and - * is typically called immediately prior to unreserving a bo. - */ -void ttm_bo_add_to_lru(struct ttm_buffer_object *bo); - -/** - * ttm_bo_del_from_lru - * - * @bo: The buffer object. - * - * Remove this bo from all lru lists used to lookup and reserve an object. - * This function must be called with struct ttm_bo_global::lru_lock held, - * and is usually called just immediately after the bo has been reserved to - * avoid recursive reservation from lru lists. - */ -void ttm_bo_del_from_lru(struct ttm_buffer_object *bo); - -/** * ttm_bo_move_to_lru_tail * * @bo: The buffer object. @@ -444,31 +408,6 @@ bool ttm_bo_eviction_valuable(struct ttm_buffer_object *bo, const struct ttm_place *place); /** - * ttm_bo_synccpu_write_grab - * - * @bo: The buffer object: - * @no_wait: Return immediately if buffer is busy. - * - * Synchronizes a buffer object for CPU RW access. This means - * command submission that affects the buffer will return -EBUSY - * until ttm_bo_synccpu_write_release is called. - * - * Returns - * -EBUSY if the buffer is busy and no_wait is true. - * -ERESTARTSYS if interrupted by a signal. - */ -int ttm_bo_synccpu_write_grab(struct ttm_buffer_object *bo, bool no_wait); - -/** - * ttm_bo_synccpu_write_release: - * - * @bo : The buffer object. - * - * Releases a synccpu lock. - */ -void ttm_bo_synccpu_write_release(struct ttm_buffer_object *bo); - -/** * ttm_bo_acc_size * * @bdev: Pointer to a ttm_bo_device struct. @@ -495,7 +434,7 @@ size_t ttm_bo_dma_acc_size(struct ttm_bo_device *bdev, * @page_alignment: Data alignment in pages. * @ctx: TTM operation context for memory allocation. * @acc_size: Accounted size for this object. - * @resv: Pointer to a reservation_object, or NULL to let ttm allocate one. + * @resv: Pointer to a dma_resv, or NULL to let ttm allocate one. * @destroy: Destroy function. Use NULL for kfree(). * * This function initializes a pre-allocated struct ttm_buffer_object. @@ -528,7 +467,7 @@ int ttm_bo_init_reserved(struct ttm_bo_device *bdev, struct ttm_operation_ctx *ctx, size_t acc_size, struct sg_table *sg, - struct reservation_object *resv, + struct dma_resv *resv, void (*destroy) (struct ttm_buffer_object *)); /** @@ -547,7 +486,7 @@ int ttm_bo_init_reserved(struct ttm_bo_device *bdev, * point to the shmem object backing a GEM object if TTM is used to back a * GEM user interface. * @acc_size: Accounted size for this object. - * @resv: Pointer to a reservation_object, or NULL to let ttm allocate one. + * @resv: Pointer to a dma_resv, or NULL to let ttm allocate one. * @destroy: Destroy function. Use NULL for kfree(). * * This function initializes a pre-allocated struct ttm_buffer_object. @@ -572,7 +511,7 @@ int ttm_bo_init(struct ttm_bo_device *bdev, struct ttm_buffer_object *bo, unsigned long size, enum ttm_bo_type type, struct ttm_placement *placement, uint32_t page_alignment, bool interrubtible, size_t acc_size, - struct sg_table *sg, struct reservation_object *resv, + struct sg_table *sg, struct dma_resv *resv, void (*destroy) (struct ttm_buffer_object *)); /** @@ -712,16 +651,14 @@ int ttm_bo_kmap(struct ttm_buffer_object *bo, unsigned long start_page, void ttm_bo_kunmap(struct ttm_bo_kmap_obj *map); /** - * ttm_fbdev_mmap - mmap fbdev memory backed by a ttm buffer object. + * ttm_bo_mmap_obj - mmap memory backed by a ttm buffer object. * * @vma: vma as input from the fbdev mmap method. - * @bo: The bo backing the address space. The address space will - * have the same size as the bo, and start at offset 0. + * @bo: The bo backing the address space. * - * This function is intended to be called by the fbdev mmap method - * if the fbdev address space is to be backed by a bo. + * Maps a buffer object. */ -int ttm_fbdev_mmap(struct vm_area_struct *vma, struct ttm_buffer_object *bo); +int ttm_bo_mmap_obj(struct vm_area_struct *vma, struct ttm_buffer_object *bo); /** * ttm_bo_mmap - mmap out of the ttm device address space. @@ -767,5 +704,43 @@ ssize_t ttm_bo_io(struct ttm_bo_device *bdev, struct file *filp, int ttm_bo_swapout(struct ttm_bo_global *glob, struct ttm_operation_ctx *ctx); void ttm_bo_swapout_all(struct ttm_bo_device *bdev); -int ttm_bo_wait_unreserved(struct ttm_buffer_object *bo); + +/** + * ttm_bo_uses_embedded_gem_object - check if the given bo uses the + * embedded drm_gem_object. + * + * Most ttm drivers are using gem too, so the embedded + * ttm_buffer_object.base will be initialized by the driver (before + * calling ttm_bo_init). It is also possible to use ttm without gem + * though (vmwgfx does that). + * + * This helper will figure whenever a given ttm bo is a gem object too + * or not. + * + * @bo: The bo to check. + */ +static inline bool ttm_bo_uses_embedded_gem_object(struct ttm_buffer_object *bo) +{ + return bo->base.dev != NULL; +} + +/* Default number of pre-faulted pages in the TTM fault handler */ +#define TTM_BO_VM_NUM_PREFAULT 16 + +vm_fault_t ttm_bo_vm_reserve(struct ttm_buffer_object *bo, + struct vm_fault *vmf); + +vm_fault_t ttm_bo_vm_fault_reserved(struct vm_fault *vmf, + pgprot_t prot, + pgoff_t num_prefault); + +vm_fault_t ttm_bo_vm_fault(struct vm_fault *vmf); + +void ttm_bo_vm_open(struct vm_area_struct *vma); + +void ttm_bo_vm_close(struct vm_area_struct *vma); + +int ttm_bo_vm_access(struct vm_area_struct *vma, unsigned long addr, + void *buf, int len, int write); + #endif diff --git a/include/drm/ttm/ttm_bo_driver.h b/include/drm/ttm/ttm_bo_driver.h index c9b8ba492f24..cac7a8a0825a 100644 --- a/include/drm/ttm/ttm_bo_driver.h +++ b/include/drm/ttm/ttm_bo_driver.h @@ -35,7 +35,7 @@ #include <linux/workqueue.h> #include <linux/fs.h> #include <linux/spinlock.h> -#include <linux/reservation.h> +#include <linux/dma-resv.h> #include "ttm_bo_api.h" #include "ttm_memory.h" @@ -390,6 +390,16 @@ struct ttm_bo_driver { * notify driver that a BO was deleted from LRU. */ void (*del_from_lru_notify)(struct ttm_buffer_object *bo); + + /** + * Notify the driver that we're about to release a BO + * + * @bo: BO that is about to be released + * + * Gives the driver a chance to do any cleanup, including + * adding fences that may force a delayed delete + */ + void (*release_notify)(struct ttm_buffer_object *bo); }; /** @@ -413,7 +423,6 @@ extern struct ttm_bo_global { */ struct kobject kobj; - struct ttm_mem_global *mem_glob; struct page *dummy_read_page; spinlock_t lru_lock; @@ -441,7 +450,7 @@ extern struct ttm_bo_global { * * @driver: Pointer to a struct ttm_bo_driver struct setup by the driver. * @man: An array of mem_type_managers. - * @vma_manager: Address space manager + * @vma_manager: Address space manager (pointer) * lru_lock: Spinlock that protects the buffer+device lru lists and * ddestroy lists. * @dev_mapping: A pointer to the struct address_space representing the @@ -457,14 +466,13 @@ struct ttm_bo_device { * Constant after bo device init / atomic. */ struct list_head device_list; - struct ttm_bo_global *glob; struct ttm_bo_driver *driver; struct ttm_mem_type_manager man[TTM_NUM_MEM_TYPES]; /* * Protected by internal locks. */ - struct drm_vma_offset_manager vma_manager; + struct drm_vma_offset_manager *vma_manager; /* * Protected by the global:lru lock. @@ -585,6 +593,7 @@ int ttm_bo_device_release(struct ttm_bo_device *bdev); * @glob: A pointer to an initialized struct ttm_bo_global. * @driver: A pointer to a struct ttm_bo_driver set up by the caller. * @mapping: The address space to use for this bo. + * @vma_manager: A pointer to a vma manager. * @file_page_offset: Offset into the device address space that is available * for buffer data. This ensures compatibility with other users of the * address space. @@ -596,6 +605,7 @@ int ttm_bo_device_release(struct ttm_bo_device *bdev); int ttm_bo_device_init(struct ttm_bo_device *bdev, struct ttm_bo_driver *driver, struct address_space *mapping, + struct drm_vma_offset_manager *vma_manager, bool need_dma32); /** @@ -619,9 +629,6 @@ void ttm_mem_io_free_vm(struct ttm_buffer_object *bo); int ttm_mem_io_lock(struct ttm_mem_type_manager *man, bool interruptible); void ttm_mem_io_unlock(struct ttm_mem_type_manager *man); -void ttm_bo_del_sub_from_lru(struct ttm_buffer_object *bo); -void ttm_bo_add_to_lru(struct ttm_buffer_object *bo); - /** * __ttm_bo_reserve: * @@ -654,14 +661,14 @@ static inline int __ttm_bo_reserve(struct ttm_buffer_object *bo, if (WARN_ON(ticket)) return -EBUSY; - success = reservation_object_trylock(bo->resv); + success = dma_resv_trylock(bo->base.resv); return success ? 0 : -EBUSY; } if (interruptible) - ret = reservation_object_lock_interruptible(bo->resv, ticket); + ret = dma_resv_lock_interruptible(bo->base.resv, ticket); else - ret = reservation_object_lock(bo->resv, ticket); + ret = dma_resv_lock(bo->base.resv, ticket); if (ret == -EINTR) return -ERESTARTSYS; return ret; @@ -715,15 +722,9 @@ static inline int ttm_bo_reserve(struct ttm_buffer_object *bo, bool interruptible, bool no_wait, struct ww_acquire_ctx *ticket) { - int ret; - WARN_ON(!kref_read(&bo->kref)); - ret = __ttm_bo_reserve(bo, interruptible, no_wait, ticket); - if (likely(ret == 0)) - ttm_bo_del_sub_from_lru(bo); - - return ret; + return __ttm_bo_reserve(bo, interruptible, no_wait, ticket); } /** @@ -745,14 +746,12 @@ static inline int ttm_bo_reserve_slowpath(struct ttm_buffer_object *bo, WARN_ON(!kref_read(&bo->kref)); if (interruptible) - ret = ww_mutex_lock_slow_interruptible(&bo->resv->lock, - ticket); + ret = dma_resv_lock_slow_interruptible(bo->base.resv, + ticket); else - ww_mutex_lock_slow(&bo->resv->lock, ticket); + dma_resv_lock_slow(bo->base.resv, ticket); - if (likely(ret == 0)) - ttm_bo_del_sub_from_lru(bo); - else if (ret == -EINTR) + if (ret == -EINTR) ret = -ERESTARTSYS; return ret; @@ -767,13 +766,10 @@ static inline int ttm_bo_reserve_slowpath(struct ttm_buffer_object *bo, */ static inline void ttm_bo_unreserve(struct ttm_buffer_object *bo) { - spin_lock(&bo->bdev->glob->lru_lock); - if (list_empty(&bo->lru)) - ttm_bo_add_to_lru(bo); - else - ttm_bo_move_to_lru_tail(bo, NULL); - spin_unlock(&bo->bdev->glob->lru_lock); - reservation_object_unlock(bo->resv); + spin_lock(&ttm_bo_glob.lru_lock); + ttm_bo_move_to_lru_tail(bo, NULL); + spin_unlock(&ttm_bo_glob.lru_lock); + dma_resv_unlock(bo->base.resv); } /* diff --git a/include/drm/ttm/ttm_execbuf_util.h b/include/drm/ttm/ttm_execbuf_util.h index 7e46cc678e7e..5a19843bb80d 100644 --- a/include/drm/ttm/ttm_execbuf_util.h +++ b/include/drm/ttm/ttm_execbuf_util.h @@ -99,7 +99,7 @@ extern void ttm_eu_backoff_reservation(struct ww_acquire_ctx *ticket, extern int ttm_eu_reserve_buffers(struct ww_acquire_ctx *ticket, struct list_head *list, bool intr, - struct list_head *dups, bool del_lru); + struct list_head *dups); /** * function ttm_eu_fence_buffer_objects. diff --git a/include/drm/ttm/ttm_memory.h b/include/drm/ttm/ttm_memory.h index 3ff48a0a2d7b..c78ea99c42cf 100644 --- a/include/drm/ttm/ttm_memory.h +++ b/include/drm/ttm/ttm_memory.h @@ -65,7 +65,6 @@ struct ttm_mem_zone; extern struct ttm_mem_global { struct kobject kobj; - struct ttm_bo_global *bo_glob; struct workqueue_struct *swap_queue; struct work_struct work; spinlock_t lock; diff --git a/include/drm/ttm/ttm_page_alloc.h b/include/drm/ttm/ttm_page_alloc.h index 4d9b019d253c..a6b6ef5f9bf4 100644 --- a/include/drm/ttm/ttm_page_alloc.h +++ b/include/drm/ttm/ttm_page_alloc.h @@ -74,7 +74,7 @@ void ttm_unmap_and_unpopulate_pages(struct device *dev, struct ttm_dma_tt *tt); */ int ttm_page_alloc_debugfs(struct seq_file *m, void *data); -#if defined(CONFIG_SWIOTLB) || defined(CONFIG_INTEL_IOMMU) +#if defined(CONFIG_DRM_TTM_DMA_PAGE_POOL) /** * Initialize pool allocator. */ |