diff options
author | Dave Airlie <airlied@redhat.com> | 2017-04-03 16:30:24 +1000 |
---|---|---|
committer | Dave Airlie <airlied@redhat.com> | 2017-04-03 16:30:24 +1000 |
commit | 320d8c3d38739fa8e31a076b86cbdafcf8897d5e (patch) | |
tree | ac43e4981ad56b9612cd0cfc0e075401da38f89f | |
parent | 7558ab66424e61819cbf3d778d9f780f3aa205e9 (diff) | |
parent | b121b051d14cc6e4e799e96e9c06c55989f9e073 (diff) | |
download | blackbird-op-linux-320d8c3d38739fa8e31a076b86cbdafcf8897d5e.tar.gz blackbird-op-linux-320d8c3d38739fa8e31a076b86cbdafcf8897d5e.zip |
Merge tag 'drm-misc-next-2017-03-31' of git://anongit.freedesktop.org/git/drm-misc into drm-next
drm-misc for 4.12:
Core:
- Removed some fb subsampling dimension checks from core (Ville)
- Some MST slot cleanup (Dhinakaran)
- Extracted drm_debugfs.h & drm_ioctl.h from drmP.h (Daniel)
- Added drm_atomic_helper_shutdown() to compliment suspend/resume counterparts
(Daniel)
- Pipe context through legacy modeset to remove legacy_backoff nasties (Daniel)
- Cleanups around vblank as well as allowing lockless counter reads (Chris W.)
- VGA Switcheroo added to MAINTAINERS with Lukas Wunner as reviewer (Lukas)
Drivers:
- Enhancements to rockchip driver probe (Jeffy) and dsi (Chris Z.)
- Thunderbolt external GPU awareness added (Lukas)
* tag 'drm-misc-next-2017-03-31' of git://anongit.freedesktop.org/git/drm-misc: (63 commits)
apple-gmux: Don't switch external DP port on 2011+ MacBook Pros
drm/nouveau: Don't register Thunderbolt eGPU with vga_switcheroo
drm/amdgpu: Don't register Thunderbolt eGPU with vga_switcheroo
drm/radeon: Don't register Thunderbolt eGPU with vga_switcheroo
PCI: Recognize Thunderbolt devices
MAINTAINERS: Add Lukas Wunner as reviewer for vga_switcheroo
drm: Fix locking gotcha in page_flip ioctl
drm: Clarify the role of plane_state argument to drm_simple update().
drm: Clear e after kfree in drm_mode_page_flip_ioctl
drm: Convert cmpxchg(bool) back to a two step operation
drm/bridge: ti-tfp410: support hpd via gpio
drm: use .hword to represent 16-bit numbers
Revert unrelated part of "drm: simplify the locking in the GETCRTC ioctl"
drm: Fixup failure paths in drm_atomic_helper_set_config
drm: Peek at the current counter/timestamp for vblank queries
drm: Refactor vblank sequence number comparison
drm: vblank cannot be enabled if dev->irq_enabled is false
drm: Mark up accesses of vblank->enabled outside of its spinlock
drm: Make the decision to keep vblank irq enabled earlier
drm/atomic-helper: Remove the backoff hack from set_config
...
101 files changed, 1596 insertions, 769 deletions
diff --git a/Documentation/EDID/edid.S b/Documentation/EDID/edid.S index 7ac03276d7a2..ef082dcc6084 100644 --- a/Documentation/EDID/edid.S +++ b/Documentation/EDID/edid.S @@ -59,9 +59,9 @@ /* Fixed header pattern */ header: .byte 0x00,0xff,0xff,0xff,0xff,0xff,0xff,0x00 -mfg_id: .word swap16(mfgname2id(MFG_LNX1, MFG_LNX2, MFG_LNX3)) +mfg_id: .hword swap16(mfgname2id(MFG_LNX1, MFG_LNX2, MFG_LNX3)) -prod_code: .word 0 +prod_code: .hword 0 /* Serial number. 32 bits, little endian. */ serial_number: .long SERIAL @@ -177,7 +177,7 @@ std_vres: .byte (XY_RATIO<<6)+VFREQ-60 descriptor1: /* Pixel clock in 10 kHz units. (0.-655.35 MHz, little-endian) */ -clock: .word CLOCK/10 +clock: .hword CLOCK/10 /* Horizontal active pixels 8 lsbits (0-4095) */ x_act_lsb: .byte XPIX&0xff diff --git a/Documentation/devicetree/bindings/display/rockchip/dw_mipi_dsi_rockchip.txt b/Documentation/devicetree/bindings/display/rockchip/dw_mipi_dsi_rockchip.txt index 188f6f7403e6..1d722f5055ab 100644 --- a/Documentation/devicetree/bindings/display/rockchip/dw_mipi_dsi_rockchip.txt +++ b/Documentation/devicetree/bindings/display/rockchip/dw_mipi_dsi_rockchip.txt @@ -10,7 +10,7 @@ Required properties: - interrupts: Represent the controller's interrupt to the CPU(s). - clocks, clock-names: Phandles to the controller's pll reference clock(ref) and APB clock(pclk). For RK3399, a phy config clock - (phy_cfg) is additional required. As described in [1]. + (phy_cfg) and a grf clock(grf) are required. As described in [1]. - rockchip,grf: this soc should set GRF regs to mux vopl/vopb. - ports: contain a port node with endpoint definitions as defined in [2]. For vopb,set the reg = <0> and set the reg = <1> for vopl. diff --git a/Documentation/gpu/drm-uapi.rst b/Documentation/gpu/drm-uapi.rst index 352652810dab..76356c86e358 100644 --- a/Documentation/gpu/drm-uapi.rst +++ b/Documentation/gpu/drm-uapi.rst @@ -207,6 +207,18 @@ Display CRC Support .. kernel-doc:: drivers/gpu/drm/drm_debugfs_crc.c :doc: CRC ABI +.. kernel-doc:: drivers/gpu/drm/drm_debugfs_crc.c + :export: + +Debugfs Support +--------------- + +.. kernel-doc:: include/drm/drm_debugfs.h + :internal: + +.. kernel-doc:: drivers/gpu/drm/drm_debugfs.c + :export: + VBlank event handling ===================== diff --git a/Documentation/gpu/introduction.rst b/Documentation/gpu/introduction.rst index 1f8bd5ef5f9d..05a82bdfbca4 100644 --- a/Documentation/gpu/introduction.rst +++ b/Documentation/gpu/introduction.rst @@ -60,3 +60,28 @@ checkpatch or sparse. We welcome such contributions. Anyone looking to kick it up a notch can find a list of janitorial tasks on the :ref:`TODO list <todo>`. + +Contribution Process +==================== + +Mostly the DRM subsystem works like any other kernel subsystem, see :ref:`the +main process guidelines and documentation <process_index>` for how things work. +Here we just document some of the specialities of the GPU subsystem. + +Feature Merge Deadlines +----------------------- + +All feature work must be in the linux-next tree by the -rc6 release of the +current release cycle, otherwise they must be postponed and can't reach the next +merge window. All patches must have landed in the drm-next tree by latest -rc7, +but if your branch is not in linux-next then this must have happened by -rc6 +already. + +After that point only bugfixes (like after the upstream merge window has closed +with the -rc1 release) are allowed. No new platform enabling or new drivers are +allowed. + +This means that there's a blackout-period of about one month where feature work +can't be merged. The recommended way to deal with that is having a -next tree +that's always open, but making sure to not feed it into linux-next during the +blackout period. As an example, drm-misc works like that. diff --git a/Documentation/gpu/kms-properties.csv b/Documentation/gpu/kms-properties.csv index 981873a05d14..927b65e14219 100644 --- a/Documentation/gpu/kms-properties.csv +++ b/Documentation/gpu/kms-properties.csv @@ -1,10 +1,5 @@ Owner Module/Drivers,Group,Property Name,Type,Property Values,Object attached,Description/Restrictions ,,“scaling mode”,ENUM,"{ ""None"", ""Full"", ""Center"", ""Full aspect"" }",Connector,"Supported by: amdgpu, gma500, i915, nouveau and radeon." -,Connector,“EDID”,BLOB | IMMUTABLE,0,Connector,Contains id of edid blob ptr object. -,,“DPMS”,ENUM,"{ “On”, “Standby”, “Suspend”, “Off” }",Connector,Contains DPMS operation mode value. -,,“PATH”,BLOB | IMMUTABLE,0,Connector,Contains topology path to a connector. -,,“TILE”,BLOB | IMMUTABLE,0,Connector,Contains tiling information for a connector. -,,“CRTC_ID”,OBJECT,DRM_MODE_OBJECT_CRTC,Connector,CRTC that connector is attached to (atomic) ,DVI-I,“subconnector”,ENUM,"{ “Unknown”, “DVI-D”, “DVI-A” }",Connector,TBD ,,“select subconnector”,ENUM,"{ “Automatic”, “DVI-D”, “DVI-A” }",Connector,TBD ,TV,“subconnector”,ENUM,"{ ""Unknown"", ""Composite"", ""SVIDEO"", ""Component"", ""SCART"" }",Connector,TBD diff --git a/Documentation/gpu/todo.rst b/Documentation/gpu/todo.rst index 64e9d16170ce..e255b36b34a3 100644 --- a/Documentation/gpu/todo.rst +++ b/Documentation/gpu/todo.rst @@ -99,6 +99,30 @@ events for atomic commits correctly. But fixing these bugs is good anyway. Contact: Daniel Vetter, respective driver maintainers +Better manual-upload support for atomic +--------------------------------------- + +This would be especially useful for tinydrm: + +- Add a struct drm_rect dirty_clip to drm_crtc_state. When duplicating the + crtc state, clear that to the max values, x/y = 0 and w/h = MAX_INT, in + __drm_atomic_helper_crtc_duplicate_state(). + +- Move tinydrm_merge_clips into drm_framebuffer.c, dropping the tinydrm_ + prefix ofc and using drm_fb_. drm_framebuffer.c makes sense since this + is a function useful to implement the fb->dirty function. + +- Create a new drm_fb_dirty function which does essentially what e.g. + mipi_dbi_fb_dirty does. You can use e.g. drm_atomic_helper_update_plane as the + template. But instead of doing a simple full-screen plane update, this new + helper also sets crtc_state->dirty_clip to the right coordinates. And of + course it needs to check whether the fb is actually active (and maybe where), + so there's some book-keeping involved. There's also some good fun involved in + scaling things appropriately. For that case we might simply give up and + declare the entire area covered by the plane as dirty. + +Contact: Noralf Trønnes, Daniel Vetter + Fallout from atomic KMS ----------------------- @@ -272,6 +296,32 @@ This is a really varied tasks with lots of little bits and pieces: Contact: Daniel Vetter +Clean up the debugfs support +---------------------------- + +There's a bunch of issues with it: + +- The drm_info_list ->show() function doesn't even bother to cast to the drm + structure for you. This is lazy. + +- We probably want to have some support for debugfs files on crtc/connectors and + maybe other kms objects directly in core. There's even drm_print support in + the funcs for these objects to dump kms state, so it's all there. And then the + ->show() functions should obviously give you a pointer to the right object. + +- The drm_info_list stuff is centered on drm_minor instead of drm_device. For + anything we want to print drm_device (or maybe drm_file) is the right thing. + +- The drm_driver->debugfs_init hooks we have is just an artifact of the old + midlayered load sequence. DRM debugfs should work more like sysfs, where you + can create properties/files for an object anytime you want, and the core + takes care of publishing/unpuplishing all the files at register/unregister + time. Drivers shouldn't need to worry about these technicalities, and fixing + this (together with the drm_minor->drm_device move) would allow us to remove + debugfs_init. + +Contact: Daniel Vetter + Better Testing ============== @@ -310,6 +360,52 @@ Contact: Daniel Vetter Driver Specific =============== +tinydrm +------- + +Tinydrm is the helper driver for really simple fb drivers. The goal is to make +those drivers as simple as possible, so lots of room for refactoring: + +- backlight helpers, probably best to put them into a new drm_backlight.c. + This is because drivers/video is de-facto unmaintained. We could also + move drivers/video/backlight to drivers/gpu/backlight and take it all + over within drm-misc, but that's more work. + +- spi helpers, probably best put into spi core/helper code. Thierry said + the spi maintainer is fast&reactive, so shouldn't be a big issue. + +- extract the mipi-dbi helper (well, the non-tinydrm specific parts at + least) into a separate helper, like we have for mipi-dsi already. Or follow + one of the ideas for having a shared dsi/dbi helper, abstracting away the + transport details more. + +- tinydrm_lastclose could be drm_fb_helper_lastclose. Only thing we need + for that is to store the drm_fb_helper pointer somewhere in + drm_device->mode_config. And then we could roll that out to all the + drivers. + +- tinydrm_gem_cma_prime_import_sg_table should probably go into the cma + helpers, as a _vmapped variant (since not every driver needs the vmap). + And tinydrm_gem_cma_free_object could the be merged into + drm_gem_cma_free_object(). + +- tinydrm_fb_create we could move into drm_simple_pipe, only need to add + the fb_create hook to drm_simple_pipe_funcs, which would again simplify a + bunch of things (since it gives you a one-stop vfunc for simple drivers). + +- Quick aside: The unregister devm stuff is kinda getting the lifetimes of + a drm_device wrong. Doesn't matter, since everyone else gets it wrong + too :-) + +- With the fbdev pointer in dev->mode_config we could also make + suspend/resume helpers entirely generic, at least if we add a + dev->mode_config.suspend_state. We could even provide a generic pm_ops + structure with those. + +- also rework the drm_framebuffer_funcs->dirty hook wire-up, see above. + +Contact: Noralf Trønnes, Daniel Vetter + Outside DRM =========== diff --git a/Documentation/process/index.rst b/Documentation/process/index.rst index 10aa6920709a..82fc399fcd33 100644 --- a/Documentation/process/index.rst +++ b/Documentation/process/index.rst @@ -3,6 +3,7 @@ \renewcommand\thesection* \renewcommand\thesubsection* +.. _process_index: Working with the kernel development community ============================================= diff --git a/MAINTAINERS b/MAINTAINERS index be86eee3353f..fa8479e1799a 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -4145,6 +4145,7 @@ F: Documentation/devicetree/bindings/video/ F: Documentation/gpu/ F: include/drm/ F: include/uapi/drm/ +F: include/linux/vga* DRM DRIVERS AND MISC GPU PATCHES M: Daniel Vetter <daniel.vetter@intel.com> @@ -4158,6 +4159,7 @@ F: drivers/gpu/vga/ F: drivers/gpu/drm/* F: include/drm/drm* F: include/uapi/drm/drm* +F: include/linux/vga* DRM DRIVER FOR AST SERVER GRAPHICS CHIPS M: Dave Airlie <airlied@redhat.com> @@ -13257,6 +13259,14 @@ L: kvm@vger.kernel.org S: Maintained F: drivers/vfio/platform/ +VGA_SWITCHEROO +R: Lukas Wunner <lukas@wunner.de> +S: Maintained +F: Documentation/gpu/vga-switcheroo.rst +F: drivers/gpu/vga/vga_switcheroo.c +F: include/linux/vga_switcheroo.h +T: git git://anongit.freedesktop.org/drm/drm-misc + VIDEOBUF2 FRAMEWORK M: Pawel Osciak <pawel@osciak.com> M: Marek Szyprowski <m.szyprowski@samsung.com> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c index 93061a439dbc..83dda05325b8 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c @@ -1929,7 +1929,9 @@ int amdgpu_device_init(struct amdgpu_device *adev, runtime = true; if (amdgpu_device_is_px(ddev)) runtime = true; - vga_switcheroo_register_client(adev->pdev, &amdgpu_switcheroo_ops, runtime); + if (!pci_is_thunderbolt_attached(adev->pdev)) + vga_switcheroo_register_client(adev->pdev, + &amdgpu_switcheroo_ops, runtime); if (runtime) vga_switcheroo_init_domain_pm_ops(adev->dev, &adev->vga_pm_domain); @@ -2084,7 +2086,8 @@ void amdgpu_device_fini(struct amdgpu_device *adev) amdgpu_atombios_fini(adev); kfree(adev->bios); adev->bios = NULL; - vga_switcheroo_unregister_client(adev->pdev); + if (!pci_is_thunderbolt_attached(adev->pdev)) + vga_switcheroo_unregister_client(adev->pdev); if (adev->flags & AMD_IS_PX) vga_switcheroo_fini_domain_pm_ops(adev->dev); vga_client_register(adev->pdev, NULL, NULL, NULL); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c index 39fc388f222a..ce15721cadda 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c @@ -311,7 +311,8 @@ int amdgpu_crtc_page_flip_target(struct drm_crtc *crtc, struct drm_framebuffer *fb, struct drm_pending_vblank_event *event, uint32_t page_flip_flags, - uint32_t target) + uint32_t target, + struct drm_modeset_acquire_ctx *ctx) { struct amdgpu_bo *new_abo; struct amdgpu_flip_work *work; @@ -332,7 +333,8 @@ int amdgpu_crtc_page_flip_target(struct drm_crtc *crtc, return 0; } -int amdgpu_crtc_set_config(struct drm_mode_set *set) +int amdgpu_crtc_set_config(struct drm_mode_set *set, + struct drm_modeset_acquire_ctx *ctx) { struct drm_device *dev; struct amdgpu_device *adev; @@ -349,7 +351,7 @@ int amdgpu_crtc_set_config(struct drm_mode_set *set) if (ret < 0) return ret; - ret = drm_crtc_helper_set_config(set); + ret = drm_crtc_helper_set_config(set, ctx); list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) if (crtc->enabled) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c index 5ded370a4b35..dfb029ab3448 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c @@ -103,7 +103,8 @@ int amdgpu_driver_load_kms(struct drm_device *dev, unsigned long flags) amdgpu_has_atpx() && (amdgpu_is_atpx_hybrid() || amdgpu_has_atpx_dgpu_power_cntl()) && - ((flags & AMD_IS_APU) == 0)) + ((flags & AMD_IS_APU) == 0) && + !pci_is_thunderbolt_attached(dev->pdev)) flags |= AMD_IS_PX; /* amdgpu_device_init should report only fatal error diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h index c12497bd3889..db8f8dda209c 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h @@ -590,11 +590,13 @@ int amdgpu_align_pitch(struct amdgpu_device *adev, int width, int bpp, bool tile /* amdgpu_display.c */ void amdgpu_print_display_setup(struct drm_device *dev); int amdgpu_modeset_create_props(struct amdgpu_device *adev); -int amdgpu_crtc_set_config(struct drm_mode_set *set); +int amdgpu_crtc_set_config(struct drm_mode_set *set, + struct drm_modeset_acquire_ctx *ctx); int amdgpu_crtc_page_flip_target(struct drm_crtc *crtc, struct drm_framebuffer *fb, struct drm_pending_vblank_event *event, - uint32_t page_flip_flags, uint32_t target); + uint32_t page_flip_flags, uint32_t target, + struct drm_modeset_acquire_ctx *ctx); void amdgpu_crtc_cleanup_flip_ctx(struct amdgpu_flip_work *work, struct amdgpu_bo *new_abo); int amdgpu_crtc_prepare_flip(struct drm_crtc *crtc, diff --git a/drivers/gpu/drm/armada/armada_crtc.c b/drivers/gpu/drm/armada/armada_crtc.c index 1341e0b9368a..4fe19fde84f9 100644 --- a/drivers/gpu/drm/armada/armada_crtc.c +++ b/drivers/gpu/drm/armada/armada_crtc.c @@ -1027,7 +1027,8 @@ static void armada_drm_crtc_destroy(struct drm_crtc *crtc) * and a mode_set. */ static int armada_drm_crtc_page_flip(struct drm_crtc *crtc, - struct drm_framebuffer *fb, struct drm_pending_vblank_event *event, uint32_t page_flip_flags) + struct drm_framebuffer *fb, struct drm_pending_vblank_event *event, uint32_t page_flip_flags, + struct drm_modeset_acquire_ctx *ctx) { struct armada_crtc *dcrtc = drm_to_armada_crtc(crtc); struct armada_frame_work *work; diff --git a/drivers/gpu/drm/armada/armada_overlay.c b/drivers/gpu/drm/armada/armada_overlay.c index 34cb73d0db77..424e465ff407 100644 --- a/drivers/gpu/drm/armada/armada_overlay.c +++ b/drivers/gpu/drm/armada/armada_overlay.c @@ -94,7 +94,8 @@ static int armada_ovl_plane_update(struct drm_plane *plane, struct drm_crtc *crtc, struct drm_framebuffer *fb, int crtc_x, int crtc_y, unsigned crtc_w, unsigned crtc_h, - uint32_t src_x, uint32_t src_y, uint32_t src_w, uint32_t src_h) + uint32_t src_x, uint32_t src_y, uint32_t src_w, uint32_t src_h, + struct drm_modeset_acquire_ctx *ctx) { struct armada_ovl_plane *dplane = drm_to_armada_ovl_plane(plane); struct armada_crtc *dcrtc = drm_to_armada_crtc(crtc); @@ -257,7 +258,8 @@ armada_ovl_plane_update(struct drm_plane *plane, struct drm_crtc *crtc, return 0; } -static int armada_ovl_plane_disable(struct drm_plane *plane) +static int armada_ovl_plane_disable(struct drm_plane *plane, + struct drm_modeset_acquire_ctx *ctx) { struct armada_ovl_plane *dplane = drm_to_armada_ovl_plane(plane); struct drm_framebuffer *fb; diff --git a/drivers/gpu/drm/bochs/bochs_fbdev.c b/drivers/gpu/drm/bochs/bochs_fbdev.c index 471bd588550b..c38deffa14de 100644 --- a/drivers/gpu/drm/bochs/bochs_fbdev.c +++ b/drivers/gpu/drm/bochs/bochs_fbdev.c @@ -192,6 +192,8 @@ void bochs_fbdev_fini(struct bochs_device *bochs) if (bochs->fb.initialized) bochs_fbdev_destroy(bochs); - drm_fb_helper_fini(&bochs->fb.helper); + if (bochs->fb.helper.fbdev) + drm_fb_helper_fini(&bochs->fb.helper); + bochs->fb.initialized = false; } diff --git a/drivers/gpu/drm/bochs/bochs_kms.c b/drivers/gpu/drm/bochs/bochs_kms.c index d5e63eff357b..6a91e62da2f4 100644 --- a/drivers/gpu/drm/bochs/bochs_kms.c +++ b/drivers/gpu/drm/bochs/bochs_kms.c @@ -96,7 +96,8 @@ static void bochs_crtc_commit(struct drm_crtc *crtc) static int bochs_crtc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb, struct drm_pending_vblank_event *event, - uint32_t page_flip_flags) + uint32_t page_flip_flags, + struct drm_modeset_acquire_ctx *ctx) { struct bochs_device *bochs = container_of(crtc, struct bochs_device, crtc); diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c index af93f7a20697..32f02e92e0b9 100644 --- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c +++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c @@ -1916,7 +1916,7 @@ static irqreturn_t dw_hdmi_irq(int irq, void *dev_id) if (intr_stat & (HDMI_IH_PHY_STAT0_RX_SENSE | HDMI_IH_PHY_STAT0_HPD)) { mutex_lock(&hdmi->mutex); - if (!hdmi->disabled && !hdmi->force) { + if (!hdmi->force) { /* * If the RX sense status indicates we're disconnected, * clear the software rxsense status. diff --git a/drivers/gpu/drm/bridge/ti-tfp410.c b/drivers/gpu/drm/bridge/ti-tfp410.c index b379d046991b..7d519b46aee4 100644 --- a/drivers/gpu/drm/bridge/ti-tfp410.c +++ b/drivers/gpu/drm/bridge/ti-tfp410.c @@ -8,6 +8,10 @@ * */ +#include <linux/delay.h> +#include <linux/fwnode.h> +#include <linux/gpio/consumer.h> +#include <linux/irq.h> #include <linux/module.h> #include <linux/of_graph.h> #include <linux/platform_device.h> @@ -18,11 +22,15 @@ #include <drm/drm_crtc.h> #include <drm/drm_crtc_helper.h> +#define HOTPLUG_DEBOUNCE_MS 1100 + struct tfp410 { struct drm_bridge bridge; struct drm_connector connector; struct i2c_adapter *ddc; + struct gpio_desc *hpd; + struct delayed_work hpd_work; struct device *dev; }; @@ -76,6 +84,13 @@ tfp410_connector_detect(struct drm_connector *connector, bool force) { struct tfp410 *dvi = drm_connector_to_tfp410(connector); + if (dvi->hpd) { + if (gpiod_get_value_cansleep(dvi->hpd)) + return connector_status_connected; + else + return connector_status_disconnected; + } + if (dvi->ddc) { if (drm_probe_ddc(dvi->ddc)) return connector_status_connected; @@ -106,6 +121,9 @@ static int tfp410_attach(struct drm_bridge *bridge) return -ENODEV; } + if (dvi->hpd) + dvi->connector.polled = DRM_CONNECTOR_POLL_HPD; + drm_connector_helper_add(&dvi->connector, &tfp410_con_helper_funcs); ret = drm_connector_init(bridge->dev, &dvi->connector, @@ -125,7 +143,27 @@ static const struct drm_bridge_funcs tfp410_bridge_funcs = { .attach = tfp410_attach, }; -static int tfp410_get_connector_ddc(struct tfp410 *dvi) +static void tfp410_hpd_work_func(struct work_struct *work) +{ + struct tfp410 *dvi; + + dvi = container_of(work, struct tfp410, hpd_work.work); + + if (dvi->bridge.dev) + drm_helper_hpd_irq_event(dvi->bridge.dev); +} + +static irqreturn_t tfp410_hpd_irq_thread(int irq, void *arg) +{ + struct tfp410 *dvi = arg; + + mod_delayed_work(system_wq, &dvi->hpd_work, + msecs_to_jiffies(HOTPLUG_DEBOUNCE_MS)); + + return IRQ_HANDLED; +} + +static int tfp410_get_connector_properties(struct tfp410 *dvi) { struct device_node *ep = NULL, *connector_node = NULL; struct device_node *ddc_phandle = NULL; @@ -140,6 +178,17 @@ static int tfp410_get_connector_ddc(struct tfp410 *dvi) if (!connector_node) goto fail; + dvi->hpd = fwnode_get_named_gpiod(&connector_node->fwnode, + "hpd-gpios", 0, GPIOD_IN, "hpd"); + if (IS_ERR(dvi->hpd)) { + ret = PTR_ERR(dvi->hpd); + dvi->hpd = NULL; + if (ret == -ENOENT) + ret = 0; + else + goto fail; + } + ddc_phandle = of_parse_phandle(connector_node, "ddc-i2c-bus", 0); if (!ddc_phandle) goto fail; @@ -176,10 +225,23 @@ static int tfp410_init(struct device *dev) dvi->bridge.of_node = dev->of_node; dvi->dev = dev; - ret = tfp410_get_connector_ddc(dvi); + ret = tfp410_get_connector_properties(dvi); if (ret) goto fail; + if (dvi->hpd) { + INIT_DELAYED_WORK(&dvi->hpd_work, tfp410_hpd_work_func); + + ret = devm_request_threaded_irq(dev, gpiod_to_irq(dvi->hpd), + NULL, tfp410_hpd_irq_thread, IRQF_TRIGGER_RISING | + IRQF_TRIGGER_FALLING | IRQF_ONESHOT, + "hdmi-hpd", dvi); + if (ret) { + DRM_ERROR("failed to register hpd interrupt\n"); + goto fail; + } + } + ret = drm_bridge_add(&dvi->bridge); if (ret) { dev_err(dev, "drm_bridge_add() failed: %d\n", ret); @@ -189,6 +251,8 @@ static int tfp410_init(struct device *dev) return 0; fail: i2c_put_adapter(dvi->ddc); + if (dvi->hpd) + gpiod_put(dvi->hpd); return ret; } @@ -196,10 +260,14 @@ static int tfp410_fini(struct device *dev) { struct tfp410 *dvi = dev_get_drvdata(dev); + cancel_delayed_work_sync(&dvi->hpd_work); + drm_bridge_remove(&dvi->bridge); if (dvi->ddc) i2c_put_adapter(dvi->ddc); + if (dvi->hpd) + gpiod_put(dvi->hpd); return 0; } diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c index 4e26b73bb0d5..c3994b4d5f32 100644 --- a/drivers/gpu/drm/drm_atomic_helper.c +++ b/drivers/gpu/drm/drm_atomic_helper.c @@ -2077,6 +2077,7 @@ EXPORT_SYMBOL(drm_atomic_helper_swap_state); * @src_y: y offset of @fb for panning * @src_w: width of source rectangle in @fb * @src_h: height of source rectangle in @fb + * @ctx: lock acquire context * * Provides a default plane update handler using the atomic driver interface. * @@ -2089,7 +2090,8 @@ int drm_atomic_helper_update_plane(struct drm_plane *plane, int crtc_x, int crtc_y, unsigned int crtc_w, unsigned int crtc_h, uint32_t src_x, uint32_t src_y, - uint32_t src_w, uint32_t src_h) + uint32_t src_w, uint32_t src_h, + struct drm_modeset_acquire_ctx *ctx) { struct drm_atomic_state *state; struct drm_plane_state *plane_state; @@ -2099,8 +2101,7 @@ int drm_atomic_helper_update_plane(struct drm_plane *plane, if (!state) return -ENOMEM; - state->acquire_ctx = drm_modeset_legacy_acquire_ctx(crtc); -retry: + state->acquire_ctx = ctx; plane_state = drm_atomic_get_plane_state(state, plane); if (IS_ERR(plane_state)) { ret = PTR_ERR(plane_state); @@ -2125,59 +2126,33 @@ retry: ret = drm_atomic_commit(state); fail: - if (ret == -EDEADLK) - goto backoff; - drm_atomic_state_put(state); return ret; - -backoff: - drm_atomic_state_clear(state); - drm_atomic_legacy_backoff(state); - - /* - * Someone might have exchanged the framebuffer while we dropped locks - * in the backoff code. We need to fix up the fb refcount tracking the - * core does for us. - */ - plane->old_fb = plane->fb; - - goto retry; } EXPORT_SYMBOL(drm_atomic_helper_update_plane); /** * drm_atomic_helper_disable_plane - Helper for primary plane disable using * atomic * @plane: plane to disable + * @ctx: lock acquire context * * Provides a default plane disable handler using the atomic driver interface. * * RETURNS: * Zero on success, error code on failure */ -int drm_atomic_helper_disable_plane(struct drm_plane *plane) +int drm_atomic_helper_disable_plane(struct drm_plane *plane, + struct drm_modeset_acquire_ctx *ctx) { struct drm_atomic_state *state; struct drm_plane_state *plane_state; int ret = 0; - /* - * FIXME: Without plane->crtc set we can't get at the implicit legacy - * acquire context. The real fix will be to wire the acquire ctx through - * everywhere we need it, but meanwhile prevent chaos by just skipping - * this noop. The critical case is the cursor ioctls which a) only grab - * crtc/cursor-plane locks (so we need the crtc to get at the right - * acquire context) and b) can try to disable the plane multiple times. - */ - if (!plane->crtc) - return 0; - state = drm_atomic_state_alloc(plane->dev); if (!state) return -ENOMEM; - state->acquire_ctx = drm_modeset_legacy_acquire_ctx(plane->crtc); -retry: + state->acquire_ctx = ctx; plane_state = drm_atomic_get_plane_state(state, plane); if (IS_ERR(plane_state)) { ret = PTR_ERR(plane_state); @@ -2193,24 +2168,8 @@ retry: ret = drm_atomic_commit(state); fail: - if (ret == -EDEADLK) - goto backoff; - drm_atomic_state_put(state); return ret; - -backoff: - drm_atomic_state_clear(state); - drm_atomic_legacy_backoff(state); - - /* - * Someone might have exchanged the framebuffer while we dropped locks - * in the backoff code. We need to fix up the fb refcount tracking the - * core does for us. - */ - plane->old_fb = plane->fb; - - goto retry; } EXPORT_SYMBOL(drm_atomic_helper_disable_plane); @@ -2306,6 +2265,7 @@ static int update_output_state(struct drm_atomic_state *state, /** * drm_atomic_helper_set_config - set a new config from userspace * @set: mode set configuration + * @ctx: lock acquisition context * * Provides a default crtc set_config handler using the atomic driver interface. * @@ -2318,7 +2278,8 @@ static int update_output_state(struct drm_atomic_state *state, * Returns: * Returns 0 on success, negative errno numbers on failure. */ -int drm_atomic_helper_set_config(struct drm_mode_set *set) +int drm_atomic_helper_set_config(struct drm_mode_set *set, + struct drm_modeset_acquire_ctx *ctx) { struct drm_atomic_state *state; struct drm_crtc *crtc = set->crtc; @@ -2329,32 +2290,16 @@ int drm_atomic_helper_set_config(struct drm_mode_set *set) return -ENOMEM; state->legacy_set_config = true; - state->acquire_ctx = drm_modeset_legacy_acquire_ctx(crtc); -retry: + state->acquire_ctx = ctx; ret = __drm_atomic_helper_set_config(set, state); if (ret != 0) goto fail; ret = drm_atomic_commit(state); -fail: - if (ret == -EDEADLK) - goto backoff; +fail: drm_atomic_state_put(state); return ret; - -backoff: - drm_atomic_state_clear(state); - drm_atomic_legacy_backoff(state); - - /* - * Someone might have exchanged the framebuffer while we dropped locks - * in the backoff code. We need to fix up the fb refcount tracking the - * core does for us. - */ - crtc->primary->old_fb = crtc->primary->fb; - - goto retry; } EXPORT_SYMBOL(drm_atomic_helper_set_config); @@ -2443,7 +2388,8 @@ commit: * that they are connected to. * * This is used for example in suspend/resume to disable all currently active - * functions when suspending. + * functions when suspending. If you just want to shut down everything at e.g. + * driver unload, look at drm_atomic_helper_shutdown(). * * Note that if callers haven't already acquired all modeset locks this might * return -EDEADLK, which must be handled by calling drm_modeset_backoff(). @@ -2452,7 +2398,8 @@ commit: * 0 on success or a negative error code on failure. * * See also: - * drm_atomic_helper_suspend(), drm_atomic_helper_resume() + * drm_atomic_helper_suspend(), drm_atomic_helper_resume() and + * drm_atomic_helper_shutdown(). */ int drm_atomic_helper_disable_all(struct drm_device *dev, struct drm_modeset_acquire_ctx *ctx) @@ -2517,6 +2464,42 @@ free: EXPORT_SYMBOL(drm_atomic_helper_disable_all); /** + * drm_atomic_helper_shutdown - shutdown all CRTC + * @dev: DRM device + * + * This shuts down all CRTC, which is useful for driver unloading. Shutdown on + * suspend should instead be handled with drm_atomic_helper_suspend(), since + * that also takes a snapshot of the modeset state to be restored on resume. + * + * This is just a convenience wrapper around drm_atomic_helper_disable_all(), + * and it is the atomic version of drm_crtc_force_disable_all(). + */ +void drm_atomic_helper_shutdown(struct drm_device *dev) +{ + struct drm_modeset_acquire_ctx ctx; + int ret; + + drm_modeset_acquire_init(&ctx, 0); + while (1) { + ret = drm_modeset_lock_all_ctx(dev, &ctx); + if (!ret) + ret = drm_atomic_helper_disable_all(dev, &ctx); + + if (ret != -EDEADLK) + break; + + drm_modeset_backoff(&ctx); + } + + if (ret) + DRM_ERROR("Disabling all crtc's during unload failed with %i\n", ret); + + drm_modeset_drop_locks(&ctx); + drm_modeset_acquire_fini(&ctx); +} +EXPORT_SYMBOL(drm_atomic_helper_shutdown); + +/** * drm_atomic_helper_suspend - subsystem-level suspend helper * @dev: DRM device * @@ -2862,6 +2845,7 @@ static int page_flip_common( * @fb: DRM framebuffer * @event: optional DRM event to signal upon completion * @flags: flip flags for non-vblank sync'ed updates + * @ctx: lock acquisition context * * Provides a default &drm_crtc_funcs.page_flip implementation * using the atomic driver interface. @@ -2875,7 +2859,8 @@ static int page_flip_common( int drm_atomic_helper_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb, struct drm_pending_vblank_event *event, - uint32_t flags) + uint32_t flags, + struct drm_modeset_acquire_ctx *ctx) { struct drm_plane *plane = crtc->primary; struct drm_atomic_state *state; @@ -2885,34 +2870,16 @@ int drm_atomic_helper_page_flip(struct drm_crtc *crtc, if (!state) return -ENOMEM; - state->acquire_ctx = drm_modeset_legacy_acquire_ctx(crtc); + state->acquire_ctx = ctx; -retry: ret = page_flip_common(state, crtc, fb, event, flags); if (ret != 0) goto fail; ret = drm_atomic_nonblocking_commit(state); - fail: - if (ret == -EDEADLK) - goto backoff; - drm_atomic_state_put(state); return ret; - -backoff: - drm_atomic_state_clear(state); - drm_atomic_legacy_backoff(state); - - /* - * Someone might have exchanged the framebuffer while we dropped locks - * in the backoff code. We need to fix up the fb refcount tracking the - * core does for us. - */ - plane->old_fb = plane->fb; - - goto retry; } EXPORT_SYMBOL(drm_atomic_helper_page_flip); @@ -2923,6 +2890,7 @@ EXPORT_SYMBOL(drm_atomic_helper_page_flip); * @event: optional DRM event to signal upon completion * @flags: flip flags for non-vblank sync'ed updates * @target: specifying the target vblank period when the flip to take effect + * @ctx: lock acquisition context * * Provides a default &drm_crtc_funcs.page_flip_target implementation. * Similar to drm_atomic_helper_page_flip() with extra parameter to specify @@ -2936,7 +2904,8 @@ int drm_atomic_helper_page_flip_target( struct drm_framebuffer *fb, struct drm_pending_vblank_event *event, uint32_t flags, - uint32_t target) + uint32_t target, + struct drm_modeset_acquire_ctx *ctx) { struct drm_plane *plane = crtc->primary; struct drm_atomic_state *state; @@ -2947,9 +2916,8 @@ int drm_atomic_helper_page_flip_target( if (!state) return -ENOMEM; - state->acquire_ctx = drm_modeset_legacy_acquire_ctx(crtc); + state->acquire_ctx = ctx; -retry: ret = page_flip_common(state, crtc, fb, event, flags); if (ret != 0) goto fail; @@ -2962,26 +2930,9 @@ retry: crtc_state->target_vblank = target; ret = drm_atomic_nonblocking_commit(state); - fail: - if (ret == -EDEADLK) - goto backoff; - drm_atomic_state_put(state); return ret; - -backoff: - drm_atomic_state_clear(state); - drm_atomic_legacy_backoff(state); - - /* - * Someone might have exchanged the framebuffer while we dropped locks - * in the backoff code. We need to fix up the fb refcount tracking the - * core does for us. - */ - plane->old_fb = plane->fb; - - goto retry; } EXPORT_SYMBOL(drm_atomic_helper_page_flip_target); diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index e2974d3c92e7..d69e180fc563 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -94,6 +94,8 @@ EXPORT_SYMBOL(drm_crtc_from_index); * drm_crtc_force_disable - Forcibly turn off a CRTC * @crtc: CRTC to turn off * + * Note: This should only be used by non-atomic legacy drivers. + * * Returns: * Zero on success, error code on failure. */ @@ -103,6 +105,8 @@ int drm_crtc_force_disable(struct drm_crtc *crtc) .crtc = crtc, }; + WARN_ON(drm_drv_uses_atomic_modeset(crtc->dev)); + return drm_mode_set_config_internal(&set); } EXPORT_SYMBOL(drm_crtc_force_disable); @@ -114,6 +118,9 @@ EXPORT_SYMBOL(drm_crtc_force_disable); * Drivers may want to call this on unload to ensure that all displays are * unlit and the GPU is in a consistent, low power state. Takes modeset locks. * + * Note: This should only be used by non-atomic legacy drivers. For an atomic + * version look at drm_atomic_helper_shutdown(). + * * Returns: * Zero on success, error code on failure. */ @@ -399,9 +406,9 @@ int drm_mode_getcrtc(struct drm_device *dev, if (!crtc) return -ENOENT; - drm_modeset_lock_crtc(crtc, crtc->primary); crtc_resp->gamma_size = crtc->gamma_size; + drm_modeset_lock(&crtc->primary->mutex, NULL); if (crtc->primary->state && crtc->primary->state->fb) crtc_resp->fb_id = crtc->primary->state->fb->base.id; else if (!crtc->primary->state && crtc->primary->fb) @@ -409,9 +416,14 @@ int drm_mode_getcrtc(struct drm_device *dev, else crtc_resp->fb_id = 0; - if (crtc->state) { + if (crtc->primary->state) { crtc_resp->x = crtc->primary->state->src_x >> 16; crtc_resp->y = crtc->primary->state->src_y >> 16; + } + drm_modeset_unlock(&crtc->primary->mutex); + + drm_modeset_lock(&crtc->mutex, NULL); + if (crtc->state) { if (crtc->state->enable) { drm_mode_convert_to_umode(&crtc_resp->mode, &crtc->state->mode); crtc_resp->mode_valid = 1; @@ -430,23 +442,13 @@ int drm_mode_getcrtc(struct drm_device *dev, crtc_resp->mode_valid = 0; } } - drm_modeset_unlock_crtc(crtc); + drm_modeset_unlock(&crtc->mutex); return 0; } -/** - * drm_mode_set_config_internal - helper to call &drm_mode_config_funcs.set_config - * @set: modeset config to set - * - * This is a little helper to wrap internal calls to the - * &drm_mode_config_funcs.set_config driver interface. The only thing it adds is - * correct refcounting dance. - * - * Returns: - * Zero on success, negative errno on failure. - */ -int drm_mode_set_config_internal(struct drm_mode_set *set) +static int __drm_mode_set_config_internal(struct drm_mode_set *set, + struct drm_modeset_acquire_ctx *ctx) { struct drm_crtc *crtc = set->crtc; struct drm_framebuffer *fb; @@ -463,7 +465,7 @@ int drm_mode_set_config_internal(struct drm_mode_set *set) fb = set->fb; - ret = crtc->funcs->set_config(set); + ret = crtc->funcs->set_config(set, ctx); if (ret == 0) { crtc->primary->crtc = crtc; crtc->primary->fb = fb; @@ -479,6 +481,25 @@ int drm_mode_set_config_internal(struct drm_mode_set *set) return ret; } +/** + * drm_mode_set_config_internal - helper to call &drm_mode_config_funcs.set_config + * @set: modeset config to set + * + * This is a little helper to wrap internal calls to the + * &drm_mode_config_funcs.set_config driver interface. The only thing it adds is + * correct refcounting dance. + * + * This should only be used by non-atomic legacy drivers. + * + * Returns: + * Zero on success, negative errno on failure. + */ +int drm_mode_set_config_internal(struct drm_mode_set *set) +{ + WARN_ON(drm_drv_uses_atomic_modeset(set->crtc->dev)); + + return __drm_mode_set_config_internal(set, NULL); +} EXPORT_SYMBOL(drm_mode_set_config_internal); /** @@ -534,6 +555,7 @@ int drm_mode_setcrtc(struct drm_device *dev, void *data, struct drm_display_mode *mode = NULL; struct drm_mode_set set; uint32_t __user *set_connectors_ptr; + struct drm_modeset_acquire_ctx ctx; int ret; int i; @@ -547,15 +569,18 @@ int drm_mode_setcrtc(struct drm_device *dev, void *data, if (crtc_req->x & 0xffff0000 || crtc_req->y & 0xffff0000) return -ERANGE; - drm_modeset_lock_all(dev); crtc = drm_crtc_find(dev, crtc_req->crtc_id); if (!crtc) { DRM_DEBUG_KMS("Unknown CRTC ID %d\n", crtc_req->crtc_id); - ret = -ENOENT; - goto out; + return -ENOENT; } DRM_DEBUG_KMS("[CRTC:%d:%s]\n", crtc->base.id, crtc->name); + drm_modeset_acquire_init(&ctx, 0); +retry: + ret = drm_modeset_lock_all_ctx(crtc->dev, &ctx); + if (ret) + goto out; if (crtc_req->mode_valid) { /* If we have a mode we need a framebuffer. */ /* If we pass -1, set the mode with the currently bound fb */ @@ -676,7 +701,7 @@ int drm_mode_setcrtc(struct drm_device *dev, void *data, set.connectors = connector_set; set.num_connectors = crtc_req->count_connectors; set.fb = fb; - ret = drm_mode_set_config_internal(&set); + ret = __drm_mode_set_config_internal(&set, &ctx); out: if (fb) @@ -690,7 +715,13 @@ out: } kfree(connector_set); drm_mode_destroy(dev, mode); - drm_modeset_unlock_all(dev); + if (ret == -EDEADLK) { + drm_modeset_backoff(&ctx); + goto retry; + } + drm_modeset_drop_locks(&ctx); + drm_modeset_acquire_fini(&ctx); + return ret; } diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c index 8aa8c1084121..4afdf7902eda 100644 --- a/drivers/gpu/drm/drm_crtc_helper.c +++ b/drivers/gpu/drm/drm_crtc_helper.c @@ -476,6 +476,7 @@ drm_crtc_helper_disable(struct drm_crtc *crtc) /** * drm_crtc_helper_set_config - set a new config from userspace * @set: mode set configuration + * @ctx: lock acquire context, not used here * * The drm_crtc_helper_set_config() helper function implements the of * &drm_crtc_funcs.set_config callback for drivers using the legacy CRTC @@ -510,7 +511,8 @@ drm_crtc_helper_disable(struct drm_crtc *crtc) * Returns: * Returns 0 on success, negative errno numbers on failure. */ -int drm_crtc_helper_set_config(struct drm_mode_set *set) +int drm_crtc_helper_set_config(struct drm_mode_set *set, + struct drm_modeset_acquire_ctx *ctx) { struct drm_device *dev; struct drm_crtc **save_encoder_crtcs, *new_crtc; diff --git a/drivers/gpu/drm/drm_debugfs.c b/drivers/gpu/drm/drm_debugfs.c index 1d2d18d82d2e..c1807d5754b2 100644 --- a/drivers/gpu/drm/drm_debugfs.c +++ b/drivers/gpu/drm/drm_debugfs.c @@ -1,10 +1,3 @@ -/** - * \file drm_debugfs.c - * debugfs support for DRM - * - * \author Ben Gamari <bgamari@gmail.com> - */ - /* * Created: Sun Dec 21 13:08:50 2008 by bgamari@gmail.com * @@ -34,9 +27,12 @@ #include <linux/seq_file.h> #include <linux/slab.h> #include <linux/export.h> -#include <drm/drmP.h> + +#include <drm/drm_debugfs.h> #include <drm/drm_edid.h> #include <drm/drm_atomic.h> +#include <drm/drmP.h> + #include "drm_internal.h" #include "drm_crtc_internal.h" @@ -72,16 +68,15 @@ static const struct file_operations drm_debugfs_fops = { /** - * Initialize a given set of debugfs files for a device - * - * \param files The array of files to create - * \param count The number of files given - * \param root DRI debugfs dir entry. - * \param minor device minor number - * \return Zero on success, non-zero on failure + * drm_debugfs_create_files - Initialize a given set of debugfs files for DRM + * minor + * @files: The array of files to create + * @count: The number of files given + * @root: DRI debugfs dir entry. + * @minor: device minor number * * Create a given set of debugfs files represented by an array of - * &drm_info_list in the given root directory. These files will be removed + * &struct drm_info_list in the given root directory. These files will be removed * automatically on drm_debugfs_cleanup(). */ int drm_debugfs_create_files(const struct drm_info_list *files, int count, @@ -130,17 +125,6 @@ fail: } EXPORT_SYMBOL(drm_debugfs_create_files); -/** - * Initialize the DRI debugfs filesystem for a device - * - * \param dev DRM device - * \param minor device minor number - * \param root DRI debugfs dir entry. - * - * Create the DRI debugfs root entry "/sys/kernel/debug/dri", the device debugfs root entry - * "/sys/kernel/debug/dri/%minor%/", and each entry in debugfs_list as - * "/sys/kernel/debug/dri/%minor%/%name%". - */ int drm_debugfs_init(struct drm_minor *minor, int minor_id, struct dentry *root) { @@ -186,16 +170,6 @@ int drm_debugfs_init(struct drm_minor *minor, int minor_id, } -/** - * Remove a list of debugfs files - * - * \param files The list of files - * \param count The number of files - * \param minor The minor of which we should remove the files - * \return always zero. - * - * Remove all debugfs entries created by debugfs_init(). - */ int drm_debugfs_remove_files(const struct drm_info_list *files, int count, struct drm_minor *minor) { @@ -232,14 +206,6 @@ static void drm_debugfs_remove_all_files(struct drm_minor *minor) mutex_unlock(&minor->debugfs_lock); } -/** - * Cleanup the debugfs filesystem resources. - * - * \param minor device minor number. - * \return always zero. - * - * Remove all debugfs entries created by debugfs_init(). - */ int drm_debugfs_cleanup(struct drm_minor *minor) { if (!minor->debugfs_root) diff --git a/drivers/gpu/drm/drm_debugfs_crc.c b/drivers/gpu/drm/drm_debugfs_crc.c index 96891c4a6e23..1722d8f21449 100644 --- a/drivers/gpu/drm/drm_debugfs_crc.c +++ b/drivers/gpu/drm/drm_debugfs_crc.c @@ -36,7 +36,7 @@ * DOC: CRC ABI * * DRM device drivers can provide to userspace CRC information of each frame as - * it reached a given hardware component (a "source"). + * it reached a given hardware component (a CRC sampling "source"). * * Userspace can control generation of CRCs in a given CRTC by writing to the * file dri/0/crtc-N/crc/control in debugfs, with N being the index of the CRTC. @@ -57,6 +57,11 @@ * rely on being able to generate matching CRC values for the frame contents that * it submits. In this general case, the maximum userspace can do is to compare * the reported CRCs of frames that should have the same contents. + * + * On the driver side the implementation effort is minimal, drivers only need to + * implement &drm_crtc_funcs.set_crc_source. The debugfs files are automatically + * set up if that vfunc is set. CRC samples need to be captured in the driver by + * calling drm_crtc_add_crc_entry(). */ static int crc_control_show(struct seq_file *m, void *data) @@ -280,16 +285,6 @@ static const struct file_operations drm_crtc_crc_data_fops = { .release = crtc_crc_release, }; -/** - * drm_debugfs_crtc_crc_add - Add files to debugfs for capture of frame CRCs - * @crtc: CRTC to whom the frames will belong - * - * Adds files to debugfs directory that allows userspace to control the - * generation of frame CRCs and to read them. - * - * Returns: - * Zero on success, error code on failure. - */ int drm_debugfs_crtc_crc_add(struct drm_crtc *crtc) { struct dentry *crc_ent, *ent; diff --git a/drivers/gpu/drm/drm_dp_mst_topology.c b/drivers/gpu/drm/drm_dp_mst_topology.c index f2cc375907d0..d3fc7e4e85b7 100644 --- a/drivers/gpu/drm/drm_dp_mst_topology.c +++ b/drivers/gpu/drm/drm_dp_mst_topology.c @@ -2042,10 +2042,6 @@ int drm_dp_mst_topology_mgr_set_mst(struct drm_dp_mst_topology_mgr *mgr, bool ms goto out_unlock; } - mgr->total_pbn = 2560; - mgr->total_slots = DIV_ROUND_UP(mgr->total_pbn, mgr->pbn_div); - mgr->avail_slots = mgr->total_slots; - /* add initial branch device at LCT 1 */ mstb = drm_dp_add_mst_branch_device(1, NULL); if (mstb == NULL) { @@ -2475,26 +2471,25 @@ int drm_dp_find_vcpi_slots(struct drm_dp_mst_topology_mgr *mgr, num_slots = DIV_ROUND_UP(pbn, mgr->pbn_div); - if (num_slots > mgr->avail_slots) + /* max. time slots - one slot for MTP header */ + if (num_slots > 63) return -ENOSPC; return num_slots; } EXPORT_SYMBOL(drm_dp_find_vcpi_slots); static int drm_dp_init_vcpi(struct drm_dp_mst_topology_mgr *mgr, - struct drm_dp_vcpi *vcpi, int pbn) + struct drm_dp_vcpi *vcpi, int pbn, int slots) { - int num_slots; int ret; - num_slots = DIV_ROUND_UP(pbn, mgr->pbn_div); - - if (num_slots > mgr->avail_slots) + /* max. time slots - one slot for MTP header */ + if (slots > 63) return -ENOSPC; vcpi->pbn = pbn; - vcpi->aligned_pbn = num_slots * mgr->pbn_div; - vcpi->num_slots = num_slots; + vcpi->aligned_pbn = slots * mgr->pbn_div; + vcpi->num_slots = slots; ret = drm_dp_mst_assign_payload_id(mgr, vcpi); if (ret < 0) @@ -2509,7 +2504,8 @@ static int drm_dp_init_vcpi(struct drm_dp_mst_topology_mgr *mgr, * @pbn: payload bandwidth number to request * @slots: returned number of slots for this PBN. */ -bool drm_dp_mst_allocate_vcpi(struct drm_dp_mst_topology_mgr *mgr, struct drm_dp_mst_port *port, int pbn, int *slots) +bool drm_dp_mst_allocate_vcpi(struct drm_dp_mst_topology_mgr *mgr, + struct drm_dp_mst_port *port, int pbn, int slots) { int ret; @@ -2517,22 +2513,25 @@ bool drm_dp_mst_allocate_vcpi(struct drm_dp_mst_topology_mgr *mgr, struct drm_dp if (!port) return false; + if (slots < 0) + return false; + if (port->vcpi.vcpi > 0) { DRM_DEBUG_KMS("payload: vcpi %d already allocated for pbn %d - requested pbn %d\n", port->vcpi.vcpi, port->vcpi.pbn, pbn); if (pbn == port->vcpi.pbn) { - *slots = port->vcpi.num_slots; drm_dp_put_port(port); return true; } } - ret = drm_dp_init_vcpi(mgr, &port->vcpi, pbn); + ret = drm_dp_init_vcpi(mgr, &port->vcpi, pbn, slots); if (ret) { - DRM_DEBUG_KMS("failed to init vcpi %d %d %d\n", DIV_ROUND_UP(pbn, mgr->pbn_div), mgr->avail_slots, ret); + DRM_DEBUG_KMS("failed to init vcpi slots=%d max=63 ret=%d\n", + DIV_ROUND_UP(pbn, mgr->pbn_div), ret); goto out; } - DRM_DEBUG_KMS("initing vcpi for %d %d\n", pbn, port->vcpi.num_slots); - *slots = port->vcpi.num_slots; + DRM_DEBUG_KMS("initing vcpi for pbn=%d slots=%d\n", + pbn, port->vcpi.num_slots); drm_dp_put_port(port); return true; diff --git a/drivers/gpu/drm/drm_fb_cma_helper.c b/drivers/gpu/drm/drm_fb_cma_helper.c index 74cd393a6407..50abd1faf38f 100644 --- a/drivers/gpu/drm/drm_fb_cma_helper.c +++ b/drivers/gpu/drm/drm_fb_cma_helper.c @@ -177,7 +177,7 @@ struct drm_framebuffer *drm_fb_cma_create_with_funcs(struct drm_device *dev, int ret; int i; - info = drm_format_info(mode_cmd->pixel_format); + info = drm_get_format_info(dev, mode_cmd); if (!info) return ERR_PTR(-EINVAL); diff --git a/drivers/gpu/drm/drm_fourcc.c b/drivers/gpu/drm/drm_fourcc.c index 92bf3306d4b3..9c0152df45ad 100644 --- a/drivers/gpu/drm/drm_fourcc.c +++ b/drivers/gpu/drm/drm_fourcc.c @@ -207,6 +207,31 @@ const struct drm_format_info *drm_format_info(u32 format) EXPORT_SYMBOL(drm_format_info); /** + * drm_get_format_info - query information for a given framebuffer configuration + * @dev: DRM device + * @mode_cmd: metadata from the userspace fb creation request + * + * Returns: + * The instance of struct drm_format_info that describes the pixel format, or + * NULL if the format is unsupported. + */ +const struct drm_format_info * +drm_get_format_info(struct drm_device *dev, + const struct drm_mode_fb_cmd2 *mode_cmd) +{ + const struct drm_format_info *info = NULL; + + if (dev->mode_config.funcs->get_format_info) + info = dev->mode_config.funcs->get_format_info(mode_cmd); + + if (!info) + info = drm_format_info(mode_cmd->pixel_format); + + return info; +} +EXPORT_SYMBOL(drm_get_format_info); + +/** * drm_format_num_planes - get the number of planes for format * @format: pixel format (DRM_FORMAT_*) * diff --git a/drivers/gpu/drm/drm_framebuffer.c b/drivers/gpu/drm/drm_framebuffer.c index e4909aef75d7..e8f9c13a0afd 100644 --- a/drivers/gpu/drm/drm_framebuffer.c +++ b/drivers/gpu/drm/drm_framebuffer.c @@ -126,11 +126,31 @@ int drm_mode_addfb(struct drm_device *dev, return 0; } -static int framebuffer_check(const struct drm_mode_fb_cmd2 *r) +static int fb_plane_width(int width, + const struct drm_format_info *format, int plane) +{ + if (plane == 0) + return width; + + return DIV_ROUND_UP(width, format->hsub); +} + +static int fb_plane_height(int height, + const struct drm_format_info *format, int plane) +{ + if (plane == 0) + return height; + + return DIV_ROUND_UP(height, format->vsub); +} + +static int framebuffer_check(struct drm_device *dev, + const struct drm_mode_fb_cmd2 *r) { const struct drm_format_info *info; int i; + /* check if the format is supported at all */ info = __drm_format_info(r->pixel_format & ~DRM_FORMAT_BIG_ENDIAN); if (!info) { struct drm_format_name_buf format_name; @@ -140,19 +160,22 @@ static int framebuffer_check(const struct drm_mode_fb_cmd2 *r) return -EINVAL; } - if (r->width == 0 || r->width % info->hsub) { + /* now let the driver pick its own format info */ + info = drm_get_format_info(dev, r); + + if (r->width == 0) { DRM_DEBUG_KMS("bad framebuffer width %u\n", r->width); return -EINVAL; } - if (r->height == 0 || r->height % info->vsub) { + if (r->height == 0) { DRM_DEBUG_KMS("bad framebuffer height %u\n", r->height); return -EINVAL; } for (i = 0; i < info->num_planes; i++) { - unsigned int width = r->width / (i != 0 ? info->hsub : 1); - unsigned int height = r->height / (i != 0 ? info->vsub : 1); + unsigned int width = fb_plane_width(r->width, info, i); + unsigned int height = fb_plane_height(r->height, info, i); unsigned int cpp = info->cpp[i]; if (!r->handles[i]) { @@ -263,7 +286,7 @@ drm_internal_framebuffer_create(struct drm_device *dev, return ERR_PTR(-EINVAL); } - ret = framebuffer_check(r); + ret = framebuffer_check(dev, r); if (ret) return ERR_PTR(ret); @@ -816,10 +839,7 @@ int drm_framebuffer_plane_width(int width, if (plane >= fb->format->num_planes) return 0; - if (plane == 0) - return width; - - return width / fb->format->hsub; + return fb_plane_width(width, fb->format, plane); } EXPORT_SYMBOL(drm_framebuffer_plane_width); @@ -838,9 +858,6 @@ int drm_framebuffer_plane_height(int height, if (plane >= fb->format->num_planes) return 0; - if (plane == 0) - return height; - - return height / fb->format->vsub; + return fb_plane_height(height, fb->format, plane); } EXPORT_SYMBOL(drm_framebuffer_plane_height); diff --git a/drivers/gpu/drm/drm_internal.h b/drivers/gpu/drm/drm_internal.h index 92ff4b9393b1..3d8e8f878924 100644 --- a/drivers/gpu/drm/drm_internal.h +++ b/drivers/gpu/drm/drm_internal.h @@ -100,7 +100,7 @@ int drm_gem_open_ioctl(struct drm_device *dev, void *data, void drm_gem_open(struct drm_device *dev, struct drm_file *file_private); void drm_gem_release(struct drm_device *dev, struct drm_file *file_private); -/* drm_debugfs.c */ +/* drm_debugfs.c drm_debugfs_crc.c */ #if defined(CONFIG_DEBUG_FS) int drm_debugfs_init(struct drm_minor *minor, int minor_id, struct dentry *root); diff --git a/drivers/gpu/drm/drm_ioctl.c b/drivers/gpu/drm/drm_ioctl.c index a7c61c23685a..7d6deaa91281 100644 --- a/drivers/gpu/drm/drm_ioctl.c +++ b/drivers/gpu/drm/drm_ioctl.c @@ -28,6 +28,7 @@ * OTHER DEALINGS IN THE SOFTWARE. */ +#include <drm/drm_ioctl.h> #include <drm/drmP.h> #include <drm/drm_auth.h> #include "drm_legacy.h" diff --git a/drivers/gpu/drm/drm_irq.c b/drivers/gpu/drm/drm_irq.c index 53a526c7b24d..dac1b2593cb1 100644 --- a/drivers/gpu/drm/drm_irq.c +++ b/drivers/gpu/drm/drm_irq.c @@ -325,6 +325,8 @@ static void vblank_disable_and_save(struct drm_device *dev, unsigned int pipe) struct drm_vblank_crtc *vblank = &dev->vblank[pipe]; unsigned long irqflags; + assert_spin_locked(&dev->vbl_lock); + /* Prevent vblank irq processing while disabling vblank irqs, * so no updates of timestamps or count can happen after we've * disabled. Needed to prevent races in case of delayed irq's. @@ -384,7 +386,7 @@ void drm_vblank_cleanup(struct drm_device *dev) for (pipe = 0; pipe < dev->num_crtcs; pipe++) { struct drm_vblank_crtc *vblank = &dev->vblank[pipe]; - WARN_ON(vblank->enabled && + WARN_ON(READ_ONCE(vblank->enabled) && drm_core_check_feature(dev, DRIVER_MODESET)); del_timer_sync(&vblank->disable_timer); @@ -810,14 +812,6 @@ int drm_calc_vbltimestamp_from_scanoutpos(struct drm_device *dev, /* Return upper bound of timestamp precision error. */ *max_error = duration_ns; - /* Check if in vblank area: - * vpos is >=0 in video scanout area, but negative - * within vblank area, counting down the number of lines until - * start of scanout. - */ - if (vbl_status & DRM_SCANOUTPOS_IN_VBLANK) - ret |= DRM_VBLANKTIME_IN_VBLANK; - /* Convert scanout position into elapsed time at raw_time query * since start of scanout at first display scanline. delta_ns * can be negative if start of scanout hasn't happened yet. @@ -1105,11 +1099,16 @@ static int drm_vblank_enable(struct drm_device *dev, unsigned int pipe) */ ret = __enable_vblank(dev, pipe); DRM_DEBUG("enabling vblank on crtc %u, ret: %d\n", pipe, ret); - if (ret) + if (ret) { atomic_dec(&vblank->refcount); - else { - vblank->enabled = true; + } else { drm_update_vblank_count(dev, pipe, 0); + /* drm_update_vblank_count() includes a wmb so we just + * need to ensure that the compiler emits the write + * to mark the vblank as enabled after the call + * to drm_update_vblank_count(). + */ + WRITE_ONCE(vblank->enabled, true); } } @@ -1487,6 +1486,11 @@ int drm_legacy_modeset_ctl(struct drm_device *dev, void *data, return 0; } +static inline bool vblank_passed(u32 seq, u32 ref) +{ + return (seq - ref) <= (1 << 23); +} + static int drm_queue_vblank_event(struct drm_device *dev, unsigned int pipe, union drm_wait_vblank *vblwait, struct drm_file *file_priv) @@ -1517,7 +1521,7 @@ static int drm_queue_vblank_event(struct drm_device *dev, unsigned int pipe, * vblank disable, so no need for further locking. The reference from * drm_vblank_get() protects against vblank disable from another source. */ - if (!vblank->enabled) { + if (!READ_ONCE(vblank->enabled)) { ret = -EINVAL; goto err_unlock; } @@ -1537,7 +1541,7 @@ static int drm_queue_vblank_event(struct drm_device *dev, unsigned int pipe, vblwait->request.sequence); e->event.sequence = vblwait->request.sequence; - if ((seq - vblwait->request.sequence) <= (1 << 23)) { + if (vblank_passed(seq, vblwait->request.sequence)) { drm_vblank_put(dev, pipe); send_vblank_event(dev, e, seq, &now); vblwait->reply.sequence = seq; @@ -1559,6 +1563,17 @@ err_put: return ret; } +static bool drm_wait_vblank_is_query(union drm_wait_vblank *vblwait) +{ + if (vblwait->request.sequence) + return false; + + return _DRM_VBLANK_RELATIVE == + (vblwait->request.type & (_DRM_VBLANK_TYPES_MASK | + _DRM_VBLANK_EVENT | + _DRM_VBLANK_NEXTONMISS)); +} + /* * Wait for VBLANK. * @@ -1608,6 +1623,21 @@ int drm_wait_vblank(struct drm_device *dev, void *data, vblank = &dev->vblank[pipe]; + /* If the counter is currently enabled and accurate, short-circuit + * queries to return the cached timestamp of the last vblank. + */ + if (dev->vblank_disable_immediate && + drm_wait_vblank_is_query(vblwait) && + READ_ONCE(vblank->enabled)) { + struct timeval now; + + vblwait->reply.sequence = + drm_vblank_count_and_time(dev, pipe, &now); + vblwait->reply.tval_sec = now.tv_sec; + vblwait->reply.tval_usec = now.tv_usec; + return 0; + } + ret = drm_vblank_get(dev, pipe); if (ret) { DRM_DEBUG("crtc %d failed to acquire vblank counter, %d\n", pipe, ret); @@ -1627,9 +1657,8 @@ int drm_wait_vblank(struct drm_device *dev, void *data, } if ((flags & _DRM_VBLANK_NEXTONMISS) && - (seq - vblwait->request.sequence) <= (1 << 23)) { + vblank_passed(seq, vblwait->request.sequence)) vblwait->request.sequence = seq + 1; - } if (flags & _DRM_VBLANK_EVENT) { /* must hold on to the vblank ref until the event fires @@ -1642,10 +1671,9 @@ int drm_wait_vblank(struct drm_device *dev, void *data, DRM_DEBUG("waiting on vblank count %u, crtc %u\n", vblwait->request.sequence, pipe); DRM_WAIT_ON(ret, vblank->queue, 3 * HZ, - (((drm_vblank_count(dev, pipe) - - vblwait->request.sequence) <= (1 << 23)) || - !vblank->enabled || - !dev->irq_enabled)); + vblank_passed(drm_vblank_count(dev, pipe), + vblwait->request.sequence) || + !READ_ONCE(vblank->enabled)); } if (ret != -EINTR) { @@ -1679,7 +1707,7 @@ static void drm_handle_vblank_events(struct drm_device *dev, unsigned int pipe) list_for_each_entry_safe(e, t, &dev->vblank_event_list, base.link) { if (e->pipe != pipe) continue; - if ((seq - e->event.sequence) > (1<<23)) + if (!vblank_passed(seq, e->event.sequence)) continue; DRM_DEBUG("vblank event on %u, current %u\n", @@ -1707,6 +1735,7 @@ bool drm_handle_vblank(struct drm_device *dev, unsigned int pipe) { struct drm_vblank_crtc *vblank = &dev->vblank[pipe]; unsigned long irqflags; + bool disable_irq; if (WARN_ON_ONCE(!dev->num_crtcs)) return false; @@ -1734,20 +1763,23 @@ bool drm_handle_vblank(struct drm_device *dev, unsigned int pipe) spin_unlock(&dev->vblank_time_lock); wake_up(&vblank->queue); - drm_handle_vblank_events(dev, pipe); /* With instant-off, we defer disabling the interrupt until after - * we finish processing the following vblank. The disable has to - * be last (after drm_handle_vblank_events) so that the timestamp - * is always accurate. + * we finish processing the following vblank after all events have + * been signaled. The disable has to be last (after + * drm_handle_vblank_events) so that the timestamp is always accurate. */ - if (dev->vblank_disable_immediate && - drm_vblank_offdelay > 0 && - !atomic_read(&vblank->refcount)) - vblank_disable_fn((unsigned long)vblank); + disable_irq = (dev->vblank_disable_immediate && + drm_vblank_offdelay > 0 && + !atomic_read(&vblank->refcount)); + + drm_handle_vblank_events(dev, pipe); spin_unlock_irqrestore(&dev->event_lock, irqflags); + if (disable_irq) + vblank_disable_fn((unsigned long)vblank); + return true; } EXPORT_SYMBOL(drm_handle_vblank); diff --git a/drivers/gpu/drm/drm_modeset_helper.c b/drivers/gpu/drm/drm_modeset_helper.c index cc44a9a4b004..2b33825f2f93 100644 --- a/drivers/gpu/drm/drm_modeset_helper.c +++ b/drivers/gpu/drm/drm_modeset_helper.c @@ -78,7 +78,7 @@ void drm_helper_mode_fill_fb_struct(struct drm_device *dev, int i; fb->dev = dev; - fb->format = drm_format_info(mode_cmd->pixel_format); + fb->format = drm_get_format_info(dev, mode_cmd); fb->width = mode_cmd->width; fb->height = mode_cmd->height; for (i = 0; i < 4; i++) { diff --git a/drivers/gpu/drm/drm_plane.c b/drivers/gpu/drm/drm_plane.c index a22e76837065..bc71aa2b7872 100644 --- a/drivers/gpu/drm/drm_plane.c +++ b/drivers/gpu/drm/drm_plane.c @@ -277,6 +277,12 @@ EXPORT_SYMBOL(drm_plane_from_index); * * Used when the plane's current framebuffer is destroyed, * and when restoring fbdev mode. + * + * Note that this function is not suitable for atomic drivers, since it doesn't + * wire through the lock acquisition context properly and hence can't handle + * retries or driver private locks. You probably want to use + * drm_atomic_helper_disable_plane() or + * drm_atomic_helper_disable_planes_on_crtc() instead. */ void drm_plane_force_disable(struct drm_plane *plane) { @@ -285,8 +291,10 @@ void drm_plane_force_disable(struct drm_plane *plane) if (!plane->fb) return; + WARN_ON(drm_drv_uses_atomic_modeset(plane->dev)); + plane->old_fb = plane->fb; - ret = plane->funcs->disable_plane(plane); + ret = plane->funcs->disable_plane(plane, NULL); if (ret) { DRM_ERROR("failed to disable plane with busy fb\n"); plane->old_fb = NULL; @@ -457,14 +465,15 @@ static int __setplane_internal(struct drm_plane *plane, uint32_t crtc_w, uint32_t crtc_h, /* src_{x,y,w,h} values are 16.16 fixed point */ uint32_t src_x, uint32_t src_y, - uint32_t src_w, uint32_t src_h) + uint32_t src_w, uint32_t src_h, + struct drm_modeset_acquire_ctx *ctx) { int ret = 0; /* No fb means shut it down */ if (!fb) { plane->old_fb = plane->fb; - ret = plane->funcs->disable_plane(plane); + ret = plane->funcs->disable_plane(plane, ctx); if (!ret) { plane->crtc = NULL; plane->fb = NULL; @@ -509,7 +518,7 @@ static int __setplane_internal(struct drm_plane *plane, plane->old_fb = plane->fb; ret = plane->funcs->update_plane(plane, crtc, fb, crtc_x, crtc_y, crtc_w, crtc_h, - src_x, src_y, src_w, src_h); + src_x, src_y, src_w, src_h, ctx); if (!ret) { plane->crtc = crtc; plane->fb = fb; @@ -537,13 +546,25 @@ static int setplane_internal(struct drm_plane *plane, uint32_t src_x, uint32_t src_y, uint32_t src_w, uint32_t src_h) { + struct drm_modeset_acquire_ctx ctx; int ret; - drm_modeset_lock_all(plane->dev); + drm_modeset_acquire_init(&ctx, 0); +retry: + ret = drm_modeset_lock_all_ctx(plane->dev, &ctx); + if (ret) + goto fail; ret = __setplane_internal(plane, crtc, fb, crtc_x, crtc_y, crtc_w, crtc_h, - src_x, src_y, src_w, src_h); - drm_modeset_unlock_all(plane->dev); + src_x, src_y, src_w, src_h, &ctx); + +fail: + if (ret == -EDEADLK) { + drm_modeset_backoff(&ctx); + goto retry; + } + drm_modeset_drop_locks(&ctx); + drm_modeset_acquire_fini(&ctx); return ret; } @@ -613,11 +634,21 @@ static int drm_mode_cursor_universal(struct drm_crtc *crtc, int32_t crtc_x, crtc_y; uint32_t crtc_w = 0, crtc_h = 0; uint32_t src_w = 0, src_h = 0; + struct drm_modeset_acquire_ctx ctx; int ret = 0; BUG_ON(!crtc->cursor); WARN_ON(crtc->cursor->crtc != crtc && crtc->cursor->crtc != NULL); + drm_modeset_acquire_init(&ctx, 0); +retry: + ret = drm_modeset_lock(&crtc->mutex, &ctx); + if (ret) + goto fail; + ret = drm_modeset_lock(&crtc->cursor->mutex, &ctx); + if (ret) + goto fail; + /* * Obtain fb we'll be using (either new or existing) and take an extra * reference to it if fb != null. setplane will take care of dropping @@ -662,7 +693,7 @@ static int drm_mode_cursor_universal(struct drm_crtc *crtc, */ ret = __setplane_internal(crtc->cursor, crtc, fb, crtc_x, crtc_y, crtc_w, crtc_h, - 0, 0, src_w, src_h); + 0, 0, src_w, src_h, &ctx); /* Update successful; save new cursor position, if necessary */ if (ret == 0 && req->flags & DRM_MODE_CURSOR_MOVE) { @@ -670,6 +701,15 @@ static int drm_mode_cursor_universal(struct drm_crtc *crtc, crtc->cursor_y = req->y; } +fail: + if (ret == -EDEADLK) { + drm_modeset_backoff(&ctx); + goto retry; + } + + drm_modeset_drop_locks(&ctx); + drm_modeset_acquire_fini(&ctx); + return ret; } @@ -696,12 +736,10 @@ static int drm_mode_cursor_common(struct drm_device *dev, * If this crtc has a universal cursor plane, call that plane's update * handler rather than using legacy cursor handlers. */ - drm_modeset_lock_crtc(crtc, crtc->cursor); - if (crtc->cursor) { - ret = drm_mode_cursor_universal(crtc, req, file_priv); - goto out; - } + if (crtc->cursor) + return drm_mode_cursor_universal(crtc, req, file_priv); + drm_modeset_lock_crtc(crtc, crtc->cursor); if (req->flags & DRM_MODE_CURSOR_BO) { if (!crtc->funcs->cursor_set && !crtc->funcs->cursor_set2) { ret = -ENXIO; @@ -765,6 +803,7 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev, struct drm_framebuffer *fb = NULL; struct drm_pending_vblank_event *e = NULL; u32 target_vblank = page_flip->sequence; + struct drm_modeset_acquire_ctx ctx; int ret = -EINVAL; if (!drm_core_check_feature(dev, DRIVER_MODESET)) @@ -828,7 +867,15 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev, return -EINVAL; } - drm_modeset_lock_crtc(crtc, crtc->primary); + drm_modeset_acquire_init(&ctx, 0); +retry: + ret = drm_modeset_lock(&crtc->mutex, &ctx); + if (ret) + goto out; + ret = drm_modeset_lock(&crtc->primary->mutex, &ctx); + if (ret) + goto out; + if (crtc->primary->fb == NULL) { /* The framebuffer is currently unbound, presumably * due to a hotplug event, that userspace has not @@ -876,6 +923,7 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev, ret = drm_event_reserve_init(dev, file_priv, &e->base, &e->event.base); if (ret) { kfree(e); + e = NULL; goto out; } } @@ -884,9 +932,11 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev, if (crtc->funcs->page_flip_target) ret = crtc->funcs->page_flip_target(crtc, fb, e, page_flip->flags, - target_vblank); + target_vblank, + &ctx); else - ret = crtc->funcs->page_flip(crtc, fb, e, page_flip->flags); + ret = crtc->funcs->page_flip(crtc, fb, e, page_flip->flags, + &ctx); if (ret) { if (page_flip->flags & DRM_MODE_PAGE_FLIP_EVENT) drm_event_cancel_free(dev, &e->base); @@ -906,7 +956,14 @@ out: if (crtc->primary->old_fb) drm_framebuffer_put(crtc->primary->old_fb); crtc->primary->old_fb = NULL; - drm_modeset_unlock_crtc(crtc); + + if (ret == -EDEADLK) { + drm_modeset_backoff(&ctx); + goto retry; + } + + drm_modeset_drop_locks(&ctx); + drm_modeset_acquire_fini(&ctx); return ret; } diff --git a/drivers/gpu/drm/drm_plane_helper.c b/drivers/gpu/drm/drm_plane_helper.c index de1ac5e08f4d..b84a295230fc 100644 --- a/drivers/gpu/drm/drm_plane_helper.c +++ b/drivers/gpu/drm/drm_plane_helper.c @@ -275,6 +275,7 @@ EXPORT_SYMBOL(drm_plane_helper_check_update); * @src_y: y offset of @fb for panning * @src_w: width of source rectangle in @fb * @src_h: height of source rectangle in @fb + * @ctx: lock acquire context, not used here * * Provides a default plane update handler for primary planes. This is handler * is called in response to a userspace SetPlane operation on the plane with a @@ -303,7 +304,8 @@ int drm_primary_helper_update(struct drm_plane *plane, struct drm_crtc *crtc, int crtc_x, int crtc_y, unsigned int crtc_w, unsigned int crtc_h, uint32_t src_x, uint32_t src_y, - uint32_t src_w, uint32_t src_h) + uint32_t src_w, uint32_t src_h, + struct drm_modeset_acquire_ctx *ctx) { struct drm_mode_set set = { .crtc = crtc, @@ -347,7 +349,7 @@ int drm_primary_helper_update(struct drm_plane *plane, struct drm_crtc *crtc, * provides their own disable function, this will just * wind up returning -EINVAL to userspace. */ - return plane->funcs->disable_plane(plane); + return plane->funcs->disable_plane(plane, ctx); /* Find current connectors for CRTC */ num_connectors = get_connectors_for_crtc(crtc, NULL, 0); @@ -369,7 +371,7 @@ int drm_primary_helper_update(struct drm_plane *plane, struct drm_crtc *crtc, * drm_mode_setplane() already handles the basic refcounting for the * framebuffers involved in this operation. */ - ret = crtc->funcs->set_config(&set); + ret = crtc->funcs->set_config(&set, ctx); kfree(connector_list); return ret; @@ -396,7 +398,8 @@ EXPORT_SYMBOL(drm_primary_helper_update); * RETURNS: * Unconditionally returns -EINVAL. */ -int drm_primary_helper_disable(struct drm_plane *plane) +int drm_primary_helper_disable(struct drm_plane *plane, + struct drm_modeset_acquire_ctx *ctx) { return -EINVAL; } diff --git a/drivers/gpu/drm/drm_simple_kms_helper.c b/drivers/gpu/drm/drm_simple_kms_helper.c index 16789faa9291..e084f9f8ca66 100644 --- a/drivers/gpu/drm/drm_simple_kms_helper.c +++ b/drivers/gpu/drm/drm_simple_kms_helper.c @@ -114,7 +114,7 @@ static int drm_simple_kms_plane_atomic_check(struct drm_plane *plane, } static void drm_simple_kms_plane_atomic_update(struct drm_plane *plane, - struct drm_plane_state *pstate) + struct drm_plane_state *old_pstate) { struct drm_simple_display_pipe *pipe; @@ -122,7 +122,7 @@ static void drm_simple_kms_plane_atomic_update(struct drm_plane *plane, if (!pipe->funcs || !pipe->funcs->update) return; - pipe->funcs->update(pipe, pstate); + pipe->funcs->update(pipe, old_pstate); } static int drm_simple_kms_plane_prepare_fb(struct drm_plane *plane, diff --git a/drivers/gpu/drm/gma500/gma_display.c b/drivers/gpu/drm/gma500/gma_display.c index d1c5642b1c1e..93ff46535c04 100644 --- a/drivers/gpu/drm/gma500/gma_display.c +++ b/drivers/gpu/drm/gma500/gma_display.c @@ -514,17 +514,18 @@ void gma_crtc_destroy(struct drm_crtc *crtc) kfree(gma_crtc); } -int gma_crtc_set_config(struct drm_mode_set *set) +int gma_crtc_set_config(struct drm_mode_set *set, + struct drm_modeset_acquire_ctx *ctx) { struct drm_device *dev = set->crtc->dev; struct drm_psb_private *dev_priv = dev->dev_private; int ret; if (!dev_priv->rpm_enabled) - return drm_crtc_helper_set_config(set); + return drm_crtc_helper_set_config(set, ctx); pm_runtime_forbid(&dev->pdev->dev); - ret = drm_crtc_helper_set_config(set); + ret = drm_crtc_helper_set_config(set, ctx); pm_runtime_allow(&dev->pdev->dev); return ret; diff --git a/drivers/gpu/drm/gma500/gma_display.h b/drivers/gpu/drm/gma500/gma_display.h index e72dd08b701b..166e608923db 100644 --- a/drivers/gpu/drm/gma500/gma_display.h +++ b/drivers/gpu/drm/gma500/gma_display.h @@ -79,7 +79,8 @@ extern void gma_crtc_prepare(struct drm_crtc *crtc); extern void gma_crtc_commit(struct drm_crtc *crtc); extern void gma_crtc_disable(struct drm_crtc *crtc); extern void gma_crtc_destroy(struct drm_crtc *crtc); -extern int gma_crtc_set_config(struct drm_mode_set *set); +extern int gma_crtc_set_config(struct drm_mode_set *set, + struct drm_modeset_acquire_ctx *ctx); extern void gma_crtc_save(struct drm_crtc *crtc); extern void gma_crtc_restore(struct drm_crtc *crtc); diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index 03d9e45694c9..98b17070a123 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -1307,8 +1307,6 @@ void i915_driver_unload(struct drm_device *dev) { struct drm_i915_private *dev_priv = to_i915(dev); struct pci_dev *pdev = dev_priv->drm.pdev; - struct drm_modeset_acquire_ctx ctx; - int ret; intel_fbdev_fini(dev); @@ -1317,23 +1315,7 @@ void i915_driver_unload(struct drm_device *dev) intel_display_power_get(dev_priv, POWER_DOMAIN_INIT); - drm_modeset_acquire_init(&ctx, 0); - while (1) { - ret = drm_modeset_lock_all_ctx(dev, &ctx); - if (!ret) - ret = drm_atomic_helper_disable_all(dev, &ctx); - - if (ret != -EDEADLK) - break; - - drm_modeset_backoff(&ctx); - } - - if (ret) - DRM_ERROR("Disabling all crtc's during unload failed with %i\n", ret); - - drm_modeset_drop_locks(&ctx); - drm_modeset_acquire_fini(&ctx); + drm_atomic_helper_shutdown(dev); intel_gvt_cleanup(dev_priv); diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 010e5ddb198a..e27ea89efd67 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -13426,7 +13426,8 @@ intel_legacy_cursor_update(struct drm_plane *plane, int crtc_x, int crtc_y, unsigned int crtc_w, unsigned int crtc_h, uint32_t src_x, uint32_t src_y, - uint32_t src_w, uint32_t src_h) + uint32_t src_w, uint32_t src_h, + struct drm_modeset_acquire_ctx *ctx) { struct drm_i915_private *dev_priv = to_i915(crtc->dev); int ret; @@ -13539,7 +13540,7 @@ out_free: slow: return drm_atomic_helper_update_plane(plane, crtc, fb, crtc_x, crtc_y, crtc_w, crtc_h, - src_x, src_y, src_w, src_h); + src_x, src_y, src_w, src_h, ctx); } static const struct drm_plane_funcs intel_cursor_plane_funcs = { diff --git a/drivers/gpu/drm/i915/intel_dp_mst.c b/drivers/gpu/drm/i915/intel_dp_mst.c index 094cbdcbcd6d..c1f62eb07c07 100644 --- a/drivers/gpu/drm/i915/intel_dp_mst.c +++ b/drivers/gpu/drm/i915/intel_dp_mst.c @@ -149,7 +149,6 @@ static void intel_mst_pre_enable_dp(struct intel_encoder *encoder, to_intel_connector(conn_state->connector); int ret; uint32_t temp; - int slots; /* MST encoders are bound to a crtc, not to a connector, * force the mapping here for get_hw_state. @@ -165,7 +164,8 @@ static void intel_mst_pre_enable_dp(struct intel_encoder *encoder, ret = drm_dp_mst_allocate_vcpi(&intel_dp->mst_mgr, connector->port, - pipe_config->pbn, &slots); + pipe_config->pbn, + pipe_config->dp_m_n.tu); if (ret == false) { DRM_ERROR("failed to allocate vcpi\n"); return; diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c index 0ffb8affef35..60a5451ae0b9 100644 --- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c +++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c @@ -37,7 +37,8 @@ static int mdp5_update_cursor_plane_legacy(struct drm_plane *plane, int crtc_x, int crtc_y, unsigned int crtc_w, unsigned int crtc_h, uint32_t src_x, uint32_t src_y, - uint32_t src_w, uint32_t src_h); + uint32_t src_w, uint32_t src_h, + struct drm_modeset_acquire_ctx *ctx); static void set_scanout_locked(struct drm_plane *plane, struct drm_framebuffer *fb); @@ -886,7 +887,8 @@ static int mdp5_update_cursor_plane_legacy(struct drm_plane *plane, int crtc_x, int crtc_y, unsigned int crtc_w, unsigned int crtc_h, uint32_t src_x, uint32_t src_y, - uint32_t src_w, uint32_t src_h) + uint32_t src_w, uint32_t src_h, + struct drm_modeset_acquire_ctx *ctx) { struct drm_plane_state *plane_state, *new_plane_state; struct mdp5_plane_state *mdp5_pstate; @@ -954,7 +956,7 @@ slow_free: slow: return drm_atomic_helper_update_plane(plane, crtc, fb, crtc_x, crtc_y, crtc_w, crtc_h, - src_x, src_y, src_w, src_h); + src_x, src_y, src_w, src_h, ctx); } enum mdp5_pipe mdp5_plane_pipe(struct drm_plane *plane) diff --git a/drivers/gpu/drm/nouveau/dispnv04/crtc.c b/drivers/gpu/drm/nouveau/dispnv04/crtc.c index ab7b69c11d40..43ab560de7f9 100644 --- a/drivers/gpu/drm/nouveau/dispnv04/crtc.c +++ b/drivers/gpu/drm/nouveau/dispnv04/crtc.c @@ -1031,8 +1031,9 @@ nv04_crtc_cursor_move(struct drm_crtc *crtc, int x, int y) return 0; } -int -nouveau_crtc_set_config(struct drm_mode_set *set) +static int +nouveau_crtc_set_config(struct drm_mode_set *set, + struct drm_modeset_acquire_ctx *ctx) { struct drm_device *dev; struct nouveau_drm *drm; @@ -1049,7 +1050,7 @@ nouveau_crtc_set_config(struct drm_mode_set *set) if (ret < 0 && ret != -EACCES) return ret; - ret = drm_crtc_helper_set_config(set); + ret = drm_crtc_helper_set_config(set, ctx); drm = nouveau_drm(dev); diff --git a/drivers/gpu/drm/nouveau/dispnv04/overlay.c b/drivers/gpu/drm/nouveau/dispnv04/overlay.c index 5319f2a7f24d..e54944d23268 100644 --- a/drivers/gpu/drm/nouveau/dispnv04/overlay.c +++ b/drivers/gpu/drm/nouveau/dispnv04/overlay.c @@ -94,7 +94,8 @@ nv10_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, struct drm_framebuffer *fb, int crtc_x, int crtc_y, unsigned int crtc_w, unsigned int crtc_h, uint32_t src_x, uint32_t src_y, - uint32_t src_w, uint32_t src_h) + uint32_t src_w, uint32_t src_h, + struct drm_modeset_acquire_ctx *ctx) { struct nouveau_drm *drm = nouveau_drm(plane->dev); struct nvif_object *dev = &drm->client.device.object; @@ -172,7 +173,8 @@ nv10_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, } static int -nv10_disable_plane(struct drm_plane *plane) +nv10_disable_plane(struct drm_plane *plane, + struct drm_modeset_acquire_ctx *ctx) { struct nvif_object *dev = &nouveau_drm(plane->dev)->client.device.object; struct nouveau_plane *nv_plane = @@ -190,7 +192,7 @@ nv10_disable_plane(struct drm_plane *plane) static void nv_destroy_plane(struct drm_plane *plane) { - plane->funcs->disable_plane(plane); + drm_plane_force_disable(plane); drm_plane_cleanup(plane); kfree(plane); } @@ -331,7 +333,7 @@ nv10_overlay_init(struct drm_device *device) plane->set_params = nv10_set_params; nv10_set_params(plane); - nv10_disable_plane(&plane->base); + drm_plane_force_disable(&plane->base); return; cleanup: drm_plane_cleanup(&plane->base); @@ -345,7 +347,8 @@ nv04_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, struct drm_framebuffer *fb, int crtc_x, int crtc_y, unsigned int crtc_w, unsigned int crtc_h, uint32_t src_x, uint32_t src_y, - uint32_t src_w, uint32_t src_h) + uint32_t src_w, uint32_t src_h, + struct drm_modeset_acquire_ctx *ctx) { struct nvif_object *dev = &nouveau_drm(plane->dev)->client.device.object; struct nouveau_plane *nv_plane = @@ -425,7 +428,8 @@ nv04_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, } static int -nv04_disable_plane(struct drm_plane *plane) +nv04_disable_plane(struct drm_plane *plane, + struct drm_modeset_acquire_ctx *ctx) { struct nvif_object *dev = &nouveau_drm(plane->dev)->client.device.object; struct nouveau_plane *nv_plane = @@ -483,7 +487,7 @@ nv04_overlay_init(struct drm_device *device) drm_object_attach_property(&plane->base.base, plane->props.brightness, plane->brightness); - nv04_disable_plane(&plane->base); + drm_plane_force_disable(&plane->base); return; cleanup: drm_plane_cleanup(&plane->base); diff --git a/drivers/gpu/drm/nouveau/nouveau_display.c b/drivers/gpu/drm/nouveau/nouveau_display.c index 33269c7df30f..6104f61b00fc 100644 --- a/drivers/gpu/drm/nouveau/nouveau_display.c +++ b/drivers/gpu/drm/nouveau/nouveau_display.c @@ -436,8 +436,12 @@ nouveau_display_fini(struct drm_device *dev, bool suspend) struct drm_connector *connector; struct drm_crtc *crtc; - if (!suspend) - drm_crtc_force_disable_all(dev); + if (!suspend) { + if (drm_drv_uses_atomic_modeset(dev)) + drm_atomic_helper_shutdown(dev); + else + drm_crtc_force_disable_all(dev); + } /* Make sure that drm and hw vblank irqs get properly disabled. */ drm_for_each_crtc(crtc, dev) @@ -788,7 +792,8 @@ fail: int nouveau_crtc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb, - struct drm_pending_vblank_event *event, u32 flags) + struct drm_pending_vblank_event *event, u32 flags, + struct drm_modeset_acquire_ctx *ctx) { const int swap_interval = (flags & DRM_MODE_PAGE_FLIP_ASYNC) ? 0 : 1; struct drm_device *dev = crtc->dev; diff --git a/drivers/gpu/drm/nouveau/nouveau_display.h b/drivers/gpu/drm/nouveau/nouveau_display.h index 4a75df06c139..e1d772d39488 100644 --- a/drivers/gpu/drm/nouveau/nouveau_display.h +++ b/drivers/gpu/drm/nouveau/nouveau_display.h @@ -76,7 +76,8 @@ int nouveau_display_vblstamp(struct drm_device *, unsigned int, int *, int nouveau_crtc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb, struct drm_pending_vblank_event *event, - uint32_t page_flip_flags); + uint32_t page_flip_flags, + struct drm_modeset_acquire_ctx *ctx); int nouveau_finish_page_flip(struct nouveau_channel *, struct nouveau_page_flip_state *); @@ -87,7 +88,6 @@ int nouveau_display_dumb_map_offset(struct drm_file *, struct drm_device *, void nouveau_hdmi_mode_set(struct drm_encoder *, struct drm_display_mode *); -int nouveau_crtc_set_config(struct drm_mode_set *set); #ifdef CONFIG_DRM_NOUVEAU_BACKLIGHT extern int nouveau_backlight_init(struct drm_device *); extern void nouveau_backlight_exit(struct drm_device *); diff --git a/drivers/gpu/drm/nouveau/nouveau_vga.c b/drivers/gpu/drm/nouveau/nouveau_vga.c index ccb597eac538..a4aacbc0cec8 100644 --- a/drivers/gpu/drm/nouveau/nouveau_vga.c +++ b/drivers/gpu/drm/nouveau/nouveau_vga.c @@ -95,6 +95,10 @@ nouveau_vga_init(struct nouveau_drm *drm) vga_client_register(dev->pdev, dev, NULL, nouveau_vga_set_decode); + /* don't register Thunderbolt eGPU with vga_switcheroo */ + if (pci_is_thunderbolt_attached(dev->pdev)) + return; + if (nouveau_runtime_pm == 1) runtime = true; if ((nouveau_runtime_pm == -1) && (nouveau_is_optimus() || nouveau_is_v1_dsm())) @@ -111,6 +115,11 @@ nouveau_vga_fini(struct nouveau_drm *drm) struct drm_device *dev = drm->dev; bool runtime = false; + vga_client_register(dev->pdev, NULL, NULL, NULL); + + if (pci_is_thunderbolt_attached(dev->pdev)) + return; + if (nouveau_runtime_pm == 1) runtime = true; if ((nouveau_runtime_pm == -1) && (nouveau_is_optimus() || nouveau_is_v1_dsm())) @@ -119,7 +128,6 @@ nouveau_vga_fini(struct nouveau_drm *drm) vga_switcheroo_unregister_client(dev->pdev); if (runtime && nouveau_is_v1_dsm() && !nouveau_is_optimus()) vga_switcheroo_fini_domain_pm_ops(drm->dev->dev); - vga_client_register(dev->pdev, NULL, NULL, NULL); } diff --git a/drivers/gpu/drm/nouveau/nv50_display.c b/drivers/gpu/drm/nouveau/nv50_display.c index 7ad1ee580cf0..418872b493a3 100644 --- a/drivers/gpu/drm/nouveau/nv50_display.c +++ b/drivers/gpu/drm/nouveau/nv50_display.c @@ -2895,7 +2895,8 @@ nv50_msto_enable(struct drm_encoder *encoder) if (WARN_ON(!mstc)) return; - r = drm_dp_mst_allocate_vcpi(&mstm->mgr, mstc->port, mstc->pbn, &slots); + slots = drm_dp_find_vcpi_slots(&mstm->mgr, mstc->pbn); + r = drm_dp_mst_allocate_vcpi(&mstm->mgr, mstc->port, mstc->pbn, slots); WARN_ON(!r); if (mstm->outp->dcb->sorconf.link & 1) diff --git a/drivers/gpu/drm/radeon/radeon_device.c b/drivers/gpu/drm/radeon/radeon_device.c index 64b02f3c7906..6ecf42783d4b 100644 --- a/drivers/gpu/drm/radeon/radeon_device.c +++ b/drivers/gpu/drm/radeon/radeon_device.c @@ -1468,7 +1468,9 @@ int radeon_device_init(struct radeon_device *rdev, if (rdev->flags & RADEON_IS_PX) runtime = true; - vga_switcheroo_register_client(rdev->pdev, &radeon_switcheroo_ops, runtime); + if (!pci_is_thunderbolt_attached(rdev->pdev)) + vga_switcheroo_register_client(rdev->pdev, + &radeon_switcheroo_ops, runtime); if (runtime) vga_switcheroo_init_domain_pm_ops(rdev->dev, &rdev->vga_pm_domain); @@ -1561,7 +1563,8 @@ void radeon_device_fini(struct radeon_device *rdev) /* evict vram memory */ radeon_bo_evict_vram(rdev); radeon_fini(rdev); - vga_switcheroo_unregister_client(rdev->pdev); + if (!pci_is_thunderbolt_attached(rdev->pdev)) + vga_switcheroo_unregister_client(rdev->pdev); if (rdev->flags & RADEON_IS_PX) vga_switcheroo_fini_domain_pm_ops(rdev->dev); vga_client_register(rdev->pdev, NULL, NULL, NULL); diff --git a/drivers/gpu/drm/radeon/radeon_display.c b/drivers/gpu/drm/radeon/radeon_display.c index aea8b62835a4..146297a702ab 100644 --- a/drivers/gpu/drm/radeon/radeon_display.c +++ b/drivers/gpu/drm/radeon/radeon_display.c @@ -485,7 +485,8 @@ static int radeon_crtc_page_flip_target(struct drm_crtc *crtc, struct drm_framebuffer *fb, struct drm_pending_vblank_event *event, uint32_t page_flip_flags, - uint32_t target) + uint32_t target, + struct drm_modeset_acquire_ctx *ctx) { struct drm_device *dev = crtc->dev; struct radeon_device *rdev = dev->dev_private; @@ -623,7 +624,8 @@ cleanup: } static int -radeon_crtc_set_config(struct drm_mode_set *set) +radeon_crtc_set_config(struct drm_mode_set *set, + struct drm_modeset_acquire_ctx *ctx) { struct drm_device *dev; struct radeon_device *rdev; @@ -640,7 +642,7 @@ radeon_crtc_set_config(struct drm_mode_set *set) if (ret < 0) return ret; - ret = drm_crtc_helper_set_config(set); + ret = drm_crtc_helper_set_config(set, ctx); list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) if (crtc->enabled) diff --git a/drivers/gpu/drm/radeon/radeon_dp_mst.c b/drivers/gpu/drm/radeon/radeon_dp_mst.c index 7d5ada3980dc..6598306dca9b 100644 --- a/drivers/gpu/drm/radeon/radeon_dp_mst.c +++ b/drivers/gpu/drm/radeon/radeon_dp_mst.c @@ -453,9 +453,11 @@ radeon_mst_encoder_dpms(struct drm_encoder *encoder, int mode) DRM_DEBUG_KMS("dig encoder is %d %d %d\n", dig_enc->dig_encoder, dig_enc->linkb, radeon_crtc->crtc_id); + slots = drm_dp_find_vcpi_slots(&radeon_connector->mst_port->mst_mgr, + mst_enc->pbn); ret = drm_dp_mst_allocate_vcpi(&radeon_connector->mst_port->mst_mgr, radeon_connector->port, - mst_enc->pbn, &slots); + mst_enc->pbn, slots); ret = drm_dp_update_payload_part1(&radeon_connector->mst_port->mst_mgr); radeon_dp_mst_set_be_cntl(primary, mst_enc, diff --git a/drivers/gpu/drm/radeon/radeon_kms.c b/drivers/gpu/drm/radeon/radeon_kms.c index a32a62e03a44..e3e7cb1d10a2 100644 --- a/drivers/gpu/drm/radeon/radeon_kms.c +++ b/drivers/gpu/drm/radeon/radeon_kms.c @@ -115,7 +115,8 @@ int radeon_driver_load_kms(struct drm_device *dev, unsigned long flags) if ((radeon_runtime_pm != 0) && radeon_has_atpx() && - ((flags & RADEON_IS_IGP) == 0)) + ((flags & RADEON_IS_IGP) == 0) && + !pci_is_thunderbolt_attached(rdev->pdev)) flags |= RADEON_IS_PX; /* radeon_device_init should report only fatal error diff --git a/drivers/gpu/drm/rockchip/Kconfig b/drivers/gpu/drm/rockchip/Kconfig index 0e4eb845cbb0..50c41c0a50ef 100644 --- a/drivers/gpu/drm/rockchip/Kconfig +++ b/drivers/gpu/drm/rockchip/Kconfig @@ -13,7 +13,7 @@ config DRM_ROCKCHIP IP found on the SoC. config ROCKCHIP_ANALOGIX_DP - tristate "Rockchip specific extensions for Analogix DP driver" + bool "Rockchip specific extensions for Analogix DP driver" depends on DRM_ROCKCHIP select DRM_ANALOGIX_DP help @@ -22,7 +22,7 @@ config ROCKCHIP_ANALOGIX_DP on RK3288 based SoC, you should selet this option. config ROCKCHIP_CDN_DP - tristate "Rockchip cdn DP" + bool "Rockchip cdn DP" depends on DRM_ROCKCHIP depends on EXTCON select SND_SOC_HDMI_CODEC if SND_SOC @@ -33,7 +33,7 @@ config ROCKCHIP_CDN_DP option. config ROCKCHIP_DW_HDMI - tristate "Rockchip specific extensions for Synopsys DW HDMI" + bool "Rockchip specific extensions for Synopsys DW HDMI" depends on DRM_ROCKCHIP select DRM_DW_HDMI help @@ -43,7 +43,7 @@ config ROCKCHIP_DW_HDMI option. config ROCKCHIP_DW_MIPI_DSI - tristate "Rockchip specific extensions for Synopsys DW MIPI DSI" + bool "Rockchip specific extensions for Synopsys DW MIPI DSI" depends on DRM_ROCKCHIP select DRM_MIPI_DSI help @@ -53,7 +53,7 @@ config ROCKCHIP_DW_MIPI_DSI option. config ROCKCHIP_INNO_HDMI - tristate "Rockchip specific extensions for Innosilicon HDMI" + bool "Rockchip specific extensions for Innosilicon HDMI" depends on DRM_ROCKCHIP help This selects support for Rockchip SoC specific extensions diff --git a/drivers/gpu/drm/rockchip/Makefile b/drivers/gpu/drm/rockchip/Makefile index c931e2a7d8de..fa8dc9d9aac2 100644 --- a/drivers/gpu/drm/rockchip/Makefile +++ b/drivers/gpu/drm/rockchip/Makefile @@ -3,14 +3,14 @@ # Direct Rendering Infrastructure (DRI) in XFree86 4.1.0 and higher. rockchipdrm-y := rockchip_drm_drv.o rockchip_drm_fb.o \ - rockchip_drm_gem.o rockchip_drm_psr.o rockchip_drm_vop.o + rockchip_drm_gem.o rockchip_drm_psr.o \ + rockchip_drm_vop.o rockchip_vop_reg.o rockchipdrm-$(CONFIG_DRM_FBDEV_EMULATION) += rockchip_drm_fbdev.o -obj-$(CONFIG_ROCKCHIP_ANALOGIX_DP) += analogix_dp-rockchip.o -obj-$(CONFIG_ROCKCHIP_CDN_DP) += cdn-dp.o -cdn-dp-objs := cdn-dp-core.o cdn-dp-reg.o -obj-$(CONFIG_ROCKCHIP_DW_HDMI) += dw_hdmi-rockchip.o -obj-$(CONFIG_ROCKCHIP_DW_MIPI_DSI) += dw-mipi-dsi.o -obj-$(CONFIG_ROCKCHIP_INNO_HDMI) += inno_hdmi.o +rockchipdrm-$(CONFIG_ROCKCHIP_ANALOGIX_DP) += analogix_dp-rockchip.o +rockchipdrm-$(CONFIG_ROCKCHIP_CDN_DP) += cdn-dp-core.o cdn-dp-reg.o +rockchipdrm-$(CONFIG_ROCKCHIP_DW_HDMI) += dw_hdmi-rockchip.o +rockchipdrm-$(CONFIG_ROCKCHIP_DW_MIPI_DSI) += dw-mipi-dsi.o +rockchipdrm-$(CONFIG_ROCKCHIP_INNO_HDMI) += inno_hdmi.o -obj-$(CONFIG_DRM_ROCKCHIP) += rockchipdrm.o rockchip_vop_reg.o +obj-$(CONFIG_DRM_ROCKCHIP) += rockchipdrm.o diff --git a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c index 8548e8271639..91ebe5c2c7a0 100644 --- a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c +++ b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c @@ -507,7 +507,7 @@ static const struct of_device_id rockchip_dp_dt_ids[] = { }; MODULE_DEVICE_TABLE(of, rockchip_dp_dt_ids); -static struct platform_driver rockchip_dp_driver = { +struct platform_driver rockchip_dp_driver = { .probe = rockchip_dp_probe, .remove = rockchip_dp_remove, .driver = { @@ -516,10 +516,3 @@ static struct platform_driver rockchip_dp_driver = { .of_match_table = of_match_ptr(rockchip_dp_dt_ids), }, }; - -module_platform_driver(rockchip_dp_driver); - -MODULE_AUTHOR("Yakir Yang <ykk@rock-chips.com>"); -MODULE_AUTHOR("Jeff chen <jeff.chen@rock-chips.com>"); -MODULE_DESCRIPTION("Rockchip Specific Analogix-DP Driver Extension"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/gpu/drm/rockchip/cdn-dp-core.c b/drivers/gpu/drm/rockchip/cdn-dp-core.c index 9edb8dc1ea14..4e55d63c3ef3 100644 --- a/drivers/gpu/drm/rockchip/cdn-dp-core.c +++ b/drivers/gpu/drm/rockchip/cdn-dp-core.c @@ -1244,7 +1244,7 @@ static const struct dev_pm_ops cdn_dp_pm_ops = { cdn_dp_resume) }; -static struct platform_driver cdn_dp_driver = { +struct platform_driver cdn_dp_driver = { .probe = cdn_dp_probe, .remove = cdn_dp_remove, .shutdown = cdn_dp_shutdown, @@ -1255,9 +1255,3 @@ static struct platform_driver cdn_dp_driver = { .pm = &cdn_dp_pm_ops, }, }; - -module_platform_driver(cdn_dp_driver); - -MODULE_AUTHOR("Chris Zhong <zyw@rock-chips.com>"); -MODULE_DESCRIPTION("cdn DP Driver"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/gpu/drm/rockchip/dw-mipi-dsi.c b/drivers/gpu/drm/rockchip/dw-mipi-dsi.c index f84f9ae2fd35..21b9737662ae 100644 --- a/drivers/gpu/drm/rockchip/dw-mipi-dsi.c +++ b/drivers/gpu/drm/rockchip/dw-mipi-dsi.c @@ -34,7 +34,7 @@ #define RK3288_DSI0_SEL_VOP_LIT BIT(6) #define RK3288_DSI1_SEL_VOP_LIT BIT(9) -#define RK3399_GRF_SOC_CON19 0x6250 +#define RK3399_GRF_SOC_CON20 0x6250 #define RK3399_DSI0_SEL_VOP_LIT BIT(0) #define RK3399_DSI1_SEL_VOP_LIT BIT(4) @@ -251,6 +251,9 @@ #define THS_PRE_PROGRAM_EN BIT(7) #define THS_ZERO_PROGRAM_EN BIT(6) +#define DW_MIPI_NEEDS_PHY_CFG_CLK BIT(0) +#define DW_MIPI_NEEDS_GRF_CLK BIT(1) + enum { BANDGAP_97_07, BANDGAP_98_05, @@ -279,6 +282,7 @@ struct dw_mipi_dsi_plat_data { u32 grf_switch_reg; u32 grf_dsi0_mode; u32 grf_dsi0_mode_reg; + unsigned int flags; unsigned int max_data_lanes; }; @@ -291,6 +295,7 @@ struct dw_mipi_dsi { struct regmap *grf_regmap; void __iomem *base; + struct clk *grf_clk; struct clk *pllref_clk; struct clk *pclk; struct clk *phy_cfg_clk; @@ -979,6 +984,17 @@ static void dw_mipi_dsi_encoder_enable(struct drm_encoder *encoder) dw_mipi_dsi_dphy_interface_config(dsi); dw_mipi_dsi_clear_err(dsi); + /* + * For the RK3399, the clk of grf must be enabled before writing grf + * register. And for RK3288 or other soc, this grf_clk must be NULL, + * the clk_prepare_enable return true directly. + */ + ret = clk_prepare_enable(dsi->grf_clk); + if (ret) { + dev_err(dsi->dev, "Failed to enable grf_clk: %d\n", ret); + return; + } + if (pdata->grf_dsi0_mode_reg) regmap_write(dsi->grf_regmap, pdata->grf_dsi0_mode_reg, pdata->grf_dsi0_mode); @@ -1003,6 +1019,8 @@ static void dw_mipi_dsi_encoder_enable(struct drm_encoder *encoder) regmap_write(dsi->grf_regmap, pdata->grf_switch_reg, val); dev_dbg(dsi->dev, "vop %s output to dsi0\n", (mux) ? "LIT" : "BIG"); dsi->dpms_mode = DRM_MODE_DPMS_ON; + + clk_disable_unprepare(dsi->grf_clk); } static int @@ -1133,9 +1151,10 @@ static struct dw_mipi_dsi_plat_data rk3288_mipi_dsi_drv_data = { static struct dw_mipi_dsi_plat_data rk3399_mipi_dsi_drv_data = { .dsi0_en_bit = RK3399_DSI0_SEL_VOP_LIT, .dsi1_en_bit = RK3399_DSI1_SEL_VOP_LIT, - .grf_switch_reg = RK3399_GRF_SOC_CON19, + .grf_switch_reg = RK3399_GRF_SOC_CON20, .grf_dsi0_mode = RK3399_GRF_DSI_MODE, .grf_dsi0_mode_reg = RK3399_GRF_SOC_CON22, + .flags = DW_MIPI_NEEDS_PHY_CFG_CLK | DW_MIPI_NEEDS_GRF_CLK, .max_data_lanes = 4, }; @@ -1227,15 +1246,22 @@ static int dw_mipi_dsi_bind(struct device *dev, struct device *master, clk_disable_unprepare(dsi->pclk); } - dsi->phy_cfg_clk = devm_clk_get(dev, "phy_cfg"); - if (IS_ERR(dsi->phy_cfg_clk)) { - ret = PTR_ERR(dsi->phy_cfg_clk); - if (ret != -ENOENT) { + if (pdata->flags & DW_MIPI_NEEDS_PHY_CFG_CLK) { + dsi->phy_cfg_clk = devm_clk_get(dev, "phy_cfg"); + if (IS_ERR(dsi->phy_cfg_clk)) { + ret = PTR_ERR(dsi->phy_cfg_clk); dev_err(dev, "Unable to get phy_cfg_clk: %d\n", ret); return ret; } - dsi->phy_cfg_clk = NULL; - dev_dbg(dev, "have not phy_cfg_clk\n"); + } + + if (pdata->flags & DW_MIPI_NEEDS_GRF_CLK) { + dsi->grf_clk = devm_clk_get(dev, "grf"); + if (IS_ERR(dsi->grf_clk)) { + ret = PTR_ERR(dsi->grf_clk); + dev_err(dev, "Unable to get grf_clk: %d\n", ret); + return ret; + } } ret = clk_prepare_enable(dsi->pllref_clk); @@ -1304,7 +1330,7 @@ static int dw_mipi_dsi_remove(struct platform_device *pdev) return 0; } -static struct platform_driver dw_mipi_dsi_driver = { +struct platform_driver dw_mipi_dsi_driver = { .probe = dw_mipi_dsi_probe, .remove = dw_mipi_dsi_remove, .driver = { @@ -1312,9 +1338,3 @@ static struct platform_driver dw_mipi_dsi_driver = { .name = DRIVER_NAME, }, }; -module_platform_driver(dw_mipi_dsi_driver); - -MODULE_DESCRIPTION("ROCKCHIP MIPI DSI host controller driver"); -MODULE_AUTHOR("Chris Zhong <zyw@rock-chips.com>"); -MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:" DRIVER_NAME); diff --git a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c index d53827413996..63dab6f1b191 100644 --- a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c +++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c @@ -325,7 +325,7 @@ static int dw_hdmi_rockchip_remove(struct platform_device *pdev) return 0; } -static struct platform_driver dw_hdmi_rockchip_pltfm_driver = { +struct platform_driver dw_hdmi_rockchip_pltfm_driver = { .probe = dw_hdmi_rockchip_probe, .remove = dw_hdmi_rockchip_remove, .driver = { @@ -333,11 +333,3 @@ static struct platform_driver dw_hdmi_rockchip_pltfm_driver = { .of_match_table = dw_hdmi_rockchip_dt_ids, }, }; - -module_platform_driver(dw_hdmi_rockchip_pltfm_driver); - -MODULE_AUTHOR("Andy Yan <andy.yan@rock-chips.com>"); -MODULE_AUTHOR("Yakir Yang <ykk@rock-chips.com>"); -MODULE_DESCRIPTION("Rockchip Specific DW-HDMI Driver Extension"); -MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:dwhdmi-rockchip"); diff --git a/drivers/gpu/drm/rockchip/inno_hdmi.c b/drivers/gpu/drm/rockchip/inno_hdmi.c index 006260de9dbd..7d9b75eb6c44 100644 --- a/drivers/gpu/drm/rockchip/inno_hdmi.c +++ b/drivers/gpu/drm/rockchip/inno_hdmi.c @@ -923,7 +923,7 @@ static const struct of_device_id inno_hdmi_dt_ids[] = { }; MODULE_DEVICE_TABLE(of, inno_hdmi_dt_ids); -static struct platform_driver inno_hdmi_driver = { +struct platform_driver inno_hdmi_driver = { .probe = inno_hdmi_probe, .remove = inno_hdmi_remove, .driver = { @@ -931,11 +931,3 @@ static struct platform_driver inno_hdmi_driver = { .of_match_table = inno_hdmi_dt_ids, }, }; - -module_platform_driver(inno_hdmi_driver); - -MODULE_AUTHOR("Zheng Yang <zhengyang@rock-chips.com>"); -MODULE_AUTHOR("Yakir Yang <ykk@rock-chips.com>"); -MODULE_DESCRIPTION("Rockchip Specific INNO-HDMI Driver"); -MODULE_LICENSE("GPL v2"); -MODULE_ALIAS("platform:innohdmi-rockchip"); diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c index ccf456938792..cd7d02e1f758 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c @@ -304,34 +304,37 @@ static const struct dev_pm_ops rockchip_drm_pm_ops = { rockchip_drm_sys_resume) }; -static int compare_of(struct device *dev, void *data) -{ - struct device_node *np = data; +#define MAX_ROCKCHIP_SUB_DRIVERS 16 +static struct platform_driver *rockchip_sub_drivers[MAX_ROCKCHIP_SUB_DRIVERS]; +static int num_rockchip_sub_drivers; - return dev->of_node == np; +static int compare_dev(struct device *dev, void *data) +{ + return dev == (struct device *)data; } -static void rockchip_add_endpoints(struct device *dev, - struct component_match **match, - struct device_node *port) +static struct component_match *rockchip_drm_match_add(struct device *dev) { - struct device_node *ep, *remote; + struct component_match *match = NULL; + int i; - for_each_child_of_node(port, ep) { - remote = of_graph_get_remote_port_parent(ep); - if (!remote || !of_device_is_available(remote)) { - of_node_put(remote); - continue; - } else if (!of_device_is_available(remote->parent)) { - dev_warn(dev, "parent device of %s is not available\n", - remote->full_name); - of_node_put(remote); - continue; - } + for (i = 0; i < num_rockchip_sub_drivers; i++) { + struct platform_driver *drv = rockchip_sub_drivers[i]; + struct device *p = NULL, *d; + + do { + d = bus_find_device(&platform_bus_type, p, &drv->driver, + (void *)platform_bus_type.match); + put_device(p); + p = d; - drm_of_component_match_add(dev, match, compare_of, remote); - of_node_put(remote); + if (!d) + break; + component_match_add(dev, &match, compare_dev, d); + } while (true); } + + return match ?: ERR_PTR(-ENODEV); } static const struct component_master_ops rockchip_drm_ops = { @@ -339,21 +342,16 @@ static const struct component_master_ops rockchip_drm_ops = { .unbind = rockchip_drm_unbind, }; -static int rockchip_drm_platform_probe(struct platform_device *pdev) +static int rockchip_drm_platform_of_probe(struct device *dev) { - struct device *dev = &pdev->dev; - struct component_match *match = NULL; struct device_node *np = dev->of_node; struct device_node *port; + bool found = false; int i; if (!np) return -ENODEV; - /* - * Bind the crtc ports first, so that - * drm_of_find_possible_crtcs called from encoder .bind callbacks - * works as expected. - */ + for (i = 0;; i++) { struct device_node *iommu; @@ -377,9 +375,9 @@ static int rockchip_drm_platform_probe(struct platform_device *pdev) is_support_iommu = false; } + found = true; + of_node_put(iommu); - drm_of_component_match_add(dev, &match, compare_of, - port->parent); of_node_put(port); } @@ -388,27 +386,27 @@ static int rockchip_drm_platform_probe(struct platform_device *pdev) return -ENODEV; } - if (!match) { + if (!found) { dev_err(dev, "No available vop found for display-subsystem.\n"); return -ENODEV; } - /* - * For each bound crtc, bind the encoders attached to its - * remote endpoint. - */ - for (i = 0;; i++) { - port = of_parse_phandle(np, "ports", i); - if (!port) - break; - if (!of_device_is_available(port->parent)) { - of_node_put(port); - continue; - } + return 0; +} - rockchip_add_endpoints(dev, &match, port); - of_node_put(port); - } +static int rockchip_drm_platform_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct component_match *match = NULL; + int ret; + + ret = rockchip_drm_platform_of_probe(dev); + if (ret) + return ret; + + match = rockchip_drm_match_add(dev); + if (IS_ERR(match)) + return PTR_ERR(match); return component_master_add_with_match(dev, &rockchip_drm_ops, match); } @@ -436,7 +434,54 @@ static struct platform_driver rockchip_drm_platform_driver = { }, }; -module_platform_driver(rockchip_drm_platform_driver); +#define ADD_ROCKCHIP_SUB_DRIVER(drv, cond) { \ + if (IS_ENABLED(cond) && \ + !WARN_ON(num_rockchip_sub_drivers >= MAX_ROCKCHIP_SUB_DRIVERS)) \ + rockchip_sub_drivers[num_rockchip_sub_drivers++] = &drv; \ +} + +static int __init rockchip_drm_init(void) +{ + int ret; + + num_rockchip_sub_drivers = 0; + ADD_ROCKCHIP_SUB_DRIVER(vop_platform_driver, CONFIG_DRM_ROCKCHIP); + ADD_ROCKCHIP_SUB_DRIVER(rockchip_dp_driver, + CONFIG_ROCKCHIP_ANALOGIX_DP); + ADD_ROCKCHIP_SUB_DRIVER(cdn_dp_driver, CONFIG_ROCKCHIP_CDN_DP); + ADD_ROCKCHIP_SUB_DRIVER(dw_hdmi_rockchip_pltfm_driver, + CONFIG_ROCKCHIP_DW_HDMI); + ADD_ROCKCHIP_SUB_DRIVER(dw_mipi_dsi_driver, + CONFIG_ROCKCHIP_DW_MIPI_DSI); + ADD_ROCKCHIP_SUB_DRIVER(inno_hdmi_driver, CONFIG_ROCKCHIP_INNO_HDMI); + + ret = platform_register_drivers(rockchip_sub_drivers, + num_rockchip_sub_drivers); + if (ret) + return ret; + + ret = platform_driver_register(&rockchip_drm_platform_driver); + if (ret) + goto err_unreg_drivers; + + return 0; + +err_unreg_drivers: + platform_unregister_drivers(rockchip_sub_drivers, + num_rockchip_sub_drivers); + return ret; +} + +static void __exit rockchip_drm_fini(void) +{ + platform_driver_unregister(&rockchip_drm_platform_driver); + + platform_unregister_drivers(rockchip_sub_drivers, + num_rockchip_sub_drivers); +} + +module_init(rockchip_drm_init); +module_exit(rockchip_drm_fini); MODULE_AUTHOR("Mark Yao <mark.yao@rock-chips.com>"); MODULE_DESCRIPTION("ROCKCHIP DRM Driver"); diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h index 8aca219ec4c8..a48fcce3f5f6 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h +++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h @@ -65,4 +65,10 @@ void rockchip_drm_dma_detach_device(struct drm_device *drm_dev, int rockchip_drm_wait_line_flag(struct drm_crtc *crtc, unsigned int line_num, unsigned int mstimeout); +extern struct platform_driver cdn_dp_driver; +extern struct platform_driver dw_hdmi_rockchip_pltfm_driver; +extern struct platform_driver dw_mipi_dsi_driver; +extern struct platform_driver inno_hdmi_driver; +extern struct platform_driver rockchip_dp_driver; +extern struct platform_driver vop_platform_driver; #endif /* _ROCKCHIP_DRM_DRV_H_ */ diff --git a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c index 91fbc7b52147..0da44442aab0 100644 --- a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c +++ b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c @@ -404,7 +404,7 @@ static int vop_remove(struct platform_device *pdev) return 0; } -static struct platform_driver vop_platform_driver = { +struct platform_driver vop_platform_driver = { .probe = vop_probe, .remove = vop_remove, .driver = { @@ -412,9 +412,3 @@ static struct platform_driver vop_platform_driver = { .of_match_table = of_match_ptr(vop_driver_dt_match), }, }; - -module_platform_driver(vop_platform_driver); - -MODULE_AUTHOR("Mark Yao <mark.yao@rock-chips.com>"); -MODULE_DESCRIPTION("ROCKCHIP VOP Driver"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/gpu/drm/shmobile/shmob_drm_crtc.c b/drivers/gpu/drm/shmobile/shmob_drm_crtc.c index 5fcabc04f307..e7738939a86d 100644 --- a/drivers/gpu/drm/shmobile/shmob_drm_crtc.c +++ b/drivers/gpu/drm/shmobile/shmob_drm_crtc.c @@ -449,7 +449,8 @@ void shmob_drm_crtc_finish_page_flip(struct shmob_drm_crtc *scrtc) static int shmob_drm_crtc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb, struct drm_pending_vblank_event *event, - uint32_t page_flip_flags) + uint32_t page_flip_flags, + struct drm_modeset_acquire_ctx *ctx) { struct shmob_drm_crtc *scrtc = to_shmob_crtc(crtc); struct drm_device *dev = scrtc->crtc.dev; diff --git a/drivers/gpu/drm/shmobile/shmob_drm_plane.c b/drivers/gpu/drm/shmobile/shmob_drm_plane.c index 2023a93cee2b..97f6e4a3eb0d 100644 --- a/drivers/gpu/drm/shmobile/shmob_drm_plane.c +++ b/drivers/gpu/drm/shmobile/shmob_drm_plane.c @@ -177,7 +177,8 @@ shmob_drm_plane_update(struct drm_plane *plane, struct drm_crtc *crtc, struct drm_framebuffer *fb, int crtc_x, int crtc_y, unsigned int crtc_w, unsigned int crtc_h, uint32_t src_x, uint32_t src_y, - uint32_t src_w, uint32_t src_h) + uint32_t src_w, uint32_t src_h, + struct drm_modeset_acquire_ctx *ctx) { struct shmob_drm_plane *splane = to_shmob_plane(plane); struct shmob_drm_device *sdev = plane->dev->dev_private; @@ -208,7 +209,8 @@ shmob_drm_plane_update(struct drm_plane *plane, struct drm_crtc *crtc, return 0; } -static int shmob_drm_plane_disable(struct drm_plane *plane) +static int shmob_drm_plane_disable(struct drm_plane *plane, + struct drm_modeset_acquire_ctx *ctx) { struct shmob_drm_plane *splane = to_shmob_plane(plane); struct shmob_drm_device *sdev = plane->dev->dev_private; @@ -221,7 +223,7 @@ static int shmob_drm_plane_disable(struct drm_plane *plane) static void shmob_drm_plane_destroy(struct drm_plane *plane) { - shmob_drm_plane_disable(plane); + drm_plane_force_disable(plane); drm_plane_cleanup(plane); } diff --git a/drivers/gpu/drm/tegra/dc.c b/drivers/gpu/drm/tegra/dc.c index 0db5d5a8d3b9..95b373f739f2 100644 --- a/drivers/gpu/drm/tegra/dc.c +++ b/drivers/gpu/drm/tegra/dc.c @@ -1382,7 +1382,7 @@ static int tegra_dc_show_regs(struct seq_file *s, void *data) struct tegra_dc *dc = node->info_ent->data; int err = 0; - drm_modeset_lock_crtc(&dc->base, NULL); + drm_modeset_lock(&dc->base.mutex, NULL); if (!dc->base.state->active) { err = -EBUSY; @@ -1609,7 +1609,7 @@ static int tegra_dc_show_regs(struct seq_file *s, void *data) #undef DUMP_REG unlock: - drm_modeset_unlock_crtc(&dc->base); + drm_modeset_unlock(&dc->base.mutex); return err; } @@ -1620,7 +1620,7 @@ static int tegra_dc_show_crc(struct seq_file *s, void *data) int err = 0; u32 value; - drm_modeset_lock_crtc(&dc->base, NULL); + drm_modeset_lock(&dc->base.mutex, NULL); if (!dc->base.state->active) { err = -EBUSY; @@ -1640,7 +1640,7 @@ static int tegra_dc_show_crc(struct seq_file *s, void *data) tegra_dc_writel(dc, 0, DC_COM_CRC_CONTROL); unlock: - drm_modeset_unlock_crtc(&dc->base); + drm_modeset_unlock(&dc->base.mutex); return err; } diff --git a/drivers/gpu/drm/tilcdc/tilcdc_crtc.c b/drivers/gpu/drm/tilcdc/tilcdc_crtc.c index c92faa8f7560..afd2a7b2aff7 100644 --- a/drivers/gpu/drm/tilcdc/tilcdc_crtc.c +++ b/drivers/gpu/drm/tilcdc/tilcdc_crtc.c @@ -579,7 +579,7 @@ static void tilcdc_crtc_recover_work(struct work_struct *work) dev_info(crtc->dev->dev, "%s: Reset CRTC", __func__); - drm_modeset_lock_crtc(crtc, NULL); + drm_modeset_lock(&crtc->mutex, NULL); if (!tilcdc_crtc_is_on(crtc)) goto out; @@ -587,7 +587,7 @@ static void tilcdc_crtc_recover_work(struct work_struct *work) tilcdc_crtc_disable(crtc); tilcdc_crtc_enable(crtc); out: - drm_modeset_unlock_crtc(crtc); + drm_modeset_unlock(&crtc->mutex); } static void tilcdc_crtc_destroy(struct drm_crtc *crtc) @@ -595,9 +595,9 @@ static void tilcdc_crtc_destroy(struct drm_crtc *crtc) struct tilcdc_crtc *tilcdc_crtc = to_tilcdc_crtc(crtc); struct tilcdc_drm_private *priv = crtc->dev->dev_private; - drm_modeset_lock_crtc(crtc, NULL); + drm_modeset_lock(&crtc->mutex, NULL); tilcdc_crtc_disable(crtc); - drm_modeset_unlock_crtc(crtc); + drm_modeset_unlock(&crtc->mutex); flush_workqueue(priv->wq); @@ -856,7 +856,7 @@ void tilcdc_crtc_update_clk(struct drm_crtc *crtc) struct tilcdc_drm_private *priv = dev->dev_private; struct tilcdc_crtc *tilcdc_crtc = to_tilcdc_crtc(crtc); - drm_modeset_lock_crtc(crtc, NULL); + drm_modeset_lock(&crtc->mutex, NULL); if (tilcdc_crtc->lcd_fck_rate != clk_get_rate(priv->clk)) { if (tilcdc_crtc_is_on(crtc)) { pm_runtime_get_sync(dev->dev); @@ -868,7 +868,7 @@ void tilcdc_crtc_update_clk(struct drm_crtc *crtc) pm_runtime_put_sync(dev->dev); } } - drm_modeset_unlock_crtc(crtc); + drm_modeset_unlock(&crtc->mutex); } #define SYNC_LOST_COUNT_LIMIT 50 diff --git a/drivers/gpu/drm/tinydrm/core/tinydrm-core.c b/drivers/gpu/drm/tinydrm/core/tinydrm-core.c index 6a257dd08ee0..551709e6b114 100644 --- a/drivers/gpu/drm/tinydrm/core/tinydrm-core.c +++ b/drivers/gpu/drm/tinydrm/core/tinydrm-core.c @@ -122,21 +122,6 @@ void tinydrm_gem_cma_free_object(struct drm_gem_object *gem_obj) } EXPORT_SYMBOL_GPL(tinydrm_gem_cma_free_object); -const struct file_operations tinydrm_fops = { - .owner = THIS_MODULE, - .open = drm_open, - .release = drm_release, - .unlocked_ioctl = drm_ioctl, -#ifdef CONFIG_COMPAT - .compat_ioctl = drm_compat_ioctl, -#endif - .poll = drm_poll, - .read = drm_read, - .llseek = no_llseek, - .mmap = drm_gem_cma_mmap, -}; -EXPORT_SYMBOL(tinydrm_fops); - static struct drm_framebuffer * tinydrm_fb_create(struct drm_device *drm, struct drm_file *file_priv, const struct drm_mode_fb_cmd2 *mode_cmd) @@ -251,7 +236,7 @@ static void tinydrm_unregister(struct tinydrm_device *tdev) { struct drm_fbdev_cma *fbdev_cma = tdev->fbdev_cma; - drm_crtc_force_disable_all(tdev->drm); + drm_atomic_helper_shutdown(tdev->drm); /* don't restore fbdev in lastclose, keep pipeline disabled */ tdev->fbdev_cma = NULL; drm_dev_unregister(tdev->drm); @@ -302,7 +287,7 @@ EXPORT_SYMBOL(devm_tinydrm_register); */ void tinydrm_shutdown(struct tinydrm_device *tdev) { - drm_crtc_force_disable_all(tdev->drm); + drm_atomic_helper_shutdown(tdev->drm); } EXPORT_SYMBOL(tinydrm_shutdown); diff --git a/drivers/gpu/drm/tinydrm/mi0283qt.c b/drivers/gpu/drm/tinydrm/mi0283qt.c index b29fe86158f7..482ff1c3db61 100644 --- a/drivers/gpu/drm/tinydrm/mi0283qt.c +++ b/drivers/gpu/drm/tinydrm/mi0283qt.c @@ -132,9 +132,12 @@ static const struct drm_display_mode mi0283qt_mode = { TINYDRM_MODE(320, 240, 58, 43), }; +DEFINE_DRM_GEM_CMA_FOPS(mi0283qt_fops); + static struct drm_driver mi0283qt_driver = { .driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_PRIME | DRIVER_ATOMIC, + .fops = &mi0283qt_fops, TINYDRM_GEM_DRIVER_OPS, .lastclose = tinydrm_lastclose, .debugfs_init = mipi_dbi_debugfs_init, diff --git a/drivers/gpu/drm/udl/udl_modeset.c b/drivers/gpu/drm/udl/udl_modeset.c index f2b2481cad52..5bcae7649795 100644 --- a/drivers/gpu/drm/udl/udl_modeset.c +++ b/drivers/gpu/drm/udl/udl_modeset.c @@ -361,7 +361,8 @@ static void udl_crtc_destroy(struct drm_crtc *crtc) static int udl_crtc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb, struct drm_pending_vblank_event *event, - uint32_t page_flip_flags) + uint32_t page_flip_flags, + struct drm_modeset_acquire_ctx *ctx) { struct udl_framebuffer *ufb = to_udl_fb(fb); struct drm_device *dev = crtc->dev; diff --git a/drivers/gpu/drm/vc4/vc4_crtc.c b/drivers/gpu/drm/vc4/vc4_crtc.c index 24edd0c22cc9..865e9f494bcc 100644 --- a/drivers/gpu/drm/vc4/vc4_crtc.c +++ b/drivers/gpu/drm/vc4/vc4_crtc.c @@ -807,12 +807,13 @@ static int vc4_async_page_flip(struct drm_crtc *crtc, static int vc4_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb, struct drm_pending_vblank_event *event, - uint32_t flags) + uint32_t flags, + struct drm_modeset_acquire_ctx *ctx) { if (flags & DRM_MODE_PAGE_FLIP_ASYNC) return vc4_async_page_flip(crtc, fb, event, flags); else - return drm_atomic_helper_page_flip(crtc, fb, event, flags); + return drm_atomic_helper_page_flip(crtc, fb, event, flags, ctx); } static struct drm_crtc_state *vc4_crtc_duplicate_state(struct drm_crtc *crtc) diff --git a/drivers/gpu/drm/vc4/vc4_plane.c b/drivers/gpu/drm/vc4/vc4_plane.c index 0f4564beb017..d34cd5393a9b 100644 --- a/drivers/gpu/drm/vc4/vc4_plane.c +++ b/drivers/gpu/drm/vc4/vc4_plane.c @@ -756,7 +756,8 @@ vc4_update_plane(struct drm_plane *plane, int crtc_x, int crtc_y, unsigned int crtc_w, unsigned int crtc_h, uint32_t src_x, uint32_t src_y, - uint32_t src_w, uint32_t src_h) + uint32_t src_w, uint32_t src_h, + struct drm_modeset_acquire_ctx *ctx) { struct drm_plane_state *plane_state; struct vc4_plane_state *vc4_state; @@ -817,7 +818,8 @@ out: crtc_x, crtc_y, crtc_w, crtc_h, src_x, src_y, - src_w, src_h); + src_w, src_h, + ctx); } static const struct drm_plane_funcs vc4_plane_funcs = { diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c index c18c81f63ac3..6078654d033b 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c @@ -2947,10 +2947,11 @@ vmw_kms_create_implicit_placement_property(struct vmw_private *dev_priv, * the vmwgfx modesetting. So explicitly clear that member before calling * into drm_atomic_helper_set_config. */ -int vmw_kms_set_config(struct drm_mode_set *set) +int vmw_kms_set_config(struct drm_mode_set *set, + struct drm_modeset_acquire_ctx *ctx) { if (set && set->mode) set->mode->type = 0; - return drm_atomic_helper_set_config(set); + return drm_atomic_helper_set_config(set, ctx); } diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h index 9c161d29aaeb..0c226b2adea5 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h @@ -453,6 +453,7 @@ int vmw_kms_stdu_dma(struct vmw_private *dev_priv, bool to_surface, bool interruptible); -int vmw_kms_set_config(struct drm_mode_set *set); +int vmw_kms_set_config(struct drm_mode_set *set, + struct drm_modeset_acquire_ctx *ctx); #endif diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c b/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c index 2664e4c16750..8d7dc9def7c2 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c @@ -310,7 +310,8 @@ static void vmw_sou_crtc_helper_disable(struct drm_crtc *crtc) static int vmw_sou_crtc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *new_fb, struct drm_pending_vblank_event *event, - uint32_t flags) + uint32_t flags, + struct drm_modeset_acquire_ctx *ctx) { struct vmw_private *dev_priv = vmw_priv(crtc->dev); struct drm_framebuffer *old_fb = crtc->primary->fb; @@ -323,7 +324,7 @@ static int vmw_sou_crtc_page_flip(struct drm_crtc *crtc, return -EINVAL; flags &= ~DRM_MODE_PAGE_FLIP_ASYNC; - ret = drm_atomic_helper_page_flip(crtc, new_fb, NULL, flags); + ret = drm_atomic_helper_page_flip(crtc, new_fb, NULL, flags, ctx); if (ret) { DRM_ERROR("Page flip error %d.\n", ret); return ret; diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c b/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c index e872ffe5f0db..bad31bdf09b6 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c @@ -481,7 +481,8 @@ static void vmw_stdu_crtc_helper_disable(struct drm_crtc *crtc) static int vmw_stdu_crtc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *new_fb, struct drm_pending_vblank_event *event, - uint32_t flags) + uint32_t flags, + struct drm_modeset_acquire_ctx *ctx) { struct vmw_private *dev_priv = vmw_priv(crtc->dev); @@ -504,7 +505,7 @@ static int vmw_stdu_crtc_page_flip(struct drm_crtc *crtc, * don't hand it to the helper. */ flags &= ~DRM_MODE_PAGE_FLIP_ASYNC; - ret = drm_atomic_helper_page_flip(crtc, new_fb, NULL, flags); + ret = drm_atomic_helper_page_flip(crtc, new_fb, NULL, flags, ctx); if (ret) { DRM_ERROR("Page flip error %d.\n", ret); return ret; diff --git a/drivers/gpu/drm/zte/zx_hdmi.c b/drivers/gpu/drm/zte/zx_hdmi.c index c47b9cbfe270..0df7366e594b 100644 --- a/drivers/gpu/drm/zte/zx_hdmi.c +++ b/drivers/gpu/drm/zte/zx_hdmi.c @@ -50,7 +50,6 @@ struct zx_hdmi { struct clk *xclk; bool sink_is_hdmi; bool sink_has_audio; - const struct vou_inf *inf; struct platform_device *audio_pdev; }; diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h index 8dd38e69d6f2..4dbf9f96ae5b 100644 --- a/drivers/pci/pci.h +++ b/drivers/pci/pci.h @@ -3,6 +3,8 @@ #define PCI_FIND_CAP_TTL 48 +#define PCI_VSEC_ID_INTEL_TBT 0x1234 /* Thunderbolt */ + extern const unsigned char pcie_link_speed[]; bool pcie_cap_has_lnkctl(const struct pci_dev *dev); diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index dfc9a2794141..90592d424e9b 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -1208,6 +1208,24 @@ void set_pcie_hotplug_bridge(struct pci_dev *pdev) pdev->is_hotplug_bridge = 1; } +static void set_pcie_thunderbolt(struct pci_dev *dev) +{ + int vsec = 0; + u32 header; + + while ((vsec = pci_find_next_ext_capability(dev, vsec, + PCI_EXT_CAP_ID_VNDR))) { + pci_read_config_dword(dev, vsec + PCI_VNDR_HEADER, &header); + + /* Is the device part of a Thunderbolt controller? */ + if (dev->vendor == PCI_VENDOR_ID_INTEL && + PCI_VNDR_HEADER_ID(header) == PCI_VSEC_ID_INTEL_TBT) { + dev->is_thunderbolt = 1; + return; + } + } +} + /** * pci_ext_cfg_is_aliased - is ext config space just an alias of std config? * @dev: PCI device @@ -1360,6 +1378,9 @@ int pci_setup_device(struct pci_dev *dev) /* need to have dev->class ready */ dev->cfg_size = pci_cfg_space_size(dev); + /* need to have dev->cfg_size ready */ + set_pcie_thunderbolt(dev); + /* "Unknown power state" */ dev->current_state = PCI_UNKNOWN; diff --git a/drivers/platform/x86/apple-gmux.c b/drivers/platform/x86/apple-gmux.c index a66be137324c..623d322447a2 100644 --- a/drivers/platform/x86/apple-gmux.c +++ b/drivers/platform/x86/apple-gmux.c @@ -60,6 +60,7 @@ struct apple_gmux_data { /* switcheroo data */ acpi_handle dhandle; int gpe; + bool external_switchable; enum vga_switcheroo_client_id switch_state_display; enum vga_switcheroo_client_id switch_state_ddc; enum vga_switcheroo_client_id switch_state_external; @@ -358,6 +359,19 @@ static const struct backlight_ops gmux_bl_ops = { * ports while the discrete GPU is asleep, but currently we do not make use * of this feature. * + * Our switching policy for the external port is that on those generations + * which are able to switch it fully, the port is switched together with the + * panel when IGD / DIS commands are issued to vga_switcheroo. It is thus + * possible to drive e.g. a beamer on battery power with the integrated GPU. + * The user may manually switch to the discrete GPU if more performance is + * needed. + * + * On all newer generations, the external port can only be driven by the + * discrete GPU. If a display is plugged in while the panel is switched to + * the integrated GPU, *both* GPUs will be in use for maximum performance. + * To decrease power consumption, the user may manually switch to the + * discrete GPU, thereby suspending the integrated GPU. + * * gmux' initial switch state on bootup is user configurable via the EFI * variable ``gpu-power-prefs-fa4ce28d-b62f-4c99-9cc3-6815686e30f9`` (5th byte, * 1 = IGD, 0 = DIS). Based on this setting, the EFI firmware tells gmux to @@ -414,7 +428,8 @@ static int gmux_switchto(enum vga_switcheroo_client_id id) { apple_gmux_data->switch_state_ddc = id; apple_gmux_data->switch_state_display = id; - apple_gmux_data->switch_state_external = id; + if (apple_gmux_data->external_switchable) + apple_gmux_data->switch_state_external = id; gmux_write_switch_state(apple_gmux_data); @@ -601,6 +616,11 @@ static struct pci_dev *gmux_get_io_pdev(void) return NULL; } +static int is_thunderbolt(struct device *dev, void *data) +{ + return to_pci_dev(dev)->is_thunderbolt; +} + static int gmux_probe(struct pnp_dev *pnp, const struct pnp_device_id *id) { struct apple_gmux_data *gmux_data; @@ -755,6 +775,15 @@ static int gmux_probe(struct pnp_dev *pnp, const struct pnp_device_id *id) gmux_data->gpe = -1; } + /* + * If Thunderbolt is present, the external DP port is not fully + * switchable. Force its AUX channel to the discrete GPU. + */ + gmux_data->external_switchable = + !bus_for_each_dev(&pci_bus_type, NULL, NULL, is_thunderbolt); + if (!gmux_data->external_switchable) + gmux_write8(gmux_data, GMUX_PORT_SWITCH_EXTERNAL, 3); + apple_gmux_data = gmux_data; init_completion(&gmux_data->powerchange_done); gmux_enable_interrupts(gmux_data); diff --git a/include/drm/drmP.h b/include/drm/drmP.h index 0e383438f793..3bfafcdb8710 100644 --- a/include/drm/drmP.h +++ b/include/drm/drmP.h @@ -78,6 +78,8 @@ #include <drm/drm_prime.h> #include <drm/drm_pci.h> #include <drm/drm_file.h> +#include <drm/drm_debugfs.h> +#include <drm/drm_ioctl.h> struct module; @@ -316,54 +318,10 @@ struct pci_controller; #define DRM_IF_VERSION(maj, min) (maj << 16 | min) -/** - * Ioctl function type. - * - * \param inode device inode. - * \param file_priv DRM file private pointer. - * \param cmd command. - * \param arg argument. - */ -typedef int drm_ioctl_t(struct drm_device *dev, void *data, - struct drm_file *file_priv); - -typedef int drm_ioctl_compat_t(struct file *filp, unsigned int cmd, - unsigned long arg); - -#define DRM_IOCTL_NR(n) _IOC_NR(n) -#define DRM_MAJOR 226 - -#define DRM_AUTH 0x1 -#define DRM_MASTER 0x2 -#define DRM_ROOT_ONLY 0x4 -#define DRM_CONTROL_ALLOW 0x8 -#define DRM_UNLOCKED 0x10 -#define DRM_RENDER_ALLOW 0x20 - -struct drm_ioctl_desc { - unsigned int cmd; - int flags; - drm_ioctl_t *func; - const char *name; -}; - -/** - * Creates a driver or general drm_ioctl_desc array entry for the given - * ioctl, for use by drm_ioctl(). - */ - -#define DRM_IOCTL_DEF_DRV(ioctl, _func, _flags) \ - [DRM_IOCTL_NR(DRM_IOCTL_##ioctl) - DRM_COMMAND_BASE] = { \ - .cmd = DRM_IOCTL_##ioctl, \ - .func = _func, \ - .flags = _flags, \ - .name = #ioctl \ - } /* Flags and return codes for get_vblank_timestamp() driver function. */ #define DRM_CALLED_FROM_VBLIRQ 1 #define DRM_VBLANKTIME_SCANOUTPOS_METHOD (1 << 0) -#define DRM_VBLANKTIME_IN_VBLANK (1 << 1) /* get_scanout_position() return flags */ #define DRM_SCANOUTPOS_VALID (1 << 0) @@ -371,27 +329,6 @@ struct drm_ioctl_desc { #define DRM_SCANOUTPOS_ACCURATE (1 << 2) /** - * Info file list entry. This structure represents a debugfs or proc file to - * be created by the drm core - */ -struct drm_info_list { - const char *name; /** file name */ - int (*show)(struct seq_file*, void*); /** show callback */ - u32 driver_features; /**< Required driver features for this entry */ - void *data; -}; - -/** - * debugfs node structure. This structure represents a debugfs file. - */ -struct drm_info_node { - struct list_head list; - struct drm_minor *minor; - const struct drm_info_list *info_ent; - struct dentry *dent; -}; - -/** * DRM device structure. This structure represent a complete card that * may contain multiple heads. */ @@ -569,51 +506,12 @@ static inline int drm_device_is_unplugged(struct drm_device *dev) /*@{*/ /* Driver support (drm_drv.h) */ -extern int drm_ioctl_permit(u32 flags, struct drm_file *file_priv); -extern long drm_ioctl(struct file *filp, - unsigned int cmd, unsigned long arg); -#ifdef CONFIG_COMPAT -extern long drm_compat_ioctl(struct file *filp, - unsigned int cmd, unsigned long arg); -#else -/* Let drm_compat_ioctl be assigned to .compat_ioctl unconditionally */ -#define drm_compat_ioctl NULL -#endif -extern bool drm_ioctl_flags(unsigned int nr, unsigned int *flags); - -/* Misc. IOCTL support (drm_ioctl.c) */ -int drm_noop(struct drm_device *dev, void *data, - struct drm_file *file_priv); -int drm_invalid_op(struct drm_device *dev, void *data, - struct drm_file *file_priv); /* * These are exported to drivers so that they can implement fencing using * DMA quiscent + idle. DMA quiescent usually requires the hardware lock. */ - /* Debugfs support */ -#if defined(CONFIG_DEBUG_FS) -extern int drm_debugfs_create_files(const struct drm_info_list *files, - int count, struct dentry *root, - struct drm_minor *minor); -extern int drm_debugfs_remove_files(const struct drm_info_list *files, - int count, struct drm_minor *minor); -#else -static inline int drm_debugfs_create_files(const struct drm_info_list *files, - int count, struct dentry *root, - struct drm_minor *minor) -{ - return 0; -} - -static inline int drm_debugfs_remove_files(const struct drm_info_list *files, - int count, struct drm_minor *minor) -{ - return 0; -} -#endif - /* sysfs support (drm_sysfs.c) */ extern void drm_sysfs_hotplug_event(struct drm_device *dev); diff --git a/include/drm/drm_atomic.h b/include/drm/drm_atomic.h index 0147a047878d..fd33ed5eaeb4 100644 --- a/include/drm/drm_atomic.h +++ b/include/drm/drm_atomic.h @@ -498,6 +498,23 @@ int __must_check drm_atomic_nonblocking_commit(struct drm_atomic_state *state); void drm_state_dump(struct drm_device *dev, struct drm_printer *p); +/** + * for_each_connector_in_state - iterate over all connectors in an atomic update + * @__state: &struct drm_atomic_state pointer + * @connector: &struct drm_connector iteration cursor + * @connector_state: &struct drm_connector_state iteration cursor + * @__i: int iteration cursor, for macro-internal use + * + * This iterates over all connectors in an atomic update. Note that before the + * software state is committed (by calling drm_atomic_helper_swap_state(), this + * points to the new state, while afterwards it points to the old state. Due to + * this tricky confusion this macro is deprecated. + * + * FIXME: + * + * Replace all usage of this with one of the explicit iterators below and then + * remove this macro. + */ #define for_each_connector_in_state(__state, connector, connector_state, __i) \ for ((__i) = 0; \ (__i) < (__state)->num_connector && \ @@ -506,6 +523,20 @@ void drm_state_dump(struct drm_device *dev, struct drm_printer *p); (__i)++) \ for_each_if (connector) +/** + * for_each_oldnew_connector_in_state - iterate over all connectors in an atomic update + * @__state: &struct drm_atomic_state pointer + * @connector: &struct drm_connector iteration cursor + * @old_connector_state: &struct drm_connector_state iteration cursor for the + * old state + * @new_connector_state: &struct drm_connector_state iteration cursor for the + * new state + * @__i: int iteration cursor, for macro-internal use + * + * This iterates over all connectors in an atomic update, tracking both old and + * new state. This is useful in places where the state delta needs to be + * considered, for example in atomic check functions. + */ #define for_each_oldnew_connector_in_state(__state, connector, old_connector_state, new_connector_state, __i) \ for ((__i) = 0; \ (__i) < (__state)->num_connector && \ @@ -515,6 +546,18 @@ void drm_state_dump(struct drm_device *dev, struct drm_printer *p); (__i)++) \ for_each_if (connector) +/** + * for_each_old_connector_in_state - iterate over all connectors in an atomic update + * @__state: &struct drm_atomic_state pointer + * @connector: &struct drm_connector iteration cursor + * @old_connector_state: &struct drm_connector_state iteration cursor for the + * old state + * @__i: int iteration cursor, for macro-internal use + * + * This iterates over all connectors in an atomic update, tracking only the old + * state. This is useful in disable functions, where we need the old state the + * hardware is still in. + */ #define for_each_old_connector_in_state(__state, connector, old_connector_state, __i) \ for ((__i) = 0; \ (__i) < (__state)->num_connector && \ @@ -523,6 +566,18 @@ void drm_state_dump(struct drm_device *dev, struct drm_printer *p); (__i)++) \ for_each_if (connector) +/** + * for_each_new_connector_in_state - iterate over all connectors in an atomic update + * @__state: &struct drm_atomic_state pointer + * @connector: &struct drm_connector iteration cursor + * @new_connector_state: &struct drm_connector_state iteration cursor for the + * new state + * @__i: int iteration cursor, for macro-internal use + * + * This iterates over all connectors in an atomic update, tracking only the new + * state. This is useful in enable functions, where we need the new state the + * hardware should be in when the atomic commit operation has completed. + */ #define for_each_new_connector_in_state(__state, connector, new_connector_state, __i) \ for ((__i) = 0; \ (__i) < (__state)->num_connector && \ @@ -531,6 +586,23 @@ void drm_state_dump(struct drm_device *dev, struct drm_printer *p); (__i)++) \ for_each_if (connector) +/** + * for_each_crtc_in_state - iterate over all connectors in an atomic update + * @__state: &struct drm_atomic_state pointer + * @crtc: &struct drm_crtc iteration cursor + * @crtc_state: &struct drm_crtc_state iteration cursor + * @__i: int iteration cursor, for macro-internal use + * + * This iterates over all CRTCs in an atomic update. Note that before the + * software state is committed (by calling drm_atomic_helper_swap_state(), this + * points to the new state, while afterwards it points to the old state. Due to + * this tricky confusion this macro is deprecated. + * + * FIXME: + * + * Replace all usage of this with one of the explicit iterators below and then + * remove this macro. + */ #define for_each_crtc_in_state(__state, crtc, crtc_state, __i) \ for ((__i) = 0; \ (__i) < (__state)->dev->mode_config.num_crtc && \ @@ -539,6 +611,18 @@ void drm_state_dump(struct drm_device *dev, struct drm_printer *p); (__i)++) \ for_each_if (crtc_state) +/** + * for_each_oldnew_crtc_in_state - iterate over all CRTCs in an atomic update + * @__state: &struct drm_atomic_state pointer + * @crtc: &struct drm_crtc iteration cursor + * @old_crtc_state: &struct drm_crtc_state iteration cursor for the old state + * @new_crtc_state: &struct drm_crtc_state iteration cursor for the new state + * @__i: int iteration cursor, for macro-internal use + * + * This iterates over all CRTCs in an atomic update, tracking both old and + * new state. This is useful in places where the state delta needs to be + * considered, for example in atomic check functions. + */ #define for_each_oldnew_crtc_in_state(__state, crtc, old_crtc_state, new_crtc_state, __i) \ for ((__i) = 0; \ (__i) < (__state)->dev->mode_config.num_crtc && \ @@ -548,6 +632,17 @@ void drm_state_dump(struct drm_device *dev, struct drm_printer *p); (__i)++) \ for_each_if (crtc) +/** + * for_each_old_crtc_in_state - iterate over all CRTCs in an atomic update + * @__state: &struct drm_atomic_state pointer + * @crtc: &struct drm_crtc iteration cursor + * @old_crtc_state: &struct drm_crtc_state iteration cursor for the old state + * @__i: int iteration cursor, for macro-internal use + * + * This iterates over all CRTCs in an atomic update, tracking only the old + * state. This is useful in disable functions, where we need the old state the + * hardware is still in. + */ #define for_each_old_crtc_in_state(__state, crtc, old_crtc_state, __i) \ for ((__i) = 0; \ (__i) < (__state)->dev->mode_config.num_crtc && \ @@ -556,6 +651,17 @@ void drm_state_dump(struct drm_device *dev, struct drm_printer *p); (__i)++) \ for_each_if (crtc) +/** + * for_each_new_crtc_in_state - iterate over all CRTCs in an atomic update + * @__state: &struct drm_atomic_state pointer + * @crtc: &struct drm_crtc iteration cursor + * @new_crtc_state: &struct drm_crtc_state iteration cursor for the new state + * @__i: int iteration cursor, for macro-internal use + * + * This iterates over all CRTCs in an atomic update, tracking only the new + * state. This is useful in enable functions, where we need the new state the + * hardware should be in when the atomic commit operation has completed. + */ #define for_each_new_crtc_in_state(__state, crtc, new_crtc_state, __i) \ for ((__i) = 0; \ (__i) < (__state)->dev->mode_config.num_crtc && \ @@ -564,6 +670,23 @@ void drm_state_dump(struct drm_device *dev, struct drm_printer *p); (__i)++) \ for_each_if (crtc) +/** + * for_each_plane_in_state - iterate over all planes in an atomic update + * @__state: &struct drm_atomic_state pointer + * @plane: &struct drm_plane iteration cursor + * @plane_state: &struct drm_plane_state iteration cursor + * @__i: int iteration cursor, for macro-internal use + * + * This iterates over all planes in an atomic update. Note that before the + * software state is committed (by calling drm_atomic_helper_swap_state(), this + * points to the new state, while afterwards it points to the old state. Due to + * this tricky confusion this macro is deprecated. + * + * FIXME: + * + * Replace all usage of this with one of the explicit iterators below and then + * remove this macro. + */ #define for_each_plane_in_state(__state, plane, plane_state, __i) \ for ((__i) = 0; \ (__i) < (__state)->dev->mode_config.num_total_plane && \ @@ -572,6 +695,18 @@ void drm_state_dump(struct drm_device *dev, struct drm_printer *p); (__i)++) \ for_each_if (plane_state) +/** + * for_each_oldnew_plane_in_state - iterate over all planes in an atomic update + * @__state: &struct drm_atomic_state pointer + * @plane: &struct drm_plane iteration cursor + * @old_plane_state: &struct drm_plane_state iteration cursor for the old state + * @new_plane_state: &struct drm_plane_state iteration cursor for the new state + * @__i: int iteration cursor, for macro-internal use + * + * This iterates over all planes in an atomic update, tracking both old and + * new state. This is useful in places where the state delta needs to be + * considered, for example in atomic check functions. + */ #define for_each_oldnew_plane_in_state(__state, plane, old_plane_state, new_plane_state, __i) \ for ((__i) = 0; \ (__i) < (__state)->dev->mode_config.num_total_plane && \ @@ -581,6 +716,17 @@ void drm_state_dump(struct drm_device *dev, struct drm_printer *p); (__i)++) \ for_each_if (plane) +/** + * for_each_old_plane_in_state - iterate over all planes in an atomic update + * @__state: &struct drm_atomic_state pointer + * @plane: &struct drm_plane iteration cursor + * @old_plane_state: &struct drm_plane_state iteration cursor for the old state + * @__i: int iteration cursor, for macro-internal use + * + * This iterates over all planes in an atomic update, tracking only the old + * state. This is useful in disable functions, where we need the old state the + * hardware is still in. + */ #define for_each_old_plane_in_state(__state, plane, old_plane_state, __i) \ for ((__i) = 0; \ (__i) < (__state)->dev->mode_config.num_total_plane && \ @@ -589,6 +735,17 @@ void drm_state_dump(struct drm_device *dev, struct drm_printer *p); (__i)++) \ for_each_if (plane) +/** + * for_each_new_plane_in_state - iterate over all planes in an atomic update + * @__state: &struct drm_atomic_state pointer + * @plane: &struct drm_plane iteration cursor + * @new_plane_state: &struct drm_plane_state iteration cursor for the new state + * @__i: int iteration cursor, for macro-internal use + * + * This iterates over all planes in an atomic update, tracking only the new + * state. This is useful in enable functions, where we need the new state the + * hardware should be in when the atomic commit operation has completed. + */ #define for_each_new_plane_in_state(__state, plane, new_plane_state, __i) \ for ((__i) = 0; \ (__i) < (__state)->dev->mode_config.num_total_plane && \ @@ -603,7 +760,7 @@ void drm_state_dump(struct drm_device *dev, struct drm_printer *p); * * To give drivers flexibility &struct drm_crtc_state has 3 booleans to track * whether the state CRTC changed enough to need a full modeset cycle: - * connectors_changed, mode_changed and active_changed. This helper simply + * planes_changed, mode_changed and active_changed. This helper simply * combines these three to compute the overall need for a modeset for @state. * * The atomic helper code sets these booleans, but drivers can and should diff --git a/include/drm/drm_atomic_helper.h b/include/drm/drm_atomic_helper.h index dc16274987c7..fd395dc050ee 100644 --- a/include/drm/drm_atomic_helper.h +++ b/include/drm/drm_atomic_helper.h @@ -94,16 +94,20 @@ int drm_atomic_helper_update_plane(struct drm_plane *plane, int crtc_x, int crtc_y, unsigned int crtc_w, unsigned int crtc_h, uint32_t src_x, uint32_t src_y, - uint32_t src_w, uint32_t src_h); -int drm_atomic_helper_disable_plane(struct drm_plane *plane); + uint32_t src_w, uint32_t src_h, + struct drm_modeset_acquire_ctx *ctx); +int drm_atomic_helper_disable_plane(struct drm_plane *plane, + struct drm_modeset_acquire_ctx *ctx); int __drm_atomic_helper_disable_plane(struct drm_plane *plane, struct drm_plane_state *plane_state); -int drm_atomic_helper_set_config(struct drm_mode_set *set); +int drm_atomic_helper_set_config(struct drm_mode_set *set, + struct drm_modeset_acquire_ctx *ctx); int __drm_atomic_helper_set_config(struct drm_mode_set *set, struct drm_atomic_state *state); int drm_atomic_helper_disable_all(struct drm_device *dev, struct drm_modeset_acquire_ctx *ctx); +void drm_atomic_helper_shutdown(struct drm_device *dev); struct drm_atomic_state *drm_atomic_helper_suspend(struct drm_device *dev); int drm_atomic_helper_commit_duplicated_state(struct drm_atomic_state *state, struct drm_modeset_acquire_ctx *ctx); @@ -122,13 +126,15 @@ int drm_atomic_helper_connector_set_property(struct drm_connector *connector, int drm_atomic_helper_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb, struct drm_pending_vblank_event *event, - uint32_t flags); + uint32_t flags, + struct drm_modeset_acquire_ctx *ctx); int drm_atomic_helper_page_flip_target( struct drm_crtc *crtc, struct drm_framebuffer *fb, struct drm_pending_vblank_event *event, uint32_t flags, - uint32_t target); + uint32_t target, + struct drm_modeset_acquire_ctx *ctx); int drm_atomic_helper_connector_dpms(struct drm_connector *connector, int mode); struct drm_encoder * diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h index f8b766d70a46..941f57f311aa 100644 --- a/include/drm/drm_connector.h +++ b/include/drm/drm_connector.h @@ -133,6 +133,7 @@ struct drm_scdc { * This information is available in CEA-861-F extension blocks (like HF-VSDB). */ struct drm_hdmi_info { + /** @scdc: sink's scdc support and capabilities */ struct drm_scdc scdc; }; @@ -655,7 +656,6 @@ struct drm_cmdline_mode { * @bad_edid_counter: track sinks that give us an EDID with invalid checksum * @edid_corrupt: indicates whether the last read EDID was corrupt * @debugfs_entry: debugfs directory for this connector - * @state: current atomic state for this connector * @has_tile: is this connector connected to a tiled monitor * @tile_group: tile group for the connected monitor * @tile_is_single_monitor: whether the tile is one monitor housing @@ -823,6 +823,21 @@ struct drm_connector { struct dentry *debugfs_entry; + /** + * @state: + * + * Current atomic state for this connector. + * + * This is protected by @drm_mode_config.connection_mutex. Note that + * nonblocking atomic commits access the current connector state without + * taking locks. Either by going through the &struct drm_atomic_state + * pointers, see for_each_connector_in_state(), + * for_each_oldnew_connector_in_state(), + * for_each_old_connector_in_state() and + * for_each_new_connector_in_state(). Or through careful ordering of + * atomic commit operations as implemented in the atomic helpers, see + * &struct drm_crtc_commit. + */ struct drm_connector_state *state; /* DisplayID bits */ diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h index 6ef59da3fd8e..2be2192b1373 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h @@ -347,7 +347,8 @@ struct drm_crtc_funcs { * * 0 on success or a negative error code on failure. */ - int (*set_config)(struct drm_mode_set *set); + int (*set_config)(struct drm_mode_set *set, + struct drm_modeset_acquire_ctx *ctx); /** * @page_flip: @@ -405,7 +406,8 @@ struct drm_crtc_funcs { int (*page_flip)(struct drm_crtc *crtc, struct drm_framebuffer *fb, struct drm_pending_vblank_event *event, - uint32_t flags); + uint32_t flags, + struct drm_modeset_acquire_ctx *ctx); /** * @page_flip_target: @@ -423,7 +425,8 @@ struct drm_crtc_funcs { int (*page_flip_target)(struct drm_crtc *crtc, struct drm_framebuffer *fb, struct drm_pending_vblank_event *event, - uint32_t flags, uint32_t target); + uint32_t flags, uint32_t target, + struct drm_modeset_acquire_ctx *ctx); /** * @set_property: @@ -590,9 +593,12 @@ struct drm_crtc_funcs { * When CRC generation is enabled, the driver should call * drm_crtc_add_crc_entry() at each frame, providing any information * that characterizes the frame contents in the crcN arguments, as - * provided from the configured source. Drivers must accept a "auto" + * provided from the configured source. Drivers must accept an "auto" * source name that will select a default source for this CRTC. * + * Note that "auto" can depend upon the current modeset configuration, + * e.g. it could pick an encoder or output specific CRC sampling point. + * * This callback is optional if the driver does not support any CRC * generation functionality. * @@ -696,10 +702,12 @@ struct drm_crtc { /** * @mutex: * - * This provides a read lock for the overall crtc state (mode, dpms + * This provides a read lock for the overall CRTC state (mode, dpms * state, ...) and a write lock for everything which can be update - * without a full modeset (fb, cursor data, crtc properties ...). A full + * without a full modeset (fb, cursor data, CRTC properties ...). A full * modeset also need to grab &drm_mode_config.connection_mutex. + * + * For atomic drivers specifically this protects @state. */ struct drm_modeset_lock mutex; @@ -745,6 +753,14 @@ struct drm_crtc { * @state: * * Current atomic state for this CRTC. + * + * This is protected by @mutex. Note that nonblocking atomic commits + * access the current CRTC state without taking locks. Either by going + * through the &struct drm_atomic_state pointers, see + * for_each_crtc_in_state(), for_each_oldnew_crtc_in_state(), + * for_each_old_crtc_in_state() and for_each_new_crtc_in_state(). Or + * through careful ordering of atomic commit operations as implemented + * in the atomic helpers, see &struct drm_crtc_commit. */ struct drm_crtc_state *state; diff --git a/include/drm/drm_crtc_helper.h b/include/drm/drm_crtc_helper.h index d026f5017c33..43505c7b2b3f 100644 --- a/include/drm/drm_crtc_helper.h +++ b/include/drm/drm_crtc_helper.h @@ -43,18 +43,19 @@ #include <drm/drm_modeset_helper_vtables.h> #include <drm/drm_modeset_helper.h> -extern void drm_helper_disable_unused_functions(struct drm_device *dev); -extern int drm_crtc_helper_set_config(struct drm_mode_set *set); -extern bool drm_crtc_helper_set_mode(struct drm_crtc *crtc, - struct drm_display_mode *mode, - int x, int y, - struct drm_framebuffer *old_fb); -extern bool drm_helper_crtc_in_use(struct drm_crtc *crtc); -extern bool drm_helper_encoder_in_use(struct drm_encoder *encoder); +void drm_helper_disable_unused_functions(struct drm_device *dev); +int drm_crtc_helper_set_config(struct drm_mode_set *set, + struct drm_modeset_acquire_ctx *ctx); +bool drm_crtc_helper_set_mode(struct drm_crtc *crtc, + struct drm_display_mode *mode, + int x, int y, + struct drm_framebuffer *old_fb); +bool drm_helper_crtc_in_use(struct drm_crtc *crtc); +bool drm_helper_encoder_in_use(struct drm_encoder *encoder); -extern int drm_helper_connector_dpms(struct drm_connector *connector, int mode); +int drm_helper_connector_dpms(struct drm_connector *connector, int mode); -extern void drm_helper_resume_force_mode(struct drm_device *dev); +void drm_helper_resume_force_mode(struct drm_device *dev); int drm_helper_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode, int x, int y, @@ -63,15 +64,15 @@ int drm_helper_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y, struct drm_framebuffer *old_fb); /* drm_probe_helper.c */ -extern int drm_helper_probe_single_connector_modes(struct drm_connector - *connector, uint32_t maxX, - uint32_t maxY); -extern void drm_kms_helper_poll_init(struct drm_device *dev); -extern void drm_kms_helper_poll_fini(struct drm_device *dev); -extern bool drm_helper_hpd_irq_event(struct drm_device *dev); -extern void drm_kms_helper_hotplug_event(struct drm_device *dev); +int drm_helper_probe_single_connector_modes(struct drm_connector + *connector, uint32_t maxX, + uint32_t maxY); +void drm_kms_helper_poll_init(struct drm_device *dev); +void drm_kms_helper_poll_fini(struct drm_device *dev); +bool drm_helper_hpd_irq_event(struct drm_device *dev); +void drm_kms_helper_hotplug_event(struct drm_device *dev); -extern void drm_kms_helper_poll_disable(struct drm_device *dev); -extern void drm_kms_helper_poll_enable(struct drm_device *dev); +void drm_kms_helper_poll_disable(struct drm_device *dev); +void drm_kms_helper_poll_enable(struct drm_device *dev); #endif diff --git a/include/drm/drm_debugfs.h b/include/drm/drm_debugfs.h new file mode 100644 index 000000000000..ac0f75df1ac9 --- /dev/null +++ b/include/drm/drm_debugfs.h @@ -0,0 +1,101 @@ +/* + * 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_DEBUGFS_H_ +#define _DRM_DEBUGFS_H_ + +/** + * struct drm_info_list - debugfs info list entry + * + * This structure represents a debugfs file to be created by the drm + * core. + */ +struct drm_info_list { + /** @name: file name */ + const char *name; + /** + * @show: + * + * Show callback. &seq_file->private will be set to the &struct + * drm_info_node corresponding to the instance of this info on a given + * &struct drm_minor. + */ + int (*show)(struct seq_file*, void*); + /** @driver_features: Required driver features for this entry */ + u32 driver_features; + /** @data: Driver-private data, should not be device-specific. */ + void *data; +}; + +/** + * struct drm_info_node - Per-minor debugfs node structure + * + * This structure represents a debugfs file, as an instantiation of a &struct + * drm_info_list on a &struct drm_minor. + * + * FIXME: + * + * No it doesn't make a hole lot of sense that we duplicate debugfs entries for + * both the render and the primary nodes, but that's how this has organically + * grown. It should probably be fixed, with a compatibility link, if needed. + */ +struct drm_info_node { + /** @minor: &struct drm_minor for this node. */ + struct drm_minor *minor; + /** @info_ent: template for this node. */ + const struct drm_info_list *info_ent; + /* private: */ + struct list_head list; + struct dentry *dent; +}; + +#if defined(CONFIG_DEBUG_FS) +int drm_debugfs_create_files(const struct drm_info_list *files, + int count, struct dentry *root, + struct drm_minor *minor); +int drm_debugfs_remove_files(const struct drm_info_list *files, + int count, struct drm_minor *minor); +#else +static inline int drm_debugfs_create_files(const struct drm_info_list *files, + int count, struct dentry *root, + struct drm_minor *minor) +{ + return 0; +} + +static inline int drm_debugfs_remove_files(const struct drm_info_list *files, + int count, struct drm_minor *minor) +{ + return 0; +} +#endif + +#endif /* _DRM_DEBUGFS_H_ */ diff --git a/include/drm/drm_dp_mst_helper.h b/include/drm/drm_dp_mst_helper.h index f4b4d154b98e..5b024764666c 100644 --- a/include/drm/drm_dp_mst_helper.h +++ b/include/drm/drm_dp_mst_helper.h @@ -479,18 +479,6 @@ struct drm_dp_mst_topology_mgr { * @pbn_div: PBN to slots divisor. */ int pbn_div; - /** - * @total_slots: Total slots that can be allocated. - */ - int total_slots; - /** - * @avail_slots: Still available slots that can be allocated. - */ - int avail_slots; - /** - * @total_pbn: Total PBN count. - */ - int total_pbn; /** * @qlock: protects @tx_msg_downq, the &drm_dp_mst_branch.txslost and @@ -579,7 +567,8 @@ struct edid *drm_dp_mst_get_edid(struct drm_connector *connector, struct drm_dp_ int drm_dp_calc_pbn_mode(int clock, int bpp); -bool drm_dp_mst_allocate_vcpi(struct drm_dp_mst_topology_mgr *mgr, struct drm_dp_mst_port *port, int pbn, int *slots); +bool drm_dp_mst_allocate_vcpi(struct drm_dp_mst_topology_mgr *mgr, + struct drm_dp_mst_port *port, int pbn, int slots); int drm_dp_mst_get_vcpi_slots(struct drm_dp_mst_topology_mgr *mgr, struct drm_dp_mst_port *port); diff --git a/include/drm/drm_drv.h b/include/drm/drm_drv.h index 8f900fb30275..53b98321df9b 100644 --- a/include/drm/drm_drv.h +++ b/include/drm/drm_drv.h @@ -522,11 +522,11 @@ struct drm_driver { int dev_priv_size; }; -extern __printf(6, 7) +__printf(6, 7) void drm_dev_printk(const struct device *dev, const char *level, unsigned int category, const char *function_name, const char *prefix, const char *format, ...); -extern __printf(3, 4) +__printf(3, 4) void drm_printk(const char *level, unsigned int category, const char *format, ...); extern unsigned int drm_debug; diff --git a/include/drm/drm_fourcc.h b/include/drm/drm_fourcc.h index fcc08da850c8..6942e84b6edd 100644 --- a/include/drm/drm_fourcc.h +++ b/include/drm/drm_fourcc.h @@ -25,6 +25,9 @@ #include <linux/types.h> #include <uapi/drm/drm_fourcc.h> +struct drm_device; +struct drm_mode_fb_cmd2; + /** * struct drm_format_info - information about a DRM format * @format: 4CC format identifier (DRM_FORMAT_*) @@ -55,6 +58,9 @@ struct drm_format_name_buf { const struct drm_format_info *__drm_format_info(u32 format); const struct drm_format_info *drm_format_info(u32 format); +const struct drm_format_info * +drm_get_format_info(struct drm_device *dev, + const struct drm_mode_fb_cmd2 *mode_cmd); uint32_t drm_mode_legacy_fb_format(uint32_t bpp, uint32_t depth); int drm_format_num_planes(uint32_t format); int drm_format_plane_cpp(uint32_t format, int plane); diff --git a/include/drm/drm_global.h b/include/drm/drm_global.h index a06805eaf649..3a830602a2e4 100644 --- a/include/drm/drm_global.h +++ b/include/drm/drm_global.h @@ -45,9 +45,9 @@ struct drm_global_reference { void (*release) (struct drm_global_reference *); }; -extern void drm_global_init(void); -extern void drm_global_release(void); -extern int drm_global_item_ref(struct drm_global_reference *ref); -extern void drm_global_item_unref(struct drm_global_reference *ref); +void drm_global_init(void); +void drm_global_release(void); +int drm_global_item_ref(struct drm_global_reference *ref); +void drm_global_item_unref(struct drm_global_reference *ref); #endif diff --git a/include/drm/drm_hashtab.h b/include/drm/drm_hashtab.h index fce2ef3fdfff..bb95ff011baf 100644 --- a/include/drm/drm_hashtab.h +++ b/include/drm/drm_hashtab.h @@ -49,17 +49,17 @@ struct drm_open_hash { u8 order; }; -extern int drm_ht_create(struct drm_open_hash *ht, unsigned int order); -extern int drm_ht_insert_item(struct drm_open_hash *ht, struct drm_hash_item *item); -extern int drm_ht_just_insert_please(struct drm_open_hash *ht, struct drm_hash_item *item, - unsigned long seed, int bits, int shift, - unsigned long add); -extern int drm_ht_find_item(struct drm_open_hash *ht, unsigned long key, struct drm_hash_item **item); +int drm_ht_create(struct drm_open_hash *ht, unsigned int order); +int drm_ht_insert_item(struct drm_open_hash *ht, struct drm_hash_item *item); +int drm_ht_just_insert_please(struct drm_open_hash *ht, struct drm_hash_item *item, + unsigned long seed, int bits, int shift, + unsigned long add); +int drm_ht_find_item(struct drm_open_hash *ht, unsigned long key, struct drm_hash_item **item); -extern void drm_ht_verbose_list(struct drm_open_hash *ht, unsigned long key); -extern int drm_ht_remove_key(struct drm_open_hash *ht, unsigned long key); -extern int drm_ht_remove_item(struct drm_open_hash *ht, struct drm_hash_item *item); -extern void drm_ht_remove(struct drm_open_hash *ht); +void drm_ht_verbose_list(struct drm_open_hash *ht, unsigned long key); +int drm_ht_remove_key(struct drm_open_hash *ht, unsigned long key); +int drm_ht_remove_item(struct drm_open_hash *ht, struct drm_hash_item *item); +void drm_ht_remove(struct drm_open_hash *ht); /* * RCU-safe interface diff --git a/include/drm/drm_ioctl.h b/include/drm/drm_ioctl.h new file mode 100644 index 000000000000..f17ee077f649 --- /dev/null +++ b/include/drm/drm_ioctl.h @@ -0,0 +1,102 @@ +/* + * 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_IOCTL_H_ +#define _DRM_IOCTL_H_ + +#include <linux/types.h> + +#include <asm/ioctl.h> + +struct drm_device; +struct drm_file; +struct file; + +/** + * Ioctl function type. + * + * \param inode device inode. + * \param file_priv DRM file private pointer. + * \param cmd command. + * \param arg argument. + */ +typedef int drm_ioctl_t(struct drm_device *dev, void *data, + struct drm_file *file_priv); + +typedef int drm_ioctl_compat_t(struct file *filp, unsigned int cmd, + unsigned long arg); + +#define DRM_IOCTL_NR(n) _IOC_NR(n) +#define DRM_MAJOR 226 + +#define DRM_AUTH 0x1 +#define DRM_MASTER 0x2 +#define DRM_ROOT_ONLY 0x4 +#define DRM_CONTROL_ALLOW 0x8 +#define DRM_UNLOCKED 0x10 +#define DRM_RENDER_ALLOW 0x20 + +struct drm_ioctl_desc { + unsigned int cmd; + int flags; + drm_ioctl_t *func; + const char *name; +}; + +/** + * Creates a driver or general drm_ioctl_desc array entry for the given + * ioctl, for use by drm_ioctl(). + */ + +#define DRM_IOCTL_DEF_DRV(ioctl, _func, _flags) \ + [DRM_IOCTL_NR(DRM_IOCTL_##ioctl) - DRM_COMMAND_BASE] = { \ + .cmd = DRM_IOCTL_##ioctl, \ + .func = _func, \ + .flags = _flags, \ + .name = #ioctl \ + } + +int drm_ioctl_permit(u32 flags, struct drm_file *file_priv); +long drm_ioctl(struct file *filp, unsigned int cmd, unsigned long arg); +#ifdef CONFIG_COMPAT +long drm_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg); +#else +/* Let drm_compat_ioctl be assigned to .compat_ioctl unconditionally */ +#define drm_compat_ioctl NULL +#endif +bool drm_ioctl_flags(unsigned int nr, unsigned int *flags); + +int drm_noop(struct drm_device *dev, void *data, + struct drm_file *file_priv); +int drm_invalid_op(struct drm_device *dev, void *data, + struct drm_file *file_priv); + +#endif /* _DRM_IOCTL_H_ */ diff --git a/include/drm/drm_mode_config.h b/include/drm/drm_mode_config.h index ea169a90b3c4..42981711189b 100644 --- a/include/drm/drm_mode_config.h +++ b/include/drm/drm_mode_config.h @@ -34,6 +34,7 @@ struct drm_file; struct drm_device; struct drm_atomic_state; struct drm_mode_fb_cmd2; +struct drm_format_info; /** * struct drm_mode_config_funcs - basic driver provided mode setting functions @@ -70,6 +71,19 @@ struct drm_mode_config_funcs { const struct drm_mode_fb_cmd2 *mode_cmd); /** + * @get_format_info: + * + * Allows a driver to return custom format information for special + * fb layouts (eg. ones with auxiliary compression control planes). + * + * RETURNS: + * + * The format information specific to the given fb metadata, or + * NULL if none is found. + */ + const struct drm_format_info *(*get_format_info)(const struct drm_mode_fb_cmd2 *mode_cmd); + + /** * @output_poll_changed: * * Callback used by helpers to inform the driver of output configuration @@ -293,21 +307,6 @@ struct drm_mode_config_funcs { /** * struct drm_mode_config - Mode configuration control structure - * @mutex: mutex protecting KMS related lists and structures - * @connection_mutex: ww mutex protecting connector state and routing - * @acquire_ctx: global implicit acquire context used by atomic drivers for - * legacy IOCTLs - * @fb_lock: mutex to protect fb state and lists - * @num_fb: number of fbs available - * @fb_list: list of framebuffers available - * @num_encoder: number of encoders on this device - * @encoder_list: list of encoder objects - * @num_overlay_plane: number of overlay planes on this device - * @num_total_plane: number of universal (i.e. with primary/curso) planes on this device - * @plane_list: list of plane objects - * @num_crtc: number of CRTCs on this device - * @crtc_list: list of CRTC objects - * @property_list: list of property objects * @min_width: minimum pixel width on this device * @min_height: minimum pixel height on this device * @max_width: maximum pixel width on this device @@ -318,9 +317,6 @@ struct drm_mode_config_funcs { * @poll_running: track polling status for this device * @delayed_event: track delayed poll uevent deliver for this device * @output_poll_work: delayed work for polling in process context - * @property_blob_list: list of all the blob property objects - * @blob_lock: mutex for blob property allocation and management - * @*_property: core property tracking * @preferred_depth: preferred RBG pixel depth, used by fb helpers * @prefer_shadow: hint to userspace to prefer shadow-fb rendering * @cursor_width: hint to userspace for max cursor width @@ -332,9 +328,37 @@ struct drm_mode_config_funcs { * global restrictions are also here, e.g. dimension restrictions. */ struct drm_mode_config { - struct mutex mutex; /* protects configuration (mode lists etc.) */ - struct drm_modeset_lock connection_mutex; /* protects connector->encoder and encoder->crtc links */ - struct drm_modeset_acquire_ctx *acquire_ctx; /* for legacy _lock_all() / _unlock_all() */ + /** + * @mutex: + * + * This is the big scary modeset BKL which protects everything that + * isn't protect otherwise. Scope is unclear and fuzzy, try to remove + * anything from under it's protection and move it into more well-scoped + * locks. + * + * The one important thing this protects is the use of @acquire_ctx. + */ + struct mutex mutex; + + /** + * @connection_mutex: + * + * This protects connector state and the connector to encoder to CRTC + * routing chain. + * + * For atomic drivers specifically this protects &drm_connector.state. + */ + struct drm_modeset_lock connection_mutex; + + /** + * @acquire_ctx: + * + * Global implicit acquire context used by atomic drivers for legacy + * IOCTLs. Deprecated, since implicit locking contexts make it + * impossible to use driver-private &struct drm_modeset_lock. Users of + * this must hold @mutex. + */ + struct drm_modeset_acquire_ctx *acquire_ctx; /** * @idr_mutex: @@ -360,8 +384,11 @@ struct drm_mode_config { */ struct idr tile_idr; - struct mutex fb_lock; /* proctects global and per-file fb lists */ + /** @fb_lock: Mutex to protect fb the global @fb_list and @num_fb. */ + struct mutex fb_lock; + /** @num_fb: Number of entries on @fb_list. */ int num_fb; + /** @fb_list: List of all &struct drm_framebuffer. */ struct list_head fb_list; /** @@ -379,27 +406,80 @@ struct drm_mode_config { */ struct ida connector_ida; /** - * @connector_list: List of connector objects. Protected by - * @connector_list_lock. Only use drm_for_each_connector_iter() and + * @connector_list: + * + * List of connector objects linked with &drm_connector.head. Protected + * by @connector_list_lock. Only use drm_for_each_connector_iter() and * &struct drm_connector_list_iter to walk this list. */ struct list_head connector_list; + /** + * @num_encoder: + * + * Number of encoders on this device. This is invariant over the + * lifetime of a device and hence doesn't need any locks. + */ int num_encoder; + /** + * @encoder_list: + * + * List of encoder objects linked with &drm_encoder.head. This is + * invariant over the lifetime of a device and hence doesn't need any + * locks. + */ struct list_head encoder_list; - /* - * Track # of overlay planes separately from # of total planes. By - * default we only advertise overlay planes to userspace; if userspace - * sets the "universal plane" capability bit, we'll go ahead and - * expose all planes. + /** + * @num_overlay_plane: + * + * Number of overlay planes on this device, excluding primary and cursor + * planes. + * + * Track number of overlay planes separately from number of total + * planes. By default we only advertise overlay planes to userspace; if + * userspace sets the "universal plane" capability bit, we'll go ahead + * and expose all planes. This is invariant over the lifetime of a + * device and hence doesn't need any locks. */ int num_overlay_plane; + /** + * @num_total_plane: + * + * Number of universal (i.e. with primary/curso) planes on this device. + * This is invariant over the lifetime of a device and hence doesn't + * need any locks. + */ int num_total_plane; + /** + * @plane_list: + * + * List of plane objects linked with &drm_plane.head. This is invariant + * over the lifetime of a device and hence doesn't need any locks. + */ struct list_head plane_list; + /** + * @num_crtc: + * + * Number of CRTCs on this device linked with &drm_crtc.head. This is invariant over the lifetime + * of a device and hence doesn't need any locks. + */ int num_crtc; + /** + * @crtc_list: + * + * List of CRTC objects linked with &drm_crtc.head. This is invariant + * over the lifetime of a device and hence doesn't need any locks. + */ struct list_head crtc_list; + /** + * @property_list: + * + * List of property type objects linked with &drm_property.head. This is + * invariant over the lifetime of a device and hence doesn't need any + * locks. + */ struct list_head property_list; int min_width, min_height; @@ -413,10 +493,24 @@ struct drm_mode_config { bool delayed_event; struct delayed_work output_poll_work; + /** + * @blob_lock: + * + * Mutex for blob property allocation and management, protects + * @property_blob_list and &drm_file.blobs. + */ struct mutex blob_lock; - /* pointers to standard properties */ + /** + * @property_blob_list: + * + * List of all the blob property objects linked with + * &drm_property_blob.head. Protected by @blob_lock. + */ struct list_head property_blob_list; + + /* pointers to standard properties */ + /** * @edid_property: Default connector property to hold the EDID of the * currently connected sink, if any. diff --git a/include/drm/drm_of.h b/include/drm/drm_of.h index 26a64805cc15..d1fc563f068a 100644 --- a/include/drm/drm_of.h +++ b/include/drm/drm_of.h @@ -11,18 +11,18 @@ struct drm_encoder; struct device_node; #ifdef CONFIG_OF -extern uint32_t drm_of_find_possible_crtcs(struct drm_device *dev, - struct device_node *port); -extern void drm_of_component_match_add(struct device *master, - struct component_match **matchptr, - int (*compare)(struct device *, void *), - struct device_node *node); -extern int drm_of_component_probe(struct device *dev, - int (*compare_of)(struct device *, void *), - const struct component_master_ops *m_ops); -extern int drm_of_encoder_active_endpoint(struct device_node *node, - struct drm_encoder *encoder, - struct of_endpoint *endpoint); +uint32_t drm_of_find_possible_crtcs(struct drm_device *dev, + struct device_node *port); +void drm_of_component_match_add(struct device *master, + struct component_match **matchptr, + int (*compare)(struct device *, void *), + struct device_node *node); +int drm_of_component_probe(struct device *dev, + int (*compare_of)(struct device *, void *), + const struct component_master_ops *m_ops); +int drm_of_encoder_active_endpoint(struct device_node *node, + struct drm_encoder *encoder, + struct of_endpoint *endpoint); #else static inline uint32_t drm_of_find_possible_crtcs(struct drm_device *dev, struct device_node *port) diff --git a/include/drm/drm_pci.h b/include/drm/drm_pci.h index f5ebfcaf69e0..4579fac1080c 100644 --- a/include/drm/drm_pci.h +++ b/include/drm/drm_pci.h @@ -39,17 +39,17 @@ struct drm_device; struct drm_driver; struct drm_master; -extern struct drm_dma_handle *drm_pci_alloc(struct drm_device *dev, size_t size, - size_t align); -extern void drm_pci_free(struct drm_device *dev, struct drm_dma_handle * dmah); +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); -extern int drm_pci_init(struct drm_driver *driver, struct pci_driver *pdriver); -extern void drm_pci_exit(struct drm_driver *driver, struct pci_driver *pdriver); +int drm_pci_init(struct drm_driver *driver, struct pci_driver *pdriver); +void drm_pci_exit(struct drm_driver *driver, struct pci_driver *pdriver); #ifdef CONFIG_PCI -extern int drm_get_pci_dev(struct pci_dev *pdev, - const struct pci_device_id *ent, - struct drm_driver *driver); -extern int drm_pci_set_busid(struct drm_device *dev, struct drm_master *master); +int drm_get_pci_dev(struct pci_dev *pdev, + const struct pci_device_id *ent, + struct drm_driver *driver); +int drm_pci_set_busid(struct drm_device *dev, struct drm_master *master); #else static inline int drm_get_pci_dev(struct pci_dev *pdev, const struct pci_device_id *ent, @@ -69,7 +69,7 @@ static inline int drm_pci_set_busid(struct drm_device *dev, #define DRM_PCIE_SPEED_50 2 #define DRM_PCIE_SPEED_80 4 -extern int drm_pcie_get_speed_cap_mask(struct drm_device *dev, u32 *speed_mask); -extern int drm_pcie_get_max_link_width(struct drm_device *dev, u32 *mlw); +int drm_pcie_get_speed_cap_mask(struct drm_device *dev, u32 *speed_mask); +int drm_pcie_get_max_link_width(struct drm_device *dev, u32 *mlw); #endif /* _DRM_PCI_H_ */ diff --git a/include/drm/drm_plane.h b/include/drm/drm_plane.h index 20867b4371ab..9ab3e7044812 100644 --- a/include/drm/drm_plane.h +++ b/include/drm/drm_plane.h @@ -29,6 +29,7 @@ struct drm_crtc; struct drm_printer; +struct drm_modeset_acquire_ctx; /** * struct drm_plane_state - mutable plane state @@ -184,7 +185,8 @@ struct drm_plane_funcs { int crtc_x, int crtc_y, unsigned int crtc_w, unsigned int crtc_h, uint32_t src_x, uint32_t src_y, - uint32_t src_w, uint32_t src_h); + uint32_t src_w, uint32_t src_h, + struct drm_modeset_acquire_ctx *ctx); /** * @disable_plane: @@ -201,7 +203,8 @@ struct drm_plane_funcs { * * 0 on success or a negative error code on failure. */ - int (*disable_plane)(struct drm_plane *plane); + int (*disable_plane)(struct drm_plane *plane, + struct drm_modeset_acquire_ctx *ctx); /** * @destroy: @@ -456,7 +459,6 @@ enum drm_plane_type { * @funcs: helper functions * @properties: property tracking for this plane * @type: type of plane (overlay, primary, cursor) - * @state: current atomic state for this plane * @zpos_property: zpos property for this plane * @rotation_property: rotation property for this plane * @helper_private: mid-layer private data @@ -473,6 +475,8 @@ struct drm_plane { * Protects modeset plane state, together with the &drm_crtc.mutex of * CRTC this plane is linked to (when active, getting activated or * getting disabled). + * + * For atomic drivers specifically this protects @state. */ struct drm_modeset_lock mutex; @@ -502,6 +506,19 @@ struct drm_plane { const struct drm_plane_helper_funcs *helper_private; + /** + * @state: + * + * Current atomic state for this plane. + * + * This is protected by @mutex. Note that nonblocking atomic commits + * access the current plane state without taking locks. Either by going + * through the &struct drm_atomic_state pointers, see + * for_each_plane_in_state(), for_each_oldnew_plane_in_state(), + * for_each_old_plane_in_state() and for_each_new_plane_in_state(). Or + * through careful ordering of atomic commit operations as implemented + * in the atomic helpers, see &struct drm_crtc_commit. + */ struct drm_plane_state *state; struct drm_property *zpos_property; @@ -510,7 +527,7 @@ struct drm_plane { #define obj_to_plane(x) container_of(x, struct drm_plane, base) -extern __printf(8, 9) +__printf(8, 9) int drm_universal_plane_init(struct drm_device *dev, struct drm_plane *plane, uint32_t possible_crtcs, @@ -519,13 +536,13 @@ int drm_universal_plane_init(struct drm_device *dev, unsigned int format_count, enum drm_plane_type type, const char *name, ...); -extern int drm_plane_init(struct drm_device *dev, - struct drm_plane *plane, - uint32_t possible_crtcs, - const struct drm_plane_funcs *funcs, - const uint32_t *formats, unsigned int format_count, - bool is_primary); -extern void drm_plane_cleanup(struct drm_plane *plane); +int drm_plane_init(struct drm_device *dev, + struct drm_plane *plane, + uint32_t possible_crtcs, + const struct drm_plane_funcs *funcs, + const uint32_t *formats, unsigned int format_count, + bool is_primary); +void drm_plane_cleanup(struct drm_plane *plane); /** * drm_plane_index - find the index of a registered plane @@ -538,8 +555,8 @@ static inline unsigned int drm_plane_index(struct drm_plane *plane) { return plane->index; } -extern struct drm_plane * drm_plane_from_index(struct drm_device *dev, int idx); -extern void drm_plane_force_disable(struct drm_plane *plane); +struct drm_plane * drm_plane_from_index(struct drm_device *dev, int idx); +void drm_plane_force_disable(struct drm_plane *plane); int drm_mode_plane_set_obj_prop(struct drm_plane *plane, struct drm_property *property, diff --git a/include/drm/drm_plane_helper.h b/include/drm/drm_plane_helper.h index c18959685c06..7c8a00ceadb7 100644 --- a/include/drm/drm_plane_helper.h +++ b/include/drm/drm_plane_helper.h @@ -61,8 +61,10 @@ int drm_primary_helper_update(struct drm_plane *plane, int crtc_x, int crtc_y, unsigned int crtc_w, unsigned int crtc_h, uint32_t src_x, uint32_t src_y, - uint32_t src_w, uint32_t src_h); -int drm_primary_helper_disable(struct drm_plane *plane); + uint32_t src_w, uint32_t src_h, + struct drm_modeset_acquire_ctx *ctx); +int drm_primary_helper_disable(struct drm_plane *plane, + struct drm_modeset_acquire_ctx *ctx); void drm_primary_helper_destroy(struct drm_plane *plane); extern const struct drm_plane_funcs drm_primary_helper_funcs; diff --git a/include/drm/drm_prime.h b/include/drm/drm_prime.h index d09563ecc4b7..0b2a235c4be0 100644 --- a/include/drm/drm_prime.h +++ b/include/drm/drm_prime.h @@ -57,24 +57,24 @@ struct drm_device; struct drm_gem_object; struct drm_file; -extern struct dma_buf *drm_gem_prime_export(struct drm_device *dev, - struct drm_gem_object *obj, - int flags); -extern 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); -extern struct drm_gem_object *drm_gem_prime_import(struct drm_device *dev, - struct dma_buf *dma_buf); -extern 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_prime_export(struct drm_device *dev, + struct drm_gem_object *obj, + int flags); +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); +struct drm_gem_object *drm_gem_prime_import(struct drm_device *dev, + struct dma_buf *dma_buf); +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); -extern void drm_gem_dmabuf_release(struct dma_buf *dma_buf); +void drm_gem_dmabuf_release(struct dma_buf *dma_buf); -extern int drm_prime_sg_to_page_addr_arrays(struct sg_table *sgt, struct page **pages, - dma_addr_t *addrs, int max_pages); -extern struct sg_table *drm_prime_pages_to_sg(struct page **pages, unsigned int nr_pages); -extern 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); +struct sg_table *drm_prime_pages_to_sg(struct page **pages, unsigned int nr_pages); +void drm_prime_gem_destroy(struct drm_gem_object *obj, struct sg_table *sg); #endif /* __DRM_PRIME_H__ */ diff --git a/include/drm/drm_scdc_helper.h b/include/drm/drm_scdc_helper.h index ab6bcfbceba9..c25122bb490a 100644 --- a/include/drm/drm_scdc_helper.h +++ b/include/drm/drm_scdc_helper.h @@ -129,6 +129,8 @@ static inline int drm_scdc_writeb(struct i2c_adapter *adapter, u8 offset, return drm_scdc_write(adapter, offset, &value, sizeof(value)); } +bool drm_scdc_get_scrambling_status(struct i2c_adapter *adapter); + /** * drm_scdc_set_scrambling - enable scrambling * @adapter: I2C adapter for DDC channel diff --git a/include/drm/drm_simple_kms_helper.h b/include/drm/drm_simple_kms_helper.h index fffbb95a0915..2d36538e4a17 100644 --- a/include/drm/drm_simple_kms_helper.h +++ b/include/drm/drm_simple_kms_helper.h @@ -72,7 +72,7 @@ struct drm_simple_display_pipe_funcs { * the hardware lacks vblank support entirely. */ void (*update)(struct drm_simple_display_pipe *pipe, - struct drm_plane_state *plane_state); + struct drm_plane_state *old_plane_state); /** * @prepare_fb: diff --git a/include/drm/drm_sysfs.h b/include/drm/drm_sysfs.h index 1d8e033fde67..23418c1f10d1 100644 --- a/include/drm/drm_sysfs.h +++ b/include/drm/drm_sysfs.h @@ -6,7 +6,7 @@ * don't want to include the full drmP.h file. */ -extern int drm_class_device_register(struct device *dev); -extern void drm_class_device_unregister(struct device *dev); +int drm_class_device_register(struct device *dev); +void drm_class_device_unregister(struct device *dev); #endif diff --git a/include/drm/tinydrm/tinydrm.h b/include/drm/tinydrm/tinydrm.h index cf9ca207b8b1..00b800df4d1b 100644 --- a/include/drm/tinydrm/tinydrm.h +++ b/include/drm/tinydrm/tinydrm.h @@ -58,8 +58,7 @@ pipe_to_tinydrm(struct drm_simple_display_pipe *pipe) .gem_prime_mmap = drm_gem_cma_prime_mmap, \ .dumb_create = drm_gem_cma_dumb_create, \ .dumb_map_offset = drm_gem_cma_dumb_map_offset, \ - .dumb_destroy = drm_gem_dumb_destroy, \ - .fops = &tinydrm_fops + .dumb_destroy = drm_gem_dumb_destroy /** * TINYDRM_MODE - tinydrm display mode @@ -84,7 +83,6 @@ pipe_to_tinydrm(struct drm_simple_display_pipe *pipe) .type = DRM_MODE_TYPE_DRIVER, \ .clock = 1 /* pass validation */ -extern const struct file_operations tinydrm_fops; void tinydrm_lastclose(struct drm_device *drm); void tinydrm_gem_cma_free_object(struct drm_gem_object *gem_obj); struct drm_gem_object * diff --git a/include/linux/pci.h b/include/linux/pci.h index eb3da1a04e6c..5948cfdc984e 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -358,6 +358,7 @@ struct pci_dev { unsigned int is_virtfn:1; unsigned int reset_fn:1; unsigned int is_hotplug_bridge:1; + unsigned int is_thunderbolt:1; /* Thunderbolt controller */ unsigned int __aer_firmware_first_valid:1; unsigned int __aer_firmware_first:1; unsigned int broken_intx_masking:1; @@ -2160,6 +2161,28 @@ static inline bool pci_ari_enabled(struct pci_bus *bus) return bus->self && bus->self->ari_enabled; } +/** + * pci_is_thunderbolt_attached - whether device is on a Thunderbolt daisy chain + * @pdev: PCI device to check + * + * Walk upwards from @pdev and check for each encountered bridge if it's part + * of a Thunderbolt controller. Reaching the host bridge means @pdev is not + * Thunderbolt-attached. (But rather soldered to the mainboard usually.) + */ +static inline bool pci_is_thunderbolt_attached(struct pci_dev *pdev) +{ + struct pci_dev *parent = pdev; + + if (pdev->is_thunderbolt) + return true; + + while ((parent = pci_upstream_bridge(parent))) + if (parent->is_thunderbolt) + return true; + + return false; +} + /* provide the legacy pci_dma_* API */ #include <linux/pci-dma-compat.h> |